Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Downgrade bundler mismatches to a warning (2nd try) #2696

Closed
13 changes: 4 additions & 9 deletions lib/rubygems.rb
Original file line number Diff line number Diff line change
Expand Up @@ -266,17 +266,10 @@ def self.find_spec_for_exe(name, exec_name, requirements)

return loaded if loaded && dep.matches_spec?(loaded)

specs = dep.matching_specs(true)
spec = dep.spec_for_exe(exec_name)

specs = specs.find_all do |spec|
spec.executables.include? exec_name
end if exec_name

unless spec = specs.first
unless spec
msg = "can't find gem #{dep} with executable #{exec_name}"
if name == "bundler" && bundler_message = Gem::BundlerVersionFinder.missing_version_message
msg = bundler_message
end
raise Gem::GemNotFoundException, msg
end

Expand Down Expand Up @@ -1182,6 +1175,8 @@ def self.use_gemdeps(path = nil)
end

ENV["BUNDLE_GEMFILE"] ||= File.expand_path(path)
ENV["BUNDLE_PATH__SYSTEM"] ||= "true"

require 'rubygems/user_interaction'
Gem::DefaultUserInteraction.use_ui(ui) do
require "bundler"
Expand Down
7 changes: 4 additions & 3 deletions lib/rubygems/bundler_version_finder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,11 @@ def self.compatible?(spec)
spec.version.segments.first == bundler_version.segments.first
end

def self.filter!(specs)
return unless bundler_version = self.bundler_version
def self.prioritize!(specs)
match_index = specs.find_index { |spec| compatible?(spec) }
return unless match_index

specs.reject! { |spec| spec.version.segments.first != bundler_version.segments.first }
specs.unshift(specs.delete_at(match_index))
end

def self.bundle_update_bundler_version
Expand Down
2 changes: 1 addition & 1 deletion lib/rubygems/core_ext/kernel_require.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def require(path)
if spec = Gem.find_unresolved_default_spec(path)
Gem.remove_unresolved_default_spec(spec)
begin
Kernel.send(:gem, spec.name)
Kernel.send(:gem, spec.name, "#{Gem::Requirement.default}.a")
rescue Exception
RUBYGEMS_ACTIVATION_MONITOR.exit
raise
Expand Down
35 changes: 29 additions & 6 deletions lib/rubygems/dependency.rb
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ def matching_specs(platform_only = false)
requirement.satisfied_by?(spec.version) && env_req.satisfied_by?(spec.version)
end.map(&:to_spec)

Gem::BundlerVersionFinder.filter!(matches) if name == "bundler".freeze
Gem::BundlerVersionFinder.prioritize!(matches) if name == "bundler".freeze

if platform_only
matches.reject! do |spec|
Expand Down Expand Up @@ -325,13 +325,36 @@ def to_spec
active = matches.find { |spec| spec.activated? }
return active if active

return matches.first if prerelease?
unless prerelease?
# Move prereleases to the end of the list for >= 0 requirements
pre, matches = matches.partition { |spec| spec.version.prerelease? }
matches += pre if requirement == Gem::Requirement.default
end

select_first(matches)
end

def spec_for_exe(exec_name)
matches = matching_specs(true)

matches = matches.find_all do |spec|
spec.executables.include? exec_name
end if exec_name

# Move prereleases to the end of the list for >= 0 requirements
pre, matches = matches.partition { |spec| spec.version.prerelease? }
matches += pre if requirement == Gem::Requirement.default
select_first(matches)
end

private

def select_first(matches)
spec = matches.first
return unless spec

if !Gem::BundlerVersionFinder.compatible?(spec)
warn Gem::BundlerVersionFinder.missing_version_message
end

matches.first
spec
end

end
3 changes: 0 additions & 3 deletions lib/rubygems/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,6 @@ def initialize(name, requirement, specs)
private

