From fd9cee5fc39a858ab513a102c9b7f7296feeb860 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Thu, 23 Apr 2026 15:26:25 +0200 Subject: [PATCH 01/15] [ruby/prism] Fix incompatibilities for `on_word_sep` in ripper It was mostly good, just a few edgecases: * word_sep always only contains a single line. if there are multiple lines, it is also multiple word_sep * Handle trailing whitespace The excluded testcase is interpolation mixed with heredoc. That is not currently handled properly and word_sep contains the content of the heredoc I also switched start/end_offset names in the method, they seem to be backwards https://github.com/ruby/prism/commit/2e151ad41b --- lib/prism/translation/ripper.rb | 28 +++++++++++++++++++++------- test/prism/ruby/ripper_test.rb | 5 +++-- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/lib/prism/translation/ripper.rb b/lib/prism/translation/ripper.rb index b066f3e3accd21..00506d650e21a8 100644 --- a/lib/prism/translation/ripper.rb +++ b/lib/prism/translation/ripper.rb @@ -704,6 +704,8 @@ def visit_array_node(node) previous = element end + visit_words_sep(opening_loc, node.elements.last, node.closing_loc) + bounds(node.closing_loc) on_tstring_end(node.closing) when /^%i/ @@ -723,6 +725,8 @@ def visit_array_node(node) previous = element end + visit_words_sep(opening_loc, node.elements.last, node.closing_loc) + bounds(node.closing_loc) on_tstring_end(node.closing) when /^%W/ @@ -760,6 +764,8 @@ def visit_array_node(node) previous = element end + visit_words_sep(opening_loc, node.elements.last, node.closing_loc) + bounds(node.closing_loc) on_tstring_end(node.closing) when /^%I/ @@ -797,6 +803,8 @@ def visit_array_node(node) previous = element end + visit_words_sep(opening_loc, node.elements.last, node.closing_loc) + bounds(node.closing_loc) on_tstring_end(node.closing) else @@ -813,15 +821,21 @@ def visit_array_node(node) on_array(elements) end - # Dispatch a words_sep event that contains the space between the elements + # Dispatch words_sep events that contains the whitespace between the elements # of list literals. private def visit_words_sep(opening_loc, previous, current) - end_offset = (previous.nil? ? opening_loc : previous.location).end_offset - start_offset = current.location.start_offset - - if end_offset != start_offset - bounds(current.location.copy(start_offset: end_offset)) - on_words_sep(source.byteslice(end_offset...start_offset)) + start_offset = (previous.nil? ? opening_loc : previous.location).end_offset + end_offset = current.start_offset + length = end_offset - start_offset + + if length > 0 + whitespace = source.byteslice(start_offset, length) + current_offset = start_offset + whitespace.each_line do |part| + bounds(opening_loc.copy(start_offset: current_offset, length: part.bytesize)) + on_words_sep(part) + current_offset += part.bytesize + end end end diff --git a/test/prism/ruby/ripper_test.rb b/test/prism/ruby/ripper_test.rb index 61065e3ffc1808..cdb8375f96a38c 100644 --- a/test/prism/ruby/ripper_test.rb +++ b/test/prism/ruby/ripper_test.rb @@ -101,6 +101,7 @@ class RipperTest < TestCase "seattlerb/messy_op_asgn_lineno.txt", "seattlerb/op_asgn_primary_colon_const_command_call.txt", "seattlerb/parse_pattern_076.txt", + "seattlerb/pct_w_heredoc_interp_nested.txt", "tilde_heredocs.txt", "unparser/corpus/literal/assignment.txt", "unparser/corpus/literal/pattern.txt", @@ -138,11 +139,11 @@ def test_lex_ignored_missing_heredoc_end end end - UNSUPPORTED_EVENTS = %i[comma ignored_nl label_end nl semicolon sp words_sep ignored_sp] + UNSUPPORTED_EVENTS = %i[comma ignored_nl label_end nl semicolon sp ignored_sp] # Events that are currently not emitted SUPPORTED_EVENTS = Translation::Ripper::EVENTS - UNSUPPORTED_EVENTS # Events that assert against their line/column - CHECK_LOCATION_EVENTS = %i[kw op lbrace rbrace lbracket rbracket lparen rparen] + CHECK_LOCATION_EVENTS = %i[kw op lbrace rbrace lbracket rbracket lparen rparen words_sep] module Events attr_reader :events From 16ad249a2ea57952e2283382c7e055b261d43c57 Mon Sep 17 00:00:00 2001 From: Adrien Rey-Jarthon Date: Mon, 20 Apr 2026 09:20:39 +0200 Subject: [PATCH 02/15] [ruby/ipaddr] Fix private?, link_local? and loopback? methods to avoid mistaking public IPv6 as IPv4-mapped https://github.com/ruby/ipaddr/commit/c1383a3356 --- lib/ipaddr.rb | 10 +++++----- test/test_ipaddr.rb | 10 ++++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/ipaddr.rb b/lib/ipaddr.rb index 6b67d7eec6706a..cc550898d2876d 100644 --- a/lib/ipaddr.rb +++ b/lib/ipaddr.rb @@ -293,7 +293,7 @@ def loopback? @addr & 0xff000000 == 0x7f000000 # 127.0.0.1/8 when Socket::AF_INET6 @addr == 1 || # ::1 - (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && ( + (@addr >> 32 == 0xffff && ( @addr & 0xff000000 == 0x7f000000 # ::ffff:127.0.0.1/8 )) else @@ -314,10 +314,10 @@ def private? @addr & 0xffff0000 == 0xc0a80000 # 192.168.0.0/16 when Socket::AF_INET6 @addr & 0xfe00_0000_0000_0000_0000_0000_0000_0000 == 0xfc00_0000_0000_0000_0000_0000_0000_0000 || - (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && ( + (@addr >> 32 == 0xffff && ( @addr & 0xff000000 == 0x0a000000 || # ::ffff:10.0.0.0/8 - @addr & 0xfff00000 == 0xac100000 || # ::ffff::172.16.0.0/12 - @addr & 0xffff0000 == 0xc0a80000 # ::ffff::192.168.0.0/16 + @addr & 0xfff00000 == 0xac100000 || # ::ffff:172.16.0.0/12 + @addr & 0xffff0000 == 0xc0a80000 # ::ffff:192.168.0.0/16 )) else raise AddressFamilyError, "unsupported address family" @@ -335,7 +335,7 @@ def link_local? @addr & 0xffff0000 == 0xa9fe0000 # 169.254.0.0/16 when Socket::AF_INET6 @addr & 0xffc0_0000_0000_0000_0000_0000_0000_0000 == 0xfe80_0000_0000_0000_0000_0000_0000_0000 || # fe80::/10 - (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && ( + (@addr >> 32 == 0xffff && ( @addr & 0xffff0000 == 0xa9fe0000 # ::ffff:169.254.0.0/16 )) else diff --git a/test/test_ipaddr.rb b/test/test_ipaddr.rb index 4b7229fc17b686..c00626e3a76b93 100644 --- a/test/test_ipaddr.rb +++ b/test/test_ipaddr.rb @@ -533,6 +533,9 @@ def test_loopback? assert_equal(false, IPAddr.new('::ffff:0.0.0.0').loopback?) assert_equal(false, IPAddr.new('::ffff:192.168.2.0').loopback?) assert_equal(false, IPAddr.new('::ffff:255.0.0.0').loopback?) + + # Global unicast addresses with 0xffff in group 5 must not be mistaken for ::ffff:127.x.x.x + assert_equal(false, IPAddr.new('2001:db8:1:1:0:ffff:7f00:1').loopback?) end def test_private? @@ -583,6 +586,10 @@ def test_private? assert_equal(false, IPAddr.new('::ffff:192.169.0.0').private?) assert_equal(false, IPAddr.new('::ffff:169.254.0.1').private?) + + # Global unicast addresses with 0xffff in group 5 must not be mistaken for ::ffff:10/172.16/192.168.x + assert_equal(false, IPAddr.new('2001:718:1404:c8:0:ffff:ac19:c80e').private?) + assert_equal(false, IPAddr.new('2001:db8:1:1:0:ffff:c0a8:1').private?) end def test_link_local? @@ -609,6 +616,9 @@ def test_link_local? assert_equal(true, IPAddr.new('::ffff:169.254.1.1').link_local?) assert_equal(true, IPAddr.new('::ffff:169.254.254.255').link_local?) + + # Global unicast addresses with 0xffff in group 5 must not be mistaken for ::ffff:169.254.x.x + assert_equal(false, IPAddr.new('2001:db8:1:1:0:ffff:a9fe:101').link_local?) end def test_hash From f408ae9960252d08a25a7a48e51a915dd6c8fd94 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 2 Apr 2026 12:33:55 +0900 Subject: [PATCH 03/15] [ruby/rubygems] Add --[no-]build-extension and --[no-]install-plugin options to gem install These options allow users to opt out of building native extensions and installing plugins during gem installation, providing an equivalent to npm's --ignore-scripts for mitigating arbitrary code execution vectors. Both options default to true to maintain backward compatibility. Users can disable them per-command or globally via gemrc configuration. https://github.com/ruby/rubygems/commit/54221ab5b2 Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/rubygems/dependency_installer.rb | 4 ++ lib/rubygems/install_update_options.rb | 12 ++++++ lib/rubygems/installer.rb | 15 +++++++- lib/rubygems/request_set.rb | 2 +- test/rubygems/test_gem_installer.rb | 52 ++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 3 deletions(-) diff --git a/lib/rubygems/dependency_installer.rb b/lib/rubygems/dependency_installer.rb index 6a6dfa5c2031ba..c842714d9580f4 100644 --- a/lib/rubygems/dependency_installer.rb +++ b/lib/rubygems/dependency_installer.rb @@ -88,6 +88,8 @@ def initialize(options = {}) @dir_mode = options[:dir_mode] @data_mode = options[:data_mode] @prog_mode = options[:prog_mode] + @build_extension = options[:build_extension] + @install_plugin = options[:install_plugin] # Indicates that we should not try to update any deps unless # we absolutely must. @@ -169,6 +171,8 @@ def install(dep_or_name, version = Gem::Requirement.default) dir_mode: @dir_mode, data_mode: @data_mode, prog_mode: @prog_mode, + build_extension: @build_extension, + install_plugin: @install_plugin, } options[:install_dir] = @install_dir if @only_install_dir diff --git a/lib/rubygems/install_update_options.rb b/lib/rubygems/install_update_options.rb index 66cb5c049bcc03..e8859cadaf159d 100644 --- a/lib/rubygems/install_update_options.rb +++ b/lib/rubygems/install_update_options.rb @@ -192,6 +192,18 @@ def add_install_update_options "rbconfig.rb for the deployment target platform") do |v, _o| Gem.set_target_rbconfig(v) end + + add_option(:"Install/Update", "--[no-]build-extension", + "Build native extensions during installation.", + "Defaults to true") do |v, _o| + options[:build_extension] = v + end + + add_option(:"Install/Update", "--[no-]install-plugin", + "Install plugins during installation.", + "Defaults to true") do |v, _o| + options[:install_plugin] = v + end end ## diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 914e413677312a..730708fc335935 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -282,12 +282,16 @@ def install extract_files - build_extensions + if options[:build_extension] == false + warn_skipped_extensions + else + build_extensions + end write_build_info_file run_post_build_hooks generate_bin - generate_plugins + generate_plugins unless options[:install_plugin] == false write_spec write_cache_file @@ -809,6 +813,13 @@ def build_extensions builder.build_extensions end + def warn_skipped_extensions # :nodoc: + return if spec.extensions.empty? + + alert_warning "#{spec.full_name} contains native extensions that were not built.\n" \ + "To build extensions, run: gem install #{spec.name} --build-extension" + end + ## # Reads the file index and extracts each file into the gem directory. # diff --git a/lib/rubygems/request_set.rb b/lib/rubygems/request_set.rb index 5a855fdb104026..dbebd1af0c377e 100644 --- a/lib/rubygems/request_set.rb +++ b/lib/rubygems/request_set.rb @@ -182,7 +182,7 @@ def install(options, &block) # :yields: request, installer # Install requested gems after they have been downloaded sorted_requests.each do |req| if req.installed? && @always_install.none? {|spec| spec == req.spec.spec } - req.spec.spec.build_extensions + req.spec.spec.build_extensions unless options[:build_extension] == false yield req, nil if block_given? next end diff --git a/test/rubygems/test_gem_installer.rb b/test/rubygems/test_gem_installer.rb index f20771c5f02e0e..ca0a82a94e114a 100644 --- a/test/rubygems/test_gem_installer.rb +++ b/test/rubygems/test_gem_installer.rb @@ -2442,6 +2442,58 @@ def test_gem_attribute assert_kind_of(String, installer.gem) end + def test_install_no_build_extension + installer = util_setup_installer + + gemdir = File.join @gemhome, "gems", @spec.full_name + + installer.options[:build_extension] = false + + use_ui @ui do + installer.install + end + + assert_path_exist gemdir + assert_path_not_exist File.join(@spec.extension_dir, "gem.build_complete") + assert_match "contains native extensions that were not built", @ui.error + end + + def test_install_no_build_extension_without_extensions + spec = quick_gem "b", 2 + + util_build_gem spec + + installer = util_installer spec, @gemhome + installer.options[:build_extension] = false + + use_ui @ui do + installer.install + end + + refute_match "contains native extensions", @ui.error + end + + def test_install_no_install_plugin + installer = util_setup_installer do |spec| + write_file File.join(@tempdir, "lib", "rubygems_plugin.rb") do |io| + io.write "# do nothing" + end + + spec.files += %w[lib/rubygems_plugin.rb] + end + + installer.options[:install_plugin] = false + + build_rake_in do + use_ui @ui do + installer.install + end + end + + plugin_path = File.join Gem.plugindir, "a_plugin.rb" + refute File.exist?(plugin_path), "plugin must not be written when --no-install-plugin" + end + private def util_execless From 39c72051f33393f48fd5e8262de6d7a8242ddee1 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 2 Apr 2026 12:34:43 +0900 Subject: [PATCH 04/15] [ruby/rubygems] Check plugin file existence before loading in load_plugin When plugins are not installed (e.g. via --no-install-plugin), the plugin files do not exist on disk. Without this check, load_plugin would attempt to load non-existent files and produce spurious LoadError warnings. https://github.com/ruby/rubygems/commit/4a95bd2f29 Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/rubygems/installer.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 730708fc335935..fc708f1aa69dbd 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -1001,9 +1001,10 @@ def load_plugin # are loaded at the same time. return unless specs.size == 1 - plugin_files = spec.plugins.map do |plugin| - File.join(@plugins_dir, "#{spec.name}_plugin#{File.extname(plugin)}") + plugin_files = spec.plugins.filter_map do |plugin| + path = File.join(@plugins_dir, "#{spec.name}_plugin#{File.extname(plugin)}") + path if File.exist?(path) end - Gem.load_plugin_files(plugin_files) + Gem.load_plugin_files(plugin_files) unless plugin_files.empty? end end From 7a2c0892f9dc006bc571bbe3eb67213645e24983 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 2 Apr 2026 13:27:35 +0900 Subject: [PATCH 05/15] [ruby/rubygems] Support no_build_extension and no_install_plugin settings in Bundler Extend the --no-build-extension and --no-install-plugin support to Bundler's installation paths. RubyGemsGemInstaller#install now respects these options, and the settings are propagated from Bundler::Settings through Source::RubyGems to the installer. Path::Installer also respects no_build_extension for git/path sources. https://github.com/ruby/rubygems/commit/4172caa14a Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/bundler/rubygems_gem_installer.rb | 8 ++- lib/bundler/settings.rb | 2 + lib/bundler/source/path/installer.rb | 2 +- lib/bundler/source/rubygems.rb | 4 +- .../install/gems/no_build_extension_spec.rb | 52 +++++++++++++++++++ 5 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 spec/bundler/install/gems/no_build_extension_spec.rb diff --git a/lib/bundler/rubygems_gem_installer.rb b/lib/bundler/rubygems_gem_installer.rb index 12405869787360..dc904d43255e01 100644 --- a/lib/bundler/rubygems_gem_installer.rb +++ b/lib/bundler/rubygems_gem_installer.rb @@ -27,7 +27,11 @@ def install extract_files end - build_extensions if spec.extensions.any? + if options[:build_extension] == false + warn_skipped_extensions + elsif spec.extensions.any? + build_extensions + end write_build_info_file run_post_build_hooks @@ -35,7 +39,7 @@ def install generate_bin end - generate_plugins + generate_plugins unless options[:install_plugin] == false write_spec diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index 120a3202afd5dc..95b48da31e927a 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -30,7 +30,9 @@ class Settings init_gems_rb inline lockfile_checksums + no_build_extension no_install + no_install_plugin no_prune path.system plugins diff --git a/lib/bundler/source/path/installer.rb b/lib/bundler/source/path/installer.rb index 0af28fe7707126..39765e5da22970 100644 --- a/lib/bundler/source/path/installer.rb +++ b/lib/bundler/source/path/installer.rb @@ -24,7 +24,7 @@ def initialize(spec, options = {}) def post_install run_hooks(:pre_install) - unless @disable_extensions + unless @disable_extensions || Bundler.settings[:no_build_extension] build_extensions run_hooks(:post_build) end diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index cee5196f3082c9..b5c3b9169d1649 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -533,7 +533,9 @@ def rubygems_gem_installer(spec, options) wrappers: true, env_shebang: true, build_args: options[:build_args], - bundler_extension_cache_path: extension_cache_path(spec) + bundler_extension_cache_path: extension_cache_path(spec), + build_extension: Bundler.settings[:no_build_extension] ? false : nil, + install_plugin: Bundler.settings[:no_install_plugin] ? false : nil ) @gem_installers_mutex.synchronize { @gem_installers[spec.name] ||= installer } end diff --git a/spec/bundler/install/gems/no_build_extension_spec.rb b/spec/bundler/install/gems/no_build_extension_spec.rb new file mode 100644 index 00000000000000..38b570ef90f858 --- /dev/null +++ b/spec/bundler/install/gems/no_build_extension_spec.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +RSpec.describe "bundle install with --no-build-extension" do + before do + build_repo2 do + build_gem "with_extension" do |s| + s.extensions << "Rakefile" + s.write "Rakefile", <<-RUBY + task :default do + path = File.expand_path("lib", __dir__) + FileUtils.mkdir_p(path) + File.open("\#{path}/with_extension.rb", "w") do |f| + f.puts "WITH_EXTENSION = 'YES'" + end + end + RUBY + end + end + end + + it "skips building native extensions when no_build_extension is set" do + bundle_config "no_build_extension true" + + gemfile <<-G + source "https://gem.repo2" + gem "with_extension" + gem "rake" + G + + bundle :install + + build_complete = default_bundle_path("extensions").join( + Gem::Platform.local.to_s, + Gem.extension_api_version.to_s, + "with_extension-1.0", + "gem.build_complete" + ) + expect(build_complete).not_to exist + end + + it "builds native extensions by default" do + gemfile <<-G + source "https://gem.repo2" + gem "with_extension" + gem "rake" + G + + bundle :install + + expect(out).to include("Installing with_extension 1.0 with native extensions") + end +end From fe51923c880217dbadb63957df3e14916d79fdc0 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 9 Apr 2026 09:40:17 +0900 Subject: [PATCH 06/15] [ruby/rubygems] Add warnings with recovery instructions when skipping extensions or plugins When extensions or plugins are skipped via --no-build-extension or --no-install-plugin, warn the user and point them to the appropriate gem pristine command to re-enable later. https://github.com/ruby/rubygems/commit/d2e7f125db Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/bundler/rubygems_gem_installer.rb | 6 +++++- lib/rubygems/installer.rb | 15 +++++++++++++-- test/rubygems/test_gem_installer.rb | 17 +++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/lib/bundler/rubygems_gem_installer.rb b/lib/bundler/rubygems_gem_installer.rb index dc904d43255e01..c6d49e133aef4d 100644 --- a/lib/bundler/rubygems_gem_installer.rb +++ b/lib/bundler/rubygems_gem_installer.rb @@ -39,7 +39,11 @@ def install generate_bin end - generate_plugins unless options[:install_plugin] == false + if options[:install_plugin] == false + warn_skipped_plugins + else + generate_plugins + end write_spec diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index fc708f1aa69dbd..6baa47fa17d039 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -291,7 +291,11 @@ def install run_post_build_hooks generate_bin - generate_plugins unless options[:install_plugin] == false + if options[:install_plugin] == false + warn_skipped_plugins + else + generate_plugins + end write_spec write_cache_file @@ -817,7 +821,14 @@ def warn_skipped_extensions # :nodoc: return if spec.extensions.empty? alert_warning "#{spec.full_name} contains native extensions that were not built.\n" \ - "To build extensions, run: gem install #{spec.name} --build-extension" + "To build extensions, run: gem pristine #{spec.name} --extensions" + end + + def warn_skipped_plugins # :nodoc: + return if spec.plugins.empty? + + alert_warning "#{spec.full_name} contains plugins that were not installed.\n" \ + "To install plugins, run: gem pristine #{spec.name} --only-plugins" end ## diff --git a/test/rubygems/test_gem_installer.rb b/test/rubygems/test_gem_installer.rb index ca0a82a94e114a..424c13a1b7421e 100644 --- a/test/rubygems/test_gem_installer.rb +++ b/test/rubygems/test_gem_installer.rb @@ -2456,6 +2456,7 @@ def test_install_no_build_extension assert_path_exist gemdir assert_path_not_exist File.join(@spec.extension_dir, "gem.build_complete") assert_match "contains native extensions that were not built", @ui.error + assert_match "gem pristine #{@spec.name} --extensions", @ui.error end def test_install_no_build_extension_without_extensions @@ -2492,6 +2493,22 @@ def test_install_no_install_plugin plugin_path = File.join Gem.plugindir, "a_plugin.rb" refute File.exist?(plugin_path), "plugin must not be written when --no-install-plugin" + assert_match "contains plugins that were not installed", @ui.error + assert_match "gem pristine #{@spec.name} --only-plugins", @ui.error + end + + def test_install_no_install_plugin_without_plugins + installer = util_setup_installer + + installer.options[:install_plugin] = false + + build_rake_in do + use_ui @ui do + installer.install + end + end + + refute_match "contains plugins", @ui.error end private From 19a0fe5146bae38132eca902bfad03656f193b53 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 9 Apr 2026 09:54:26 +0900 Subject: [PATCH 07/15] [ruby/rubygems] Skip load_plugin when --no-install-plugin is specified Without this change, reinstalling or upgrading a gem with --no-install-plugin would still execute a pre-existing plugin wrapper left by a previous install via load_plugin. This defeats the opt-out. https://github.com/ruby/rubygems/commit/198b01ee2a Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/rubygems/installer.rb | 2 +- test/rubygems/test_gem_installer.rb | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 6baa47fa17d039..b27dea601f106a 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -306,7 +306,7 @@ def install Gem::Specification.add_spec(spec) unless @install_dir - load_plugin + load_plugin unless options[:install_plugin] == false run_post_install_hooks diff --git a/test/rubygems/test_gem_installer.rb b/test/rubygems/test_gem_installer.rb index 424c13a1b7421e..083f9bf3e864d2 100644 --- a/test/rubygems/test_gem_installer.rb +++ b/test/rubygems/test_gem_installer.rb @@ -2497,6 +2497,34 @@ def test_install_no_install_plugin assert_match "gem pristine #{@spec.name} --only-plugins", @ui.error end + def test_install_no_install_plugin_skips_load_plugin + installer = util_setup_installer do |spec| + write_file File.join(@tempdir, "lib", "rubygems_plugin.rb") do |io| + io.write "$no_install_plugin_test_loaded = true" + end + + spec.files += %w[lib/rubygems_plugin.rb] + end + + # Simulate a pre-existing plugin wrapper from a previous install + FileUtils.mkdir_p Gem.plugindir + plugin_path = File.join Gem.plugindir, "a_plugin.rb" + File.write(plugin_path, "require_relative '../../gems/#{@spec.full_name}/lib/rubygems_plugin'") + + installer.options[:install_plugin] = false + + build_rake_in do + use_ui @ui do + installer.install + end + end + + refute defined?($no_install_plugin_test_loaded) && $no_install_plugin_test_loaded, + "plugin must not be loaded when --no-install-plugin" + ensure + $no_install_plugin_test_loaded = nil + end + def test_install_no_install_plugin_without_plugins installer = util_setup_installer From c6166528204674cc0c517de1b7afa79a40e0bdab Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Mon, 13 Apr 2026 09:32:36 +0900 Subject: [PATCH 08/15] [ruby/rubygems] Document no_build_extension and no_install_plugin settings in bundle-config The quality spec requires all Bundler settings to be documented in the bundle-config man page. https://github.com/ruby/rubygems/commit/48d494326f Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/bundler/man/bundle-config.1 | 6 ++++++ lib/bundler/man/bundle-config.1.ronn | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1 index 626f0811d24962..ca312cfe00202b 100644 --- a/lib/bundler/man/bundle-config.1 +++ b/lib/bundler/man/bundle-config.1 @@ -154,9 +154,15 @@ The path to the lockfile that bundler should use\. By default, Bundler adds \fB\ \fBlockfile_checksums\fR (\fBBUNDLE_LOCKFILE_CHECKSUMS\fR) Whether Bundler should include a checksums section in new lockfiles, to protect from compromised gem sources\. Defaults to true\. .TP +\fBno_build_extension\fR (\fBBUNDLE_NO_BUILD_EXTENSION\fR) +Whether Bundler should skip building native extensions during installation\. When set, gems are installed without compiling their C extensions\. To build extensions later, run \fBgem pristine \-\-extensions\fR\. +.TP \fBno_install\fR (\fBBUNDLE_NO_INSTALL\fR) Whether \fBbundle package\fR should skip installing gems\. .TP +\fBno_install_plugin\fR (\fBBUNDLE_NO_INSTALL_PLUGIN\fR) +Whether Bundler should skip installing RubyGems plugins during installation\. When set, plugin files are not written to the plugins directory\. To install plugins later, run \fBgem pristine \-\-only\-plugins\fR\. +.TP \fBno_prune\fR (\fBBUNDLE_NO_PRUNE\fR) Whether Bundler should leave outdated gems unpruned when caching\. .TP diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn index c01e836f96b5a6..1909bd7013fe8d 100644 --- a/lib/bundler/man/bundle-config.1.ronn +++ b/lib/bundler/man/bundle-config.1.ronn @@ -200,8 +200,16 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). Gemfile to disable lockfile creation entirely (see gemfile(5)). * `lockfile_checksums` (`BUNDLE_LOCKFILE_CHECKSUMS`): Whether Bundler should include a checksums section in new lockfiles, to protect from compromised gem sources. Defaults to true. +* `no_build_extension` (`BUNDLE_NO_BUILD_EXTENSION`): + Whether Bundler should skip building native extensions during installation. + When set, gems are installed without compiling their C extensions. + To build extensions later, run `gem pristine --extensions`. * `no_install` (`BUNDLE_NO_INSTALL`): Whether `bundle package` should skip installing gems. +* `no_install_plugin` (`BUNDLE_NO_INSTALL_PLUGIN`): + Whether Bundler should skip installing RubyGems plugins during installation. + When set, plugin files are not written to the plugins directory. + To install plugins later, run `gem pristine --only-plugins`. * `no_prune` (`BUNDLE_NO_PRUNE`): Whether Bundler should leave outdated gems unpruned when caching. * `only` (`BUNDLE_ONLY`): From ab9d60c4082e1647479a908d01ba7357f2049928 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Mon, 13 Apr 2026 09:36:31 +0900 Subject: [PATCH 09/15] [ruby/rubygems] Add Bundler spec for no_install_plugin setting https://github.com/ruby/rubygems/commit/0659cc7739 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../install/gems/no_install_plugin_spec.rb | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 spec/bundler/install/gems/no_install_plugin_spec.rb diff --git a/spec/bundler/install/gems/no_install_plugin_spec.rb b/spec/bundler/install/gems/no_install_plugin_spec.rb new file mode 100644 index 00000000000000..ca9df18b5179ca --- /dev/null +++ b/spec/bundler/install/gems/no_install_plugin_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +RSpec.describe "bundle install with --no-install-plugin" do + before do + build_repo2 do + build_gem "with_plugin" do |s| + s.write "lib/rubygems_plugin.rb", "# plugin code" + end + end + end + + it "skips installing plugins when no_install_plugin is set" do + bundle_config "no_install_plugin true" + + gemfile <<-G + source "https://gem.repo2" + gem "with_plugin" + G + + bundle :install + + plugin_path = default_bundle_path("plugins", "with_plugin_plugin.rb") + expect(plugin_path).not_to exist + end + + it "installs plugins by default" do + gemfile <<-G + source "https://gem.repo2" + gem "with_plugin" + G + + bundle :install + + plugin_path = default_bundle_path("plugins", "with_plugin_plugin.rb") + expect(plugin_path).to exist + end +end From 8dc707519f24df1cc54c8bddea70d5ab48de1059 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Mon, 13 Apr 2026 09:37:53 +0900 Subject: [PATCH 10/15] [ruby/rubygems] Remove stale plugin wrappers even when --no-install-plugin is specified When a gem upgrades from a version with plugins to one without, generate_plugins normally removes the old wrapper files. Skipping generate_plugins entirely with --no-install-plugin prevented this cleanup, leaving stale wrappers that would still be loaded. https://github.com/ruby/rubygems/commit/982fc8f7d2 Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/bundler/rubygems_gem_installer.rb | 1 + lib/rubygems/installer.rb | 8 +++++++ test/rubygems/test_gem_installer.rb | 33 +++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/lib/bundler/rubygems_gem_installer.rb b/lib/bundler/rubygems_gem_installer.rb index c6d49e133aef4d..ce7054b4db1405 100644 --- a/lib/bundler/rubygems_gem_installer.rb +++ b/lib/bundler/rubygems_gem_installer.rb @@ -40,6 +40,7 @@ def install end if options[:install_plugin] == false + remove_stale_plugins warn_skipped_plugins else generate_plugins diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index b27dea601f106a..c9b51e37aca901 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -292,6 +292,7 @@ def install generate_bin if options[:install_plugin] == false + remove_stale_plugins warn_skipped_plugins else generate_plugins @@ -831,6 +832,13 @@ def warn_skipped_plugins # :nodoc: "To install plugins, run: gem pristine #{spec.name} --only-plugins" end + def remove_stale_plugins # :nodoc: + return unless spec.plugins.empty? + + ensure_writable_dir @plugins_dir + remove_plugins_for(spec, @plugins_dir) + end + ## # Reads the file index and extracts each file into the gem directory. # diff --git a/test/rubygems/test_gem_installer.rb b/test/rubygems/test_gem_installer.rb index 083f9bf3e864d2..4cdc9479f722fa 100644 --- a/test/rubygems/test_gem_installer.rb +++ b/test/rubygems/test_gem_installer.rb @@ -2539,6 +2539,39 @@ def test_install_no_install_plugin_without_plugins refute_match "contains plugins", @ui.error end + def test_install_no_install_plugin_removes_stale_wrappers + # First install a version with a plugin + installer = util_setup_installer do |spec| + write_file File.join(@tempdir, "lib", "rubygems_plugin.rb") do |io| + io.write "# plugin code" + end + + spec.files += %w[lib/rubygems_plugin.rb] + end + + build_rake_in do + use_ui @ui do + installer.install + end + end + + plugin_path = File.join Gem.plugindir, "a_plugin.rb" + assert File.exist?(plugin_path), "plugin wrapper should exist after first install" + + # Now install a new version without plugins, using --no-install-plugin + spec2 = quick_gem "a", 3 + util_build_gem spec2 + + installer2 = util_installer spec2, @gemhome + installer2.options[:install_plugin] = false + + use_ui @ui do + installer2.install + end + + refute File.exist?(plugin_path), "stale plugin wrapper must be removed" + end + private def util_execless From a3c2ff3e335d2a8d4eee3563f251ef504ceb8029 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Mon, 13 Apr 2026 09:39:19 +0900 Subject: [PATCH 11/15] [ruby/rubygems] Add no_build_extension and no_install_plugin specs to windows_tag_group https://github.com/ruby/rubygems/commit/51d3b3e76a Co-Authored-By: Claude Opus 4.6 (1M context) --- spec/bundler/support/windows_tag_group.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/bundler/support/windows_tag_group.rb b/spec/bundler/support/windows_tag_group.rb index f1a78f23e8d37e..b91deb7ed3e6f2 100644 --- a/spec/bundler/support/windows_tag_group.rb +++ b/spec/bundler/support/windows_tag_group.rb @@ -187,6 +187,8 @@ module WindowsTagGroup "spec/bundler/digest_spec.rb", "spec/bundler/fetcher/gem_remote_fetcher_spec.rb", "spec/bundler/uri_normalizer_spec.rb", + "spec/install/gems/no_build_extension_spec.rb", + "spec/install/gems/no_install_plugin_spec.rb", ], }.freeze end From 487ea390e07eab22a91aba5634f9af79682a91da Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 16 Apr 2026 17:36:29 +0900 Subject: [PATCH 12/15] [ruby/rubygems] Honor --no-build-extension for git-sourced gems Gem::Resolver::GitSpecification#install calls Gem::Installer#build_extensions directly, so the guard at the main install path did not cover git sources. Move the options check into build_extensions itself so every caller skips the build and emits the same warning when the option is set. https://github.com/ruby/rubygems/commit/de76e0f63a Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/rubygems/installer.rb | 11 +++--- .../test_gem_resolver_git_specification.rb | 38 +++++++++++++++++++ 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index c9b51e37aca901..15d6aac0fd1ba0 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -282,11 +282,7 @@ def install extract_files - if options[:build_extension] == false - warn_skipped_extensions - else - build_extensions - end + build_extensions write_build_info_file run_post_build_hooks @@ -813,6 +809,11 @@ def windows_stub_script(bindir, bin_file_name) # configure scripts and rakefiles or mkrf_conf files. def build_extensions + if options[:build_extension] == false + warn_skipped_extensions + return + end + builder = Gem::Ext::Builder.new spec, build_args, Gem.target_rbconfig, build_jobs builder.build_extensions diff --git a/test/rubygems/test_gem_resolver_git_specification.rb b/test/rubygems/test_gem_resolver_git_specification.rb index 621333d3bf51fd..e03c61e27ddc23 100644 --- a/test/rubygems/test_gem_resolver_git_specification.rb +++ b/test/rubygems/test_gem_resolver_git_specification.rb @@ -97,6 +97,44 @@ def test_install_extension assert_path_exist File.join git_spec.spec.extension_dir, "b.rb" end + def test_install_no_build_extension + pend if Gem.java_platform? + pend "terminates on mswin" if vc_windows? && ruby_repo? + name, _, repository, = git_gem "a", 1 do |s| + s.extensions << "ext/extconf.rb" + end + + Dir.chdir "git/a" do + FileUtils.mkdir_p "ext/lib" + + File.open "ext/extconf.rb", "w" do |io| + io.puts 'require "mkmf"' + io.puts 'create_makefile "a"' + end + + FileUtils.touch "ext/lib/b.rb" + + system @git, "add", "ext/extconf.rb" + system @git, "add", "ext/lib/b.rb" + + system @git, "commit", "--quiet", "-m", "Add extension files" + end + + source = Gem::Source::Git.new name, repository, nil, true + + spec = source.specs.first + + git_spec = Gem::Resolver::GitSpecification.new @set, spec, source + + use_ui @ui do + git_spec.install(build_extension: false) + end + + assert_path_not_exist File.join(git_spec.spec.extension_dir, "b.rb") + assert_match "contains native extensions that were not built", @ui.error + assert_match "gem pristine #{git_spec.spec.name} --extensions", @ui.error + end + def test_install_installed git_gem "a", 1 From 7844f72f20bdb18989f4006b235fb786eb47b29b Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 16 Apr 2026 17:44:21 +0900 Subject: [PATCH 13/15] [ruby/rubygems] Cover stale plugin wrapper removal in no_install_plugin spec The existing spec only checked that the wrapper is skipped on a fresh install. Add a version upgrade case so that when a later version of the gem no longer ships plugins, the previously generated wrapper is removed even though no_install_plugin is set. https://github.com/ruby/rubygems/commit/c5f3a48344 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../install/gems/no_install_plugin_spec.rb | 38 +++++++++++++------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/spec/bundler/install/gems/no_install_plugin_spec.rb b/spec/bundler/install/gems/no_install_plugin_spec.rb index ca9df18b5179ca..f3309eddbee7bb 100644 --- a/spec/bundler/install/gems/no_install_plugin_spec.rb +++ b/spec/bundler/install/gems/no_install_plugin_spec.rb @@ -3,35 +3,49 @@ RSpec.describe "bundle install with --no-install-plugin" do before do build_repo2 do - build_gem "with_plugin" do |s| + build_gem "with_plugin", "1.0" do |s| s.write "lib/rubygems_plugin.rb", "# plugin code" end + + build_gem "with_plugin", "2.0" end end - it "skips installing plugins when no_install_plugin is set" do + let(:plugin_path) { default_bundle_path("plugins", "with_plugin_plugin.rb") } + + it "does not generate the plugin wrapper when no_install_plugin is set" do bundle_config "no_install_plugin true" - gemfile <<-G + install_gemfile <<-G source "https://gem.repo2" - gem "with_plugin" + gem "with_plugin", "1.0" G - bundle :install - - plugin_path = default_bundle_path("plugins", "with_plugin_plugin.rb") expect(plugin_path).not_to exist end - it "installs plugins by default" do - gemfile <<-G + it "removes a stale plugin wrapper from a prior version when no_install_plugin is set" do + install_gemfile <<-G source "https://gem.repo2" - gem "with_plugin" + gem "with_plugin", "1.0" G + expect(plugin_path).to exist - bundle :install + bundle_config "no_install_plugin true" + install_gemfile <<-G + source "https://gem.repo2" + gem "with_plugin", "2.0" + G + + expect(plugin_path).not_to exist + end + + it "generates the plugin wrapper by default" do + install_gemfile <<-G + source "https://gem.repo2" + gem "with_plugin", "1.0" + G - plugin_path = default_bundle_path("plugins", "with_plugin_plugin.rb") expect(plugin_path).to exist end end From 11e0e7ccdc5f00813c07569a0b304991099f9344 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 16 Apr 2026 18:03:14 +0900 Subject: [PATCH 14/15] [ruby/rubygems] Point recovery instructions at bundle pristine under Bundler gem pristine does not reach gems that Bundler installed under BUNDLE_PATH, so the guidance emitted when no_build_extension or no_install_plugin is set needs a Bundler-native equivalent. Override warn_skipped_extensions and warn_skipped_plugins in RubyGemsGemInstaller so they advise unsetting the matching Bundler setting and running bundle pristine, and update the bundle-config man page to match. https://github.com/ruby/rubygems/commit/8549874e53 Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/bundler/man/bundle-config.1 | 4 ++-- lib/bundler/man/bundle-config.1.ronn | 4 ++-- lib/bundler/rubygems_gem_installer.rb | 14 ++++++++++++++ .../install/gems/no_build_extension_spec.rb | 4 +++- .../bundler/install/gems/no_install_plugin_spec.rb | 4 +++- 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1 index ca312cfe00202b..8835ae75bd9e92 100644 --- a/lib/bundler/man/bundle-config.1 +++ b/lib/bundler/man/bundle-config.1 @@ -155,13 +155,13 @@ The path to the lockfile that bundler should use\. By default, Bundler adds \fB\ Whether Bundler should include a checksums section in new lockfiles, to protect from compromised gem sources\. Defaults to true\. .TP \fBno_build_extension\fR (\fBBUNDLE_NO_BUILD_EXTENSION\fR) -Whether Bundler should skip building native extensions during installation\. When set, gems are installed without compiling their C extensions\. To build extensions later, run \fBgem pristine \-\-extensions\fR\. +Whether Bundler should skip building native extensions during installation\. When set, gems are installed without compiling their C extensions\. To build extensions later, unset this setting and run \fBbundle pristine \fR\. .TP \fBno_install\fR (\fBBUNDLE_NO_INSTALL\fR) Whether \fBbundle package\fR should skip installing gems\. .TP \fBno_install_plugin\fR (\fBBUNDLE_NO_INSTALL_PLUGIN\fR) -Whether Bundler should skip installing RubyGems plugins during installation\. When set, plugin files are not written to the plugins directory\. To install plugins later, run \fBgem pristine \-\-only\-plugins\fR\. +Whether Bundler should skip installing RubyGems plugins during installation\. When set, plugin files are not written to the plugins directory\. To install plugins later, unset this setting and run \fBbundle pristine \fR\. .TP \fBno_prune\fR (\fBBUNDLE_NO_PRUNE\fR) Whether Bundler should leave outdated gems unpruned when caching\. diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn index 1909bd7013fe8d..9657e7414514ef 100644 --- a/lib/bundler/man/bundle-config.1.ronn +++ b/lib/bundler/man/bundle-config.1.ronn @@ -203,13 +203,13 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). * `no_build_extension` (`BUNDLE_NO_BUILD_EXTENSION`): Whether Bundler should skip building native extensions during installation. When set, gems are installed without compiling their C extensions. - To build extensions later, run `gem pristine --extensions`. + To build extensions later, unset this setting and run `bundle pristine `. * `no_install` (`BUNDLE_NO_INSTALL`): Whether `bundle package` should skip installing gems. * `no_install_plugin` (`BUNDLE_NO_INSTALL_PLUGIN`): Whether Bundler should skip installing RubyGems plugins during installation. When set, plugin files are not written to the plugins directory. - To install plugins later, run `gem pristine --only-plugins`. + To install plugins later, unset this setting and run `bundle pristine `. * `no_prune` (`BUNDLE_NO_PRUNE`): Whether Bundler should leave outdated gems unpruned when caching. * `only` (`BUNDLE_ONLY`): diff --git a/lib/bundler/rubygems_gem_installer.rb b/lib/bundler/rubygems_gem_installer.rb index ce7054b4db1405..e4dd2d95afa3db 100644 --- a/lib/bundler/rubygems_gem_installer.rb +++ b/lib/bundler/rubygems_gem_installer.rb @@ -89,6 +89,20 @@ def generate_plugins end end + def warn_skipped_extensions + return if spec.extensions.empty? + + Bundler.ui.warn "#{spec.full_name} contains native extensions that were not built.\n" \ + "To build extensions, unset no_build_extension and run `bundle pristine #{spec.name}`." + end + + def warn_skipped_plugins + return if spec.plugins.empty? + + Bundler.ui.warn "#{spec.full_name} contains plugins that were not installed.\n" \ + "To install plugins, unset no_install_plugin and run `bundle pristine #{spec.name}`." + end + if Bundler.rubygems.provides?("< 3.5.19") def generate_bin_script(filename, bindir) bin_script_path = File.join bindir, formatted_program_filename(filename) diff --git a/spec/bundler/install/gems/no_build_extension_spec.rb b/spec/bundler/install/gems/no_build_extension_spec.rb index 38b570ef90f858..31f01704339a34 100644 --- a/spec/bundler/install/gems/no_build_extension_spec.rb +++ b/spec/bundler/install/gems/no_build_extension_spec.rb @@ -18,7 +18,7 @@ end end - it "skips building native extensions when no_build_extension is set" do + it "skips building native extensions and warns when no_build_extension is set" do bundle_config "no_build_extension true" gemfile <<-G @@ -36,6 +36,8 @@ "gem.build_complete" ) expect(build_complete).not_to exist + expect(err).to include("with_extension-1.0 contains native extensions that were not built") + expect(err).to include("unset no_build_extension and run `bundle pristine with_extension`") end it "builds native extensions by default" do diff --git a/spec/bundler/install/gems/no_install_plugin_spec.rb b/spec/bundler/install/gems/no_install_plugin_spec.rb index f3309eddbee7bb..e040e6b813e83b 100644 --- a/spec/bundler/install/gems/no_install_plugin_spec.rb +++ b/spec/bundler/install/gems/no_install_plugin_spec.rb @@ -13,7 +13,7 @@ let(:plugin_path) { default_bundle_path("plugins", "with_plugin_plugin.rb") } - it "does not generate the plugin wrapper when no_install_plugin is set" do + it "does not generate the plugin wrapper and warns when no_install_plugin is set" do bundle_config "no_install_plugin true" install_gemfile <<-G @@ -22,6 +22,8 @@ G expect(plugin_path).not_to exist + expect(err).to include("with_plugin-1.0 contains plugins that were not installed") + expect(err).to include("unset no_install_plugin and run `bundle pristine with_plugin`") end it "removes a stale plugin wrapper from a prior version when no_install_plugin is set" do From 7e1039e191550869aa146a4895af2db48b506882 Mon Sep 17 00:00:00 2001 From: y-onishi Date: Thu, 23 Apr 2026 19:57:36 +0900 Subject: [PATCH 15/15] [ruby/rubygems] Update gem creation guide URL to rubygems.org Update the gem creation guide links in the CLI output and gemspac template. The previous Bundler guide URL now redirects to RubyGems Guides. https://github.com/ruby/rubygems/commit/0b469edf03 --- lib/bundler/cli/gem.rb | 2 +- lib/bundler/templates/newgem/newgem.gemspec.tt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/bundler/cli/gem.rb b/lib/bundler/cli/gem.rb index 79344314fe4950..3f9432db3a810d 100644 --- a/lib/bundler/cli/gem.rb +++ b/lib/bundler/cli/gem.rb @@ -288,7 +288,7 @@ def run open_editor(options["edit"], target.join("#{name}.gemspec")) if options[:edit] Bundler.ui.info "\nGem '#{name}' was successfully created. " \ - "For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html" + "For more information on making a RubyGem visit https://guides.rubygems.org/make-your-own-gem/" end private diff --git a/lib/bundler/templates/newgem/newgem.gemspec.tt b/lib/bundler/templates/newgem/newgem.gemspec.tt index fabb308043c9c4..b81ecec624af0a 100644 --- a/lib/bundler/templates/newgem/newgem.gemspec.tt +++ b/lib/bundler/templates/newgem/newgem.gemspec.tt @@ -54,5 +54,5 @@ Gem::Specification.new do |spec| <%- end -%> # For more information and examples about making a new gem, check out our - # guide at: https://bundler.io/guides/creating_gem.html + # guide at: https://guides.rubygems.org/make-your-own-gem/ end