aboutsummaryrefslogtreecommitdiffstats
path: root/spec/bundler/install/gemfile/sources_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/bundler/install/gemfile/sources_spec.rb')
-rw-r--r--spec/bundler/install/gemfile/sources_spec.rb518
1 files changed, 518 insertions, 0 deletions
diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb
new file mode 100644
index 0000000000..c5375b4abf
--- /dev/null
+++ b/spec/bundler/install/gemfile/sources_spec.rb
@@ -0,0 +1,518 @@
+# frozen_string_literal: true
+require "spec_helper"
+
+RSpec.describe "bundle install with gems on multiple sources" do
+ # repo1 is built automatically before all of the specs run
+ # it contains rack-obama 1.0.0 and rack 0.9.1 & 1.0.0 amongst other gems
+
+ context "without source affinity" do
+ before do
+ # Oh no! Someone evil is trying to hijack rack :(
+ # need this to be broken to check for correct source ordering
+ build_repo gem_repo3 do
+ build_gem "rack", repo3_rack_version do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
+ end
+ end
+ end
+
+ context "with multiple toplevel sources" do
+ let(:repo3_rack_version) { "1.0.0" }
+
+ before do
+ gemfile <<-G
+ source "file://#{gem_repo3}"
+ source "file://#{gem_repo1}"
+ gem "rack-obama"
+ gem "rack"
+ G
+ bundle "config major_deprecations true"
+ end
+
+ it "warns about ambiguous gems, but installs anyway, prioritizing sources last to first" do
+ bundle :install
+
+ expect(out).to have_major_deprecation a_string_including("Your Gemfile contains multiple primary sources.")
+ expect(out).to include("Warning: the gem 'rack' was found in multiple sources.")
+ expect(out).to include("Installed from: file:#{gem_repo1}")
+ expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0", :source => "remote1")
+ end
+
+ it "errors when disable_multisource is set" do
+ bundle "config disable_multisource true"
+ bundle :install
+ expect(out).to include("Each source after the first must include a block")
+ expect(exitstatus).to eq(4) if exitstatus
+ end
+ end
+
+ context "when different versions of the same gem are in multiple sources" do
+ let(:repo3_rack_version) { "1.2" }
+
+ before do
+ gemfile <<-G
+ source "file://#{gem_repo3}"
+ source "file://#{gem_repo1}"
+ gem "rack-obama"
+ gem "rack", "1.0.0" # force it to install the working version in repo1
+ G
+ bundle "config major_deprecations true"
+ end
+
+ it "warns about ambiguous gems, but installs anyway" do
+ bundle :install
+
+ expect(out).to have_major_deprecation a_string_including("Your Gemfile contains multiple primary sources.")
+ expect(out).to include("Warning: the gem 'rack' was found in multiple sources.")
+ expect(out).to include("Installed from: file:#{gem_repo1}")
+ expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0", :source => "remote1")
+ end
+ end
+ end
+
+ context "with source affinity" do
+ context "with sources given by a block" do
+ before do
+ # Oh no! Someone evil is trying to hijack rack :(
+ # need this to be broken to check for correct source ordering
+ build_repo gem_repo3 do
+ build_gem "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
+ end
+ end
+
+ gemfile <<-G
+ source "file://#{gem_repo3}"
+ source "file://#{gem_repo1}" do
+ gem "thin" # comes first to test name sorting
+ gem "rack"
+ end
+ gem "rack-obama" # shoud come from repo3!
+ G
+ end
+
+ it "installs the gems without any warning" do
+ bundle :install
+ expect(out).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 :package
+
+ 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 "install --deployment"
+
+ expect(exitstatus).to eq(0) if exitstatus
+ expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0")
+ end
+ end
+
+ context "with sources set by an option" do
+ before do
+ # Oh no! Someone evil is trying to hijack rack :(
+ # need this to be broken to check for correct source ordering
+ build_repo gem_repo3 do
+ build_gem "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
+ end
+ end
+
+ gemfile <<-G
+ source "file://#{gem_repo3}"
+ gem "rack-obama" # should come from repo3!
+ gem "rack", :source => "file://#{gem_repo1}"
+ G
+ end
+
+ it "installs the gems without any warning" do
+ bundle :install
+ expect(out).not_to include("Warning")
+ expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0")
+ end
+ end
+
+ context "with an indirect dependency" do
+ before do
+ build_repo gem_repo3 do
+ build_gem "depends_on_rack", "1.0.1" do |s|
+ s.add_dependency "rack"
+ end
+ end
+ end
+
+ context "when the indirect dependency is in the pinned source" do
+ before do
+ # we need a working rack gem in repo3
+ update_repo gem_repo3 do
+ build_gem "rack", "1.0.0"
+ end
+
+ gemfile <<-G
+ source "file://#{gem_repo2}"
+ source "file://#{gem_repo3}" do
+ gem "depends_on_rack"
+ end
+ G
+ end
+
+ context "and not in any other sources" do
+ before do
+ build_repo(gem_repo2) {}
+ end
+
+ it "installs from the same source without any warning" do
+ bundle :install
+ expect(out).not_to include("Warning")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
+ end
+ end
+
+ context "and in another source" do
+ before do
+ # need this to be broken to check for correct source ordering
+ build_repo gem_repo2 do
+ build_gem "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
+ end
+ end
+ end
+
+ it "installs from the same source without any warning" do
+ bundle :install
+ expect(out).not_to include("Warning")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
+ end
+ end
+ end
+
+ context "when the indirect dependency is in a different source" do
+ before do
+ # In these tests, we need a working rack gem in repo2 and not repo3
+ build_repo gem_repo2 do
+ build_gem "rack", "1.0.0"
+ end
+ end
+
+ context "and not in any other sources" do
+ before do
+ gemfile <<-G
+ source "file://#{gem_repo2}"
+ source "file://#{gem_repo3}" do
+ gem "depends_on_rack"
+ end
+ G
+ end
+
+ it "installs from the other source without any warning" do
+ bundle :install
+ expect(out).not_to include("Warning")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
+ end
+ end
+
+ context "and in yet another source" do
+ before do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ source "file://#{gem_repo2}"
+ source "file://#{gem_repo3}" do
+ gem "depends_on_rack"
+ end
+ G
+ end
+
+ it "installs from the other source and warns about ambiguous gems" do
+ bundle "config major_deprecations true"
+ bundle :install
+ expect(out).to have_major_deprecation a_string_including("Your Gemfile contains multiple primary sources.")
+ expect(out).to include("Warning: the gem 'rack' was found in multiple sources.")
+ expect(out).to include("Installed from: file:#{gem_repo2}")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
+ end
+ end
+
+ context "and only the dependency is pinned" do
+ before do
+ # need this to be broken to check for correct source ordering
+ build_repo gem_repo2 do
+ build_gem "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
+ end
+ end
+
+ gemfile <<-G
+ source "file://#{gem_repo3}" # contains depends_on_rack
+ source "file://#{gem_repo2}" # contains broken rack
+
+ gem "depends_on_rack" # installed from gem_repo3
+ gem "rack", :source => "file://#{gem_repo1}"
+ G
+ end
+
+ it "installs the dependency from the pinned source without warning" do
+ bundle :install
+
+ expect(out).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")
+
+ # 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
+
+ expect(out).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
+ end
+ end
+ end
+
+ context "with a gem that is only found in the wrong source" do
+ before do
+ build_repo gem_repo3 do
+ build_gem "not_in_repo1", "1.0.0"
+ end
+
+ gemfile <<-G
+ source "file://#{gem_repo3}"
+ gem "not_in_repo1", :source => "file://#{gem_repo1}"
+ G
+ end
+
+ it "does not install the gem" do
+ bundle :install
+ expect(out).to include("Could not find gem 'not_in_repo1'")
+ end
+ end
+
+ context "with an existing lockfile" do
+ before do
+ system_gems "rack-0.9.1", "rack-1.0.0"
+
+ lockfile <<-L
+ GEM
+ remote: file:#{gem_repo1}
+ remote: file:#{gem_repo3}
+ specs:
+ rack (0.9.1)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ rack!
+ L
+
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ source "file://#{gem_repo3}" do
+ gem 'rack'
+ end
+ G
+ end
+
+ # Reproduction of https://github.com/bundler/bundler/issues/3298
+ it "does not unlock the installed gem on exec" do
+ expect(the_bundle).to include_gems("rack 0.9.1")
+ end
+ end
+
+ context "with a path gem in the same Gemfile" do
+ before do
+ build_lib "foo"
+
+ gemfile <<-G
+ gem "rack", :source => "file://#{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 %(exec ruby -e 'puts "OK"')
+
+ expect(out).to include("OK")
+ expect(exitstatus).to eq(0) if exitstatus
+ end
+ end
+ end
+
+ context "when an older version of the same gem also ships with Ruby" do
+ before do
+ system_gems "rack-0.9.1"
+
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack" # shoud come from repo1!
+ G
+ end
+
+ it "installs the gems without any warning" do
+ bundle :install
+ expect(out).not_to include("Warning")
+ expect(the_bundle).to include_gems("rack 1.0.0")
+ end
+ end
+
+ context "when a single source contains multiple locked gems" do
+ before do
+ # 1. With these gems,
+ build_repo4 do
+ build_gem "foo", "0.1"
+ build_gem "bar", "0.1"
+ end
+
+ # 2. Installing this gemfile will produce...
+ gemfile <<-G
+ source 'file://#{gem_repo1}'
+ gem 'rack'
+ gem 'foo', '~> 0.1', :source => 'file://#{gem_repo4}'
+ gem 'bar', '~> 0.1', :source => 'file://#{gem_repo4}'
+ G
+
+ # 3. this lockfile.
+ lockfile <<-L
+ GEM
+ remote: file:/Users/andre/src/bundler/bundler/tmp/gems/remote1/
+ remote: file:/Users/andre/src/bundler/bundler/tmp/gems/remote4/
+ specs:
+ bar (0.1)
+ foo (0.1)
+ rack (1.0.0)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ bar (~> 0.1)!
+ foo (~> 0.1)!
+ rack
+ L
+
+ bundle "install --path ../gems/system"
+
+ # 4. Then we add some new versions...
+ update_repo4 do
+ build_gem "foo", "0.2"
+ build_gem "bar", "0.3"
+ end
+ end
+
+ it "allows them to be unlocked separately" do
+ # 5. and install this gemfile, updating only foo.
+ install_gemfile <<-G
+ source 'file://#{gem_repo1}'
+ gem 'rack'
+ gem 'foo', '~> 0.2', :source => 'file://#{gem_repo4}'
+ gem 'bar', '~> 0.1', :source => 'file://#{gem_repo4}'
+ G
+
+ # 6. Which should update foo to 0.2, but not the (locked) bar 0.1
+ expect(the_bundle).to include_gems("foo 0.2")
+ expect(the_bundle).to include_gems("bar 0.1")
+ end
+ end
+
+ context "re-resolving" do
+ context "when there is a mix of sources in the gemfile" do
+ before do
+ build_repo3
+ build_lib "path1"
+ build_lib "path2"
+ build_git "git1"
+ build_git "git2"
+
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rails"
+
+ source "file://#{gem_repo3}" do
+ gem "rack"
+ end
+
+ gem "path1", :path => "#{lib_path("path1-1.0")}"
+ gem "path2", :path => "#{lib_path("path2-1.0")}"
+ gem "git1", :git => "#{lib_path("git1-1.0")}"
+ gem "git2", :git => "#{lib_path("git2-1.0")}"
+ G
+ end
+
+ it "does not re-resolve" do
+ bundle :install, :verbose => true
+ expect(out).to include("using resolution from the lockfile")
+ expect(out).not_to include("re-resolving dependencies")
+ end
+ end
+ end
+
+ context "when a gem is installed to system gems" do
+ before do
+ install_gemfile! <<-G
+ source "file://#{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://#{gem_repo1}"
+ second_uri = "file://#{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...
+ gemfile <<-G
+ source "#{source_uri}"
+
+ source "#{second_uri}" do
+ gem "rack", "2.0.1.1.forked"
+ gem "thor"
+ end
+ gem "rack-obama"
+ G
+
+ # It creates this lockfile.
+ lockfile <<-L
+ GEM
+ remote: #{source_uri}/
+ remote: #{second_uri}/
+ specs:
+ rack (2.0.1.1.forked)
+ rack-obama (1.0)
+ rack
+ thor (0.19.1.1.forked)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ rack (= 2.0.1.1.forked)!
+ rack-obama
+ thor!
+ L
+
+ # Then we change the Gemfile by adding a version to thor
+ gemfile <<-G
+ source "#{source_uri}"
+
+ source "#{second_uri}" do
+ gem "rack", "2.0.1.1.forked"
+ gem "thor", "0.19.1.1.forked"
+ end
+ gem "rack-obama"
+ G
+
+ # But we should still be able to find rack 2.0.1.1.forked and install it
+ bundle! :install
+ end
+ end
+ end
+end