diff options
Diffstat (limited to 'spec/bundler/runtime')
| -rw-r--r-- | spec/bundler/runtime/env_helpers_spec.rb (renamed from spec/bundler/runtime/with_unbundled_env_spec.rb) | 132 | ||||
| -rw-r--r-- | spec/bundler/runtime/executable_spec.rb | 116 | ||||
| -rw-r--r-- | spec/bundler/runtime/gem_tasks_spec.rb | 86 | ||||
| -rw-r--r-- | spec/bundler/runtime/inline_spec.rb | 382 | ||||
| -rw-r--r-- | spec/bundler/runtime/load_spec.rb | 30 | ||||
| -rw-r--r-- | spec/bundler/runtime/platform_spec.rb | 184 | ||||
| -rw-r--r-- | spec/bundler/runtime/require_spec.rb | 149 | ||||
| -rw-r--r-- | spec/bundler/runtime/requiring_spec.rb | 15 | ||||
| -rw-r--r-- | spec/bundler/runtime/self_management_spec.rb | 217 | ||||
| -rw-r--r-- | spec/bundler/runtime/setup_spec.rb | 707 |
10 files changed, 1238 insertions, 780 deletions
diff --git a/spec/bundler/runtime/with_unbundled_env_spec.rb b/spec/bundler/runtime/env_helpers_spec.rb index 731a9921a2..c4ebdd1fd2 100644 --- a/spec/bundler/runtime/with_unbundled_env_spec.rb +++ b/spec/bundler/runtime/env_helpers_spec.rb @@ -1,14 +1,14 @@ # frozen_string_literal: true -RSpec.describe "Bundler.with_env helpers" do +RSpec.describe "env helpers" do def bundle_exec_ruby(args, options = {}) - build_bundler_context options + build_bundler_context options.dup bundle "exec '#{Gem.ruby}' #{args}", options end def build_bundler_context(options = {}) - bundle "config set path vendor/bundle" - gemfile "source \"#{file_uri_for(gem_repo1)}\"" + bundle "config set path vendor/bundle", options.dup + gemfile "source 'https://gem.repo1'" bundle "install", options end @@ -24,7 +24,7 @@ RSpec.describe "Bundler.with_env helpers" do path = `getconf PATH`.strip + "#{File::PATH_SEPARATOR}/foo" with_path_as(path) do bundle_exec_ruby(bundled_app("source.rb").to_s) - expect(last_command.stdboth).to eq(path) + expect(stdboth).to eq(path) end end @@ -35,7 +35,7 @@ RSpec.describe "Bundler.with_env helpers" do gem_path = ENV["GEM_PATH"] + "#{File::PATH_SEPARATOR}/foo" with_gem_path_as(gem_path) do bundle_exec_ruby(bundled_app("source.rb").to_s) - expect(last_command.stdboth).to eq(gem_path) + expect(stdboth).to eq(gem_path) end end @@ -62,88 +62,78 @@ RSpec.describe "Bundler.with_env helpers" do end it "removes variables that bundler added", :ruby_repo do - # Simulate bundler has not yet been loaded - ENV.replace(ENV.to_hash.delete_if {|k, _v| k.start_with?(Bundler::EnvironmentPreserver::BUNDLER_PREFIX) }) - - original = ruby('puts ENV.to_a.map {|e| e.join("=") }.sort.join("\n")') + original = ruby('puts ENV.to_a.map {|e| e.join("=") }.sort.join("\n")', artifice: "fail") create_file("source.rb", <<-RUBY) puts Bundler.original_env.to_a.map {|e| e.join("=") }.sort.join("\n") RUBY - bundle_exec_ruby bundled_app("source.rb") + bundle_exec_ruby bundled_app("source.rb"), artifice: "fail" expect(out).to eq original end end - shared_examples_for "an unbundling helper" do + describe "Bundler.unbundled_env" do it "should delete BUNDLE_PATH" do create_file("source.rb", <<-RUBY) - print #{modified_env}.has_key?('BUNDLE_PATH') + print Bundler.unbundled_env.has_key?('BUNDLE_PATH') RUBY ENV["BUNDLE_PATH"] = "./foo" bundle_exec_ruby bundled_app("source.rb") - expect(last_command.stdboth).to include "false" + expect(stdboth).to include "false" end it "should remove absolute path to 'bundler/setup' from RUBYOPT even if it was present in original env" do create_file("source.rb", <<-RUBY) - print #{modified_env}['RUBYOPT'] + print Bundler.unbundled_env['RUBYOPT'] RUBY setup_require = "-r#{lib_dir}/bundler/setup" ENV["BUNDLER_ORIG_RUBYOPT"] = "-W2 #{setup_require} #{ENV["RUBYOPT"]}" - simulate_bundler_version_when_missing_prerelease_default_gem_activation do - bundle_exec_ruby bundled_app("source.rb") - end - expect(last_command.stdboth).not_to include(setup_require) + bundle_exec_ruby bundled_app("source.rb") + expect(stdboth).not_to include(setup_require) end it "should remove relative path to 'bundler/setup' from RUBYOPT even if it was present in original env" do create_file("source.rb", <<-RUBY) - print #{modified_env}['RUBYOPT'] + print Bundler.unbundled_env['RUBYOPT'] RUBY ENV["BUNDLER_ORIG_RUBYOPT"] = "-W2 -rbundler/setup #{ENV["RUBYOPT"]}" - simulate_bundler_version_when_missing_prerelease_default_gem_activation do - bundle_exec_ruby bundled_app("source.rb") - end - expect(last_command.stdboth).not_to include("-rbundler/setup") + bundle_exec_ruby bundled_app("source.rb") + expect(stdboth).not_to include("-rbundler/setup") + end + + it "should delete BUNDLER_SETUP even if it was present in original env" do + create_file("source.rb", <<-RUBY) + print Bundler.unbundled_env.has_key?('BUNDLER_SETUP') + RUBY + ENV["BUNDLER_ORIG_BUNDLER_SETUP"] = system_gem_path("gems/bundler-#{Bundler::VERSION}/lib/bundler/setup").to_s + bundle_exec_ruby bundled_app("source.rb") + expect(stdboth).to include "false" end it "should restore RUBYLIB", :ruby_repo do create_file("source.rb", <<-RUBY) - print #{modified_env}['RUBYLIB'] + print Bundler.unbundled_env['RUBYLIB'] RUBY ENV["RUBYLIB"] = lib_dir.to_s + File::PATH_SEPARATOR + "/foo" ENV["BUNDLER_ORIG_RUBYLIB"] = lib_dir.to_s + File::PATH_SEPARATOR + "/foo-original" bundle_exec_ruby bundled_app("source.rb") - expect(last_command.stdboth).to include("/foo-original") + expect(stdboth).to include("/foo-original") end it "should restore the original MANPATH" do create_file("source.rb", <<-RUBY) - print #{modified_env}['MANPATH'] + print Bundler.unbundled_env['MANPATH'] RUBY ENV["MANPATH"] = "/foo" ENV["BUNDLER_ORIG_MANPATH"] = "/foo-original" bundle_exec_ruby bundled_app("source.rb") - expect(last_command.stdboth).to include("/foo-original") + expect(stdboth).to include("/foo-original") end end - describe "Bundler.unbundled_env" do - let(:modified_env) { "Bundler.unbundled_env" } - - it_behaves_like "an unbundling helper" - end - - describe "Bundler.clean_env", :bundler => 2 do - let(:modified_env) { "Bundler.clean_env" } - - it_behaves_like "an unbundling helper" - end - describe "Bundler.with_original_env" do it "should set ENV to original_env in the block" do expected = Bundler.original_env - actual = Bundler.with_original_env { Bundler::EnvironmentPreserver.env_to_hash(ENV) } + actual = Bundler.with_original_env { ENV.to_hash } expect(actual).to eq(expected) end @@ -156,30 +146,10 @@ RSpec.describe "Bundler.with_env helpers" do end end - describe "Bundler.with_clean_env", :bundler => 2 do - it "should set ENV to unbundled_env in the block" do - expected = Bundler.unbundled_env - - actual = Bundler.ui.silence do - Bundler.with_clean_env { Bundler::EnvironmentPreserver.env_to_hash(ENV) } - end - - expect(actual).to eq(expected) - end - - it "should restore the environment after execution" do - Bundler.ui.silence do - Bundler.with_clean_env { ENV["FOO"] = "hello" } - end - - expect(ENV).not_to have_key("FOO") - end - end - describe "Bundler.with_unbundled_env" do it "should set ENV to unbundled_env in the block" do expected = Bundler.unbundled_env - actual = Bundler.with_unbundled_env { Bundler::EnvironmentPreserver.env_to_hash(ENV) } + actual = Bundler.with_unbundled_env { ENV.to_hash } expect(actual).to eq(expected) end @@ -207,21 +177,6 @@ RSpec.describe "Bundler.with_env helpers" do end end - describe "Bundler.clean_system", :bundler => 2 do - before do - create_file("source.rb", <<-'RUBY') - Bundler.ui.silence { Bundler.clean_system("ruby", "-e", "exit(42) unless ENV['BUNDLE_FOO'] == 'bar'") } - - exit $?.exitstatus - RUBY - end - - it "runs system inside with_clean_env" do - run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb")) - expect($?.exitstatus).to eq(42) - end - end - describe "Bundler.unbundled_system" do before do create_file("source.rb", <<-'RUBY') @@ -258,27 +213,6 @@ RSpec.describe "Bundler.with_env helpers" do end end - describe "Bundler.clean_exec", :bundler => 2 do - before do - create_file("source.rb", <<-'RUBY') - Process.fork do - exit Bundler.ui.silence { Bundler.clean_exec(%(test "\$BUNDLE_FOO" = "bar")) } - end - - _, status = Process.wait2 - - exit(status.exitstatus) - RUBY - end - - it "runs exec inside with_clean_env" do - skip "Fork not implemented" if Gem.win_platform? - - run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb")) - expect($?.exitstatus).to eq(1) - end - end - describe "Bundler.unbundled_exec" do before do create_file("source.rb", <<-'RUBY') @@ -292,7 +226,7 @@ RSpec.describe "Bundler.with_env helpers" do RUBY end - it "runs exec inside with_clean_env" do + it "runs exec inside with_unbundled_env" do skip "Fork not implemented" if Gem.win_platform? run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb")) diff --git a/spec/bundler/runtime/executable_spec.rb b/spec/bundler/runtime/executable_spec.rb index a11f547648..89cee21b00 100644 --- a/spec/bundler/runtime/executable_spec.rb +++ b/spec/bundler/runtime/executable_spec.rb @@ -3,140 +3,112 @@ RSpec.describe "Running bin/* commands" do before :each do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G end it "runs the bundled command when in the bundle" do - bundle "binstubs rack" + bundle "binstubs myrack" - build_gem "rack", "2.0", :to_system => true do |s| - s.executables = "rackup" + build_gem "myrack", "2.0", to_system: true do |s| + s.executables = "myrackup" end - gembin "rackup" + gembin "myrackup" expect(out).to eq("1.0.0") end - it "allows the location of the gem stubs to be specified" do - bundle "binstubs rack", :path => "gbin" + it "allows the location of the gem stubs to be configured" do + bundle_config "bin gbin" + bundle "binstubs myrack" expect(bundled_app("bin")).not_to exist - expect(bundled_app("gbin/rackup")).to exist + expect(bundled_app("gbin/myrackup")).to exist - gembin bundled_app("gbin/rackup") + gembin bundled_app("gbin/myrackup") expect(out).to eq("1.0.0") end it "allows absolute paths as a specification of where to install bin stubs" do - bundle "binstubs rack", :path => tmp("bin") + bundle_config "bin #{tmp("bin")}" + bundle "binstubs myrack" - gembin tmp("bin/rackup") + gembin tmp("bin/myrackup") expect(out).to eq("1.0.0") end it "uses the default ruby install name when shebang is not specified" do - bundle "binstubs rack" - expect(File.readlines(bundled_app("bin/rackup")).first).to eq("#!/usr/bin/env #{RbConfig::CONFIG["ruby_install_name"]}\n") + bundle "binstubs myrack" + expect(File.readlines(bundled_app("bin/myrackup")).first).to eq("#!/usr/bin/env #{RbConfig::CONFIG["ruby_install_name"]}\n") end it "allows the name of the shebang executable to be specified" do - bundle "binstubs rack", :shebang => "ruby-foo" - expect(File.readlines(bundled_app("bin/rackup")).first).to eq("#!/usr/bin/env ruby-foo\n") + bundle "binstubs myrack", shebang: "ruby-foo" + expect(File.readlines(bundled_app("bin/myrackup")).first).to eq("#!/usr/bin/env ruby-foo\n") end it "runs the bundled command when out of the bundle" do - bundle "binstubs rack" + bundle "binstubs myrack" - build_gem "rack", "2.0", :to_system => true do |s| - s.executables = "rackup" + build_gem "myrack", "2.0", to_system: true do |s| + s.executables = "myrackup" end - gembin "rackup", :dir => tmp + gembin "myrackup", dir: tmp expect(out).to eq("1.0.0") end it "works with gems in path" do - build_lib "rack", :path => lib_path("rack") do |s| - s.executables = "rackup" + build_lib "myrack", path: lib_path("myrack") do |s| + s.executables = "myrackup" end gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", :path => "#{lib_path("rack")}" + source "https://gem.repo1" + gem "myrack", :path => "#{lib_path("myrack")}" G - bundle "binstubs rack" + bundle "binstubs myrack" - build_gem "rack", "2.0", :to_system => true do |s| - s.executables = "rackup" + build_gem "myrack", "2.0", to_system: true do |s| + s.executables = "myrackup" end - gembin "rackup" + gembin "myrackup" expect(out).to eq("1.0") end - it "creates a bundle binstub" do + it "does not create a bundle binstub" do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "bundler" G bundle "binstubs bundler" - expect(bundled_app("bin/bundle")).to exist - end - - it "does not generate bin stubs if the option was not specified" do - bundle "install" - - expect(bundled_app("bin/rackup")).not_to exist - end - - it "allows you to stop installing binstubs", :bundler => "< 3" do - skip "delete permission error" if Gem.win_platform? - - bundle "install --binstubs bin/" - bundled_app("bin/rackup").rmtree - bundle "install --binstubs \"\"" - - expect(bundled_app("bin/rackup")).not_to exist + expect(bundled_app("bin/bundle")).not_to exist - bundle "config bin" - expect(out).to include("You have not configured a value for `bin`") + expect(err).to include("Bundler itself does not use binstubs because its version is selected by RubyGems") end - it "remembers that the option was specified", :bundler => "< 3" do - gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "activesupport" - G - - bundle :install, :binstubs => "bin" - - gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "activesupport" - gem "rack" - G - + it "does not generate bin stubs if the option was not specified" do bundle "install" - expect(bundled_app("bin/rackup")).to exist + expect(bundled_app("bin/myrackup")).not_to exist end - it "rewrites bins on binstubs (to maintain backwards compatibility)" do + it "rewrites bins on binstubs with --force option" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G - create_file("bin/rackup", "OMG") + create_file("bin/myrackup", "OMG") - bundle "binstubs rack" + bundle "binstubs myrack", { force: true } - expect(bundled_app("bin/rackup").read).to_not eq("OMG") + expect(bundled_app("bin/myrackup").read.strip).to_not eq("OMG") end it "use BUNDLE_GEMFILE gemfile for binstub" do @@ -148,8 +120,8 @@ RSpec.describe "Running bin/* commands" do build_gem("bindir") {|s| s.executables = "foo" } end - create_file("OtherGemfile", <<-G) - source "#{file_uri_for(gem_repo2)}" + gemfile("OtherGemfile", <<-G) + source "https://gem.repo2" gem 'bindir' G diff --git a/spec/bundler/runtime/gem_tasks_spec.rb b/spec/bundler/runtime/gem_tasks_spec.rb index b89fdf2cb1..b855142e60 100644 --- a/spec/bundler/runtime/gem_tasks_spec.rb +++ b/spec/bundler/runtime/gem_tasks_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.describe "require 'bundler/gem_tasks'" do - before :each do + let(:define_local_gem_using_gem_tasks) do bundled_app("foo.gemspec").open("w") do |f| f.write <<-GEMSPEC Gem::Specification.new do |s| @@ -20,17 +20,54 @@ RSpec.describe "require 'bundler/gem_tasks'" do end install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "rake" G end - it "includes the relevant tasks" do - with_gem_path_as(base_system_gem_path.to_s) do - sys_exec "#{rake} -T", :env => { "GEM_HOME" => system_gem_path.to_s } + let(:define_local_gem_with_extensions_using_gem_tasks_and_gemspec_dsl) do + bundled_app("foo.gemspec").open("w") do |f| + f.write <<-GEMSPEC + Gem::Specification.new do |s| + s.name = "foo" + s.version = "1.0" + s.summary = "dummy" + s.author = "Perry Mason" + s.extensions = "ext/extconf.rb" + end + GEMSPEC + end + + bundled_app("Rakefile").open("w") do |f| + f.write <<-RAKEFILE + require "bundler/gem_tasks" + RAKEFILE end + Dir.mkdir bundled_app("ext") + + bundled_app("ext/extconf.rb").open("w") do |f| + f.write <<-EXTCONF + require "mkmf" + File.write("Makefile", dummy_makefile($srcdir).join) + EXTCONF + end + + install_gemfile <<-G + source "https://gem.repo1" + + gemspec + + gem "rake" + G + end + + it "includes the relevant tasks" do + define_local_gem_using_gem_tasks + + in_bundled_app "rake -T" + expect(err).to be_empty expected_tasks = [ "rake build", @@ -44,9 +81,9 @@ RSpec.describe "require 'bundler/gem_tasks'" do end it "defines a working `rake install` task", :ruby_repo do - with_gem_path_as(base_system_gem_path.to_s) do - sys_exec "#{rake} install", :env => { "GEM_HOME" => system_gem_path.to_s } - end + define_local_gem_using_gem_tasks + + in_bundled_app "rake install" expect(err).to be_empty @@ -55,11 +92,21 @@ RSpec.describe "require 'bundler/gem_tasks'" do expect(err).to be_empty end + it "defines a working `rake install` task for local gems with extensions", :ruby_repo do + define_local_gem_with_extensions_using_gem_tasks_and_gemspec_dsl + + bundle "exec rake install" + + expect(err).to be_empty + end + context "rake build when path has spaces", :ruby_repo do before do - spaced_bundled_app = tmp.join("bundled app") + define_local_gem_using_gem_tasks + + spaced_bundled_app = tmp("bundled app") FileUtils.cp_r bundled_app, spaced_bundled_app - bundle "exec rake build", :dir => spaced_bundled_app + bundle "exec rake build", dir: spaced_bundled_app end it "still runs successfully" do @@ -69,9 +116,11 @@ RSpec.describe "require 'bundler/gem_tasks'" do context "rake build when path has brackets", :ruby_repo do before do - bracketed_bundled_app = tmp.join("bundled[app") + define_local_gem_using_gem_tasks + + bracketed_bundled_app = tmp("bundled[app") FileUtils.cp_r bundled_app, bracketed_bundled_app - bundle "exec rake build", :dir => bracketed_bundled_app + bundle "exec rake build", dir: bracketed_bundled_app end it "still runs successfully" do @@ -81,12 +130,14 @@ RSpec.describe "require 'bundler/gem_tasks'" do context "bundle path configured locally" do before do - bundle "config set path vendor/bundle" + define_local_gem_using_gem_tasks + + bundle_config "path vendor/bundle" end it "works", :ruby_repo do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "rake" G @@ -98,9 +149,10 @@ RSpec.describe "require 'bundler/gem_tasks'" do end it "adds 'pkg' to rake/clean's CLOBBER" do - with_gem_path_as(base_system_gem_path.to_s) do - sys_exec %(#{rake} -e 'load "Rakefile"; puts CLOBBER.inspect'), :env => { "GEM_HOME" => system_gem_path.to_s } - end + define_local_gem_using_gem_tasks + + in_bundled_app %(rake -e 'load "Rakefile"; puts CLOBBER.inspect') + expect(out).to eq '["pkg"]' end end diff --git a/spec/bundler/runtime/inline_spec.rb b/spec/bundler/runtime/inline_spec.rb index 9567d2a3c3..c6f9bbdbd7 100644 --- a/spec/bundler/runtime/inline_spec.rb +++ b/spec/bundler/runtime/inline_spec.rb @@ -2,10 +2,9 @@ RSpec.describe "bundler/inline#gemfile" do def script(code, options = {}) - requires = ["#{entrypoint}/inline"] - requires.unshift "#{spec_dir}/support/artifice/" + options.delete(:artifice) if options.key?(:artifice) - requires = requires.map {|r| "require '#{r}'" }.join("\n") - ruby("#{requires}\n\n" + code, options) + options[:artifice] ||= "compact_index" + options[:env] ||= { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s } + ruby("require 'bundler/inline'\n\n" + code, options) end before :each do @@ -28,7 +27,7 @@ RSpec.describe "bundler/inline#gemfile" do s.write "lib/four.rb", "puts 'four'" end - build_lib "five", "1.0.0", :no_default => true do |s| + build_lib "five", "1.0.0", no_default: true do |s| s.write "lib/mofive.rb", "puts 'five'" end @@ -48,7 +47,7 @@ RSpec.describe "bundler/inline#gemfile" do it "requires the gems" do script <<-RUBY gemfile do - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" path "#{lib_path}" do gem "two" end @@ -57,9 +56,9 @@ RSpec.describe "bundler/inline#gemfile" do expect(out).to eq("two") - script <<-RUBY, :raise_on_error => false + script <<-RUBY, raise_on_error: false gemfile do - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" path "#{lib_path}" do gem "eleven" end @@ -73,29 +72,29 @@ RSpec.describe "bundler/inline#gemfile" do script <<-RUBY gemfile(true) do - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" end RUBY - expect(out).to include("Rack's post install message") + expect(out).to include("Myrack's post install message") - script <<-RUBY, :artifice => "endpoint" + script <<-RUBY, artifice: "endpoint" gemfile(true) do - source "https://notaserver.com" + source "https://notaserver.test" gem "activesupport", :require => true end RUBY expect(out).to include("Installing activesupport") err_lines = err.split("\n") - err_lines.reject! {|line| line =~ /\.rb:\d+: warning: / } unless RUBY_VERSION < "2.7" + err_lines.reject! {|line| line =~ /\.rb:\d+: warning: / } expect(err_lines).to be_empty end it "lets me use my own ui object" do - script <<-RUBY, :artifice => "endpoint" - require '#{entrypoint}' + script <<-RUBY, artifice: "endpoint" + require 'bundler' class MyBundlerUI < Bundler::UI::Shell def confirm(msg, newline = nil) puts "CONFIRMED!" @@ -104,7 +103,7 @@ RSpec.describe "bundler/inline#gemfile" do my_ui = MyBundlerUI.new my_ui.level = "confirm" gemfile(true, :ui => my_ui) do - source "https://notaserver.com" + source "https://notaserver.test" gem "activesupport", :require => true end RUBY @@ -113,11 +112,11 @@ RSpec.describe "bundler/inline#gemfile" do end it "has an option for quiet installation" do - script <<-RUBY, :artifice => "endpoint" - require '#{entrypoint}/inline' + script <<-RUBY, artifice: "endpoint" + require 'bundler/inline' gemfile(true, :quiet => true) do - source "https://notaserver.com" + source "https://notaserver.test" gem "activesupport", :require => true end RUBY @@ -126,7 +125,7 @@ RSpec.describe "bundler/inline#gemfile" do end it "raises an exception if passed unknown arguments" do - script <<-RUBY, :raise_on_error => false + script <<-RUBY, raise_on_error: false gemfile(true, :arglebargle => true) do path "#{lib_path}" gem "two" @@ -140,10 +139,10 @@ RSpec.describe "bundler/inline#gemfile" do it "does not mutate the option argument" do script <<-RUBY - require '#{entrypoint}' + require 'bundler' options = { :ui => Bundler::UI::Shell.new } gemfile(false, options) do - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" path "#{lib_path}" do gem "two" end @@ -157,11 +156,11 @@ RSpec.describe "bundler/inline#gemfile" do it "installs quietly if necessary when the install option is not set" do script <<-RUBY gemfile do - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" end - puts RACK + puts MYRACK RUBY expect(out).to eq("1.0.0") @@ -170,21 +169,46 @@ RSpec.describe "bundler/inline#gemfile" do it "installs subdependencies quietly if necessary when the install option is not set" do build_repo4 do - build_gem "rack" do |s| - s.add_dependency "rackdep" + build_gem "myrack" do |s| + s.add_dependency "myrackdep" end - build_gem "rackdep", "1.0.0" + build_gem "myrackdep", "1.0.0" end - script <<-RUBY + script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + gemfile do + source "https://gem.repo4" + gem "myrack" + end + + require "myrackdep" + puts MYRACKDEP + RUBY + + expect(out).to eq("1.0.0") + expect(err).to be_empty + end + + it "installs subdependencies quietly if necessary when the install option is not set, and multiple sources used" do + build_repo4 do + build_gem "myrack" do |s| + s.add_dependency "myrackdep" + end + + build_gem "myrackdep", "1.0.0" + end + + script <<-RUBY, artifice: "compact_index_extra_api" gemfile do - source "#{file_uri_for(gem_repo4)}" - gem "rack" + source "https://test.repo" + source "https://test.repo/extra" do + gem "myrack" + end end - require "rackdep" - puts RACKDEP + require "myrackdep" + puts MYRACKDEP RUBY expect(out).to eq("1.0.0") @@ -196,7 +220,7 @@ RSpec.describe "bundler/inline#gemfile" do baz_ref = build_git("baz", "2.0.0").ref_for("HEAD") script <<-RUBY gemfile do - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "foo", :git => #{lib_path("foo-1.0.0").to_s.dump} gem "baz", :git => #{lib_path("baz-2.0.0").to_s.dump}, :ref => #{baz_ref.dump} end @@ -213,14 +237,14 @@ RSpec.describe "bundler/inline#gemfile" do script <<-RUBY gemfile do path "#{lib_path}" do - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "two" end end gemfile do path "#{lib_path}" do - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "four" end end @@ -231,73 +255,73 @@ RSpec.describe "bundler/inline#gemfile" do end it "doesn't reinstall already installed gems" do - system_gems "rack-1.0.0" + system_gems "myrack-1.0.0" script <<-RUBY - require '#{entrypoint}' + require 'bundler' ui = Bundler::UI::Shell.new ui.level = "confirm" gemfile(true, ui: ui) do - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "activesupport" - gem "rack" + gem "myrack" end RUBY expect(out).to include("Installing activesupport") - expect(out).not_to include("Installing rack") + expect(out).not_to include("Installing myrack") expect(err).to be_empty end it "installs gems in later gemfile calls" do - system_gems "rack-1.0.0" + system_gems "myrack-1.0.0" script <<-RUBY - require '#{entrypoint}' + require 'bundler' ui = Bundler::UI::Shell.new ui.level = "confirm" gemfile(true, ui: ui) do - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" end gemfile(true, ui: ui) do - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "activesupport" end RUBY expect(out).to include("Installing activesupport") - expect(out).not_to include("Installing rack") + expect(out).not_to include("Installing myrack") expect(err).to be_empty end it "doesn't reinstall already installed gems in later gemfile calls" do - system_gems "rack-1.0.0" + system_gems "myrack-1.0.0" script <<-RUBY - require '#{entrypoint}' + require 'bundler' ui = Bundler::UI::Shell.new ui.level = "confirm" gemfile(true, ui: ui) do - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "activesupport" end gemfile(true, ui: ui) do - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" end RUBY expect(out).to include("Installing activesupport") - expect(out).not_to include("Installing rack") + expect(out).not_to include("Installing myrack") expect(err).to be_empty end it "installs gems with native extensions in later gemfile calls" do - system_gems "rack-1.0.0" + system_gems "myrack-1.0.0" build_git "foo" do |s| s.add_dependency "rake" @@ -314,16 +338,16 @@ RSpec.describe "bundler/inline#gemfile" do end script <<-RUBY - require '#{entrypoint}' + require 'bundler' ui = Bundler::UI::Shell.new ui.level = "confirm" gemfile(true, ui: ui) do - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" end gemfile(true, ui: ui) do - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "foo", :git => "#{lib_path("foo-1.0")}" end @@ -339,7 +363,7 @@ RSpec.describe "bundler/inline#gemfile" do it "installs inline gems when a Gemfile.lock is present" do gemfile <<-G - source "https://notaserver.com" + source "https://notaserver.test" gem "rake" G @@ -356,16 +380,16 @@ RSpec.describe "bundler/inline#gemfile" do rake BUNDLED WITH - #{Bundler::VERSION} + #{Bundler::VERSION} G script <<-RUBY gemfile do - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" end - puts RACK + puts MYRACK RUBY expect(err).to be_empty @@ -373,7 +397,7 @@ RSpec.describe "bundler/inline#gemfile" do it "does not leak Gemfile.lock versions to the installation output" do gemfile <<-G - source "https://notaserver.com" + source "https://notaserver.test" gem "rake" G @@ -390,42 +414,42 @@ RSpec.describe "bundler/inline#gemfile" do rake BUNDLED WITH - #{Bundler::VERSION} + #{Bundler::VERSION} G script <<-RUBY gemfile(true) do - source "#{file_uri_for(gem_repo1)}" - gem "rake", "~> 13.0" + source "https://gem.repo1" + gem "rake", "#{rake_version}" end RUBY - expect(out).to include("Installing rake 13.0") + expect(out).to include("Installing rake #{rake_version}") expect(out).not_to include("was 11.3.0") expect(err).to be_empty end it "installs inline gems when frozen is set" do - script <<-RUBY, :env => { "BUNDLE_FROZEN" => "true" } + script <<-RUBY, env: { "BUNDLE_FROZEN" => "true", "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s } gemfile do - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" end - puts RACK + puts MYRACK RUBY expect(last_command.stderr).to be_empty end it "installs inline gems when deployment is set" do - script <<-RUBY, :env => { "BUNDLE_DEPLOYMENT" => "true" } + script <<-RUBY, env: { "BUNDLE_DEPLOYMENT" => "true", "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s } gemfile do - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" end - puts RACK + puts MYRACK RUBY expect(last_command.stderr).to be_empty @@ -436,11 +460,11 @@ RSpec.describe "bundler/inline#gemfile" do script <<-RUBY gemfile do - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" end - puts RACK + puts MYRACK RUBY expect(err).to be_empty @@ -451,11 +475,11 @@ RSpec.describe "bundler/inline#gemfile" do script <<-RUBY gemfile do - source "#{file_uri_for(gem_repo1)}" - gem "rack" # has the rackup executable + source "https://gem.repo1" + gem "myrack" # has the myrackup executable end - puts RACK + puts MYRACK RUBY expect(last_command).to be_success expect(out).to eq "1.0.0" @@ -463,24 +487,24 @@ RSpec.describe "bundler/inline#gemfile" do context "when BUNDLE_PATH is set" do it "installs inline gems to the system path regardless" do - script <<-RUBY, :env => { "BUNDLE_PATH" => "./vendor/inline" } + script <<-RUBY, env: { "BUNDLE_PATH" => "./vendor/inline", "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s } gemfile(true) do - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" end RUBY expect(last_command).to be_success - expect(system_gem_path("gems/rack-1.0.0")).to exist + expect(system_gem_path("gems/myrack-1.0.0")).to exist end end it "skips platform warnings" do - bundle "config set --local force_ruby_platform true" + bundle_config "force_ruby_platform true" script <<-RUBY gemfile(true) do - source "#{file_uri_for(gem_repo1)}" - gem "rack", platform: :jruby + source "https://gem.repo1" + gem "myrack", platform: :jruby end RUBY @@ -488,25 +512,25 @@ RSpec.describe "bundler/inline#gemfile" do end it "still installs if the application has `bundle package` no_install config set" do - bundle "config set --local no_install true" + bundle_config "no_install true" script <<-RUBY gemfile do - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" end RUBY expect(last_command).to be_success - expect(system_gem_path("gems/rack-1.0.0")).to exist + expect(system_gem_path("gems/myrack-1.0.0")).to exist end it "preserves previous BUNDLE_GEMFILE value" do ENV["BUNDLE_GEMFILE"] = "" script <<-RUBY gemfile do - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" end puts "BUNDLE_GEMFILE is empty" if ENV["BUNDLE_GEMFILE"].empty? @@ -522,8 +546,8 @@ RSpec.describe "bundler/inline#gemfile" do ENV["BUNDLE_GEMFILE"] = nil script <<-RUBY gemfile do - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" end puts "BUNDLE_GEMFILE is empty" if ENV["BUNDLE_GEMFILE"].empty? @@ -551,9 +575,9 @@ RSpec.describe "bundler/inline#gemfile" do s.write "lib/foo.rb", foo_code end - script <<-RUBY, :dir => tmp("path_without_gemfile") + script <<-RUBY, dir: tmp("path_without_gemfile"), env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } gemfile do - source "#{file_uri_for(gem_repo2)}" + source "https://gem.repo2" path "#{lib_path}" do gem "foo", require: false end @@ -566,36 +590,162 @@ RSpec.describe "bundler/inline#gemfile" do expect(err).to be_empty end - it "when requiring fileutils after does not show redefinition warnings", :realworld do - dependency_installer_loads_fileutils = ruby "require 'rubygems/dependency_installer'; puts $LOADED_FEATURES.grep(/fileutils/)", :raise_on_error => false - skip "does not work if rubygems/dependency_installer loads fileutils, which happens until rubygems 3.2.0" unless dependency_installer_loads_fileutils.empty? + it "does not load default timeout", rubygems: ">= 3.5.0" do + default_timeout_version = ruby "gem 'timeout', '< 999999'; require 'timeout'; puts Timeout::VERSION", raise_on_error: false + skip "timeout isn't a default gem" if default_timeout_version.empty? + + build_repo4 do + build_gem "timeout", "999" + end + + script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + require "bundler/inline" - skip "pathname does not install cleanly on this ruby" if RUBY_VERSION < "2.7.0" + gemfile(true) do + source "https://gem.repo4" - Dir.mkdir tmp("path_without_gemfile") + gem "timeout" + end + RUBY + + expect(out).to include("Installing timeout 999") + end + + it "does not upcase ENV" do + script <<-RUBY + require 'bundler/inline' + + ENV['Test_Variable'] = 'value string' + puts("before: \#{ENV.each_key.select { |key| key.match?(/test_variable/i) }}") + + gemfile do + source "https://gem.repo1" + end + + puts("after: \#{ENV.each_key.select { |key| key.match?(/test_variable/i) }}") + RUBY + + expect(out).to include("before: [\"Test_Variable\"]") + expect(out).to include("after: [\"Test_Variable\"]") + end + + it "does not create a lockfile" do + script <<-RUBY + require 'bundler/inline' + + gemfile do + source "https://gem.repo1" + end + + puts Dir.glob("Gemfile.lock") + RUBY + + expect(out).to be_empty + end - default_fileutils_version = ruby "gem 'fileutils', '< 999999'; require 'fileutils'; puts FileUtils::VERSION", :raise_on_error => false - skip "fileutils isn't a default gem" if default_fileutils_version.empty? + it "does not reset ENV" do + script <<-RUBY + require 'bundler/inline' + + gemfile do + source "https://gem.repo1" - realworld_system_gems "fileutils --version 1.4.1" + ENV['FOO'] = 'bar' + end - realworld_system_gems "pathname --version 0.2.0" + puts ENV['FOO'] + RUBY - realworld_system_gems "timeout uri" # this spec uses net/http which requires these default gems + expect(out).to eq("bar") + end - # on prerelease rubies, a required_rubygems_version constraint is added by RubyGems to the resolution, causing Molinillo to load the `set` gem - realworld_system_gems "set --version 1.0.3" if Gem.ruby_version.prerelease? + it "does not load specified version of psych and stringio", :ruby_repo do + build_repo4 do + build_gem "psych", "999" + build_gem "stringio", "999" + end - script <<-RUBY, :dir => tmp("path_without_gemfile"), :env => { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s } + script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } require "bundler/inline" gemfile(true) do - source "#{file_uri_for(gem_repo2)}" + source "https://gem.repo4" + + gem "psych" + gem "stringio" + end + RUBY + + expect(out).to include("Installing psych 999") + expect(out).to include("Installing stringio 999") + if Gem.respond_to?(:use_psych?) && Gem.use_psych? + expect(out).to include("The psych gem was resolved to 999") + expect(out).to include("The stringio gem was resolved to 999") + end + end + + it "installs a conflicting default gem and non-default gems together" do + build_repo4 do + build_gem "securerandom", "999" + build_gem "myrack", "1.0.0" + end + + script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + gemfile(true) do + source "https://gem.repo4" + gem "securerandom" + gem "myrack" end - require "fileutils" + puts MYRACK + RUBY + + expect(out).to include("Installing securerandom 999") + expect(out).to include("Installing myrack 1.0.0") + expect(out).to include("1.0.0") + expect(err).to be_empty + end + + it "installs a conflicting default gem alongside git sources" do + build_repo4 do + build_gem "securerandom", "999" + end + + build_git "foo", "1.0.0" + + script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + gemfile(true) do + source "https://gem.repo4" + gem "securerandom" + gem "foo", :git => #{lib_path("foo-1.0.0").to_s.dump} + end + + puts FOO + RUBY + + expect(out).to include("Installing securerandom 999") + expect(out).to include("1.0.0") + expect(err).to be_empty + end + + it "leaves a lockfile in the same directory as the inline script alone" do + install_gemfile <<~G + source "https://gem.repo1" + gem "foo" + G + + original_lockfile = lockfile + + script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s } + require "bundler/inline" + + gemfile(true) do + source "https://gem.repo1" + + gem "myrack" + end RUBY - expect(err).to eq("The Gemfile specifies no dependencies") + expect(lockfile).to eq(original_lockfile) end end diff --git a/spec/bundler/runtime/load_spec.rb b/spec/bundler/runtime/load_spec.rb index 96a22a46cc..472cde87c5 100644 --- a/spec/bundler/runtime/load_spec.rb +++ b/spec/bundler/runtime/load_spec.rb @@ -4,18 +4,18 @@ RSpec.describe "Bundler.load" do describe "with a gemfile" do before(:each) do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G allow(Bundler::SharedHelpers).to receive(:pwd).and_return(bundled_app) end it "provides a list of the env dependencies" do - expect(Bundler.load.dependencies).to have_dep("rack", ">= 0") + expect(Bundler.load.dependencies).to have_dep("myrack", ">= 0") end it "provides a list of the resolved gems" do - expect(Bundler.load.gems).to have_gem("rack-1.0.0", "bundler-#{Bundler::VERSION}") + expect(Bundler.load.gems).to have_gem("myrack-1.0.0", "bundler-#{Bundler::VERSION}") end it "ignores blank BUNDLE_GEMFILEs" do @@ -28,20 +28,20 @@ RSpec.describe "Bundler.load" do describe "with a gems.rb file" do before(:each) do - create_file "gems.rb", <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + gemfile "gems.rb", <<-G + source "https://gem.repo1" + gem "myrack" G bundle :install allow(Bundler::SharedHelpers).to receive(:pwd).and_return(bundled_app) end it "provides a list of the env dependencies" do - expect(Bundler.load.dependencies).to have_dep("rack", ">= 0") + expect(Bundler.load.dependencies).to have_dep("myrack", ">= 0") end it "provides a list of the resolved gems" do - expect(Bundler.load.gems).to have_gem("rack-1.0.0", "bundler-#{Bundler::VERSION}") + expect(Bundler.load.gems).to have_gem("myrack-1.0.0", "bundler-#{Bundler::VERSION}") end end @@ -68,7 +68,7 @@ RSpec.describe "Bundler.load" do begin expect { Bundler.load }.to raise_error(Bundler::GemfileNotFound) ensure - bundler_gemfile.rmtree if @remove_bundler_gemfile + FileUtils.rm_rf bundler_gemfile if @remove_bundler_gemfile end end end @@ -76,16 +76,16 @@ RSpec.describe "Bundler.load" do describe "when called twice" do it "doesn't try to load the runtime twice" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" gem "activesupport", :group => :test G ruby <<-RUBY - require "#{entrypoint}" + require "bundler" Bundler.setup :default Bundler.require :default - puts RACK + puts MYRACK begin require "activesupport" rescue LoadError @@ -100,7 +100,7 @@ RSpec.describe "Bundler.load" do describe "not hurting brittle rubygems" do it "does not inject #source into the generated YAML of the gem specs" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "activerecord" G allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) diff --git a/spec/bundler/runtime/platform_spec.rb b/spec/bundler/runtime/platform_spec.rb index b31bc4abe8..6d96758956 100644 --- a/spec/bundler/runtime/platform_spec.rb +++ b/spec/bundler/runtime/platform_spec.rb @@ -3,26 +3,26 @@ RSpec.describe "Bundler.setup with multi platform stuff" do it "raises a friendly error when gems are missing locally" do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G lockfile <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: https://gem.repo1/ specs: - rack (1.0) + myrack (1.0) PLATFORMS #{local_tag} DEPENDENCIES - rack + myrack G ruby <<-R begin - require '#{entrypoint}' + require 'bundler' Bundler.ui.silence { Bundler.setup } rescue Bundler::GemNotFound => e puts "WIN" @@ -35,7 +35,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do it "will resolve correctly on the current platform when the lockfile was targeted for a different one" do lockfile <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: https://gem.repo1/ specs: nokogiri (1.4.2-java) weakling (= 0.0.3) @@ -48,55 +48,63 @@ RSpec.describe "Bundler.setup with multi platform stuff" do nokogiri G - simulate_platform "x86-darwin-10" - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "nokogiri" - G + simulate_platform "x86-darwin-10" do + install_gemfile <<-G + source "https://gem.repo1" + gem "nokogiri" + G - expect(the_bundle).to include_gems "nokogiri 1.4.2" + expect(the_bundle).to include_gems "nokogiri 1.4.2" + end end it "will keep both platforms when both ruby and a specific ruby platform are locked and the bundle is unlocked" do build_repo4 do build_gem "nokogiri", "1.11.1" do |s| s.add_dependency "mini_portile2", "~> 2.5.0" - s.add_dependency "racc", "~> 1.5.2" + s.add_dependency "racca", "~> 1.5.2" end build_gem "nokogiri", "1.11.1" do |s| s.platform = Bundler.local_platform - s.add_dependency "racc", "~> 1.4" + s.add_dependency "racca", "~> 1.4" end build_gem "mini_portile2", "2.5.0" - build_gem "racc", "1.5.2" + build_gem "racca", "1.5.2" + end + + checksums = checksums_section do |c| + c.checksum gem_repo4, "mini_portile2", "2.5.0" + c.checksum gem_repo4, "nokogiri", "1.11.1" + c.checksum gem_repo4, "nokogiri", "1.11.1", Bundler.local_platform + c.checksum gem_repo4, "racca", "1.5.2" end good_lockfile = <<~L GEM - remote: #{file_uri_for(gem_repo4)}/ + remote: https://gem.repo4/ specs: mini_portile2 (2.5.0) nokogiri (1.11.1) mini_portile2 (~> 2.5.0) - racc (~> 1.5.2) + racca (~> 1.5.2) nokogiri (1.11.1-#{Bundler.local_platform}) - racc (~> 1.4) - racc (1.5.2) + racca (~> 1.4) + racca (1.5.2) PLATFORMS #{lockfile_platforms("ruby")} DEPENDENCIES nokogiri (~> 1.11) - + #{checksums} BUNDLED WITH - #{Bundler::VERSION} + #{Bundler::VERSION} L gemfile <<-G - source "#{file_uri_for(gem_repo4)}" + source "https://gem.repo4" gem "nokogiri", "~> 1.11" G @@ -118,13 +126,13 @@ RSpec.describe "Bundler.setup with multi platform stuff" do end gemfile <<-G - source "https://gems.repo4" + source "https://gem.repo4" gem "nokogiri" G lockfile <<~L GEM - remote: https://gems.repo4/ + remote: https://gem.repo4/ specs: nokogiri (1.11.1) @@ -135,10 +143,10 @@ RSpec.describe "Bundler.setup with multi platform stuff" do nokogiri BUNDLED WITH - #{Bundler::VERSION} + #{Bundler::VERSION} L - bundle "install", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + bundle "install" expect(out).to include("Fetching nokogiri 1.11.1") expect(the_bundle).to include_gems "nokogiri 1.11.1" @@ -147,13 +155,13 @@ RSpec.describe "Bundler.setup with multi platform stuff" do it "will use the java platform if both generic java and generic ruby platforms are locked", :jruby_only do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "nokogiri" G lockfile <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: https://gem.repo1/ specs: nokogiri (1.4.2) nokogiri (1.4.2-java) @@ -174,13 +182,13 @@ RSpec.describe "Bundler.setup with multi platform stuff" do bundle "install" expect(out).to include("Fetching nokogiri 1.4.2 (java)") - expect(the_bundle).to include_gems "nokogiri 1.4.2 JAVA" + expect(the_bundle).to include_gems "nokogiri 1.4.2 java" end it "will add the resolve for the current platform" do lockfile <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: https://gem.repo1/ specs: nokogiri (1.4.2-java) weakling (= 0.0.3) @@ -193,77 +201,77 @@ RSpec.describe "Bundler.setup with multi platform stuff" do nokogiri G - simulate_platform "x86-darwin-100" - - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "nokogiri" - gem "platform_specific" - G + simulate_platform "x86-darwin-100" do + install_gemfile <<-G + source "https://gem.repo1" + gem "nokogiri" + gem "platform_specific" + G - expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 x86-darwin-100" + expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 x86-darwin-100" + end end it "allows specifying only-ruby-platform on jruby", :jruby_only do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "nokogiri" gem "platform_specific" G - bundle "config set force_ruby_platform true" + bundle_config "force_ruby_platform true" bundle "install" - expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 RUBY" + expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 ruby" end it "allows specifying only-ruby-platform" do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "nokogiri" gem "platform_specific" G - bundle "config set force_ruby_platform true" + bundle_config "force_ruby_platform true" bundle "install" - expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 RUBY" + expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 ruby" end it "allows specifying only-ruby-platform even if the lockfile is locked to a specific compatible platform" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "nokogiri" gem "platform_specific" G - bundle "config set force_ruby_platform true" + bundle_config "force_ruby_platform true" bundle "install" - expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 RUBY" + expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 ruby" end it "doesn't pull platform specific gems on truffleruby", :truffleruby_only do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "platform_specific" G - expect(the_bundle).to include_gems "platform_specific 1.0 RUBY" + expect(the_bundle).to include_gems "platform_specific 1.0 ruby" end - it "doesn't pull platform specific gems on truffleruby (except when whitelisted) even if lockfile was generated with an older version that declared RUBY as platform", :truffleruby_only do + it "doesn't pull platform specific gems on truffleruby (except when whitelisted) even if lockfile was generated with an older version that declared ruby as platform", :truffleruby_only do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "platform_specific" G lockfile <<-L GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: https://gem.repo1/ specs: platform_specific (1.0) @@ -274,12 +282,12 @@ RSpec.describe "Bundler.setup with multi platform stuff" do platform_specific BUNDLED WITH - #{Bundler::VERSION} + #{Bundler::VERSION} L bundle "install" - expect(the_bundle).to include_gems "platform_specific 1.0 RUBY" + expect(the_bundle).to include_gems "platform_specific 1.0 ruby" simulate_platform "x86_64-linux" do build_repo4 do @@ -291,13 +299,13 @@ RSpec.describe "Bundler.setup with multi platform stuff" do end gemfile <<-G - source "#{file_uri_for(gem_repo4)}" + source "https://gem.repo4" gem "libv8" G lockfile <<-L GEM - remote: #{file_uri_for(gem_repo4)}/ + remote: https://gem.repo4/ specs: libv8 (1.0) @@ -308,7 +316,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do libv8 BUNDLED WITH - #{Bundler::VERSION} + #{Bundler::VERSION} L bundle "install" @@ -319,13 +327,13 @@ RSpec.describe "Bundler.setup with multi platform stuff" do it "doesn't pull platform specific gems on truffleruby, even if lockfile only includes those", :truffleruby_only do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "platform_specific" G lockfile <<-L GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: https://gem.repo1/ specs: platform_specific (1.0-x86-darwin-100) @@ -336,12 +344,12 @@ RSpec.describe "Bundler.setup with multi platform stuff" do platform_specific BUNDLED WITH - #{Bundler::VERSION} + #{Bundler::VERSION} L bundle "install" - expect(the_bundle).to include_gems "platform_specific 1.0 RUBY" + expect(the_bundle).to include_gems "platform_specific 1.0 ruby" end it "pulls platform specific gems correctly on musl" do @@ -352,8 +360,8 @@ RSpec.describe "Bundler.setup with multi platform stuff" do end simulate_platform "aarch64-linux-musl" do - install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }, :verbose => true - source "https://gems.repo4" + install_gemfile <<-G, verbose: true + source "https://gem.repo4" gem "nokogiri" G end @@ -362,38 +370,38 @@ RSpec.describe "Bundler.setup with multi platform stuff" do end it "allows specifying only-ruby-platform on windows with dependency platforms" do - simulate_windows do + simulate_platform "x86-mswin32" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "nokogiri", :platforms => [:windows, :mswin, :mswin64, :mingw, :x64_mingw, :jruby] + source "https://gem.repo1" + gem "nokogiri", :platforms => [:windows, :jruby] gem "platform_specific" G - bundle "config set force_ruby_platform true" + bundle_config "force_ruby_platform true" bundle "install" - expect(the_bundle).to include_gems "platform_specific 1.0 RUBY" + expect(the_bundle).to include_gems "platform_specific 1.0 ruby" expect(the_bundle).to not_include_gems "nokogiri" end end it "allows specifying only-ruby-platform on windows with gemspec dependency" do - build_lib("foo", "1.0", :path => bundled_app) do |s| - s.add_dependency "rack" + build_lib("foo", "1.0", path: bundled_app) do |s| + s.add_dependency "myrack" end gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gemspec G bundle :lock - simulate_windows do - bundle "config set force_ruby_platform true" + simulate_platform "x86-mswin32" do + bundle_config "force_ruby_platform true" bundle "install" - expect(the_bundle).to include_gems "rack 1.0" + expect(the_bundle).to include_gems "myrack 1.0" end end @@ -403,41 +411,39 @@ RSpec.describe "Bundler.setup with multi platform stuff" do s.add_dependency "platform_specific" end end - simulate_windows x64_mingw32 do + simulate_platform "x64-mingw-ucrt" do lockfile <<-L GEM - remote: #{file_uri_for(gem_repo2)}/ + remote: https://gem.repo2/ specs: platform_specific (1.0-x86-mingw32) requires_platform_specific (1.0) platform_specific PLATFORMS - x64-mingw32 + x64-mingw-ucrt x86-mingw32 DEPENDENCIES requires_platform_specific L - install_gemfile <<-G, :verbose => true - source "#{file_uri_for(gem_repo2)}" + install_gemfile <<-G, verbose: true + source "https://gem.repo2" gem "requires_platform_specific" G expect(out).to include("lockfile does not have all gems needed for the current platform") - expect(the_bundle).to include_gem "platform_specific 1.0 x64-mingw32" + expect(the_bundle).to include_gem "platform_specific 1.0 x64-mingw-ucrt" end end - %w[x86-mswin32 x64-mswin64 x86-mingw32 x64-mingw32 x64-mingw-ucrt].each do |arch| - it "allows specifying platform windows on #{arch} arch" do - platform = send(arch.tr("-", "_")) - - simulate_windows platform do + %w[x86-mswin32 x64-mswin64 x86-mingw32 x64-mingw-ucrt aarch64-mingw-ucrt].each do |platform| + it "allows specifying platform windows on #{platform} platform" do + simulate_platform platform do lockfile <<-L GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: https://gem.repo1/ specs: platform_specific (1.0-#{platform}) requires_platform_specific (1.0) @@ -451,12 +457,10 @@ RSpec.describe "Bundler.setup with multi platform stuff" do L install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "platform_specific", :platforms => [:windows] G - bundle "install" - expect(the_bundle).to include_gems "platform_specific 1.0 #{platform}" end end diff --git a/spec/bundler/runtime/require_spec.rb b/spec/bundler/runtime/require_spec.rb index e59fa564f6..46613286d2 100644 --- a/spec/bundler/runtime/require_spec.rb +++ b/spec/bundler/runtime/require_spec.rb @@ -21,7 +21,7 @@ RSpec.describe "Bundler.require" do s.write "lib/four.rb", "puts 'four'" end - build_lib "five", "1.0.0", :no_default => true do |s| + build_lib "five", "1.0.0", no_default: true do |s| s.write "lib/mofive.rb", "puts 'five'" end @@ -46,7 +46,7 @@ RSpec.describe "Bundler.require" do end gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" path "#{lib_path}" do gem "one", :group => :bar, :require => %w[baz qux] gem "two" @@ -113,17 +113,15 @@ RSpec.describe "Bundler.require" do it "raises an exception if a require is specified but the file does not exist" do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" path "#{lib_path}" do gem "two", :require => 'fail' end G - load_error_run <<-R, "fail" - Bundler.require - R + run "Bundler.require", raise_on_error: false - expect(err_without_deprecations).to eq("ZOMG LOAD ERROR") + expect(err_without_deprecations).to include("cannot load such file -- fail") end it "displays a helpful message if the required gem throws an error" do @@ -132,13 +130,13 @@ RSpec.describe "Bundler.require" do end gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" path "#{lib_path}" do gem "faulty" end G - run "Bundler.require", :raise_on_error => false + run "Bundler.require", raise_on_error: false expect(err).to match("error while trying to load the gem 'faulty'") expect(err).to match("Gem Internal Error Message") end @@ -149,22 +147,15 @@ RSpec.describe "Bundler.require" do end gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" path "#{lib_path}" do gem "loadfuuu" end G - cmd = <<-RUBY - begin - Bundler.require - rescue LoadError => e - warn "ZOMG LOAD ERROR: \#{e.message}" - end - RUBY - run(cmd) + run "Bundler.require", raise_on_error: false - expect(err_without_deprecations).to eq("ZOMG LOAD ERROR: cannot load such file -- load-bar") + expect(err_without_deprecations).to include("cannot load such file -- load-bar") end describe "with namespaced gems" do @@ -176,7 +167,7 @@ RSpec.describe "Bundler.require" do it "requires gem names that are namespaced" do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" path '#{lib_path}' do gem 'jquery-rails' end @@ -187,11 +178,11 @@ RSpec.describe "Bundler.require" do end it "silently passes if the require fails" do - build_lib "bcrypt-ruby", "1.0.0", :no_default => true do |s| + build_lib "bcrypt-ruby", "1.0.0", no_default: true do |s| s.write "lib/brcrypt.rb", "BCrypt = '1.0.0'" end gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" path "#{lib_path}" do gem "bcrypt-ruby" @@ -199,7 +190,7 @@ RSpec.describe "Bundler.require" do G cmd = <<-RUBY - require '#{entrypoint}' + require 'bundler' Bundler.require RUBY ruby(cmd) @@ -209,16 +200,15 @@ RSpec.describe "Bundler.require" do it "does not mangle explicitly given requires" do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" path "#{lib_path}" do gem 'jquery-rails', :require => 'jquery-rails' end G - load_error_run <<-R, "jquery-rails" - Bundler.require - R - expect(err_without_deprecations).to eq("ZOMG LOAD ERROR") + run "Bundler.require", raise_on_error: false + + expect(err_without_deprecations).to include("cannot load such file -- jquery-rails") end it "handles the case where regex fails" do @@ -227,22 +217,15 @@ RSpec.describe "Bundler.require" do end gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" path "#{lib_path}" do gem "load-fuuu" end G - cmd = <<-RUBY - begin - Bundler.require - rescue LoadError => e - warn "ZOMG LOAD ERROR" if e.message.include?("Could not open library 'libfuuu-1.0'") - end - RUBY - run(cmd) + run "Bundler.require", raise_on_error: false - expect(err_without_deprecations).to eq("ZOMG LOAD ERROR") + expect(err_without_deprecations).to include("libfuuu-1.0").and include("cannot open shared object file") end it "doesn't swallow the error when the library has an unrelated error" do @@ -251,22 +234,15 @@ RSpec.describe "Bundler.require" do end gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" path "#{lib_path}" do gem "load-fuuu" end G - cmd = <<-RUBY - begin - Bundler.require - rescue LoadError => e - warn "ZOMG LOAD ERROR: \#{e.message}" - end - RUBY - run(cmd) + run "Bundler.require", raise_on_error: false - expect(err_without_deprecations).to eq("ZOMG LOAD ERROR: cannot load such file -- load-bar") + expect(err_without_deprecations).to include("cannot load such file -- load-bar") end end @@ -310,7 +286,7 @@ RSpec.describe "Bundler.require" do it "works when the gems are in the Gemfile in the correct order" do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" path "#{lib_path}" do gem "two" gem "one" @@ -323,13 +299,13 @@ RSpec.describe "Bundler.require" do describe "a gem with different requires for different envs" do before(:each) do - build_gem "multi_gem", :to_bundle => true do |s| + build_gem "multi_gem", to_bundle: true do |s| s.write "lib/one.rb", "puts 'ONE'" s.write "lib/two.rb", "puts 'TWO'" end install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "multi_gem", :require => "one", :group => :one gem "multi_gem", :require => "two", :group => :two G @@ -353,7 +329,7 @@ RSpec.describe "Bundler.require" do it "fails when the gems are in the Gemfile in the wrong order" do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" path "#{lib_path}" do gem "one" gem "two" @@ -366,31 +342,30 @@ RSpec.describe "Bundler.require" do describe "with busted gems" do it "should be busted" do - build_gem "busted_require", :to_bundle => true do |s| + build_gem "busted_require", to_bundle: true do |s| s.write "lib/busted_require.rb", "require 'no_such_file_omg'" end install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "busted_require" G - load_error_run <<-R, "no_such_file_omg" - Bundler.require - R - expect(err_without_deprecations).to eq("ZOMG LOAD ERROR") + run "Bundler.require", raise_on_error: false + + expect(err_without_deprecations).to include("cannot load such file -- no_such_file_omg") end end end it "does not load rubygems gemspecs that are used" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G run <<-R - path = File.join(Gem.dir, "specifications", "rack-1.0.0.gemspec") + path = File.join(Gem.dir, "specifications", "myrack-1.0.0.gemspec") contents = File.read(path) contents = contents.lines.to_a.insert(-2, "\n raise 'broken gemspec'\n").join File.open(path, "w") do |f| @@ -410,7 +385,7 @@ RSpec.describe "Bundler.require" do build_git "foo" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "foo", :git => "#{lib_path("foo-1.0")}" G @@ -430,18 +405,58 @@ RSpec.describe "Bundler.require" do expect(out).to eq("WIN") end + + it "does not load plugins" do + install_gemfile <<-G + source "https://gem.repo1" + gem "myrack" + G + + create_file "plugins/rubygems_plugin.rb", "puts 'FAIL'" + + run <<~R, env: { "RUBYLIB" => rubylib.unshift(bundled_app("plugins").to_s).join(File::PATH_SEPARATOR) } + Bundler.require + puts "WIN" + R + + expect(out).to eq("WIN") + end + + it "does not extract gemspecs from application cache packages" do + gemfile <<-G + source "https://gem.repo1" + gem "myrack" + G + + bundle :cache + + path = cached_gem("myrack-1.0.0") + + run <<-R + File.open("#{path}", "w") do |f| + f.write "broken package" + end + R + + run <<-R + Bundler.require + puts "WIN" + R + + expect(out).to eq("WIN") + end end RSpec.describe "Bundler.require with platform specific dependencies" do it "does not require the gems that are pinned to other platforms" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" platforms :#{not_local_tag} do gem "platform_specific", :require => "omgomg" end - gem "rack", "1.0.0" + gem "myrack", "1.0.0" G run "Bundler.require" @@ -450,14 +465,14 @@ RSpec.describe "Bundler.require with platform specific dependencies" do it "requires gems pinned to multiple platforms, including the current one" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" platforms :#{not_local_tag}, :#{local_tag} do - gem "rack", :require => "rack" + gem "myrack", :require => "myrack" end G - run "Bundler.require; puts RACK" + run "Bundler.require; puts MYRACK" expect(out).to eq("1.0.0") expect(err).to be_empty diff --git a/spec/bundler/runtime/requiring_spec.rb b/spec/bundler/runtime/requiring_spec.rb new file mode 100644 index 0000000000..f0e0aeacaf --- /dev/null +++ b/spec/bundler/runtime/requiring_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +RSpec.describe "Requiring bundler" do + it "takes care of requiring rubygems when entrypoint is bundler/setup" do + sys_exec("#{Gem.ruby} -I#{lib_dir} -rbundler/setup -e'puts true'", env: { "RUBYOPT" => "--disable=gems" }) + + expect(stdboth).to eq("true") + end + + it "takes care of requiring rubygems when requiring just bundler" do + sys_exec("#{Gem.ruby} -I#{lib_dir} -rbundler -e'puts true'", env: { "RUBYOPT" => "--disable=gems" }) + + expect(stdboth).to eq("true") + end +end diff --git a/spec/bundler/runtime/self_management_spec.rb b/spec/bundler/runtime/self_management_spec.rb index 700084babf..176c2a3121 100644 --- a/spec/bundler/runtime/self_management_spec.rb +++ b/spec/bundler/runtime/self_management_spec.rb @@ -1,48 +1,75 @@ # frozen_string_literal: true -RSpec.describe "Self management", :rubygems => ">= 3.3.0.dev", :realworld => true do +RSpec.describe "Self management" do describe "auto switching" do let(:previous_minor) do - "2.3.0" + "9.3.0" + end + + let(:current_version) do + "9.4.0" end before do - build_repo2 + build_repo4 do + build_bundler previous_minor + + build_bundler current_version + + build_gem "myrack", "1.0.0" + end gemfile <<-G - source "#{file_uri_for(gem_repo2)}" + source "https://gem.repo4" - gem "rack" + gem "myrack" G + + pristine_system_gems "bundler-#{current_version}" end it "installs locked version when using system path and uses it" do lockfile_bundled_with(previous_minor) - bundle "config set --local path.system true" - bundle "install", :artifice => "vcr" - expect(out).to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.") + bundle_config "path.system true" + bundle "install" + expect(out).to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.") # It uninstalls the older system bundler - bundle "clean --force" - expect(out).to eq("Removing bundler (#{Bundler::VERSION})") + bundle "clean --force", artifice: nil + expect(out).to eq("Removing bundler (#{current_version})") # App now uses locked version - bundle "-v" - expect(out).to end_with(previous_minor[0] == "2" ? "Bundler version #{previous_minor}" : previous_minor) + bundle "-v", artifice: nil + expect(out).to eq(previous_minor) + + # ruby-core test setup has always "lib" in $LOAD_PATH so `require "bundler/setup"` always activate the local version rather than using RubyGems gem activation stuff + unless ruby_core? + # App now uses locked version, even when not using the CLI directly + file = bundled_app("bin/bundle_version.rb") + create_file file, <<-RUBY + #!#{Gem.ruby} + require 'bundler/setup' + puts '#{previous_minor}' + RUBY + file.chmod(0o777) + cmd = Gem.win_platform? ? "#{Gem.ruby} bin/bundle_version.rb" : "bin/bundle_version.rb" + in_bundled_app cmd + expect(out).to eq(previous_minor) + end # Subsequent installs use the locked version without reinstalling - bundle "install --verbose" + bundle "install --verbose", artifice: nil expect(out).to include("Using bundler #{previous_minor}") - expect(out).not_to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.") + expect(out).not_to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.") end it "installs locked version when using local path and uses it" do lockfile_bundled_with(previous_minor) - bundle "config set --local path vendor/bundle" - bundle "install", :artifice => "vcr" - expect(out).to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.") + bundle_config "path vendor/bundle" + bundle "install" + expect(out).to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.") expect(vendored_gems("gems/bundler-#{previous_minor}")).to exist # It does not uninstall the locked bundler @@ -51,20 +78,39 @@ RSpec.describe "Self management", :rubygems => ">= 3.3.0.dev", :realworld => tru # App now uses locked version bundle "-v" - expect(out).to end_with(previous_minor[0] == "2" ? "Bundler version #{previous_minor}" : previous_minor) + expect(out).to eq(previous_minor) + + # Preserves original gem home when auto-switching + bundle "exec ruby -e 'puts Bundler.original_env[\"GEM_HOME\"]'" + expect(out).to eq(ENV["GEM_HOME"]) + + # ruby-core test setup has always "lib" in $LOAD_PATH so `require "bundler/setup"` always activate the local version rather than using RubyGems gem activation stuff + unless ruby_core? + # App now uses locked version, even when not using the CLI directly + file = bundled_app("bin/bundle_version.rb") + create_file file, <<-RUBY + #!#{Gem.ruby} + require 'bundler/setup' + puts '#{previous_minor}' + RUBY + file.chmod(0o777) + cmd = Gem.win_platform? ? "#{Gem.ruby} bin/bundle_version.rb" : "bin/bundle_version.rb" + in_bundled_app cmd + expect(out).to eq(previous_minor) + end # Subsequent installs use the locked version without reinstalling bundle "install --verbose" expect(out).to include("Using bundler #{previous_minor}") - expect(out).not_to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.") + expect(out).not_to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.") end it "installs locked version when using deployment option and uses it" do lockfile_bundled_with(previous_minor) - bundle "config set --local deployment true" - bundle "install", :artifice => "vcr" - expect(out).to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.") + bundle_config "deployment true" + bundle "install" + expect(out).to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.") expect(vendored_gems("gems/bundler-#{previous_minor}")).to exist # It does not uninstall the locked bundler @@ -73,12 +119,12 @@ RSpec.describe "Self management", :rubygems => ">= 3.3.0.dev", :realworld => tru # App now uses locked version bundle "-v" - expect(out).to end_with(previous_minor[0] == "2" ? "Bundler version #{previous_minor}" : previous_minor) + expect(out).to eq(previous_minor) # Subsequent installs use the locked version without reinstalling bundle "install --verbose" expect(out).to include("Using bundler #{previous_minor}") - expect(out).not_to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.") + expect(out).not_to include("Bundler #{current_version} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.") end it "does not try to install a development version" do @@ -88,19 +134,126 @@ RSpec.describe "Self management", :rubygems => ">= 3.3.0.dev", :realworld => tru expect(out).not_to match(/restarting using that version/) bundle "-v" - expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION) + expect(out).to eq(current_version) + end + + it "does not try to install when --local is passed" do + lockfile_bundled_with(previous_minor) + system_gems "myrack-1.0.0", path: local_gem_path + + bundle "install --local" + expect(out).not_to match(/Installing Bundler/) + + bundle "-v" + expect(out).to eq(current_version) end it "shows a discrete message if locked bundler does not exist" do - missing_minor = "#{Bundler::VERSION[0]}.999.999" + missing_minor = "#{current_version[0]}.999.999" lockfile_bundled_with(missing_minor) - bundle "install", :artifice => "vcr" - expect(err).to eq("Your lockfile is locked to a version of bundler (#{missing_minor}) that doesn't exist at https://rubygems.org/. Going on using #{Bundler::VERSION}") + bundle "install" + expect(err).to eq("Your lockfile is locked to a version of bundler (#{missing_minor}) that doesn't exist at https://rubygems.org/. Going on using #{current_version}") + + bundle "-v" + expect(out).to eq(current_version) + end + + it "installs BUNDLE_VERSION version when using bundle config version x.y.z" do + lockfile_bundled_with(current_version) + + bundle_config "version #{previous_minor}" + bundle "install" + expect(out).to include("Bundler #{current_version} is running, but your configuration was #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.") + + bundle "-v" + expect(out).to eq(previous_minor) + end + + it "requires the right bundler version from the config and run bundle CLI without re-exec" do + unless Bundler.rubygems.provides?(">= 4.1.0.dev") + skip "This spec can only run when Gem::BundlerVersionFinder.bundler_versions reads bundler configs" + end + + lockfile_bundled_with(current_version) + + bundle_config "version #{previous_minor}" + bundle_config "path.system true" + bundle "install" + + script = bundled_app("script.rb") + create_file(script, "p 'executed once'") + + bundle "-v", env: { "RUBYOPT" => "-r#{script}" } + expect(out).to eq(%("executed once"\n9.3.0)) + end + + it "does not try to install when using bundle config version global" do + lockfile_bundled_with(previous_minor) + + bundle_config "version system" + bundle "install" + expect(out).not_to match(/restarting using that version/) bundle "-v" - expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION) + expect(out).to eq(current_version) + end + + it "does not try to install when using bundle config version <dev-version>" do + lockfile_bundled_with(previous_minor) + + bundle_config "version #{previous_minor}.dev" + bundle "install" + expect(out).not_to match(/restarting using that version/) + + bundle "-v" + expect(out).to eq(current_version) + end + + it "ignores malformed lockfile version" do + lockfile_bundled_with("2.3.") + + bundle "install --verbose" + expect(out).to include("Using bundler #{current_version}") + end + + it "uses the right original script when re-execing, if `$0` has been changed to something that's not a script", :ruby_repo do + system_gems "bundler-9.9.9", path: local_gem_path + + test = bundled_app("test.rb") + + create_file test, <<~RUBY + $0 = "this is the program name" + require "bundler/setup" + RUBY + + lockfile_bundled_with("9.9.9") + + in_bundled_app "#{Gem.ruby} #{test}", raise_on_error: false + expect(err).to include("Could not find myrack-1.0.0") + expect(err).not_to include("this is the program name") + end + + it "uses modified $0 when re-execing, if `$0` has been changed to a script", :ruby_repo do + system_gems "bundler-9.9.9", path: local_gem_path + + runner = bundled_app("runner.rb") + + create_file runner, <<~RUBY + $0 = ARGV.shift + load $0 + RUBY + + script = bundled_app("script.rb") + create_file script, <<~RUBY + require "bundler/setup" + RUBY + + lockfile_bundled_with("9.9.9") + + in_bundled_app "#{Gem.ruby} #{runner} #{script}", raise_on_error: false + expect(err).to include("Could not find myrack-1.0.0") end private @@ -108,15 +261,15 @@ RSpec.describe "Self management", :rubygems => ">= 3.3.0.dev", :realworld => tru def lockfile_bundled_with(version) lockfile <<~L GEM - remote: #{file_uri_for(gem_repo2)}/ + remote: https://gem.repo4/ specs: - rack (1.0.0) + myrack (1.0.0) PLATFORMS #{lockfile_platforms} DEPENDENCIES - rack + myrack BUNDLED WITH #{version} diff --git a/spec/bundler/runtime/setup_spec.rb b/spec/bundler/runtime/setup_spec.rb index 9bfcbdaed8..ceb6fcf66a 100644 --- a/spec/bundler/runtime/setup_spec.rb +++ b/spec/bundler/runtime/setup_spec.rb @@ -6,16 +6,16 @@ RSpec.describe "Bundler.setup" do describe "with no arguments" do it "makes all groups available" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", :group => :test + source "https://gem.repo1" + gem "myrack", :group => :test G ruby <<-RUBY require 'bundler' Bundler.setup - require 'rack' - puts RACK + require 'myrack' + puts MYRACK RUBY expect(err).to be_empty expect(out).to eq("1.0.0") @@ -25,9 +25,9 @@ RSpec.describe "Bundler.setup" do describe "when called with groups" do before(:each) do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "yard" - gem "rack", :group => :test + gem "myrack", :group => :test G end @@ -37,7 +37,7 @@ RSpec.describe "Bundler.setup" do Bundler.setup(:default) begin - require 'rack' + require 'myrack' rescue LoadError puts "WIN" end @@ -51,8 +51,8 @@ RSpec.describe "Bundler.setup" do require 'bundler' Bundler.setup(:default, 'test') - require 'rack' - puts RACK + require 'myrack' + puts MYRACK RUBY expect(err).to be_empty expect(out).to eq("1.0.0") @@ -64,8 +64,8 @@ RSpec.describe "Bundler.setup" do Bundler.setup Bundler.setup(:default) - require 'rack' - puts RACK + require 'myrack' + puts MYRACK RUBY expect(err).to be_empty expect(out).to eq("1.0.0") @@ -89,16 +89,16 @@ RSpec.describe "Bundler.setup" do end it "handles multiple non-additive invocations" do - ruby <<-RUBY, :raise_on_error => false + ruby <<-RUBY, raise_on_error: false require 'bundler' Bundler.setup(:default, :test) Bundler.setup(:default) - require 'rack' + require 'myrack' puts "FAIL" RUBY - expect(err).to match("rack") + expect(err).to match("myrack") expect(err).to match("LoadError") expect(out).not_to match("FAIL") end @@ -113,8 +113,8 @@ RSpec.describe "Bundler.setup" do it "puts loaded gems after -I and RUBYLIB", :ruby_repo do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G ENV["RUBYOPT"] = "#{ENV["RUBYOPT"]} -Idash_i_dir" @@ -127,23 +127,24 @@ RSpec.describe "Bundler.setup" do RUBY load_path = out.split("\n") - rack_load_order = load_path.index {|path| path.include?("rack") } + myrack_load_order = load_path.index {|path| path.include?("myrack") } expect(err).to be_empty expect(load_path).to include(a_string_ending_with("dash_i_dir"), "rubylib_dir") - expect(rack_load_order).to be > 0 + expect(myrack_load_order).to be > 0 end it "orders the load path correctly when there are dependencies" do - bundle "config set path.system true" + bundle_config "path.system true" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "rails" G ruby <<-RUBY require 'bundler' + gem "bundler", "#{Bundler::VERSION}" if #{ruby_core?} Bundler.setup puts $LOAD_PATH RUBY @@ -157,15 +158,15 @@ RSpec.describe "Bundler.setup" do "/gems/actionpack-2.3.2/lib", "/gems/actionmailer-2.3.2/lib", "/gems/activesupport-2.3.2/lib", - "/gems/rake-13.0.1/lib" + "/gems/rake-#{rake_version}/lib" ) end it "falls back to order the load path alphabetically for backwards compatibility" do - bundle "config set path.system true" + bundle_config "path.system true" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "weakling" gem "duradura" gem "terranova" @@ -188,12 +189,12 @@ RSpec.describe "Bundler.setup" do it "raises if the Gemfile was not yet installed" do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G ruby <<-R - require '#{entrypoint}' + require 'bundler' begin Bundler.setup @@ -208,11 +209,11 @@ RSpec.describe "Bundler.setup" do it "doesn't create a Gemfile.lock if the setup fails" do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G - ruby <<-R, :raise_on_error => false + ruby <<-R, raise_on_error: false require 'bundler' Bundler.setup @@ -223,19 +224,19 @@ RSpec.describe "Bundler.setup" do it "doesn't change the Gemfile.lock if the setup fails" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G lockfile = File.read(bundled_app_lock) gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" gem "nosuchgem", "10.0" G - ruby <<-R, :raise_on_error => false + ruby <<-R, raise_on_error: false require 'bundler' Bundler.setup @@ -246,8 +247,8 @@ RSpec.describe "Bundler.setup" do it "makes a Gemfile.lock if setup succeeds" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G File.read(bundled_app_lock) @@ -262,12 +263,12 @@ RSpec.describe "Bundler.setup" do context "user provides an absolute path" do it "uses BUNDLE_GEMFILE to locate the gemfile if present" do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G gemfile bundled_app("4realz"), <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "activesupport", "2.3.5" G @@ -281,11 +282,11 @@ RSpec.describe "Bundler.setup" do context "an absolute path is not provided" do it "uses BUNDLE_GEMFILE to locate the gemfile if present and doesn't fail in deployment mode" do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" G bundle "install" - bundle "config set --local deployment true" + bundle_config "deployment true" ENV["BUNDLE_GEMFILE"] = "Gemfile" ruby <<-R @@ -302,28 +303,54 @@ RSpec.describe "Bundler.setup" do expect(out).to eq("WIN") end end + + context "user sets it via `config set --local gemfile`" do + it "uses the value in the config" do + gemfile <<-G + source "https://gem.repo1" + gem "myrack" + G + + gemfile bundled_app("CustomGemfile"), <<-G + source "https://gem.repo1" + gem "activesupport", "2.3.5" + G + + bundle_config "gemfile #{bundled_app("CustomGemfile")}" + bundle "install" + + ruby <<-R + require 'bundler' + Bundler.setup + require 'activesupport' + puts ACTIVESUPPORT + R + + expect(out).to eq("2.3.5") + end + end end it "prioritizes gems in BUNDLE_PATH over gems in GEM_HOME" do ENV["BUNDLE_PATH"] = bundled_app(".bundle").to_s install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", "1.0.0" + source "https://gem.repo1" + gem "myrack", "1.0.0" G - build_gem "rack", "1.0", :to_system => true do |s| - s.write "lib/rack.rb", "RACK = 'FAIL'" + build_gem "myrack", "1.0", to_system: true do |s| + s.write "lib/myrack.rb", "MYRACK = 'FAIL'" end - expect(the_bundle).to include_gems "rack 1.0.0" + expect(the_bundle).to include_gems "myrack 1.0.0" end describe "integrate with rubygems" do describe "by replacing #gem" do before :each do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", "0.9.1" + source "https://gem.repo1" + gem "myrack", "0.9.1" G end @@ -343,7 +370,7 @@ RSpec.describe "Bundler.setup" do it "replaces #gem but raises when the version is wrong" do run <<-R begin - gem "rack", "1.0.0" + gem "myrack", "1.0.0" puts "FAIL" rescue LoadError puts "WIN" @@ -358,20 +385,21 @@ RSpec.describe "Bundler.setup" do before :each do system_gems "activesupport-2.3.5" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "yard" G end it "removes system gems from Gem.source_index" do run "require 'yard'" - expect(out).to eq("bundler-#{Bundler::VERSION}\nyard-1.0") + expect(out).to include("bundler-#{Bundler::VERSION}").and include("yard-1.0") + expect(out).not_to include("activesupport-2.3.5") end context "when the ruby stdlib is a substring of Gem.path" do it "does not reject the stdlib from $LOAD_PATH" do substring = "/" + $LOAD_PATH.find {|p| p.include?("vendor_ruby") }.split("/")[2] - run "puts 'worked!'", :env => { "GEM_PATH" => substring } + run "puts 'worked!'", env: { "GEM_PATH" => substring } expect(out).to eq("worked!") end end @@ -380,37 +408,37 @@ RSpec.describe "Bundler.setup" do describe "with paths" do it "activates the gems in the path source" do - system_gems "rack-1.0.0" + system_gems "myrack-1.0.0" - build_lib "rack", "1.0.0" do |s| - s.write "lib/rack.rb", "puts 'WIN'" + build_lib "myrack", "1.0.0" do |s| + s.write "lib/myrack.rb", "puts 'WIN'" end gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - path "#{lib_path("rack-1.0.0")}" do - gem "rack" + source "https://gem.repo1" + path "#{lib_path("myrack-1.0.0")}" do + gem "myrack" end G - run "require 'rack'" + run "require 'myrack'" expect(out).to eq("WIN") end end describe "with git" do before do - build_git "rack", "1.0.0" + build_git "myrack", "1.0.0" gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-1.0.0")}" + source "https://gem.repo1" + gem "myrack", :git => "#{lib_path("myrack-1.0.0")}" G end it "provides a useful exception when the git repo is not checked out yet" do - run "1", :raise_on_error => false - expect(err).to match(/the git source #{lib_path('rack-1.0.0')} is not yet checked out. Please run `bundle install`/i) + run "1", raise_on_error: false + expect(err).to match(/the git source #{lib_path("myrack-1.0.0")} is not yet checked out. Please run `bundle install`/i) end it "does not hit the git binary if the lockfile is available and up to date" do @@ -440,7 +468,7 @@ RSpec.describe "Bundler.setup" do break_git! ruby <<-R - require "#{entrypoint}" + require "bundler" begin Bundler.setup @@ -450,126 +478,125 @@ RSpec.describe "Bundler.setup" do end R - run "puts 'FAIL'", :raise_on_error => false + run "puts 'FAIL'", raise_on_error: false expect(err).not_to include "This is not the git you are looking for" end it "works even when the cache directory has been deleted" do - bundle "config set --local path vendor/bundle" bundle :install - FileUtils.rm_rf vendored_gems("cache") - expect(the_bundle).to include_gems "rack 1.0.0" + FileUtils.rm_r default_cache_path + expect(the_bundle).to include_gems "myrack 1.0.0" end it "does not randomly change the path when specifying --path and the bundle directory becomes read only" do - bundle "config set --local path vendor/bundle" + bundle_config "path vendor/bundle" bundle :install with_read_only("#{bundled_app}/**/*") do - expect(the_bundle).to include_gems "rack 1.0.0" + expect(the_bundle).to include_gems "myrack 1.0.0" end end it "finds git gem when default bundle path becomes read only" do - bundle "config set --local path .bundle" + bundle_config "path .bundle" bundle "install" with_read_only("#{bundled_app(".bundle")}/**/*") do - expect(the_bundle).to include_gems "rack 1.0.0" + expect(the_bundle).to include_gems "myrack 1.0.0" end end end describe "when specifying local override" do it "explodes if given path does not exist on runtime" do - build_git "rack", "0.8" + build_git "myrack", "0.8" - FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack")) + FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack")) gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main" + source "https://gem.repo1" + gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main" G - bundle %(config set local.rack #{lib_path("local-rack")}) + bundle %(config set local.myrack #{lib_path("local-myrack")}) bundle :install - FileUtils.rm_rf(lib_path("local-rack")) - run "require 'rack'", :raise_on_error => false - expect(err).to match(/Cannot use local override for rack-0.8 because #{Regexp.escape(lib_path('local-rack').to_s)} does not exist/) + FileUtils.rm_r(lib_path("local-myrack")) + run "require 'myrack'", raise_on_error: false + expect(err).to match(/Cannot use local override for myrack-0.8 because #{Regexp.escape(lib_path("local-myrack").to_s)} does not exist/) end it "explodes if branch is not given on runtime" do - build_git "rack", "0.8" + build_git "myrack", "0.8" - FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack")) + FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack")) gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main" + source "https://gem.repo1" + gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main" G - bundle %(config set local.rack #{lib_path("local-rack")}) + bundle %(config set local.myrack #{lib_path("local-myrack")}) bundle :install gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}" + source "https://gem.repo1" + gem "myrack", :git => "#{lib_path("myrack-0.8")}" G - run "require 'rack'", :raise_on_error => false + run "require 'myrack'", raise_on_error: false expect(err).to match(/because :branch is not specified in Gemfile/) end it "explodes on different branches on runtime" do - build_git "rack", "0.8" + build_git "myrack", "0.8" - FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack")) + FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack")) gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main" + source "https://gem.repo1" + gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main" G - bundle %(config set local.rack #{lib_path("local-rack")}) + bundle %(config set local.myrack #{lib_path("local-myrack")}) bundle :install gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "changed" + source "https://gem.repo1" + gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "changed" G - run "require 'rack'", :raise_on_error => false + run "require 'myrack'", raise_on_error: false expect(err).to match(/is using branch main but Gemfile specifies changed/) end it "explodes on refs with different branches on runtime" do - build_git "rack", "0.8" + build_git "myrack", "0.8" - FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack")) + FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack")) install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :ref => "main", :branch => "main" + source "https://gem.repo1" + gem "myrack", :git => "#{lib_path("myrack-0.8")}", :ref => "main", :branch => "main" G gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :ref => "main", :branch => "nonexistent" + source "https://gem.repo1" + gem "myrack", :git => "#{lib_path("myrack-0.8")}", :ref => "main", :branch => "nonexistent" G - bundle %(config set local.rack #{lib_path("local-rack")}) - run "require 'rack'", :raise_on_error => false + bundle %(config set local.myrack #{lib_path("local-myrack")}) + run "require 'myrack'", raise_on_error: false expect(err).to match(/is using branch main but Gemfile specifies nonexistent/) end end describe "when excluding groups" do it "doesn't change the resolve if --without is used" do - bundle "config set --local without rails" + bundle_config "without rails" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "activesupport" group :rails do @@ -579,13 +606,13 @@ RSpec.describe "Bundler.setup" do system_gems "activesupport-2.3.5" - expect(the_bundle).to include_gems "activesupport 2.3.2", :groups => :default + expect(the_bundle).to include_gems "activesupport 2.3.2", groups: :default end it "remembers --without and does not bail on bare Bundler.setup" do - bundle "config set --local without rails" + bundle_config "without rails" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "activesupport" group :rails do @@ -599,20 +626,20 @@ RSpec.describe "Bundler.setup" do end it "remembers --without and does not bail on bare Bundler.setup, even in the case of path gems no longer available" do - bundle "config set --local without development" + bundle_config "without development" path = bundled_app(File.join("vendor", "foo")) - build_lib "foo", :path => path + build_lib "foo", path: path install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "activesupport", "2.3.2" gem 'foo', :path => 'vendor/foo', :group => :development G - FileUtils.rm_rf(path) + FileUtils.rm_r(path) - ruby "require 'bundler'; Bundler.setup", :env => { "DEBUG" => "1" } + ruby "require 'bundler'; Bundler.setup", env: { "DEBUG" => "1" } expect(out).to include("Assuming that source at `vendor/foo` has not changed since fetching its specs errored") expect(out).to include("Found no changes, using resolution from the lockfile") expect(err).to be_empty @@ -628,26 +655,36 @@ RSpec.describe "Bundler.setup" do end install_gemfile <<~G - source "#{file_uri_for(gem_repo4)}" + source "https://gem.repo4" gem "depends_on_bundler" G - ruby "require '#{system_gem_path("gems/bundler-9.99.9.beta1/lib/bundler.rb")}'; Bundler.setup", :env => { "DEBUG" => "1" } + ruby "require '#{system_gem_path("gems/bundler-9.99.9.beta1/lib/bundler.rb")}'; Bundler.setup", env: { "DEBUG" => "1" } expect(out).to include("Found no changes, using resolution from the lockfile") expect(out).not_to include("lockfile does not have all gems needed for the current platform") expect(err).to be_empty end + it "doesn't fail in frozen mode when bundler is a Gemfile dependency" do + install_gemfile <<~G + source "https://gem.repo4" + gem "bundler" + G + + bundle "install --verbose", env: { "BUNDLE_FROZEN" => "true" } + expect(err).to be_empty + end + it "doesn't re-resolve when deleting dependencies" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" gem "actionpack" G - install_gemfile <<-G, :verbose => true - source "#{file_uri_for(gem_repo1)}" - gem "rack" + install_gemfile <<-G, verbose: true + source "https://gem.repo1" + gem "myrack" G expect(out).to include("Some dependencies were deleted, using a subset of the resolution from the lockfile") @@ -655,13 +692,13 @@ RSpec.describe "Bundler.setup" do end it "remembers --without and does not include groups passed to Bundler.setup" do - bundle "config set --local without rails" + bundle_config "without rails" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "activesupport" - group :rack do - gem "rack" + group :myrack do + gem "myrack" end group :rails do @@ -669,19 +706,19 @@ RSpec.describe "Bundler.setup" do end G - expect(the_bundle).not_to include_gems "activesupport 2.3.2", :groups => :rack - expect(the_bundle).to include_gems "rack 1.0.0", :groups => :rack + expect(the_bundle).not_to include_gems "activesupport 2.3.2", groups: :myrack + expect(the_bundle).to include_gems "myrack 1.0.0", groups: :myrack end end # RubyGems returns loaded_from as a string it "has loaded_from as a string on all specs" do build_git "foo" - build_git "no-gemspec", :gemspec => false + build_git "no-gemspec", gemspec: false install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" gem "foo", :git => "#{lib_path("foo-1.0")}" gem "no-gemspec", "1.0", :git => "#{lib_path("no-gemspec-1.0")}" G @@ -695,38 +732,80 @@ RSpec.describe "Bundler.setup" do expect(out).to be_empty end + it "has gem_dir pointing to local repo" do + build_lib "foo", "1.0", path: bundled_app + + install_gemfile <<-G + source "https://gem.repo1" + gemspec + G + + run <<-R + puts Gem.loaded_specs['foo'].gem_dir + R + + expect(out).to eq(bundled_app.to_s) + end + it "does not load all gemspecs" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G run <<-R - File.open(File.join(Gem.dir, "specifications", "broken.gemspec"), "w") do |f| + File.open(File.join(Gem.dir, "specifications", "invalid.gemspec"), "w") do |f| f.write <<-RUBY # -*- encoding: utf-8 -*- -# stub: broken 1.0.0 ruby lib +# stub: invalid 1.0.0 ruby lib Gem::Specification.new do |s| - s.name = "broken" + s.name = "invalid" s.version = "1.0.0" - raise "BROKEN GEMSPEC" + s.authors = ["Invalid Author"] + s.files = ["lib/invalid.rb"] + s.add_dependency "nonexistent-gem", "~> 999.999.999" + s.validate! end RUBY end R run <<-R - puts "WIN" + File.open(File.join(Gem.dir, "specifications", "invalid-ext.gemspec"), "w") do |f| + f.write <<-RUBY +# -*- encoding: utf-8 -*- +# stub: invalid-ext 1.0.0 ruby lib +# stub: a.ext\\0b.ext + +Gem::Specification.new do |s| + s.name = "invalid-ext" + s.version = "1.0.0" + s.authors = ["Invalid Author"] + s.files = ["lib/invalid.rb"] + s.required_ruby_version = "~> 0.8.0" + s.validate! +end + RUBY + end + # Need to write the gem.build_complete file, + # otherwise the full spec is loaded to check the installed_by_version + extensions_dir = Gem.default_ext_dir_for(Gem.dir) || File.join(Gem.dir, "extensions", Gem::Platform.local.to_s, Gem.extension_api_version) + Bundler::FileUtils.mkdir_p(File.join(extensions_dir, "invalid-ext-1.0.0")) + File.open(File.join(extensions_dir, "invalid-ext-1.0.0", "gem.build_complete"), "w") {} R - expect(out).to eq("WIN") + run <<-R + puts "Success" + R + + expect(out).to eq("Success") end it "ignores empty gem paths" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G ENV["GEM_HOME"] = "" @@ -735,6 +814,18 @@ end expect(err).to be_empty end + it "can require rubygems without warnings, when using a local cache", :truffleruby do + install_gemfile <<-G + source "https://gem.repo1" + gem "myrack" + G + + bundle "package" + bundle %(exec ruby -w -e "require 'rubygems'") + + expect(err).to be_empty + end + context "when the user has `MANPATH` set", :man do before { ENV["MANPATH"] = "/foo#{File::PATH_SEPARATOR}" } @@ -746,7 +837,7 @@ end end install_gemfile <<-G - source "#{file_uri_for(gem_repo4)}" + source "https://gem.repo4" gem "with_man" G @@ -770,7 +861,7 @@ end end install_gemfile <<-G - source "#{file_uri_for(gem_repo4)}" + source "https://gem.repo4" gem "with_man" G @@ -783,7 +874,7 @@ end expect(out).to eq("#{default_bundle_path("gems/with_man-1.0/man")}#{File::PATH_SEPARATOR}\ntrue") install_gemfile <<-G - source "#{file_uri_for(gem_repo4)}" + source "https://gem.repo4" gem "with_man_overriding_system_man" G @@ -810,7 +901,7 @@ end end install_gemfile <<-G - source "#{file_uri_for(gem_repo2)}" + source "https://gem.repo2" gem "requirepaths", :require => nil G @@ -821,21 +912,14 @@ end it "should clean $LOAD_PATH properly" do gem_name = "very_simple_binary" full_gem_name = gem_name + "-1.0" - ext_dir = File.join(tmp("extensions", full_gem_name)) system_gems full_gem_name install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" G ruby <<-R - s = Gem::Specification.find_by_name '#{gem_name}' - s.extension_dir = '#{ext_dir}' - - # Don't build extensions. - s.class.send(:define_method, :build_extensions) { nil } - require 'bundler' gem '#{gem_name}' @@ -873,9 +957,9 @@ end end it "should not remove itself from the LOAD_PATH and require a different copy of 'bundler/setup'" do - install_gemfile "source \"#{file_uri_for(gem_repo1)}\"" + install_gemfile "source 'https://gem.repo1'" - ruby <<-R, :env => { "GEM_PATH" => symlinked_gem_home } + ruby <<-R, env: { "GEM_PATH" => symlinked_gem_home } TracePoint.trace(:class) do |tp| if tp.path.include?("bundler") && !tp.path.start_with?("#{source_root}") puts "OMG. Defining a class from another bundler at \#{tp.path}:\#{tp.lineno}" @@ -890,17 +974,17 @@ end end it "does not reveal system gems even when Gem.refresh is called" do - system_gems "rack-1.0.0" + system_gems "myrack-1.0.0" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "activesupport" G run <<-R - puts Bundler.rubygems.all_specs.map(&:name) + puts Bundler.rubygems.installed_specs.map(&:name) Gem.refresh - puts Bundler.rubygems.all_specs.map(&:name) + puts Bundler.rubygems.installed_specs.map(&:name) R expect(out).to eq("activesupport\nbundler\nactivesupport\nbundler") @@ -915,18 +999,18 @@ end it "should resolve paths relative to the Gemfile" do path = bundled_app(File.join("vendor", "foo")) - build_lib "foo", :path => path + build_lib "foo", path: path # If the .gemspec exists, then Bundler handles the path differently. # See Source::Path.load_spec_files for details. FileUtils.rm(File.join(path, "foo.gemspec")) install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem 'foo', '1.2.3', :path => 'vendor/foo' G - run <<-R, :env => { "BUNDLE_GEMFILE" => bundled_app_gemfile.to_s }, :dir => bundled_app.parent + run <<-R, env: { "BUNDLE_GEMFILE" => bundled_app_gemfile.to_s }, dir: bundled_app.parent require 'foo' R expect(err).to be_empty @@ -936,20 +1020,20 @@ end relative_path = File.join("vendor", Dir.pwd.gsub(/^#{filesystem_root}/, "")) absolute_path = bundled_app(relative_path) FileUtils.mkdir_p(absolute_path) - build_lib "foo", :path => absolute_path + build_lib "foo", path: absolute_path # If the .gemspec exists, then Bundler handles the path differently. # See Source::Path.load_spec_files for details. FileUtils.rm(File.join(absolute_path, "foo.gemspec")) gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem 'foo', '1.2.3', :path => '#{relative_path}' G bundle :install - run <<-R, :env => { "BUNDLE_GEMFILE" => bundled_app_gemfile.to_s }, :dir => bundled_app.parent + run <<-R, env: { "BUNDLE_GEMFILE" => bundled_app_gemfile.to_s }, dir: bundled_app.parent require 'foo' R @@ -959,10 +1043,10 @@ end describe "with git gems that don't have gemspecs" do before :each do - build_git "no_gemspec", :gemspec => false + build_git "no_gemspec", gemspec: false install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "no_gemspec", "1.0", :git => "#{lib_path("no_gemspec-1.0")}" G end @@ -979,10 +1063,10 @@ end describe "with bundled and system gems" do before :each do - system_gems "rack-1.0.0" + system_gems "myrack-1.0.0" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "activesupport", "2.3.5" G @@ -991,7 +1075,7 @@ end it "does not pull in system gems" do run <<-R begin; - require 'rack' + require 'myrack' rescue LoadError puts 'WIN' end @@ -1013,13 +1097,13 @@ end it "raises an exception if gem is used to invoke a system gem not in the bundle" do run <<-R begin - gem 'rack' + gem 'myrack' rescue LoadError => e puts e.message end R - expect(out).to eq("rack is not part of the bundle. Add it to your Gemfile.") + expect(out).to eq("myrack is not part of the bundle. Add it to your Gemfile.") end it "sets GEM_HOME appropriately" do @@ -1030,12 +1114,12 @@ end describe "with system gems in the bundle" do before :each do - bundle "config set path.system true" - system_gems "rack-1.0.0" + bundle_config "path.system true" + system_gems "myrack-1.0.0" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack", "1.0.0" + source "https://gem.repo1" + gem "myrack", "1.0.0" gem "activesupport", "2.3.5" G end @@ -1049,7 +1133,7 @@ end describe "with a gemspec that requires other files" do before :each do - build_git "bar", :gemspec => false do |s| + build_git "bar", gemspec: false do |s| s.write "lib/bar/version.rb", %(BAR_VERSION = '1.0') s.write "bar.gemspec", <<-G require_relative 'lib/bar/version' @@ -1065,7 +1149,7 @@ end end gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "bar", :git => "#{lib_path("bar-1.0")}" G end @@ -1079,10 +1163,10 @@ end it "error intelligently if the gemspec has a LoadError" do skip "whitespace issue?" if Gem.win_platform? - ref = update_git "bar", :gemspec => false do |s| + ref = update_git "bar", gemspec: false do |s| s.write "bar.gemspec", "require 'foobarbaz'" end.ref_for("HEAD") - bundle :install, :raise_on_error => false + bundle :install, raise_on_error: false expect(err.lines.map(&:chomp)).to include( a_string_starting_with("[!] There was an error while loading `bar.gemspec`:"), @@ -1099,7 +1183,7 @@ end bundler_module = class << Bundler; self; end bundler_module.send(:remove_method, :require) def Bundler.require(path) - raise "LOSE" + raise StandardError, "didn't use binding from top level" end Bundler.load RUBY @@ -1112,7 +1196,7 @@ end describe "when Bundler is bundled" do it "doesn't blow up" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "bundler", :path => "#{root}" G @@ -1125,15 +1209,15 @@ end def lock_with(bundler_version = nil) lock = <<~L GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: https://gem.repo1/ specs: - rack (1.0.0) + myrack (1.0.0) PLATFORMS #{lockfile_platforms} DEPENDENCIES - rack + myrack L if bundler_version @@ -1144,18 +1228,18 @@ end end before do - bundle "config set --local path.system true" + bundle_config "path.system true" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G end context "is not present" do it "does not change the lock" do lockfile lock_with(nil) - ruby "require '#{entrypoint}/setup'" + ruby "require 'bundler/setup'" expect(lockfile).to eq lock_with(nil) end end @@ -1174,7 +1258,7 @@ end it "does not change the lock" do system_gems "bundler-1.10.1" lockfile lock_with("1.10.1") - ruby "require '#{entrypoint}/setup'" + ruby "require 'bundler/setup'" expect(lockfile).to eq lock_with("1.10.1") end end @@ -1184,17 +1268,22 @@ end let(:ruby_version) { nil } def lock_with(ruby_version = nil) + checksums = checksums_section do |c| + c.checksum gem_repo1, "myrack", "1.0.0" + end + lock = <<~L GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: https://gem.repo1/ specs: - rack (1.0.0) + myrack (1.0.0) PLATFORMS #{lockfile_platforms} DEPENDENCIES - rack + myrack + #{checksums} L if ruby_version @@ -1204,7 +1293,7 @@ end lock += <<~L BUNDLED WITH - #{Bundler::VERSION} + #{Bundler::VERSION} L lock @@ -1213,14 +1302,19 @@ end before do install_gemfile <<-G ruby ">= 0" - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G lockfile lock_with(ruby_version) end context "is not present" do - it "does not change the lock" do + # Skipped on ruby-core because `ruby "require 'bundler/setup'"` does not + # activate bundler as a gem there, so Source::Metadata falls back to a + # synthetic spec whose cache_file does not exist on disk and + # LockfileGenerator#bundler_checksum drops the bundler checksum, while + # the on-disk lockfile still has it. + it "does not change the lock", :ruby_repo do expect { ruby "require 'bundler/setup'" }.not_to change { lockfile } end end @@ -1244,9 +1338,7 @@ end describe "with gemified standard libraries" do it "does not load Digest", :ruby_repo do - skip "Only for Ruby 3.0+" unless RUBY_VERSION >= "3.0" - - build_git "bar", :gemspec => false do |s| + build_git "bar", gemspec: false do |s| s.write "lib/bar/version.rb", %(BAR_VERSION = '1.0') s.write "bar.gemspec", <<-G require_relative 'lib/bar/version' @@ -1258,20 +1350,20 @@ end s.files = Dir["lib/**/*.rb"] s.author = 'no one' - s.add_runtime_dependency 'digest' + s.add_dependency 'digest' end G end gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "bar", :git => "#{lib_path("bar-1.0")}" G - bundle :install + bundle :install, env: { "BUNDLE_LOCKFILE_CHECKSUMS" => "false" } - ruby <<-RUBY - require '#{entrypoint}/setup' + ruby <<-RUBY, artifice: nil + require 'bundler/setup' puts defined?(::Digest) ? "Digest defined" : "Digest undefined" require 'digest' RUBY @@ -1279,9 +1371,9 @@ end end it "does not load Psych" do - gemfile "source \"#{file_uri_for(gem_repo1)}\"" + gemfile "source 'https://gem.repo1'" ruby <<-RUBY - require '#{entrypoint}/setup' + require 'bundler/setup' puts defined?(Psych::VERSION) ? Psych::VERSION : "undefined" require 'psych' puts Psych::VERSION @@ -1292,8 +1384,8 @@ end end it "does not load openssl" do - install_gemfile "source \"#{file_uri_for(gem_repo1)}\"" - ruby <<-RUBY + install_gemfile "source 'https://gem.repo1'" + ruby <<-RUBY, artifice: nil require "bundler/setup" puts defined?(OpenSSL) || "undefined" require "openssl" @@ -1302,20 +1394,62 @@ end expect(out).to eq("undefined\nconstant") end + it "does not load uri while reading gemspecs", rubygems: ">= 3.6.0.dev" do + Dir.mkdir bundled_app("test") + + create_file(bundled_app("test/test.gemspec"), <<-G) + Gem::Specification.new do |s| + s.name = "test" + s.version = "1.0.0" + s.summary = "test" + s.authors = ['John Doe'] + s.homepage = 'https://example.com' + end + G + + install_gemfile <<-G + source "https://gem.repo1" + gem "test", path: "#{bundled_app("test")}" + G + + ruby <<-RUBY, artifice: nil + require "bundler/setup" + puts defined?(URI) || "undefined" + require "uri" + puts defined?(URI) || "undefined" + RUBY + expect(out).to eq("undefined\nconstant") + end + + it "activates default gems when they are part of the bundle, but not installed explicitly", :ruby_repo do + default_delegate_version = ruby "gem 'delegate'; require 'delegate'; puts Delegator::VERSION" + + build_repo2 do + build_gem "delegate", default_delegate_version + end + + gemfile "source \"https://gem.repo2\"; gem 'delegate'" + + ruby <<-RUBY + require "bundler/setup" + require "delegate" + puts defined?(::Delegator) ? "Delegator defined" : "Delegator undefined" + RUBY + + expect(out).to eq("Delegator defined") + expect(err).to be_empty + end + describe "default gem activation" do let(:exemptions) do - exempts = %w[did_you_mean bundler] - exempts << "uri" if Gem.ruby_version >= Gem::Version.new("2.7") - exempts << "pathname" if Gem.ruby_version >= Gem::Version.new("3.0") - exempts << "set" unless Gem.rubygems_version >= Gem::Version.new("3.2.6") - exempts << "tsort" unless Gem.rubygems_version >= Gem::Version.new("3.2.31") + exempts = %w[did_you_mean bundler uri pathname] exempts << "error_highlight" # added in Ruby 3.1 as a default gem exempts << "ruby2_keywords" # added in Ruby 3.1 as a default gem exempts << "syntax_suggest" # added in Ruby 3.2 as a default gem exempts end - let(:activation_warning_hack) { strip_whitespace(<<-RUBY) } + let(:activation_warning_hack) { <<~RUBY } require #{spec_dir.join("support/hax").to_s.dump} Gem::Specification.send(:alias_method, :bundler_spec_activate, :activate) @@ -1335,7 +1469,7 @@ end "-r#{bundled_app("activation_warning_hack.rb")} #{ENV["RUBYOPT"]}" end - let(:code) { strip_whitespace(<<-RUBY) } + let(:code) { <<~RUBY } require "pp" loaded_specs = Gem.loaded_specs.dup #{exemptions.inspect}.each {|s| loaded_specs.delete(s) } @@ -1349,25 +1483,25 @@ end RUBY it "activates no gems with -rbundler/setup" do - install_gemfile "source \"#{file_uri_for(gem_repo1)}\"" - ruby code, :env => { "RUBYOPT" => activation_warning_hack_rubyopt + " -rbundler/setup" } + install_gemfile "source 'https://gem.repo1'" + ruby code, env: { "RUBYOPT" => activation_warning_hack_rubyopt + " -rbundler/setup" }, artifice: nil expect(out).to eq("{}") end it "activates no gems with bundle exec" do - install_gemfile "source \"#{file_uri_for(gem_repo1)}\"" + install_gemfile "source 'https://gem.repo1'" create_file("script.rb", code) - bundle "exec ruby ./script.rb", :env => { "RUBYOPT" => activation_warning_hack_rubyopt } + bundle "exec ruby ./script.rb", env: { "RUBYOPT" => activation_warning_hack_rubyopt } expect(out).to eq("{}") end it "activates no gems with bundle exec that is loaded" do skip "not executable" if Gem.win_platform? - install_gemfile "source \"#{file_uri_for(gem_repo1)}\"" + install_gemfile "source 'https://gem.repo1'" create_file("script.rb", "#!/usr/bin/env ruby\n\n#{code}") FileUtils.chmod(0o777, bundled_app("script.rb")) - bundle "exec ./script.rb", :artifice => nil, :env => { "RUBYOPT" => activation_warning_hack_rubyopt } + bundle "exec ./script.rb", env: { "RUBYOPT" => activation_warning_hack_rubyopt } expect(out).to eq("{}") end @@ -1376,14 +1510,14 @@ end build_gem "net-http-pipeline", "1.0.1" end - system_gems "net-http-pipeline-1.0.1", :gem_repo => gem_repo4 + system_gems "net-http-pipeline-1.0.1", gem_repo: gem_repo4 gemfile <<-G - source "#{file_uri_for(gem_repo4)}" + source "https://gem.repo4" gem "net-http-pipeline", "1.0.1" G - bundle "config set --local path vendor/bundle" + bundle_config "path vendor/bundle" bundle :install @@ -1401,11 +1535,11 @@ end end install_gemfile <<-G - source "#{file_uri_for(gem_repo4)}" + source "https://gem.repo4" gem "#{g}", "999999" G - expect(the_bundle).to include_gem("#{g} 999999", :env => { "RUBYOPT" => activation_warning_hack_rubyopt }) + expect(the_bundle).to include_gem("#{g} 999999", env: { "RUBYOPT" => activation_warning_hack_rubyopt }, artifice: nil) end it "activates older versions of #{g}", :ruby_repo do @@ -1416,84 +1550,63 @@ end end install_gemfile <<-G - source "#{file_uri_for(gem_repo4)}" + source "https://gem.repo4" gem "#{g}", "0.0.0.a" G - expect(the_bundle).to include_gem("#{g} 0.0.0.a", :env => { "RUBYOPT" => activation_warning_hack_rubyopt }) + expect(the_bundle).to include_gem("#{g} 0.0.0.a", env: { "RUBYOPT" => activation_warning_hack_rubyopt }, artifice: nil) end end end end describe "after setup" do - it "allows calling #gem on random objects", :bundler => "< 3" do - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" - G - - ruby <<-RUBY - require "bundler/setup" - Object.new.gem "rack" - puts Gem.loaded_specs["rack"].full_name - RUBY - - expect(out).to eq("rack-1.0.0") - end - - it "keeps Kernel#gem private", :bundler => "3" do + it "keeps Kernel#gem private" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G - ruby <<-RUBY, :raise_on_error => false + ruby <<-RUBY, raise_on_error: false require "bundler/setup" - Object.new.gem "rack" + Object.new.gem "myrack" puts "FAIL" RUBY - expect(last_command.stdboth).not_to include "FAIL" - expect(err).to include "private method `gem'" + expect(stdboth).not_to include "FAIL" + expect(err).to match(/private method [`']gem'/) end it "keeps Kernel#require private" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" + source "https://gem.repo1" + gem "myrack" G - ruby <<-RUBY, :raise_on_error => false + ruby <<-RUBY, raise_on_error: false require "bundler/setup" - Object.new.require "rack" + Object.new.require "myrack" puts "FAIL" RUBY - expect(last_command.stdboth).not_to include "FAIL" - expect(err).to include "private method `require'" - end - - it "takes care of requiring rubygems" do - sys_exec("#{Gem.ruby} -I#{lib_dir} -rbundler/setup -e'puts true'", :env => { "RUBYOPT" => opt_add("--disable=gems", ENV["RUBYOPT"]) }) - - expect(last_command.stdboth).to eq("true") + expect(stdboth).not_to include "FAIL" + expect(err).to match(/private method [`']require'/) end it "memoizes initial set of specs when requiring bundler/setup, so that even if further code mutates dependencies, Bundler.definition.specs is not affected" do install_gemfile <<~G - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo1" gem "yard" - gem "rack", :group => :test + gem "myrack", :group => :test G - ruby <<-RUBY, :raise_on_error => false + ruby <<-RUBY, raise_on_error: false require "bundler/setup" Bundler.require(:test).select! {|d| (d.groups & [:test]).any? } puts Bundler.definition.specs.map(&:name).join(", ") RUBY - expect(out).to include("rack, yard") + expect(out).to include("myrack, yard") end it "does not cause double loads when higher versions of default gems are activated before bundler" do @@ -1507,9 +1620,9 @@ end end end - system_gems "json-999.999.999", :gem_repo => gem_repo2 + system_gems "json-999.999.999", gem_repo: gem_repo2 - install_gemfile "source \"#{file_uri_for(gem_repo1)}\"" + install_gemfile "source 'https://gem.repo1'" ruby <<-RUBY require "json" require "bundler/setup" @@ -1520,8 +1633,8 @@ end end end - it "does not undo the Kernel.require decorations", :rubygems => ">= 3.4.6" do - install_gemfile "source \"#{file_uri_for(gem_repo1)}\"" + it "does not undo the Kernel.require decorations", rubygems: ">= 3.4.6" do + install_gemfile "source 'https://gem.repo1'" script = bundled_app("bin/script") create_file(script, <<~RUBY) module Kernel @@ -1541,7 +1654,57 @@ end require "foo" RUBY - sys_exec "#{Gem.ruby} #{script}", :raise_on_error => false + sys_exec "#{Gem.ruby} #{script}", raise_on_error: false expect(out).to include("requiring foo used the monkeypatch") end + + it "performs an automatic bundle install" do + build_repo4 do + build_gem "myrack", "1.0.0" + end + + gemfile <<-G + source "https://gem.repo1" + gem "myrack", :group => :test + G + + bundle_config "auto_install 1" + + ruby <<-RUBY, artifice: "compact_index" + require 'bundler/setup' + RUBY + expect(err).to be_empty + expect(out).to include("Installing myrack 1.0.0") + end + + context "in a read-only filesystem" do + before do + gemfile <<-G + source "https://gem.repo4" + G + + lockfile <<-L + GEM + remote: https://gem.repo4/ + + PLATFORMS + x86_64-darwin-19 + + DEPENDENCIES + + BUNDLED WITH + #{Bundler::VERSION} + L + end + + it "should fail loudly if the lockfile platforms don't include the current platform" do + simulate_platform "x86_64-linux" do + ruby <<-RUBY, raise_on_error: false, env: { "BUNDLER_SPEC_READ_ONLY" => "true", "BUNDLER_FORCE_TTY" => "true" } + require "bundler/setup" + RUBY + end + + expect(err).to include("Your lockfile is missing the current platform, but can't be updated because file system is read-only") + end + end end |
