From c10b93cd5f04e1ae2fa34dd1bc3dc9e4de37a115 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Wed, 4 Feb 2026 08:10:42 +0900 Subject: [PATCH 01/17] tool: Support `$NO_COLOR` in `ifchange` --- tool/ifchange | 1 + 1 file changed, 1 insertion(+) diff --git a/tool/ifchange b/tool/ifchange index 9e4a89533c0f95..b20ae4461a26ad 100755 --- a/tool/ifchange +++ b/tool/ifchange @@ -20,6 +20,7 @@ timestamp= keepsuffix= srcavail=f color=auto +[ "x${NO_COLOR-}" = x ] || color=never until [ $# -eq 0 ]; do case "$1" in --) From d2ce6dd46653f2fa072b82a3a2a2f9ee6153621d Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Wed, 4 Feb 2026 08:12:49 +0900 Subject: [PATCH 02/17] tool: Update a comment `ifchange` [ci skip] --- tool/ifchange | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tool/ifchange b/tool/ifchange index b20ae4461a26ad..2a5f3db522b260 100755 --- a/tool/ifchange +++ b/tool/ifchange @@ -1,7 +1,8 @@ #!/bin/sh # usage: ifchange target temporary -# Used in generating revision.h via Makefiles. +# Used in generating various files such as rbconfig.rb, revision.h, +# etc. via Makefiles. help() { cat < Date: Wed, 4 Feb 2026 12:09:48 +0900 Subject: [PATCH 03/17] add deps --- depend | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/depend b/depend index 7525bcf396b901..978ac438b903d6 100644 --- a/depend +++ b/depend @@ -11091,6 +11091,7 @@ pathname.$(OBJEXT): {$(VPATH)}st.h pathname.$(OBJEXT): {$(VPATH)}subst.h prism/api_node.$(OBJEXT): $(hdrdir)/ruby.h prism/api_node.$(OBJEXT): $(hdrdir)/ruby/ruby.h +prism/api_node.$(OBJEXT): $(hdrdir)/ruby/version.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/api_node.c prism/api_node.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/api_node.$(OBJEXT): $(top_srcdir)/prism/defines.h @@ -11286,6 +11287,7 @@ prism/api_node.$(OBJEXT): {$(VPATH)}st.h prism/api_node.$(OBJEXT): {$(VPATH)}subst.h prism/api_pack.$(OBJEXT): $(hdrdir)/ruby.h prism/api_pack.$(OBJEXT): $(hdrdir)/ruby/ruby.h +prism/api_pack.$(OBJEXT): $(hdrdir)/ruby/version.h prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/api_pack.c prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/defines.h @@ -11496,6 +11498,7 @@ prism/encoding.$(OBJEXT): $(top_srcdir)/prism/encoding.h prism/encoding.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h prism/extension.$(OBJEXT): $(hdrdir)/ruby.h prism/extension.$(OBJEXT): $(hdrdir)/ruby/ruby.h +prism/extension.$(OBJEXT): $(hdrdir)/ruby/version.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/ast.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/defines.h prism/extension.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h @@ -11885,6 +11888,7 @@ prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.c prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h prism_init.$(OBJEXT): $(hdrdir)/ruby.h prism_init.$(OBJEXT): $(hdrdir)/ruby/ruby.h +prism_init.$(OBJEXT): $(hdrdir)/ruby/version.h prism_init.$(OBJEXT): $(top_srcdir)/prism/ast.h prism_init.$(OBJEXT): $(top_srcdir)/prism/defines.h prism_init.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h From 2dc4e872e8bc6ee86ee734310970f66cc9dd51af Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 3 Feb 2026 19:04:37 +0900 Subject: [PATCH 04/17] [ruby/rubygems] Lock diff-lcs < 2.0 https://github.com/ruby/rubygems/commit/23aecf4a86 --- spec/bundler/spec_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/bundler/spec_helper.rb b/spec/bundler/spec_helper.rb index a79e33fbb01684..0fbeb484f0ee8e 100644 --- a/spec/bundler/spec_helper.rb +++ b/spec/bundler/spec_helper.rb @@ -21,7 +21,7 @@ # If we use shared GEM_HOME and install multiple versions, it may cause # unexpected test failures. -gem "diff-lcs" +gem "diff-lcs", "< 2.0" require "rspec/core" require "rspec/expectations" From 2ba2950d20e82f82017a52da9b09fdf1291479a2 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Tue, 3 Feb 2026 17:37:05 +0900 Subject: [PATCH 05/17] show loadavg if the test fails to survey the following failure: ``` 1) Failure: TestFile#test_stat [/tmp/ruby/src/trunk-repeat20/test/ruby/test_file.rb:412]: Expected |1770056232.744032 - 1770056230.6465776| (2.097454309463501) to be <= 1. ``` BTW I found that `test/ruby/test_file.rb:412` `assert_in_delta atime, stat.atime.to_f, delta` only fails (mtime, ctime doesn't fail on 100 days). --- tool/lib/test/unit/assertions.rb | 10 +++++++++- tool/test/testunit/test_minitest_unit.rb | 9 +++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/tool/lib/test/unit/assertions.rb b/tool/lib/test/unit/assertions.rb index 19581fc3ab3ec0..0908666166e4a6 100644 --- a/tool/lib/test/unit/assertions.rb +++ b/tool/lib/test/unit/assertions.rb @@ -128,8 +128,16 @@ def assert_empty obj, msg = nil def assert_in_delta exp, act, delta = 0.001, msg = nil n = (exp - act).abs + loadavg = begin + if File.readable?("/proc/loadavg") + " (/proc/loadavg=#{File.read("/proc/loadavg").strip})" + end + rescue StandardError + nil + end + loadavg ||= "" msg = message(msg) { - "Expected |#{exp} - #{act}| (#{n}) to be <= #{delta}" + "Expected |#{exp} - #{act}| (#{n}) to be <= #{delta}#{loadavg}" } assert delta >= n, msg end diff --git a/tool/test/testunit/test_minitest_unit.rb b/tool/test/testunit/test_minitest_unit.rb index 84b6cf688c7b25..7f53e4b7dde59d 100644 --- a/tool/test/testunit/test_minitest_unit.rb +++ b/tool/test/testunit/test_minitest_unit.rb @@ -646,7 +646,7 @@ def test_delta_consistency def test_assert_in_delta_triggered x = "1.0e-06" - util_assert_triggered "Expected |0.0 - 0.001| (0.001) to be <= #{x}." do + util_assert_triggered "Expected |0.0 - 0.001| (0.001) to be <= #{x}.", strip: /\s+\(\/proc\/loadavg=.*\)/ do @tc.assert_in_delta 0.0, 1.0 / 1000, 0.000001 end end @@ -678,7 +678,7 @@ def test_epsilon_consistency end def test_assert_in_epsilon_triggered - util_assert_triggered 'Expected |10000 - 9990| (10) to be <= 9.99.' do + util_assert_triggered 'Expected |10000 - 9990| (10) to be <= 9.99.', strip: /\s+\(\/proc\/loadavg=.*\)/ do @tc.assert_in_epsilon 10000, 9990 end end @@ -686,7 +686,7 @@ def test_assert_in_epsilon_triggered def test_assert_in_epsilon_triggered_negative_case x = "0.100000xxx" y = "0.1" - util_assert_triggered "Expected |-1.1 - -1| (#{x}) to be <= #{y}." do + util_assert_triggered "Expected |-1.1 - -1| (#{x}) to be <= #{y}.", strip: /\s+\(\/proc\/loadavg=.*\)/ do @tc.assert_in_epsilon(-1.1, -1, 0.1) end end @@ -1352,7 +1352,7 @@ def test_test3; assert "does not matter" end assert_equal expected, sample_test_case.test_methods.sort end - def assert_triggered expected, klass = Test::Unit::AssertionFailedError + def assert_triggered expected, klass = Test::Unit::AssertionFailedError, strip: nil e = assert_raise klass do yield end @@ -1360,6 +1360,7 @@ def assert_triggered expected, klass = Test::Unit::AssertionFailedError msg = e.message.sub(/(---Backtrace---).*/m, '\1') msg.gsub!(/\(oid=[-0-9]+\)/, '(oid=N)') msg.gsub!(/(\d\.\d{6})\d+/, '\1xxx') # normalize: ruby version, impl, platform + msg.gsub!(strip, '') if strip assert_equal expected, msg end From 995c80bcd8509f59374506c04b60d94128cc2699 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Fri, 5 Dec 2025 18:52:02 +0900 Subject: [PATCH 06/17] Make `rb_node_case2_t` and `rb_node_case3_t` aliases of rb_node_case_t --- rubyparser.h | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/rubyparser.h b/rubyparser.h index 5af8f6db62c308..36a2dc30a6f8b2 100644 --- a/rubyparser.h +++ b/rubyparser.h @@ -289,25 +289,7 @@ typedef struct RNode_CASE { struct RNode *nd_body; rb_code_location_t case_keyword_loc; rb_code_location_t end_keyword_loc; -} rb_node_case_t; - -typedef struct RNode_CASE2 { - NODE node; - - struct RNode *nd_head; - struct RNode *nd_body; - rb_code_location_t case_keyword_loc; - rb_code_location_t end_keyword_loc; -} rb_node_case2_t; - -typedef struct RNode_CASE3 { - NODE node; - - struct RNode *nd_head; - struct RNode *nd_body; - rb_code_location_t case_keyword_loc; - rb_code_location_t end_keyword_loc; -} rb_node_case3_t; +} rb_node_case_t, rb_node_case2_t, rb_node_case3_t; typedef struct RNode_WHEN { NODE node; From c8b2a453d0fe099064e095d165ce38ee8c3eef38 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Fri, 5 Dec 2025 18:52:34 +0900 Subject: [PATCH 07/17] [Bug #21669] Fix void value expression check for `rescue` If any `rescue` node is non-void, the enclosing block is also non-void. --- parse.y | 3 +-- test/ruby/test_syntax.rb | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/parse.y b/parse.y index 7ca1197b37339a..b20141680ec68b 100644 --- a/parse.y +++ b/parse.y @@ -13847,8 +13847,7 @@ value_expr_check(struct parser_params *p, NODE *node) return NULL; } if (!(vn = value_expr_check(p, RNODE_RESBODY(r)->nd_body))) { - void_node = 0; - break; + return NULL; } if (!void_node) void_node = vn; } diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index 5065a1db332a54..79e373ea66fab4 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -2013,6 +2013,8 @@ def foo(*args) = super assert_equal(1, b.new.foo(1), bug21256) end + BUG_21669 = '[Bug #21669]' + def test_value_expr_in_condition mesg = /void value expression/ assert_syntax_error("tap {a = (true ? next : break)}", mesg) @@ -2026,6 +2028,20 @@ def test_value_expr_in_singleton assert_syntax_error("class << (return); end", mesg) end + def test_value_expr_in_rescue + assert_valid_syntax("#{<<~"{#"}\n#{<<~'};'}", "#{BUG_21669} 1.1") + {# + x = begin + raise + return + rescue + "OK" + else + return + end + }; + end + def test_tautological_condition assert_valid_syntax("def f() return if false and invalid; nil end") assert_valid_syntax("def f() return unless true or invalid; nil end") From 4f360107387c47bfd82e7010b8eb7393575d4d76 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Fri, 5 Dec 2025 18:54:43 +0900 Subject: [PATCH 08/17] [Bug #21669] Fix void value expression check for `rescue`-else If `rescue`-else node is void, the `rescue`-body is also void. --- parse.y | 4 +++- test/ruby/test_syntax.rb | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/parse.y b/parse.y index b20141680ec68b..7efc7a7ea5c8ce 100644 --- a/parse.y +++ b/parse.y @@ -13839,7 +13839,9 @@ value_expr_check(struct parser_params *p, NODE *node) case NODE_RESCUE: /* void only if all children are void */ vn = RNODE_RESCUE(node)->nd_head; - if (!vn || !(vn = value_expr_check(p, vn))) return NULL; + if (!vn || !(vn = value_expr_check(p, vn))) { + if (!RNODE_RESCUE(node)->nd_else) return NULL; + } if (!void_node) void_node = vn; for (NODE *r = RNODE_RESCUE(node)->nd_resq; r; r = RNODE_RESBODY(r)->nd_next) { if (!nd_type_p(r, NODE_RESBODY)) { diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index 79e373ea66fab4..9a143750565d67 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -2040,6 +2040,17 @@ def test_value_expr_in_rescue return end }; + + assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 1.2") + {# + x = begin + foo + rescue + return + else + return + end + }; end def test_tautological_condition From 932ce048feb9f26bcd9e8dc93ada4d2a407ace1f Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Fri, 5 Dec 2025 19:01:21 +0900 Subject: [PATCH 09/17] [Bug #21669] Implement void value expression check for `case`/`when` If the all `when` and `else` branches are void, the `case` is also void. --- parse.y | 12 ++++++++++++ test/ruby/test_syntax.rb | 24 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/parse.y b/parse.y index 7efc7a7ea5c8ce..63b6ab9b163652 100644 --- a/parse.y +++ b/parse.y @@ -13864,6 +13864,18 @@ value_expr_check(struct parser_params *p, NODE *node) case NODE_RETRY: goto found; + case NODE_CASE: + case NODE_CASE2: + for (node = RNODE_CASE(node)->nd_body; + node && nd_type_p(node, NODE_WHEN); + node = RNODE_WHEN(node)->nd_next) { + if (!(vn = value_expr_check(p, RNODE_WHEN(node)->nd_body))) { + return NULL; + } + if (!void_node) void_node = vn; + } + break; + case NODE_CASE3: if (!RNODE_CASE3(node)->nd_body || !nd_type_p(RNODE_CASE3(node)->nd_body, NODE_IN)) { compile_error(p, "unexpected node"); diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index 9a143750565d67..3638d83e2bf351 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -2053,6 +2053,30 @@ def test_value_expr_in_rescue }; end + def test_value_expr_in_case + assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 1.3") + {# + x = + case a + when 1; return + when 2; return + else return + end + }; + end + + def test_value_expr_in_case2 + assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 1.3") + {# + x = + case + when 1; return + when 2; return + else return + end + }; + end + def test_tautological_condition assert_valid_syntax("def f() return if false and invalid; nil end") assert_valid_syntax("def f() return unless true or invalid; nil end") From 35b95ec2e2c1b377cb884c706fd0836328e5a90f Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Fri, 5 Dec 2025 19:18:58 +0900 Subject: [PATCH 10/17] [Bug #21669] Add more void value expression check for `if` If the both branches are void, the `if`/`unless` is also void. --- test/ruby/test_syntax.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index 3638d83e2bf351..a64591ececd933 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -2021,6 +2021,15 @@ def test_value_expr_in_condition assert_valid_syntax("tap {a = (true ? true : break)}") assert_valid_syntax("tap {a = (break if false)}") assert_valid_syntax("tap {a = (break unless true)}") + + assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 1.4") + {# + x = if rand < 0.5 + return + else + return + end + }; end def test_value_expr_in_singleton From baaf0ccb9c74d902d834c821c4d7e17e4bac4694 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Fri, 5 Dec 2025 18:52:34 +0900 Subject: [PATCH 11/17] [Bug #21669] Fix void value expression check for block A block containing a void statement that is not contained in a branch is also void. --- parse.y | 2 ++ test/ruby/test_syntax.rb | 46 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/parse.y b/parse.y index 63b6ab9b163652..a872eb61a339e8 100644 --- a/parse.y +++ b/parse.y @@ -13889,6 +13889,8 @@ value_expr_check(struct parser_params *p, NODE *node) case NODE_BLOCK: while (RNODE_BLOCK(node)->nd_next) { + vn = value_expr_check(p, RNODE_BLOCK(node)->nd_head); + if (vn) return vn; node = RNODE_BLOCK(node)->nd_next; } node = RNODE_BLOCK(node)->nd_head; diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index a64591ececd933..1ea646d2162899 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -2015,6 +2015,16 @@ def foo(*args) = super BUG_21669 = '[Bug #21669]' + def test_value_expr_in_block + assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 2.1") + {# + x = begin + return + "NG" + end + }; + end + def test_value_expr_in_condition mesg = /void value expression/ assert_syntax_error("tap {a = (true ? next : break)}", mesg) @@ -2030,6 +2040,42 @@ def test_value_expr_in_condition return end }; + + assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 2.2") + {# + x = if rand < 0.5 + return + "NG" + else + return + end + }; + + assert_valid_syntax("#{<<~"{#"}\n#{<<~'};'}", "#{BUG_21669} 2.3") + {# + x = begin + return if true + "OK" + end + }; + + assert_valid_syntax("#{<<~"{#"}\n#{<<~'};'}") + {# + x = if true + return "NG" + else + "OK" + end + }; + + assert_valid_syntax("#{<<~"{#"}\n#{<<~'};'}") + {# + x = if false + "OK" + else + return "NG" + end + }; end def test_value_expr_in_singleton From cb303ff4b82dca932cb7342e9f7fd337d69dc175 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Sat, 6 Dec 2025 08:48:29 +0900 Subject: [PATCH 12/17] [Bug #21669] Fix void value expression check for pattern-matching If the all `in` and `else` branches are void, the `case` is also void. --- parse.y | 26 ++++++++++++++++++-------- test/ruby/test_syntax.rb | 12 ++++++++++++ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/parse.y b/parse.y index a872eb61a339e8..b874e4f8dc9371 100644 --- a/parse.y +++ b/parse.y @@ -13877,15 +13877,25 @@ value_expr_check(struct parser_params *p, NODE *node) break; case NODE_CASE3: - if (!RNODE_CASE3(node)->nd_body || !nd_type_p(RNODE_CASE3(node)->nd_body, NODE_IN)) { - compile_error(p, "unexpected node"); - return NULL; - } - if (RNODE_IN(RNODE_CASE3(node)->nd_body)->nd_body) { - return NULL; + { + NODE *in = RNODE_CASE3(node)->nd_body; + if (!in || !nd_type_p(in, NODE_IN)) { + compile_error(p, "unexpected node"); + return NULL; + } + if (!RNODE_IN(in)->nd_body) { + /* single line pattern matching with "=>" operator */ + goto found; + } + do { + vn = value_expr_check(p, RNODE_IN(in)->nd_body); + if (!vn) return NULL; + if (!void_node) void_node = vn; + in = RNODE_IN(in)->nd_next; + } while (in && nd_type_p(in, NODE_IN)); + node = in; /* else */ } - /* single line pattern matching with "=>" operator */ - goto found; + break; case NODE_BLOCK: while (RNODE_BLOCK(node)->nd_next) { diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index 1ea646d2162899..e868967e8b7927 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -2132,6 +2132,18 @@ def test_value_expr_in_case2 }; end + def test_value_expr_in_case3 + assert_syntax_error("#{<<~"{#"}\n#{<<~'};'}", /void value expression/, nil, "#{BUG_21669} 1.3") + {# + x = + case a + in 1; return + in 2; return + else return + end + }; + end + def test_tautological_condition assert_valid_syntax("def f() return if false and invalid; nil end") assert_valid_syntax("def f() return unless true or invalid; nil end") From d26940e807844f9f64a964fbdc3ec6fb63998c58 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Wed, 4 Feb 2026 14:02:17 +0900 Subject: [PATCH 13/17] Revert "Comment out to disable ppc64le and s390x CI builds" This reverts commit e1655dad3a00a7b4026c653ff7c611811e7e34da. --- .github/workflows/ubuntu.yml | 48 ++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 0a4e19e229b9a0..2ed27e278b1dd4 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -177,30 +177,30 @@ jobs: SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot if: ${{ failure() }} - # make-ibm: - # strategy: - # matrix: - # include: - # - test_task: check - # os: ubuntu-24.04-ppc64le - # - test_task: check - # os: ubuntu-24.04-s390x - # fail-fast: false - - # env: *make-env - - # runs-on: ${{ matrix.os }} - - # if: >- - # ${{github.repository == 'ruby/ruby' - # && !(false - # || contains(github.event.head_commit.message, '[DOC]') - # || contains(github.event.pull_request.title, '[DOC]') - # || contains(github.event.pull_request.labels.*.name, 'Documentation') - # || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]') - # )}} - - # steps: *make-steps + make-ibm: + strategy: + matrix: + include: + - test_task: check + os: ubuntu-24.04-ppc64le + - test_task: check + os: ubuntu-24.04-s390x + fail-fast: false + + env: *make-env + + runs-on: ${{ matrix.os }} + + if: >- + ${{github.repository == 'ruby/ruby' + && !(false + || contains(github.event.head_commit.message, '[DOC]') + || contains(github.event.pull_request.title, '[DOC]') + || contains(github.event.pull_request.labels.*.name, 'Documentation') + || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]') + )}} + + steps: *make-steps # Separated from `make` job to avoid making it a required status check ruby-bench: From 779c3f928acd6d827b1d753ccb9e85c9e11e62bf Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Wed, 4 Feb 2026 12:04:20 +0900 Subject: [PATCH 14/17] Expand realpath to symlink when running with macOS Co-authored-by: Nobuyoshi Nakada --- spec/bundled_gems_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/bundled_gems_spec.rb b/spec/bundled_gems_spec.rb index d985ddad412e01..c02ae818e0d064 100644 --- a/spec/bundled_gems_spec.rb +++ b/spec/bundled_gems_spec.rb @@ -280,7 +280,7 @@ def my # Original issue is childprocess 5.0.0 and logger. build_lib "fileutils2", "5.0.0" do |s| # bootsnap expand required feature to full path - rubylibpath = File.expand_path(File.join(__dir__, "..", "lib")) + rubylibpath = File.realpath(File.join(__dir__, "..", "lib")) s.write "lib/fileutils2.rb", "require '#{rubylibpath}/fileutils'" end From e6483d98907654d015ececd5de6a0079084f8f33 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 3 Feb 2026 21:03:25 +0900 Subject: [PATCH 15/17] [ruby/rubygems] Added failing example https://github.com/ruby/rubygems/commit/73735b503c --- spec/bundler/install/gemfile/sources_spec.rb | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb index 69b0816a18999e..4957ef70be2cfe 100644 --- a/spec/bundler/install/gemfile/sources_spec.rb +++ b/spec/bundler/install/gemfile/sources_spec.rb @@ -1236,4 +1236,41 @@ expect(the_bundle).to include_gems("fallback_dep 1.0.0", source: "remote2") end end + + context "when a path gem has a transitive dependency that does not exist in the path source" do + before do + build_repo2 do + build_gem "missing_dep", "1.0.0" + build_gem "foo", "1.0.0" + end + + build_lib "parent_gem", "1.0.0", path: lib_path("parent_gem") do |s| + s.add_dependency "missing_dep" + end + + gemfile <<-G + source "https://gem.repo2" + + gem "foo" + + gem "parent_gem", path: "#{lib_path("parent_gem")}" + G + + bundle :install, artifice: "compact_index" + end + + it "falls back to the default rubygems source for that dependency when updating" do + build_repo2 do + build_gem "foo", "2.0.0" + end + + system_gems [] + + bundle "update foo", artifice: "compact_index" + + expect(the_bundle).to include_gems("parent_gem 1.0.0", "missing_dep 1.0.0", "foo 2.0.0") + expect(the_bundle).to include_gems("parent_gem 1.0.0", source: "path@#{lib_path("parent_gem")}") + expect(the_bundle).to include_gems("missing_dep 1.0.0", source: "remote2") + end + end end From 0c2ded4a07e0ba0e4d2d9ab92d549135300d495b Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Wed, 4 Feb 2026 10:51:06 +0900 Subject: [PATCH 16/17] [ruby/rubygems] Require parent path source to contain matching specs before selecting it as replacement https://github.com/ruby/rubygems/commit/7c89d2588d --- lib/bundler/definition.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 639740e46b6b04..3cf9fbe8bf03aa 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -1077,7 +1077,7 @@ def converge_specs(specs) end end - if parent_dep && parent_dep.source.is_a?(Source::Path) + if parent_dep && parent_dep.source.is_a?(Source::Path) && parent_dep.source.specs[s]&.any? replacement_source = parent_dep.source else replacement_source = sources.get(lockfile_source) From 03a17facfdd8c2bbcca5862fa98f51e9979b77ca Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 02:50:52 +0000 Subject: [PATCH 17/17] [ruby/rubygems] Add test case for git sources with transitive dependencies https://github.com/ruby/rubygems/commit/00c8bb7bc5 Co-authored-by: hsbt <12301+hsbt@users.noreply.github.com> --- spec/bundler/install/gemfile/sources_spec.rb | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb index 4957ef70be2cfe..c72a2b982a99ec 100644 --- a/spec/bundler/install/gemfile/sources_spec.rb +++ b/spec/bundler/install/gemfile/sources_spec.rb @@ -1273,4 +1273,41 @@ expect(the_bundle).to include_gems("missing_dep 1.0.0", source: "remote2") end end + + context "when a git gem has a transitive dependency that does not exist in the git source" do + before do + build_repo2 do + build_gem "missing_dep", "1.0.0" + build_gem "foo", "1.0.0" + end + + build_git "parent_gem", "1.0.0", path: lib_path("parent_gem") do |s| + s.add_dependency "missing_dep" + end + + gemfile <<-G + source "https://gem.repo2" + + gem "foo" + + gem "parent_gem", git: "#{lib_path("parent_gem")}" + G + + bundle :install, artifice: "compact_index" + end + + it "falls back to the default rubygems source for that dependency when updating" do + build_repo2 do + build_gem "foo", "2.0.0" + end + + system_gems [] + + bundle "update foo", artifice: "compact_index" + + expect(the_bundle).to include_gems("parent_gem 1.0.0", "missing_dep 1.0.0", "foo 2.0.0") + expect(the_bundle).to include_gems("parent_gem 1.0.0", source: "git@#{lib_path("parent_gem")}") + expect(the_bundle).to include_gems("missing_dep 1.0.0", source: "remote2") + end + end end