From 4b717a8b7fd712537ffb43ae51c487180b3d0190 Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Wed, 22 Jul 2026 08:11:33 +0100 Subject: [PATCH 01/10] Regenerate required dict file --- .github/workflows/release-rubygem.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/release-rubygem.yaml b/.github/workflows/release-rubygem.yaml index 301a923a..d6932f1a 100644 --- a/.github/workflows/release-rubygem.yaml +++ b/.github/workflows/release-rubygem.yaml @@ -23,6 +23,10 @@ jobs: with: ruby-version: 4.0.6 working-directory: ruby + - name: Synchronize CiEnvironments.json + working-directory: ruby + run: bundle exec rake ci_environments + - run: ./scripts/fail-if-dirty - uses: rubygems/configure-rubygems-credentials@dc5a8d8553e6ee01fc26761a49e99e733d17954a # v2.1.0 - uses: cucumber/action-publish-rubygem@4e79bb9aed597c835e8438f57c04d0996ab80d72 # v2.0.0 with: From 5c86576092cf93d12862efb1d605136c3c06410e Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Wed, 22 Jul 2026 08:11:49 +0100 Subject: [PATCH 02/10] Attribution --- ruby/cucumber-ci-environment.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/cucumber-ci-environment.gemspec b/ruby/cucumber-ci-environment.gemspec index 91bb3985..333aa3cb 100644 --- a/ruby/cucumber-ci-environment.gemspec +++ b/ruby/cucumber-ci-environment.gemspec @@ -5,7 +5,7 @@ version = File.read(File.expand_path('VERSION', __dir__)).strip Gem::Specification.new do |s| s.name = 'cucumber-ci-environment' s.version = version - s.authors = ['Vincent PrĂȘtre'] + s.authors = ['Vincent PrĂȘtre', 'Luke Hill'] s.description = 'Detect CI Environment from environment variables' s.summary = "#{s.name}-#{s.version}" s.email = 'cukes@googlegroups.com' From 90dbf7496c300e5af8e08e354e64b70e5f8c79d7 Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Wed, 22 Jul 2026 08:12:42 +0100 Subject: [PATCH 03/10] Fix test matrix --- .github/workflows/test-ruby.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-ruby.yaml b/.github/workflows/test-ruby.yaml index 46710276..610cc707 100644 --- a/.github/workflows/test-ruby.yaml +++ b/.github/workflows/test-ruby.yaml @@ -28,12 +28,12 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest] - ruby: ['3.2', '3.3', '3.4', '3.5'] + ruby: ['3.2', '3.3', '3.4', '4.0'] include: - os: windows-latest - ruby: '3.4' + ruby: '4.0' - os: macos-latest - ruby: '3.4' + ruby: '4.0' steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: From 5a6c29e2c6a41dd58c6acab5f7e9bad35c6b9c49 Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Wed, 22 Jul 2026 08:13:23 +0100 Subject: [PATCH 04/10] Add changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 723d4b76..f11639e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Fixed +- [Ruby] Ensure `CiEnvironments.json` is published in gem package ## [14.0.0] - 2026-06-11 ### Changed From 96af816ca00b6fba17bcddcee1a28ad387ab0f3c Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Wed, 22 Jul 2026 08:28:18 +0100 Subject: [PATCH 05/10] Slightly reduce complexity of a couple of methods --- ruby/lib/cucumber/ci_environment.rb | 15 ++++---- .../ci_environment/variable_expression.rb | 36 +++++++++---------- 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/ruby/lib/cucumber/ci_environment.rb b/ruby/lib/cucumber/ci_environment.rb index 8a768859..115b13dc 100644 --- a/ruby/lib/cucumber/ci_environment.rb +++ b/ruby/lib/cucumber/ci_environment.rb @@ -7,6 +7,7 @@ module Cucumber module CiEnvironment extend VariableExpression + CI_ENVIRONMENTS_PATH = File.join(File.dirname(__FILE__), 'ci_environment/CiEnvironments.json') module_function @@ -43,16 +44,12 @@ def detect_git(ci_environment, env) remote = evaluate(ci_environment['git']['remote'], env) return nil if remote.nil? - git_info = { + { remote: remove_userinfo_from_url(remote), - revision: revision - } - - tag = evaluate(ci_environment['git']['tag'], env) - branch = evaluate(ci_environment['git']['branch'], env) - git_info[:tag] = tag if tag - git_info[:branch] = branch if branch - git_info + revision: revision, + tag: evaluate(ci_environment['git']['tag'], env), + branch: evaluate(ci_environment['git']['branch'], env) + }.compact end def detect_revision(ci_environment, env) diff --git a/ruby/lib/cucumber/ci_environment/variable_expression.rb b/ruby/lib/cucumber/ci_environment/variable_expression.rb index dadf80a2..dcd5bf6a 100644 --- a/ruby/lib/cucumber/ci_environment/variable_expression.rb +++ b/ruby/lib/cucumber/ci_environment/variable_expression.rb @@ -6,31 +6,29 @@ module VariableExpression def evaluate(expression, env) return nil if expression.nil? - begin - expression.gsub(/\${(.*?)(?:(? Date: Wed, 22 Jul 2026 08:36:25 +0100 Subject: [PATCH 06/10] Simplify namespace for files --- ruby/lib/cucumber/.gitignore | 1 + ruby/lib/cucumber/ci_environment.rb | 100 +++++++++--------- ruby/lib/cucumber/ci_environment/.gitignore | 1 - .../ci_environment/variable_expression.rb | 47 -------- ruby/lib/cucumber/variable_expression.rb | 45 ++++++++ 5 files changed, 97 insertions(+), 97 deletions(-) create mode 100644 ruby/lib/cucumber/.gitignore delete mode 100644 ruby/lib/cucumber/ci_environment/.gitignore delete mode 100644 ruby/lib/cucumber/ci_environment/variable_expression.rb create mode 100644 ruby/lib/cucumber/variable_expression.rb diff --git a/ruby/lib/cucumber/.gitignore b/ruby/lib/cucumber/.gitignore new file mode 100644 index 00000000..2424f0bc --- /dev/null +++ b/ruby/lib/cucumber/.gitignore @@ -0,0 +1 @@ +ci_environment/CiEnvironments.json diff --git a/ruby/lib/cucumber/ci_environment.rb b/ruby/lib/cucumber/ci_environment.rb index 115b13dc..c43109c1 100644 --- a/ruby/lib/cucumber/ci_environment.rb +++ b/ruby/lib/cucumber/ci_environment.rb @@ -5,73 +5,75 @@ require 'cucumber/ci_environment/variable_expression' module Cucumber - module CiEnvironment + class CiEnvironment extend VariableExpression CI_ENVIRONMENTS_PATH = File.join(File.dirname(__FILE__), 'ci_environment/CiEnvironments.json') - module_function + class << self + def detect_ci_environment(env) + ci_environments = JSON.parse(File.read(CI_ENVIRONMENTS_PATH)) + ci_environments.each do |ci_environment| + detected = detect(ci_environment, env) + return detected unless detected.nil? + end - def detect_ci_environment(env) - ci_environments = JSON.parse(File.read(CI_ENVIRONMENTS_PATH)) - ci_environments.each do |ci_environment| - detected = detect(ci_environment, env) - return detected unless detected.nil? + nil end - nil - end - - def detect(ci_environment, env) - url = evaluate(ci_environment['url'], env) - return nil if url.nil? + def remove_userinfo_from_url(value) + return nil if value.nil? - result = { - name: ci_environment['name'], - url: url, - buildNumber: evaluate(ci_environment['buildNumber'], env) - } + begin + uri = URI(value) + uri.userinfo = '' + uri.to_s + rescue StandardError + value + end + end - detected_git = detect_git(ci_environment, env) - result[:git] = detected_git if detected_git - result - end + private - def detect_git(ci_environment, env) - revision = detect_revision(ci_environment, env) - return nil if revision.nil? + def detect(ci_environment, env) + url = evaluate(ci_environment['url'], env) + return nil if url.nil? - remote = evaluate(ci_environment['git']['remote'], env) - return nil if remote.nil? + result = { + name: ci_environment['name'], + url: url, + buildNumber: evaluate(ci_environment['buildNumber'], env) + } - { - remote: remove_userinfo_from_url(remote), - revision: revision, - tag: evaluate(ci_environment['git']['tag'], env), - branch: evaluate(ci_environment['git']['branch'], env) - }.compact - end + detected_git = detect_git(ci_environment, env) + result[:git] = detected_git if detected_git + result + end - def detect_revision(ci_environment, env) - return evaluate(ci_environment['git']['revision'], env) unless env['GITHUB_EVENT_NAME'] == 'pull_request' + def detect_git(ci_environment, env) + revision = detect_revision(ci_environment, env) + return nil if revision.nil? - raise StandardError('GITHUB_EVENT_PATH not set') unless env['GITHUB_EVENT_PATH'] + remote = evaluate(ci_environment['git']['remote'], env) + return nil if remote.nil? - event = JSON.parse(File.read(env['GITHUB_EVENT_PATH'])) - event.dig('pull_request', 'head', 'sha').tap do |revision| - raise StandardError("Could not find .pull_request.head.sha in GITHUB_EVENT_PATH:\n#{JSON.pretty_generate(event)}") if revision.nil? + { + remote: remove_userinfo_from_url(remote), + revision: revision, + tag: evaluate(ci_environment['git']['tag'], env), + branch: evaluate(ci_environment['git']['branch'], env) + }.compact end - end - def remove_userinfo_from_url(value) - return nil if value.nil? + def detect_revision(ci_environment, env) + return evaluate(ci_environment['git']['revision'], env) unless env['GITHUB_EVENT_NAME'] == 'pull_request' + + raise StandardError('GITHUB_EVENT_PATH not set') unless env['GITHUB_EVENT_PATH'] - begin - uri = URI(value) - uri.userinfo = '' - uri.to_s - rescue StandardError - value + event = JSON.parse(File.read(env['GITHUB_EVENT_PATH'])) + event.dig('pull_request', 'head', 'sha').tap do |revision| + raise StandardError("Could not find .pull_request.head.sha in GITHUB_EVENT_PATH:\n#{JSON.pretty_generate(event)}") if revision.nil? + end end end end diff --git a/ruby/lib/cucumber/ci_environment/.gitignore b/ruby/lib/cucumber/ci_environment/.gitignore deleted file mode 100644 index ab44ddb1..00000000 --- a/ruby/lib/cucumber/ci_environment/.gitignore +++ /dev/null @@ -1 +0,0 @@ -CiEnvironments.json diff --git a/ruby/lib/cucumber/ci_environment/variable_expression.rb b/ruby/lib/cucumber/ci_environment/variable_expression.rb deleted file mode 100644 index dcd5bf6a..00000000 --- a/ruby/lib/cucumber/ci_environment/variable_expression.rb +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -module Cucumber - module CiEnvironment - module VariableExpression - def evaluate(expression, env) - return nil if expression.nil? - - expression.gsub(/\${(.*?)(?:(? Date: Wed, 22 Jul 2026 08:37:20 +0100 Subject: [PATCH 07/10] Fix file path load --- ruby/lib/cucumber/ci_environment.rb | 2 +- .../cucumber/{ci_environment => }/variable_expression_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename ruby/spec/cucumber/{ci_environment => }/variable_expression_spec.rb (93%) diff --git a/ruby/lib/cucumber/ci_environment.rb b/ruby/lib/cucumber/ci_environment.rb index c43109c1..288243e2 100644 --- a/ruby/lib/cucumber/ci_environment.rb +++ b/ruby/lib/cucumber/ci_environment.rb @@ -2,7 +2,7 @@ require 'uri' require 'json' -require 'cucumber/ci_environment/variable_expression' +require 'cucumber/variable_expression' module Cucumber class CiEnvironment diff --git a/ruby/spec/cucumber/ci_environment/variable_expression_spec.rb b/ruby/spec/cucumber/variable_expression_spec.rb similarity index 93% rename from ruby/spec/cucumber/ci_environment/variable_expression_spec.rb rename to ruby/spec/cucumber/variable_expression_spec.rb index f69d41ad..06faefc5 100644 --- a/ruby/spec/cucumber/ci_environment/variable_expression_spec.rb +++ b/ruby/spec/cucumber/variable_expression_spec.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require 'cucumber/ci_environment' +require 'cucumber/variable_expression' -describe Cucumber::CiEnvironment::VariableExpression do +describe Cucumber::VariableExpression do describe '.evaluate' do subject(:ci_environment) { Cucumber::CiEnvironment } From ac4e6a4c3500a756b55b5e49f86a04596164ce56 Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Wed, 22 Jul 2026 08:37:31 +0100 Subject: [PATCH 08/10] Update rubocop autogen --- ruby/.rubocop_todo.yml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/ruby/.rubocop_todo.yml b/ruby/.rubocop_todo.yml index bdf91a04..1fa9bf2e 100644 --- a/ruby/.rubocop_todo.yml +++ b/ruby/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2025-10-07 17:03:37 UTC using RuboCop version 1.81.1. +# on 2026-07-22 07:32:12 UTC using RuboCop version 1.81.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -9,19 +9,14 @@ # TODO: Oct '23 -> 10 files inspected, 63 offenses detected, 53 offenses autocorrectable # TODO: Nov '24 -> 9 files inspected, 4 offenses detected, 0 offenses autocorrectable # TODO: Oct '25 -> 9 files inspected, 5 offenses detected, 1 offenses autocorrectable +# TODO: Jul '26 -> 7 files inspected, 2 offenses detected # Offense count: 1 -# This cop supports safe autocorrection (--autocorrect). -Layout/EmptyLinesAfterModuleInclusion: - Exclude: - - 'lib/cucumber/ci_environment.rb' - -# Offense count: 2 # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. Metrics/AbcSize: Max: 22 -# Offense count: 2 +# Offense count: 1 # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. Metrics/MethodLength: - Max: 23 + Max: 21 From 5dbe4c28f689d1a77a0a6f37c0d87a0a4f2d1516 Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Thu, 23 Jul 2026 08:10:04 +0100 Subject: [PATCH 09/10] Fix file ref --- ruby/.gitignore | 3 +-- ruby/Rakefile | 2 +- ruby/lib/cucumber/.gitignore | 1 - ruby/lib/cucumber/ci_environment.rb | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) delete mode 100644 ruby/lib/cucumber/.gitignore diff --git a/ruby/.gitignore b/ruby/.gitignore index 5e7eec9f..463c834f 100644 --- a/ruby/.gitignore +++ b/ruby/.gitignore @@ -3,7 +3,6 @@ coverage/ pkg/ *.gem .compared -.deps -.tested* +lib/cucumber/CiEnvironments.json *-go *.iml diff --git a/ruby/Rakefile b/ruby/Rakefile index e00ae19c..6341b384 100644 --- a/ruby/Rakefile +++ b/ruby/Rakefile @@ -3,7 +3,7 @@ $LOAD_PATH.unshift(File.expand_path('lib', __dir__)) file :ci_environments do - FileUtils.cp('../CiEnvironments.json', 'lib/cucumber/ci_environment/CiEnvironments.json') + FileUtils.cp('../CiEnvironments.json', 'lib/cucumber/CiEnvironments.json') end desc 'Copy the sample environments & run all the unit tests for all environment types' diff --git a/ruby/lib/cucumber/.gitignore b/ruby/lib/cucumber/.gitignore deleted file mode 100644 index 2424f0bc..00000000 --- a/ruby/lib/cucumber/.gitignore +++ /dev/null @@ -1 +0,0 @@ -ci_environment/CiEnvironments.json diff --git a/ruby/lib/cucumber/ci_environment.rb b/ruby/lib/cucumber/ci_environment.rb index 288243e2..f713bb59 100644 --- a/ruby/lib/cucumber/ci_environment.rb +++ b/ruby/lib/cucumber/ci_environment.rb @@ -8,7 +8,7 @@ module Cucumber class CiEnvironment extend VariableExpression - CI_ENVIRONMENTS_PATH = File.join(File.dirname(__FILE__), 'ci_environment/CiEnvironments.json') + CI_ENVIRONMENTS_PATH = File.join(File.dirname(__FILE__), './CiEnvironments.json') class << self def detect_ci_environment(env) From c7c2028238eecc322bdf0f58bf8c0a89a9927847 Mon Sep 17 00:00:00 2001 From: Luke Hill Date: Thu, 23 Jul 2026 08:13:21 +0100 Subject: [PATCH 10/10] Add changelog; --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f11639e3..103c2741 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Fixed -- [Ruby] Ensure `CiEnvironments.json` is published in gem package +- [Ruby] Ensure `CiEnvironments.json` is published (in new dir), in gem package +- BREAKING CHANGE: [Ruby] change `VariableExpression` module namespace to be top level alongside `CiEnvironment` module ## [14.0.0] - 2026-06-11 ### Changed