diff options
-rw-r--r-- | lib/bundler/definition.rb | 14 | ||||
-rw-r--r-- | spec/bundler/commands/update_spec.rb | 66 |
2 files changed, 75 insertions, 5 deletions
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 61add4be10..24dae86493 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -938,7 +938,7 @@ module Bundler def converge_dependencies @missing_lockfile_dep = nil - changes = false + @changed_dependencies = [] current_dependencies.each do |dep| if dep.source @@ -960,10 +960,10 @@ module Bundler end end - changes ||= dep_changed + @changed_dependencies << name if dep_changed end - changes + @changed_dependencies.any? end # Remove elements from the locked specs that are expired. This will most @@ -1095,9 +1095,13 @@ module Bundler def additional_base_requirements_to_prevent_downgrades(resolution_packages) return resolution_packages unless @locked_gems && !sources.expired_sources?(@locked_gems.sources) - converge_specs(@originally_locked_specs).each do |locked_spec| + @originally_locked_specs.each do |locked_spec| next if locked_spec.source.is_a?(Source::Path) - resolution_packages.base_requirements[locked_spec.name] = Gem::Requirement.new(">= #{locked_spec.version}") + + name = locked_spec.name + next if @changed_dependencies.include?(name) + + resolution_packages.base_requirements[name] = Gem::Requirement.new(">= #{locked_spec.version}") end resolution_packages end diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb index 058cd2ec82..f6d0188794 100644 --- a/spec/bundler/commands/update_spec.rb +++ b/spec/bundler/commands/update_spec.rb @@ -428,6 +428,72 @@ RSpec.describe "bundle update" do expect(out).to include("Installing sneakers 2.11.0").and include("Installing rake 13.0.6") end + it "does not downgrade direct dependencies unnecessarily" do + build_repo4 do + build_gem "redis", "4.8.1" + build_gem "redis", "5.3.0" + + build_gem "sidekiq", "6.5.5" do |s| + s.add_dependency "redis", ">= 4.5.0" + end + + build_gem "sidekiq", "6.5.12" do |s| + s.add_dependency "redis", ">= 4.5.0", "< 5" + end + + # one version of sidekiq above Gemfile's range is needed to make the + # resolver choose `redis` first and trying to upgrade it, reproducing + # the accidental sidekiq downgrade as a result + build_gem "sidekiq", "7.0.0 " do |s| + s.add_dependency "redis", ">= 4.2.0" + end + + build_gem "sentry-sidekiq", "5.22.0" do |s| + s.add_dependency "sidekiq", ">= 3.0" + end + + build_gem "sentry-sidekiq", "5.22.4" do |s| + s.add_dependency "sidekiq", ">= 3.0" + end + end + + gemfile <<~G + source "https://gem.repo4" + + gem "redis" + gem "sidekiq", "~> 6.5" + gem "sentry-sidekiq" + G + + original_lockfile = <<~L + GEM + remote: https://gem.repo4/ + specs: + redis (4.8.1) + sentry-sidekiq (5.22.0) + sidekiq (>= 3.0) + sidekiq (6.5.12) + redis (>= 4.5.0, < 5) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + redis + sentry-sidekiq + sidekiq (~> 6.5) + + BUNDLED WITH + #{Bundler::VERSION} + L + + lockfile original_lockfile + + bundle "lock --update sentry-sidekiq" + + expect(lockfile).to eq(original_lockfile.sub("sentry-sidekiq (5.22.0)", "sentry-sidekiq (5.22.4)")) + end + it "does not downgrade indirect dependencies unnecessarily" do build_repo4 do build_gem "a" do |s| |