mirror of
https://github.com/ruby/ruby.git
synced 2025-08-24 13:34:17 +02:00

Overriding the version constant feels too magic and creates a set of
problems. For example, Bundler will lock the simulated version, and that
can cause issues when the lockfile is used under an environment not
simulating Bundler 4 (it will try to auto-install and auto-switch to a
version that does not exist).
On top of that, it can only be configured with an ENV variable which is
not too flexible.
This commit takes a different approach of using a setting, which is
configurable through ENV or `bundle config`, and pass the simulated
version to `Bundler::FeatureFlag`. The real version is still the one set
by `VERSION`, but anything that `Bundler::FeatureFlag` controls will use
the logic of the "simulated version".
In particular, all feature flags and deprecation messages will respect
the simulated version, and this is exactly the set of functionality that
we want users to be able to easily try before releasing it.
8129402193
2314 lines
50 KiB
Ruby
2314 lines
50 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
RSpec.describe "the lockfile format" do
|
|
before do
|
|
build_repo2
|
|
end
|
|
|
|
it "generates a simple lockfile for a single source, gem" do
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.checksum(gem_repo2, "myrack", "1.0.0")
|
|
end
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2"
|
|
|
|
gem "myrack"
|
|
G
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
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
|
|
GIT
|
|
remote: git://github.com/nex3/haml.git
|
|
revision: 8a2271f
|
|
specs:
|
|
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
omg!
|
|
myrack
|
|
|
|
BUNDLED WITH
|
|
1.8.2
|
|
L
|
|
|
|
install_gemfile <<-G, verbose: true, env: { "BUNDLER_VERSION" => Bundler::VERSION }
|
|
source "https://gem.repo2"
|
|
|
|
gem "myrack"
|
|
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: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "does not update the lockfile's bundler version if nothing changed during bundle install, but uses the locked version" do
|
|
version = "2.3.0"
|
|
|
|
build_repo4 do
|
|
build_gem "myrack", "1.0.0"
|
|
|
|
build_bundler version
|
|
end
|
|
|
|
lockfile <<-L
|
|
GEM
|
|
remote: https://gem.repo4/
|
|
specs:
|
|
myrack (1.0.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack
|
|
|
|
BUNDLED WITH
|
|
#{version}
|
|
L
|
|
|
|
install_gemfile <<-G, verbose: true
|
|
source "https://gem.repo4"
|
|
|
|
gem "myrack"
|
|
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: https://gem.repo4/
|
|
specs:
|
|
myrack (1.0.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack
|
|
|
|
BUNDLED WITH
|
|
#{version}
|
|
G
|
|
end
|
|
|
|
it "adds the BUNDLED WITH section if not present" do
|
|
lockfile <<-L
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack
|
|
L
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2"
|
|
|
|
gem "myrack", "> 0"
|
|
G
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack (> 0)
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "update the bundler major version just fine" do
|
|
current_version = Bundler::VERSION
|
|
older_major = previous_major(current_version)
|
|
|
|
system_gems "bundler-#{older_major}"
|
|
|
|
lockfile <<-L
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack
|
|
|
|
BUNDLED WITH
|
|
#{older_major}
|
|
L
|
|
|
|
install_gemfile <<-G, env: { "BUNDLER_VERSION" => Bundler::VERSION }
|
|
source "https://gem.repo2/"
|
|
|
|
gem "myrack"
|
|
G
|
|
|
|
expect(err).to be_empty
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack
|
|
|
|
BUNDLED WITH
|
|
#{current_version}
|
|
G
|
|
end
|
|
|
|
it "generates a simple lockfile for a single source, gem with dependencies" do
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2/"
|
|
|
|
gem "myrack-obama"
|
|
G
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.checksum gem_repo2, "myrack", "1.0.0"
|
|
c.checksum gem_repo2, "myrack-obama", "1.0"
|
|
end
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
myrack-obama (1.0)
|
|
myrack
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack-obama
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "generates a simple lockfile for a single source, gem with a version requirement" do
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2/"
|
|
|
|
gem "myrack-obama", ">= 1.0"
|
|
G
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.checksum gem_repo2, "myrack", "1.0.0"
|
|
c.checksum gem_repo2, "myrack-obama", "1.0"
|
|
end
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
myrack-obama (1.0)
|
|
myrack
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack-obama (>= 1.0)
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "generates a lockfile without credentials" do
|
|
bundle "config set https://localgemserver.test/ user:pass"
|
|
|
|
install_gemfile(<<-G, artifice: "endpoint_strict_basic_authentication", quiet: true)
|
|
source "https://gem.repo1"
|
|
|
|
source "https://localgemserver.test/" do
|
|
|
|
end
|
|
|
|
source "https://user:pass@othergemserver.test/" do
|
|
gem "myrack-obama", ">= 1.0"
|
|
end
|
|
G
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.checksum gem_repo2, "myrack", "1.0.0"
|
|
c.checksum gem_repo2, "myrack-obama", "1.0"
|
|
end
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo1/
|
|
specs:
|
|
|
|
GEM
|
|
remote: https://localgemserver.test/
|
|
specs:
|
|
|
|
GEM
|
|
remote: https://othergemserver.test/
|
|
specs:
|
|
myrack (1.0.0)
|
|
myrack-obama (1.0)
|
|
myrack
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack-obama (>= 1.0)!
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "does not add credentials to lockfile when it does not have them already" do
|
|
bundle "config set http://localgemserver.test/ user:pass"
|
|
|
|
gemfile <<~G
|
|
source "https://gem.repo1"
|
|
|
|
source "http://localgemserver.test/" do
|
|
|
|
end
|
|
|
|
source "http://user:pass@othergemserver.test/" do
|
|
gem "myrack-obama", ">= 1.0"
|
|
end
|
|
G
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.checksum gem_repo2, "myrack", "1.0.0"
|
|
c.checksum gem_repo2, "myrack-obama", "1.0"
|
|
end
|
|
|
|
lockfile_without_credentials = <<~L
|
|
GEM
|
|
remote: http://localgemserver.test/
|
|
specs:
|
|
|
|
GEM
|
|
remote: http://othergemserver.test/
|
|
specs:
|
|
myrack (1.0.0)
|
|
myrack-obama (1.0)
|
|
myrack
|
|
|
|
GEM
|
|
remote: https://gem.repo1/
|
|
specs:
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack-obama (>= 1.0)!
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
|
|
lockfile lockfile_without_credentials
|
|
|
|
# when not re-resolving
|
|
bundle "install", artifice: "endpoint_strict_basic_authentication", quiet: true
|
|
expect(lockfile).to eq lockfile_without_credentials
|
|
|
|
# when re-resolving with full unlock
|
|
bundle "update", artifice: "endpoint_strict_basic_authentication"
|
|
expect(lockfile).to eq lockfile_without_credentials
|
|
|
|
# when re-resolving without ful unlocking
|
|
bundle "update myrack-obama", artifice: "endpoint_strict_basic_authentication"
|
|
expect(lockfile).to eq lockfile_without_credentials
|
|
end
|
|
|
|
it "keeps credentials in lockfile if already there" do
|
|
bundle "config set http://localgemserver.test/ user:pass"
|
|
|
|
gemfile <<~G
|
|
source "https://gem.repo1"
|
|
|
|
source "http://localgemserver.test/" do
|
|
|
|
end
|
|
|
|
source "http://user:pass@othergemserver.test/" do
|
|
gem "myrack-obama", ">= 1.0"
|
|
end
|
|
G
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.checksum gem_repo2, "myrack", "1.0.0"
|
|
c.checksum gem_repo2, "myrack-obama", "1.0"
|
|
end
|
|
|
|
lockfile_with_credentials = <<~L
|
|
GEM
|
|
remote: http://localgemserver.test/
|
|
specs:
|
|
|
|
GEM
|
|
remote: http://user:pass@othergemserver.test/
|
|
specs:
|
|
myrack (1.0.0)
|
|
myrack-obama (1.0)
|
|
myrack
|
|
|
|
GEM
|
|
remote: https://gem.repo1/
|
|
specs:
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack-obama (>= 1.0)!
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
|
|
lockfile lockfile_with_credentials
|
|
|
|
bundle "install", artifice: "endpoint_strict_basic_authentication", quiet: true
|
|
|
|
expect(lockfile).to eq lockfile_with_credentials
|
|
end
|
|
|
|
it "generates lockfiles with multiple requirements" do
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2/"
|
|
gem "net-sftp"
|
|
G
|
|
|
|
checksums = checksums_section_when_enabled 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: https://gem.repo2/
|
|
specs:
|
|
net-sftp (1.1.1)
|
|
net-ssh (>= 1.0.0, < 1.99.0)
|
|
net-ssh (1.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
net-sftp
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
|
|
expect(the_bundle).to include_gems "net-sftp 1.1.1", "net-ssh 1.0.0"
|
|
end
|
|
|
|
it "generates a simple lockfile for a single pinned source, gem with a version requirement" do
|
|
git = build_git "foo"
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
gem "foo", :git => "#{lib_path("foo-1.0")}"
|
|
G
|
|
|
|
checksums = checksums_section_when_enabled 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("main")}
|
|
specs:
|
|
foo (1.0)
|
|
|
|
GEM
|
|
remote: https://gem.repo1/
|
|
specs:
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
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")
|
|
|
|
gemfile <<-G
|
|
source "https://gem.repo2/"
|
|
|
|
platforms :#{not_local_tag} do
|
|
gem "omg", :path => "#{lib_path("omg")}"
|
|
end
|
|
|
|
gem "myrack"
|
|
G
|
|
|
|
lockfile <<-L
|
|
GIT
|
|
remote: git://github.com/nex3/haml.git
|
|
revision: 8a2271f
|
|
specs:
|
|
|
|
GEM
|
|
remote: https://gem.repo2//
|
|
specs:
|
|
myrack (1.0.0)
|
|
|
|
PLATFORMS
|
|
#{not_local}
|
|
|
|
DEPENDENCIES
|
|
omg!
|
|
myrack
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
|
|
bundle "install"
|
|
expect(the_bundle).to include_gems "myrack 1.0.0"
|
|
end
|
|
|
|
it "serializes global git sources" do
|
|
git = build_git "foo"
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.no_checksum "foo", "1.0"
|
|
end
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
git "#{lib_path("foo-1.0")}" do
|
|
gem "foo"
|
|
end
|
|
G
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GIT
|
|
remote: #{lib_path("foo-1.0")}
|
|
revision: #{git.ref_for("main")}
|
|
specs:
|
|
foo (1.0)
|
|
|
|
GEM
|
|
remote: https://gem.repo1/
|
|
specs:
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
foo!
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
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"
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.no_checksum "foo", "1.0"
|
|
end
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
gem "foo", :git => "#{lib_path("foo-1.0")}", :branch => "omg"
|
|
G
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GIT
|
|
remote: #{lib_path("foo-1.0")}
|
|
revision: #{git.ref_for("omg")}
|
|
branch: omg
|
|
specs:
|
|
foo (1.0)
|
|
|
|
GEM
|
|
remote: https://gem.repo1/
|
|
specs:
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
foo!
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
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"
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.no_checksum "foo", "1.0"
|
|
end
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
gem "foo", :git => "#{lib_path("foo-1.0")}", :tag => "omg"
|
|
G
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GIT
|
|
remote: #{lib_path("foo-1.0")}
|
|
revision: #{git.ref_for("omg")}
|
|
tag: omg
|
|
specs:
|
|
foo (1.0)
|
|
|
|
GEM
|
|
remote: https://gem.repo1/
|
|
specs:
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
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: @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 "https://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: https://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: https://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_enabled do |c|
|
|
c.no_checksum "foo", "1.0"
|
|
end
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
gem "foo", :path => "#{lib_path("foo-1.0")}"
|
|
G
|
|
|
|
expect(lockfile).to eq <<~G
|
|
PATH
|
|
remote: #{lib_path("foo-1.0")}
|
|
specs:
|
|
foo (1.0)
|
|
|
|
GEM
|
|
remote: https://gem.repo1/
|
|
specs:
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
foo!
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "serializes pinned path sources to the lockfile even when packaging" do
|
|
build_lib "foo"
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
gem "foo", :path => "#{lib_path("foo-1.0")}"
|
|
G
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.no_checksum "foo", "1.0"
|
|
end
|
|
|
|
bundle "config set cache_all true"
|
|
bundle :cache
|
|
bundle :install, local: true
|
|
|
|
expect(lockfile).to eq <<~G
|
|
PATH
|
|
remote: #{lib_path("foo-1.0")}
|
|
specs:
|
|
foo (1.0)
|
|
|
|
GEM
|
|
remote: https://gem.repo1/
|
|
specs:
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
foo!
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "sorts serialized sources by type" do
|
|
build_lib "foo"
|
|
bar = build_git "bar"
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.no_checksum "foo", "1.0"
|
|
c.no_checksum "bar", "1.0"
|
|
c.checksum gem_repo2, "myrack", "1.0.0"
|
|
end
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2/"
|
|
|
|
gem "myrack"
|
|
gem "foo", :path => "#{lib_path("foo-1.0")}"
|
|
gem "bar", :git => "#{lib_path("bar-1.0")}"
|
|
G
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GIT
|
|
remote: #{lib_path("bar-1.0")}
|
|
revision: #{bar.ref_for("main")}
|
|
specs:
|
|
bar (1.0)
|
|
|
|
PATH
|
|
remote: #{lib_path("foo-1.0")}
|
|
specs:
|
|
foo (1.0)
|
|
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
bar!
|
|
foo!
|
|
myrack
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "removes redundant sources" do
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2/"
|
|
|
|
gem "myrack", :source => "https://gem.repo2/"
|
|
G
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.checksum gem_repo2, "myrack", "1.0.0"
|
|
end
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack!
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "lists gems alphabetically" do
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2/"
|
|
|
|
gem "thin"
|
|
gem "actionpack"
|
|
gem "myrack-obama"
|
|
G
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.checksum gem_repo2, "actionpack", "2.3.2"
|
|
c.checksum gem_repo2, "activesupport", "2.3.2"
|
|
c.checksum gem_repo2, "myrack", "1.0.0"
|
|
c.checksum gem_repo2, "myrack-obama", "1.0"
|
|
c.checksum gem_repo2, "thin", "1.0"
|
|
end
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
actionpack (2.3.2)
|
|
activesupport (= 2.3.2)
|
|
activesupport (2.3.2)
|
|
myrack (1.0.0)
|
|
myrack-obama (1.0)
|
|
myrack
|
|
thin (1.0)
|
|
myrack
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
actionpack
|
|
myrack-obama
|
|
thin
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "orders dependencies' dependencies in alphabetical order" do
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2/"
|
|
|
|
gem "rails"
|
|
G
|
|
|
|
checksums = checksums_section_when_enabled 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: https://gem.repo2/
|
|
specs:
|
|
actionmailer (2.3.2)
|
|
activesupport (= 2.3.2)
|
|
actionpack (2.3.2)
|
|
activesupport (= 2.3.2)
|
|
activerecord (2.3.2)
|
|
activesupport (= 2.3.2)
|
|
activeresource (2.3.2)
|
|
activesupport (= 2.3.2)
|
|
activesupport (2.3.2)
|
|
rails (2.3.2)
|
|
actionmailer (= 2.3.2)
|
|
actionpack (= 2.3.2)
|
|
activerecord (= 2.3.2)
|
|
activeresource (= 2.3.2)
|
|
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 "https://gem.repo2"
|
|
gem 'double_deps'
|
|
G
|
|
|
|
checksums = checksums_section_when_enabled 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: https://gem.repo2/
|
|
specs:
|
|
double_deps (1.0)
|
|
net-ssh
|
|
net-ssh (>= 1.0.0)
|
|
net-ssh (1.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
double_deps
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "does not add the :require option to the lockfile" do
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2/"
|
|
|
|
gem "myrack-obama", ">= 1.0", :require => "myrack/obama"
|
|
G
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.checksum gem_repo2, "myrack", "1.0.0"
|
|
c.checksum gem_repo2, "myrack-obama", "1.0"
|
|
end
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
myrack-obama (1.0)
|
|
myrack
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack-obama (>= 1.0)
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "does not add the :group option to the lockfile" do
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2/"
|
|
|
|
gem "myrack-obama", ">= 1.0", :group => :test
|
|
G
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.checksum gem_repo2, "myrack", "1.0.0"
|
|
c.checksum gem_repo2, "myrack-obama", "1.0"
|
|
end
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
myrack-obama (1.0)
|
|
myrack
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack-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")
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.no_checksum "foo", "1.0"
|
|
end
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
path "foo" do
|
|
gem "foo"
|
|
end
|
|
G
|
|
|
|
expect(lockfile).to eq <<~G
|
|
PATH
|
|
remote: foo
|
|
specs:
|
|
foo (1.0)
|
|
|
|
GEM
|
|
remote: https://gem.repo1/
|
|
specs:
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
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"))
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.no_checksum "foo", "1.0"
|
|
end
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
path "../foo" do
|
|
gem "foo"
|
|
end
|
|
G
|
|
|
|
expect(lockfile).to eq <<~G
|
|
PATH
|
|
remote: ../foo
|
|
specs:
|
|
foo (1.0)
|
|
|
|
GEM
|
|
remote: https://gem.repo1/
|
|
specs:
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
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")
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
path File.expand_path("foo", __dir__) do
|
|
gem "foo"
|
|
end
|
|
G
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.no_checksum "foo", "1.0"
|
|
end
|
|
|
|
expect(lockfile).to eq <<~G
|
|
PATH
|
|
remote: foo
|
|
specs:
|
|
foo (1.0)
|
|
|
|
GEM
|
|
remote: https://gem.repo1/
|
|
specs:
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
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("foo"))
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.no_checksum "foo", "1.0"
|
|
end
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo1"
|
|
gemspec :path => "../foo"
|
|
G
|
|
|
|
expect(lockfile).to eq <<~G
|
|
PATH
|
|
remote: ../foo
|
|
specs:
|
|
foo (1.0)
|
|
|
|
GEM
|
|
remote: https://gem.repo1/
|
|
specs:
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
foo!
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "keeps existing platforms in the lockfile" do
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.no_checksum "myrack", "1.0.0"
|
|
end
|
|
|
|
lockfile <<-G
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
|
|
PLATFORMS
|
|
java
|
|
|
|
DEPENDENCIES
|
|
myrack
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2/"
|
|
|
|
gem "myrack"
|
|
G
|
|
|
|
checksums.checksum(gem_repo2, "myrack", "1.0.0")
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms("java", local_platform, defaults: [])}
|
|
|
|
DEPENDENCIES
|
|
myrack
|
|
#{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 "https://gem.repo4"
|
|
gem "google-protobuf"
|
|
G
|
|
bundle "lock --add-platform x64-mingw-ucrt"
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.checksum gem_repo4, "google-protobuf", "3.25.1"
|
|
c.checksum gem_repo4, "google-protobuf", "3.25.1", "arm64-darwin-23"
|
|
end
|
|
|
|
expect(lockfile).to eq <<~L
|
|
GEM
|
|
remote: https://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
|
|
#{checksums}
|
|
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|
|
|
s.platform = Gem::Platform.new("universal-java-16")
|
|
end
|
|
end
|
|
|
|
simulate_platform "universal-java-16" do
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2"
|
|
gem "platform_specific"
|
|
G
|
|
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.checksum gem_repo2, "platform_specific", "1.0", "universal-java-16"
|
|
end
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
platform_specific (1.0-universal-java-16)
|
|
|
|
PLATFORMS
|
|
universal-java-16
|
|
|
|
DEPENDENCIES
|
|
platform_specific
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
end
|
|
|
|
it "does not add duplicate gems" do
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.checksum(gem_repo2, "activesupport", "2.3.5")
|
|
c.checksum(gem_repo2, "myrack", "1.0.0")
|
|
end
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2/"
|
|
gem "myrack"
|
|
G
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2/"
|
|
gem "myrack"
|
|
gem "activesupport"
|
|
G
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
activesupport (2.3.5)
|
|
myrack (1.0.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
activesupport
|
|
myrack
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "does not add duplicate dependencies" do
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.checksum(gem_repo2, "myrack", "1.0.0")
|
|
end
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2/"
|
|
gem "myrack"
|
|
gem "myrack"
|
|
G
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "does not add duplicate dependencies with versions" do
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.checksum(gem_repo2, "myrack", "1.0.0")
|
|
end
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2/"
|
|
gem "myrack", "1.0"
|
|
gem "myrack", "1.0"
|
|
G
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack (= 1.0)
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "does not add duplicate dependencies in different groups" do
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.checksum(gem_repo2, "myrack", "1.0.0")
|
|
end
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2/"
|
|
gem "myrack", "1.0", :group => :one
|
|
gem "myrack", "1.0", :group => :two
|
|
G
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (1.0.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack (= 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
|
|
source "https://gem.repo2/"
|
|
gem "myrack", "1.0"
|
|
gem "myrack", "1.1"
|
|
G
|
|
|
|
expect(bundled_app_lock).not_to exist
|
|
expect(err).to include "myrack (= 1.0) and myrack (= 1.1)"
|
|
end
|
|
|
|
it "raises if two different sources are used" do
|
|
install_gemfile <<-G, raise_on_error: false
|
|
source "https://gem.repo2/"
|
|
gem "myrack"
|
|
gem "myrack", :git => "git://hubz.com"
|
|
G
|
|
|
|
expect(bundled_app_lock).not_to exist
|
|
expect(err).to include "myrack (>= 0) should come from an unspecified source and git://hubz.com"
|
|
end
|
|
|
|
it "works correctly with multiple version dependencies" do
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.checksum(gem_repo2, "myrack", "0.9.1")
|
|
end
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2/"
|
|
gem "myrack", "> 0.9", "< 1.0"
|
|
G
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (0.9.1)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack (> 0.9, < 1.0)
|
|
#{checksums}
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "captures the Ruby version in the lockfile" do
|
|
checksums = checksums_section_when_enabled do |c|
|
|
c.checksum(gem_repo2, "myrack", "0.9.1")
|
|
end
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2/"
|
|
ruby '#{Gem.ruby_version}'
|
|
gem "myrack", "> 0.9", "< 1.0"
|
|
G
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (0.9.1)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack (> 0.9, < 1.0)
|
|
#{checksums}
|
|
RUBY VERSION
|
|
#{Bundler::RubyVersion.system}
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "automatically fixes the lockfile when it's missing deps" do
|
|
lockfile <<-L
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack_middleware (1.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack_middleware
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2"
|
|
gem "myrack_middleware"
|
|
G
|
|
|
|
expect(lockfile).to eq <<~L
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack (0.9.1)
|
|
myrack_middleware (1.0)
|
|
myrack (= 0.9.1)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack_middleware
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
end
|
|
|
|
it "raises a clear error when frozen mode is set and lockfile is missing deps, and does not install any gems" do
|
|
lockfile <<-L
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack_middleware (1.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack_middleware
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
|
|
install_gemfile <<-G, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false
|
|
source "https://gem.repo2"
|
|
gem "myrack_middleware"
|
|
G
|
|
|
|
expect(err).to eq("Bundler found incorrect dependencies in the lockfile for myrack_middleware-1.0")
|
|
expect(the_bundle).not_to include_gems "myrack_middleware 1.0"
|
|
end
|
|
|
|
it "raises a clear error when frozen mode is set and lockfile is missing entries in CHECKSUMS section, and does not install any gems" do
|
|
lockfile <<-L
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack_middleware (1.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack_middleware
|
|
|
|
CHECKSUMS
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
|
|
install_gemfile <<-G, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false
|
|
source "https://gem.repo2"
|
|
gem "myrack_middleware"
|
|
G
|
|
|
|
expect(err).to eq <<~L.strip
|
|
Your lockfile is missing a checksums entry for \"myrack_middleware\", but can't be updated because frozen mode is set
|
|
|
|
Run `bundle install` elsewhere and add the updated Gemfile.lock to version control.
|
|
L
|
|
|
|
expect(the_bundle).not_to include_gems "myrack_middleware 1.0"
|
|
end
|
|
|
|
it "automatically fixes the lockfile when it's missing deps, they conflict with other locked deps, but conflicts are fixable" do
|
|
build_repo4 do
|
|
build_gem "other_dep", "0.9"
|
|
build_gem "other_dep", "1.0"
|
|
|
|
build_gem "myrack", "0.9.1"
|
|
|
|
build_gem "myrack_middleware", "1.0" do |s|
|
|
s.add_dependency "myrack", "= 0.9.1"
|
|
s.add_dependency "other_dep", "= 0.9"
|
|
end
|
|
end
|
|
|
|
lockfile <<~L
|
|
GEM
|
|
remote: https://gem.repo4/
|
|
specs:
|
|
myrack_middleware (1.0)
|
|
other_dep (1.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack_middleware
|
|
other_dep
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo4"
|
|
gem "myrack_middleware"
|
|
gem "other_dep"
|
|
G
|
|
|
|
expect(lockfile).to eq <<~L
|
|
GEM
|
|
remote: https://gem.repo4/
|
|
specs:
|
|
myrack (0.9.1)
|
|
myrack_middleware (1.0)
|
|
myrack (= 0.9.1)
|
|
other_dep (= 0.9)
|
|
other_dep (0.9)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack_middleware
|
|
other_dep
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
end
|
|
|
|
it "automatically fixes the lockfile when it's missing multiple deps, they conflict with other locked deps, but conflicts are fixable" do
|
|
build_repo4 do
|
|
build_gem "other_dep", "0.9"
|
|
build_gem "other_dep", "1.0"
|
|
|
|
build_gem "myrack", "0.9.1"
|
|
|
|
build_gem "myrack_middleware", "1.0" do |s|
|
|
s.add_dependency "myrack", "= 0.9.1"
|
|
end
|
|
|
|
build_gem "another_dep_middleware", "1.0" do |s|
|
|
s.add_dependency "other_dep", "= 0.9"
|
|
end
|
|
end
|
|
|
|
lockfile <<~L
|
|
GEM
|
|
remote: https://gem.repo4/
|
|
specs:
|
|
myrack_middleware (1.0)
|
|
another_dep_middleware (1.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack_middleware
|
|
another_dep_middleware
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo4"
|
|
gem "myrack_middleware"
|
|
gem "another_dep_middleware"
|
|
G
|
|
|
|
expect(lockfile).to eq <<~L
|
|
GEM
|
|
remote: https://gem.repo4/
|
|
specs:
|
|
another_dep_middleware (1.0)
|
|
other_dep (= 0.9)
|
|
myrack (0.9.1)
|
|
myrack_middleware (1.0)
|
|
myrack (= 0.9.1)
|
|
other_dep (0.9)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
another_dep_middleware
|
|
myrack_middleware
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
end
|
|
|
|
it "raises a resolution error when lockfile is missing deps, they conflict with other locked deps, and conflicts are not fixable" do
|
|
build_repo4 do
|
|
build_gem "other_dep", "0.9"
|
|
build_gem "other_dep", "1.0"
|
|
|
|
build_gem "myrack", "0.9.1"
|
|
|
|
build_gem "myrack_middleware", "1.0" do |s|
|
|
s.add_dependency "myrack", "= 0.9.1"
|
|
s.add_dependency "other_dep", "= 0.9"
|
|
end
|
|
end
|
|
|
|
lockfile <<~L
|
|
GEM
|
|
remote: https://gem.repo4/
|
|
specs:
|
|
myrack_middleware (1.0)
|
|
other_dep (1.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack_middleware
|
|
other_dep
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
|
|
install_gemfile <<-G, raise_on_error: false
|
|
source "https://gem.repo4"
|
|
gem "myrack_middleware"
|
|
gem "other_dep", "1.0"
|
|
G
|
|
|
|
expect(err).to eq <<~ERROR.strip
|
|
Could not find compatible versions
|
|
|
|
Because every version of myrack_middleware depends on other_dep = 0.9
|
|
and Gemfile depends on myrack_middleware >= 0,
|
|
other_dep = 0.9 is required.
|
|
So, because Gemfile depends on other_dep = 1.0,
|
|
version solving has failed.
|
|
ERROR
|
|
end
|
|
|
|
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
|
|
|
|
build_gem "direct_dependency", "4.5.6" do |s|
|
|
s.add_dependency "indirect_dependency", ">= 0"
|
|
end
|
|
end
|
|
|
|
lockfile <<-G
|
|
GEM
|
|
remote: https://gem.repo4/
|
|
specs:
|
|
|
|
PLATFORMS
|
|
ruby
|
|
|
|
DEPENDENCIES
|
|
direct_dependency
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo4"
|
|
|
|
gem "direct_dependency"
|
|
G
|
|
|
|
expect(lockfile).to eq <<~G
|
|
GEM
|
|
remote: https://gem.repo4/
|
|
specs:
|
|
direct_dependency (4.5.6)
|
|
indirect_dependency
|
|
indirect_dependency (1.2.3)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms(generic_default_locked_platform || local_platform, defaults: ["ruby"])}
|
|
|
|
DEPENDENCIES
|
|
direct_dependency
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
G
|
|
end
|
|
|
|
it "automatically fixes the lockfile when it's missing deps and the full index is in use" do
|
|
lockfile <<-L
|
|
GEM
|
|
remote: https://gem.repo2/
|
|
specs:
|
|
myrack_middleware (1.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack_middleware
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
|
|
install_gemfile <<-G
|
|
source "#{file_uri_for(gem_repo2)}"
|
|
gem "myrack_middleware"
|
|
G
|
|
|
|
expect(lockfile).to eq <<~L
|
|
GEM
|
|
remote: #{file_uri_for(gem_repo2)}/
|
|
specs:
|
|
myrack (0.9.1)
|
|
myrack_middleware (1.0)
|
|
myrack (= 0.9.1)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack_middleware
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
end
|
|
|
|
it "automatically fixes the lockfile when it includes a gem under the correct GIT section, but also under an incorrect GEM section, with a higher version, and with no explicit Gemfile requirement" do
|
|
git = build_git "foo"
|
|
|
|
gemfile <<~G
|
|
source "https://gem.repo1/"
|
|
gem "foo", git: "#{lib_path("foo-1.0")}"
|
|
G
|
|
|
|
# If the lockfile erroneously lists platform versions of the gem
|
|
# that don't match the locked version of the git repo we should remove them.
|
|
|
|
lockfile <<~L
|
|
GIT
|
|
remote: #{lib_path("foo-1.0")}
|
|
revision: #{git.ref_for("main")}
|
|
specs:
|
|
foo (1.0)
|
|
|
|
GEM
|
|
remote: https://gem.repo1/
|
|
specs:
|
|
foo (1.1-x86_64-linux-gnu)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
foo!
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
|
|
bundle "install"
|
|
|
|
expect(lockfile).to eq <<~L
|
|
GIT
|
|
remote: #{lib_path("foo-1.0")}
|
|
revision: #{git.ref_for("main")}
|
|
specs:
|
|
foo (1.0)
|
|
|
|
GEM
|
|
remote: https://gem.repo1/
|
|
specs:
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
foo!
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
end
|
|
|
|
it "automatically fixes the lockfile when it includes a gem under the correct GIT section, but also under an incorrect GEM section, with a higher version" do
|
|
git = build_git "foo"
|
|
|
|
gemfile <<~G
|
|
source "https://gem.repo1/"
|
|
gem "foo", "= 1.0", git: "#{lib_path("foo-1.0")}"
|
|
G
|
|
|
|
# If the lockfile erroneously lists platform versions of the gem
|
|
# that don't match the locked version of the git repo we should remove them.
|
|
|
|
lockfile <<~L
|
|
GIT
|
|
remote: #{lib_path("foo-1.0")}
|
|
revision: #{git.ref_for("main")}
|
|
specs:
|
|
foo (1.0)
|
|
|
|
GEM
|
|
remote: https://gem.repo1/
|
|
specs:
|
|
foo (1.1-x86_64-linux-gnu)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
foo (= 1.0)!
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
|
|
bundle "install"
|
|
|
|
expect(lockfile).to eq <<~L
|
|
GIT
|
|
remote: #{lib_path("foo-1.0")}
|
|
revision: #{git.ref_for("main")}
|
|
specs:
|
|
foo (1.0)
|
|
|
|
GEM
|
|
remote: https://gem.repo1/
|
|
specs:
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
foo (= 1.0)!
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
end
|
|
|
|
it "automatically fixes the lockfile when it has incorrect deps, keeping the locked version" do
|
|
build_repo4 do
|
|
build_gem "net-smtp", "0.5.0" do |s|
|
|
s.add_dependency "net-protocol"
|
|
end
|
|
|
|
build_gem "net-smtp", "0.5.1" do |s|
|
|
s.add_dependency "net-protocol"
|
|
end
|
|
|
|
build_gem "net-protocol", "0.2.2"
|
|
end
|
|
|
|
gemfile <<~G
|
|
source "#{file_uri_for(gem_repo4)}"
|
|
gem "net-smtp"
|
|
G
|
|
|
|
lockfile <<~L
|
|
GEM
|
|
remote: #{file_uri_for(gem_repo4)}/
|
|
specs:
|
|
net-protocol (0.2.2)
|
|
net-smtp (0.5.0)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
net-smtp
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
|
|
bundle "install"
|
|
|
|
expect(lockfile).to eq <<~L
|
|
GEM
|
|
remote: #{file_uri_for(gem_repo4)}/
|
|
specs:
|
|
net-protocol (0.2.2)
|
|
net-smtp (0.5.0)
|
|
net-protocol
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
net-smtp
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
end
|
|
|
|
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 "https://gem.repo4"
|
|
gem "minitest-bisect"
|
|
G
|
|
|
|
# Corrupt lockfile (completely missing path_expander)
|
|
lockfile <<~L
|
|
GEM
|
|
remote: https://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: https://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 "https://gem.repo4"
|
|
gem "minitest-bisect"
|
|
G
|
|
|
|
lockfile <<~L
|
|
GEM
|
|
remote: https://gem.repo4/
|
|
specs:
|
|
minitest-bisect (1.6.0)
|
|
path_expander (~> 1.1)
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
minitest-bisect
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
|
|
bundle "install --verbose"
|
|
expect(out).to include("re-resolving dependencies because your lockfile includes \"minitest-bisect\" but not some of its dependencies")
|
|
|
|
expect(lockfile).to eq <<~L
|
|
GEM
|
|
remote: https://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
|
|
def set_lockfile_mtime_to_known_value
|
|
time = Time.local(2000, 1, 1, 0, 0, 0)
|
|
File.utime(time, time, bundled_app_lock)
|
|
end
|
|
before(:each) do
|
|
build_repo2
|
|
|
|
install_gemfile <<-G
|
|
source "https://gem.repo2"
|
|
gem "myrack"
|
|
G
|
|
set_lockfile_mtime_to_known_value
|
|
end
|
|
|
|
it "generates Gemfile.lock with \\n line endings" do
|
|
expect(File.read(bundled_app_lock)).not_to match("\r\n")
|
|
expect(the_bundle).to include_gems "myrack 1.0"
|
|
end
|
|
|
|
context "during updates" do
|
|
it "preserves Gemfile.lock \\n line endings" do
|
|
update_repo2 do
|
|
build_gem "myrack", "1.2" do |s|
|
|
s.executables = "myrackup"
|
|
end
|
|
end
|
|
|
|
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 "myrack 1.2"
|
|
end
|
|
|
|
it "preserves Gemfile.lock \\n\\r line endings" do
|
|
skip "needs to be adapted" if Gem.win_platform?
|
|
|
|
update_repo2 do
|
|
build_gem "myrack", "1.2" do |s|
|
|
s.executables = "myrackup"
|
|
end
|
|
end
|
|
|
|
win_lock = File.read(bundled_app_lock).gsub(/\n/, "\r\n")
|
|
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(File.read(bundled_app_lock)).to match("\r\n")
|
|
|
|
expect(the_bundle).to include_gems "myrack 1.2"
|
|
end
|
|
end
|
|
|
|
context "when nothing changes" do
|
|
it "preserves Gemfile.lock \\n line endings" do
|
|
expect do
|
|
ruby <<-RUBY
|
|
require 'bundler'
|
|
Bundler.setup
|
|
RUBY
|
|
end.not_to change { File.mtime(bundled_app_lock) }
|
|
end
|
|
|
|
it "preserves Gemfile.lock \\n\\r line endings" do
|
|
win_lock = File.read(bundled_app_lock).gsub(/\n/, "\r\n")
|
|
File.open(bundled_app_lock, "wb") {|f| f.puts(win_lock) }
|
|
set_lockfile_mtime_to_known_value
|
|
|
|
expect do
|
|
ruby <<-RUBY
|
|
require 'bundler'
|
|
Bundler.setup
|
|
RUBY
|
|
end.not_to change { File.mtime(bundled_app_lock) }
|
|
end
|
|
end
|
|
end
|
|
|
|
it "refuses to install if Gemfile.lock contains conflict markers" do
|
|
lockfile <<-L
|
|
GEM
|
|
remote: https://gem.repo2//
|
|
specs:
|
|
<<<<<<<
|
|
myrack (1.0.0)
|
|
=======
|
|
myrack (1.0.1)
|
|
>>>>>>>
|
|
|
|
PLATFORMS
|
|
#{lockfile_platforms}
|
|
|
|
DEPENDENCIES
|
|
myrack
|
|
|
|
BUNDLED WITH
|
|
#{Bundler::VERSION}
|
|
L
|
|
|
|
install_gemfile <<-G, raise_on_error: false
|
|
source "https://gem.repo2/"
|
|
gem "myrack"
|
|
G
|
|
|
|
expect(err).to match(/your Gemfile.lock contains merge conflicts/i)
|
|
expect(err).to match(/git checkout HEAD -- Gemfile.lock/i)
|
|
end
|
|
|
|
private
|
|
|
|
def previous_major(version)
|
|
version.split(".").map.with_index {|v, i| i == 0 ? v.to_i - 1 : v }.join(".")
|
|
end
|
|
end
|