[ruby/rubygems] Add support for BUNDLE_LOCKFILE environment variable

This specifies the lockfile location. This allows for easy support
of different lockfiles per Ruby version or platform.

https://github.com/ruby/rubygems/commit/b54d65bc0a

Co-authored-by: Sutou Kouhei <kou@cozmixng.org>
Co-authored-by: Colby Swandale <996377+colby-swandale@users.noreply.github.com>
This commit is contained in:
Jeremy Evans 2025-11-10 18:23:58 -08:00 committed by git
parent 1562803e51
commit 010b23a7cf
11 changed files with 95 additions and 3 deletions

View File

@ -6,6 +6,7 @@ module Bundler
BUNDLER_KEYS = %w[
BUNDLE_BIN_PATH
BUNDLE_GEMFILE
BUNDLE_LOCKFILE
BUNDLER_VERSION
BUNDLER_SETUP
GEM_HOME

View File

@ -44,12 +44,14 @@ def gemfile(force_latest_compatible = false, options = {}, &gemfile)
raise ArgumentError, "Unknown options: #{opts.keys.join(", ")}" unless opts.empty?
old_gemfile = ENV["BUNDLE_GEMFILE"]
old_lockfile = ENV["BUNDLE_LOCKFILE"]
Bundler.unbundle_env!
begin
Bundler.instance_variable_set(:@bundle_path, Pathname.new(Gem.dir))
Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile"
Bundler::SharedHelpers.set_env "BUNDLE_LOCKFILE", "Gemfile.lock"
Bundler::Plugin.gemfile_install(&gemfile) if Bundler.settings[:plugins]
builder = Bundler::Dsl.new
@ -94,5 +96,11 @@ def gemfile(force_latest_compatible = false, options = {}, &gemfile)
else
ENV["BUNDLE_GEMFILE"] = ""
end
if old_lockfile
ENV["BUNDLE_LOCKFILE"] = old_lockfile
else
ENV["BUNDLE_LOCKFILE"] = ""
end
end
end

View File

@ -145,6 +145,9 @@ Generate a \fBgems\.rb\fR instead of a \fBGemfile\fR when running \fBbundle init
\fBjobs\fR (\fBBUNDLE_JOBS\fR)
The number of gems Bundler can install in parallel\. Defaults to the number of available processors\.
.TP
\fBlockfile\fR (\fBBUNDLE_LOCKFILE\fR)
The path to the lockfile that bundler should use\. By default, Bundler adds \fB\.lock\fR to the end of the \fBgemfile\fR entry\. Can be set to \fBfalse\fR in the Gemfile to disable lockfile creation entirely (see gemfile(5))\.
.TP
\fBlockfile_checksums\fR (\fBBUNDLE_LOCKFILE_CHECKSUMS\fR)
Whether Bundler should include a checksums section in new lockfiles, to protect from compromised gem sources\. Defaults to true\.
.TP

View File

@ -189,6 +189,10 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html).
* `jobs` (`BUNDLE_JOBS`):
The number of gems Bundler can install in parallel. Defaults to the number of
available processors.
* `lockfile` (`BUNDLE_LOCKFILE`):
The path to the lockfile that bundler should use. By default, Bundler adds
`.lock` to the end of the `gemfile` entry. Can be set to `false` in the
Gemfile to disable lockfile creation entirely (see gemfile(5)).
* `lockfile_checksums` (`BUNDLE_LOCKFILE_CHECKSUMS`):
Whether Bundler should include a checksums section in new lockfiles, to protect from compromised gem sources. Defaults to true.
* `no_install` (`BUNDLE_NO_INSTALL`):

View File

@ -487,3 +487,15 @@ lockfile false
.IP "" 0
.P
This is useful for library development and other situations where the code is expected to work with a range of dependency versions\.
.SS "LOCKFILE PRECEDENCE"
When determining path to the lockfile or whether to create a lockfile, the following precedence is used:
.IP "1." 4
The \fBbundle install\fR \fB\-\-no\-lock\fR option (which disables lockfile creation)\.
.IP "2." 4
The \fBlockfile\fR method in the Gemfile\.
.IP "3." 4
The \fBBUNDLE_LOCKFILE\fR environment variable\.
.IP "4." 4
The default behavior of adding \fB\.lock\fR to the end of the Gemfile name\.
.IP "" 0

