diff options
73 files changed, 601 insertions, 587 deletions
diff --git a/lib/bundler/cli/doctor.rb b/lib/bundler/cli/doctor.rb index 2986ddbc99..959b1b5e04 100644 --- a/lib/bundler/cli/doctor.rb +++ b/lib/bundler/cli/doctor.rb @@ -100,8 +100,11 @@ module Bundler files_not_readable_or_writable = [] files_not_rw_and_owned_by_different_user = [] files_not_owned_by_current_user_but_still_rw = [] + broken_symlinks = [] Find.find(Bundler.bundle_path.to_s).each do |f| - if !File.writable?(f) || !File.readable?(f) + if !File.exist?(f) + broken_symlinks << f + elsif !File.writable?(f) || !File.readable?(f) if File.stat(f).uid != Process.uid files_not_rw_and_owned_by_different_user << f else @@ -113,6 +116,13 @@ module Bundler end ok = true + + if broken_symlinks.any? + Bundler.ui.warn "Broken links exist in the Bundler home. Please report them to the offending gem's upstream repo. These files are:\n - #{broken_symlinks.join("\n - ")}" + + ok = false + end + if files_not_owned_by_current_user_but_still_rw.any? Bundler.ui.warn "Files exist in the Bundler home that are owned by another " \ "user, but are still readable/writable. These files are:\n - #{files_not_owned_by_current_user_but_still_rw.join("\n - ")}" diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb index 47c1da10e7..5e39e2a36d 100644 --- a/lib/bundler/cli/install.rb +++ b/lib/bundler/cli/install.rb @@ -104,7 +104,7 @@ module Bundler private def warn_if_root - return if Bundler.settings[:silence_root_warning] || Bundler::WINDOWS || !Process.uid.zero? + return if Bundler.settings[:silence_root_warning] || Gem.win_platform? || !Process.uid.zero? Bundler.ui.warn "Don't run Bundler as root. Bundler can ask for sudo " \ "if it is needed, and installing your bundle as root will break this " \ "application for all non-root users on this machine.", :wrap => true diff --git a/lib/bundler/cli/lock.rb b/lib/bundler/cli/lock.rb index 7dd078b1ef..7d613a6644 100644 --- a/lib/bundler/cli/lock.rb +++ b/lib/bundler/cli/lock.rb @@ -21,9 +21,13 @@ module Bundler Bundler::Fetcher.disable_endpoint = options["full-index"] update = options[:update] + conservative = options[:conservative] + if update.is_a?(Array) # unlocking specific gems Bundler::CLI::Common.ensure_all_gems_in_lockfile!(update) - update = { :gems => update, :lock_shared_dependencies => options[:conservative] } + update = { :gems => update, :conservative => conservative } + elsif update + update = { :conservative => conservative } if conservative end definition = Bundler.definition(update) diff --git a/lib/bundler/cli/update.rb b/lib/bundler/cli/update.rb index 94699484d4..cf6a5b26d3 100644 --- a/lib/bundler/cli/update.rb +++ b/lib/bundler/cli/update.rb @@ -27,9 +27,14 @@ module Bundler raise InvalidOption, "Cannot specify --all along with specific options." end + conservative = options[:conservative] + if full_update - # We're doing a full update - Bundler.definition(true) + if conservative + Bundler.definition(:conservative => conservative) + else + Bundler.definition(true) + end else unless Bundler.default_lockfile.exist? raise GemfileLockNotFound, "This Bundle hasn't been installed yet. " \ @@ -43,7 +48,7 @@ module Bundler end Bundler.definition(:gems => gems, :sources => sources, :ruby => options[:ruby], - :lock_shared_dependencies => options[:conservative], + :conservative => conservative, :bundler => options[:bundler]) end diff --git a/lib/bundler/current_ruby.rb b/lib/bundler/current_ruby.rb index b8c7cada1c..f84d68e262 100644 --- a/lib/bundler/current_ruby.rb +++ b/lib/bundler/current_ruby.rb @@ -65,19 +65,19 @@ module Bundler end def mswin? - Bundler::WINDOWS + Gem.win_platform? end def mswin64? - Bundler::WINDOWS && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mswin64" && Bundler.local_platform.cpu == "x64" + Gem.win_platform? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mswin64" && Bundler.local_platform.cpu == "x64" end def mingw? - Bundler::WINDOWS && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu != "x64" + Gem.win_platform? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu != "x64" end def x64_mingw? - Bundler::WINDOWS && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu == "x64" + Gem.win_platform? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu == "x64" end (KNOWN_MINOR_VERSIONS + KNOWN_MAJOR_VERSIONS).each do |version| diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 274b558c1b..e043b5c713 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -56,10 +56,8 @@ module Bundler @unlocking_bundler = false @unlocking = unlock else - unlock = unlock.dup @unlocking_bundler = unlock.delete(:bundler) - unlock.delete_if {|_k, v| Array(v).empty? } - @unlocking = !unlock.empty? + @unlocking = unlock.any? {|_k, v| !Array(v).empty? } end @dependencies = dependencies @@ -106,8 +104,8 @@ module Bundler @locked_platforms = [] end - @locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } - @multisource_allowed = @locked_gem_sources.any?(&:multiple_remotes?) && (sources.aggregate_global_source? || Bundler.frozen_bundle?) + locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } + @multisource_allowed = locked_gem_sources.size == 1 && locked_gem_sources.first.multiple_remotes? && Bundler.frozen_bundle? if @multisource_allowed unless sources.aggregate_global_source? @@ -116,10 +114,9 @@ module Bundler Bundler::SharedHelpers.major_deprecation 2, msg end - @sources.merged_gem_lockfile_sections! + @sources.merged_gem_lockfile_sections!(locked_gem_sources.first) end - @unlock[:gems] ||= [] @unlock[:sources] ||= [] @unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object @ruby_version.diff(locked_ruby_version_object) @@ -132,8 +129,10 @@ module Bundler @path_changes = converge_paths @source_changes = converge_sources - unless @unlock[:lock_shared_dependencies] - eager_unlock = expand_dependencies(@unlock[:gems], true) + if @unlock[:conservative] + @unlock[:gems] ||= @dependencies.map(&:name) + else + eager_unlock = expand_dependencies(@unlock[:gems] || [], true) @unlock[:gems] = @locked_specs.for(eager_unlock, [], false, false, false).map(&:name) end @@ -257,7 +256,7 @@ module Bundler def specs_for(groups) deps = dependencies_for(groups) - specs.for(expand_dependencies(deps)) + SpecSet.new(specs.for(expand_dependencies(deps))) end def dependencies_for(groups) @@ -498,9 +497,6 @@ module Bundler attr_reader :sources private :sources - attr_reader :locked_gem_sources - private :locked_gem_sources - def nothing_changed? !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@locked_specs_incomplete_for_platform end @@ -628,35 +624,11 @@ module Bundler end end - def converge_rubygems_sources - return false unless multisource_allowed? - - return false if locked_gem_sources.empty? - - # Get the RubyGems remotes from the Gemfile - actual_remotes = sources.rubygems_remotes - return false if actual_remotes.empty? - - changes = false - - # If there is a RubyGems source in both - locked_gem_sources.each do |locked_gem_source| - # Merge the remotes from the Gemfile into the Gemfile.lock - changes |= locked_gem_source.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes]) - end - - changes - end - def converge_sources - changes = false - - changes |= converge_rubygems_sources - # Replace the sources from the Gemfile with the sources from the Gemfile.lock, # if they exist in the Gemfile.lock and are `==`. If you can't find an equivalent # source in the Gemfile.lock, use the one from the Gemfile. - changes |= sources.replace_sources!(@locked_sources) + changes = sources.replace_sources!(@locked_sources) sources.all_sources.each do |source| # If the source is unlockable and the current command allows an unlock of @@ -741,8 +713,6 @@ module Bundler end end - unlock_source_unlocks_spec = Bundler.feature_flag.unlock_source_unlocks_spec? - converged = [] @locked_specs.each do |s| # Replace the locked dependency's source with the equivalent source from the Gemfile @@ -754,11 +724,6 @@ module Bundler next if s.source.nil? next if @unlock[:sources].include?(s.source.name) - # XXX This is a backwards-compatibility fix to preserve the ability to - # unlock a single gem by passing its name via `--source`. See issue #3759 - # TODO: delete in Bundler 2 - next if unlock_source_unlocks_spec && @unlock[:sources].include?(s.name) - # If the spec is from a path source and it doesn't exist anymore # then we unlock it. @@ -790,7 +755,7 @@ module Bundler resolve = SpecSet.new(converged) @locked_specs_incomplete_for_platform = !resolve.for(expand_dependencies(requested_dependencies & deps), @unlock[:gems], true, true) - resolve = resolve.for(expand_dependencies(deps, true), @unlock[:gems], false, false, false) + resolve = SpecSet.new(resolve.for(expand_dependencies(deps, true), [], false, false, false).reject{|s| @unlock[:gems].include?(s.name) }) diff = nil # Now, we unlock any sources that do not have anymore gems pinned to it @@ -912,14 +877,13 @@ module Bundler end def additional_base_requirements_for_resolve - return [] unless @locked_gems + return [] unless @locked_gems && unlocking? && !sources.expired_sources?(@locked_gems.sources) dependencies_by_name = dependencies.inject({}) {|memo, dep| memo.update(dep.name => dep) } @locked_gems.specs.reduce({}) do |requirements, locked_spec| name = locked_spec.name dependency = dependencies_by_name[name] - next requirements unless dependency next requirements if @locked_gems.dependencies[name] != dependency - next requirements if dependency.source.is_a?(Source::Path) + next requirements if dependency && dependency.source.is_a?(Source::Path) dep = Gem::Dependency.new(name, ">= #{locked_spec.version}") requirements[name] = DepProxy.get_proxy(dep, locked_spec.platform) requirements diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb index 313d1a9a41..dc72bf0d93 100644 --- a/lib/bundler/dsl.rb +++ b/lib/bundler/dsl.rb @@ -24,9 +24,6 @@ module Bundler def initialize @source = nil @sources = SourceList.new - - @global_rubygems_sources = [] - @git_sources = {} @dependencies = [] @groups = [] @@ -48,7 +45,6 @@ module Bundler @gemfiles << expanded_gemfile_path contents ||= Bundler.read_file(@gemfile.to_s) instance_eval(contents.dup.tap{|x| x.untaint if RUBY_VERSION < "2.7" }, gemfile.to_s, 1) - check_primary_source_safety rescue Exception => e # rubocop:disable Lint/RescueException message = "There was an error " \ "#{e.is_a?(GemfileEvalError) ? "evaluating" : "parsing"} " \ @@ -168,7 +164,7 @@ module Bundler elsif block_given? with_source(@sources.add_rubygems_source("remotes" => source), &blk) else - @global_rubygems_sources << source + @sources.add_global_rubygems_remote(source) end end @@ -222,6 +218,7 @@ module Bundler end def to_definition(lockfile, unlock) + check_primary_source_safety Definition.new(lockfile, @dependencies, @sources, unlock, @ruby_version, @optional_groups, @gemfiles) end @@ -453,12 +450,7 @@ repo_name ||= user_name end def check_rubygems_source_safety - @sources.global_rubygems_source = @global_rubygems_sources.shift - return if @global_rubygems_sources.empty? - - @global_rubygems_sources.each do |source| - @sources.add_rubygems_remote(source) - end + return unless @sources.aggregate_global_source? if Bundler.feature_flag.bundler_3_mode? msg = "This Gemfile contains multiple primary sources. " \ diff --git a/lib/bundler/feature_flag.rb b/lib/bundler/feature_flag.rb index aee127ba80..e441b941c2 100644 --- a/lib/bundler/feature_flag.rb +++ b/lib/bundler/feature_flag.rb @@ -38,7 +38,6 @@ module Bundler settings_flag(:print_only_version_number) { bundler_3_mode? } settings_flag(:setup_makes_kernel_gem_public) { !bundler_3_mode? } settings_flag(:suppress_install_using_messages) { bundler_3_mode? } - settings_flag(:unlock_source_unlocks_spec) { !bundler_3_mode? } settings_flag(:update_requires_all_flag) { bundler_4_mode? } settings_flag(:use_gem_version_promoter_for_major_updates) { bundler_3_mode? } diff --git a/lib/bundler/fetcher/downloader.rb b/lib/bundler/fetcher/downloader.rb index 5d30333158..f2aad3a500 100644 --- a/lib/bundler/fetcher/downloader.rb +++ b/lib/bundler/fetcher/downloader.rb @@ -68,8 +68,7 @@ module Bundler raise CertificateFailureError.new(uri) rescue *HTTP_ERRORS => e Bundler.ui.trace e - case e.message - when /host down:/, /getaddrinfo: nodename nor servname provided/ + if e.is_a?(SocketError) || e.message =~ /host down:/ raise NetworkDownError, "Could not reach host #{uri.host}. Check your network " \ "connection and try again." else diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb index a88fb91cb5..2624ac4b18 100644 --- a/lib/bundler/installer.rb +++ b/lib/bundler/installer.rb @@ -135,7 +135,7 @@ module Bundler next end - mode = Bundler::WINDOWS ? "wb:UTF-8" : "w" + mode = Gem.win_platform? ? "wb:UTF-8" : "w" require "erb" content = if RUBY_VERSION >= "2.6" ERB.new(template, :trim_mode => "-").result(binding) @@ -144,7 +144,7 @@ module Bundler end File.write(binstub_path, content, :mode => mode, :perm => 0o777 & ~File.umask) - if Bundler::WINDOWS || options[:all_platforms] + if Gem.win_platform? || options[:all_platforms] prefix = "@ruby -x \"%~f0\" %*\n@exit /b %ERRORLEVEL%\n\n" File.write("#{binstub_path}.cmd", prefix + content, :mode => mode) end @@ -182,7 +182,7 @@ module Bundler executable_path = Pathname(spec.full_gem_path).join(spec.bindir, executable).relative_path_from(bin_path) executable_path = executable_path - mode = Bundler::WINDOWS ? "wb:UTF-8" : "w" + mode = Gem.win_platform? ? "wb:UTF-8" : "w" require "erb" content = if RUBY_VERSION >= "2.6" ERB.new(template, :trim_mode => "-").result(binding) @@ -191,7 +191,7 @@ module Bundler end File.write("#{bin_path}/#{executable}", content, :mode => mode, :perm => 0o755) - if Bundler::WINDOWS || options[:all_platforms] + if Gem.win_platform? || options[:all_platforms] prefix = "@ruby -x \"%~f0\" %*\n@exit /b %ERRORLEVEL%\n\n" File.write("#{bin_path}/#{executable}.cmd", prefix + content, :mode => mode) end diff --git a/lib/bundler/lockfile_parser.rb b/lib/bundler/lockfile_parser.rb index f87faff70c..afc21fd006 100644 --- a/lib/bundler/lockfile_parser.rb +++ b/lib/bundler/lockfile_parser.rb @@ -1,16 +1,5 @@ # frozen_string_literal: true -#-- -# Some versions of the Bundler 1.1 RC series introduced corrupted -# lockfiles. There were two major problems: -# -# * multiple copies of the same GIT section appeared in the lockfile -# * when this happened, those sections got multiple copies of gems -# in those sections. -# -# As a result, Bundler 1.1 contains code that fixes the earlier -# corruption. We will remove this fix-up code in Bundler 1.2. - module Bundler class LockfileParser attr_reader :sources, :dependencies, :specs, :platforms, :bundler_version, :ruby_version @@ -124,12 +113,7 @@ module Bundler @sources << @current_source when GIT @current_source = TYPES[@type].from_lock(@opts) - # Strip out duplicate GIT sections - if @sources.include?(@current_source) - @current_source = @sources.find {|s| s == @current_source } - else - @sources << @current_source - end + @sources << @current_source when GEM @opts["remotes"] = Array(@opts.delete("remote")).reverse @current_source = TYPES[@type].from_lock(@opts) @@ -212,9 +196,7 @@ module Bundler @current_spec = LazySpecification.new(name, version, platform) @current_spec.source = @current_source - # Avoid introducing multiple copies of the same spec (caused by - # duplicate GIT sections) - @specs[@current_spec.identifier] ||= @current_spec + @specs[@current_spec.identifier] = @current_spec elsif spaces.size == 6 version = version.split(",").map(&:strip) if version dep = Gem::Dependency.new(name, version) diff --git a/lib/bundler/man/bundle-add.1 b/lib/bundler/man/bundle-add.1 index a8d3420d59..4945747f42 100644 --- a/lib/bundler/man/bundle-add.1 +++ b/lib/bundler/man/bundle-add.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-ADD" "1" "May 2021" "" "" +.TH "BUNDLE\-ADD" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install diff --git a/lib/bundler/man/bundle-binstubs.1 b/lib/bundler/man/bundle-binstubs.1 index 3493770304..dd43180b19 100644 --- a/lib/bundler/man/bundle-binstubs.1 +++ b/lib/bundler/man/bundle-binstubs.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-BINSTUBS" "1" "May 2021" "" "" +.TH "BUNDLE\-BINSTUBS" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-binstubs\fR \- Install the binstubs of the listed gems diff --git a/lib/bundler/man/bundle-cache.1 b/lib/bundler/man/bundle-cache.1 index 7bfbaa6a4e..22ce1dfc76 100644 --- a/lib/bundler/man/bundle-cache.1 +++ b/lib/bundler/man/bundle-cache.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CACHE" "1" "May 2021" "" "" +.TH "BUNDLE\-CACHE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application diff --git a/lib/bundler/man/bundle-check.1 b/lib/bundler/man/bundle-check.1 index bae888df27..6e1b38ab05 100644 --- a/lib/bundler/man/bundle-check.1 +++ b/lib/bundler/man/bundle-check.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CHECK" "1" "May 2021" "" "" +.TH "BUNDLE\-CHECK" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems diff --git a/lib/bundler/man/bundle-clean.1 b/lib/bundler/man/bundle-clean.1 index 2e2bb615c4..eb658e1c73 100644 --- a/lib/bundler/man/bundle-clean.1 +++ b/lib/bundler/man/bundle-clean.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CLEAN" "1" "May 2021" "" "" +.TH "BUNDLE\-CLEAN" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1 index 26e9418c0c..ffd9d27cb4 100644 --- a/lib/bundler/man/bundle-config.1 +++ b/lib/bundler/man/bundle-config.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CONFIG" "1" "May 2021" "" "" +.TH "BUNDLE\-CONFIG" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-config\fR \- Set bundler configuration options @@ -274,9 +274,6 @@ The following is a list of all configuration keys and their purpose\. You can le \fBtimeout\fR (\fBBUNDLE_TIMEOUT\fR): The seconds allowed before timing out for network requests\. Defaults to \fB10\fR\. . .IP "\(bu" 4 -\fBunlock_source_unlocks_spec\fR (\fBBUNDLE_UNLOCK_SOURCE_UNLOCKS_SPEC\fR): Whether running \fBbundle update \-\-source NAME\fR unlocks a gem with the given name\. Defaults to \fBtrue\fR\. -. -.IP "\(bu" 4 \fBupdate_requires_all_flag\fR (\fBBUNDLE_UPDATE_REQUIRES_ALL_FLAG\fR): Require passing \fB\-\-all\fR to \fBbundle update\fR when everything should be updated, and disallow passing no options to \fBbundle update\fR\. . .IP "\(bu" 4 diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn index cffd87a160..2e47774497 100644 --- a/lib/bundler/man/bundle-config.1.ronn +++ b/lib/bundler/man/bundle-config.1.ronn @@ -260,9 +260,6 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). The location where RubyGems installs binstubs. Defaults to `Gem.bindir`. * `timeout` (`BUNDLE_TIMEOUT`): The seconds allowed before timing out for network requests. Defaults to `10`. -* `unlock_source_unlocks_spec` (`BUNDLE_UNLOCK_SOURCE_UNLOCKS_SPEC`): - Whether running `bundle update --source NAME` unlocks a gem with the given - name. Defaults to `true`. * `update_requires_all_flag` (`BUNDLE_UPDATE_REQUIRES_ALL_FLAG`): Require passing `--all` to `bundle update` when everything should be updated, and disallow passing no options to `bundle update`. diff --git a/lib/bundler/man/bundle-doctor.1 b/lib/bundler/man/bundle-doctor.1 index 0c8ff27d3e..84d1f4c9df 100644 --- a/lib/bundler/man/bundle-doctor.1 +++ b/lib/bundler/man/bundle-doctor.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-DOCTOR" "1" "May 2021" "" "" +.TH "BUNDLE\-DOCTOR" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-doctor\fR \- Checks the bundle for common problems diff --git a/lib/bundler/man/bundle-exec.1 b/lib/bundler/man/bundle-exec.1 index c8d51cd4a2..b3c60fbbfd 100644 --- a/lib/bundler/man/bundle-exec.1 +++ b/lib/bundler/man/bundle-exec.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-EXEC" "1" "May 2021" "" "" +.TH "BUNDLE\-EXEC" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-exec\fR \- Execute a command in the context of the bundle diff --git a/lib/bundler/man/bundle-gem.1 b/lib/bundler/man/bundle-gem.1 index 4b7e5a088c..617454e503 100644 --- a/lib/bundler/man/bundle-gem.1 +++ b/lib/bundler/man/bundle-gem.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-GEM" "1" "May 2021" "" "" +.TH "BUNDLE\-GEM" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem diff --git a/lib/bundler/man/bundle-info.1 b/lib/bundler/man/bundle-info.1 index 4039ec9c94..337e7bdd38 100644 --- a/lib/bundler/man/bundle-info.1 +++ b/lib/bundler/man/bundle-info.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INFO" "1" "May 2021" "" "" +.TH "BUNDLE\-INFO" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-info\fR \- Show information for the given gem in your bundle diff --git a/lib/bundler/man/bundle-init.1 b/lib/bundler/man/bundle-init.1 index f538b06bf6..0c5b8c7a39 100644 --- a/lib/bundler/man/bundle-init.1 +++ b/lib/bundler/man/bundle-init.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INIT" "1" "May 2021" "" "" +.TH "BUNDLE\-INIT" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-init\fR \- Generates a Gemfile into the current working directory diff --git a/lib/bundler/man/bundle-inject.1 b/lib/bundler/man/bundle-inject.1 index 85549b4585..f228ed247f 100644 --- a/lib/bundler/man/bundle-inject.1 +++ b/lib/bundler/man/bundle-inject.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INJECT" "1" "May 2021" "" "" +.TH "BUNDLE\-INJECT" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile diff --git a/lib/bundler/man/bundle-install.1 b/lib/bundler/man/bundle-install.1 index 867a41d70d..ae9747bd83 100644 --- a/lib/bundler/man/bundle-install.1 +++ b/lib/bundler/man/bundle-install.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INSTALL" "1" "May 2021" "" "" +.TH "BUNDLE\-INSTALL" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-install\fR \- Install the dependencies specified in your Gemfile diff --git a/lib/bundler/man/bundle-list.1 b/lib/bundler/man/bundle-list.1 index 0b67785a21..cce8881059 100644 --- a/lib/bundler/man/bundle-list.1 +++ b/lib/bundler/man/bundle-list.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-LIST" "1" "May 2021" "" "" +.TH "BUNDLE\-LIST" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-list\fR \- List all the gems in the bundle diff --git a/lib/bundler/man/bundle-lock.1 b/lib/bundler/man/bundle-lock.1 index 860a2e07ef..23388daaee 100644 --- a/lib/bundler/man/bundle-lock.1 +++ b/lib/bundler/man/bundle-lock.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-LOCK" "1" "May 2021" "" "" +.TH "BUNDLE\-LOCK" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-lock\fR \- Creates / Updates a lockfile without installing diff --git a/lib/bundler/man/bundle-open.1 b/lib/bundler/man/bundle-open.1 index b907e2d544..8cc104b81d 100644 --- a/lib/bundler/man/bundle-open.1 +++ b/lib/bundler/man/bundle-open.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-OPEN" "1" "May 2021" "" "" +.TH "BUNDLE\-OPEN" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-open\fR \- Opens the source directory for a gem in your bundle diff --git a/lib/bundler/man/bundle-outdated.1 b/lib/bundler/man/bundle-outdated.1 index 5427a2ab77..bdd81a66af 100644 --- a/lib/bundler/man/bundle-outdated.1 +++ b/lib/bundler/man/bundle-outdated.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-OUTDATED" "1" "May 2021" "" "" +.TH "BUNDLE\-OUTDATED" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-outdated\fR \- List installed gems with newer versions available diff --git a/lib/bundler/man/bundle-platform.1 b/lib/bundler/man/bundle-platform.1 index 2a80abb8d6..dab5269c04 100644 --- a/lib/bundler/man/bundle-platform.1 +++ b/lib/bundler/man/bundle-platform.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-PLATFORM" "1" "May 2021" "" "" +.TH "BUNDLE\-PLATFORM" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-platform\fR \- Displays platform compatibility information diff --git a/lib/bundler/man/bundle-pristine.1 b/lib/bundler/man/bundle-pristine.1 index 7fff665de0..e5b0dab334 100644 --- a/lib/bundler/man/bundle-pristine.1 +++ b/lib/bundler/man/bundle-pristine.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-PRISTINE" "1" "May 2021" "" "" +.TH "BUNDLE\-PRISTINE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-pristine\fR \- Restores installed gems to their pristine condition diff --git a/lib/bundler/man/bundle-remove.1 b/lib/bundler/man/bundle-remove.1 index 17de5ed5a9..8af691283d 100644 --- a/lib/bundler/man/bundle-remove.1 +++ b/lib/bundler/man/bundle-remove.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-REMOVE" "1" "May 2021" "" "" +.TH "BUNDLE\-REMOVE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-remove\fR \- Removes gems from the Gemfile diff --git a/lib/bundler/man/bundle-show.1 b/lib/bundler/man/bundle-show.1 index fbbe18741f..c08c7205aa 100644 --- a/lib/bundler/man/bundle-show.1 +++ b/lib/bundler/man/bundle-show.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-SHOW" "1" "May 2021" "" "" +.TH "BUNDLE\-SHOW" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem diff --git a/lib/bundler/man/bundle-update.1 b/lib/bundler/man/bundle-update.1 index 3c9af3dcc1..7da2ce3438 100644 --- a/lib/bundler/man/bundle-update.1 +++ b/lib/bundler/man/bundle-update.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-UPDATE" "1" "May 2021" "" "" +.TH "BUNDLE\-UPDATE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-update\fR \- Update your gems to the latest available versions @@ -79,7 +79,7 @@ Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR . .TP \fB\-\-conservative\fR -Use bundle install conservative update behavior and do not allow shared dependencies to be updated\. +Use bundle install conservative update behavior and do not allow indirect dependencies to be updated\. . .SH "UPDATING ALL GEMS" If you run \fBbundle update \-\-all\fR, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources\. @@ -208,13 +208,13 @@ In this case, the two gems have their own set of dependencies, but they share \f In short, by default, when you update a gem using \fBbundle update\fR, bundler will update all dependencies of that gem, including those that are also dependencies of another gem\. . .P -To prevent updating shared dependencies, prior to version 1\.14 the only option was the \fBCONSERVATIVE UPDATING\fR behavior in bundle install(1) \fIbundle\-install\.1\.html\fR: +To prevent updating indirect dependencies, prior to version 1\.14 the only option was the \fBCONSERVATIVE UPDATING\fR behavior in bundle install(1) \fIbundle\-install\.1\.html\fR: . .P In this scenario, updating the \fBthin\fR version manually in the Gemfile(5), and then running bundle install(1) \fIbundle\-install\.1\.html\fR will only update \fBdaemons\fR and \fBeventmachine\fR, but not \fBrack\fR\. For more information, see the \fBCONSERVATIVE UPDATING\fR section of bundle install(1) \fIbundle\-install\.1\.html\fR\. . .P -Starting with 1\.14, specifying the \fB\-\-conservative\fR option will also prevent shared dependencies from being updated\. +Starting with 1\.14, specifying the \fB\-\-conservative\fR option will also prevent indirect dependencies from being updated\. . .SH "PATCH LEVEL OPTIONS" Version 1\.14 introduced 4 patch\-level options that will influence how gem versions are resolved\. One of the following options can be used: \fB\-\-patch\fR, \fB\-\-minor\fR or \fB\-\-major\fR\. \fB\-\-strict\fR can be added to further influence resolution\. diff --git a/lib/bundler/man/bundle-update.1.ronn b/lib/bundler/man/bundle-update.1.ronn index 397fecadcb..3a16f29149 100644 --- a/lib/bundler/man/bundle-update.1.ronn +++ b/lib/bundler/man/bundle-update.1.ronn @@ -80,7 +80,7 @@ gem. Do not allow any gem to be updated past latest `--patch` | `--minor` | `--major`. * `--conservative`: - Use bundle install conservative update behavior and do not allow shared dependencies to be updated. + Use bundle install conservative update behavior and do not allow indirect dependencies to be updated. ## UPDATING ALL GEMS @@ -195,7 +195,7 @@ In short, by default, when you update a gem using `bundle update`, bundler will update all dependencies of that gem, including those that are also dependencies of another gem. -To prevent updating shared dependencies, prior to version 1.14 the only option +To prevent updating indirect dependencies, prior to version 1.14 the only option was the `CONSERVATIVE UPDATING` behavior in [bundle install(1)](bundle-install.1.html): In this scenario, updating the `thin` version manually in the Gemfile(5), @@ -203,7 +203,7 @@ and then running [bundle install(1)](bundle-install.1.html) will only update `da but not `rack`. For more information, see the `CONSERVATIVE UPDATING` section of [bundle install(1)](bundle-install.1.html). -Starting with 1.14, specifying the `--conservative` option will also prevent shared +Starting with 1.14, specifying the `--conservative` option will also prevent indirect dependencies from being updated. ## PATCH LEVEL OPTIONS diff --git a/lib/bundler/man/bundle-viz.1 b/lib/bundler/man/bundle-viz.1 index fbc48aa902..9683f0678b 100644 --- a/lib/bundler/man/bundle-viz.1 +++ b/lib/bundler/man/bundle-viz.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-VIZ" "1" "May 2021" "" "" +.TH "BUNDLE\-VIZ" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile diff --git a/lib/bundler/man/bundle.1 b/lib/bundler/man/bundle.1 index 5b6c9afe78..b741f7cf6a 100644 --- a/lib/bundler/man/bundle.1 +++ b/lib/bundler/man/bundle.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE" "1" "May 2021" "" "" +.TH "BUNDLE" "1" "June 2021" "" "" . .SH "NAME" \fBbundle\fR \- Ruby Dependency Management diff --git a/lib/bundler/man/gemfile.5 b/lib/bundler/man/gemfile.5 index 2497fad234..af714c1718 100644 --- a/lib/bundler/man/gemfile.5 +++ b/lib/bundler/man/gemfile.5 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "GEMFILE" "5" "May 2021" "" "" +.TH "GEMFILE" "5" "June 2021" "" "" . .SH "NAME" \fBGemfile\fR \- A format for describing gem dependencies for Ruby programs diff --git a/lib/bundler/plugin/installer.rb b/lib/bundler/plugin/installer.rb index 980b0e29b8..4cb7ddf5d6 100644 --- a/lib/bundler/plugin/installer.rb +++ b/lib/bundler/plugin/installer.rb @@ -77,7 +77,7 @@ module Bundler source_list = SourceList.new source_list.add_git_source(git_source_options) if git_source_options - source_list.global_rubygems_source = rubygems_source if rubygems_source + source_list.add_global_rubygems_remote(rubygems_source) if rubygems_source deps = names.map {|name| Dependency.new name, version } diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index fac5070619..a78b2db157 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -21,7 +21,7 @@ module Bundler base = SpecSet.new(base) unless base.is_a?(SpecSet) resolver = new(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) result = resolver.start(requirements) - SpecSet.new(result).for(requirements.reject{|dep| dep.name.end_with?("\0") }) + SpecSet.new(SpecSet.new(result).for(requirements.reject{|dep| dep.name.end_with?("\0") })) end def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index 13fcb447d0..95da31a765 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -44,7 +44,6 @@ module Bundler silence_deprecations silence_root_warning suppress_install_using_messages - unlock_source_unlocks_spec update_requires_all_flag use_gem_version_promoter_for_major_updates ].freeze diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index 0e9b4e02a5..43b193cf1c 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -73,7 +73,7 @@ module Bundler def can_lock?(spec) return super unless multiple_remotes? - spec.source.is_a?(Rubygems) + include?(spec.source) end def options @@ -252,19 +252,6 @@ module Bundler other_remotes.map(&method(:remove_auth)) == @remotes.map(&method(:remove_auth)) end - def replace_remotes(other_remotes, allow_equivalent = false) - return false if other_remotes == @remotes - - equivalent = allow_equivalent && equivalent_remotes?(other_remotes) - - @remotes = [] - other_remotes.reverse_each do |r| - add_remote r.to_s - end - - !equivalent - end - def spec_names if @allow_remote && dependency_api_available? remote_specs.spec_names diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb index 9a7f0ea0a2..113d49ba72 100644 --- a/lib/bundler/source_list.rb +++ b/lib/bundler/source_list.rb @@ -28,8 +28,9 @@ module Bundler @merged_gem_lockfile_sections end - def merged_gem_lockfile_sections! + def merged_gem_lockfile_sections!(replacement_source) @merged_gem_lockfile_sections = true + @global_rubygems_source = replacement_source end def aggregate_global_source? @@ -53,18 +54,17 @@ module Bundler end def add_rubygems_source(options = {}) - add_source_to_list Source::Rubygems.new(options), @rubygems_sources + new_source = Source::Rubygems.new(options) + return @global_rubygems_source if @global_rubygems_source == new_source + + add_source_to_list new_source, @rubygems_sources end def add_plugin_source(source, options = {}) add_source_to_list Plugin.source(source).new(options), @plugin_sources end - def global_rubygems_source=(uri) - @global_rubygems_source ||= rubygems_aggregate_class.new("remotes" => uri, "allow_local" => true) - end - - def add_rubygems_remote(uri) + def add_global_rubygems_remote(uri) global_rubygems_source.add_remote(uri) global_rubygems_source end @@ -109,27 +109,26 @@ module Bundler if merged_gem_lockfile_sections? [combine_rubygems_sources] else - rubygems_sources.sort_by(&:to_s).uniq + rubygems_sources.sort_by(&:to_s) end end # Returns true if there are changes def replace_sources!(replacement_sources) - return true if replacement_sources.empty? + return false if replacement_sources.empty? - [path_sources, git_sources, plugin_sources].each do |source_list| - source_list.map! do |source| - replacement_sources.find {|s| s == source } || source - end - end + @path_sources, @git_sources, @plugin_sources = map_sources(replacement_sources) + + different_sources?(lock_sources, replacement_sources) + end - replacement_rubygems = merged_gem_lockfile_sections? && - replacement_sources.detect {|s| s.is_a?(Source::Rubygems) } - @global_rubygems_source = replacement_rubygems if replacement_rubygems + # Returns true if there are changes + def expired_sources?(replacement_sources) + return false if replacement_sources.empty? - return true if !equal_sources?(lock_sources, replacement_sources) && !equivalent_sources?(lock_sources, replacement_sources) + lock_sources = dup_with_replaced_sources(replacement_sources).lock_sources - false + different_sources?(lock_sources, replacement_sources) end def local_only! @@ -146,6 +145,24 @@ module Bundler private + def dup_with_replaced_sources(replacement_sources) + new_source_list = dup + new_source_list.replace_sources!(replacement_sources) + new_source_list + end + + def map_sources(replacement_sources) + [path_sources, git_sources, plugin_sources].map do |sources| + sources.map do |source| + replacement_sources.find {|s| s == source } || source + end + end + end + + def different_sources?(lock_sources, replacement_sources) + !equal_sources?(lock_sources, replacement_sources) && !equivalent_sources?(lock_sources, replacement_sources) + end + def rubygems_aggregate_class Source::Rubygems end diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index 67669cdd0e..af16984454 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -46,11 +46,7 @@ module Bundler specs << spec end - check ? true : SpecSet.new(specs) - end - - def valid_for?(deps) - self.for(deps, [], true) + check ? true : specs end def [](key) @@ -77,7 +73,7 @@ module Bundler end def materialize(deps, missing_specs = nil) - materialized = self.for(deps, [], false, true, !missing_specs).to_a + materialized = self.for(deps, [], false, true, !missing_specs) materialized.group_by(&:source).each do |source, specs| next unless specs.any?{|s| s.is_a?(LazySpecification) } diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb index 1c34797243..2d491e5314 100644 --- a/lib/bundler/version.rb +++ b/lib/bundler/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false module Bundler - VERSION = "2.2.21".freeze + VERSION = "2.2.22".freeze def self.bundler_major_version @bundler_major_version ||= VERSION.split(".").first.to_i diff --git a/lib/rubygems.rb b/lib/rubygems.rb index 9d16f6ecf8..cb03a9e000 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -8,7 +8,7 @@ require 'rbconfig' module Gem - VERSION = "3.2.21".freeze + VERSION = "3.2.22".freeze end # Must be first since it unloads the prelude from 1.9.2 diff --git a/lib/rubygems/commands/cert_command.rb b/lib/rubygems/commands/cert_command.rb index 998df0621b..3fc0daea7d 100644 --- a/lib/rubygems/commands/cert_command.rb +++ b/lib/rubygems/commands/cert_command.rb @@ -7,37 +7,9 @@ class Gem::Commands::CertCommand < Gem::Command super 'cert', 'Manage RubyGems certificates and signing settings', :add => [], :remove => [], :list => [], :build => [], :sign => [] - OptionParser.accept OpenSSL::X509::Certificate do |certificate_file| - begin - certificate = OpenSSL::X509::Certificate.new File.read certificate_file - rescue Errno::ENOENT - raise OptionParser::InvalidArgument, "#{certificate_file}: does not exist" - rescue OpenSSL::X509::CertificateError - raise OptionParser::InvalidArgument, - "#{certificate_file}: invalid X509 certificate" - end - [certificate, certificate_file] - end - - OptionParser.accept OpenSSL::PKey::RSA do |key_file| - begin - passphrase = ENV['GEM_PRIVATE_KEY_PASSPHRASE'] - key = OpenSSL::PKey::RSA.new File.read(key_file), passphrase - rescue Errno::ENOENT - raise OptionParser::InvalidArgument, "#{key_file}: does not exist" - rescue OpenSSL::PKey::RSAError - raise OptionParser::InvalidArgument, "#{key_file}: invalid RSA key" - end - - raise OptionParser::InvalidArgument, - "#{key_file}: private key not found" unless key.private? - - key - end - - add_option('-a', '--add CERT', OpenSSL::X509::Certificate, - 'Add a trusted certificate.') do |(cert, _), options| - options[:add] << cert + add_option('-a', '--add CERT', + 'Add a trusted certificate.') do |cert_file, options| + options[:add] << open_cert(cert_file) end add_option('-l', '--list [FILTER]', @@ -60,15 +32,15 @@ class Gem::Commands::CertCommand < Gem::Command options[:build] << email_address end - add_option('-C', '--certificate CERT', OpenSSL::X509::Certificate, - 'Signing certificate for --sign') do |(cert, cert_file), options| - options[:issuer_cert] = cert + add_option('-C', '--certificate CERT', + 'Signing certificate for --sign') do |cert_file, options| + options[:issuer_cert] = open_cert(cert_file) options[:issuer_cert_file] = cert_file end - add_option('-K', '--private-key KEY', OpenSSL::PKey::RSA, - 'Key for --sign or --build') do |key, options| - options[:key] = key + add_option('-K', '--private-key KEY', + 'Key for --sign or --build') do |key_file, options| + options[:key] = open_private_key(key_file) end add_option('-s', '--sign CERT', @@ -97,7 +69,39 @@ class Gem::Commands::CertCommand < Gem::Command say "Added '#{certificate.subject}'" end + def check_openssl + return if Gem::HAVE_OPENSSL + + alert_error "OpenSSL library is required for the cert command" + terminate_interaction 1 + end + + def open_cert(certificate_file) + check_openssl + OpenSSL::X509::Certificate.new File.read certificate_file + rescue Errno::ENOENT + raise OptionParser::InvalidArgument, "#{certificate_file}: does not exist" + rescue OpenSSL::X509::CertificateError + raise OptionParser::InvalidArgument, + "#{certificate_file}: invalid X509 certificate" + end + + def open_private_key(key_file) + check_openssl + passphrase = ENV['GEM_PRIVATE_KEY_PASSPHRASE'] + key = OpenSSL::PKey::RSA.new File.read(key_file), passphrase + raise OptionParser::InvalidArgument, + "#{key_file}: private key not found" unless key.private? + key + rescue Errno::ENOENT + raise OptionParser::InvalidArgument, "#{key_file}: does not exist" + rescue OpenSSL::PKey::RSAError + raise OptionParser::InvalidArgument, "#{key_file}: invalid RSA key" + end + def execute + check_openssl + options[:add].each do |certificate| add_certificate certificate end @@ -311,4 +315,4 @@ For further reading on signing gems see `ri Gem::Security`. # It's simple, but is all we need email =~ /\A.+@.+\z/ end -end if Gem::HAVE_OPENSSL +end diff --git a/lib/rubygems/gemcutter_utilities.rb b/lib/rubygems/gemcutter_utilities.rb index 3687e776e2..00e68916c4 100644 --- a/lib/rubygems/gemcutter_utilities.rb +++ b/lib/rubygems/gemcutter_utilities.rb @@ -52,6 +52,13 @@ module Gem::GemcutterUtilities end ## + # The OTP code from the command options or from the user's configuration. + + def otp + options[:otp] || ENV["GEM_HOST_OTP_CODE"] + end + + ## # The host to connect to either from the RUBYGEMS_HOST environment variable # or from the user's configuration @@ -126,7 +133,7 @@ module Gem::GemcutterUtilities response = rubygems_api_request(:put, "api/v1/api_key", sign_in_host, scope: scope) do |request| request.basic_auth email, password - request["OTP"] = options[:otp] if options[:otp] + request["OTP"] = otp if otp request.body = URI.encode_www_form({:api_key => api_key }.merge(update_scope_params)) end @@ -159,7 +166,7 @@ module Gem::GemcutterUtilities response = rubygems_api_request(:post, "api/v1/api_key", sign_in_host, scope: scope) do |request| request.basic_auth email, password - request["OTP"] = options[:otp] if options[:otp] + request["OTP"] = otp if otp request.body = URI.encode_www_form({ name: key_name }.merge(scope_params)) end @@ -224,7 +231,7 @@ module Gem::GemcutterUtilities request_method = Net::HTTP.const_get method.to_s.capitalize Gem::RemoteFetcher.fetcher.request(uri, request_method) do |req| - req["OTP"] = options[:otp] if options[:otp] + req["OTP"] = otp if otp block.call(req) end end diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index 7206c3eaf0..23a37e966b 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -2421,7 +2421,6 @@ class Gem::Specification < Gem::BasicSpecification # still have their default values are omitted. def to_ruby - require_relative 'openssl' mark_version result = [] result << "# -*- encoding: utf-8 -*-" @@ -2455,16 +2454,21 @@ class Gem::Specification < Gem::BasicSpecification :has_rdoc, :default_executable, :metadata, + :signing_key, ] @@attributes.each do |attr_name| next if handled.include? attr_name current_value = self.send(attr_name) if current_value != default_value(attr_name) || self.class.required_attribute?(attr_name) - result << " s.#{attr_name} = #{ruby_code current_value}" unless defined?(OpenSSL::PKey::RSA) && current_value.is_a?(OpenSSL::PKey::RSA) + result << " s.#{attr_name} = #{ruby_code current_value}" end end + if String === signing_key + result << " s.signing_key = #{signing_key.dump}.freeze" + end + if @installed_by_version result << nil result << " s.installed_by_version = \"#{Gem::VERSION}\" if s.respond_to? :installed_by_version" diff --git a/spec/bundler/bundler/cli_spec.rb b/spec/bundler/bundler/cli_spec.rb index e49066f7dc..cc8949d27d 100644 --- a/spec/bundler/bundler/cli_spec.rb +++ b/spec/bundler/bundler/cli_spec.rb @@ -2,16 +2,6 @@ require "bundler/cli" -using Module.new { - # Some `man` (e.g., on macOS) always highlights the output even to - # non-tty. - refine Spec::Helpers do - def out - super.gsub(/.[\b]/, "") - end - end -} if RUBY_VERSION >= "2.4" - RSpec.describe "bundle executable" do it "returns non-zero exit status when passed unrecognized options" do bundle "--invalid_argument", :raise_on_error => false @@ -42,49 +32,57 @@ RSpec.describe "bundle executable" do it "aliases e to exec" do bundle "e --help" - expect(out).to include("bundle-exec") + expect(out_with_macos_man_workaround).to include("bundle-exec") end it "aliases ex to exec" do bundle "ex --help" - expect(out).to include("bundle-exec") + expect(out_with_macos_man_workaround).to include("bundle-exec") end it "aliases exe to exec" do bundle "exe --help" - expect(out).to include("bundle-exec") + expect(out_with_macos_man_workaround).to include("bundle-exec") end it "aliases c to check" do bundle "c --help" - expect(out).to include("bundle-check") + expect(out_with_macos_man_workaround).to include("bundle-check") end it "aliases i to install" do bundle "i --help" - expect(out).to include("bundle-install") + expect(out_with_macos_man_workaround).to include("bundle-install") end it "aliases ls to list" do bundle "ls --help" - expect(out).to include("bundle-list") + expect(out_with_macos_man_workaround).to include("bundle-list") end it "aliases package to cache" do bundle "package --help" - expect(out).to include("bundle-cache") + expect(out_with_macos_man_workaround).to include("bundle-cache") end it "aliases pack to cache" do bundle "pack --help" - expect(out).to include("bundle-cache") + expect(out_with_macos_man_workaround).to include("bundle-cache") + end + + private + + # Some `man` (e.g., on macOS) always highlights the output even to + # non-tty. + def out_with_macos_man_workaround + out.gsub(/.[\b]/, "") end end diff --git a/spec/bundler/bundler/definition_spec.rb b/spec/bundler/bundler/definition_spec.rb index 67a1536541..86d3359087 100644 --- a/spec/bundler/bundler/definition_spec.rb +++ b/spec/bundler/bundler/definition_spec.rb @@ -194,7 +194,7 @@ RSpec.describe Bundler::Definition do context "eager unlock" do let(:source_list) do Bundler::SourceList.new.tap do |source_list| - source_list.global_rubygems_source = file_uri_for(gem_repo4) + source_list.add_global_rubygems_remote(file_uri_for(gem_repo4)) end end @@ -258,7 +258,7 @@ RSpec.describe Bundler::Definition do bundled_app_lock, updated_deps_in_gemfile, source_list, - :gems => ["shared_owner_a"], :lock_shared_dependencies => true + :gems => ["shared_owner_a"], :conservative => true ) locked = definition.send(:converge_locked_specs).map(&:name) expect(locked).to eq %w[isolated_dep isolated_owner shared_dep shared_owner_b] diff --git a/spec/bundler/bundler/fetcher/downloader_spec.rb b/spec/bundler/bundler/fetcher/downloader_spec.rb index 667f484349..4d3dff3a89 100644 --- a/spec/bundler/bundler/fetcher/downloader_spec.rb +++ b/spec/bundler/bundler/fetcher/downloader_spec.rb @@ -231,16 +231,7 @@ RSpec.describe Bundler::Fetcher::Downloader do end end - context "when error message is about getaddrinfo issues" do - let(:message) { "getaddrinfo: nodename nor servname provided for http://www.uri-to-fetch.com" } - - it "should raise a Bundler::Fetcher::NetworkDownError" do - expect { subject.request(uri, options) }.to raise_error(Bundler::Fetcher::NetworkDownError, - /Could not reach host www.uri-to-fetch.com/) - end - end - - context "when error message is about neither host down or getaddrinfo" do + context "when error message is not about host down" do let(:message) { "other error about network" } it "should raise a Bundler::HTTPError" do diff --git a/spec/bundler/bundler/source_list_spec.rb b/spec/bundler/bundler/source_list_spec.rb index 0c40ba8a77..c2d1978b29 100644 --- a/spec/bundler/bundler/source_list_spec.rb +++ b/spec/bundler/bundler/source_list_spec.rb @@ -115,15 +115,15 @@ RSpec.describe Bundler::SourceList do end end - describe "#add_rubygems_remote", :bundler => "< 3" do - let!(:returned_source) { source_list.add_rubygems_remote("https://rubygems.org/") } + describe "#add_global_rubygems_remote" do + let!(:returned_source) { source_list.add_global_rubygems_remote("https://rubygems.org/") } it "returns the aggregate rubygems source" do expect(returned_source).to be_instance_of(Bundler::Source::Rubygems) end it "adds the provided remote to the beginning of the aggregate source" do - source_list.add_rubygems_remote("https://othersource.org") + source_list.add_global_rubygems_remote("https://othersource.org") expect(returned_source.remotes).to eq [ Bundler::URI("https://othersource.org/"), Bundler::URI("https://rubygems.org/"), @@ -212,22 +212,22 @@ RSpec.describe Bundler::SourceList do describe "#path_sources" do it "returns an empty array when no path sources have been added" do - source_list.add_rubygems_remote("https://rubygems.org") + source_list.add_global_rubygems_remote("https://rubygems.org") source_list.add_git_source("uri" => "git://host/path.git") expect(source_list.path_sources).to be_empty end it "returns path sources in the reverse order that they were added" do source_list.add_git_source("uri" => "git://third-git.org/path.git") - source_list.add_rubygems_remote("https://fifth-rubygems.org") + source_list.add_global_rubygems_remote("https://fifth-rubygems.org") source_list.add_path_source("path" => "/third/path/to/gem") - source_list.add_rubygems_remote("https://fourth-rubygems.org") + source_list.add_global_rubygems_remote("https://fourth-rubygems.org") source_list.add_path_source("path" => "/second/path/to/gem") - source_list.add_rubygems_remote("https://third-rubygems.org") + source_list.add_global_rubygems_remote("https://third-rubygems.org") source_list.add_git_source("uri" => "git://second-git.org/path.git") - source_list.add_rubygems_remote("https://second-rubygems.org") + source_list.add_global_rubygems_remote("https://second-rubygems.org") source_list.add_path_source("path" => "/first/path/to/gem") - source_list.add_rubygems_remote("https://first-rubygems.org") + source_list.add_global_rubygems_remote("https://first-rubygems.org") source_list.add_git_source("uri" => "git://first-git.org/path.git") expect(source_list.path_sources).to eq [ @@ -240,7 +240,7 @@ RSpec.describe Bundler::SourceList do describe "#git_sources" do it "returns an empty array when no git sources have been added" do - source_list.add_rubygems_remote("https://rubygems.org") + source_list.add_global_rubygems_remote("https://rubygems.org") source_list.add_path_source("path" => "/path/to/gem") expect(source_list.git_sources).to be_empty @@ -248,15 +248,15 @@ RSpec.describe Bundler::SourceList do it "returns git sources in the reverse order that they were added" do source_list.add_git_source("uri" => "git://third-git.org/path.git") - source_list.add_rubygems_remote("https://fifth-rubygems.org") + source_list.add_global_rubygems_remote("https://fifth-rubygems.org") source_list.add_path_source("path" => "/third/path/to/gem") - source_list.add_rubygems_remote("https://fourth-rubygems.org") + source_list.add_global_rubygems_remote("https://fourth-rubygems.org") source_list.add_path_source("path" => "/second/path/to/gem") - source_list.add_rubygems_remote("https://third-rubygems.org") + source_list.add_global_rubygems_remote("https://third-rubygems.org") source_list.add_git_source("uri" => "git://second-git.org/path.git") - source_list.add_rubygems_remote("https://second-rubygems.org") + source_list.add_global_rubygems_remote("https://second-rubygems.org") source_list.add_path_source("path" => "/first/path/to/gem") - source_list.add_rubygems_remote("https://first-rubygems.org") + source_list.add_global_rubygems_remote("https://first-rubygems.org") source_list.add_git_source("uri" => "git://first-git.org/path.git") expect(source_list.git_sources).to eq [ @@ -269,7 +269,7 @@ RSpec.describe Bundler::SourceList do describe "#plugin_sources" do it "returns an empty array when no plugin sources have been added" do - source_list.add_rubygems_remote("https://rubygems.org") + source_list.add_global_rubygems_remote("https://rubygems.org") source_list.add_path_source("path" => "/path/to/gem") expect(source_list.plugin_sources).to be_empty @@ -279,13 +279,13 @@ RSpec.describe Bundler::SourceList do source_list.add_plugin_source("new_source", "uri" => "https://third-git.org/path.git") source_list.add_git_source("https://new-git.org") source_list.add_path_source("path" => "/third/path/to/gem") - source_list.add_rubygems_remote("https://fourth-rubygems.org") + source_list.add_global_rubygems_remote("https://fourth-rubygems.org") source_list.add_path_source("path" => "/second/path/to/gem") - source_list.add_rubygems_remote("https://third-rubygems.org") + source_list.add_global_rubygems_remote("https://third-rubygems.org") source_list.add_plugin_source("new_source", "uri" => "git://second-git.org/path.git") - source_list.add_rubygems_remote("https://second-rubygems.org") + source_list.add_global_rubygems_remote("https://second-rubygems.org") source_list.add_path_source("path" => "/first/path/to/gem") - source_list.add_rubygems_remote("https://first-rubygems.org") + source_list.add_global_rubygems_remote("https://first-rubygems.org") source_list.add_plugin_source("new_source", "uri" => "git://first-git.org/path.git") expect(source_list.plugin_sources).to eq [ @@ -339,7 +339,7 @@ RSpec.describe Bundler::SourceList do describe "#get" do context "when it includes an equal source" do let(:rubygems_source) { Bundler::Source::Rubygems.new("remotes" => ["https://rubygems.org"]) } - before { @equal_source = source_list.add_rubygems_remote("https://rubygems.org") } + before { @equal_source = source_list.add_global_rubygems_remote("https://rubygems.org") } it "returns the equal source" do expect(source_list.get(rubygems_source)).to be @equal_source diff --git a/spec/bundler/commands/doctor_spec.rb b/spec/bundler/commands/doctor_spec.rb index d8e9674a24..a59ccc540a 100644 --- a/spec/bundler/commands/doctor_spec.rb +++ b/spec/bundler/commands/doctor_spec.rb @@ -32,6 +32,8 @@ RSpec.describe "bundle doctor" do unwritable_file = double("file") allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) allow(Find).to receive(:find).with(Bundler.bundle_path.to_s) { [unwritable_file] } + allow(File).to receive(:exist?).and_call_original + allow(File).to receive(:exist?).with(unwritable_file).and_return(true) allow(File).to receive(:stat).with(unwritable_file) { stat } allow(stat).to receive(:uid) { Process.uid } allow(File).to receive(:writable?).with(unwritable_file) { true } @@ -47,7 +49,6 @@ RSpec.describe "bundle doctor" do doctor = Bundler::CLI::Doctor.new({}) expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/rack/rack.bundle"] expect(doctor).to receive(:dylibs).exactly(2).times.and_return ["/usr/lib/libSystem.dylib"] - allow(File).to receive(:exist?).and_call_original allow(File).to receive(:exist?).with("/usr/lib/libSystem.dylib").and_return(true) expect { doctor.run }.not_to(raise_error, @stdout.string) expect(@stdout.string).to be_empty @@ -57,7 +58,6 @@ RSpec.describe "bundle doctor" do doctor = Bundler::CLI::Doctor.new({}) expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/rack/rack.bundle"] expect(doctor).to receive(:dylibs).exactly(2).times.and_return ["/usr/local/opt/icu4c/lib/libicui18n.57.1.dylib"] - allow(File).to receive(:exist?).and_call_original allow(File).to receive(:exist?).with("/usr/local/opt/icu4c/lib/libicui18n.57.1.dylib").and_return(false) expect { doctor.run }.to raise_error(Bundler::ProductionError, strip_whitespace(<<-E).strip), @stdout.string The following gems are missing OS dependencies: @@ -67,12 +67,32 @@ RSpec.describe "bundle doctor" do end end + context "when home contains broken symlinks" do + before(:each) do + @broken_symlink = double("file") + allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) + allow(Find).to receive(:find).with(Bundler.bundle_path.to_s) { [@broken_symlink] } + allow(File).to receive(:exist?).and_call_original + allow(File).to receive(:exist?).with(@broken_symlink) { false } + end + + it "exits with an error if home contains files that are not readable/writable" do + expect { Bundler::CLI::Doctor.new({}).run }.not_to raise_error + expect(@stdout.string).to include( + "Broken links exist in the Bundler home. Please report them to the offending gem's upstream repo. These files are:\n - #{@unwritable_file}" + ) + expect(@stdout.string).not_to include("No issues") + end + end + context "when home contains files that are not readable/writable" do before(:each) do @stat = double("stat") @unwritable_file = double("file") allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) allow(Find).to receive(:find).with(Bundler.bundle_path.to_s) { [@unwritable_file] } + allow(File).to receive(:exist?).and_call_original + allow(File).to receive(:exist?).with(@unwritable_file) { true } allow(File).to receive(:stat).with(@unwritable_file) { @stat } end diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb index 4d5bab063d..f9548238e9 100644 --- a/spec/bundler/commands/update_spec.rb +++ b/spec/bundler/commands/update_spec.rb @@ -241,6 +241,94 @@ RSpec.describe "bundle update" do expect(the_bundle).to include_gems("slim 3.0.9", "slim-rails 3.1.3", "slim_lint 0.16.1") end + it "does not go to an older version, even if the version upgrade that could cause another gem to downgrade is activated first" do + build_repo4 do + # countries is processed before country_select by the resolver due to having less spec groups (groups of versions with the same dependencies) (2 vs 3) + + build_gem "countries", "2.1.4" + build_gem "countries", "3.1.0" + + build_gem "countries", "4.0.0" do |s| + s.add_dependency "sixarm_ruby_unaccent", "~> 1.1" + end + + build_gem "country_select", "1.2.0" + + build_gem "country_select", "2.1.4" do |s| + s.add_dependency "countries", "~> 2.0" + end + build_gem "country_select", "3.1.1" do |s| + s.add_dependency "countries", "~> 2.0" + end + + build_gem "country_select", "5.1.0" do |s| + s.add_dependency "countries", "~> 3.0" + end + + build_gem "sixarm_ruby_unaccent", "1.1.0" + end + + gemfile <<~G + source "#{file_uri_for(gem_repo4)}" + + gem "country_select" + gem "countries" + G + + lockfile <<~L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + countries (3.1.0) + country_select (5.1.0) + countries (~> 3.0) + + PLATFORMS + #{specific_local_platform} + + DEPENDENCIES + countries + country_select + + BUNDLED WITH + #{Bundler::VERSION} + L + + previous_lockfile = lockfile + + bundle "lock --update" + + expect(lockfile).to eq(previous_lockfile) + end + + it "does not downgrade indirect dependencies unnecessarily" do + build_repo4 do + build_gem "a" do |s| + s.add_dependency "b" + s.add_dependency "c" + end + build_gem "b" + build_gem "c" + build_gem "c", "2.0" + end + + install_gemfile <<-G, :verbose => true + source "#{file_uri_for(gem_repo4)}" + gem "a" + G + + expect(the_bundle).to include_gems("a 1.0", "b 1.0", "c 2.0") + + update_repo4 do + build_gem "b", "2.0" do |s| + s.add_dependency "c", "< 2" + end + end + + bundle "update", :all => true, :verbose => true + expect(the_bundle).to include_gems("a 1.0", "b 1.0", "c 2.0") + end + it "should still downgrade if forced by the Gemfile" do build_repo4 do build_gem "a" @@ -411,7 +499,7 @@ RSpec.describe "bundle update" do build_repo2 end - it "should not update gems not included in the source that happen to have the same name", :bundler => "< 3" do + it "should not update gems not included in the source that happen to have the same name" do install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" gem "activesupport" @@ -419,10 +507,10 @@ RSpec.describe "bundle update" do update_repo2 { build_gem "activesupport", "3.0" } bundle "update --source activesupport" - expect(the_bundle).to include_gem "activesupport 3.0" + expect(the_bundle).not_to include_gem "activesupport 3.0" end - it "should not update gems not included in the source that happen to have the same name", :bundler => "3" do + it "should not update gems not included in the source that happen to have the same name" do install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" gem "activesupport" @@ -430,22 +518,7 @@ RSpec.describe "bundle update" do update_repo2 { build_gem "activesupport", "3.0" } bundle "update --source activesupport" - expect(the_bundle).not_to include_gem "activesupport 3.0" - end - - context "with unlock_source_unlocks_spec set to false" do - before { bundle "config set unlock_source_unlocks_spec false" } - - it "should not update gems not included in the source that happen to have the same name" do - install_gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - gem "activesupport" - G - update_repo2 { build_gem "activesupport", "3.0" } - - bundle "update --source activesupport" - expect(the_bundle).not_to include_gems "activesupport 3.0" - end + expect(the_bundle).not_to include_gems "activesupport 3.0" end end @@ -465,20 +538,7 @@ RSpec.describe "bundle update" do G end - it "should not update the child dependencies of a gem that has the same name as the source", :bundler => "< 3" do - update_repo2 do - build_gem "fred", "2.0" - build_gem "harry", "2.0" do |s| - s.add_dependency "fred" - end - end - - bundle "update --source harry" - expect(the_bundle).to include_gems "harry 2.0" - expect(the_bundle).to include_gems "fred 1.0" - end - - it "should not update the child dependencies of a gem that has the same name as the source", :bundler => "3" do + it "should not update the child dependencies of a gem that has the same name as the source" do update_repo2 do build_gem "fred", "2.0" build_gem "harry", "2.0" do |s| @@ -510,21 +570,7 @@ RSpec.describe "bundle update" do G end - it "should not update the child dependencies of a gem that has the same name as the source", :bundler => "< 3" do - update_repo2 do - build_gem "george", "2.0" - build_gem "harry", "2.0" do |s| - s.add_dependency "george" - end - end - - bundle "update --source harry" - expect(the_bundle).to include_gems "harry 2.0" - expect(the_bundle).to include_gems "fred 1.0" - expect(the_bundle).to include_gems "george 1.0" - end - - it "should not update the child dependencies of a gem that has the same name as the source", :bundler => "3" do + it "should not update the child dependencies of a gem that has the same name as the source" do update_repo2 do build_gem "george", "2.0" build_gem "harry", "2.0" do |s| @@ -1106,9 +1152,9 @@ RSpec.describe "bundle update conservative" do gem 'shared_owner_b' G - lockfile <<-L + lockfile <<~L GEM - remote: #{file_uri_for(gem_repo4)} + remote: #{file_uri_for(gem_repo4)}/ specs: isolated_dep (2.0.1) isolated_owner (1.0.1) @@ -1120,12 +1166,12 @@ RSpec.describe "bundle update conservative" do shared_dep (~> 5.0) PLATFORMS - ruby + #{specific_local_platform} DEPENDENCIES + isolated_owner shared_owner_a shared_owner_b - isolated_owner BUNDLED WITH #{Bundler::VERSION} @@ -1147,7 +1193,42 @@ RSpec.describe "bundle update conservative" do it "should not eagerly unlock with --conservative" do bundle "update --conservative shared_owner_a isolated_owner" - expect(the_bundle).to include_gems "isolated_owner 1.0.2", "isolated_dep 2.0.2", "shared_dep 5.0.1", "shared_owner_a 3.0.2", "shared_owner_b 4.0.1" + expect(the_bundle).to include_gems "isolated_owner 1.0.2", "isolated_dep 2.0.1", "shared_dep 5.0.1", "shared_owner_a 3.0.2", "shared_owner_b 4.0.1" + end + + it "should only update direct dependencies when fully updating with --conservative" do + bundle "update --conservative" + + expect(the_bundle).to include_gems "isolated_owner 1.0.2", "isolated_dep 2.0.1", "shared_dep 5.0.1", "shared_owner_a 3.0.2", "shared_owner_b 4.0.2" + end + + it "should only change direct dependencies when updating the lockfile with --conservative" do + bundle "lock --update --conservative" + + expect(lockfile).to eq <<~L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + isolated_dep (2.0.1) + isolated_owner (1.0.2) + isolated_dep (~> 2.0) + shared_dep (5.0.1) + shared_owner_a (3.0.2) + shared_dep (~> 5.0) + shared_owner_b (4.0.2) + shared_dep (~> 5.0) + + PLATFORMS + #{specific_local_platform} + + DEPENDENCIES + isolated_owner + shared_owner_a + shared_owner_b + + BUNDLED WITH + #{Bundler::VERSION} + L end it "should match bundle install conservative update behavior when not eagerly unlocking" do diff --git a/spec/bundler/install/gemfile/eval_gemfile_spec.rb b/spec/bundler/install/gemfile/eval_gemfile_spec.rb index 102f61dc12..8303e6284e 100644 --- a/spec/bundler/install/gemfile/eval_gemfile_spec.rb +++ b/spec/bundler/install/gemfile/eval_gemfile_spec.rb @@ -26,6 +26,38 @@ RSpec.describe "bundle install with gemfile that uses eval_gemfile" do end end + context "eval-ed Gemfile points to an internal gemspec and uses a scoped source that duplicates the main Gemfile global source" do + before do + build_repo2 do + build_gem "rails", "6.1.3.2" + + build_gem "zip-zip", "0.3" + end + + create_file bundled_app("gems/Gemfile"), <<-G + gemspec :path => "\#{__dir__}/gunks" + + source "#{file_uri_for(gem_repo2)}" do + gem "zip-zip" + end + G + end + + it "installs and finds gems correctly" do + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + + gem "rails" + + eval_gemfile File.join(__dir__, "gems/Gemfile") + G + expect(out).to include("Resolving dependencies") + expect(out).to include("Bundle complete") + + expect(the_bundle).to include_gem "rails 6.1.3.2" + end + end + context "eval-ed Gemfile has relative-path gems" do before do build_lib("a", :path => bundled_app("gems/a")) diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb index 82129677b3..0739285a5d 100644 --- a/spec/bundler/install/gemfile/sources_spec.rb +++ b/spec/bundler/install/gemfile/sources_spec.rb @@ -247,7 +247,33 @@ RSpec.describe "bundle install with gems on multiple sources" do bundle :install, :artifice => "compact_index" expect(err).to include("Warning: the gem 'rack' was found in multiple sources.") expect(err).to include("Installed from: https://gem.repo2") + + expect(lockfile).to eq <<~L + GEM + remote: https://gem.repo1/ + remote: https://gem.repo2/ + specs: + rack (1.0.0) + + GEM + remote: https://gem.repo3/ + specs: + depends_on_rack (1.0.1) + rack + + PLATFORMS + #{specific_local_platform} + + DEPENDENCIES + depends_on_rack! + + BUNDLED WITH + #{Bundler::VERSION} + L + + previous_lockfile = lockfile expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") + expect(lockfile).to eq(previous_lockfile) end it "fails", :bundler => "3" do @@ -945,7 +971,7 @@ RSpec.describe "bundle install with gems on multiple sources" do rack (0.9.1) PLATFORMS - ruby + #{specific_local_platform} DEPENDENCIES rack! @@ -1254,6 +1280,25 @@ RSpec.describe "bundle install with gems on multiple sources" do expect(out).to include("Using example 0.1.0") end + it "fails inmmediately with a helpful error when a non retriable network error happens while resolving sources" do + gemfile <<-G + source "https://gem.repo1" + + source "https://gem.repo4" do + gem "example" + end + G + + simulate_bundler_version_when_missing_prerelease_default_gem_activation do + ruby <<~R, :raise_on_error => false + require 'bundler/setup' + R + end + + expect(last_command).to be_failure + expect(err).to include("Could not reach host gem.repo4. Check your network connection and try again.") + end + context "when an indirect dependency is available from multiple ambiguous sources", :bundler => "< 3" do it "succeeds but warns, suggesting a source block" do build_repo4 do @@ -1310,4 +1355,74 @@ RSpec.describe "bundle install with gems on multiple sources" do expect(the_bundle).not_to be_locked end end + + context "when upgrading a lockfile suffering from dependency confusion" do + before do + build_repo4 do + build_gem "mime-types", "3.0.0" + end + + build_repo2 do + build_gem "capybara", "2.5.0" do |s| + s.add_dependency "mime-types", ">= 1.16" + end + + build_gem "mime-types", "3.3.1" + end + + gemfile <<~G + source "https://gem.repo2" + + gem "capybara", "~> 2.5.0" + + source "https://gem.repo4" do + gem "mime-types", "~> 3.0" + end + G + + lockfile <<-L + GEM + remote: https://gem.repo2/ + remote: https://gem.repo4/ + specs: + capybara (2.5.0) + mime-types (>= 1.16) + mime-types (3.3.1) + + PLATFORMS + #{specific_local_platform} + + DEPENDENCIES + capybara (~> 2.5.0) + mime-types (~> 3.0)! + L + end + + it "upgrades the lockfile correctly" do + bundle "lock --update", :artifice => "compact_index" + + expect(lockfile).to eq <<~L + GEM + remote: https://gem.repo2/ + specs: + capybara (2.5.0) + mime-types (>= 1.16) + + GEM + remote: https://gem.repo4/ + specs: + mime-types (3.0.0) + + PLATFORMS + #{specific_local_platform} + + DEPENDENCIES + capybara (~> 2.5.0) + mime-types (~> 3.0)! + + BUNDLED WITH + #{Bundler::VERSION} + L + end + end end diff --git a/spec/bundler/install/gems/compact_index_spec.rb b/spec/bundler/install/gems/compact_index_spec.rb index 8be97ed5d2..6257cf4f71 100644 --- a/spec/bundler/install/gems/compact_index_spec.rb +++ b/spec/bundler/install/gems/compact_index_spec.rb @@ -399,7 +399,7 @@ The checksum of /versions does not match the checksum provided by the server! So api_request_limit = low_api_request_limit_for(gem_repo2) - install_gemfile <<-G, :artifice => "compact_index_extra_missing", :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation) + install_gemfile <<-G, :artifice => "compact_index_extra_missing", :requires => [api_request_limit_hack_file], :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation) source "#{source_uri}" source "#{source_uri}/extra" do gem "back_deps" @@ -421,7 +421,7 @@ The checksum of /versions does not match the checksum provided by the server! So api_request_limit = low_api_request_limit_for(gem_repo4) - install_gemfile <<-G, :artifice => "compact_index_extra_api_missing", :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation) + install_gemfile <<-G, :artifice => "compact_index_extra_api_missing", :requires => [api_request_limit_hack_file], :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation) source "#{source_uri}" source "#{source_uri}/extra" do gem "back_deps" diff --git a/spec/bundler/install/gems/dependency_api_spec.rb b/spec/bundler/install/gems/dependency_api_spec.rb index eae8daa682..9738a75474 100644 --- a/spec/bundler/install/gems/dependency_api_spec.rb +++ b/spec/bundler/install/gems/dependency_api_spec.rb @@ -371,7 +371,7 @@ RSpec.describe "gemcutter's dependency API" do api_request_limit = low_api_request_limit_for(gem_repo2) - install_gemfile <<-G, :artifice => "endpoint_extra_missing", :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation) + install_gemfile <<-G, :artifice => "endpoint_extra_missing", :requires => [api_request_limit_hack_file], :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation) source "#{source_uri}" source "#{source_uri}/extra" gem "back_deps" @@ -392,7 +392,7 @@ RSpec.describe "gemcutter's dependency API" do api_request_limit = low_api_request_limit_for(gem_repo2) - install_gemfile <<-G, :artifice => "endpoint_extra_missing", :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation) + install_gemfile <<-G, :artifice => "endpoint_extra_missing", :requires => [api_request_limit_hack_file], :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation) source "#{source_uri}" source "#{source_uri}/extra" do gem "back_deps" diff --git a/spec/bundler/install/global_cache_spec.rb b/spec/bundler/install/global_cache_spec.rb index 68ebef2d89..9bc243e7cf 100644 --- a/spec/bundler/install/global_cache_spec.rb +++ b/spec/bundler/install/global_cache_spec.rb @@ -181,8 +181,11 @@ RSpec.describe "global gem caching" do bundle :install, :artifice => "compact_index_no_gem", :dir => bundled_app2 # activesupport is installed and both are in the global cache - expect(the_bundle).not_to include_gems "rack 1.0.0", :dir => bundled_app2 - expect(the_bundle).to include_gems "activesupport 2.3.5", :dir => bundled_app2 + simulate_bundler_version_when_missing_prerelease_default_gem_activation do + expect(the_bundle).not_to include_gems "rack 1.0.0", :dir => bundled_app2 + expect(the_bundle).to include_gems "activesupport 2.3.5", :dir => bundled_app2 + end + expect(source_global_cache("rack-1.0.0.gem")).to exist expect(source_global_cache("activesupport-2.3.5.gem")).to exist end diff --git a/spec/bundler/lock/lockfile_spec.rb b/spec/bundler/lock/lockfile_spec.rb index 0fbe9ee80d..0ab31eabc6 100644 --- a/spec/bundler/lock/lockfile_spec.rb +++ b/spec/bundler/lock/lockfile_spec.rb @@ -1178,83 +1178,6 @@ RSpec.describe "the lockfile format" do G end - # Some versions of the Bundler 1.1 RC series introduced corrupted - # lockfiles. There were two major problems: - # - # * multiple copies of the same GIT section appeared in the lockfile - # * when this happened, those sections got multiple copies of gems - # in those sections. - it "fixes corrupted lockfiles" do - build_git "omg", :path => lib_path("omg") - revision = revision_for(lib_path("omg")) - - gemfile <<-G - source "#{file_uri_for(gem_repo2)}/" - gem "omg", :git => "#{lib_path("omg")}", :branch => 'master' - G - - bundle "config set --local path vendor" - bundle :install - expect(the_bundle).to include_gems "omg 1.0" - - # Create a Gemfile.lock that has duplicate GIT sections - lockfile <<-L - GIT - remote: #{lib_path("omg")} - revision: #{revision} - branch: master - specs: - omg (1.0) - - GIT - remote: #{lib_path("omg")} - revision: #{revision} - branch: master - specs: - omg (1.0) - - GEM - remote: #{file_uri_for(gem_repo2)}/ - specs: - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - omg! - - BUNDLED WITH - #{Bundler::VERSION} - L - - FileUtils.rm_rf(bundled_app("vendor")) - bundle "install" - expect(the_bundle).to include_gems "omg 1.0" - - # Confirm that duplicate specs do not appear - lockfile_should_be(<<-L) - GIT - remote: #{lib_path("omg")} - revision: #{revision} - branch: master - specs: - omg (1.0) - - GEM - remote: #{file_uri_for(gem_repo2)}/ - specs: - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - omg! - - BUNDLED WITH - #{Bundler::VERSION} - L - end - it "raises a helpful error message when the lockfile is missing deps" do lockfile <<-L GEM @@ -1326,7 +1249,10 @@ RSpec.describe "the lockfile format" do expect { bundle "update", :all => true }.to change { File.mtime(bundled_app_lock) } expect(File.read(bundled_app_lock)).to match("\r\n") - expect(the_bundle).to include_gems "rack 1.2" + + simulate_bundler_version_when_missing_prerelease_default_gem_activation do + expect(the_bundle).to include_gems "rack 1.2" + end end end diff --git a/spec/bundler/realworld/edgecases_spec.rb b/spec/bundler/realworld/edgecases_spec.rb index 0fac56c942..556a11d2f3 100644 --- a/spec/bundler/realworld/edgecases_spec.rb +++ b/spec/bundler/realworld/edgecases_spec.rb @@ -211,133 +211,6 @@ RSpec.describe "real world edgecases", :realworld => true do expect(err).to be_empty end - it "checks out git repos when the lockfile is corrupted" do - gemfile <<-G - source "https://rubygems.org" - git_source(:github) {|repo| "https://github.com/\#{repo}.git" } - - gem 'activerecord', :github => 'carlhuda/rails-bundler-test', :branch => 'master' - gem 'activesupport', :github => 'carlhuda/rails-bundler-test', :branch => 'master' - gem 'actionpack', :github => 'carlhuda/rails-bundler-test', :branch => 'master' - G - - lockfile <<-L - GIT - remote: https://github.com/carlhuda/rails-bundler-test.git - revision: 369e28a87419565f1940815219ea9200474589d4 - branch: master - specs: - actionpack (3.2.2) - activemodel (= 3.2.2) - activesupport (= 3.2.2) - builder (~> 3.0.0) - erubis (~> 2.7.0) - journey (~> 1.0.1) - rack (~> 1.4.0) - rack-cache (~> 1.2) - rack-test (~> 0.6.1) - sprockets (~> 2.1.2) - activemodel (3.2.2) - activesupport (= 3.2.2) - builder (~> 3.0.0) - activerecord (3.2.2) - activemodel (= 3.2.2) - activesupport (= 3.2.2) - arel (~> 3.0.2) - tzinfo (~> 0.3.29) - activesupport (3.2.2) - i18n (~> 0.6) - multi_json (~> 1.0) - - GIT - remote: https://github.com/carlhuda/rails-bundler-test.git - revision: 369e28a87419565f1940815219ea9200474589d4 - branch: master - specs: - actionpack (3.2.2) - activemodel (= 3.2.2) - activesupport (= 3.2.2) - builder (~> 3.0.0) - erubis (~> 2.7.0) - journey (~> 1.0.1) - rack (~> 1.4.0) - rack-cache (~> 1.2) - rack-test (~> 0.6.1) - sprockets (~> 2.1.2) - activemodel (3.2.2) - activesupport (= 3.2.2) - builder (~> 3.0.0) - activerecord (3.2.2) - activemodel (= 3.2.2) - activesupport (= 3.2.2) - arel (~> 3.0.2) - tzinfo (~> 0.3.29) - activesupport (3.2.2) - i18n (~> 0.6) - multi_json (~> 1.0) - - GIT - remote: https://github.com/carlhuda/rails-bundler-test.git - revision: 369e28a87419565f1940815219ea9200474589d4 - branch: master - specs: - actionpack (3.2.2) - activemodel (= 3.2.2) - activesupport (= 3.2.2) - builder (~> 3.0.0) - erubis (~> 2.7.0) - journey (~> 1.0.1) - rack (~> 1.4.0) - rack-cache (~> 1.2) - rack-test (~> 0.6.1) - sprockets (~> 2.1.2) - activemodel (3.2.2) - activesupport (= 3.2.2) - builder (~> 3.0.0) - activerecord (3.2.2) - activemodel (= 3.2.2) - activesupport (= 3.2.2) - arel (~> 3.0.2) - tzinfo (~> 0.3.29) - activesupport (3.2.2) - i18n (~> 0.6) - multi_json (~> 1.0) - - GEM - remote: https://rubygems.org/ - specs: - arel (3.0.2) - builder (3.0.0) - erubis (2.7.0) - hike (1.2.1) - i18n (0.6.0) - journey (1.0.3) - multi_json (1.1.0) - rack (1.4.1) - rack-cache (1.2) - rack (>= 0.4) - rack-test (0.6.1) - rack (>= 1.0) - sprockets (2.1.2) - hike (~> 1.2) - rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) - tilt (1.3.3) - tzinfo (0.3.32) - - PLATFORMS - ruby - - DEPENDENCIES - actionpack! - activerecord! - activesupport! - L - - bundle :lock - expect(err).to be_empty - end - it "outputs a helpful error message when gems have invalid gemspecs" do install_gemfile <<-G, :standalone => true, :raise_on_error => false source 'https://rubygems.org' @@ -349,14 +222,14 @@ RSpec.describe "real world edgecases", :realworld => true do end it "doesn't hang on big gemfile" do - skip "Only for ruby 2.7.2" if RUBY_VERSION != "2.7.2" + skip "Only for ruby 2.7.3" if RUBY_VERSION != "2.7.3" || RUBY_PLATFORM =~ /darwin/ gemfile <<~G # frozen_string_literal: true source "https://rubygems.org" - ruby "2.7.2" + ruby "2.7.3" gem "rails" gem "pg", ">= 0.18", "< 2.0" @@ -461,7 +334,7 @@ RSpec.describe "real world edgecases", :realworld => true do end it "doesn't hang on tricky gemfile" do - skip "Only for ruby 2.7.2" if RUBY_VERSION != "2.7.2" + skip "Only for ruby 2.7.3" if RUBY_VERSION != "2.7.3" || RUBY_PLATFORM =~ /darwin/ gemfile <<~G source 'https://rubygems.org' @@ -487,7 +360,7 @@ RSpec.describe "real world edgecases", :realworld => true do end it "doesn't hang on nix gemfile" do - skip "Only for ruby 3.0.0" if RUBY_VERSION != "3.0.0" + skip "Only for ruby 3.0.1" if RUBY_VERSION != "3.0.1" || RUBY_PLATFORM =~ /darwin/ gemfile <<~G source "https://rubygems.org" do diff --git a/spec/bundler/realworld/slow_perf_spec.rb b/spec/bundler/realworld/slow_perf_spec.rb index 518da2800b..aced5a1641 100644 --- a/spec/bundler/realworld/slow_perf_spec.rb +++ b/spec/bundler/realworld/slow_perf_spec.rb @@ -4,17 +4,19 @@ require "spec_helper" RSpec.describe "bundle install with complex dependencies", :realworld => true do it "resolves quickly" do - start_time = Time.now - - install_gemfile <<-G + gemfile <<-G source 'https://rubygems.org' gem "actionmailer" gem "mongoid", ">= 0.10.2" G + start_time = Time.now + + bundle "lock" + duration = Time.now - start_time - expect(duration.to_f).to be < 120 # seconds + expect(duration.to_f).to be < 12 # seconds end end diff --git a/spec/bundler/spec_helper.rb b/spec/bundler/spec_helper.rb index 36a6bcd099..80b0ccff4d 100644 --- a/spec/bundler/spec_helper.rb +++ b/spec/bundler/spec_helper.rb @@ -13,6 +13,7 @@ require "bundler" require "rspec/core" require "rspec/expectations" require "rspec/mocks" +require "rspec/support/differ" require_relative "support/builders" require_relative "support/build_metadata" diff --git a/spec/bundler/support/api_request_limit_hax.rb b/spec/bundler/support/api_request_limit_hax.rb new file mode 100644 index 0000000000..37ff0203b3 --- /dev/null +++ b/spec/bundler/support/api_request_limit_hax.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +if ENV["BUNDLER_SPEC_API_REQUEST_LIMIT"] + require_relative "path" + require "bundler/source" + require "bundler/source/rubygems" + + module Bundler + class Source + class Rubygems < Source + remove_const :API_REQUEST_LIMIT + API_REQUEST_LIMIT = ENV["BUNDLER_SPEC_API_REQUEST_LIMIT"].to_i + end + end + end +end diff --git a/spec/bundler/support/hax.rb b/spec/bundler/support/hax.rb index 8fd35890ae..ddb62f7d53 100644 --- a/spec/bundler/support/hax.rb +++ b/spec/bundler/support/hax.rb @@ -35,28 +35,3 @@ module Gem end end end - -if ENV["BUNDLER_SPEC_WINDOWS"] == "true" - require_relative "path" - require "bundler/constants" - - module Bundler - remove_const :WINDOWS if defined?(WINDOWS) - WINDOWS = true - end -end - -if ENV["BUNDLER_SPEC_API_REQUEST_LIMIT"] - require_relative "path" - require "bundler/source" - require "bundler/source/rubygems" - - module Bundler - class Source - class Rubygems < Source - remove_const :API_REQUEST_LIMIT - API_REQUEST_LIMIT = ENV["BUNDLER_SPEC_API_REQUEST_LIMIT"].to_i - end - end - end -end diff --git a/spec/bundler/support/helpers.rb b/spec/bundler/support/helpers.rb index d660a972e3..ba1ce7c20f 100644 --- a/spec/bundler/support/helpers.rb +++ b/spec/bundler/support/helpers.rb @@ -455,20 +455,15 @@ module Spec end def simulate_windows(platform = mswin) - old = ENV["BUNDLER_SPEC_WINDOWS"] - ENV["BUNDLER_SPEC_WINDOWS"] = "true" simulate_platform platform do simulate_bundler_version_when_missing_prerelease_default_gem_activation do yield end end - ensure - ENV["BUNDLER_SPEC_WINDOWS"] = old end - # workaround for missing https://github.com/rubygems/rubygems/commit/929e92d752baad3a08f3ac92eaec162cb96aedd1 def simulate_bundler_version_when_missing_prerelease_default_gem_activation - return yield unless Gem.rubygems_version < Gem::Version.new("3.1.0.pre.1") + return yield unless rubygems_version_failing_to_activate_bundler_prereleases old = ENV["BUNDLER_VERSION"] ENV["BUNDLER_VERSION"] = Bundler::VERSION @@ -477,15 +472,20 @@ module Spec ENV["BUNDLER_VERSION"] = old end - # workaround for missing https://github.com/rubygems/rubygems/commit/929e92d752baad3a08f3ac92eaec162cb96aedd1 def env_for_missing_prerelease_default_gem_activation - if Gem.rubygems_version < Gem::Version.new("3.1.0.pre.1") + if rubygems_version_failing_to_activate_bundler_prereleases { "BUNDLER_VERSION" => Bundler::VERSION } else {} end end + # versions providing a bundler version finder but not including + # https://github.com/rubygems/rubygems/commit/929e92d752baad3a08f3ac92eaec162cb96aedd1 + def rubygems_version_failing_to_activate_bundler_prereleases + Gem.rubygems_version < Gem::Version.new("3.1.0.pre.1") && Gem.rubygems_version >= Gem::Version.new("2.7.0") + end + def revision_for(path) sys_exec("git rev-parse HEAD", :dir => path).strip end diff --git a/spec/bundler/support/matchers.rb b/spec/bundler/support/matchers.rb index 3c1014edc7..180ad54c5b 100644 --- a/spec/bundler/support/matchers.rb +++ b/spec/bundler/support/matchers.rb @@ -118,14 +118,14 @@ module Spec opts[:raise_on_error] = false @errors = names.map do |full_name| name, version, platform = full_name.split(/\s+/) - require_path = name == "bundler" ? "#{lib_dir}/bundler" : name.tr("-", "/") + require_path = name.tr("-", "/") version_const = name == "bundler" ? "Bundler::VERSION" : Spec::Builders.constantize(name) source_const = "#{Spec::Builders.constantize(name)}_SOURCE" ruby <<~R, opts - require '#{lib_dir}/bundler' + require 'bundler' Bundler.setup(#{groups}) - require '#{require_path}.rb' + require '#{require_path}' actual_version, actual_platform = #{version_const}.split(/\s+/, 2) unless Gem::Version.new(actual_version) == Gem::Version.new('#{version}') puts actual_version @@ -170,7 +170,7 @@ module Spec name, version = name.split(/\s+/, 2) ruby <<-R, opts begin - require '#{lib_dir}/bundler' + require 'bundler' Bundler.setup(#{groups}) rescue Bundler::GemNotFound, Bundler::GitError exit 0 diff --git a/spec/bundler/support/path.rb b/spec/bundler/support/path.rb index dbe5862b44..9de716ff35 100644 --- a/spec/bundler/support/path.rb +++ b/spec/bundler/support/path.rb @@ -67,6 +67,10 @@ module Spec @spec_dir ||= source_root.join(ruby_core? ? "spec/bundler" : "spec") end + def api_request_limit_hack_file + spec_dir.join("support/api_request_limit_hax.rb") + end + def man_dir @man_dir ||= lib_dir.join("bundler/man") end diff --git a/test/rubygems/test_gem_ext_rake_builder.rb b/test/rubygems/test_gem_ext_rake_builder.rb index 833f57615d..505f42ba06 100644 --- a/test/rubygems/test_gem_ext_rake_builder.rb +++ b/test/rubygems/test_gem_ext_rake_builder.rb @@ -48,6 +48,8 @@ class TestGemExtRakeBuilder < Gem::TestCase end def test_class_no_openssl_override + pend 'openssl is missing' unless Gem::HAVE_OPENSSL + create_temp_mkrf_file('task :default') rake = util_spec 'rake' do |s| diff --git a/test/rubygems/test_gem_gemcutter_utilities.rb b/test/rubygems/test_gem_gemcutter_utilities.rb index ae31b9a7dd..fa9f951f8e 100644 --- a/test/rubygems/test_gem_gemcutter_utilities.rb +++ b/test/rubygems/test_gem_gemcutter_utilities.rb @@ -14,6 +14,7 @@ class TestGemGemcutterUtilities < Gem::TestCase Gem.configuration.disable_default_gem_server = nil ENV['RUBYGEMS_HOST'] = nil + ENV['GEM_HOST_OTP_CODE'] = nil Gem.configuration.rubygems_api_key = nil @cmd = Gem::Command.new '', 'summary' @@ -22,6 +23,7 @@ class TestGemGemcutterUtilities < Gem::TestCase def teardown ENV['RUBYGEMS_HOST'] = nil + ENV['GEM_HOST_OTP_CODE'] = nil Gem.configuration.rubygems_api_key = nil credential_teardown @@ -186,6 +188,16 @@ class TestGemGemcutterUtilities < Gem::TestCase assert_match %r{Access Denied.}, @sign_in_ui.output end + def test_signin_with_env_otp_code + ENV['GEM_HOST_OTP_CODE'] = '111111' + api_key = 'a5fdbb6ba150cbb83aad2bb2fede64cf040453903' + + util_sign_in [api_key, 200, 'OK'] + + assert_match 'Signed in with API key:', @sign_in_ui.output + assert_equal '111111', @fetcher.last_request['OTP'] + end + def test_sign_in_with_correct_otp_code api_key = 'a5fdbb6ba150cbb83aad2bb2fede64cf040453903' response_fail = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry." diff --git a/tool/bundler/rubocop_gems.rb.lock b/tool/bundler/rubocop_gems.rb.lock index e2b5b76031..d172532f83 100644 --- a/tool/bundler/rubocop_gems.rb.lock +++ b/tool/bundler/rubocop_gems.rb.lock @@ -5,7 +5,7 @@ GEM diff-lcs (1.4.4) minitest (5.14.4) parallel (1.19.2) - parser (3.0.0.0) + parser (3.0.1.0) ast (~> 2.4.1) power_assert (2.0.0) rainbow (3.0.0) @@ -56,4 +56,4 @@ DEPENDENCIES test-unit BUNDLED WITH - 2.2.21 + 2.2.22 diff --git a/tool/bundler/test_gems.rb.lock b/tool/bundler/test_gems.rb.lock index e39db5fef0..4a3ccadbc4 100644 --- a/tool/bundler/test_gems.rb.lock +++ b/tool/bundler/test_gems.rb.lock @@ -40,4 +40,4 @@ DEPENDENCIES webrick (= 1.7.0) BUNDLED WITH - 2.2.21 + 2.2.22 |