diff options
| author | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2026-05-07 20:08:37 +0900 |
|---|---|---|
| committer | git <svn-admin@ruby-lang.org> | 2026-05-08 06:43:45 +0000 |
| commit | dff3200e5ca078977a40d92ad4236b9c8d60499e (patch) | |
| tree | 2346f9213fde8e6d0604a6078d17d86881728fe2 | |
| parent | 0beb804ef79c3355c19ed272106c42b02780b607 (diff) | |
[ruby/rubygems] Stop blanket-unlocking the lockfile on :all overrides
Previously, any :all override called unlock_all_locked_specs_for_override
which pushed every locked spec into @gems_to_unlock. A user adding a
narrow `override :all, required_ruby_version: :ignore_upper` thus paid
for a full re-resolve that could pull unrelated dependency
upgrades/downgrades.
Make :all overrides leave the lockfile alone at converge time. They
take effect on a fresh resolution (no lockfile) or when the user opts
in via `bundle update`. Per-gem overrides retain their unlock for the
named gem since the user explicitly named the target.
https://github.com/ruby/rubygems/commit/3c95ab99e3
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| -rw-r--r-- | lib/bundler/definition.rb | 18 | ||||
| -rw-r--r-- | spec/bundler/install/gemfile/override_spec.rb | 8 |
2 files changed, 11 insertions, 15 deletions
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 2fe28f7656..2aa74804ba 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -1061,11 +1061,10 @@ module Bundler def converge_overrides_outside_dependencies @overrides.each do |override| - if override.target == :all - unlock_all_locked_specs_for_override - next - end - + # :all overrides are intentionally not pre-unlocked. They take effect on + # fresh resolution (no lockfile) or when the user runs `bundle update`. + # Forcing a full re-resolve from a single :all directive would surprise + # users with unrelated dependency churn. next unless override.target.is_a?(String) name = override.target @@ -1081,15 +1080,6 @@ module Bundler end end - def unlock_all_locked_specs_for_override - @originally_locked_specs.each do |locked_spec| - name = locked_spec.name - next if @changed_dependencies.include?(name) - @gems_to_unlock << name - @changed_dependencies << name - end - end - # Remove elements from the locked specs that are expired. This will most # commonly happen if the Gemfile has changed since the lockfile was last # generated diff --git a/spec/bundler/install/gemfile/override_spec.rb b/spec/bundler/install/gemfile/override_spec.rb index 19fa2ee915..02b0e7d772 100644 --- a/spec/bundler/install/gemfile/override_spec.rb +++ b/spec/bundler/install/gemfile/override_spec.rb @@ -291,7 +291,7 @@ RSpec.describe "override DSL" do expect(err).to include("still_blocked") end - it "re-resolves a previously locked spec when an :all metadata override is added" do + it "preserves locked versions when an :all metadata override is added without bundle update" do build_repo2 do build_gem "selectable", "1.0" build_gem "selectable", "2.0" do |s| @@ -313,7 +313,13 @@ RSpec.describe "override DSL" do gem "selectable" G + # :all override alone does not pre-unlock locked specs; narrow change + # should not trigger unrelated lockfile churn. bundle :lock + expect(lockfile).to include("selectable (1.0)") + + # bundle update opts the user into re-resolution under the override. + bundle "update selectable" expect(lockfile).to include("selectable (2.0)") end end |