View File

@ -573,3 +573,13 @@ To avoid writing a lock file, use `false` as the argument:
This is useful for library development and other situations where the code is
expected to work with a range of dependency versions.
### LOCKFILE PRECEDENCE
When determining path to the lockfile or whether to create a lockfile, the
following precedence is used:
1. The `bundle install` `--no-lock` option (which disables lockfile creation).
2. The `lockfile` method in the Gemfile.
3. The `BUNDLE_LOCKFILE` environment variable.
4. The default behavior of adding `.lock` to the end of the Gemfile name.

View File

@ -65,6 +65,7 @@ module Bundler
gem.rubocop
gem.test
gemfile
lockfile
path
shebang
simulate_version

View File

@ -23,6 +23,9 @@ module Bundler
end
def default_lockfile
given = ENV["BUNDLE_LOCKFILE"]
return Pathname.new(given) if given && !given.empty?
gemfile = default_gemfile
case gemfile.basename.to_s
@ -297,6 +300,7 @@ module Bundler
def set_bundle_variables
Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", bundle_bin_path
Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", find_gemfile.to_s
Bundler::SharedHelpers.set_env "BUNDLE_LOCKFILE", default_lockfile.to_s
Bundler::SharedHelpers.set_env "BUNDLER_VERSION", Bundler::VERSION
Bundler::SharedHelpers.set_env "BUNDLER_SETUP", File.expand_path("setup", __dir__)
end

View File

@ -65,9 +65,12 @@ module Gem::BundlerVersionFinder
return unless gemfile
lockfile = case gemfile
when "gems.rb" then "gems.locked"
else "#{gemfile}.lock"
lockfile = ENV["BUNDLE_LOCKFILE"]
lockfile = nil if lockfile&.empty?
lockfile ||= case gemfile
when "gems.rb" then "gems.locked"
else "#{gemfile}.lock"
end
return unless File.file?(lockfile)

View File

@ -592,3 +592,20 @@ RSpec.describe "setting gemfile via config" do
end
end
end
RSpec.describe "setting lockfile via config" do
it "persists the lockfile location to .bundle/config" do
gemfile bundled_app("NotGemfile"), <<-G
source "https://gem.repo1"
gem 'myrack'
G
bundle "config set --local gemfile #{bundled_app("NotGemfile")}"
bundle "config set --local lockfile #{bundled_app("ReallyNotGemfile.lock")}"
expect(File.exist?(bundled_app(".bundle/config"))).to eq(true)
bundle "config list"
expect(out).to include("NotGemfile")
expect(out).to include("ReallyNotGemfile.lock")
end
end

View File

@ -27,6 +27,35 @@ RSpec.describe "bundle install" do
ENV["BUNDLE_GEMFILE"] = "NotGemfile"
expect(the_bundle).to include_gems "myrack 1.0.0"
end
it "respects lockfile and BUNDLE_LOCKFILE" do
gemfile bundled_app("NotGemfile"), <<-G
lockfile "ReallyNotGemfile.lock"
source "https://gem.repo1"
gem 'myrack'
G
bundle :install, gemfile: bundled_app("NotGemfile")
ENV["BUNDLE_GEMFILE"] = "NotGemfile"
ENV["BUNDLE_LOCKFILE"] = "ReallyNotGemfile.lock"
expect(the_bundle).to include_gems "myrack 1.0.0"
end
it "respects BUNDLE_LOCKFILE during bundle install" do
ENV["BUNDLE_LOCKFILE"] = "ReallyNotGemfile.lock"
gemfile bundled_app("NotGemfile"), <<-G
source "https://gem.repo1"
gem 'myrack'
G
bundle :install, gemfile: bundled_app("NotGemfile")
expect(bundled_app("ReallyNotGemfile.lock")).to exist
ENV["BUNDLE_GEMFILE"] = "NotGemfile"
expect(the_bundle).to include_gems "myrack 1.0.0"
end
end
context "with gemfile set via config" do