summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbdelkader Boudih <terminale@gmail.com>2026-01-05 10:15:31 +0100
committergit <svn-admin@ruby-lang.org>2026-02-13 06:19:27 +0000
commit7e20c950933821dc1ee51f0f1d5d41706206ea24 (patch)
tree4410267f2a0683e2e85040bbdb4c035b002a4377
parent00440871dbe648cf7f8e2ebc2f01d3b1e0024cd6 (diff)
[ruby/rubygems] fix(bundler): only preload git sources for requested groups
Skip fetching git sources for excluded groups (--without). This is important for production builds where development git dependencies may be private repos without access, or should not be included in Docker images. https://github.com/ruby/rubygems/commit/d034ee10bb
-rw-r--r--lib/bundler/definition.rb19
-rw-r--r--lib/bundler/source/rubygems_aggregate.rb5
-rw-r--r--lib/bundler/source_map.rb8
-rw-r--r--spec/bundler/install/git_spec.rb28
4 files changed, 54 insertions, 6 deletions
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb
index 3cf9fbe8bf..4c0c337535 100644
--- a/lib/bundler/definition.rb
+++ b/lib/bundler/definition.rb
@@ -1125,11 +1125,24 @@ module Bundler
end
def preload_git_sources
- sources.git_sources.each {|source| preload_git_source_worker.enq(source) }
+ needed_git_sources.each {|source| preload_git_source_worker.enq(source) }
ensure
preload_git_source_worker.stop
end
+ # Git sources needed for the requested groups (excludes sources only used by --without groups)
+ def needed_git_sources
+ needed_deps = dependencies_for(requested_groups)
+ sources.git_sources.select do |source|
+ needed_deps.any? {|d| d.source == source }
+ end
+ end
+
+ # Git sources that should be excluded (only used by --without groups)
+ def excluded_git_sources
+ sources.git_sources - needed_git_sources
+ end
+
def find_source_requirements
if Gem.ruby_version >= Gem::Version.new("3.3")
# Ruby 3.2 has a bug that incorrectly triggers a circular dependency warning. This version will continue to
@@ -1141,10 +1154,10 @@ module Bundler
# specs will be available later when the resolver knows where to
# look for that gemspec (or its dependencies)
source_requirements = if precompute_source_requirements_for_indirect_dependencies?
- all_requirements = source_map.all_requirements
+ all_requirements = source_map.all_requirements(excluded_git_sources)
{ default: default_source }.merge(all_requirements)
else
- { default: Source::RubygemsAggregate.new(sources, source_map) }.merge(source_map.direct_requirements)
+ { default: Source::RubygemsAggregate.new(sources, source_map, excluded_git_sources) }.merge(source_map.direct_requirements)
end
source_requirements.merge!(source_map.locked_requirements) if nothing_changed?
metadata_dependencies.each do |dep|
diff --git a/lib/bundler/source/rubygems_aggregate.rb b/lib/bundler/source/rubygems_aggregate.rb
index 99ef81ad54..8aeaa375fa 100644
--- a/lib/bundler/source/rubygems_aggregate.rb
+++ b/lib/bundler/source/rubygems_aggregate.rb
@@ -5,9 +5,10 @@ module Bundler
class RubygemsAggregate
attr_reader :source_map, :sources
- def initialize(sources, source_map)
+ def initialize(sources, source_map, excluded_sources = [])
@sources = sources
@source_map = source_map
+ @excluded_sources = excluded_sources
@index = build_index
end
@@ -31,6 +32,8 @@ module Bundler
dependency_names = source_map.pinned_spec_names
sources.all_sources.each do |source|
+ next if @excluded_sources.include?(source)
+
source.dependency_names = dependency_names - source_map.pinned_spec_names(source)
idx.add_source source.specs
dependency_names.concat(source.unmet_deps).uniq!
diff --git a/lib/bundler/source_map.rb b/lib/bundler/source_map.rb
index cb88caf1bd..513eb37f8b 100644
--- a/lib/bundler/source_map.rb
+++ b/lib/bundler/source_map.rb
@@ -14,10 +14,14 @@ module Bundler
direct_requirements.reject {|_, source| source == skip }.keys
end
- def all_requirements
+ def all_requirements(excluded_sources = [])
requirements = direct_requirements.dup
- unmet_deps = sources.non_default_explicit_sources.map do |source|
+ explicit_sources = sources.non_default_explicit_sources.reject do |source|
+ excluded_sources.include?(source)
+ end
+
+ unmet_deps = explicit_sources.map do |source|
(source.spec_names - pinned_spec_names).each do |indirect_dependency_name|
previous_source = requirements[indirect_dependency_name]
if previous_source.nil?
diff --git a/spec/bundler/install/git_spec.rb b/spec/bundler/install/git_spec.rb
index aa707a0222..6ecf3574d7 100644
--- a/spec/bundler/install/git_spec.rb
+++ b/spec/bundler/install/git_spec.rb
@@ -290,4 +290,32 @@ RSpec.describe "bundle install" do
end
end
end
+
+ describe "with excluded groups" do
+ it "works if you exclude a group with a git gem", :ruby => ">= 3.3" do
+ build_git "production_gem", "1.0"
+ build_git "development_gem", "1.0"
+
+ gemfile <<-G
+ source "https://gem.repo1"
+
+ gem "production_gem", :git => "#{lib_path("production_gem-1.0")}"
+
+ group :development do
+ gem "development_gem", :git => "#{lib_path("development_gem-1.0")}"
+ end
+ G
+
+ # First install all groups to create lockfile
+ bundle :install
+
+ # Set without and reinstall
+ bundle "config set --local without development"
+ bundle :install
+
+ # Verify only production gem is available
+ expect(the_bundle).to include_gems("production_gem 1.0")
+ expect(the_bundle).not_to include_gems("development_gem 1.0")
+ end
+ end
end