From 8baaa354aabd7f05db4b66a5b08f8f79638751c3 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 29 May 2026 14:43:49 +0900 Subject: [PATCH 1/3] Split macOS Intel bundler tests across four tag-group runners A single macos-15-intel runner took around 40 minutes. Reuse the Windows tag groups to fan the run out to four runners, keeping each under roughly ten minutes. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/bundler.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/bundler.yml b/.github/workflows/bundler.yml index fa472134bcd8..e176467f2299 100644 --- a/.github/workflows/bundler.yml +++ b/.github/workflows/bundler.yml @@ -40,8 +40,12 @@ jobs: - { os: { name: macOS, value: macos-26 }, ruby: { name: ruby-3.4, value: 3.4.9 }, timeout: 90 } - { os: { name: macOS, value: macos-26 }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 90 } - # Regression coverage for the Intel architecture with the latest Ruby only - - { os: { name: macOS-intel, value: macos-15-intel }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 90 } + # Regression coverage for the Intel architecture with the latest Ruby only. + # Split across runners using the Windows tag groups to keep each run reasonable. + - { os: { name: macOS-intel, value: macos-15-intel }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 90, group: a } + - { os: { name: macOS-intel, value: macos-15-intel }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 90, group: b } + - { os: { name: macOS-intel, value: macos-15-intel }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 90, group: c } + - { os: { name: macOS-intel, value: macos-15-intel }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 90, group: d } # Ruby 3.2 is about 20 minutes slower than 3.3/3.4, so it will be excluded from testing. - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-3.3, value: 3.3.11 }, timeout: 150, group: a } @@ -129,11 +133,15 @@ jobs: - name: Run Test (CRuby) run: | bin/parallel_rspec - if: matrix.ruby.name != 'jruby' && matrix.ruby.name != 'truffleruby' && matrix.os.name != 'Windows' + if: matrix.ruby.name != 'jruby' && matrix.ruby.name != 'truffleruby' && matrix.os.name != 'Windows' && matrix.os.name != 'macOS-intel' - name: Run Test (CRuby on Windows - Group ${{ matrix.group }}) run: | bin/parallel_rspec --tag windows_${{ matrix.group }} if: matrix.ruby.name != 'jruby' && matrix.ruby.name != 'truffleruby' && matrix.os.name == 'Windows' + - name: Run Test (CRuby on macOS Intel - Group ${{ matrix.group }}) + run: | + bin/parallel_rspec --tag windows_${{ matrix.group }} + if: matrix.ruby.name != 'jruby' && matrix.ruby.name != 'truffleruby' && matrix.os.name == 'macOS-intel' - name: Run Test (JRuby) run: | bin/parallel_rspec --tag jruby_only --tag jruby From 139d8b7232d69591190b2cf2fa6ee36fff9d51b1 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 29 May 2026 14:49:49 +0900 Subject: [PATCH 2/3] Rename Windows tag groups to test shards These groups now drive the macOS Intel split as well as Windows, so the "windows" naming no longer fits. Rename the module to Spec::Shards and the tags to shard_a..d. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/bundler.yml | 6 +++--- spec/spec_helper.rb | 10 +++++----- spec/support/{windows_tag_group.rb => shards.rb} | 16 ++++++++-------- 3 files changed, 16 insertions(+), 16 deletions(-) rename spec/support/{windows_tag_group.rb => shards.rb} (96%) diff --git a/.github/workflows/bundler.yml b/.github/workflows/bundler.yml index e176467f2299..fba82194b8fa 100644 --- a/.github/workflows/bundler.yml +++ b/.github/workflows/bundler.yml @@ -41,7 +41,7 @@ jobs: - { os: { name: macOS, value: macos-26 }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 90 } # Regression coverage for the Intel architecture with the latest Ruby only. - # Split across runners using the Windows tag groups to keep each run reasonable. + # Split across runners using the test shards to keep each run reasonable. - { os: { name: macOS-intel, value: macos-15-intel }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 90, group: a } - { os: { name: macOS-intel, value: macos-15-intel }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 90, group: b } - { os: { name: macOS-intel, value: macos-15-intel }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 90, group: c } @@ -136,11 +136,11 @@ jobs: if: matrix.ruby.name != 'jruby' && matrix.ruby.name != 'truffleruby' && matrix.os.name != 'Windows' && matrix.os.name != 'macOS-intel' - name: Run Test (CRuby on Windows - Group ${{ matrix.group }}) run: | - bin/parallel_rspec --tag windows_${{ matrix.group }} + bin/parallel_rspec --tag shard_${{ matrix.group }} if: matrix.ruby.name != 'jruby' && matrix.ruby.name != 'truffleruby' && matrix.os.name == 'Windows' - name: Run Test (CRuby on macOS Intel - Group ${{ matrix.group }}) run: | - bin/parallel_rspec --tag windows_${{ matrix.group }} + bin/parallel_rspec --tag shard_${{ matrix.group }} if: matrix.ruby.name != 'jruby' && matrix.ruby.name != 'truffleruby' && matrix.os.name == 'macOS-intel' - name: Run Test (JRuby) run: | diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 877deca66340..27ddc6a77125 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -38,7 +38,7 @@ require_relative "support/matchers" require_relative "support/permissions" require_relative "support/platforms" -require_relative "support/windows_tag_group" +require_relative "support/shards" begin raise LoadError if File.exist?(File.expand_path("../../lib/bundler/bundler.gemspec", __dir__)) @@ -88,7 +88,7 @@ def self.ruby=(ruby) config.include Spec::Path config.include Spec::Platforms config.include Spec::Permissions - config.include Spec::WindowsTagGroup + config.include Spec::Shards # Enable flags like --only-failures and --next-failure config.example_status_persistence_file_path = ".rspec_status" @@ -175,7 +175,7 @@ def self.ruby=(ruby) reset! end - Spec::WindowsTagGroup::EXAMPLE_MAPPINGS.each do |tag, file_paths| + Spec::Shards::EXAMPLE_MAPPINGS.each do |tag, file_paths| file_pattern = Regexp.union(file_paths.map {|path| Regexp.new(Regexp.escape(path) + "$") }) config.define_derived_metadata(file_path: file_pattern) do |metadata| @@ -185,8 +185,8 @@ def self.ruby=(ruby) config.before(:context) do |example| metadata = example.class.metadata - if metadata[:type] != :aruba && !metadata[:realworld] && metadata.keys.none? {|k| Spec::WindowsTagGroup::EXAMPLE_MAPPINGS.keys.include?(k) } - warn "#{metadata[:file_path]} is not assigned to any Windows runner group. see spec/support/windows_tag_group.rb for details." + if metadata[:type] != :aruba && !metadata[:realworld] && metadata.keys.none? {|k| Spec::Shards::EXAMPLE_MAPPINGS.keys.include?(k) } + warn "#{metadata[:file_path]} is not assigned to any shard. see spec/support/shards.rb for details." end end unless Spec::Path.ruby_core? end diff --git a/spec/support/windows_tag_group.rb b/spec/support/shards.rb similarity index 96% rename from spec/support/windows_tag_group.rb rename to spec/support/shards.rb index fb9c0811493f..580997eb72df 100644 --- a/spec/support/windows_tag_group.rb +++ b/spec/support/shards.rb @@ -1,14 +1,14 @@ # frozen_string_literal: true -# This group classifies test files into 4 groups by running `bin/rspec --profile 10000` +# This classifies test files into 4 shards by running `bin/rspec --profile 10000` # to ensure balanced execution times. When adding new test files, it is recommended to -# re-aggregate and adjust the groups to keep them balanced. -# For now, please add new files to group 'windows_d'. +# re-aggregate and adjust the shards to keep them balanced. +# For now, please add new files to shard 'shard_d'. module Spec - module WindowsTagGroup + module Shards EXAMPLE_MAPPINGS = { - windows_a: [ + shard_a: [ "spec/runtime/setup_spec.rb", "spec/commands/install_spec.rb", "spec/commands/add_spec.rb", @@ -53,7 +53,7 @@ module WindowsTagGroup "spec/bundler/plugin/source_list_spec.rb", "spec/bundler/source/path_spec.rb", ], - windows_b: [ + shard_b: [ "spec/install/gemfile/git_spec.rb", "spec/install/gems/standalone_spec.rb", "spec/commands/lock_spec.rb", @@ -97,7 +97,7 @@ module WindowsTagGroup "spec/bundler/index_spec.rb", "spec/other/cli_man_pages_spec.rb", ], - windows_c: [ + shard_c: [ "spec/commands/newgem_spec.rb", "spec/commands/exec_spec.rb", "spec/commands/clean_spec.rb", @@ -142,7 +142,7 @@ module WindowsTagGroup "spec/bundler/cli_common_spec.rb", "spec/bundler/ci_detector_spec.rb", ], - windows_d: [ + shard_d: [ "spec/commands/outdated_spec.rb", "spec/commands/update_spec.rb", "spec/lock/lockfile_spec.rb", From 2843b6442e59672ba684bc2a45d531e76acba2ec Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 29 May 2026 14:51:03 +0900 Subject: [PATCH 3/3] Rename the matrix group field to shard Matches the shard_a..d tag names so the matrix variable reads consistently with what it selects. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/bundler.yml | 40 +++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/bundler.yml b/.github/workflows/bundler.yml index fba82194b8fa..d66b2dc94f7a 100644 --- a/.github/workflows/bundler.yml +++ b/.github/workflows/bundler.yml @@ -42,24 +42,24 @@ jobs: # Regression coverage for the Intel architecture with the latest Ruby only. # Split across runners using the test shards to keep each run reasonable. - - { os: { name: macOS-intel, value: macos-15-intel }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 90, group: a } - - { os: { name: macOS-intel, value: macos-15-intel }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 90, group: b } - - { os: { name: macOS-intel, value: macos-15-intel }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 90, group: c } - - { os: { name: macOS-intel, value: macos-15-intel }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 90, group: d } + - { os: { name: macOS-intel, value: macos-15-intel }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 90, shard: a } + - { os: { name: macOS-intel, value: macos-15-intel }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 90, shard: b } + - { os: { name: macOS-intel, value: macos-15-intel }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 90, shard: c } + - { os: { name: macOS-intel, value: macos-15-intel }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 90, shard: d } # Ruby 3.2 is about 20 minutes slower than 3.3/3.4, so it will be excluded from testing. - - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-3.3, value: 3.3.11 }, timeout: 150, group: a } - - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-3.3, value: 3.3.11 }, timeout: 150, group: b } - - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-3.3, value: 3.3.11 }, timeout: 150, group: c } - - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-3.3, value: 3.3.11 }, timeout: 150, group: d } - - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-3.4, value: 3.4.9 }, timeout: 150, group: a } - - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-3.4, value: 3.4.9 }, timeout: 150, group: b } - - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-3.4, value: 3.4.9 }, timeout: 150, group: c } - - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-3.4, value: 3.4.9 }, timeout: 150, group: d } - - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 150, group: a } - - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 150, group: b } - - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 150, group: c } - - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 150, group: d } + - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-3.3, value: 3.3.11 }, timeout: 150, shard: a } + - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-3.3, value: 3.3.11 }, timeout: 150, shard: b } + - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-3.3, value: 3.3.11 }, timeout: 150, shard: c } + - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-3.3, value: 3.3.11 }, timeout: 150, shard: d } + - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-3.4, value: 3.4.9 }, timeout: 150, shard: a } + - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-3.4, value: 3.4.9 }, timeout: 150, shard: b } + - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-3.4, value: 3.4.9 }, timeout: 150, shard: c } + - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-3.4, value: 3.4.9 }, timeout: 150, shard: d } + - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 150, shard: a } + - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 150, shard: b } + - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 150, shard: c } + - { os: { name: Windows, value: windows-2025 }, ruby: { name: ruby-4.0, value: 4.0.5 }, timeout: 150, shard: d } - { os: { name: Ubuntu, value: ubuntu-24.04 }, ruby: { name: jruby, value: jruby-10.1.0.0 } } - { os: { name: macOS, value: macos-26 }, ruby: { name: jruby, value: jruby-10.1.0.0 } } @@ -134,13 +134,13 @@ jobs: run: | bin/parallel_rspec if: matrix.ruby.name != 'jruby' && matrix.ruby.name != 'truffleruby' && matrix.os.name != 'Windows' && matrix.os.name != 'macOS-intel' - - name: Run Test (CRuby on Windows - Group ${{ matrix.group }}) + - name: Run Test (CRuby on Windows - Shard ${{ matrix.shard }}) run: | - bin/parallel_rspec --tag shard_${{ matrix.group }} + bin/parallel_rspec --tag shard_${{ matrix.shard }} if: matrix.ruby.name != 'jruby' && matrix.ruby.name != 'truffleruby' && matrix.os.name == 'Windows' - - name: Run Test (CRuby on macOS Intel - Group ${{ matrix.group }}) + - name: Run Test (CRuby on macOS Intel - Shard ${{ matrix.shard }}) run: | - bin/parallel_rspec --tag shard_${{ matrix.group }} + bin/parallel_rspec --tag shard_${{ matrix.shard }} if: matrix.ruby.name != 'jruby' && matrix.ruby.name != 'truffleruby' && matrix.os.name == 'macOS-intel' - name: Run Test (JRuby) run: |