From c8f4df4ae93cec8825c919bfebaa5f1f744ba09c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Rodr=C3=ADguez?= Date: Mon, 10 Feb 2025 15:41:54 +0100 Subject: [PATCH] [rubygems/rubygems] Make Bundler never instantiate development dependencies Bundler does not really have a concept of "development dependencies", like RubyGems has. Bundler has the more generic concept of "groups". Under the hood, the `gemspec` DSL will put gemspec development dependencies under a `:development` Gemfile group, but there's no reason to instantiate these as development dependencies, they are regular runtime dependencies, except that they belong in a group named :development. By never instantiating development dependencies at all, we avoid having to introduce hacks to "undo" the type Bundler does not know about, and I also think the error messages read better. https://github.com/rubygems/rubygems/commit/9a06fa5bda --- lib/bundler/definition.rb | 8 -------- lib/bundler/dependency.rb | 6 +++++- lib/bundler/dsl.rb | 6 +++--- spec/bundler/commands/install_spec.rb | 2 +- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index da5c344354..b88f724680 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -948,14 +948,6 @@ module Bundler next end - # Gem::Dependency#== matches Gem::Dependency#type. As the lockfile - # doesn't carry a notion of the dependency type, if you use - # add_development_dependency in a gemspec that's loaded with the gemspec - # directive, the lockfile dependencies and resolved dependencies end up - # with a mismatch on #type. Work around that by setting the type on the - # dep from the lockfile. - locked_dep.instance_variable_set(:@type, dep.type) - # We already know the name matches from the hash lookup # so we only need to check the requirement now changes ||= dep.requirement != locked_dep.requirement diff --git a/lib/bundler/dependency.rb b/lib/bundler/dependency.rb index 736758e12c..e81696ff42 100644 --- a/lib/bundler/dependency.rb +++ b/lib/bundler/dependency.rb @@ -111,7 +111,11 @@ module Bundler end def gemspec_dev_dep? - type == :development + @gemspec_dev_dep ||= @options.fetch("gemspec_dev_dep", false) + end + + def gemfile_dep? + !gemspec_dev_dep? end def current_env? diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb index d9cc3e0f34..b55752663e 100644 --- a/lib/bundler/dsl.rb +++ b/lib/bundler/dsl.rb @@ -82,7 +82,7 @@ module Bundler end spec.development_dependencies.each do |dep| - add_dependency dep.name, dep.requirement.as_list, "type" => :development, "group" => development_group + add_dependency dep.name, dep.requirement.as_list, "gemspec_dev_dep" => true, "group" => development_group end when 0 raise InvalidOption, "There are no gemspecs at #{expanded_path}" @@ -247,7 +247,7 @@ module Bundler gemspec_dep = [dep, current].find(&:gemspec_dev_dep?) if gemspec_dep - gemfile_dep = [dep, current].find(&:runtime?) + gemfile_dep = [dep, current].find(&:gemfile_dep?) 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" \ @@ -264,7 +264,7 @@ module Bundler 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}" + raise GemfileError, "Two gemspec development dependencies have conflicting requirements on the same gem: #{dep} and #{current}" end end else diff --git a/spec/bundler/commands/install_spec.rb b/spec/bundler/commands/install_spec.rb index f2c1781418..00418da27f 100644 --- a/spec/bundler/commands/install_spec.rb +++ b/spec/bundler/commands/install_spec.rb @@ -581,7 +581,7 @@ RSpec.describe "bundle install with gem sources" do 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.") + expect(err).to include("Two gemspec development dependencies have conflicting requirements on the same gem: rubocop (~> 1.36.0) and rubocop (~> 2.0). Bundler cannot continue.") end it "warns when a Gemfile dependency is overriding a gemspec development dependency, with different requirements" do