diff --git a/lib/bundler/bundler.gemspec b/lib/bundler/bundler.gemspec index 9da149dd8d..38c533b0c1 100644 --- a/lib/bundler/bundler.gemspec +++ b/lib/bundler/bundler.gemspec @@ -34,9 +34,10 @@ Gem::Specification.new do |s| s.required_ruby_version = ">= 2.3.0" s.required_rubygems_version = ">= 2.5.2" - s.files = (Dir.glob("lib/bundler/**/*", File::FNM_DOTMATCH) + Dir.glob("libexec/bundle*")).reject {|f| File.directory?(f) } + s.files = Dir.glob("lib/bundler{.rb,/**/*}", File::FNM_DOTMATCH).reject {|f| File.directory?(f) } - s.files += ["lib/bundler.rb"] + # include the gemspec itself because warbler breaks w/o it + s.files += %w[lib/bundler/bundler.gemspec] s.bindir = "libexec" s.executables = %w[bundle bundler] diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb index b924edb28e..6562f3a853 100644 --- a/lib/bundler/cli.rb +++ b/lib/bundler/cli.rb @@ -510,8 +510,8 @@ module Bundler By default, setting a configuration value sets it for all projects on the machine. - If a global setting is superceded by local configuration, this command - will show the current value, as well as any superceded values and + If a global setting is superseded by local configuration, this command + will show the current value, as well as any superseded values and where they were specified. D require_relative "cli/config" diff --git a/lib/bundler/cli/common.rb b/lib/bundler/cli/common.rb index 32d952fb72..ba259143b7 100644 --- a/lib/bundler/cli/common.rb +++ b/lib/bundler/cli/common.rb @@ -94,6 +94,8 @@ module Bundler end def self.ensure_all_gems_in_lockfile!(names, locked_gems = Bundler.locked_gems) + return unless locked_gems + locked_names = locked_gems.specs.map(&:name).uniq names.-(locked_names).each do |g| raise GemNotFound, gem_not_found_message(g, locked_names) diff --git a/lib/bundler/compact_index_client/updater.rb b/lib/bundler/compact_index_client/updater.rb index b4b2321797..06486f98cb 100644 --- a/lib/bundler/compact_index_client/updater.rb +++ b/lib/bundler/compact_index_client/updater.rb @@ -50,16 +50,20 @@ module Bundler content = response.body - SharedHelpers.filesystem_access(local_temp_path) do + etag = (response["ETag"] || "").gsub(%r{\AW/}, "") + correct_response = SharedHelpers.filesystem_access(local_temp_path) do if response.is_a?(Net::HTTPPartialContent) && local_temp_path.size.nonzero? local_temp_path.open("a") {|f| f << slice_body(content, 1..-1) } + + etag_for(local_temp_path) == etag else local_temp_path.open("wb") {|f| f << content } + + etag.length.zero? || etag_for(local_temp_path) == etag end end - etag = (response["ETag"] || "").gsub(%r{\AW/}, "") - if etag.length.zero? || etag_for(local_temp_path) == etag + if correct_response SharedHelpers.filesystem_access(local_path) do FileUtils.mv(local_temp_path, local_path) end diff --git a/lib/bundler/current_ruby.rb b/lib/bundler/current_ruby.rb index c132e8ecc0..b8c7cada1c 100644 --- a/lib/bundler/current_ruby.rb +++ b/lib/bundler/current_ruby.rb @@ -20,6 +20,7 @@ module Bundler 2.5 2.6 2.7 + 3.0 ].freeze KNOWN_MAJOR_VERSIONS = KNOWN_MINOR_VERSIONS.map {|v| v.split(".", 2).first }.uniq.freeze diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index ca5aadba9d..fc30dd5ca8 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -166,16 +166,14 @@ module Bundler end def resolve_with_cache! - raise "Specs already loaded" if @specs sources.cached! - specs + resolve end def resolve_remotely! - return if @specs @remote = true sources.remote! - specs + resolve end # For given dependency list returns a SpecSet with Gemspec of all the required diff --git a/lib/bundler/dependency.rb b/lib/bundler/dependency.rb index af07e8bc36..27206b1bac 100644 --- a/lib/bundler/dependency.rb +++ b/lib/bundler/dependency.rb @@ -96,15 +96,11 @@ module Bundler def gem_platforms(valid_platforms) return valid_platforms if @platforms.empty? - valid_generic_platforms = valid_platforms.map {|p| [p, GemHelpers.generic(p)] }.to_h - @gem_platforms ||= expanded_platforms.compact.uniq - - filtered_generic_platforms = valid_generic_platforms.values & @gem_platforms - valid_generic_platforms.select {|_, v| filtered_generic_platforms.include?(v) }.keys + valid_platforms.select {|p| expanded_platforms.include?(GemHelpers.generic(p)) } end def expanded_platforms - @platforms.map {|pl| PLATFORM_MAP[pl] } + @expanded_platforms ||= @platforms.map {|pl| PLATFORM_MAP[pl] }.compact.uniq end def should_include? diff --git a/lib/bundler/fetcher.rb b/lib/bundler/fetcher.rb index f9c54f7ad2..d237837948 100644 --- a/lib/bundler/fetcher.rb +++ b/lib/bundler/fetcher.rb @@ -47,7 +47,8 @@ module Bundler remote_uri = filter_uri(remote_uri) super "Authentication is required for #{remote_uri}.\n" \ "Please supply credentials for this source. You can do this by running:\n" \ - " bundle config set --global #{remote_uri} username:password" + "`bundle config set --global #{remote_uri} username:password`\n" \ + "or by storing the credentials in the `#{Settings.key_for(remote_uri)}` environment variable" end end # This error is raised if HTTP authentication is provided, but incorrect. diff --git a/lib/bundler/fetcher/compact_index.rb b/lib/bundler/fetcher/compact_index.rb index 0304155bdd..27969d74ec 100644 --- a/lib/bundler/fetcher/compact_index.rb +++ b/lib/bundler/fetcher/compact_index.rb @@ -68,11 +68,16 @@ module Bundler compact_index_request :fetch_spec def available? - return nil unless SharedHelpers.md5_available? - user_home = Bundler.user_home - return nil unless user_home.directory? && user_home.writable? + unless SharedHelpers.md5_available? + Bundler.ui.debug("FIPS mode is enabled, bundler can't use the CompactIndex API") + return nil + end + if fetch_uri.scheme == "file" + Bundler.ui.debug("Using a local server, bundler won't use the CompactIndex API") + return false + end # Read info file checksums out of /versions, so we can know if gems are up to date - fetch_uri.scheme != "file" && compact_index_client.update_and_parse_checksums! + compact_index_client.update_and_parse_checksums! rescue CompactIndexClient::Updater::MisMatchedChecksumError => e Bundler.ui.debug(e.message) nil diff --git a/lib/bundler/fetcher/downloader.rb b/lib/bundler/fetcher/downloader.rb index a2289aaaae..5d30333158 100644 --- a/lib/bundler/fetcher/downloader.rb +++ b/lib/bundler/fetcher/downloader.rb @@ -14,8 +14,10 @@ module Bundler def fetch(uri, headers = {}, counter = 0) raise HTTPError, "Too many redirects" if counter >= redirect_limit + filtered_uri = URICredentialsFilter.credential_filtered_uri(uri) + response = request(uri, headers) - Bundler.ui.debug("HTTP #{response.code} #{response.message} #{uri}") + Bundler.ui.debug("HTTP #{response.code} #{response.message} #{filtered_uri}") case response when Net::HTTPSuccess, Net::HTTPNotModified @@ -40,7 +42,7 @@ module Bundler raise BadAuthenticationError, uri.host if uri.userinfo raise AuthenticationRequiredError, uri.host when Net::HTTPNotFound - raise FallbackError, "Net::HTTPNotFound: #{URICredentialsFilter.credential_filtered_uri(uri)}" + raise FallbackError, "Net::HTTPNotFound: #{filtered_uri}" else raise HTTPError, "#{response.class}#{": #{response.body}" unless response.body.empty?}" end @@ -49,7 +51,9 @@ module Bundler def request(uri, headers) validate_uri_scheme!(uri) - Bundler.ui.debug "HTTP GET #{uri}" + filtered_uri = URICredentialsFilter.credential_filtered_uri(uri) + + Bundler.ui.debug "HTTP GET #{filtered_uri}" req = Net::HTTP::Get.new uri.request_uri, headers if uri.user user = CGI.unescape(uri.user) @@ -69,7 +73,7 @@ module Bundler raise NetworkDownError, "Could not reach host #{uri.host}. Check your network " \ "connection and try again." else - raise HTTPError, "Network error while fetching #{URICredentialsFilter.credential_filtered_uri(uri)}" \ + raise HTTPError, "Network error while fetching #{filtered_uri}" \ " (#{e})" end end diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1 index b17b3aea3c..81cfaa7165 100644 --- a/lib/bundler/man/bundle-config.1 +++ b/lib/bundler/man/bundle-config.1 @@ -199,7 +199,7 @@ The following is a list of all configuration keys and their purpose\. You can le \fBfrozen\fR (\fBBUNDLE_FROZEN\fR): Disallow changes to the \fBGemfile\fR\. When the \fBGemfile\fR is changed and the lockfile has not been updated, running Bundler commands will be blocked\. Defaults to \fBtrue\fR when \fB\-\-deployment\fR is used\. . .IP "\(bu" 4 -\fBgem\.github_username\fR (\fBBUNDLE_GEM__GITHUB_USERNAME\fR): Sets a GitHub username or organization to be used in \fBREADME\fR file when you create a new gem via \fBbundle gem\fR command\. It can be overriden by passing an explicit \fB\-\-github\-username\fR flag to \fBbundle gem\fR\. +\fBgem\.github_username\fR (\fBBUNDLE_GEM__GITHUB_USERNAME\fR): Sets a GitHub username or organization to be used in \fBREADME\fR file when you create a new gem via \fBbundle gem\fR command\. It can be overridden by passing an explicit \fB\-\-github\-username\fR flag to \fBbundle gem\fR\. . .IP "\(bu" 4 \fBgem\.push_key\fR (\fBBUNDLE_GEM__PUSH_KEY\fR): Sets the \fB\-\-key\fR parameter for \fBgem push\fR when using the \fBrake release\fR command with a private gemstash server\. @@ -470,6 +470,23 @@ export BUNDLE_GITHUB__COM=abcd0123generatedtoken:x\-oauth\-basic . .IP "" 0 . +.P +Note that any configured credentials will be redacted by informative commands such as \fBbundle config list\fR or \fBbundle config get\fR, unless you use the \fB\-\-parseable\fR flag\. This is to avoid unintentially leaking credentials when copy\-pasting bundler output\. +. +.P +Also note that to guarantee a sane mapping between valid environment variable names and valid host names, bundler makes the following transformations: +. +.IP "\(bu" 4 +Any \fB\-\fR characters in a host name are mapped to a triple dash (\fB___\fR) in the corresponding enviroment variable\. +. +.IP "\(bu" 4 +Any \fB\.\fR characters in a host name are mapped to a double dash (\fB__\fR) in the corresponding environment variable\. +. +.IP "" 0 +. +.P +This means that if you have a gem server named \fBmy\.gem\-host\.com\fR, you\'ll need to use the \fBBUNDLE_MY__GEM___HOST__COM\fR variable to configure credentials for it through ENV\. +. .SH "CONFIGURE BUNDLER DIRECTORIES" Bundler\'s home, config, cache and plugin directories are able to be configured through environment variables\. The default location for Bundler\'s home directory is \fB~/\.bundle\fR, which all directories inherit from by default\. The following outlines the available environment variables and their default values . diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn index c260561109..b759939d3c 100644 --- a/lib/bundler/man/bundle-config.1.ronn +++ b/lib/bundler/man/bundle-config.1.ronn @@ -196,7 +196,7 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). Defaults to `true` when `--deployment` is used. * `gem.github_username` (`BUNDLE_GEM__GITHUB_USERNAME`): Sets a GitHub username or organization to be used in `README` file when you - create a new gem via `bundle gem` command. It can be overriden by passing an + create a new gem via `bundle gem` command. It can be overridden by passing an explicit `--github-username` flag to `bundle gem`. * `gem.push_key` (`BUNDLE_GEM__PUSH_KEY`): Sets the `--key` parameter for `gem push` when using the `rake release` @@ -376,6 +376,23 @@ where you can use personal OAuth tokens: export BUNDLE_GITHUB__COM=abcd0123generatedtoken:x-oauth-basic +Note that any configured credentials will be redacted by informative commands +such as `bundle config list` or `bundle config get`, unless you use the +`--parseable` flag. This is to avoid unintentially leaking credentials when +copy-pasting bundler output. + +Also note that to guarantee a sane mapping between valid environment variable +names and valid host names, bundler makes the following transformations: + +* Any `-` characters in a host name are mapped to a triple dash (`___`) in the + corresponding enviroment variable. + +* Any `.` characters in a host name are mapped to a double dash (`__`) in the + corresponding environment variable. + +This means that if you have a gem server named `my.gem-host.com`, you'll need to +use the `BUNDLE_MY__GEM___HOST__COM` variable to configure credentials for it +through ENV. ## CONFIGURE BUNDLER DIRECTORIES diff --git a/lib/bundler/plugin.rb b/lib/bundler/plugin.rb index dddb468582..023c25b33e 100644 --- a/lib/bundler/plugin.rb +++ b/lib/bundler/plugin.rb @@ -164,7 +164,7 @@ module Bundler end # To be called from Cli class to pass the command and argument to - # approriate plugin class + # appropriate plugin class def exec_command(command, args) raise UndefinedCommandError, "Command `#{command}` not found" unless command? command @@ -183,7 +183,7 @@ module Bundler !index.source_plugin(name.to_s).nil? end - # @return [Class] that handles the source. The calss includes API::Source + # @return [Class] that handles the source. The class includes API::Source def source(name) raise UnknownSourceError, "Source #{name} not found" unless source? name diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index 69899dc6c3..660385c2ff 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) + 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) @@ -46,9 +46,6 @@ module Bundler @gem_version_promoter = gem_version_promoter @use_gvp = Bundler.feature_flag.use_gem_version_promoter_for_major_updates? || !@gem_version_promoter.major? @no_aggregate_global_source = @source_requirements[:global].nil? - - @variant_specific_names = [] - @generic_names = ["Ruby\0", "RubyGems\0"] end def start(requirements) @@ -112,24 +109,14 @@ module Bundler include Molinillo::SpecificationProvider def dependencies_for(specification) - all_dependencies = specification.dependencies_for_activated_platforms - - if @variant_specific_names.include?(specification.name) - @variant_specific_names |= all_dependencies.map(&:name) - @generic_names - else - generic_names, variant_specific_names = specification.partitioned_dependency_names_for_activated_platforms - @variant_specific_names |= variant_specific_names - @generic_names - @generic_names |= generic_names - end - - all_dependencies + specification.dependencies_for_activated_platforms end def search_for(dependency_proxy) platform = dependency_proxy.__platform dependency = dependency_proxy.dep name = dependency.name - search_result = @search_for[dependency_proxy] ||= begin + @search_for[dependency_proxy] ||= begin results = results_for(dependency, @base[name]) if vertex = @base_dg.vertex_named(name) @@ -181,22 +168,6 @@ module Bundler @gem_version_promoter.sort_versions(dependency, spec_groups) end end - - unless search_result.empty? - specific_dependency = @variant_specific_names.include?(name) - return search_result unless specific_dependency - - search_result.each do |sg| - if @generic_names.include?(name) - @variant_specific_names -= [name] - sg.activate_all_platforms! - else - sg.activate_platform!(platform) - end - end - end - - search_result end def index_for(dependency) diff --git a/lib/bundler/resolver/spec_group.rb b/lib/bundler/resolver/spec_group.rb index 73ffec5838..8f4fd18c46 100644 --- a/lib/bundler/resolver/spec_group.rb +++ b/lib/bundler/resolver/spec_group.rb @@ -21,14 +21,10 @@ module Bundler @version = exemplary_spec.version @source = exemplary_spec.source - @all_platforms = relevant_platforms @activated_platforms = relevant_platforms @dependencies = Hash.new do |dependencies, platforms| dependencies[platforms] = dependencies_for(platforms) end - @partitioned_dependency_names = Hash.new do |partitioned_dependency_names, platforms| - partitioned_dependency_names[platforms] = partitioned_dependency_names_for(platforms) - end @specs = specs end @@ -45,14 +41,6 @@ module Bundler end.flatten.compact.uniq end - def activate_platform!(platform) - self.activated_platforms = [platform] - end - - def activate_all_platforms! - self.activated_platforms = @all_platforms - end - def to_s activated_platforms_string = sorted_activated_platforms.join(", ") "#{name} (#{version}) (#{activated_platforms_string})" @@ -62,10 +50,6 @@ module Bundler @dependencies[activated_platforms] end - def partitioned_dependency_names_for_activated_platforms - @partitioned_dependency_names[activated_platforms] - end - def ==(other) return unless other.is_a?(SpecGroup) name == other.name && @@ -100,14 +84,6 @@ module Bundler end.flatten end - def partitioned_dependency_names_for(platforms) - return @dependencies[platforms].map(&:name), [] if platforms.size == 1 - - @dependencies[platforms].partition do |dep_proxy| - @dependencies[platforms].count {|dp| dp.dep == dep_proxy.dep } == platforms.size - end.map {|deps| deps.map(&:name) } - end - def __dependencies(platform) dependencies = [] @specs[platform].first.dependencies.each do |dep| diff --git a/lib/bundler/retry.rb b/lib/bundler/retry.rb index e95f15f7fb..2415ade200 100644 --- a/lib/bundler/retry.rb +++ b/lib/bundler/retry.rb @@ -49,7 +49,7 @@ module Bundler raise e end return true unless name - Bundler.ui.info "" unless Bundler.ui.debug? # Add new line incase dots preceded this + Bundler.ui.info "" unless Bundler.ui.debug? # Add new line in case dots preceded this Bundler.ui.warn "Retrying #{name} due to error (#{current_run.next}/#{total_runs}): #{e.class} #{e.message}", Bundler.ui.debug? end diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index f59ae37eed..e9155acf48 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -13,6 +13,7 @@ module Bundler auto_install cache_all cache_all_platforms + clean default_install_uses_path deployment disable_checksum_validation @@ -25,11 +26,14 @@ module Bundler force_ruby_platform forget_cli_options frozen + gem.changelog gem.coc gem.mit + git.allow_insecure global_gem_cache ignore_messages init_gems_rb + inline no_install no_prune path_relative_to_cwd @@ -59,6 +63,22 @@ module Bundler without ].freeze + STRING_KEYS = %w[ + bin + cache_path + console + gem.ci + gem.github_username + gem.linter + gem.rubocop + gem.test + gemfile + path + shebang + system_bindir + trust-policy + ].freeze + DEFAULT_CONFIG = { "BUNDLE_SILENCE_DEPRECATIONS" => false, "BUNDLE_DISABLE_VERSION_CHECK" => true, @@ -124,8 +144,8 @@ module Bundler keys = @temporary.keys | @global_config.keys | @local_config.keys | @env_config.keys keys.map do |key| - key.sub(/^BUNDLE_/, "").gsub(/__/, ".").downcase - end + key.sub(/^BUNDLE_/, "").gsub(/___/, "-").gsub(/__/, ".").downcase + end.sort end def local_overrides @@ -171,19 +191,19 @@ module Bundler locations = [] if value = @temporary[key] - locations << "Set for the current command: #{converted_value(value, exposed_key).inspect}" + locations << "Set for the current command: #{printable_value(value, exposed_key).inspect}" end if value = @local_config[key] - locations << "Set for your local app (#{local_config_file}): #{converted_value(value, exposed_key).inspect}" + locations << "Set for your local app (#{local_config_file}): #{printable_value(value, exposed_key).inspect}" end if value = @env_config[key] - locations << "Set via #{key}: #{converted_value(value, exposed_key).inspect}" + locations << "Set via #{key}: #{printable_value(value, exposed_key).inspect}" end if value = @global_config[key] - locations << "Set for the current user (#{global_config_file}): #{converted_value(value, exposed_key).inspect}" + locations << "Set for the current user (#{global_config_file}): #{printable_value(value, exposed_key).inspect}" end return ["You have not configured a value for `#{exposed_key}`"] if locations.empty? @@ -275,9 +295,7 @@ module Bundler end def key_for(key) - key = Settings.normalize_uri(key).to_s if key.is_a?(String) && /https?:/ =~ key - key = key.to_s.gsub(".", "__").upcase - "BUNDLE_#{key}" + self.class.key_for(key) end private @@ -312,6 +330,10 @@ module Bundler BOOL_KEYS.include?(name.to_s) || BOOL_KEYS.include?(parent_setting_for(name.to_s)) end + def is_string(name) + STRING_KEYS.include?(name.to_s) || name.to_s.start_with?("local.") || name.to_s.start_with?("mirror.") || name.to_s.start_with?("build.") + end + def to_bool(value) case value when nil, /\A(false|f|no|n|0|)\z/i, false @@ -329,6 +351,14 @@ module Bundler ARRAY_KEYS.include?(key.to_s) end + def is_credential(key) + key == "gem.push_key" + end + + def is_userinfo(value) + value.include?(":") + end + def to_array(value) return [] unless value value.split(":").map(&:to_sym) @@ -375,6 +405,21 @@ module Bundler end end + def printable_value(value, key) + converted = converted_value(value, key) + return converted unless converted.is_a?(String) + + if is_string(key) + converted + elsif is_credential(key) + "[REDACTED]" + elsif is_userinfo(converted) + converted.gsub(/:.*$/, ":[REDACTED]") + else + converted + end + end + def global_config_file if ENV["BUNDLE_CONFIG"] && !ENV["BUNDLE_CONFIG"].empty? Pathname.new(ENV["BUNDLE_CONFIG"]) @@ -414,6 +459,12 @@ module Bundler \z /ix.freeze + def self.key_for(key) + key = normalize_uri(key).to_s if key.is_a?(String) && /https?:/ =~ key + key = key.to_s.gsub(".", "__").gsub("-", "___").upcase + "BUNDLE_#{key}" + end + # TODO: duplicates Rubygems#normalize_uri # TODO: is this the correct place to validate mirror URIs? def self.normalize_uri(uri) diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index cede580b0a..2b7cfd53b9 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -423,11 +423,11 @@ module Bundler def fetch_names(fetchers, dependency_names, index, override_dupes) fetchers.each do |f| if dependency_names - Bundler.ui.info "Fetching gem metadata from #{f.uri}", Bundler.ui.debug? + Bundler.ui.info "Fetching gem metadata from #{URICredentialsFilter.credential_filtered_uri(f.uri)}", Bundler.ui.debug? index.use f.specs_with_retry(dependency_names, self), override_dupes Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over else - Bundler.ui.info "Fetching source index from #{f.uri}" + Bundler.ui.info "Fetching source index from #{URICredentialsFilter.credential_filtered_uri(f.uri)}" index.use f.specs_with_retry(nil, self), override_dupes end end diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index dfc3114c41..67669cdd0e 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -78,11 +78,17 @@ module Bundler def materialize(deps, missing_specs = nil) materialized = self.for(deps, [], false, true, !missing_specs).to_a - deps = materialized.map(&:name).uniq + + materialized.group_by(&:source).each do |source, specs| + next unless specs.any?{|s| s.is_a?(LazySpecification) } + + source.local! + names = -> { specs.map(&:name).uniq } + source.double_check_for(names) + end + materialized.map! do |s| next s unless s.is_a?(LazySpecification) - s.source.dependency_names = deps if s.source.respond_to?(:dependency_names=) - s.source.local! spec = s.__materialize__ unless spec unless missing_specs @@ -99,12 +105,17 @@ module Bundler # This is in contrast to how for does platform filtering (and specifically different from how `materialize` calls `for` only for the current platform) # @return [Array] def materialized_for_all_platforms - names = @specs.map(&:name).uniq + @specs.group_by(&:source).each do |source, specs| + next unless specs.any?{|s| s.is_a?(LazySpecification) } + + source.local! + source.remote! + names = -> { specs.map(&:name).uniq } + source.double_check_for(names) + end + @specs.map do |s| next s unless s.is_a?(LazySpecification) - s.source.dependency_names = names if s.source.respond_to?(:dependency_names=) - s.source.local! - s.source.remote! spec = s.__materialize__ raise GemNotFound, "Could not find #{s.full_name} in any of the sources" unless spec spec diff --git a/lib/bundler/templates/newgem/newgem.gemspec.tt b/lib/bundler/templates/newgem/newgem.gemspec.tt index 1f2da6d077..d961d615b4 100644 --- a/lib/bundler/templates/newgem/newgem.gemspec.tt +++ b/lib/bundler/templates/newgem/newgem.gemspec.tt @@ -39,6 +39,6 @@ Gem::Specification.new do |spec| # Uncomment to register a new dependency of your gem # spec.add_dependency "example-gem", "~> 1.0" - # For more information and examples about making a new gem, checkout our + # For more information and examples about making a new gem, check out our # guide at: https://bundler.io/guides/creating_gem.html end diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb b/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb index edf2366b7b..eeae79af3c 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Bundler::Molinillo - # Provides information about specifcations and dependencies to the resolver, + # Provides information about specifications and dependencies to the resolver, # allowing the {Resolver} class to remain generic while still providing power # and flexibility. # diff --git a/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb b/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb index 62c82b3dba..90a8d2e847 100644 --- a/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +++ b/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb @@ -252,7 +252,7 @@ class Bundler::Thor # flag:: the regexp or string to be replaced # replacement:: the replacement, can be also given as a block # config:: give :verbose => false to not log the status, and - # :force => true, to force the replacement regardles of runner behavior. + # :force => true, to force the replacement regardless of runner behavior. # # ==== Example # diff --git a/lib/rubygems.rb b/lib/rubygems.rb index 76d86ee6c9..3585defd2d 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -626,7 +626,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} # Try requiring the gem version *or* stdlib version of psych. require 'psych' rescue ::LoadError - # If we can't load psych, thats fine, go on. + # If we can't load psych, that's fine, go on. else # If 'yaml' has already been required, then we have to # be sure to switch it over to the newly loaded psych. diff --git a/lib/rubygems/commands/install_command.rb b/lib/rubygems/commands/install_command.rb index a528ea087e..4d36c69d51 100644 --- a/lib/rubygems/commands/install_command.rb +++ b/lib/rubygems/commands/install_command.rb @@ -130,7 +130,7 @@ You can use `i` command instead of `install`. end def usage # :nodoc: - "#{program_name} GEMNAME [GEMNAME ...] [options] -- --build-flags" + "#{program_name} [options] GEMNAME [GEMNAME ...] -- --build-flags" end def check_install_dir # :nodoc: diff --git a/lib/rubygems/commands/open_command.rb b/lib/rubygems/commands/open_command.rb index 1e40758ec5..8012a9a0e1 100644 --- a/lib/rubygems/commands/open_command.rb +++ b/lib/rubygems/commands/open_command.rb @@ -36,7 +36,7 @@ class Gem::Commands::OpenCommand < Gem::Command end def usage # :nodoc: - "#{program_name} GEMNAME [-e COMMAND]" + "#{program_name} [-e COMMAND] GEMNAME" end def get_env_editor diff --git a/lib/rubygems/commands/yank_command.rb b/lib/rubygems/commands/yank_command.rb index 7e8b66b300..a7930253d6 100644 --- a/lib/rubygems/commands/yank_command.rb +++ b/lib/rubygems/commands/yank_command.rb @@ -24,7 +24,7 @@ data you will need to change them immediately and yank your gem. end def usage # :nodoc: - "#{program_name} GEM -v VERSION [-p PLATFORM] [--key KEY_NAME] [--host HOST]" + "#{program_name} -v VERSION [-p PLATFORM] [--key KEY_NAME] [--host HOST] GEM" end def initialize diff --git a/lib/rubygems/deprecate.rb b/lib/rubygems/deprecate.rb index 67285d4161..8c822cda95 100644 --- a/lib/rubygems/deprecate.rb +++ b/lib/rubygems/deprecate.rb @@ -60,12 +60,13 @@ module Gem::Deprecate target = klass ? "#{self}." : "#{self.class}#" msg = [ "NOTE: #{target}#{name} is deprecated", repl == :none ? " with no replacement" : "; use #{repl} instead", - ". It will be removed on or after %4d-%02d-01." % [year, month], + ". It will be removed on or after %4d-%02d." % [year, month], "\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}", ] warn "#{msg.join}." unless Gem::Deprecate.skip send old, *args, &block end + ruby2_keywords name if respond_to?(:ruby2_keywords, true) end end @@ -90,6 +91,7 @@ module Gem::Deprecate warn "#{msg.join}." unless Gem::Deprecate.skip send old, *args, &block end + ruby2_keywords name if respond_to?(:ruby2_keywords, true) end end diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb index 9448dc7bf3..1067bf7439 100644 --- a/lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb +++ b/lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Gem::Resolver::Molinillo - # Provides information about specifcations and dependencies to the resolver, + # Provides information about specifications and dependencies to the resolver, # allowing the {Resolver} class to remain generic while still providing power # and flexibility. # diff --git a/spec/bundler/bundler/compact_index_client/updater_spec.rb b/spec/bundler/bundler/compact_index_client/updater_spec.rb index cecaddfba4..4acd7dbc63 100644 --- a/spec/bundler/bundler/compact_index_client/updater_spec.rb +++ b/spec/bundler/bundler/compact_index_client/updater_spec.rb @@ -38,7 +38,6 @@ RSpec.describe Bundler::CompactIndexClient::Updater do context "when bundler doesn't have permissions on Dir.tmpdir" do it "Errno::EACCES is raised" do - local_path # create local path before stubbing mktmpdir allow(Bundler::Dir).to receive(:mktmpdir) { raise Errno::EACCES } expect do diff --git a/spec/bundler/bundler/env_spec.rb b/spec/bundler/bundler/env_spec.rb index 2cdead6eac..0dc19d1cf8 100644 --- a/spec/bundler/bundler/env_spec.rb +++ b/spec/bundler/bundler/env_spec.rb @@ -113,6 +113,20 @@ RSpec.describe Bundler::Env do end end + context "when there's bundler config with credentials" do + before do + bundle "config set https://localgemserver.test/ user:pass" + end + + let(:output) { described_class.report(:print_gemfile => true) } + + it "prints the config with redacted values" do + expect(output).to include("https://localgemserver.test") + expect(output).to include("user:[REDACTED]") + expect(output).to_not include("user:pass") + end + end + context "when Gemfile contains a gemspec and print_gemspecs is true" do let(:gemspec) do strip_whitespace(<<-GEMSPEC) diff --git a/spec/bundler/bundler/fetcher/downloader_spec.rb b/spec/bundler/bundler/fetcher/downloader_spec.rb index ba8451d9fa..667f484349 100644 --- a/spec/bundler/bundler/fetcher/downloader_spec.rb +++ b/spec/bundler/bundler/fetcher/downloader_spec.rb @@ -83,6 +83,11 @@ RSpec.describe Bundler::Fetcher::Downloader do /Authentication is required for www.uri-to-fetch.com/) end + it "should raise a Bundler::Fetcher::AuthenticationRequiredError with advices" do + expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::Fetcher::AuthenticationRequiredError, + /`bundle config set --global www\.uri-to-fetch\.com username:password`.*`BUNDLE_WWW__URI___TO___FETCH__COM`/m) + end + context "when the there are credentials provided in the request" do let(:uri) { Bundler::URI("http://user:password@www.uri-to-fetch.com") } diff --git a/spec/bundler/bundler/plugin/dsl_spec.rb b/spec/bundler/bundler/plugin/dsl_spec.rb index be23db3bba..00e39dca69 100644 --- a/spec/bundler/bundler/plugin/dsl_spec.rb +++ b/spec/bundler/bundler/plugin/dsl_spec.rb @@ -28,7 +28,7 @@ RSpec.describe Bundler::Plugin::DSL do expect(dsl.inferred_plugins).to eq(["bundler-source-news"]) end - it "registers a source type plugin only once for multiple declataions" do + it "registers a source type plugin only once for multiple declarations" do expect(dsl).to receive(:plugin).with("bundler-source-news").and_call_original.once dsl.source("some_random_url", :type => "news") {} diff --git a/spec/bundler/bundler/plugin/index_spec.rb b/spec/bundler/bundler/plugin/index_spec.rb index 925dc558ac..e7bde66879 100644 --- a/spec/bundler/bundler/plugin/index_spec.rb +++ b/spec/bundler/bundler/plugin/index_spec.rb @@ -22,7 +22,7 @@ RSpec.describe Bundler::Plugin::Index do expect(index.plugin_path(plugin_name)).to eq(lib_path(plugin_name)) end - it "load_paths is available for retrival" do + it "load_paths is available for retrieval" do expect(index.load_paths(plugin_name)).to eq([lib_path(plugin_name).join("lib").to_s]) end diff --git a/spec/bundler/commands/cache_spec.rb b/spec/bundler/commands/cache_spec.rb index 3b8bce4b01..df027a497a 100644 --- a/spec/bundler/commands/cache_spec.rb +++ b/spec/bundler/commands/cache_spec.rb @@ -211,14 +211,10 @@ RSpec.describe "bundle cache" do end context "with --all-platforms" do - before do - skip "doesn't put gems where it should" if Gem.win_platform? - end - it "puts the gems in vendor/cache even for other rubies" do gemfile <<-D source "#{file_uri_for(gem_repo1)}" - gem 'rack', :platforms => :ruby_19 + gem 'rack', :platforms => [:ruby_20, :x64_mingw_20] D bundle "cache --all-platforms" @@ -236,11 +232,11 @@ RSpec.describe "bundle cache" do bundle "config set --local without wo" install_gemfile <<-G - source "file:#{gem_repo1}" + source "#{file_uri_for(gem_repo1)}" gem "rack" group :wo do gem "weakling" - gem "uninstallable", :source => "file:#{gem_repo4}" + gem "uninstallable", :source => "#{file_uri_for(gem_repo4)}" end G @@ -255,6 +251,21 @@ RSpec.describe "bundle cache" do expect(the_bundle).to include_gem "rack 1.0" expect(the_bundle).not_to include_gems "weakling", "uninstallable" end + + it "does not fail to cache gems in excluded groups when there's a lockfile but gems not previously installed" do + bundle "config set --local without wo" + gemfile <<-G + source "https://my.gem.repo.1" + gem "rack" + group :wo do + gem "weakling" + end + G + + bundle :lock, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s } + bundle :cache, "all-platforms" => true, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s } + expect(bundled_app("vendor/cache/weakling-0.0.3.gem")).to exist + end end context "with frozen configured" do diff --git a/spec/bundler/commands/clean_spec.rb b/spec/bundler/commands/clean_spec.rb index 7c43aaabc4..1889f6a197 100644 --- a/spec/bundler/commands/clean_spec.rb +++ b/spec/bundler/commands/clean_spec.rb @@ -199,7 +199,7 @@ RSpec.describe "bundle clean" do revision = revision_for(git_path) gemfile <<-G - source "file://#{gem_repo1}" + source "#{file_uri_for(gem_repo1)}" gem "rack", "1.0.0" git "#{git_path}", :ref => "#{revision}" do diff --git a/spec/bundler/commands/config_spec.rb b/spec/bundler/commands/config_spec.rb index a7c0813210..2f4488a552 100644 --- a/spec/bundler/commands/config_spec.rb +++ b/spec/bundler/commands/config_spec.rb @@ -408,6 +408,14 @@ E expect(out).to eq "spec_run=true" end + it "list with credentials" do + bundle "config list", :env => { "BUNDLE_GEMS__MYSERVER__COM" => "user:password" } + expect(out).to eq "Settings are listed in order of priority. The top value will be used.\ngems.myserver.com\nSet via BUNDLE_GEMS__MYSERVER__COM: \"user:[REDACTED]\"\n\nspec_run\nSet via BUNDLE_SPEC_RUN: \"true\"" + + bundle "config list", :parseable => true, :env => { "BUNDLE_GEMS__MYSERVER__COM" => "user:password" } + expect(out).to eq "gems.myserver.com=user:password\nspec_run=true" + end + it "get" do ENV["BUNDLE_BAR"] = "bar_val" diff --git a/spec/bundler/commands/outdated_spec.rb b/spec/bundler/commands/outdated_spec.rb index 7c4005824c..b0f0448655 100644 --- a/spec/bundler/commands/outdated_spec.rb +++ b/spec/bundler/commands/outdated_spec.rb @@ -1,24 +1,24 @@ # frozen_string_literal: true RSpec.describe "bundle outdated" do - before :each do - build_repo2 do - build_git "foo", :path => lib_path("foo") - build_git "zebra", :path => lib_path("zebra") + describe "with no arguments" do + before do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "zebra", :git => "#{lib_path("zebra")}" + gem "foo", :git => "#{lib_path("foo")}" + gem "activesupport", "2.3.5" + gem "weakling", "~> 0.0.1" + gem "duradura", '7.0' + gem "terranova", '8' + G end - install_gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - gem "zebra", :git => "#{lib_path("zebra")}" - gem "foo", :git => "#{lib_path("foo")}" - gem "activesupport", "2.3.5" - gem "weakling", "~> 0.0.1" - gem "duradura", '7.0' - gem "terranova", '8' - G - end - - describe "with no arguments" do it "returns a sorted list of outdated gems" do update_repo2 do build_gem "activesupport", "3.0" @@ -102,6 +102,23 @@ RSpec.describe "bundle outdated" do end describe "with --verbose option" do + before do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "zebra", :git => "#{lib_path("zebra")}" + gem "foo", :git => "#{lib_path("foo")}" + gem "activesupport", "2.3.5" + gem "weakling", "~> 0.0.1" + gem "duradura", '7.0' + gem "terranova", '8' + G + end + it "shows the location of the latest version's gemspec if installed" do bundle "config set clean false" @@ -134,8 +151,79 @@ RSpec.describe "bundle outdated" do end end + describe "with multiple, duplicated sources, with lockfile in old format", :bundler => "< 3" do + before do + build_repo2 do + build_gem "dotenv", "2.7.6" + + build_gem "oj", "3.11.3" + build_gem "oj", "3.11.5" + + build_gem "vcr", "6.0.0" + end + + build_repo gem_repo3 do + build_gem "pkg-gem-flowbyte-with-dep", "1.0.0" do |s| + s.add_dependency "oj" + end + end + + gemfile <<~G + source "https://gem.repo2" + + gem "dotenv" + + source "https://gem.repo3" do + gem 'pkg-gem-flowbyte-with-dep' + end + + gem "vcr",source: "https://gem.repo2" + G + + lockfile <<~L + GEM + remote: https://gem.repo2/ + remote: https://gem.repo3/ + specs: + dotenv (2.7.6) + oj (3.11.3) + pkg-gem-flowbyte-with-dep (1.0.0) + oj + vcr (6.0.0) + + PLATFORMS + #{specific_local_platform} + + DEPENDENCIES + dotenv + pkg-gem-flowbyte-with-dep! + vcr! + + BUNDLED WITH + #{Bundler::VERSION} + L + end + + it "works" do + bundle :install, :artifice => :compact_index + bundle :outdated, :artifice => :compact_index, :raise_on_error => false + + expected_output = <<~TABLE + Gem Current Latest Requested Groups + oj 3.11.3 3.11.5 + TABLE + + expect(out).to include(expected_output.strip) + end + end + describe "with --group option" do before do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + end + install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" @@ -201,7 +289,10 @@ RSpec.describe "bundle outdated" do describe "with --groups option and outdated transitive dependencies" do before do - update_repo2 do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + build_gem "bar", %w[2.0.0] build_gem "bar_dependant", "7.0" do |s| @@ -234,6 +325,11 @@ RSpec.describe "bundle outdated" do describe "with --groups option" do before do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + end + install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" @@ -272,6 +368,24 @@ RSpec.describe "bundle outdated" do end describe "with --local option" do + before do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + + gem "weakling", "~> 0.0.1" + gem "terranova", '8' + group :development, :test do + gem 'activesupport', '2.3.5' + gem "duradura", '7.0' + end + G + end + it "uses local cache to return a list of outdated gems" do update_repo2 do build_gem "activesupport", "2.3.4" @@ -305,10 +419,23 @@ RSpec.describe "bundle outdated" do shared_examples_for "a minimal output is desired" do context "and gems are outdated" do before do - update_repo2 do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + build_gem "activesupport", "3.0" build_gem "weakling", "0.2" end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "zebra", :git => "#{lib_path("zebra")}" + gem "foo", :git => "#{lib_path("foo")}" + gem "activesupport", "2.3.5" + gem "weakling", "~> 0.0.1" + gem "duradura", '7.0' + gem "terranova", '8' + G end it "outputs a sorted list of outdated gems with a more minimal format" do @@ -341,6 +468,21 @@ RSpec.describe "bundle outdated" do describe "with specified gems" do it "returns list of outdated gems" do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "zebra", :git => "#{lib_path("zebra")}" + gem "foo", :git => "#{lib_path("foo")}" + gem "activesupport", "2.3.5" + gem "weakling", "~> 0.0.1" + gem "duradura", '7.0' + gem "terranova", '8' + G + update_repo2 do build_gem "activesupport", "3.0" update_git "foo", :path => lib_path("foo") @@ -358,6 +500,23 @@ RSpec.describe "bundle outdated" do end describe "pre-release gems" do + before do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "zebra", :git => "#{lib_path("zebra")}" + gem "foo", :git => "#{lib_path("foo")}" + gem "activesupport", "2.3.5" + gem "weakling", "~> 0.0.1" + gem "duradura", '7.0' + gem "terranova", '8' + G + end + context "without the --pre option" do it "ignores pre-release versions" do update_repo2 do @@ -413,6 +572,23 @@ RSpec.describe "bundle outdated" do filter_strict_option = Bundler.feature_flag.bundler_2_mode? ? :"filter-strict" : :strict describe "with --#{filter_strict_option} option" do + before do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "zebra", :git => "#{lib_path("zebra")}" + gem "foo", :git => "#{lib_path("foo")}" + gem "activesupport", "2.3.5" + gem "weakling", "~> 0.0.1" + gem "duradura", '7.0' + gem "terranova", '8' + G + end + it "only reports gems that have a newer version that matches the specified dependency version requirements" do update_repo2 do build_gem "activesupport", "3.0" @@ -521,6 +697,23 @@ RSpec.describe "bundle outdated" do end describe "with invalid gem name" do + before do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "zebra", :git => "#{lib_path("zebra")}" + gem "foo", :git => "#{lib_path("foo")}" + gem "activesupport", "2.3.5" + gem "weakling", "~> 0.0.1" + gem "duradura", '7.0' + gem "terranova", '8' + G + end + it "returns could not find gem name" do bundle "outdated invalid_gem_name", :raise_on_error => false expect(err).to include("Could not find gem 'invalid_gem_name'.") @@ -546,12 +739,16 @@ RSpec.describe "bundle outdated" do context "after bundle install --deployment", :bundler => "< 3" do before do - install_gemfile <<-G, :deployment => true, :raise_on_error => false + build_repo2 + + gemfile <<-G source "#{file_uri_for(gem_repo2)}" gem "rack" gem "foo" G + bundle :lock + bundle :install, :deployment => true end it "outputs a helpful message about being in deployment mode" do @@ -568,6 +765,11 @@ RSpec.describe "bundle outdated" do context "after bundle config set --local deployment true" do before do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + end + install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" @@ -591,6 +793,8 @@ RSpec.describe "bundle outdated" do context "update available for a gem on a different platform" do before do + build_repo2 + install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" gem "laduradura", '= 5.15.2' @@ -604,6 +808,10 @@ RSpec.describe "bundle outdated" do end context "update available for a gem on the same platform while multiple platforms used for gem" do + before do + build_repo2 + end + it "reports that updates are available if the Ruby platform is used" do install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" @@ -643,6 +851,21 @@ RSpec.describe "bundle outdated" do shared_examples_for "major version updates are detected" do before do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "zebra", :git => "#{lib_path("zebra")}" + gem "foo", :git => "#{lib_path("foo")}" + gem "activesupport", "2.3.5" + gem "weakling", "~> 0.0.1" + gem "duradura", '7.0' + gem "terranova", '8' + G + update_repo2 do build_gem "activesupport", "3.3.5" build_gem "weakling", "0.8.0" @@ -654,6 +877,21 @@ RSpec.describe "bundle outdated" do context "when on a new machine" do before do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "zebra", :git => "#{lib_path("zebra")}" + gem "foo", :git => "#{lib_path("foo")}" + gem "activesupport", "2.3.5" + gem "weakling", "~> 0.0.1" + gem "duradura", '7.0' + gem "terranova", '8' + G + simulate_new_machine update_git "foo", :path => lib_path("foo") @@ -669,6 +907,21 @@ RSpec.describe "bundle outdated" do shared_examples_for "minor version updates are detected" do before do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "zebra", :git => "#{lib_path("zebra")}" + gem "foo", :git => "#{lib_path("foo")}" + gem "activesupport", "2.3.5" + gem "weakling", "~> 0.0.1" + gem "duradura", '7.0' + gem "terranova", '8' + G + update_repo2 do build_gem "activesupport", "2.7.5" build_gem "weakling", "2.0.1" @@ -680,6 +933,21 @@ RSpec.describe "bundle outdated" do shared_examples_for "patch version updates are detected" do before do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "zebra", :git => "#{lib_path("zebra")}" + gem "foo", :git => "#{lib_path("foo")}" + gem "activesupport", "2.3.5" + gem "weakling", "~> 0.0.1" + gem "duradura", '7.0' + gem "terranova", '8' + G + update_repo2 do build_gem "activesupport", "2.3.7" build_gem "weakling", "0.3.1" @@ -698,6 +966,21 @@ RSpec.describe "bundle outdated" do shared_examples_for "major version is ignored" do before do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "zebra", :git => "#{lib_path("zebra")}" + gem "foo", :git => "#{lib_path("foo")}" + gem "activesupport", "2.3.5" + gem "weakling", "~> 0.0.1" + gem "duradura", '7.0' + gem "terranova", '8' + G + update_repo2 do build_gem "activesupport", "3.3.5" build_gem "weakling", "1.0.1" @@ -709,6 +992,21 @@ RSpec.describe "bundle outdated" do shared_examples_for "minor version is ignored" do before do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "zebra", :git => "#{lib_path("zebra")}" + gem "foo", :git => "#{lib_path("foo")}" + gem "activesupport", "2.3.5" + gem "weakling", "~> 0.0.1" + gem "duradura", '7.0' + gem "terranova", '8' + G + update_repo2 do build_gem "activesupport", "2.4.5" build_gem "weakling", "0.3.1" @@ -720,6 +1018,21 @@ RSpec.describe "bundle outdated" do shared_examples_for "patch version is ignored" do before do + build_repo2 do + build_git "foo", :path => lib_path("foo") + build_git "zebra", :path => lib_path("zebra") + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "zebra", :git => "#{lib_path("zebra")}" + gem "foo", :git => "#{lib_path("foo")}" + gem "activesupport", "2.3.5" + gem "weakling", "~> 0.0.1" + gem "duradura", '7.0' + gem "terranova", '8' + G + update_repo2 do build_gem "activesupport", "2.3.6" build_gem "weakling", "0.0.4" diff --git a/spec/bundler/commands/pristine_spec.rb b/spec/bundler/commands/pristine_spec.rb index 6978f302c1..2f730bd4e2 100644 --- a/spec/bundler/commands/pristine_spec.rb +++ b/spec/bundler/commands/pristine_spec.rb @@ -203,6 +203,16 @@ RSpec.describe "bundle pristine", :ruby_repo do end end + context "when BUNDLE_GEMFILE doesn't exist" do + before do + bundle "pristine", :env => { "BUNDLE_GEMFILE" => "does/not/exist" }, :raise_on_error => false + end + + it "shows a meaningful error" do + expect(err).to eq("#{bundled_app("does/not/exist")} not found") + end + end + def find_spec(name) without_env_side_effects do Bundler.definition.specs[name].first diff --git a/spec/bundler/commands/remove_spec.rb b/spec/bundler/commands/remove_spec.rb index 46c42fea10..170545f80c 100644 --- a/spec/bundler/commands/remove_spec.rb +++ b/spec/bundler/commands/remove_spec.rb @@ -229,7 +229,7 @@ RSpec.describe "bundle remove" do end end - context "when the gem is present in mutiple groups" do + context "when the gem is present in multiple groups" do it "removes all empty blocks" do gemfile <<-G source "#{file_uri_for(gem_repo1)}" @@ -333,7 +333,7 @@ RSpec.describe "bundle remove" do end describe "arbitrary gemfile" do - context "when mutiple gems are present in same line" do + context "when multiple gems are present in same line" do it "shows warning for gems not removed" do install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb index 0f17d931a3..51a0b925a3 100644 --- a/spec/bundler/commands/update_spec.rb +++ b/spec/bundler/commands/update_spec.rb @@ -1,18 +1,18 @@ # frozen_string_literal: true RSpec.describe "bundle update" do - before :each do - build_repo2 + describe "with no arguments" do + before do + build_repo2 - install_gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - gem "activesupport" - gem "rack-obama" - gem "platform_specific" - G - end + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "activesupport" + gem "rack-obama" + gem "platform_specific" + G + end - describe "with no arguments", :bundler => "< 3" do it "updates the entire bundle" do update_repo2 do build_gem "rack", "1.2" do |s| @@ -39,7 +39,18 @@ RSpec.describe "bundle update" do end end - describe "with --all", :bundler => "3" do + describe "with --all" do + before do + build_repo2 + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "activesupport" + gem "rack-obama" + gem "platform_specific" + G + end + it "updates the entire bundle" do update_repo2 do build_gem "rack", "1.2" do |s| @@ -55,6 +66,8 @@ RSpec.describe "bundle update" do end it "doesn't delete the Gemfile.lock file if something goes wrong" do + install_gemfile "" + gemfile <<-G source "#{file_uri_for(gem_repo2)}" gem "activesupport" @@ -102,6 +115,17 @@ RSpec.describe "bundle update" do end describe "--quiet argument" do + before do + build_repo2 + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "activesupport" + gem "rack-obama" + gem "platform_specific" + G + end + it "hides UI messages" do bundle "update --quiet" expect(out).not_to include("Bundle updated!") @@ -109,6 +133,17 @@ RSpec.describe "bundle update" do end describe "with a top level dependency" do + before do + build_repo2 + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "activesupport" + gem "rack-obama" + gem "platform_specific" + G + end + it "unlocks all child dependencies that are unrelated to other locked dependencies" do update_repo2 do build_gem "rack", "1.2" do |s| @@ -124,6 +159,17 @@ RSpec.describe "bundle update" do end describe "with an unknown dependency" do + before do + build_repo2 + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "activesupport" + gem "rack-obama" + gem "platform_specific" + G + end + it "should inform the user" do bundle "update halting-problem-solver", :raise_on_error => false expect(err).to include "Could not find gem 'halting-problem-solver'" @@ -135,6 +181,17 @@ RSpec.describe "bundle update" do end describe "with a child dependency" do + before do + build_repo2 + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "activesupport" + gem "rack-obama" + gem "platform_specific" + G + end + it "should update the child dependency" do update_repo2 do build_gem "rack", "1.2" do |s| @@ -212,6 +269,17 @@ RSpec.describe "bundle update" do end describe "with --local option" do + before do + build_repo2 + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "activesupport" + gem "rack-obama" + gem "platform_specific" + G + end + it "doesn't hit repo2" do FileUtils.rm_rf(gem_repo2) @@ -221,6 +289,10 @@ RSpec.describe "bundle update" do end describe "with --group option" do + before do + build_repo2 + end + it "should update only specified group gems" do install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" @@ -257,7 +329,7 @@ RSpec.describe "bundle update" do end context "when there is a source with the same name as a gem in a group" do - before :each do + before do build_git "foo", :path => lib_path("activesupport") install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" @@ -299,6 +371,17 @@ RSpec.describe "bundle update" do end describe "in a frozen bundle" do + before do + build_repo2 + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "activesupport" + gem "rack-obama" + gem "platform_specific" + G + end + it "should fail loudly", :bundler => "< 3" do bundle "install --deployment" bundle "update", :all => true, :raise_on_error => false @@ -324,6 +407,10 @@ RSpec.describe "bundle update" do end describe "with --source option" do + before do + build_repo2 + end + it "should not update gems not included in the source that happen to have the same name", :bundler => "< 3" do install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" @@ -449,10 +536,130 @@ RSpec.describe "bundle update" do expect(the_bundle).to include_gems "harry 1.0", "fred 1.0", "george 1.0" end end + + it "shows the previous version of the gem when updated from rubygems source", :bundler => "< 3" do + build_repo2 + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "activesupport" + G + + bundle "update", :all => true + expect(out).to include("Using activesupport 2.3.5") + + update_repo2 do + build_gem "activesupport", "3.0" + end + + bundle "update", :all => true + expect(out).to include("Installing activesupport 3.0 (was 2.3.5)") + end + + context "with suppress_install_using_messages set" do + before { bundle "config set suppress_install_using_messages true" } + + it "only prints `Using` for versions that have changed" do + build_repo4 do + build_gem "bar" + build_gem "foo" + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem "bar" + gem "foo" + G + + bundle "update", :all => true + expect(out).to match(/Resolving dependencies\.\.\.\.*\nBundle updated!/) + + update_repo4 do + build_gem "foo", "2.0" + end + + bundle "update", :all => true + out.sub!("Removing foo (1.0)\n", "") + expect(out).to match(/Resolving dependencies\.\.\.\.*\nFetching foo 2\.0 \(was 1\.0\)\nInstalling foo 2\.0 \(was 1\.0\)\nBundle updated/) + end + end + + it "shows error message when Gemfile.lock is not preset and gem is specified" do + gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "activesupport" + G + + bundle "update nonexisting", :raise_on_error => false + expect(err).to include("This Bundle hasn't been installed yet. Run `bundle install` to update and install the bundled gems.") + expect(exitstatus).to eq(22) + end + + context "with multiple, duplicated sources, with lockfile in old format", :bundler => "< 3" do + before do + build_repo2 do + build_gem "dotenv", "2.7.6" + + build_gem "oj", "3.11.3" + build_gem "oj", "3.11.5" + + build_gem "vcr", "6.0.0" + end + + build_repo gem_repo3 do + build_gem "pkg-gem-flowbyte-with-dep", "1.0.0" do |s| + s.add_dependency "oj" + end + end + + gemfile <<~G + source "https://gem.repo2" + + gem "dotenv" + + source "https://gem.repo3" do + gem 'pkg-gem-flowbyte-with-dep' + end + + gem "vcr",source: "https://gem.repo2" + G + + lockfile <<~L + GEM + remote: https://gem.repo2/ + remote: https://gem.repo3/ + specs: + dotenv (2.7.6) + oj (3.11.3) + pkg-gem-flowbyte-with-dep (1.0.0) + oj + vcr (6.0.0) + + PLATFORMS + #{specific_local_platform} + + DEPENDENCIES + dotenv + pkg-gem-flowbyte-with-dep! + vcr! + + BUNDLED WITH + #{Bundler::VERSION} + L + end + + it "works" do + bundle :install, :artifice => :compact_index + bundle "update oj", :artifice => :compact_index + + expect(out).to include("Bundle updated!") + expect(the_bundle).to include_gems "oj 3.11.5" + end + end end RSpec.describe "bundle update in more complicated situations" do - before :each do + before do build_repo2 end @@ -640,7 +847,7 @@ RSpec.describe "bundle update without a Gemfile.lock" do end RSpec.describe "bundle update when a gem depends on a newer version of bundler" do - before(:each) do + before do build_repo2 do build_gem "rails", "3.0.1" do |s| s.add_dependency "bundler", Bundler::VERSION.succ @@ -663,66 +870,6 @@ RSpec.describe "bundle update when a gem depends on a newer version of bundler" end end -RSpec.describe "bundle update" do - it "shows the previous version of the gem when updated from rubygems source", :bundler => "< 3" do - build_repo2 - - install_gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - gem "activesupport" - G - - bundle "update", :all => true - expect(out).to include("Using activesupport 2.3.5") - - update_repo2 do - build_gem "activesupport", "3.0" - end - - bundle "update", :all => true - expect(out).to include("Installing activesupport 3.0 (was 2.3.5)") - end - - context "with suppress_install_using_messages set" do - before { bundle "config set suppress_install_using_messages true" } - - it "only prints `Using` for versions that have changed" do - build_repo4 do - build_gem "bar" - build_gem "foo" - end - - install_gemfile <<-G - source "#{file_uri_for(gem_repo4)}" - gem "bar" - gem "foo" - G - - bundle "update", :all => true - expect(out).to match(/Resolving dependencies\.\.\.\.*\nBundle updated!/) - - update_repo4 do - build_gem "foo", "2.0" - end - - bundle "update", :all => true - out.sub!("Removing foo (1.0)\n", "") - expect(out).to match(/Resolving dependencies\.\.\.\.*\nFetching foo 2\.0 \(was 1\.0\)\nInstalling foo 2\.0 \(was 1\.0\)\nBundle updated/) - end - end - - it "shows error message when Gemfile.lock is not preset and gem is specified" do - gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - gem "activesupport" - G - - bundle "update nonexisting", :raise_on_error => false - expect(err).to include("This Bundle hasn't been installed yet. Run `bundle install` to update and install the bundled gems.") - expect(exitstatus).to eq(22) - end -end - RSpec.describe "bundle update --ruby" do before do install_gemfile <<-G diff --git a/spec/bundler/install/gemfile/gemspec_spec.rb b/spec/bundler/install/gemfile/gemspec_spec.rb index ec6a1d4a4a..32dd7d24b8 100644 --- a/spec/bundler/install/gemfile/gemspec_spec.rb +++ b/spec/bundler/install/gemfile/gemspec_spec.rb @@ -567,4 +567,57 @@ RSpec.describe "bundle install from an existing gemspec" do expect(the_bundle).not_to include_gem "rack" end end + + context "with multiple platforms and resolving for more specific platforms" do + before do + build_lib("chef", :path => tmp.join("chef")) do |s| + s.version = "17.1.17" + s.write "chef-universal-mingw32.gemspec", build_spec("chef", "17.1.17", "universal-mingw32") {|sw| sw.runtime "win32-api", "~> 1.5.3" }.first.to_ruby + end + end + + it "does not remove the platform specific specs from the lockfile when updating" do + build_repo4 do + build_gem "win32-api", "1.5.3" do |s| + s.platform = "universal-mingw32" + end + end + + gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gemspec :path => "../chef" + G + + initial_lockfile = <<~L + PATH + remote: ../chef + specs: + chef (17.1.17) + chef (17.1.17-universal-mingw32) + win32-api (~> 1.5.3) + + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + win32-api (1.5.3-universal-mingw32) + + PLATFORMS + ruby + x64-mingw32 + x86-mingw32 + + DEPENDENCIES + chef! + + BUNDLED WITH + #{Bundler::VERSION} + L + + lockfile initial_lockfile + + bundle "update" + + expect(lockfile).to eq initial_lockfile + end + end end diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb index d86bc18311..4f931a493b 100644 --- a/spec/bundler/install/gemfile/sources_spec.rb +++ b/spec/bundler/install/gemfile/sources_spec.rb @@ -90,7 +90,7 @@ RSpec.describe "bundle install with gems on multiple sources" do gem "thin" # comes first to test name sorting gem "rack" end - gem "rack-obama" # shoud come from repo3! + gem "rack-obama" # should come from repo3! G end @@ -596,7 +596,7 @@ RSpec.describe "bundle install with gems on multiple sources" do L end - it "it keeps the currrent lockfile format and upgrades the requested gem when running bundle update with an argument, and warns", :bundler => "< 3" do + it "it keeps the current lockfile format and upgrades the requested gem when running bundle update with an argument, and warns", :bundler => "< 3" do bundle "update concurrent-ruby" expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") @@ -921,7 +921,7 @@ RSpec.describe "bundle install with gems on multiple sources" do install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "rack" # shoud come from repo1! + gem "rack" # should come from repo1! G end @@ -974,7 +974,10 @@ RSpec.describe "bundle install with gems on multiple sources" do context "re-resolving" do context "when there is a mix of sources in the gemfile" do before do - build_repo3 + build_repo gem_repo3 do + build_gem "rack" + end + build_lib "path1" build_lib "path2" build_git "git1" diff --git a/spec/bundler/install/gems/compact_index_spec.rb b/spec/bundler/install/gems/compact_index_spec.rb index 92cbd26b88..9454508e41 100644 --- a/spec/bundler/install/gems/compact_index_spec.rb +++ b/spec/bundler/install/gems/compact_index_spec.rb @@ -614,6 +614,17 @@ The checksum of /versions does not match the checksum provided by the server! So expect(the_bundle).to include_gems "rack 1.0.0" end + it "passes basic authentication details and strips out creds also in verbose mode" do + gemfile <<-G + source "#{basic_auth_source_uri}" + gem "rack" + G + + bundle :install, :verbose => true, :artifice => "compact_index_basic_authentication" + expect(out).not_to include("#{user}:#{password}") + expect(the_bundle).to include_gems "rack 1.0.0" + end + it "strips http basic auth creds when warning about ambiguous sources", :bundler => "< 3" do gemfile <<-G source "#{basic_auth_source_uri}" @@ -815,6 +826,28 @@ The checksum of /versions does not match the checksum provided by the server! So expect(the_bundle).to include_gems "rack 1.0.0" end + it "performs full update if server endpoints serve partial content responses but don't have incremental content and provide no Etag" do + build_repo4 do + build_gem "rack", "0.9.1" + end + + install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + source "#{source_uri}" + gem 'rack', '0.9.1' + G + + update_repo4 do + build_gem "rack", "1.0.0" + end + + install_gemfile <<-G, :artifice => "compact_index_partial_update_no_etag_not_incremental", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + source "#{source_uri}" + gem 'rack', '1.0.0' + G + + expect(the_bundle).to include_gems "rack 1.0.0" + end + it "performs full update of compact index info cache if range is not satisfiable" do gemfile <<-G source "#{source_uri}" diff --git a/spec/bundler/install/gems/dependency_api_spec.rb b/spec/bundler/install/gems/dependency_api_spec.rb index c23323682d..d8d2ac1668 100644 --- a/spec/bundler/install/gems/dependency_api_spec.rb +++ b/spec/bundler/install/gems/dependency_api_spec.rb @@ -586,6 +586,17 @@ RSpec.describe "gemcutter's dependency API" do expect(the_bundle).to include_gems "rack 1.0.0" end + it "passes basic authentication details and strips out creds also in verbose mode" do + gemfile <<-G + source "#{basic_auth_source_uri}" + gem "rack" + G + + bundle :install, :verbose => true, :artifice => "endpoint_basic_authentication" + expect(out).not_to include("#{user}:#{password}") + expect(the_bundle).to include_gems "rack 1.0.0" + end + it "strips http basic authentication creds for modern index" do gemfile <<-G source "#{basic_auth_source_uri}" @@ -630,6 +641,22 @@ RSpec.describe "gemcutter's dependency API" do expect(the_bundle).to include_gems "rack 1.0.0" end + describe "with host including dashes" do + before do + gemfile <<-G + source "http://local-gemserver.test" + gem "rack" + G + end + + it "reads authentication details from a valid ENV variable" do + bundle :install, :artifice => "endpoint_strict_basic_authentication", :env => { "BUNDLE_LOCAL___GEMSERVER__TEST" => "#{user}:#{password}" } + + expect(out).to include("Fetching gem metadata from http://local-gemserver.test") + expect(the_bundle).to include_gems "rack 1.0.0" + end + end + describe "with authentication details in bundle config" do before do gemfile <<-G diff --git a/spec/bundler/install/gems/post_install_spec.rb b/spec/bundler/install/gems/post_install_spec.rb index 3f6d7ce42c..7426f54877 100644 --- a/spec/bundler/install/gems/post_install_spec.rb +++ b/spec/bundler/install/gems/post_install_spec.rb @@ -33,7 +33,7 @@ RSpec.describe "bundle install" do end end - context "when a dependecy includes a post install message" do + context "when a dependency includes a post install message" do it "should display the post install message" do gemfile <<-G source "#{file_uri_for(gem_repo1)}" diff --git a/spec/bundler/install/prereleases_spec.rb b/spec/bundler/install/prereleases_spec.rb index c3f968ad70..629eb89dac 100644 --- a/spec/bundler/install/prereleases_spec.rb +++ b/spec/bundler/install/prereleases_spec.rb @@ -38,7 +38,11 @@ RSpec.describe "bundle install" do describe "when prerelease gems are not available" do it "still works" do - build_repo3 + build_repo gem_repo3 do + build_gem "rack" + end + FileUtils.rm_rf Dir[gem_repo3("prerelease*")] + install_gemfile <<-G source "#{file_uri_for(gem_repo3)}" gem "rack" diff --git a/spec/bundler/quality_spec.rb b/spec/bundler/quality_spec.rb index dcdbf61f52..08ec8bed5c 100644 --- a/spec/bundler/quality_spec.rb +++ b/spec/bundler/quality_spec.rb @@ -170,9 +170,16 @@ RSpec.describe "The library itself" do it "documents all used settings" do exemptions = %w[ forget_cli_options + gem.changelog + gem.ci gem.coc + gem.linter gem.mit + gem.rubocop + gem.test + git.allow_insecure inline + trust-policy use_gem_version_promoter_for_major_updates ] @@ -182,6 +189,7 @@ RSpec.describe "The library itself" do Bundler::Settings::BOOL_KEYS.each {|k| all_settings[k] << "in Bundler::Settings::BOOL_KEYS" } Bundler::Settings::NUMBER_KEYS.each {|k| all_settings[k] << "in Bundler::Settings::NUMBER_KEYS" } Bundler::Settings::ARRAY_KEYS.each {|k| all_settings[k] << "in Bundler::Settings::ARRAY_KEYS" } + Bundler::Settings::STRING_KEYS.each {|k| all_settings[k] << "in Bundler::Settings::STRING_KEYS" } key_pattern = /([a-z\._-]+)/i lib_tracked_files.each do |filename| @@ -215,7 +223,7 @@ RSpec.describe "The library itself" do end it "ships the correct set of files" do - git_list = git_ls_files(ruby_core? ? "lib/bundler lib/bundler.rb man/bundle* man/gemfile* libexec/bundle*" : "lib man exe CHANGELOG.md LICENSE.md README.md bundler.gemspec") + git_list = git_ls_files(ruby_core? ? "lib/bundler lib/bundler.rb libexec/bundle*" : "lib exe CHANGELOG.md LICENSE.md README.md bundler.gemspec") gem_list = loaded_gemspec.files diff --git a/spec/bundler/realworld/edgecases_spec.rb b/spec/bundler/realworld/edgecases_spec.rb index 1925f76c06..9f6ae399af 100644 --- a/spec/bundler/realworld/edgecases_spec.rb +++ b/spec/bundler/realworld/edgecases_spec.rb @@ -349,14 +349,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" 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 +461,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" gemfile <<~G source 'https://rubygems.org' @@ -487,7 +487,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" gemfile <<~G source "https://rubygems.org" do diff --git a/spec/bundler/runtime/inline_spec.rb b/spec/bundler/runtime/inline_spec.rb index bad1df93a9..57b7392608 100644 --- a/spec/bundler/runtime/inline_spec.rb +++ b/spec/bundler/runtime/inline_spec.rb @@ -293,7 +293,7 @@ RSpec.describe "bundler/inline#gemfile" do it "installs inline gems to the system path regardless" do script <<-RUBY, :env => { "BUNDLE_PATH" => "./vendor/inline" } gemfile(true) do - source "file://#{gem_repo1}" + source "#{file_uri_for(gem_repo1)}" gem "rack" end RUBY diff --git a/spec/bundler/spec_helper.rb b/spec/bundler/spec_helper.rb index 99be2f4df8..dc4121cb70 100644 --- a/spec/bundler/spec_helper.rb +++ b/spec/bundler/spec_helper.rb @@ -4,7 +4,6 @@ require "bundler/psyched_yaml" require "bundler/vendored_fileutils" require "bundler/vendored_uri" require "digest" -require "tmpdir" if File.expand_path(__FILE__) =~ %r{([^\w/\.:\-])} abort "The bundler specs cannot be run from a path that contains special characters (particularly #{$1.inspect})" @@ -74,6 +73,7 @@ RSpec.configure do |config| Spec::Rubygems.test_setup ENV["BUNDLE_SPEC_RUN"] = "true" ENV["BUNDLE_USER_CONFIG"] = ENV["BUNDLE_USER_CACHE"] = ENV["BUNDLE_USER_PLUGIN"] = nil + ENV["XDG_CONFIG_HOME"] = nil ENV["GEMRC"] = nil # Don't wrap output in tests @@ -111,16 +111,6 @@ RSpec.configure do |config| end end - config.around :each do |example| - Dir.mktmpdir("bundler_commands_console") do |dir| - xdg_config_home_backup = ENV.delete("XDG_CONFIG_HOME") - ENV["XDG_CONFIG_HOME"] = dir - example.run - ensure - ENV["XDG_CONFIG_HOME"] = xdg_config_home_backup - end - end - config.after :suite do FileUtils.rm_r Spec::Path.pristine_system_gem_path end diff --git a/spec/bundler/support/artifice/compact_index.rb b/spec/bundler/support/artifice/compact_index.rb index 5cf3a79f29..1b314e89ef 100644 --- a/spec/bundler/support/artifice/compact_index.rb +++ b/spec/bundler/support/artifice/compact_index.rb @@ -62,7 +62,7 @@ class CompactIndexAPI < Endpoint body.byteslice(range) end - def gems(gem_repo = GEM_REPO) + def gems(gem_repo = default_gem_repo) @gems ||= {} @gems[gem_repo] ||= begin specs = Bundler::Deprecate.skip_during do @@ -80,7 +80,7 @@ class CompactIndexAPI < Endpoint CompactIndex::Dependency.new(d.name, reqs) end checksum = begin - Digest(:SHA256).file("#{GEM_REPO}/gems/#{spec.original_name}.gem").base64digest + Digest(:SHA256).file("#{gem_repo}/gems/#{spec.original_name}.gem").base64digest rescue StandardError nil end diff --git a/spec/bundler/support/artifice/compact_index_partial_update_no_etag_not_incremental.rb b/spec/bundler/support/artifice/compact_index_partial_update_no_etag_not_incremental.rb new file mode 100644 index 0000000000..acf76dfbf0 --- /dev/null +++ b/spec/bundler/support/artifice/compact_index_partial_update_no_etag_not_incremental.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require_relative "compact_index" + +Artifice.deactivate + +class CompactIndexPartialUpdateNoEtagNotIncremental < CompactIndexAPI + def partial_update_no_etag + response_body = yield + headers "Surrogate-Control" => "max-age=2592000, stale-while-revalidate=60" + content_type "text/plain" + requested_range_for(response_body) + end + + get "/versions" do + partial_update_no_etag do + file = tmp("versions.list") + FileUtils.rm_f(file) + file = CompactIndex::VersionsFile.new(file.to_s) + file.create(gems) + lines = file.contents([], :calculate_info_checksums => true).split("\n") + name, versions, checksum = lines.last.split(" ") + + # shuffle versions so new versions are not appended to the end + [*lines[0..-2], [name, versions.split(",").reverse.join(","), checksum].join(" ")].join("\n") + end + end + + get "/info/:name" do + partial_update_no_etag do + gem = gems.find {|g| g.name == params[:name] } + lines = CompactIndex.info(gem ? gem.versions : []).split("\n") + + # shuffle versions so new versions are not appended to the end + [lines.first, lines.last, *lines[1..-2]].join("\n") + end + end +end + +Artifice.activate_with(CompactIndexPartialUpdateNoEtagNotIncremental) diff --git a/spec/bundler/support/artifice/endpoint.rb b/spec/bundler/support/artifice/endpoint.rb index 1dc7101389..e0650fa7d5 100644 --- a/spec/bundler/support/artifice/endpoint.rb +++ b/spec/bundler/support/artifice/endpoint.rb @@ -26,7 +26,6 @@ class Endpoint < Sinatra::Base @all_requests ||= [] end - GEM_REPO = Pathname.new(ENV["BUNDLER_SPEC_GEM_REPO"] || Spec::Path.gem_repo1) set :raise_errors, true set :show_exceptions, false @@ -41,7 +40,22 @@ class Endpoint < Sinatra::Base helpers do include Spec::Path - def dependencies_for(gem_names, gem_repo = GEM_REPO) + def default_gem_repo + if ENV["BUNDLER_SPEC_GEM_REPO"] + Pathname.new(ENV["BUNDLER_SPEC_GEM_REPO"]) + else + case request.host + when "gem.repo2" + Spec::Path.gem_repo2 + when "gem.repo3" + Spec::Path.gem_repo3 + else + Spec::Path.gem_repo1 + end + end + end + + def dependencies_for(gem_names, gem_repo = default_gem_repo) return [] if gem_names.nil? || gem_names.empty? all_specs = %w[specs.4.8 prerelease_specs.4.8].map do |filename| @@ -74,11 +88,11 @@ class Endpoint < Sinatra::Base end get "/fetch/actual/gem/:id" do - File.binread("#{GEM_REPO}/quick/Marshal.4.8/#{params[:id]}") + File.binread("#{default_gem_repo}/quick/Marshal.4.8/#{params[:id]}") end get "/gems/:id" do - File.binread("#{GEM_REPO}/gems/#{params[:id]}") + File.binread("#{default_gem_repo}/gems/#{params[:id]}") end get "/api/v1/dependencies" do @@ -86,11 +100,11 @@ class Endpoint < Sinatra::Base end get "/specs.4.8.gz" do - File.binread("#{GEM_REPO}/specs.4.8.gz") + File.binread("#{default_gem_repo}/specs.4.8.gz") end get "/prerelease_specs.4.8.gz" do - File.binread("#{GEM_REPO}/prerelease_specs.4.8.gz") + File.binread("#{default_gem_repo}/prerelease_specs.4.8.gz") end end diff --git a/spec/bundler/support/artifice/windows.rb b/spec/bundler/support/artifice/windows.rb index f5b4baae30..ddbbd62b96 100644 --- a/spec/bundler/support/artifice/windows.rb +++ b/spec/bundler/support/artifice/windows.rb @@ -14,7 +14,7 @@ class Windows < Sinatra::Base set :show_exceptions, false helpers do - def gem_repo + def default_gem_repo Pathname.new(ENV["BUNDLER_SPEC_GEM_REPO"] || Spec::Path.gem_repo1) end end @@ -26,7 +26,7 @@ class Windows < Sinatra::Base files.each do |file| get "/#{file}" do - File.binread gem_repo.join(file) + File.binread default_gem_repo.join(file) end end diff --git a/spec/bundler/support/builders.rb b/spec/bundler/support/builders.rb index d593ced27e..25377d2ac2 100644 --- a/spec/bundler/support/builders.rb +++ b/spec/bundler/support/builders.rb @@ -192,13 +192,6 @@ module Spec update_repo2(&blk) if block_given? end - def build_repo3 - build_repo gem_repo3 do - build_gem "rack" - end - FileUtils.rm_rf Dir[gem_repo3("prerelease*")] - end - # A repo that has no pre-installed gems included. (The caller completely # determines the contents with the block.) def build_repo4(&blk) diff --git a/spec/bundler/support/helpers.rb b/spec/bundler/support/helpers.rb index d896b5276e..6fb0c6cb1c 100644 --- a/spec/bundler/support/helpers.rb +++ b/spec/bundler/support/helpers.rb @@ -87,9 +87,11 @@ module Spec env = options.delete(:env) || {} requires = options.delete(:requires) || [] + realworld = RSpec.current_example.metadata[:realworld] + options[:verbose] = true if options[:verbose].nil? && realworld artifice = options.delete(:artifice) do - if RSpec.current_example.metadata[:realworld] + if realworld "vcr" else "fail" diff --git a/spec/bundler/support/rubygems_ext.rb b/spec/bundler/support/rubygems_ext.rb index ea774429c9..9389543a0f 100644 --- a/spec/bundler/support/rubygems_ext.rb +++ b/spec/bundler/support/rubygems_ext.rb @@ -98,7 +98,7 @@ module Spec gem_activate(gem_name) load Gem.bin_path(gem_name, bin_container) rescue Gem::LoadError => e - abort "We couln't activate #{gem_name} (#{e.requirement}). Run `gem install #{gem_name}:'#{e.requirement}'`" + abort "We couldn't activate #{gem_name} (#{e.requirement}). Run `gem install #{gem_name}:'#{e.requirement}'`" end def gem_activate(gem_name) diff --git a/test/rubygems/test_deprecate.rb b/test/rubygems/test_deprecate.rb index 5f8eef76cb..dc282dd8fb 100644 --- a/test/rubygems/test_deprecate.rb +++ b/test/rubygems/test_deprecate.rb @@ -49,6 +49,22 @@ class TestDeprecate < Gem::TestCase @message = "bar" end rubygems_deprecate :foo, :bar + + def foo_arg(msg) + @message = "foo" + msg + end + def bar_arg(msg) + @message = "bar" + msg + end + rubygems_deprecate :foo_arg, :bar_arg + + def foo_kwarg(message:) + @message = "foo" + message + end + def bar_kwarg(message:) + @message = "bar" + message + end + rubygems_deprecate :foo_kwarg, :bar_kwarg end class OtherThing @@ -61,6 +77,22 @@ class TestDeprecate < Gem::TestCase @message = "bar" end deprecate :foo, :bar, 2099, 3 + + def foo_arg(msg) + @message = "foo" + msg + end + def bar_arg(msg) + @message = "bar" + msg + end + deprecate :foo_arg, :bar_arg, 2099, 3 + + def foo_kwarg(message:) + @message = "foo" + message + end + def bar_kwarg(message:) + @message = "bar" + message + end + deprecate :foo_kwarg, :bar_kwarg, 2099, 3 end def test_deprecated_method_calls_the_old_method @@ -68,6 +100,10 @@ class TestDeprecate < Gem::TestCase thing = Thing.new thing.foo assert_equal "foo", thing.message + thing.foo_arg("msg") + assert_equal "foomsg", thing.message + thing.foo_kwarg(message: "msg") + assert_equal "foomsg", thing.message end end @@ -75,10 +111,14 @@ class TestDeprecate < Gem::TestCase out, err = capture_io do thing = Thing.new thing.foo + thing.foo_arg("msg") + thing.foo_kwarg(message: "msg") end assert_equal "", out assert_match(/Thing#foo is deprecated; use bar instead\./, err) + assert_match(/Thing#foo_arg is deprecated; use bar_arg instead\./, err) + assert_match(/Thing#foo_kwarg is deprecated; use bar_kwarg instead\./, err) assert_match(/in Rubygems [0-9]+/, err) end @@ -104,10 +144,14 @@ class TestDeprecate < Gem::TestCase out, err = capture_io do thing = OtherThing.new thing.foo + thing.foo_arg("msg") + thing.foo_kwarg(message: "msg") end assert_equal "", out - assert_match(/Thing#foo is deprecated; use bar instead\./, err) - assert_match(/on or after 2099-03-01/, err) + assert_match(/OtherThing#foo is deprecated; use bar instead\./, err) + assert_match(/OtherThing#foo_arg is deprecated; use bar_arg instead\./, err) + assert_match(/OtherThing#foo_kwarg is deprecated; use bar_kwarg instead\./, err) + assert_match(/on or after 2099-03/, err) end end diff --git a/tool/bundler/rubocop_gems.rb.lock b/tool/bundler/rubocop_gems.rb.lock index c30856aa90..19a4555a22 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) diff --git a/tool/bundler/standard_gems.rb.lock b/tool/bundler/standard_gems.rb.lock index d35cb7ad4e..1d36421cec 100644 --- a/tool/bundler/standard_gems.rb.lock +++ b/tool/bundler/standard_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)