From eb62a3c878fe6af3e91c533fd93c48c0b51f0193 Mon Sep 17 00:00:00 2001 From: Colby Swandale <996377+colby-swandale@users.noreply.github.com> Date: Mon, 15 Dec 2025 16:06:22 +1100 Subject: [PATCH] Refactor rspec gem command to use new helper methods for uninstalling and listing installed gems --- bundler/spec/bundler/gem_helper_spec.rb | 2 +- bundler/spec/commands/check_spec.rb | 2 +- bundler/spec/commands/clean_spec.rb | 8 +-- .../spec/install/gems/compact_index_spec.rb | 2 +- bundler/spec/support/builders.rb | 2 +- bundler/spec/support/helpers.rb | 71 +++++++++++++++---- 6 files changed, 64 insertions(+), 23 deletions(-) diff --git a/bundler/spec/bundler/gem_helper_spec.rb b/bundler/spec/bundler/gem_helper_spec.rb index 94f66537d3eb..0e67afa1cf59 100644 --- a/bundler/spec/bundler/gem_helper_spec.rb +++ b/bundler/spec/bundler/gem_helper_spec.rb @@ -222,7 +222,7 @@ def sha512_hexdigest(path) mock_confirm_message "#{app_name} (#{app_version}) installed." subject.install_gem(nil, :local) expect(app_gem_path).to exist - gem_command :list + installed_gems_list expect(out).to include("#{app_name} (#{app_version})") end end diff --git a/bundler/spec/commands/check_spec.rb b/bundler/spec/commands/check_spec.rb index 72da24fb0b2d..4dce7813a624 100644 --- a/bundler/spec/commands/check_spec.rb +++ b/bundler/spec/commands/check_spec.rb @@ -164,7 +164,7 @@ bundle "config set --local path vendor/bundle" bundle :cache - gem_command "uninstall myrack", env: { "GEM_HOME" => vendored_gems.to_s } + uninstall_gem("myrack", env: { "GEM_HOME" => vendored_gems.to_s }) bundle "check", raise_on_error: false expect(err).to include("* myrack (1.0.0)") diff --git a/bundler/spec/commands/clean_spec.rb b/bundler/spec/commands/clean_spec.rb index 6b678d0aa545..b4541a5e77b9 100644 --- a/bundler/spec/commands/clean_spec.rb +++ b/bundler/spec/commands/clean_spec.rb @@ -379,7 +379,7 @@ def should_not_have_gems(*gems) gem "myrack" G - gem_command :list + installed_gems_list expect(out).to include("myrack (1.0.0)").and include("thin (1.0)") end @@ -498,7 +498,7 @@ def should_not_have_gems(*gems) end bundle :update, all: true - gem_command :list + installed_gems_list expect(out).to include("foo (1.0.1, 1.0)") end @@ -522,7 +522,7 @@ def should_not_have_gems(*gems) bundle "clean --force" expect(out).to include("Removing foo (1.0)") - gem_command :list + installed_gems_list expect(out).not_to include("foo (1.0)") expect(out).to include("myrack (1.0.0)") end @@ -556,7 +556,7 @@ def should_not_have_gems(*gems) expect(err).to include(system_gem_path.to_s) expect(err).to include("grant write permissions") - gem_command :list + installed_gems_list expect(out).to include("foo (1.0)") expect(out).to include("myrack (1.0.0)") end diff --git a/bundler/spec/install/gems/compact_index_spec.rb b/bundler/spec/install/gems/compact_index_spec.rb index bb4d4011f5b9..d082b9be72ce 100644 --- a/bundler/spec/install/gems/compact_index_spec.rb +++ b/bundler/spec/install/gems/compact_index_spec.rb @@ -997,7 +997,7 @@ def start gem "activemerchant" end G - gem_command "uninstall activemerchant" + uninstall_gem("activemerchant") bundle "update rails", artifice: "compact_index" count = lockfile.match?("CHECKSUMS") ? 2 : 1 # Once in the specs, and once in CHECKSUMS expect(lockfile.scan(/activemerchant \(/).size).to eq(count) diff --git a/bundler/spec/support/builders.rb b/bundler/spec/support/builders.rb index 6087ea8cc8c6..67b7e2e880e0 100644 --- a/bundler/spec/support/builders.rb +++ b/bundler/spec/support/builders.rb @@ -664,7 +664,7 @@ def _build(opts) Bundler.rubygems.build(@spec, opts[:skip_validation]) end elsif opts[:skip_validation] - @context.gem_command "build --force #{@spec.name}", dir: lib_path + Dir.chdir(lib_path) { Gem::Package.build(@spec, true) } else Dir.chdir(lib_path) { Gem::Package.build(@spec) } end diff --git a/bundler/spec/support/helpers.rb b/bundler/spec/support/helpers.rb index 52e6ff5d9a31..65cef858ee02 100644 --- a/bundler/spec/support/helpers.rb +++ b/bundler/spec/support/helpers.rb @@ -182,19 +182,6 @@ def gembin(cmd, options = {}) sys_exec(cmd.to_s, options) end - def gem_command(command, options = {}) - env = options[:env] || {} - env["RUBYOPT"] = opt_add(opt_add("-r#{hax}", env["RUBYOPT"]), ENV["RUBYOPT"]) - options[:env] = env - - # Sometimes `gem install` commands hang at dns resolution, which has a - # default timeout of 60 seconds. When that happens, the timeout for a - # command is expired too. So give `gem install` commands a bit more time. - options[:timeout] = 120 - - sys_exec("#{Path.gem_bin} #{command}", options) - end - def sys_exec(cmd, options = {}, &block) env = options[:env] || {} env["RUBYOPT"] = opt_add(opt_add("-r#{spec_dir}/support/switch_rubygems.rb", env["RUBYOPT"]), ENV["RUBYOPT"]) @@ -326,9 +313,17 @@ def self.install_dev_bundler def install_gem(path, install_dir, default = false) raise ArgumentError, "`#{path}` does not exist!" unless File.exist?(path) - args = "--no-document --ignore-dependencies --verbose --local --install-dir #{install_dir}" + require "rubygems/installer" - gem_command "install #{args} '#{path}'" + installer = Gem::Installer.at( + path.to_s, + install_dir: install_dir.to_s, + document: [], + ignore_dependencies: true, + wrappers: true, + force: true + ) + installer.install if default gem = Pathname.new(path).basename.to_s.match(/(.*)\.gem/)[1] @@ -343,6 +338,52 @@ def install_gem(path, install_dir, default = false) end end + def uninstall_gem(name, options = {}) + require "rubygems/uninstaller" + + gem_home = options.dig(:env, "GEM_HOME") || system_gem_path.to_s + + uninstaller = Gem::Uninstaller.new( + name, + install_dir: gem_home, + ignore: true, + executables: true, + all: true + ) + uninstaller.uninstall + end + + def installed_gems_list(options = {}) + gem_home = options.dig(:env, "GEM_HOME") || system_gem_path.to_s + + # Temporarily set GEM_HOME for the command + old_gem_home = ENV["GEM_HOME"] + ENV["GEM_HOME"] = gem_home + Gem.clear_paths + + begin + require "rubygems/commands/list_command" + + # Capture output from the list command + output_io = StringIO.new + cmd = Gem::Commands::ListCommand.new + cmd.ui = Gem::StreamUI.new(StringIO.new, output_io, StringIO.new, false) + cmd.invoke + output = output_io.string.strip + ensure + ENV["GEM_HOME"] = old_gem_home + Gem.clear_paths + end + + # Create a fake command execution so `out` helper works + command_execution = Spec::CommandExecution.new("gem list", timeout: 60) + command_execution.original_stdout << output + command_execution.exitstatus = 0 + command_executions << command_execution + + output + end + def with_built_bundler(version = nil, opts = {}, &block) require_relative "builders"