def build_message
if name == "bundler" && message = Gem::BundlerVersionFinder.missing_version_message
return message
end
names = specs.map(&:full_name)
"Could not find '#{name}' (#{requirement}) - did find: [#{names.join ','}]\n"
end
Expand Down
24 changes: 17 additions & 7 deletions test/rubygems/test_gem.rb
Original file line number Diff line number Diff line change
Expand Up @@ -329,14 +329,14 @@ def test_activate_bin_path_gives_proper_error_for_bundler

File.open("Gemfile", "w") { |f| f.puts('source "https://rubygems.org"') }

e = assert_raises Gem::GemNotFoundException do
_, err = capture_io do
load Gem.activate_bin_path("bundler", "bundle", ">= 0.a")
end

assert_includes e.message, "Could not find 'bundler' (9999) required by your #{File.expand_path("Gemfile.lock")}."
assert_includes e.message, "To update to the latest version installed on your system, run `bundle update --bundler`."
assert_includes e.message, "To install the missing version, run `gem install bundler:9999`"
refute_includes e.message, "can't find gem bundler (>= 0.a) with executable bundle"
assert_includes err, "Could not find 'bundler' (9999) required by your #{File.expand_path("Gemfile.lock")}."
assert_includes err, "To update to the latest version installed on your system, run `bundle update --bundler`."
assert_includes err, "To install the missing version, run `gem install bundler:9999`"
refute_includes err, "can't find gem bundler (>= 0.a) with executable bundle"
end

def test_self_bin_path_no_exec_name
Expand Down Expand Up @@ -1824,11 +1824,21 @@ def test_use_gemdeps_missing_gem
platform = " #{platform}"
end

expected = <<-EXPECTED
expected =
if Bundler.feature_flag.lockfile_uses_separate_rubygems_sources?
<<-EXPECTED
Could not find gem 'a' in locally installed gems.
The source does not contain any versions of 'a'
You may need to `gem install -g` to install missing gems

EXPECTED
else
<<-EXPECTED
Could not find gem 'a#{platform}' in any of the gem sources listed in your Gemfile.
You may need to `gem install -g` to install missing gems

EXPECTED
EXPECTED
end

assert_output nil, expected do
Gem.use_gemdeps
Expand Down
20 changes: 10 additions & 10 deletions test/rubygems/test_gem_bundler_version_finder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,33 +100,33 @@ def test_compatible
end
end

def test_filter
def test_prioritize
versions = %w[1 1.0 1.0.1.1 2 2.a 2.0 2.1.1 3 3.a 3.0 3.1.1]
specs = versions.map { |v| util_spec("bundler", v) }

assert_equal %w[1 1.0 1.0.1.1 2 2.a 2.0 2.1.1 3 3.a 3.0 3.1.1], util_filter_specs(specs).map(&:version).map(&:to_s)
assert_equal %w[1 1.0 1.0.1.1 2 2.a 2.0 2.1.1 3 3.a 3.0 3.1.1], util_prioritize_specs(specs)

bvf.stub(:bundler_version, v("2.1.1.1")) do
assert_equal %w[2 2.a 2.0 2.1.1], util_filter_specs(specs).map(&:version).map(&:to_s)
assert_equal %w[2 1 1.0 1.0.1.1 2.a 2.0 2.1.1 3 3.a 3.0 3.1.1], util_prioritize_specs(specs)
end
bvf.stub(:bundler_version, v("1.1.1.1")) do
assert_equal %w[1 1.0 1.0.1.1], util_filter_specs(specs).map(&:version).map(&:to_s)
assert_equal %w[1 1.0 1.0.1.1 2 2.a 2.0 2.1.1 3 3.a 3.0 3.1.1], util_prioritize_specs(specs)
end
bvf.stub(:bundler_version, v("1")) do
assert_equal %w[1 1.0 1.0.1.1], util_filter_specs(specs).map(&:version).map(&:to_s)
assert_equal %w[1 1.0 1.0.1.1 2 2.a 2.0 2.1.1 3 3.a 3.0 3.1.1], util_prioritize_specs(specs)
end
bvf.stub(:bundler_version, v("2.a")) do
assert_equal %w[2 2.a 2.0 2.1.1], util_filter_specs(specs).map(&:version).map(&:to_s)
assert_equal %w[2 1 1.0 1.0.1.1 2.a 2.0 2.1.1 3 3.a 3.0 3.1.1], util_prioritize_specs(specs)
end
bvf.stub(:bundler_version, v("3")) do
assert_equal %w[3 3.a 3.0 3.1.1], util_filter_specs(specs).map(&:version).map(&:to_s)
assert_equal %w[3 1 1.0 1.0.1.1 2 2.a 2.0 2.1.1 3.a 3.0 3.1.1], util_prioritize_specs(specs)
end
end

