[rubygems/rubygems] Allow using gemspec DSL twice with same dependency and compatible requirements

https://github.com/rubygems/rubygems/commit/a8d14c1fc2
This commit is contained in:
David Rodríguez 2024-09-03 18:03:16 +02:00 committed by git
parent 817f2cc172
commit d4a18d4a78
2 changed files with 88 additions and 15 deletions

View File

@ -110,9 +110,23 @@ module Bundler
if gemspec_dep if gemspec_dep
gemfile_dep = [dep, current].find(&:runtime?) gemfile_dep = [dep, current].find(&:runtime?)
unless current_requirement_open if gemfile_dep && !current_requirement_open
Bundler.ui.warn "A gemspec development dependency (#{gemspec_dep.name}, #{gemspec_dep.requirement}) is being overridden by a Gemfile dependency (#{gemfile_dep.name}, #{gemfile_dep.requirement}).\n" \ Bundler.ui.warn "A gemspec development dependency (#{gemspec_dep.name}, #{gemspec_dep.requirement}) is being overridden by a Gemfile dependency (#{gemfile_dep.name}, #{gemfile_dep.requirement}).\n" \
"This behaviour may change in the future. Please remove either of them, or make sure they both have the same requirement\n" "This behaviour may change in the future. Please remove either of them, or make sure they both have the same requirement\n"
elsif gemfile_dep.nil?
require_relative "vendor/pub_grub/lib/pub_grub/version_range"
require_relative "vendor/pub_grub/lib/pub_grub/version_constraint"
require_relative "vendor/pub_grub/lib/pub_grub/version_union"
require_relative "vendor/pub_grub/lib/pub_grub/rubygems"
current_gemspec_range = PubGrub::RubyGems.requirement_to_range(current.requirement)
next_gemspec_range = PubGrub::RubyGems.requirement_to_range(dep.requirement)
if current_gemspec_range.intersects?(next_gemspec_range)
dep = Dependency.new(name, current.requirement.as_list + dep.requirement.as_list, options)
else
raise GemfileError, "Two gemspecs have conflicting requirements on the same gem: #{dep} and #{current}"
end
end end
else else
update_prompt = "" update_prompt = ""
@ -133,20 +147,22 @@ module Bundler
end end
end end
# Always prefer the dependency from the Gemfile unless current.gemspec_dev_dep? && dep.gemspec_dev_dep?
if current.gemspec_dev_dep? # Always prefer the dependency from the Gemfile
@dependencies.delete(current) if current.gemspec_dev_dep?
elsif dep.gemspec_dev_dep? @dependencies.delete(current)
return elsif dep.gemspec_dev_dep?
elsif current.source != dep.source return
raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \ elsif current.source != dep.source
"You specified that #{dep.name} (#{dep.requirement}) should come from " \ raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \
"#{current.source || "an unspecified source"} and #{dep.source}\n" "You specified that #{dep.name} (#{dep.requirement}) should come from " \
else "#{current.source || "an unspecified source"} and #{dep.source}\n"
Bundler.ui.warn "Your Gemfile lists the gem #{current.name} (#{current.requirement}) more than once.\n" \ else
"You should probably keep only one of them.\n" \ Bundler.ui.warn "Your Gemfile lists the gem #{current.name} (#{current.requirement}) more than once.\n" \
"Remove any duplicate entries and specify the gem only once.\n" \ "You should probably keep only one of them.\n" \
"While it's not a problem now, it could cause errors if you change the version of one of them later." "Remove any duplicate entries and specify the gem only once.\n" \
"While it's not a problem now, it could cause errors if you change the version of one of them later."
end
end end
end end

View File

@ -485,6 +485,63 @@ RSpec.describe "bundle install with gem sources" do
expect(the_bundle).to include_gems("rubocop 1.36.0") expect(the_bundle).to include_gems("rubocop 1.36.0")
end end
it "includes the gem without warning if two gemspecs add it with compatible requirements" do
gem1 = tmp("my-gem-1")
gem2 = tmp("my-gem-2")
build_lib "my-gem", path: gem1 do |s|
s.add_development_dependency "rubocop", "~> 1.0"
end
build_lib "my-gem-2", path: gem2 do |s|
s.add_development_dependency "rubocop", "~> 1.36.0"
end
build_repo4 do
build_gem "rubocop", "1.36.0"
end
gemfile <<~G
source "https://gem.repo4"
gemspec path: "#{gem1}"
gemspec path: "#{gem2}"
G
bundle :install
expect(err).to be_empty
expect(the_bundle).to include_gems("rubocop 1.36.0")
end
it "errors out if two gemspecs add it with incompatible requirements" do
gem1 = tmp("my-gem-1")
gem2 = tmp("my-gem-2")
build_lib "my-gem", path: gem1 do |s|
s.add_development_dependency "rubocop", "~> 2.0"
end
build_lib "my-gem-2", path: gem2 do |s|
s.add_development_dependency "rubocop", "~> 1.36.0"
end
build_repo4 do
build_gem "rubocop", "1.36.0"
end
gemfile <<~G
source "https://gem.repo4"
gemspec path: "#{gem1}"
gemspec path: "#{gem2}"
G
bundle :install, raise_on_error: false
expect(err).to include("Two gemspecs have conflicting requirements on the same gem: rubocop (~> 1.36.0, development) and rubocop (~> 2.0, development). Bundler cannot continue.")
end
it "warns when a Gemfile dependency is overriding a gemspec development dependency, with different requirements" do it "warns when a Gemfile dependency is overriding a gemspec development dependency, with different requirements" do
build_lib "my-gem", path: bundled_app do |s| build_lib "my-gem", path: bundled_app do |s|
s.add_development_dependency "rails", ">= 5" s.add_development_dependency "rails", ">= 5"