Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions lib/bundler/definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ def write_lock(file, preserve_unknown_sections)
updating_major = locked_major < current_major
end

preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler))
preserve_unknown_sections ||= Bundler.frozen_bundle? || (!updating_major && !(unlocking? || @unlocking_bundler))

if File.exist?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections)
return if Bundler.frozen_bundle?
Expand All @@ -419,8 +419,10 @@ def write_lock(file, preserve_unknown_sections)
end

if Bundler.frozen_bundle?
Bundler.ui.error "Cannot write a changed lockfile while frozen."
return
msg = lockfile_changes_summary("frozen mode is set") ||
"Your lockfile needs to be updated, but it can't be because frozen mode is set.\n\n" \
"Run `bundle install` elsewhere and add the updated #{SharedHelpers.relative_lockfile_path} to version control."
raise ProductionError, msg
end

# Convert to \r\n if the existing lock has them, i.e., Windows with
Expand Down
16 changes: 16 additions & 0 deletions lib/bundler/lockfile_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ def add_section(name, value)
end

def bundler_checksum
# In frozen mode the lockfile can't change, so reproduce whatever bundler
# entry is already locked instead of recording one for the running bundler
# version, which may legitimately differ from the locked one.
return locked_bundler_checksum if Bundler.frozen_bundle?

# `.dev` versions and `SKIP_BUNDLER_CHECKSUM` are deliberate opt-outs (used
# by Bundler/RubyGems' own development and release tasks): never record a
# checksum for Bundler itself in those cases.
Expand Down Expand Up @@ -138,5 +143,16 @@ def bundled_with_changing?

locked_gems.bundler_version != definition.bundler_version_to_lock
end

def locked_bundler_checksum
locked_version = definition.locked_gems&.bundler_version
return [] unless locked_version

metadata_source = definition.sources.metadata_source
locked_spec = LazySpecification.new("bundler", locked_version, Gem::Platform::RUBY, metadata_source)
return [] if metadata_source.checksum_store.missing?(locked_spec)

[metadata_source.checksum_store.to_lock(locked_spec)]
end
end
end
2 changes: 1 addition & 1 deletion spec/cache/git_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@
G
lockfile <<~L
GIT
remote: #{git_path}/
remote: #{git_path}
revision: #{locked_revision}
specs:
foo (1.0)
Expand Down
4 changes: 2 additions & 2 deletions spec/commands/cache_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -349,15 +349,15 @@
GEM
remote: https://gem.repo4/
specs:
foo (1.0.0)
bar (1.0.0)
foo (1.0.0)

PLATFORMS
#{lockfile_platforms}

DEPENDENCIES
foo
bar
foo

BUNDLED WITH
#{Bundler::VERSION}
Expand Down
69 changes: 69 additions & 0 deletions spec/install/deploy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,75 @@
end.not_to change { bundled_app_lock.mtime }
end

it "explodes if regenerating the lockfile would change it" do
lockfile lockfile.
sub(" myrack (1.0.0)", " myrack-obama (1.0)\n myrack (1.0.0)").
sub(/^ myrack \(1\.0\.0\) sha256=\S+$/) {|line| "#{line}\n #{checksum_to_lock(gem_repo1, "myrack-obama", "1.0")}" }

bundle :install, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false
expect(err).to include("Your lockfile needs to be updated, but it can't be because frozen mode is set")
expect(last_command).to be_failure
end

it "explodes on `bundle check` if the lockfile contains a gem bundler would prune" do
lockfile lockfile.sub(" myrack (1.0.0)", " myrack (1.0.0)\n myrack-obama (1.0)")

bundle :check, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false
expect(err).to include("but can't be updated because frozen mode is set")
expect(last_command).to be_failure
end

it "works when the lockfile includes a checksum entry for bundler itself" do
lockfile <<~L
GEM
remote: https://gem.repo1/
specs:
myrack (1.0.0)

PLATFORMS
#{lockfile_platforms}

DEPENDENCIES
myrack

CHECKSUMS
bundler (#{Bundler::VERSION}) sha256=#{"a" * 64}
#{checksum_to_lock gem_repo1, "myrack", "1.0.0"}

BUNDLED WITH
#{Bundler::VERSION}
L

bundle :install, env: { "BUNDLE_FROZEN" => "true" }
expect(err).to be_empty
end

it "explodes if the lockfile checksum entry for bundler does not match the BUNDLED WITH version" do
lockfile <<~L
GEM
remote: https://gem.repo1/
specs:
myrack (1.0.0)

PLATFORMS
#{lockfile_platforms}

DEPENDENCIES
myrack

CHECKSUMS
bundler (4.0.16) sha256=#{"a" * 64}
#{checksum_to_lock gem_repo1, "myrack", "1.0.0"}

BUNDLED WITH
#{Bundler::VERSION}
L

bundle :install, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false
expect(err).to include("Your lockfile needs to be updated, but it can't be because frozen mode is set")
expect(last_command).to be_failure
end

it "explodes with the `deployment` setting if you make a change and don't check in the lockfile" do
gemfile <<-G
source "https://gem.repo1"
Expand Down
2 changes: 1 addition & 1 deletion spec/install/gemfile/platform_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
it "pulls the pure ruby version on jruby if the java platform is not present in the lockfile and bundler is run in frozen mode", :jruby_only do
lockfile <<-G
GEM
remote: https://gem.repo1
remote: https://gem.repo1/
specs:
platform_specific (1.0)

Expand Down