diff options
Diffstat (limited to 'spec/bundler/lock/lockfile_spec.rb')
-rw-r--r-- | spec/bundler/lock/lockfile_spec.rb | 830 |
1 files changed, 604 insertions, 226 deletions
diff --git a/spec/bundler/lock/lockfile_spec.rb b/spec/bundler/lock/lockfile_spec.rb index 976db33b0e..4fd081e7d0 100644 --- a/spec/bundler/lock/lockfile_spec.rb +++ b/spec/bundler/lock/lockfile_spec.rb @@ -1,28 +1,22 @@ # frozen_string_literal: true RSpec.describe "the lockfile format" do - include Bundler::GemHelpers - before do - build_repo2 do - # Capistrano did this (at least until version 2.5.10) - # RubyGems 2.2 doesn't allow the specifying of a dependency twice - # See https://github.com/rubygems/rubygems/commit/03dbac93a3396a80db258d9bc63500333c25bd2f - build_gem "double_deps", "1.0", :skip_validation => true do |s| - s.add_dependency "net-ssh", ">= 1.0.0" - s.add_dependency "net-ssh" - end - end + build_repo2 end it "generates a simple lockfile for a single source, gem" do + checksums = checksums_section_when_existing do |c| + c.checksum(gem_repo2, "rack", "1.0.0") + end + install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" gem "rack" G - lockfile_should_be <<-G + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -33,13 +27,13 @@ RSpec.describe "the lockfile format" do DEPENDENCIES rack - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G end - it "updates the lockfile's bundler version if current ver. is newer" do + it "updates the lockfile's bundler version if current ver. is newer, and version was forced through BUNDLER_VERSION" do system_gems "bundler-1.8.2" lockfile <<-L @@ -64,13 +58,16 @@ RSpec.describe "the lockfile format" do 1.8.2 L - install_gemfile <<-G, :env => { "BUNDLER_VERSION" => Bundler::VERSION } + install_gemfile <<-G, verbose: true, env: { "BUNDLER_VERSION" => Bundler::VERSION } source "#{file_uri_for(gem_repo2)}" gem "rack" G - lockfile_should_be <<-G + expect(out).not_to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with 1.8.2.") + expect(out).to include("Using bundler #{Bundler::VERSION}") + + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -87,8 +84,8 @@ RSpec.describe "the lockfile format" do G end - it "does not update the lockfile's bundler version if nothing changed during bundle install" do - version = "#{Bundler::VERSION.split(".").first}.0.0.a" + it "does not update the lockfile's bundler version if nothing changed during bundle install, but uses the locked version", rubygems: ">= 3.3.0.a", realworld: true do + version = "2.3.0" lockfile <<-L GEM @@ -106,13 +103,16 @@ RSpec.describe "the lockfile format" do #{version} L - install_gemfile <<-G + install_gemfile <<-G, verbose: true, artifice: "vcr" source "#{file_uri_for(gem_repo2)}" gem "rack" G - lockfile_should_be <<-G + expect(out).to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{version}.") + expect(out).to include("Using bundler #{version}") + + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -129,7 +129,13 @@ RSpec.describe "the lockfile format" do G end - it "updates the lockfile's bundler version if not present" do + it "does not update the lockfile's bundler version if nothing changed during bundle install, and uses the latest version", rubygems: "< 3.3.0.a" do + version = "#{Bundler::VERSION.split(".").first}.0.0.a" + + checksums = checksums_section do |c| + c.checksum(gem_repo2, "rack", "1.0.0") + end + lockfile <<-L GEM remote: #{file_uri_for(gem_repo2)}/ @@ -141,15 +147,21 @@ RSpec.describe "the lockfile format" do DEPENDENCIES rack + #{checksums} + BUNDLED WITH + #{version} L - install_gemfile <<-G + install_gemfile <<-G, verbose: true source "#{file_uri_for(gem_repo2)}" - gem "rack", "> 0" + gem "rack" G - lockfile_should_be <<-G + expect(out).not_to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{version}.") + expect(out).to include("Using bundler #{Bundler::VERSION}") + + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -159,17 +171,14 @@ RSpec.describe "the lockfile format" do #{lockfile_platforms} DEPENDENCIES - rack (> 0) - + rack + #{checksums} BUNDLED WITH - #{Bundler::VERSION} + #{version} G end - it "warns if the current is older than lockfile's bundler version" do - current_version = Bundler::VERSION - newer_minor = bump_minor(current_version) - + it "adds the BUNDLED WITH section if not present" do lockfile <<-L GEM remote: #{file_uri_for(gem_repo2)}/ @@ -181,25 +190,15 @@ RSpec.describe "the lockfile format" do DEPENDENCIES rack - - BUNDLED WITH - #{newer_minor} L install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" - gem "rack" + gem "rack", "> 0" G - pre_flag = prerelease?(newer_minor) ? " --pre" : "" - warning_message = "the running version of Bundler (#{current_version}) is older " \ - "than the version that created the lockfile (#{newer_minor}). " \ - "We suggest you to upgrade to the version that created the " \ - "lockfile by running `gem install bundler:#{newer_minor}#{pre_flag}`." - expect(err).to include warning_message - - lockfile_should_be <<-G + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -209,14 +208,14 @@ RSpec.describe "the lockfile format" do #{lockfile_platforms} DEPENDENCIES - rack + rack (> 0) BUNDLED WITH - #{newer_minor} + #{Bundler::VERSION} G end - it "warns when updating bundler major version" do + it "update the bundler major version just fine" do current_version = Bundler::VERSION older_major = previous_major(current_version) @@ -238,18 +237,15 @@ RSpec.describe "the lockfile format" do #{older_major} L - install_gemfile <<-G, :env => { "BUNDLER_VERSION" => Bundler::VERSION } + install_gemfile <<-G, env: { "BUNDLER_VERSION" => Bundler::VERSION } source "#{file_uri_for(gem_repo2)}/" gem "rack" G - expect(err).to include( - "Warning: the lockfile is being updated to Bundler " \ - "#{current_version.split(".").first}, after which you will be unable to return to Bundler #{older_major.split(".").first}." - ) + expect(err).to be_empty - lockfile_should_be <<-G + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -273,7 +269,12 @@ RSpec.describe "the lockfile format" do gem "rack-obama" G - lockfile_should_be <<-G + checksums = checksums_section_when_existing do |c| + c.checksum gem_repo2, "rack", "1.0.0" + c.checksum gem_repo2, "rack-obama", "1.0" + end + + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -286,7 +287,7 @@ RSpec.describe "the lockfile format" do DEPENDENCIES rack-obama - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G @@ -299,7 +300,12 @@ RSpec.describe "the lockfile format" do gem "rack-obama", ">= 1.0" G - lockfile_should_be <<-G + checksums = checksums_section_when_existing do |c| + c.checksum gem_repo2, "rack", "1.0.0" + c.checksum gem_repo2, "rack-obama", "1.0" + end + + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -312,49 +318,18 @@ RSpec.describe "the lockfile format" do DEPENDENCIES rack-obama (>= 1.0) - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G end - it "generates a lockfile without credentials for a configured source", :bundler => "< 3" do + it "generates a lockfile without credentials" do bundle "config set http://localgemserver.test/ user:pass" - install_gemfile(<<-G, :artifice => "endpoint_strict_basic_authentication", :quiet => true) - source "http://localgemserver.test/" do - - end - - source "http://user:pass@othergemserver.test/" do - gem "rack-obama", ">= 1.0" - end - G - - lockfile_should_be <<-G - GEM - remote: http://localgemserver.test/ - remote: http://user:pass@othergemserver.test/ - specs: - rack (1.0.0) - rack-obama (1.0) - rack - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - rack-obama (>= 1.0)! + install_gemfile(<<-G, artifice: "endpoint_strict_basic_authentication", quiet: true) + source "#{file_uri_for(gem_repo1)}" - BUNDLED WITH - #{Bundler::VERSION} - G - end - - it "generates a lockfile without credentials for a configured source", :bundler => "3" do - bundle "config set http://localgemserver.test/ user:pass" - - install_gemfile(<<-G, :artifice => "endpoint_strict_basic_authentication", :quiet => true) source "http://localgemserver.test/" do end @@ -364,8 +339,14 @@ RSpec.describe "the lockfile format" do end G - lockfile_should_be <<-G + checksums = checksums_section_when_existing do |c| + c.checksum gem_repo2, "rack", "1.0.0" + c.checksum gem_repo2, "rack-obama", "1.0" + end + + expect(lockfile).to eq <<~G GEM + remote: #{file_uri_for(gem_repo1)}/ specs: GEM @@ -373,7 +354,7 @@ RSpec.describe "the lockfile format" do specs: GEM - remote: http://user:pass@othergemserver.test/ + remote: http://othergemserver.test/ specs: rack (1.0.0) rack-obama (1.0) @@ -384,7 +365,7 @@ RSpec.describe "the lockfile format" do DEPENDENCIES rack-obama (>= 1.0)! - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G @@ -396,7 +377,12 @@ RSpec.describe "the lockfile format" do gem "net-sftp" G - lockfile_should_be <<-G + checksums = checksums_section_when_existing do |c| + c.checksum gem_repo2, "net-sftp", "1.1.1" + c.checksum gem_repo2, "net-ssh", "1.0" + end + + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -409,7 +395,7 @@ RSpec.describe "the lockfile format" do DEPENDENCIES net-sftp - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G @@ -421,17 +407,23 @@ RSpec.describe "the lockfile format" do git = build_git "foo" install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :git => "#{lib_path("foo-1.0")}" G - lockfile_should_be <<-G + checksums = checksums_section_when_existing do |c| + c.no_checksum "foo", "1.0" + end + + expect(lockfile).to eq <<~G GIT remote: #{lib_path("foo-1.0")} - revision: #{git.ref_for("master")} + revision: #{git.ref_for("main")} specs: foo (1.0) GEM + remote: #{file_uri_for(gem_repo1)}/ specs: PLATFORMS @@ -439,14 +431,14 @@ RSpec.describe "the lockfile format" do DEPENDENCIES foo! - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G end it "does not asplode when a platform specific dependency is present and the Gemfile has not been resolved on that platform" do - build_lib "omg", :path => lib_path("omg") + build_lib "omg", path: lib_path("omg") gemfile <<-G source "#{file_uri_for(gem_repo2)}/" @@ -487,20 +479,26 @@ RSpec.describe "the lockfile format" do it "serializes global git sources" do git = build_git "foo" + checksums = checksums_section_when_existing do |c| + c.no_checksum "foo", "1.0" + end + install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" git "#{lib_path("foo-1.0")}" do gem "foo" end G - lockfile_should_be <<-G + expect(lockfile).to eq <<~G GIT remote: #{lib_path("foo-1.0")} - revision: #{git.ref_for("master")} + revision: #{git.ref_for("main")} specs: foo (1.0) GEM + remote: #{file_uri_for(gem_repo1)}/ specs: PLATFORMS @@ -508,7 +506,7 @@ RSpec.describe "the lockfile format" do DEPENDENCIES foo! - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G @@ -516,13 +514,18 @@ RSpec.describe "the lockfile format" do it "generates a lockfile with a ref for a single pinned source, git gem with a branch requirement" do git = build_git "foo" - update_git "foo", :branch => "omg" + update_git "foo", branch: "omg" + + checksums = checksums_section_when_existing do |c| + c.no_checksum "foo", "1.0" + end install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :git => "#{lib_path("foo-1.0")}", :branch => "omg" G - lockfile_should_be <<-G + expect(lockfile).to eq <<~G GIT remote: #{lib_path("foo-1.0")} revision: #{git.ref_for("omg")} @@ -531,6 +534,7 @@ RSpec.describe "the lockfile format" do foo (1.0) GEM + remote: #{file_uri_for(gem_repo1)}/ specs: PLATFORMS @@ -538,7 +542,7 @@ RSpec.describe "the lockfile format" do DEPENDENCIES foo! - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G @@ -546,13 +550,18 @@ RSpec.describe "the lockfile format" do it "generates a lockfile with a ref for a single pinned source, git gem with a tag requirement" do git = build_git "foo" - update_git "foo", :tag => "omg" + update_git "foo", tag: "omg" + + checksums = checksums_section_when_existing do |c| + c.no_checksum "foo", "1.0" + end install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :git => "#{lib_path("foo-1.0")}", :tag => "omg" G - lockfile_should_be <<-G + expect(lockfile).to eq <<~G GIT remote: #{lib_path("foo-1.0")} revision: #{git.ref_for("omg")} @@ -561,6 +570,7 @@ RSpec.describe "the lockfile format" do foo (1.0) GEM + remote: #{file_uri_for(gem_repo1)}/ specs: PLATFORMS @@ -568,26 +578,118 @@ RSpec.describe "the lockfile format" do DEPENDENCIES foo! - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G end + it "is conservative with dependencies of git gems" do + build_repo4 do + build_gem "orm_adapter", "0.4.1" + build_gem "orm_adapter", "0.5.0" + end + + FileUtils.mkdir_p lib_path("ckeditor/lib") + + @remote = build_git("ckeditor_remote", bare: true) + + build_git "ckeditor", path: lib_path("ckeditor") do |s| + s.write "lib/ckeditor.rb", "CKEDITOR = '4.0.7'" + s.version = "4.0.7" + s.add_dependency "orm_adapter" + end + + update_git "ckeditor", path: lib_path("ckeditor"), remote: file_uri_for(@remote.path) + update_git "ckeditor", path: lib_path("ckeditor"), tag: "v4.0.7" + old_git = update_git "ckeditor", path: lib_path("ckeditor"), push: "v4.0.7" + + update_git "ckeditor", path: lib_path("ckeditor"), gemspec: true do |s| + s.write "lib/ckeditor.rb", "CKEDITOR = '4.0.8'" + s.version = "4.0.8" + s.add_dependency "orm_adapter" + end + update_git "ckeditor", path: lib_path("ckeditor"), tag: "v4.0.8" + + new_git = update_git "ckeditor", path: lib_path("ckeditor"), push: "v4.0.8" + + gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem "ckeditor", :git => "#{@remote.path}", :tag => "v4.0.8" + G + + lockfile <<~L + GIT + remote: #{@remote.path} + revision: #{old_git.ref_for("v4.0.7")} + tag: v4.0.7 + specs: + ckeditor (4.0.7) + orm_adapter + + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + orm_adapter (0.4.1) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + ckeditor! + + BUNDLED WITH + #{Bundler::VERSION} + L + + bundle "lock" + + # Bumps the git gem, but keeps its dependency locked + expect(lockfile).to eq <<~L + GIT + remote: #{@remote.path} + revision: #{new_git.ref_for("v4.0.8")} + tag: v4.0.8 + specs: + ckeditor (4.0.8) + orm_adapter + + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + orm_adapter (0.4.1) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + ckeditor! + + BUNDLED WITH + #{Bundler::VERSION} + L + end + it "serializes pinned path sources to the lockfile" do build_lib "foo" + checksums = checksums_section_when_existing do |c| + c.no_checksum "foo", "1.0" + end + install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :path => "#{lib_path("foo-1.0")}" G - lockfile_should_be <<-G + expect(lockfile).to eq <<~G PATH remote: #{lib_path("foo-1.0")} specs: foo (1.0) GEM + remote: #{file_uri_for(gem_repo1)}/ specs: PLATFORMS @@ -595,7 +697,7 @@ RSpec.describe "the lockfile format" do DEPENDENCIES foo! - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G @@ -604,21 +706,27 @@ RSpec.describe "the lockfile format" do it "serializes pinned path sources to the lockfile even when packaging" do build_lib "foo" + checksums = checksums_section_when_existing do |c| + c.no_checksum "foo", "1.0" + end + install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gem "foo", :path => "#{lib_path("foo-1.0")}" G bundle "config set cache_all true" bundle :cache - bundle :install, :local => true + bundle :install, local: true - lockfile_should_be <<-G + expect(lockfile).to eq <<~G PATH remote: #{lib_path("foo-1.0")} specs: foo (1.0) GEM + remote: #{file_uri_for(gem_repo1)}/ specs: PLATFORMS @@ -626,7 +734,7 @@ RSpec.describe "the lockfile format" do DEPENDENCIES foo! - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G @@ -636,6 +744,12 @@ RSpec.describe "the lockfile format" do build_lib "foo" bar = build_git "bar" + checksums = checksums_section_when_existing do |c| + c.no_checksum "foo", "1.0" + c.no_checksum "bar", "1.0" + c.checksum gem_repo2, "rack", "1.0.0" + end + install_gemfile <<-G source "#{file_uri_for(gem_repo2)}/" @@ -644,10 +758,10 @@ RSpec.describe "the lockfile format" do gem "bar", :git => "#{lib_path("bar-1.0")}" G - lockfile_should_be <<-G + expect(lockfile).to eq <<~G GIT remote: #{lib_path("bar-1.0")} - revision: #{bar.ref_for("master")} + revision: #{bar.ref_for("main")} specs: bar (1.0) @@ -668,7 +782,35 @@ RSpec.describe "the lockfile format" do bar! foo! rack + #{checksums} + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "removes redundant sources" do + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}/" + + gem "rack", :source => "#{file_uri_for(gem_repo2)}/" + G + + checksums = checksums_section_when_existing do |c| + c.checksum gem_repo2, "rack", "1.0.0" + end + expect(lockfile).to eq <<~G + GEM + remote: #{file_uri_for(gem_repo2)}/ + specs: + rack (1.0.0) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + rack! + #{checksums} BUNDLED WITH #{Bundler::VERSION} G @@ -683,7 +825,15 @@ RSpec.describe "the lockfile format" do gem "rack-obama" G - lockfile_should_be <<-G + checksums = checksums_section_when_existing do |c| + c.checksum gem_repo2, "actionpack", "2.3.2" + c.checksum gem_repo2, "activesupport", "2.3.2" + c.checksum gem_repo2, "rack", "1.0.0" + c.checksum gem_repo2, "rack-obama", "1.0" + c.checksum gem_repo2, "thin", "1.0" + end + + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -703,7 +853,7 @@ RSpec.describe "the lockfile format" do actionpack rack-obama thin - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G @@ -716,7 +866,17 @@ RSpec.describe "the lockfile format" do gem "rails" G - lockfile_should_be <<-G + checksums = checksums_section_when_existing do |c| + c.checksum gem_repo2, "actionmailer", "2.3.2" + c.checksum gem_repo2, "actionpack", "2.3.2" + c.checksum gem_repo2, "activerecord", "2.3.2" + c.checksum gem_repo2, "activeresource", "2.3.2" + c.checksum gem_repo2, "activesupport", "2.3.2" + c.checksum gem_repo2, "rails", "2.3.2" + c.checksum gem_repo2, "rake", rake_version + end + + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -734,27 +894,42 @@ RSpec.describe "the lockfile format" do actionpack (= 2.3.2) activerecord (= 2.3.2) activeresource (= 2.3.2) - rake (= 13.0.1) - rake (13.0.1) + rake (= #{rake_version}) + rake (#{rake_version}) PLATFORMS #{lockfile_platforms} DEPENDENCIES rails - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G end it "orders dependencies by version" do + update_repo2 do + # Capistrano did this (at least until version 2.5.10) + # RubyGems 2.2 doesn't allow the specifying of a dependency twice + # See https://github.com/rubygems/rubygems/commit/03dbac93a3396a80db258d9bc63500333c25bd2f + build_gem "double_deps", "1.0", skip_validation: true do |s| + s.add_dependency "net-ssh", ">= 1.0.0" + s.add_dependency "net-ssh" + end + end + install_gemfile <<-G source "#{file_uri_for(gem_repo2)}/" gem 'double_deps' G - lockfile_should_be <<-G + checksums = checksums_section_when_existing do |c| + c.checksum gem_repo2, "double_deps", "1.0" + c.checksum gem_repo2, "net-ssh", "1.0" + end + + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -768,7 +943,7 @@ RSpec.describe "the lockfile format" do DEPENDENCIES double_deps - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G @@ -781,7 +956,12 @@ RSpec.describe "the lockfile format" do gem "rack-obama", ">= 1.0", :require => "rack/obama" G - lockfile_should_be <<-G + checksums = checksums_section_when_existing do |c| + c.checksum gem_repo2, "rack", "1.0.0" + c.checksum gem_repo2, "rack-obama", "1.0" + end + + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -794,7 +974,7 @@ RSpec.describe "the lockfile format" do DEPENDENCIES rack-obama (>= 1.0) - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G @@ -807,7 +987,12 @@ RSpec.describe "the lockfile format" do gem "rack-obama", ">= 1.0", :group => :test G - lockfile_should_be <<-G + checksums = checksums_section_when_existing do |c| + c.checksum gem_repo2, "rack", "1.0.0" + c.checksum gem_repo2, "rack-obama", "1.0" + end + + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -820,28 +1005,34 @@ RSpec.describe "the lockfile format" do DEPENDENCIES rack-obama (>= 1.0) - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G end it "stores relative paths when the path is provided in a relative fashion and in Gemfile dir" do - build_lib "foo", :path => bundled_app("foo") + build_lib "foo", path: bundled_app("foo") + + checksums = checksums_section_when_existing do |c| + c.no_checksum "foo", "1.0" + end install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" path "foo" do gem "foo" end G - lockfile_should_be <<-G + expect(lockfile).to eq <<~G PATH remote: foo specs: foo (1.0) GEM + remote: #{file_uri_for(gem_repo1)}/ specs: PLATFORMS @@ -849,28 +1040,34 @@ RSpec.describe "the lockfile format" do DEPENDENCIES foo! - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G end it "stores relative paths when the path is provided in a relative fashion and is above Gemfile dir" do - build_lib "foo", :path => bundled_app(File.join("..", "foo")) + build_lib "foo", path: bundled_app(File.join("..", "foo")) + + checksums = checksums_section_when_existing do |c| + c.no_checksum "foo", "1.0" + end install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" path "../foo" do gem "foo" end G - lockfile_should_be <<-G + expect(lockfile).to eq <<~G PATH remote: ../foo specs: foo (1.0) GEM + remote: #{file_uri_for(gem_repo1)}/ specs: PLATFORMS @@ -878,28 +1075,34 @@ RSpec.describe "the lockfile format" do DEPENDENCIES foo! - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G end it "stores relative paths when the path is provided in an absolute fashion but is relative" do - build_lib "foo", :path => bundled_app("foo") + build_lib "foo", path: bundled_app("foo") + + checksums = checksums_section_when_existing do |c| + c.no_checksum "foo", "1.0" + end install_gemfile <<-G - path File.expand_path("../foo", __FILE__) do + source "#{file_uri_for(gem_repo1)}" + path File.expand_path("foo", __dir__) do gem "foo" end G - lockfile_should_be <<-G + expect(lockfile).to eq <<~G PATH remote: foo specs: foo (1.0) GEM + remote: #{file_uri_for(gem_repo1)}/ specs: PLATFORMS @@ -907,26 +1110,32 @@ RSpec.describe "the lockfile format" do DEPENDENCIES foo! - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G end it "stores relative paths when the path is provided for gemspec" do - build_lib("foo", :path => tmp.join("foo")) + build_lib("foo", path: tmp.join("foo")) + + checksums = checksums_section_when_existing do |c| + c.no_checksum "foo", "1.0" + end install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" gemspec :path => "../foo" G - lockfile_should_be <<-G + expect(lockfile).to eq <<~G PATH remote: ../foo specs: foo (1.0) GEM + remote: #{file_uri_for(gem_repo1)}/ specs: PLATFORMS @@ -934,13 +1143,17 @@ RSpec.describe "the lockfile format" do DEPENDENCIES foo! - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G end it "keeps existing platforms in the lockfile" do + checksums = checksums_section_when_existing do |c| + c.no_checksum "rack", "1.0.0" + end + lockfile <<-G GEM remote: #{file_uri_for(gem_repo2)}/ @@ -952,7 +1165,7 @@ RSpec.describe "the lockfile format" do DEPENDENCIES rack - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G @@ -963,24 +1176,65 @@ RSpec.describe "the lockfile format" do gem "rack" G - lockfile_should_be <<-G + checksums.checksum(gem_repo2, "rack", "1.0.0") + + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) PLATFORMS - java - #{lockfile_platforms} + #{lockfile_platforms("java", local_platform, defaults: [])} DEPENDENCIES rack - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G end + it "adds compatible platform specific variants to the lockfile, even if resolution fallback to RUBY due to some other incompatible platform specific variant" do + simulate_platform "arm64-darwin-23" do + build_repo4 do + build_gem "google-protobuf", "3.25.1" + build_gem "google-protobuf", "3.25.1" do |s| + s.platform = "arm64-darwin-23" + end + build_gem "google-protobuf", "3.25.1" do |s| + s.platform = "x64-mingw-ucrt" + s.required_ruby_version = "> #{Gem.ruby_version}" + end + end + + gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem "google-protobuf" + G + bundle "lock --add-platform x64-mingw-ucrt" + + expect(lockfile).to eq <<~L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + google-protobuf (3.25.1) + google-protobuf (3.25.1-arm64-darwin-23) + + PLATFORMS + arm64-darwin-23 + ruby + x64-mingw-ucrt + + DEPENDENCIES + google-protobuf + + BUNDLED WITH + #{Bundler::VERSION} + L + end + end + it "persists the spec's specific platform to the lockfile" do build_repo2 do build_gem "platform_specific", "1.0" do |s| @@ -995,7 +1249,11 @@ RSpec.describe "the lockfile format" do gem "platform_specific" G - lockfile_should_be <<-G + checksums = checksums_section_when_existing do |c| + c.checksum gem_repo2, "platform_specific", "1.0", "universal-java-16" + end + + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -1006,13 +1264,18 @@ RSpec.describe "the lockfile format" do DEPENDENCIES platform_specific - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G end it "does not add duplicate gems" do + checksums = checksums_section_when_existing do |c| + c.checksum(gem_repo2, "activesupport", "2.3.5") + c.checksum(gem_repo2, "rack", "1.0.0") + end + install_gemfile <<-G source "#{file_uri_for(gem_repo2)}/" gem "rack" @@ -1024,7 +1287,7 @@ RSpec.describe "the lockfile format" do gem "activesupport" G - lockfile_should_be <<-G + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -1037,20 +1300,24 @@ RSpec.describe "the lockfile format" do DEPENDENCIES activesupport rack - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G end it "does not add duplicate dependencies" do + checksums = checksums_section_when_existing do |c| + c.checksum(gem_repo2, "rack", "1.0.0") + end + install_gemfile <<-G source "#{file_uri_for(gem_repo2)}/" gem "rack" gem "rack" G - lockfile_should_be <<-G + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -1061,20 +1328,24 @@ RSpec.describe "the lockfile format" do DEPENDENCIES rack - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G end it "does not add duplicate dependencies with versions" do + checksums = checksums_section_when_existing do |c| + c.checksum(gem_repo2, "rack", "1.0.0") + end + install_gemfile <<-G source "#{file_uri_for(gem_repo2)}/" gem "rack", "1.0" gem "rack", "1.0" G - lockfile_should_be <<-G + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -1085,20 +1356,24 @@ RSpec.describe "the lockfile format" do DEPENDENCIES rack (= 1.0) - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G end it "does not add duplicate dependencies in different groups" do + checksums = checksums_section_when_existing do |c| + c.checksum(gem_repo2, "rack", "1.0.0") + end + install_gemfile <<-G source "#{file_uri_for(gem_repo2)}/" gem "rack", "1.0", :group => :one gem "rack", "1.0", :group => :two G - lockfile_should_be <<-G + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -1109,14 +1384,14 @@ RSpec.describe "the lockfile format" do DEPENDENCIES rack (= 1.0) - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G end it "raises if two different versions are used" do - install_gemfile <<-G, :raise_on_error => false + install_gemfile <<-G, raise_on_error: false source "#{file_uri_for(gem_repo2)}/" gem "rack", "1.0" gem "rack", "1.1" @@ -1127,7 +1402,7 @@ RSpec.describe "the lockfile format" do end it "raises if two different sources are used" do - install_gemfile <<-G, :raise_on_error => false + install_gemfile <<-G, raise_on_error: false source "#{file_uri_for(gem_repo2)}/" gem "rack" gem "rack", :git => "git://hubz.com" @@ -1138,12 +1413,16 @@ RSpec.describe "the lockfile format" do end it "works correctly with multiple version dependencies" do + checksums = checksums_section_when_existing do |c| + c.checksum(gem_repo2, "rack", "0.9.1") + end + install_gemfile <<-G source "#{file_uri_for(gem_repo2)}/" gem "rack", "> 0.9", "< 1.0" G - lockfile_should_be <<-G + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -1154,20 +1433,24 @@ RSpec.describe "the lockfile format" do DEPENDENCIES rack (> 0.9, < 1.0) - + #{checksums} BUNDLED WITH #{Bundler::VERSION} G end it "captures the Ruby version in the lockfile" do + checksums = checksums_section_when_existing do |c| + c.checksum(gem_repo2, "rack", "0.9.1") + end + install_gemfile <<-G source "#{file_uri_for(gem_repo2)}/" - ruby '#{RUBY_VERSION}' + ruby '#{Gem.ruby_version}' gem "rack", "> 0.9", "< 1.0" G - lockfile_should_be <<-G + expect(lockfile).to eq <<~G GEM remote: #{file_uri_for(gem_repo2)}/ specs: @@ -1178,113 +1461,207 @@ RSpec.describe "the lockfile format" do DEPENDENCIES rack (> 0.9, < 1.0) - + #{checksums} RUBY VERSION - ruby #{RUBY_VERSION}p#{RUBY_PATCHLEVEL} + #{Bundler::RubyVersion.system} BUNDLED WITH #{Bundler::VERSION} G end - # Some versions of the Bundler 1.1 RC series introduced corrupted - # lockfiles. There were two major problems: - # - # * multiple copies of the same GIT section appeared in the lockfile - # * when this happened, those sections got multiple copies of gems - # in those sections. - it "fixes corrupted lockfiles" do - build_git "omg", :path => lib_path("omg") - revision = revision_for(lib_path("omg")) + it "raises a helpful error message when the lockfile is missing deps" do + lockfile <<-L + GEM + remote: #{file_uri_for(gem_repo2)}/ + specs: + rack_middleware (1.0) - gemfile <<-G - source "#{file_uri_for(gem_repo2)}/" - gem "omg", :git => "#{lib_path("omg")}", :branch => 'master' + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + rack_middleware + L + + install_gemfile <<-G, raise_on_error: false + source "#{file_uri_for(gem_repo2)}" + gem "rack_middleware" G - bundle "config set --local path vendor" - bundle :install - expect(the_bundle).to include_gems "omg 1.0" + expect(err).to include("Downloading rack_middleware-1.0 revealed dependencies not in the API or the lockfile (#{Gem::Dependency.new("rack", "= 0.9.1")})."). + and include("Running `bundle update rack_middleware` should fix the problem.") + end - # Create a Gemfile.lock that has duplicate GIT sections - lockfile <<-L - GIT - remote: #{lib_path("omg")} - revision: #{revision} - branch: master - specs: - omg (1.0) + it "regenerates a lockfile with no specs" do + build_repo4 do + build_gem "indirect_dependency", "1.2.3" do |s| + s.metadata["funding_uri"] = "https://example.com/donate" + end - GIT - remote: #{lib_path("omg")} - revision: #{revision} - branch: master - specs: - omg (1.0) + build_gem "direct_dependency", "4.5.6" do |s| + s.add_dependency "indirect_dependency", ">= 0" + end + end + lockfile <<-G GEM - remote: #{file_uri_for(gem_repo2)}/ + remote: #{file_uri_for(gem_repo4)}/ specs: PLATFORMS - #{lockfile_platforms} + ruby DEPENDENCIES - omg! + direct_dependency BUNDLED WITH #{Bundler::VERSION} - L + G - FileUtils.rm_rf(bundled_app("vendor")) - bundle "install" - expect(the_bundle).to include_gems "omg 1.0" + install_gemfile <<-G + source "#{file_uri_for(gem_repo4)}" - # Confirm that duplicate specs do not appear - lockfile_should_be(<<-L) - GIT - remote: #{lib_path("omg")} - revision: #{revision} - branch: master - specs: - omg (1.0) + gem "direct_dependency" + G + expect(lockfile).to eq <<~G GEM - remote: #{file_uri_for(gem_repo2)}/ + remote: #{file_uri_for(gem_repo4)}/ specs: + direct_dependency (4.5.6) + indirect_dependency + indirect_dependency (1.2.3) PLATFORMS - #{lockfile_platforms} + #{lockfile_platforms("ruby", generic_local_platform, defaults: [])} DEPENDENCIES - omg! + direct_dependency BUNDLED WITH #{Bundler::VERSION} - L + G end - it "raises a helpful error message when the lockfile is missing deps" do - lockfile <<-L + shared_examples_for "a lockfile missing dependent specs" do + it "auto-heals" do + build_repo4 do + build_gem "minitest-bisect", "1.6.0" do |s| + s.add_dependency "path_expander", "~> 1.1" + end + + build_gem "path_expander", "1.1.1" + end + + gemfile <<~G + source "#{file_uri_for(gem_repo4)}" + gem "minitest-bisect" + G + + # Corrupt lockfile (completely missing path_expander) + lockfile <<~L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + minitest-bisect (1.6.0) + + PLATFORMS + #{platforms} + + DEPENDENCIES + minitest-bisect + + BUNDLED WITH + #{Bundler::VERSION} + L + + cache_gems "minitest-bisect-1.6.0", "path_expander-1.1.1", gem_repo: gem_repo4 + bundle :install + + expect(lockfile).to eq <<~L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + minitest-bisect (1.6.0) + path_expander (~> 1.1) + path_expander (1.1.1) + + PLATFORMS + #{platforms} + + DEPENDENCIES + minitest-bisect + + BUNDLED WITH + #{Bundler::VERSION} + L + end + end + + context "with just specific platform" do + let(:platforms) { lockfile_platforms } + + it_behaves_like "a lockfile missing dependent specs" + end + + context "with both ruby and specific platform" do + let(:platforms) { lockfile_platforms("ruby") } + + it_behaves_like "a lockfile missing dependent specs" + end + + it "auto-heals when the lockfile is missing specs" do + build_repo4 do + build_gem "minitest-bisect", "1.6.0" do |s| + s.add_dependency "path_expander", "~> 1.1" + end + + build_gem "path_expander", "1.1.1" + end + + gemfile <<~G + source "#{file_uri_for(gem_repo4)}" + gem "minitest-bisect" + G + + lockfile <<~L GEM - remote: #{file_uri_for(gem_repo2)}/ + remote: #{file_uri_for(gem_repo4)}/ specs: - rack_middleware (1.0) + minitest-bisect (1.6.0) + path_expander (~> 1.1) PLATFORMS #{lockfile_platforms} DEPENDENCIES - rack_middleware + minitest-bisect + + BUNDLED WITH + #{Bundler::VERSION} L - install_gemfile <<-G, :raise_on_error => false - source "#{file_uri_for(gem_repo2)}" - gem "rack_middleware" - G + bundle "install --verbose" + expect(out).to include("re-resolving dependencies because your lock file includes \"minitest-bisect\" but not some of its dependencies") - expect(err).to include("Downloading rack_middleware-1.0 revealed dependencies not in the API or the lockfile (#{Gem::Dependency.new("rack", "= 0.9.1")})."). - and include("Either installing with `--full-index` or running `bundle update rack_middleware` should fix the problem.") + expect(lockfile).to eq <<~L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + minitest-bisect (1.6.0) + path_expander (~> 1.1) + path_expander (1.1.1) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + minitest-bisect + + BUNDLED WITH + #{Bundler::VERSION} + L end describe "a line ending" do @@ -1315,7 +1692,7 @@ RSpec.describe "the lockfile format" do end end - expect { bundle "update", :all => true }.to change { File.mtime(bundled_app_lock) } + expect { bundle "update", all: true }.to change { File.mtime(bundled_app_lock) } expect(File.read(bundled_app_lock)).not_to match("\r\n") expect(the_bundle).to include_gems "rack 1.2" end @@ -1333,8 +1710,9 @@ RSpec.describe "the lockfile format" do File.open(bundled_app_lock, "wb") {|f| f.puts(win_lock) } set_lockfile_mtime_to_known_value - expect { bundle "update", :all => true }.to change { File.mtime(bundled_app_lock) } + expect { bundle "update", all: true }.to change { File.mtime(bundled_app_lock) } expect(File.read(bundled_app_lock)).to match("\r\n") + expect(the_bundle).to include_gems "rack 1.2" end end @@ -1356,7 +1734,7 @@ RSpec.describe "the lockfile format" do expect do ruby <<-RUBY - require '#{lib_dir}/bundler' + require 'bundler' Bundler.setup RUBY end.not_to change { File.mtime(bundled_app_lock) } @@ -1385,7 +1763,7 @@ RSpec.describe "the lockfile format" do #{Bundler::VERSION} L - install_gemfile <<-G, :raise_on_error => false + install_gemfile <<-G, raise_on_error: false source "#{file_uri_for(gem_repo2)}/" gem "rack" G |