diff options
Diffstat (limited to 'spec/bundler/install/gemfile/sources_spec.rb')
-rw-r--r-- | spec/bundler/install/gemfile/sources_spec.rb | 884 |
1 files changed, 504 insertions, 380 deletions
diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb index bf150c115a..d13ba0e607 100644 --- a/spec/bundler/install/gemfile/sources_spec.rb +++ b/spec/bundler/install/gemfile/sources_spec.rb @@ -20,23 +20,23 @@ RSpec.describe "bundle install with gems on multiple sources" do before do gemfile <<-G - source "#{file_uri_for(gem_repo3)}" - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo3" + source "https://gem.repo1" gem "rack-obama" gem "rack" G end it "warns about ambiguous gems, but installs anyway, prioritizing sources last to first", :bundler => "< 3" do - bundle :install + bundle :install, :artifice => "compact_index" expect(err).to include("Warning: the gem 'rack' was found in multiple sources.") - expect(err).to include("Installed from: #{file_uri_for(gem_repo1)}") + expect(err).to include("Installed from: https://gem.repo1") expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0", :source => "remote1") end it "fails", :bundler => "3" do - bundle :instal, :raise_on_error => false + bundle :instal, :artifice => "compact_index", :raise_on_error => false expect(err).to include("Each source after the first must include a block") expect(exitstatus).to eq(4) end @@ -47,22 +47,22 @@ RSpec.describe "bundle install with gems on multiple sources" do before do gemfile <<-G - source "#{file_uri_for(gem_repo3)}" - source "#{file_uri_for(gem_repo1)}" + source "https://gem.repo3" + source "https://gem.repo1" gem "rack-obama" gem "rack", "1.0.0" # force it to install the working version in repo1 G end it "warns about ambiguous gems, but installs anyway", :bundler => "< 3" do - bundle :install + bundle :install, :artifice => "compact_index" expect(err).to include("Warning: the gem 'rack' was found in multiple sources.") - expect(err).to include("Installed from: #{file_uri_for(gem_repo1)}") + expect(err).to include("Installed from: https://gem.repo1") expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0", :source => "remote1") end it "fails", :bundler => "3" do - bundle :install, :raise_on_error => false + bundle :install, :artifice => "compact_index", :raise_on_error => false expect(err).to include("Each source after the first must include a block") expect(exitstatus).to eq(4) end @@ -85,8 +85,8 @@ RSpec.describe "bundle install with gems on multiple sources" do end gemfile <<-G - source "#{file_uri_for(gem_repo3)}" - source "#{file_uri_for(gem_repo1)}" do + source "https://gem.repo3" + source "https://gem.repo1" do gem "thin" # comes first to test name sorting gem "rack" end @@ -95,20 +95,20 @@ RSpec.describe "bundle install with gems on multiple sources" do end it "installs the gems without any warning" do - bundle :install + bundle :install, :artifice => "compact_index" expect(err).not_to include("Warning") expect(the_bundle).to include_gems("rack-obama 1.0.0") expect(the_bundle).to include_gems("rack 1.0.0", :source => "remote1") end it "can cache and deploy" do - bundle :cache + bundle :cache, :artifice => "compact_index" expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist expect(bundled_app("vendor/cache/rack-obama-1.0.gem")).to exist - bundle "config --local deployment true" - bundle :install + bundle "config set --local deployment true" + bundle :install, :artifice => "compact_index" expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0") end @@ -128,10 +128,10 @@ RSpec.describe "bundle install with gems on multiple sources" do end end - install_gemfile <<-G - source "#{file_uri_for(gem_repo3)}" + install_gemfile <<-G, :artifice => "compact_index" + source "https://gem.repo3" gem "rack-obama" # should come from repo3! - gem "rack", :source => "#{file_uri_for(gem_repo1)}" + gem "rack", :source => "https://gem.repo1" G end @@ -155,8 +155,8 @@ RSpec.describe "bundle install with gems on multiple sources" do end gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - source "#{file_uri_for(gem_repo3)}" do + source "https://gem.repo2" + source "https://gem.repo3" do gem "depends_on_rack" end G @@ -168,7 +168,7 @@ RSpec.describe "bundle install with gems on multiple sources" do end it "installs from the same source without any warning" do - bundle :install + bundle :install, :artifice => "compact_index" expect(err).not_to include("Warning") expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3") end @@ -185,7 +185,7 @@ RSpec.describe "bundle install with gems on multiple sources" do end it "installs from the same source without any warning" do - bundle :install + bundle :install, :artifice => "compact_index" expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3") @@ -193,7 +193,7 @@ RSpec.describe "bundle install with gems on multiple sources" do # In https://github.com/bundler/bundler/issues/3585 this failed # when there is already a lock file, and the gems are missing, so try again system_gems [] - bundle :install + bundle :install, :artifice => "compact_index" expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3") @@ -218,9 +218,9 @@ RSpec.describe "bundle install with gems on multiple sources" do context "and not in any other sources" do before do - install_gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - source "#{file_uri_for(gem_repo3)}" do + install_gemfile <<-G, :artifice => "compact_index" + source "https://gem.repo2" + source "https://gem.repo3" do gem "depends_on_rack" end G @@ -235,23 +235,23 @@ RSpec.describe "bundle install with gems on multiple sources" do context "and in yet another source" do before do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - source "#{file_uri_for(gem_repo2)}" - source "#{file_uri_for(gem_repo3)}" do + source "https://gem.repo1" + source "https://gem.repo2" + source "https://gem.repo3" do gem "depends_on_rack" end G end it "installs from the other source and warns about ambiguous gems", :bundler => "< 3" do - bundle :install + bundle :install, :artifice => "compact_index" expect(err).to include("Warning: the gem 'rack' was found in multiple sources.") - expect(err).to include("Installed from: #{file_uri_for(gem_repo2)}") + expect(err).to include("Installed from: https://gem.repo2") expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") end it "fails", :bundler => "3" do - bundle :install, :raise_on_error => false + bundle :install, :artifice => "compact_index", :raise_on_error => false expect(err).to include("Each source after the first must include a block") expect(exitstatus).to eq(4) end @@ -267,16 +267,16 @@ RSpec.describe "bundle install with gems on multiple sources" do end gemfile <<-G - source "#{file_uri_for(gem_repo3)}" # contains depends_on_rack - source "#{file_uri_for(gem_repo2)}" # contains broken rack + source "https://gem.repo3" # contains depends_on_rack + source "https://gem.repo2" # contains broken rack gem "depends_on_rack" # installed from gem_repo3 - gem "rack", :source => "#{file_uri_for(gem_repo1)}" + gem "rack", :source => "https://gem.repo1" G end it "installs the dependency from the pinned source without warning", :bundler => "< 3" do - bundle :install + bundle :install, :artifice => "compact_index" expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") @@ -284,14 +284,14 @@ RSpec.describe "bundle install with gems on multiple sources" do # In https://github.com/rubygems/bundler/issues/3585 this failed # when there is already a lock file, and the gems are missing, so try again system_gems [] - bundle :install + bundle :install, :artifice => "compact_index" expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") end it "fails", :bundler => "3" do - bundle :install, :raise_on_error => false + bundle :install, :artifice => "compact_index", :raise_on_error => false expect(err).to include("Each source after the first must include a block") expect(exitstatus).to eq(4) end @@ -308,360 +308,457 @@ RSpec.describe "bundle install with gems on multiple sources" do end gemfile <<-G - source "#{file_uri_for(gem_repo2)}" + source "https://gem.repo2" gem "private_gem_1" - source "#{file_uri_for(gem_repo3)}" do + source "https://gem.repo3" do gem "private_gem_2" end G end it "fails" do - bundle :install, :raise_on_error => false - expect(err).to include("Could not find gem 'private_gem_1' in rubygems repository #{file_uri_for(gem_repo2)}/ or installed locally.") + bundle :install, :artifice => "compact_index", :raise_on_error => false + expect(err).to include("Could not find gem 'private_gem_1' in rubygems repository https://gem.repo2/ or installed locally.") expect(err).to include("The source does not contain any versions of 'private_gem_1'") end end - context "when a top-level gem has an indirect dependency" do - context "when disable_multisource is set" do - before do - bundle "config set disable_multisource true" + context "when an indirect dependency can't be found in the aggregate rubygems source", :bundler => "< 3" do + before do + build_repo2 + + build_repo gem_repo3 do + build_gem "depends_on_missing", "1.0.1" do |s| + s.add_dependency "missing" + end end - before do - build_repo gem_repo2 do - build_gem "depends_on_rack", "1.0.1" do |s| - s.add_dependency "rack" - end + gemfile <<-G + source "https://gem.repo2" + + source "https://gem.repo3" + + gem "depends_on_missing" + G + end + + it "fails" do + bundle :install, :artifice => "compact_index", :raise_on_error => false + expect(err).to include("Could not find gem 'missing', which is required by gem 'depends_on_missing', in any of the sources.") + end + end + + context "when a top-level gem has an indirect dependency" do + before do + build_repo gem_repo2 do + build_gem "depends_on_rack", "1.0.1" do |s| + s.add_dependency "rack" end + end + + build_repo gem_repo3 do + build_gem "unrelated_gem", "1.0.0" + end - build_repo gem_repo3 do - build_gem "unrelated_gem", "1.0.0" + gemfile <<-G + source "https://gem.repo2" + + gem "depends_on_rack" + + source "https://gem.repo3" do + gem "unrelated_gem" end + G + end - gemfile <<-G - source "#{file_uri_for(gem_repo2)}" + context "and the dependency is only in the top-level source" do + before do + update_repo gem_repo2 do + build_gem "rack", "1.0.0" + end + end - gem "depends_on_rack" + it "installs the dependency from the top-level source without warning" do + bundle :install, :artifice => "compact_index" + expect(err).not_to include("Warning") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote2") + expect(the_bundle).to include_gems("unrelated_gem 1.0.0", :source => "remote3") + end + end - source "#{file_uri_for(gem_repo3)}" do - gem "unrelated_gem" + context "and the dependency is only in a pinned source" do + before do + update_repo gem_repo3 do + build_gem "rack", "1.0.0" do |s| + s.write "lib/rack.rb", "RACK = 'FAIL'" end - G + end end - context "and the dependency is only in the top-level source" do - before do - update_repo gem_repo2 do - build_gem "rack", "1.0.0" - end + it "does not find the dependency" do + bundle :install, :artifice => "compact_index", :raise_on_error => false + expect(err).to include( + "Could not find gem 'rack', which is required by gem 'depends_on_rack', in rubygems repository https://gem.repo2/ or installed locally." + ) + end + end + + context "and the dependency is in both the top-level and a pinned source" do + before do + update_repo gem_repo2 do + build_gem "rack", "1.0.0" end - it "installs all gems without warning" do - bundle :install - expect(err).not_to include("Warning") - expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0") + update_repo gem_repo3 do + build_gem "rack", "1.0.0" do |s| + s.write "lib/rack.rb", "RACK = 'FAIL'" + end end end - context "and the dependency is only in a pinned source" do - before do - update_repo gem_repo3 do - build_gem "rack", "1.0.0" do |s| - s.write "lib/rack.rb", "RACK = 'FAIL'" - end - end + it "installs the dependency from the top-level source without warning" do + bundle :install, :artifice => "compact_index" + expect(err).not_to include("Warning") + expect(run("require 'rack'; puts RACK")).to eq("1.0.0") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote2") + expect(the_bundle).to include_gems("unrelated_gem 1.0.0", :source => "remote3") + end + end + end + + context "when a scoped gem has a deeply nested indirect dependency" do + before do + build_repo gem_repo3 do + build_gem "depends_on_depends_on_rack", "1.0.1" do |s| + s.add_dependency "depends_on_rack" end - it "does not find the dependency" do - bundle :install, :raise_on_error => false - expect(err).to include("Could not find gem 'rack', which is required by gem 'depends_on_rack', in any of the relevant sources") + build_gem "depends_on_rack", "1.0.1" do |s| + s.add_dependency "rack" end end - context "and the dependency is in both the top-level and a pinned source" do - before do - update_repo gem_repo2 do - build_gem "rack", "1.0.0" - end + gemfile <<-G + source "https://gem.repo2" - update_repo gem_repo3 do - build_gem "rack", "1.0.0" do |s| - s.write "lib/rack.rb", "RACK = 'FAIL'" - end - end + source "https://gem.repo3" do + gem "depends_on_depends_on_rack" end + G + end - it "installs the dependency from the top-level source without warning" do - bundle :install - expect(err).not_to include("Warning") - expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0") + context "and the dependency is only in the top-level source" do + before do + update_repo gem_repo2 do + build_gem "rack", "1.0.0" end end + + it "installs the dependency from the top-level source" do + bundle :install, :artifice => "compact_index" + expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0") + expect(the_bundle).to include_gems("rack 1.0.0", :source => "remote2") + expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", :source => "remote3") + end end - context "when the lockfile has aggregated rubygems sources and newer versions of dependencies are available" do + context "and the dependency is only in a pinned source" do before do - build_repo gem_repo2 do - build_gem "activesupport", "6.0.3.4" do |s| - s.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.2" - s.add_dependency "i18n", ">= 0.7", "< 2" - s.add_dependency "minitest", "~> 5.1" - s.add_dependency "tzinfo", "~> 1.1" - s.add_dependency "zeitwerk", "~> 2.2", ">= 2.2.2" - end + build_repo2 - build_gem "activesupport", "6.1.2.1" do |s| - s.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.2" - s.add_dependency "i18n", ">= 1.6", "< 2" - s.add_dependency "minitest", ">= 5.1" - s.add_dependency "tzinfo", "~> 2.0" - s.add_dependency "zeitwerk", "~> 2.3" - end + update_repo gem_repo3 do + build_gem "rack", "1.0.0" + end + end - build_gem "concurrent-ruby", "1.1.8" - build_gem "concurrent-ruby", "1.1.9" - build_gem "connection_pool", "2.2.3" + it "installs the dependency from the pinned source" do + bundle :install, :artifice => "compact_index" + expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3") + end + end - build_gem "i18n", "1.8.9" do |s| - s.add_dependency "concurrent-ruby", "~> 1.0" + context "and the dependency is in both the top-level and a pinned source" do + before do + update_repo gem_repo2 do + build_gem "rack", "1.0.0" do |s| + s.write "lib/rack.rb", "RACK = 'FAIL'" end + end - build_gem "minitest", "5.14.3" - build_gem "rack", "2.2.3" - build_gem "redis", "4.2.5" + update_repo gem_repo3 do + build_gem "rack", "1.0.0" + end + end - build_gem "sidekiq", "6.1.3" do |s| - s.add_dependency "connection_pool", ">= 2.2.2" - s.add_dependency "rack", "~> 2.0" - s.add_dependency "redis", ">= 4.2.0" - end + it "installs the dependency from the pinned source without warning" do + bundle :install, :artifice => "compact_index" + expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3") + end + end + end - build_gem "thread_safe", "0.3.6" + context "when the lockfile has aggregated rubygems sources and newer versions of dependencies are available" do + before do + build_repo gem_repo2 do + build_gem "activesupport", "6.0.3.4" do |s| + s.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.2" + s.add_dependency "i18n", ">= 0.7", "< 2" + s.add_dependency "minitest", "~> 5.1" + s.add_dependency "tzinfo", "~> 1.1" + s.add_dependency "zeitwerk", "~> 2.2", ">= 2.2.2" + end - build_gem "tzinfo", "1.2.9" do |s| - s.add_dependency "thread_safe", "~> 0.1" - end + build_gem "activesupport", "6.1.2.1" do |s| + s.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.2" + s.add_dependency "i18n", ">= 1.6", "< 2" + s.add_dependency "minitest", ">= 5.1" + s.add_dependency "tzinfo", "~> 2.0" + s.add_dependency "zeitwerk", "~> 2.3" + end - build_gem "tzinfo", "2.0.4" do |s| - s.add_dependency "concurrent-ruby", "~> 1.0" - end + build_gem "concurrent-ruby", "1.1.8" + build_gem "concurrent-ruby", "1.1.9" + build_gem "connection_pool", "2.2.3" - build_gem "zeitwerk", "2.4.2" + build_gem "i18n", "1.8.9" do |s| + s.add_dependency "concurrent-ruby", "~> 1.0" end - build_repo gem_repo3 do - build_gem "sidekiq-pro", "5.2.1" do |s| - s.add_dependency "connection_pool", ">= 2.2.3" - s.add_dependency "sidekiq", ">= 6.1.0" - end + build_gem "minitest", "5.14.3" + build_gem "rack", "2.2.3" + build_gem "redis", "4.2.5" + + build_gem "sidekiq", "6.1.3" do |s| + s.add_dependency "connection_pool", ">= 2.2.2" + s.add_dependency "rack", "~> 2.0" + s.add_dependency "redis", ">= 4.2.0" end - gemfile <<-G - # frozen_string_literal: true + build_gem "thread_safe", "0.3.6" - source "#{file_uri_for(gem_repo2)}" + build_gem "tzinfo", "1.2.9" do |s| + s.add_dependency "thread_safe", "~> 0.1" + end - gem "activesupport" + build_gem "tzinfo", "2.0.4" do |s| + s.add_dependency "concurrent-ruby", "~> 1.0" + end - source "#{file_uri_for(gem_repo3)}" do - gem "sidekiq-pro" - end - G + build_gem "zeitwerk", "2.4.2" + end - lockfile <<~L - GEM - remote: #{file_uri_for(gem_repo2)}/ - remote: #{file_uri_for(gem_repo3)}/ - specs: - activesupport (6.0.3.4) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - zeitwerk (~> 2.2, >= 2.2.2) - concurrent-ruby (1.1.8) - connection_pool (2.2.3) - i18n (1.8.9) - concurrent-ruby (~> 1.0) - minitest (5.14.3) - rack (2.2.3) - redis (4.2.5) - sidekiq (6.1.3) - connection_pool (>= 2.2.2) - rack (~> 2.0) - redis (>= 4.2.0) - sidekiq-pro (5.2.1) - connection_pool (>= 2.2.3) - sidekiq (>= 6.1.0) - thread_safe (0.3.6) - tzinfo (1.2.9) - thread_safe (~> 0.1) - zeitwerk (2.4.2) - - PLATFORMS - #{specific_local_platform} - - DEPENDENCIES - activesupport - sidekiq-pro! - - BUNDLED WITH - #{Bundler::VERSION} - L + build_repo gem_repo3 do + build_gem "sidekiq-pro", "5.2.1" do |s| + s.add_dependency "connection_pool", ">= 2.2.3" + s.add_dependency "sidekiq", ">= 6.1.0" + end end - it "does not install newer versions or generate lockfile changes when running bundle install, and warns", :bundler => "< 3" do - initial_lockfile = lockfile + gemfile <<-G + # frozen_string_literal: true - bundle :install + source "https://gem.repo2" - expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") + gem "activesupport" - expect(the_bundle).to include_gems("activesupport 6.0.3.4") - expect(the_bundle).not_to include_gems("activesupport 6.1.2.1") - expect(the_bundle).to include_gems("tzinfo 1.2.9") - expect(the_bundle).not_to include_gems("tzinfo 2.0.4") - expect(the_bundle).to include_gems("concurrent-ruby 1.1.8") - expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.9") + source "https://gem.repo3" do + gem "sidekiq-pro" + end + G - expect(lockfile).to eq(initial_lockfile) - end + lockfile <<~L + GEM + remote: https://gem.repo2/ + remote: https://gem.repo3/ + specs: + activesupport (6.0.3.4) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) + minitest (~> 5.1) + tzinfo (~> 1.1) + zeitwerk (~> 2.2, >= 2.2.2) + concurrent-ruby (1.1.8) + connection_pool (2.2.3) + i18n (1.8.9) + concurrent-ruby (~> 1.0) + minitest (5.14.3) + rack (2.2.3) + redis (4.2.5) + sidekiq (6.1.3) + connection_pool (>= 2.2.2) + rack (~> 2.0) + redis (>= 4.2.0) + sidekiq-pro (5.2.1) + connection_pool (>= 2.2.3) + sidekiq (>= 6.1.0) + thread_safe (0.3.6) + tzinfo (1.2.9) + thread_safe (~> 0.1) + zeitwerk (2.4.2) - it "fails when running bundle install", :bundler => "3" do - initial_lockfile = lockfile + PLATFORMS + #{specific_local_platform} - bundle :install, :raise_on_error => false + DEPENDENCIES + activesupport + sidekiq-pro! - expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") + BUNDLED WITH + #{Bundler::VERSION} + L + end - expect(lockfile).to eq(initial_lockfile) - end + it "does not install newer versions or generate lockfile changes when running bundle install, and warns", :bundler => "< 3" do + initial_lockfile = lockfile - it "splits sections and upgrades gems when running bundle update, and doesn't warn" do - bundle "update --all" - expect(err).to be_empty - - expect(the_bundle).not_to include_gems("activesupport 6.0.3.4") - expect(the_bundle).to include_gems("activesupport 6.1.2.1") - expect(the_bundle).not_to include_gems("tzinfo 1.2.9") - expect(the_bundle).to include_gems("tzinfo 2.0.4") - expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8") - expect(the_bundle).to include_gems("concurrent-ruby 1.1.9") - - expect(lockfile).to eq <<~L - GEM - remote: #{file_uri_for(gem_repo2)}/ - specs: - activesupport (6.1.2.1) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 1.6, < 2) - minitest (>= 5.1) - tzinfo (~> 2.0) - zeitwerk (~> 2.3) - concurrent-ruby (1.1.9) - connection_pool (2.2.3) - i18n (1.8.9) - concurrent-ruby (~> 1.0) - minitest (5.14.3) - rack (2.2.3) - redis (4.2.5) - sidekiq (6.1.3) - connection_pool (>= 2.2.2) - rack (~> 2.0) - redis (>= 4.2.0) - tzinfo (2.0.4) - concurrent-ruby (~> 1.0) - zeitwerk (2.4.2) - - GEM - remote: #{file_uri_for(gem_repo3)}/ - specs: - sidekiq-pro (5.2.1) - connection_pool (>= 2.2.3) - sidekiq (>= 6.1.0) - - PLATFORMS - #{specific_local_platform} - - DEPENDENCIES - activesupport - sidekiq-pro! - - BUNDLED WITH - #{Bundler::VERSION} - L - end + bundle :install, :artifice => "compact_index" - it "it keeps the current lockfile format and upgrades the requested gem when running bundle update with an argument, and warns", :bundler => "< 3" do - bundle "update concurrent-ruby" - expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") - - expect(the_bundle).to include_gems("activesupport 6.0.3.4") - expect(the_bundle).not_to include_gems("activesupport 6.1.2.1") - expect(the_bundle).to include_gems("tzinfo 1.2.9") - expect(the_bundle).not_to include_gems("tzinfo 2.0.4") - expect(the_bundle).to include_gems("concurrent-ruby 1.1.9") - expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8") - - expect(lockfile).to eq <<~L - GEM - remote: #{file_uri_for(gem_repo2)}/ - remote: #{file_uri_for(gem_repo3)}/ - specs: - activesupport (6.0.3.4) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - zeitwerk (~> 2.2, >= 2.2.2) - concurrent-ruby (1.1.9) - connection_pool (2.2.3) - i18n (1.8.9) - concurrent-ruby (~> 1.0) - minitest (5.14.3) - rack (2.2.3) - redis (4.2.5) - sidekiq (6.1.3) - connection_pool (>= 2.2.2) - rack (~> 2.0) - redis (>= 4.2.0) - sidekiq-pro (5.2.1) - connection_pool (>= 2.2.3) - sidekiq (>= 6.1.0) - thread_safe (0.3.6) - tzinfo (1.2.9) - thread_safe (~> 0.1) - zeitwerk (2.4.2) - - PLATFORMS - #{specific_local_platform} - - DEPENDENCIES - activesupport - sidekiq-pro! - - BUNDLED WITH - #{Bundler::VERSION} - L - end + expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") - it "fails when running bundle update with an argument", :bundler => "3" do - initial_lockfile = lockfile + expect(the_bundle).to include_gems("activesupport 6.0.3.4") + expect(the_bundle).not_to include_gems("activesupport 6.1.2.1") + expect(the_bundle).to include_gems("tzinfo 1.2.9") + expect(the_bundle).not_to include_gems("tzinfo 2.0.4") + expect(the_bundle).to include_gems("concurrent-ruby 1.1.8") + expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.9") - bundle "update concurrent-ruby", :raise_on_error => false + expect(lockfile).to eq(initial_lockfile) + end - expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") + it "fails when running bundle install", :bundler => "3" do + initial_lockfile = lockfile - expect(lockfile).to eq(initial_lockfile) - end + bundle :install, :artifice => "compact_index", :raise_on_error => false + + expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") + + expect(lockfile).to eq(initial_lockfile) + end + + it "splits sections and upgrades gems when running bundle update, and doesn't warn" do + bundle "update --all", :artifice => "compact_index" + expect(err).to be_empty + + expect(the_bundle).not_to include_gems("activesupport 6.0.3.4") + expect(the_bundle).to include_gems("activesupport 6.1.2.1") + expect(the_bundle).not_to include_gems("tzinfo 1.2.9") + expect(the_bundle).to include_gems("tzinfo 2.0.4") + expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8") + expect(the_bundle).to include_gems("concurrent-ruby 1.1.9") + + expect(lockfile).to eq <<~L + GEM + remote: https://gem.repo2/ + specs: + activesupport (6.1.2.1) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) + concurrent-ruby (1.1.9) + connection_pool (2.2.3) + i18n (1.8.9) + concurrent-ruby (~> 1.0) + minitest (5.14.3) + rack (2.2.3) + redis (4.2.5) + sidekiq (6.1.3) + connection_pool (>= 2.2.2) + rack (~> 2.0) + redis (>= 4.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + zeitwerk (2.4.2) + + GEM + remote: https://gem.repo3/ + specs: + sidekiq-pro (5.2.1) + connection_pool (>= 2.2.3) + sidekiq (>= 6.1.0) + + PLATFORMS + #{specific_local_platform} + + DEPENDENCIES + activesupport + sidekiq-pro! + + BUNDLED WITH + #{Bundler::VERSION} + L + end + + it "it keeps the current lockfile format and upgrades the requested gem when running bundle update with an argument, and warns", :bundler => "< 3" do + bundle "update concurrent-ruby", :artifice => "compact_index" + expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") + + expect(the_bundle).to include_gems("activesupport 6.0.3.4") + expect(the_bundle).not_to include_gems("activesupport 6.1.2.1") + expect(the_bundle).to include_gems("tzinfo 1.2.9") + expect(the_bundle).not_to include_gems("tzinfo 2.0.4") + expect(the_bundle).to include_gems("concurrent-ruby 1.1.9") + expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8") + + expect(lockfile).to eq <<~L + GEM + remote: https://gem.repo2/ + remote: https://gem.repo3/ + specs: + activesupport (6.0.3.4) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) + minitest (~> 5.1) + tzinfo (~> 1.1) + zeitwerk (~> 2.2, >= 2.2.2) + concurrent-ruby (1.1.9) + connection_pool (2.2.3) + i18n (1.8.9) + concurrent-ruby (~> 1.0) + minitest (5.14.3) + rack (2.2.3) + redis (4.2.5) + sidekiq (6.1.3) + connection_pool (>= 2.2.2) + rack (~> 2.0) + redis (>= 4.2.0) + sidekiq-pro (5.2.1) + connection_pool (>= 2.2.3) + sidekiq (>= 6.1.0) + thread_safe (0.3.6) + tzinfo (1.2.9) + thread_safe (~> 0.1) + zeitwerk (2.4.2) + + PLATFORMS + #{specific_local_platform} + + DEPENDENCIES + activesupport + sidekiq-pro! + + BUNDLED WITH + #{Bundler::VERSION} + L + end + + it "fails when running bundle update with an argument", :bundler => "3" do + initial_lockfile = lockfile + + bundle "update concurrent-ruby", :artifice => "compact_index", :raise_on_error => false + + expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") + + expect(lockfile).to eq(initial_lockfile) end end - context "when a top-level gem has an indirect dependency present in the default source, but with a different version from the one resolved", :bundler => "< 3" do + context "when a top-level gem has an indirect dependency present in the default source, but with a different version from the one resolved" do before do build_lib "activesupport", "7.0.0.alpha", :path => lib_path("rails/activesupport") build_lib "rails", "7.0.0.alpha", :path => lib_path("rails") do |s| @@ -677,7 +774,7 @@ RSpec.describe "bundle install with gems on multiple sources" do end gemfile <<-G - source "#{file_uri_for(gem_repo2)}" + source "https://gem.repo2" gemspec :path => "#{lib_path("rails")}" @@ -686,7 +783,7 @@ RSpec.describe "bundle install with gems on multiple sources" do end it "installs all gems without warning" do - bundle :install + bundle :install, :artifice => "compact_index" expect(err).not_to include("Warning") expect(the_bundle).to include_gems("activesupport 7.0.0.alpha", "rails 7.0.0.alpha") expect(the_bundle).to include_gems("activesupport 7.0.0.alpha", :source => "path@#{lib_path("rails/activesupport")}") @@ -711,9 +808,9 @@ RSpec.describe "bundle install with gems on multiple sources" do end gemfile <<-G - source "#{file_uri_for(gem_repo2)}" + source "https://gem.repo2" - source "#{file_uri_for(gem_repo3)}" do + source "https://gem.repo3" do gem "handsoap" end @@ -724,14 +821,14 @@ RSpec.describe "bundle install with gems on multiple sources" do it "installs from the default source without any warnings or errors and generates a proper lockfile" do expected_lockfile = <<~L GEM - remote: #{file_uri_for(gem_repo2)}/ + remote: https://gem.repo2/ specs: nokogiri (1.11.1) racca (~> 1.4) racca (1.5.2) GEM - remote: #{file_uri_for(gem_repo3)}/ + remote: https://gem.repo3/ specs: handsoap (0.2.5.5) nokogiri (>= 1.2.3) @@ -747,7 +844,7 @@ RSpec.describe "bundle install with gems on multiple sources" do #{Bundler::VERSION} L - bundle "install --verbose" + bundle "install --verbose", :artifice => "compact_index" expect(err).not_to include("Warning") expect(the_bundle).to include_gems("handsoap 0.2.5.5", "nokogiri 1.11.1", "racca 1.5.2") expect(the_bundle).to include_gems("handsoap 0.2.5.5", :source => "remote3") @@ -756,7 +853,7 @@ RSpec.describe "bundle install with gems on multiple sources" do # Even if the gems are already installed FileUtils.rm bundled_app_lock - bundle "install --verbose" + bundle "install --verbose", :artifice => "compact_index" expect(err).not_to include("Warning") expect(the_bundle).to include_gems("handsoap 0.2.5.5", "nokogiri 1.11.1", "racca 1.5.2") expect(the_bundle).to include_gems("handsoap 0.2.5.5", :source => "remote3") @@ -771,9 +868,9 @@ RSpec.describe "bundle install with gems on multiple sources" do build_gem "not_in_repo1", "1.0.0" end - install_gemfile <<-G, :raise_on_error => false - source "#{file_uri_for(gem_repo3)}" - gem "not_in_repo1", :source => "#{file_uri_for(gem_repo1)}" + install_gemfile <<-G, :artifice => "compact_index", :raise_on_error => false + source "https://gem.repo3" + gem "not_in_repo1", :source => "https://gem.repo1" G end @@ -788,11 +885,11 @@ RSpec.describe "bundle install with gems on multiple sources" do lockfile <<-L GEM - remote: #{file_uri_for(gem_repo1)} + remote: https://gem.repo1 specs: GEM - remote: #{file_uri_for(gem_repo3)} + remote: https://gem.repo3 specs: rack (0.9.1) @@ -804,8 +901,8 @@ RSpec.describe "bundle install with gems on multiple sources" do L gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - source "#{file_uri_for(gem_repo3)}" do + source "https://gem.repo1" + source "https://gem.repo3" do gem 'rack' end G @@ -821,8 +918,8 @@ RSpec.describe "bundle install with gems on multiple sources" do let(:aggregate_gem_section_lockfile) do <<~L GEM - remote: #{file_uri_for(gem_repo1)}/ - remote: #{file_uri_for(gem_repo3)}/ + remote: https://gem.repo1/ + remote: https://gem.repo3/ specs: rack (0.9.1) @@ -840,11 +937,11 @@ RSpec.describe "bundle install with gems on multiple sources" do let(:split_gem_section_lockfile) do <<~L GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: https://gem.repo1/ specs: GEM - remote: #{file_uri_for(gem_repo3)}/ + remote: https://gem.repo3/ specs: rack (0.9.1) @@ -865,8 +962,8 @@ RSpec.describe "bundle install with gems on multiple sources" do end gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - source "#{file_uri_for(gem_repo3)}" do + source "https://gem.repo1" + source "https://gem.repo3" do gem 'rack' end G @@ -877,7 +974,7 @@ RSpec.describe "bundle install with gems on multiple sources" do it "installs the existing lockfile but prints a warning", :bundler => "< 3" do bundle "config set --local deployment true" - bundle "install" + bundle "install", :artifice => "compact_index" expect(lockfile).to eq(aggregate_gem_section_lockfile) expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") @@ -887,7 +984,7 @@ RSpec.describe "bundle install with gems on multiple sources" do it "refuses to install the existing lockfile and prints an error", :bundler => "3" do bundle "config set --local deployment true" - bundle "install", :raise_on_error =>false + bundle "install", :artifice => "compact_index", :raise_on_error =>false expect(lockfile).to eq(aggregate_gem_section_lockfile) expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") @@ -900,13 +997,13 @@ RSpec.describe "bundle install with gems on multiple sources" do build_lib "foo" gemfile <<-G - gem "rack", :source => "#{file_uri_for(gem_repo1)}" + gem "rack", :source => "https://gem.repo1" gem "foo", :path => "#{lib_path("foo-1.0")}" G end it "does not unlock the non-path gem after install" do - bundle :install + bundle :install, :artifice => "compact_index" bundle %(exec ruby -e 'puts "OK"') @@ -919,8 +1016,8 @@ RSpec.describe "bundle install with gems on multiple sources" do before do system_gems "rack-0.9.1" - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + install_gemfile <<-G, :artifice => "compact_index" + source "https://gem.repo1" gem "rack" # should come from repo1! G end @@ -941,14 +1038,14 @@ RSpec.describe "bundle install with gems on multiple sources" do # Installing this gemfile... gemfile <<-G - source '#{file_uri_for(gem_repo1)}' + source 'https://gem.repo1' gem 'rack' - gem 'foo', '~> 0.1', :source => '#{file_uri_for(gem_repo4)}' - gem 'bar', '~> 0.1', :source => '#{file_uri_for(gem_repo4)}' + gem 'foo', '~> 0.1', :source => 'https://gem.repo4' + gem 'bar', '~> 0.1', :source => 'https://gem.repo4' G - bundle "config --local path ../gems/system" - bundle :install + bundle "config set --local path ../gems/system" + bundle :install, :artifice => "compact_index" # And then we add some new versions... update_repo4 do @@ -959,11 +1056,11 @@ RSpec.describe "bundle install with gems on multiple sources" do it "allows them to be unlocked separately" do # And install this gemfile, updating only foo. - install_gemfile <<-G - source '#{file_uri_for(gem_repo1)}' + install_gemfile <<-G, :artifice => "compact_index" + source 'https://gem.repo1' gem 'rack' - gem 'foo', '~> 0.2', :source => '#{file_uri_for(gem_repo4)}' - gem 'bar', '~> 0.1', :source => '#{file_uri_for(gem_repo4)}' + gem 'foo', '~> 0.2', :source => 'https://gem.repo4' + gem 'bar', '~> 0.1', :source => 'https://gem.repo4' G # It should update foo to 0.2, but not the (locked) bar 0.1 @@ -983,11 +1080,11 @@ RSpec.describe "bundle install with gems on multiple sources" do build_git "git1" build_git "git2" - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + install_gemfile <<-G, :artifice => "compact_index" + source "https://gem.repo1" gem "rails" - source "#{file_uri_for(gem_repo3)}" do + source "https://gem.repo3" do gem "rack" end @@ -999,7 +1096,7 @@ RSpec.describe "bundle install with gems on multiple sources" do end it "does not re-resolve" do - bundle :install, :verbose => true + bundle :install, :artifice => "compact_index", :verbose => true expect(out).to include("using resolution from the lockfile") expect(out).not_to include("re-resolving dependencies") end @@ -1008,27 +1105,24 @@ RSpec.describe "bundle install with gems on multiple sources" do context "when a gem is installed to system gems" do before do - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + install_gemfile <<-G, :artifice => "compact_index" + source "https://gem.repo1" gem "rack" G end context "and the gemfile changes" do it "is still able to find that gem from remote sources" do - source_uri = file_uri_for(gem_repo1) - second_uri = file_uri_for(gem_repo4) - build_repo4 do build_gem "rack", "2.0.1.1.forked" build_gem "thor", "0.19.1.1.forked" end # When this gemfile is installed... - install_gemfile <<-G - source "#{source_uri}" + install_gemfile <<-G, :artifice => "compact_index" + source "https://gem.repo1" - source "#{second_uri}" do + source "https://gem.repo4" do gem "rack", "2.0.1.1.forked" gem "thor" end @@ -1037,9 +1131,9 @@ RSpec.describe "bundle install with gems on multiple sources" do # Then we change the Gemfile by adding a version to thor gemfile <<-G - source "#{source_uri}" + source "https://gem.repo1" - source "#{second_uri}" do + source "https://gem.repo4" do gem "rack", "2.0.1.1.forked" gem "thor", "0.19.1.1.forked" end @@ -1047,15 +1141,15 @@ RSpec.describe "bundle install with gems on multiple sources" do G # But we should still be able to find rack 2.0.1.1.forked and install it - bundle :install + bundle :install, :artifice => "compact_index" end end end describe "source changed to one containing a higher version of a dependency" do before do - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + install_gemfile <<-G, :artifice => "compact_index" + source "https://gem.repo1" gem "rack" G @@ -1072,8 +1166,8 @@ RSpec.describe "bundle install with gems on multiple sources" do s.add_dependency "bar", "=1.0.0" end - install_gemfile <<-G - source "#{file_uri_for(gem_repo2)}" + install_gemfile <<-G, :artifice => "compact_index" + source "https://gem.repo2" gem "rack" gemspec :path => "#{tmp.join("gemspec_test")}" G @@ -1093,10 +1187,10 @@ RSpec.describe "bundle install with gems on multiple sources" do build_gem "example", "1.0.2" end - install_gemfile <<-G - source "#{file_uri_for(gem_repo4)}" + install_gemfile <<-G, :artifice => "compact_index" + source "https://gem.repo4" - gem "example", :source => "#{file_uri_for(gem_repo2)}" + gem "example", :source => "https://gem.repo2" G bundle "info example" @@ -1104,12 +1198,41 @@ RSpec.describe "bundle install with gems on multiple sources" do system_gems "example-1.0.2", :path => default_bundle_path, :gem_repo => gem_repo4 - bundle "update example --verbose" + bundle "update example --verbose", :artifice => "compact_index" expect(out).not_to include("Using example 1.0.2") expect(out).to include("Using example 0.1.0") end - context "when a gem is available from multiple ambiguous sources", :bundler => "3" do + context "when an indirect dependency is available from multiple ambiguous sources", :bundler => "< 3" do + it "succeeds but warns, suggesting a source block" do + build_repo4 do + build_gem "depends_on_rack" do |s| + s.add_dependency "rack" + end + build_gem "rack" + end + + install_gemfile <<-G, :artifice => "compact_index", :raise_on_error => false + source "https://gem.repo4" do + gem "depends_on_rack" + end + + source "https://gem.repo1" do + gem "thin" + end + G + expect(err).to eq strip_whitespace(<<-EOS).strip + Warning: The gem 'rack' was found in multiple relevant sources. + * rubygems repository https://gem.repo1/ or installed locally + * rubygems repository https://gem.repo4/ or installed locally + You should add this gem to the source block for the source you wish it to be installed from. + EOS + expect(last_command).to be_success + expect(the_bundle).to be_locked + end + end + + context "when an indirect dependency is available from multiple ambiguous sources", :bundler => "3" do it "raises, suggesting a source block" do build_repo4 do build_gem "depends_on_rack" do |s| @@ -1118,18 +1241,19 @@ RSpec.describe "bundle install with gems on multiple sources" do build_gem "rack" end - install_gemfile <<-G, :raise_on_error => false - source "#{file_uri_for(gem_repo4)}" - source "#{file_uri_for(gem_repo1)}" do + install_gemfile <<-G, :artifice => "compact_index", :raise_on_error => false + source "https://gem.repo4" do + gem "depends_on_rack" + end + source "https://gem.repo1" do gem "thin" end - gem "depends_on_rack" G expect(last_command).to be_failure expect(err).to eq strip_whitespace(<<-EOS).strip The gem 'rack' was found in multiple relevant sources. - * rubygems repository #{file_uri_for(gem_repo1)}/ or installed locally - * rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally + * rubygems repository https://gem.repo1/ or installed locally + * rubygems repository https://gem.repo4/ or installed locally You must add this gem to the source block for the source you wish it to be installed from. EOS expect(the_bundle).not_to be_locked |