def util_filter_specs(specs)
def util_prioritize_specs(specs)
specs = specs.dup
bvf.filter!(specs)
specs
bvf.prioritize!(specs)
specs.map(&:version).map(&:to_s)
end

end
10 changes: 3 additions & 7 deletions test/rubygems/test_gem_dependency.rb
Original file line number Diff line number Diff line change
Expand Up @@ -353,16 +353,12 @@ def test_to_specs_respects_bundler_version

assert_equal [b, b_1], dep.to_specs

Gem::BundlerVersionFinder.stub(:bundler_version_with_reason, ["3.5", "reason"]) do
e = assert_raises Gem::MissingSpecVersionError do
dep.to_specs
end

assert_match "Could not find 'bundler' (3.5) required by reason.\nTo update to the latest version installed on your system, run `bundle update --bundler`.\nTo install the missing version, run `gem install bundler:3.5`\n", e.message
Gem::BundlerVersionFinder.stub(:bundler_version_with_reason, ["1.16", "reason"]) do
assert_equal [b_1, b], dep.to_specs
end

Gem::BundlerVersionFinder.stub(:bundler_version_with_reason, ["2.0.0.pre.1", "reason"]) do
assert_equal [b], dep.to_specs
assert_equal [b, b_1], dep.to_specs
end
end

Expand Down
4 changes: 2 additions & 2 deletions test/rubygems/test_kernel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,10 @@ def test_gem_bundler_missing_bundler_version
quick_gem 'bundler', '1'
quick_gem 'bundler', '2.a'

e = assert_raises Gem::MissingSpecVersionError do
_, e = capture_io do
gem('bundler')
end
assert_match "Could not find 'bundler' (55) required by reason.", e.message
assert_match "Could not find 'bundler' (55) required by reason.", e
end
end

Expand Down
17 changes: 15 additions & 2 deletions test/rubygems/test_require.rb
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,19 @@ def test_default_gem_and_normal_gem
assert_equal %w(default-3.0), loaded_spec_names
end

def test_default_gem_prerelease
default_gem_spec = new_default_spec("default", "2.0.0",
nil, "default/gem.rb")
install_default_specs(default_gem_spec)

default_gem_prerelease_spec = new_default_spec("default", "3.0.0.rc2",
nil, "default/gem.rb")
install_default_specs(default_gem_prerelease_spec)

assert_require "default/gem"
assert_equal %w(default-3.0.0.rc2), loaded_spec_names
end

def loaded_spec_names
Gem.loaded_specs.values.map(&:full_name).sort
end
Expand Down Expand Up @@ -399,10 +412,10 @@ def test_require_bundler_missing_bundler_version
b2a = util_spec('bundler', '2.a', nil, "lib/bundler/setup.rb")
install_specs b1, b2a

e = assert_raises Gem::MissingSpecVersionError do
_, e = capture_io do
gem('bundler')
end
assert_match "Could not find 'bundler' (55) required by reason.", e.message
assert_match "Could not find 'bundler' (55) required by reason.", e
end
end

Expand Down