diff options
35 files changed, 718 insertions, 396 deletions
diff --git a/lib/bundler/cli/init.rb b/lib/bundler/cli/init.rb index e4f8229c48..bc96507c29 100644 --- a/lib/bundler/cli/init.rb +++ b/lib/bundler/cli/init.rb @@ -32,7 +32,11 @@ module Bundler file << spec.to_gemfile end else - FileUtils.cp(File.expand_path("../templates/#{gemfile}", __dir__), gemfile) + File.open(File.expand_path("../templates/#{gemfile}", __dir__), "r") do |template| + File.open(gemfile, "wb") do |destination| + IO.copy_stream(template, destination) + end + end end puts "Writing new #{gemfile} to #{SharedHelpers.pwd}/#{gemfile}" diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 79369ec374..a46d7387de 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -106,6 +106,7 @@ module Bundler @locked_gems = nil @locked_deps = {} @locked_specs = SpecSet.new([]) + @originally_locked_specs = @locked_specs @locked_sources = [] @locked_platforms = [] end @@ -149,18 +150,7 @@ module Bundler end def gem_version_promoter - @gem_version_promoter ||= begin - locked_specs = - if unlocking? && @locked_specs.empty? && !@lockfile_contents.empty? - # Definition uses an empty set of locked_specs to indicate all gems - # are unlocked, but GemVersionPromoter needs the locked_specs - # for conservative comparison. - Bundler::SpecSet.new(@locked_gems.specs) - else - @locked_specs - end - GemVersionPromoter.new(locked_specs, @unlock[:gems]) - end + @gem_version_promoter ||= GemVersionPromoter.new(@originally_locked_specs, @unlock[:gems]) end def resolve_only_locally! diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb index 385fdd4383..547db16190 100644 --- a/lib/bundler/dsl.rb +++ b/lib/bundler/dsl.rb @@ -67,7 +67,6 @@ module Bundler gemspecs = Gem::Util.glob_files_in_dir("{,*}.gemspec", expanded_path).map {|g| Bundler.load_gemspec(g) }.compact gemspecs.reject! {|s| s.name != name } if name - Index.sort_specs(gemspecs) specs_by_name_and_version = gemspecs.group_by {|s| [s.name, s.version] } case specs_by_name_and_version.size diff --git a/lib/bundler/gem_version_promoter.rb b/lib/bundler/gem_version_promoter.rb index 1ae41e2928..ee2c38a6ec 100644 --- a/lib/bundler/gem_version_promoter.rb +++ b/lib/bundler/gem_version_promoter.rb @@ -116,15 +116,14 @@ module Bundler end def sort_dep_specs(spec_groups, locked_spec) - return spec_groups unless locked_spec - @gem_name = locked_spec.name - @locked_version = locked_spec.version + @locked_version = locked_spec&.version + @gem_name = locked_spec&.name result = spec_groups.sort do |a, b| @a_ver = a.version @b_ver = b.version - unless @prerelease_specified[@gem_name] + unless @gem_name && @prerelease_specified[@gem_name] a_pre = @a_ver.prerelease? b_pre = @b_ver.prerelease? @@ -148,7 +147,7 @@ module Bundler end def either_version_older_than_locked - @a_ver < @locked_version || @b_ver < @locked_version + @locked_version && (@a_ver < @locked_version || @b_ver < @locked_version) end def segments_do_not_match(level) @@ -157,7 +156,7 @@ module Bundler end def unlocking_gem? - unlock_gems.empty? || unlock_gems.include?(@gem_name) + unlock_gems.empty? || (@gem_name && unlock_gems.include?(@gem_name)) end # Specific version moves can't always reliably be done during sorting @@ -165,7 +164,7 @@ module Bundler def post_sort(result) # default :major behavior in Bundler does not do this return result if major? - if unlocking_gem? + if unlocking_gem? || @locked_version.nil? result else move_version_to_end(result, @locked_version) diff --git a/lib/bundler/index.rb b/lib/bundler/index.rb index 00c7a9e00d..d3743adb68 100644 --- a/lib/bundler/index.rb +++ b/lib/bundler/index.rb @@ -57,36 +57,13 @@ module Bundler # Search this index's specs, and any source indexes that this index knows # about, returning all of the results. def search(query) - sort_specs(unsorted_search(query)) - end - - def unsorted_search(query) results = local_search(query) - - seen = results.map(&:full_name).uniq unless @sources.empty? + return results unless @sources.any? @sources.each do |source| - source.unsorted_search(query).each do |spec| - next if seen.include?(spec.full_name) - - seen << spec.full_name - results << spec - end + results.concat(source.search(query)) end - - results - end - protected :unsorted_search - - def self.sort_specs(specs) - specs.sort_by do |s| - platform_string = s.platform.to_s - [s.version, platform_string == RUBY ? NULL : platform_string] - end - end - - def sort_specs(specs) - self.class.sort_specs(specs) + results.uniq(&:full_name) end def local_search(query) diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index fcb3812c5a..161a3c0518 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -42,8 +42,7 @@ module Bundler remove_from_candidates(spec) end - @gem_version_promoter.prerelease_specified = @prerelease_specified = {} - requirements.each {|dep| @prerelease_specified[dep.name] ||= dep.prerelease? } + requirements.each {|dep| prerelease_specified[dep.name] ||= dep.prerelease? } verify_gemfile_dependencies_are_found!(requirements) result = @resolver.resolve(requirements). @@ -127,13 +126,6 @@ module Bundler results = results_for(dependency) + locked_results results = results.select {|spec| requirement_satisfied_by?(locked_requirement, nil, spec) } if locked_requirement - if !@prerelease_specified[name] && locked_results.empty? - # Move prereleases to the beginning of the list, so they're considered - # last during resolution. - pre, results = results.partition {|spec| spec.version.prerelease? } - results = pre + results - end - if results.any? results = @gem_version_promoter.sort_versions(dependency, results) @@ -221,6 +213,10 @@ module Bundler @base.base_requirements end + def prerelease_specified + @gem_version_promoter.prerelease_specified + end + def remove_from_candidates(spec) @base.delete(spec) @@ -255,7 +251,7 @@ module Bundler all - 1_000_000 else search = search_for(dependency) - search = @prerelease_specified[dependency.name] ? search.count : search.count {|s| !s.version.prerelease? } + search = prerelease_specified[dependency.name] ? search.count : search.count {|s| !s.version.prerelease? } search - all end end @@ -284,7 +280,7 @@ module Bundler end def gem_not_found_message(name, requirement, source, extra_message = "") - specs = source.specs.search(name) + specs = source.specs.search(name).sort_by {|s| [s.version, s.platform.to_s] } matching_part = name requirement_label = SharedHelpers.pretty_dependency(requirement) cache_message = begin diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb index 8b46d7ece4..d53d688009 100644 --- a/lib/bundler/rubygems_ext.rb +++ b/lib/bundler/rubygems_ext.rb @@ -261,10 +261,21 @@ module Gem # version ( (@os != "linux" && (@version.nil? || other.version.nil?)) || - (@os == "linux" && (other.version == "gnu#{@version}" || other.version == "musl#{@version}" || @version == "gnu#{other.version}")) || + (@os == "linux" && (normalized_linux_version_ext == other.normalized_linux_version_ext || ["musl#{@version}", "musleabi#{@version}", "musleabihf#{@version}"].include?(other.version))) || @version == other.version ) end + + # This is a copy of RubyGems 3.3.23 or higher `normalized_linux_method`. + # Once only 3.3.23 is supported, we can use the method in RubyGems. + def normalized_linux_version_ext + return nil unless @version + + without_gnu_nor_abi_modifiers = @version.sub(/\Agnu/, "").sub(/eabi(hf)?\Z/, "") + return nil if without_gnu_nor_abi_modifiers.empty? + + without_gnu_nor_abi_modifiers + end end end diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index 1d0b7a460d..21d57fdab4 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -176,7 +176,7 @@ module Bundler def lookup @lookup ||= begin lookup = Hash.new {|h, k| h[k] = [] } - Index.sort_specs(@specs).reverse_each do |s| + @specs.each do |s| lookup[s.name] << s end lookup diff --git a/lib/bundler/templates/newgem/gitlab-ci.yml.tt b/lib/bundler/templates/newgem/gitlab-ci.yml.tt index 0e71ff26a4..42e00392de 100644 --- a/lib/bundler/templates/newgem/gitlab-ci.yml.tt +++ b/lib/bundler/templates/newgem/gitlab-ci.yml.tt @@ -1,8 +1,9 @@ -image: ruby:<%= RUBY_VERSION %> +default: + image: ruby:<%= RUBY_VERSION %> -before_script: - - gem install bundler -v <%= Bundler::VERSION %> - - bundle install + before_script: + - gem install bundler -v <%= Bundler::VERSION %> + - bundle install example_job: script: diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb index 75760528fe..22ce7daab9 100644 --- a/lib/bundler/version.rb +++ b/lib/bundler/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false module Bundler - VERSION = "2.3.22".freeze + VERSION = "2.3.23".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 d3a32b773f..e2e78a41ac 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -8,7 +8,7 @@ require "rbconfig" module Gem - VERSION = "3.3.22".freeze + VERSION = "3.3.23".freeze end # Must be first since it unloads the prelude from 1.9.2 diff --git a/lib/rubygems/gemcutter_utilities.rb b/lib/rubygems/gemcutter_utilities.rb index a785159196..3477422b79 100644 --- a/lib/rubygems/gemcutter_utilities.rb +++ b/lib/rubygems/gemcutter_utilities.rb @@ -201,7 +201,8 @@ module Gem::GemcutterUtilities # block was given or shows the response body to the user. # # If the response was not successful, shows an error to the user including - # the +error_prefix+ and the response body. + # the +error_prefix+ and the response body. If the response was a permanent redirect, + # shows an error to the user including the redirect location. def with_response(response, error_prefix = nil) case response @@ -211,6 +212,12 @@ module Gem::GemcutterUtilities else say clean_text(response.body) end + when Net::HTTPPermanentRedirect, Net::HTTPRedirection then + message = "The request has redirected permanently to #{response['location']}. Please check your defined push host URL." + message = "#{error_prefix}: #{message}" if error_prefix + + say clean_text(message) + terminate_interaction(ERROR_CODE) else message = response.body message = "#{error_prefix}: #{message}" if error_prefix diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb index 084dc5d2d9..4672866985 100644 --- a/lib/rubygems/package.rb +++ b/lib/rubygems/package.rb @@ -444,10 +444,10 @@ EOM directories << mkdir end - File.open destination, "wb" do |out| - out.write entry.read + if entry.file? + File.open(destination, "wb") {|out| out.write entry.read } FileUtils.chmod file_mode(entry.header.mode), destination - end if entry.file? + end verbose destination end @@ -467,7 +467,12 @@ EOM end def file_mode(mode) # :nodoc: - ((mode & 0111).zero? ? data_mode : prog_mode) || mode + ((mode & 0111).zero? ? data_mode : prog_mode) || + # If we're not using one of the default modes, then we're going to fall + # back to the mode from the tarball. In this case we need to mask it down + # to fit into 2^16 bits (the maximum value for a mode in CRuby since it + # gets put into an unsigned short). + (mode & ((1 << 16) - 1)) end ## diff --git a/lib/rubygems/platform.rb b/lib/rubygems/platform.rb index 06de5ded8d..6f4ead1af8 100644 --- a/lib/rubygems/platform.rb +++ b/lib/rubygems/platform.rb @@ -22,6 +22,7 @@ class Gem::Platform end def self.match_platforms?(platform, platforms) + platform = Gem::Platform.new(platform) unless platform.is_a?(Gem::Platform) platforms.any? do |local_platform| platform.nil? || local_platform == platform || @@ -162,6 +163,9 @@ class Gem::Platform # runtime platform "no version" stands for 'gnu'. To be able to disinguish # these, the method receiver is the gem platform, while the argument is # the runtime platform. + # + #-- + # NOTE: Until it can be removed, changes to this method must also be reflected in `bundler/lib/bundler/rubygems_ext.rb` def ===(other) return nil unless Gem::Platform === other @@ -180,11 +184,23 @@ class Gem::Platform # version ( (@os != "linux" && (@version.nil? || other.version.nil?)) || - (@os == "linux" && (other.version == "gnu#{@version}" || other.version == "musl#{@version}" || @version == "gnu#{other.version}")) || + (@os == "linux" && (normalized_linux_version == other.normalized_linux_version || ["musl#{@version}", "musleabi#{@version}", "musleabihf#{@version}"].include?(other.version))) || @version == other.version ) end + #-- + # NOTE: Until it can be removed, changes to this method must also be reflected in `bundler/lib/bundler/rubygems_ext.rb` + + def normalized_linux_version + return nil unless @version + + without_gnu_nor_abi_modifiers = @version.sub(/\Agnu/, "").sub(/eabi(hf)?\Z/, "") + return nil if without_gnu_nor_abi_modifiers.empty? + + without_gnu_nor_abi_modifiers + end + ## # Does +other+ match this platform? If +other+ is a String it will be # converted to a Gem::Platform first. See #=== for matching rules. diff --git a/lib/rubygems/resolver.rb b/lib/rubygems/resolver.rb index bf7d6d943b..76d1e9d0cc 100644 --- a/lib/rubygems/resolver.rb +++ b/lib/rubygems/resolver.rb @@ -246,7 +246,7 @@ class Gem::Resolver sources.each do |source| groups[source]. - sort_by {|spec| [spec.version, Gem::Platform.local =~ spec.platform ? 1 : 0] }. + sort_by {|spec| [spec.version, spec.platform =~ Gem::Platform.local ? 1 : 0] }. map {|spec| ActivationRequest.new spec, dependency }. each {|activation_request| activation_requests << activation_request } end diff --git a/spec/bundler/commands/init_spec.rb b/spec/bundler/commands/init_spec.rb index eaf8fa170a..9c499b99a1 100644 --- a/spec/bundler/commands/init_spec.rb +++ b/spec/bundler/commands/init_spec.rb @@ -7,6 +7,29 @@ RSpec.describe "bundle init" do expect(bundled_app_gemfile).to be_file end + context "with a template with permission flags not matching current process umask" do + let(:template_file) do + gemfile = Bundler.preferred_gemfile_name + templates_dir.join(gemfile) + end + + let(:target_dir) { bundled_app("init_permissions_test") } + + around do |example| + old_chmod = File.stat(template_file).mode + FileUtils.chmod(old_chmod | 0o111, template_file) # chmod +x + example.run + FileUtils.chmod(old_chmod, template_file) + end + + it "honours the current process umask when generating from a template" do + FileUtils.mkdir(target_dir) + bundle :init, :dir => target_dir + generated_mode = File.stat(File.join(target_dir, "Gemfile")).mode & 0o111 + expect(generated_mode).to be_zero + end + end + context "when a Gemfile already exists" do before do create_file "Gemfile", <<-G diff --git a/spec/bundler/spec_helper.rb b/spec/bundler/spec_helper.rb index 892ad10e98..d606220dc4 100644 --- a/spec/bundler/spec_helper.rb +++ b/spec/bundler/spec_helper.rb @@ -60,6 +60,8 @@ RSpec.configure do |config| config.expect_with :rspec do |c| c.syntax = :expect + + c.max_formatted_output_length = 1000 end config.mock_with :rspec do |mocks| diff --git a/spec/bundler/support/path.rb b/spec/bundler/support/path.rb index a39e46c78a..7443e78d52 100644 --- a/spec/bundler/support/path.rb +++ b/spec/bundler/support/path.rb @@ -312,6 +312,10 @@ module Spec source_root.join("tool/bundler") end + def templates_dir + lib_dir.join("bundler", "templates") + end + extend self end end diff --git a/test/rubygems/helper.rb b/test/rubygems/helper.rb index 970ba09c10..1ed1523f73 100644 --- a/test/rubygems/helper.rb +++ b/test/rubygems/helper.rb @@ -2,26 +2,11 @@ require "rubygems" -# If bundler gemspec exists, add to stubs -bundler_gemspec = File.expand_path("../../bundler/bundler.gemspec", __dir__) -if File.exist?(bundler_gemspec) - Gem::Specification.dirs.unshift File.dirname(bundler_gemspec) - Gem::Specification.class_variable_set :@@stubs, nil - Gem::Specification.stubs - Gem::Specification.dirs.shift -end - begin gem "test-unit", "~> 3.0" rescue Gem::LoadError end -if File.exist?(bundler_gemspec) - require_relative "../../bundler/lib/bundler" -else - require "bundler" -end - require "test/unit" ENV["JARS_SKIP"] = "true" if Gem.java_platform? # avoid unnecessary and noisy `jar-dependencies` post install hook @@ -409,7 +394,6 @@ class Gem::TestCase < Test::Unit::TestCase Gem.loaded_specs.clear Gem.instance_variable_set(:@activated_gem_paths, 0) Gem.clear_default_specs - Bundler.reset! Gem.configuration.verbose = true Gem.configuration.update_sources = true @@ -465,7 +449,7 @@ class Gem::TestCase < Test::Unit::TestCase FileUtils.rm_rf @tempdir - ENV.replace(@orig_env) + restore_env Gem::ConfigFile.send :remove_const, :SYSTEM_WIDE_CONFIG_FILE Gem::ConfigFile.send :const_set, :SYSTEM_WIDE_CONFIG_FILE, @@ -575,6 +559,7 @@ class Gem::TestCase < Test::Unit::TestCase Dir.chdir directory do unless File.exist? ".git" system @git, "init", "--quiet" + system @git, "checkout", "-b", "master", "--quiet" system @git, "config", "user.name", "RubyGems Tests" system @git, "config", "user.email", "rubygems@example" end @@ -1301,6 +1286,10 @@ Also, a list: $LOAD_PATH.find {|p| p == File.dirname($LOADED_FEATURES.find {|f| f.end_with?("/rubygems.rb") }) } end + def bundler_path + $LOAD_PATH.find {|p| p == File.dirname($LOADED_FEATURES.find {|f| f.end_with?("/bundler.rb") }) } + end + def with_clean_path_to_ruby orig_ruby = Gem.ruby @@ -1581,6 +1570,23 @@ Also, a list: PUBLIC_KEY = nil PUBLIC_CERT = nil end if Gem::HAVE_OPENSSL + + private + + def restore_env + unless Gem.win_platform? + ENV.replace(@orig_env) + return + end + + # Fallback logic for Windows below to workaround + # https://bugs.ruby-lang.org/issues/16798. Can be dropped once all + # supported rubies include the fix for that. + + ENV.clear + + @orig_env.each {|k, v| ENV[k] = v } + end end # https://github.com/seattlerb/minitest/blob/13c48a03d84a2a87855a4de0c959f96800100357/lib/minitest/mock.rb#L192 diff --git a/test/rubygems/packages/Bluebie-legs-0.6.2.gem b/test/rubygems/packages/Bluebie-legs-0.6.2.gem Binary files differnew file mode 100644 index 0000000000..60918f3bc5 --- /dev/null +++ b/test/rubygems/packages/Bluebie-legs-0.6.2.gem diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb index bbb3e6dd0a..1b8527cce9 100644 --- a/test/rubygems/test_gem.rb +++ b/test/rubygems/test_gem.rb @@ -617,20 +617,22 @@ class TestGem < Gem::TestCase end def test_self_use_gemdeps - with_rubygems_gemdeps("-") do - FileUtils.mkdir_p "detect/a/b" - FileUtils.mkdir_p "detect/a/Isolate" + with_local_bundler_at(Gem.dir) do + with_rubygems_gemdeps("-") do + FileUtils.mkdir_p "detect/a/b" + FileUtils.mkdir_p "detect/a/Isolate" - FileUtils.touch "detect/Isolate" + FileUtils.touch "detect/Isolate" - begin - Dir.chdir "detect/a/b" + begin + Dir.chdir "detect/a/b" - Gem.use_gemdeps + Gem.use_gemdeps - assert_equal add_bundler_full_name([]), loaded_spec_names - ensure - Dir.chdir @tempdir + assert_equal add_bundler_full_name([]), loaded_spec_names + ensure + Dir.chdir @tempdir + end end end end @@ -775,39 +777,40 @@ class TestGem < Gem::TestCase end def test_self_find_files_with_gemfile - cwd = File.expand_path("test/rubygems", PROJECT_DIR) - actual_load_path = $LOAD_PATH.unshift(cwd).dup + with_local_bundler_at(Gem.dir) do + cwd = File.expand_path("test/rubygems", PROJECT_DIR) + actual_load_path = $LOAD_PATH.unshift(cwd).dup - discover_path = File.join "lib", "sff", "discover.rb" + discover_path = File.join "lib", "sff", "discover.rb" - foo1, _ = %w[1 2].map do |version| - spec = quick_gem "sff", version do |s| - s.files << discover_path + foo1, _ = %w[1 2].map do |version| + spec = quick_gem "sff", version do |s| + s.files << discover_path + end + + write_file(File.join "gems", spec.full_name, discover_path) do |fp| + fp.puts "# #{spec.full_name}" + end + + spec end + Gem.refresh - write_file(File.join "gems", spec.full_name, discover_path) do |fp| - fp.puts "# #{spec.full_name}" + write_file(File.join Dir.pwd, "Gemfile") do |fp| + fp.puts "source 'https://rubygems.org'" + fp.puts "gem '#{foo1.name}', '#{foo1.version}'" end + Gem.use_gemdeps(File.join Dir.pwd, "Gemfile") - spec - end - Gem.refresh + expected = [ + File.expand_path("test/rubygems/sff/discover.rb", PROJECT_DIR), + File.join(foo1.full_gem_path, discover_path), + ].sort - write_file(File.join Dir.pwd, "Gemfile") do |fp| - fp.puts "source 'https://rubygems.org'" - fp.puts "gem '#{foo1.name}', '#{foo1.version}'" + assert_equal expected, Gem.find_files("sff/discover").sort + assert_equal expected, Gem.find_files("sff/**.rb").sort, "[ruby-core:31730]" + assert_equal cwd, actual_load_path.shift end - Gem.use_gemdeps(File.join Dir.pwd, "Gemfile") - - expected = [ - File.expand_path("test/rubygems/sff/discover.rb", PROJECT_DIR), - File.join(foo1.full_gem_path, discover_path), - ].sort - - assert_equal expected, Gem.find_files("sff/discover").sort - assert_equal expected, Gem.find_files("sff/**.rb").sort, "[ruby-core:31730]" - ensure - assert_equal cwd, actual_load_path.shift unless Gem.java_platform? end def test_self_find_latest_files @@ -1335,12 +1338,10 @@ class TestGem < Gem::TestCase refute Gem.try_activate "nonexistent" end - unless Gem.java_platform? - expected = "Ignoring ext-1 because its extensions are not built. " + - "Try: gem pristine ext --version 1\n" + expected = "Ignoring ext-1 because its extensions are not built. " + + "Try: gem pristine ext --version 1\n" - assert_equal expected, err - end + assert_equal expected, err end def test_self_use_paths_with_nils @@ -1640,159 +1641,164 @@ class TestGem < Gem::TestCase end def test_auto_activation_of_specific_gemdeps_file - a = util_spec "a", "1", nil, "lib/a.rb" - b = util_spec "b", "1", nil, "lib/b.rb" - c = util_spec "c", "1", nil, "lib/c.rb" + with_local_bundler_at(Gem.dir) do + a = util_spec "a", "1", nil, "lib/a.rb" + b = util_spec "b", "1", nil, "lib/b.rb" + c = util_spec "c", "1", nil, "lib/c.rb" - install_specs a, b, c + install_specs a, b, c - path = File.join @tempdir, "gem.deps.rb" + path = File.join @tempdir, "gem.deps.rb" - File.open path, "w" do |f| - f.puts "gem 'a'" - f.puts "gem 'b'" - f.puts "gem 'c'" - end + File.open path, "w" do |f| + f.puts "gem 'a'" + f.puts "gem 'b'" + f.puts "gem 'c'" + end - with_rubygems_gemdeps(path) do - Gem.use_gemdeps + with_rubygems_gemdeps(path) do + Gem.use_gemdeps - assert_equal add_bundler_full_name(%W[a-1 b-1 c-1]), loaded_spec_names + assert_equal add_bundler_full_name(%W[a-1 b-1 c-1]), loaded_spec_names + end end end def test_auto_activation_of_used_gemdeps_file - a = util_spec "a", "1", nil, "lib/a.rb" - b = util_spec "b", "1", nil, "lib/b.rb" - c = util_spec "c", "1", nil, "lib/c.rb" + with_local_bundler_at(Gem.dir) do + a = util_spec "a", "1", nil, "lib/a.rb" + b = util_spec "b", "1", nil, "lib/b.rb" + c = util_spec "c", "1", nil, "lib/c.rb" - install_specs a, b, c + install_specs a, b, c - path = File.join @tempdir, "gem.deps.rb" + path = File.join @tempdir, "gem.deps.rb" - File.open path, "w" do |f| - f.puts "gem 'a'" - f.puts "gem 'b'" - f.puts "gem 'c'" - end + File.open path, "w" do |f| + f.puts "gem 'a'" + f.puts "gem 'b'" + f.puts "gem 'c'" + end - with_rubygems_gemdeps("-") do - expected_specs = [a, b, util_spec("bundler", Bundler::VERSION), c].compact.map(&:full_name) + with_rubygems_gemdeps("-") do + expected_specs = [a, b, util_spec("bundler", Bundler::VERSION), c].compact.map(&:full_name) - Gem.use_gemdeps + Gem.use_gemdeps - assert_equal expected_specs, loaded_spec_names + assert_equal expected_specs, loaded_spec_names + end end end - BUNDLER_LIB_PATH = File.expand_path $LOAD_PATH.find {|lp| File.file?(File.join(lp, "bundler.rb")) } - BUNDLER_FULL_NAME = "bundler-#{Bundler::VERSION}".freeze - def add_bundler_full_name(names) - names << BUNDLER_FULL_NAME + names << "bundler-#{Bundler::VERSION}".freeze names.sort! names end def test_looks_for_gemdeps_files_automatically_from_binstubs - pend "Requiring bundler messes things up" if Gem.java_platform? + path = File.join(@tempdir, "gd-tmp") - a = util_spec "a", "1" do |s| - s.executables = %w[foo] - s.bindir = "exe" - end + with_local_bundler_at(path) do + a = util_spec "a", "1" do |s| + s.executables = %w[foo] + s.bindir = "exe" + end - write_file File.join(@tempdir, "exe", "foo") do |fp| - fp.puts "puts Gem.loaded_specs.values.map(&:full_name).sort" - end + write_file File.join(@tempdir, "exe", "foo") do |fp| + fp.puts "puts Gem.loaded_specs.values.map(&:full_name).sort" + end - b = util_spec "b", "1", nil, "lib/b.rb" - c = util_spec "c", "1", nil, "lib/c.rb" + b = util_spec "b", "1", nil, "lib/b.rb" + c = util_spec "c", "1", nil, "lib/c.rb" - install_specs a, b, c + install_specs a, b, c - path = File.join(@tempdir, "gd-tmp") - install_gem a, :install_dir => path - install_gem b, :install_dir => path - install_gem c, :install_dir => path + install_gem a, :install_dir => path + install_gem b, :install_dir => path + install_gem c, :install_dir => path - ENV["GEM_PATH"] = path + ENV["GEM_PATH"] = path - with_rubygems_gemdeps("-") do - new_PATH = [File.join(path, "bin"), ENV["PATH"]].join(File::PATH_SEPARATOR) - new_RUBYOPT = "-I#{rubygems_path} -I#{BUNDLER_LIB_PATH}" + with_rubygems_gemdeps("-") do + new_PATH = [File.join(path, "bin"), ENV["PATH"]].join(File::PATH_SEPARATOR) + new_RUBYOPT = "-I#{rubygems_path} -I#{bundler_path}" - path = File.join @tempdir, "gem.deps.rb" + path = File.join @tempdir, "gem.deps.rb" - File.open path, "w" do |f| - f.puts "gem 'a'" - end - out0 = with_path_and_rubyopt(new_PATH, new_RUBYOPT) do - IO.popen("foo", &:read).split(/\n/) - end + File.open path, "w" do |f| + f.puts "gem 'a'" + end + out0 = with_path_and_rubyopt(new_PATH, new_RUBYOPT) do + IO.popen("foo", &:read).split(/\n/) + end - File.open path, "a" do |f| - f.puts "gem 'b'" - f.puts "gem 'c'" - end - out = with_path_and_rubyopt(new_PATH, new_RUBYOPT) do - IO.popen("foo", &:read).split(/\n/) - end + File.open path, "a" do |f| + f.puts "gem 'b'" + f.puts "gem 'c'" + end + out = with_path_and_rubyopt(new_PATH, new_RUBYOPT) do + IO.popen("foo", &:read).split(/\n/) + end - assert_equal ["b-1", "c-1"], out - out0 + assert_equal ["b-1", "c-1"], out - out0 + end end end def test_looks_for_gemdeps_files_automatically_from_binstubs_in_parent_dir - pend "Requiring bundler messes things up" if Gem.java_platform? + path = File.join(@tempdir, "gd-tmp") - a = util_spec "a", "1" do |s| - s.executables = %w[foo] - s.bindir = "exe" - end + with_local_bundler_at(path) do + pend "IO.popen has issues on JRuby when passed :chdir" if Gem.java_platform? - write_file File.join(@tempdir, "exe", "foo") do |fp| - fp.puts "puts Gem.loaded_specs.values.map(&:full_name).sort" - end + a = util_spec "a", "1" do |s| + s.executables = %w[foo] + s.bindir = "exe" + end - b = util_spec "b", "1", nil, "lib/b.rb" - c = util_spec "c", "1", nil, "lib/c.rb" + write_file File.join(@tempdir, "exe", "foo") do |fp| + fp.puts "puts Gem.loaded_specs.values.map(&:full_name).sort" + end - install_specs a, b, c + b = util_spec "b", "1", nil, "lib/b.rb" + c = util_spec "c", "1", nil, "lib/c.rb" - path = File.join(@tempdir, "gd-tmp") - install_gem a, :install_dir => path - install_gem b, :install_dir => path - install_gem c, :install_dir => path + install_specs a, b, c - ENV["GEM_PATH"] = path + install_gem a, :install_dir => path + install_gem b, :install_dir => path + install_gem c, :install_dir => path - with_rubygems_gemdeps("-") do - Dir.mkdir "sub1" + ENV["GEM_PATH"] = path - new_PATH = [File.join(path, "bin"), ENV["PATH"]].join(File::PATH_SEPARATOR) - new_RUBYOPT = "-I#{rubygems_path} -I#{BUNDLER_LIB_PATH}" + with_rubygems_gemdeps("-") do + Dir.mkdir "sub1" - path = File.join @tempdir, "gem.deps.rb" + new_PATH = [File.join(path, "bin"), ENV["PATH"]].join(File::PATH_SEPARATOR) + new_RUBYOPT = "-I#{rubygems_path} -I#{bundler_path}" - File.open path, "w" do |f| - f.puts "gem 'a'" - end - out0 = with_path_and_rubyopt(new_PATH, new_RUBYOPT) do - IO.popen("foo", :chdir => "sub1", &:read).split(/\n/) - end + path = File.join @tempdir, "gem.deps.rb" - File.open path, "a" do |f| - f.puts "gem 'b'" - f.puts "gem 'c'" - end - out = with_path_and_rubyopt(new_PATH, new_RUBYOPT) do - IO.popen("foo", :chdir => "sub1", &:read).split(/\n/) - end + File.open path, "w" do |f| + f.puts "gem 'a'" + end + out0 = with_path_and_rubyopt(new_PATH, new_RUBYOPT) do + IO.popen("foo", :chdir => "sub1", &:read).split(/\n/) + end - Dir.rmdir "sub1" + File.open path, "a" do |f| + f.puts "gem 'b'" + f.puts "gem 'c'" + end + out = with_path_and_rubyopt(new_PATH, new_RUBYOPT) do + IO.popen("foo", :chdir => "sub1", &:read).split(/\n/) + end - assert_equal ["b-1", "c-1"], out - out0 + Dir.rmdir "sub1" + + assert_equal ["b-1", "c-1"], out - out0 + end end end @@ -1837,52 +1843,47 @@ class TestGem < Gem::TestCase end def test_use_gemdeps - gem_deps_file = "gem.deps.rb".tap(&Gem::UNTAINT) - spec = util_spec "a", 1 - install_specs spec + with_local_bundler_at(Gem.dir) do + gem_deps_file = "gem.deps.rb".tap(&Gem::UNTAINT) + spec = util_spec "a", 1 + install_specs spec - spec = Gem::Specification.find {|s| s == spec } - refute spec.activated? + spec = Gem::Specification.find {|s| s == spec } + refute spec.activated? - File.open gem_deps_file, "w" do |io| - io.write 'gem "a"' - end + File.open gem_deps_file, "w" do |io| + io.write 'gem "a"' + end - assert_nil Gem.gemdeps + assert_nil Gem.gemdeps - Gem.use_gemdeps gem_deps_file + Gem.use_gemdeps gem_deps_file - assert_equal add_bundler_full_name(%W[a-1]), loaded_spec_names - refute_nil Gem.gemdeps + assert_equal add_bundler_full_name(%W[a-1]), loaded_spec_names + refute_nil Gem.gemdeps + end end def test_use_gemdeps_ENV - with_rubygems_gemdeps(nil) do - spec = util_spec "a", 1 + with_local_bundler_at(Gem.dir) do + with_rubygems_gemdeps(nil) do + spec = util_spec "a", 1 - refute spec.activated? + refute spec.activated? - File.open "gem.deps.rb", "w" do |io| - io.write 'gem "a"' - end + File.open "gem.deps.rb", "w" do |io| + io.write 'gem "a"' + end - Gem.use_gemdeps + Gem.use_gemdeps - refute spec.activated? + refute spec.activated? + end end end def test_use_gemdeps_argument_missing - e = assert_raise ArgumentError do - Gem.use_gemdeps "gem.deps.rb" - end - - assert_equal "Unable to find gem dependencies file at gem.deps.rb", - e.message - end - - def test_use_gemdeps_argument_missing_match_ENV - with_rubygems_gemdeps("gem.deps.rb") do + with_local_bundler_at(Gem.dir) do e = assert_raise ArgumentError do Gem.use_gemdeps "gem.deps.rb" end @@ -1892,85 +1893,108 @@ class TestGem < Gem::TestCase end end + def test_use_gemdeps_argument_missing_match_ENV + with_local_bundler_at(Gem.dir) do + with_rubygems_gemdeps("gem.deps.rb") do + e = assert_raise ArgumentError do + Gem.use_gemdeps "gem.deps.rb" + end + + assert_equal "Unable to find gem dependencies file at gem.deps.rb", + e.message + end + end + end + def test_use_gemdeps_automatic - with_rubygems_gemdeps("-") do - spec = util_spec "a", 1 - install_specs spec - spec = Gem::Specification.find {|s| s == spec } + with_local_bundler_at(Gem.dir) do + with_rubygems_gemdeps("-") do + spec = util_spec "a", 1 + install_specs spec + spec = Gem::Specification.find {|s| s == spec } - refute spec.activated? + refute spec.activated? - File.open "Gemfile", "w" do |io| - io.write 'gem "a"' - end + File.open "Gemfile", "w" do |io| + io.write 'gem "a"' + end - Gem.use_gemdeps + Gem.use_gemdeps - assert_equal add_bundler_full_name(%W[a-1]), loaded_spec_names + assert_equal add_bundler_full_name(%W[a-1]), loaded_spec_names + end end end def test_use_gemdeps_automatic_missing - with_rubygems_gemdeps("-") do - Gem.use_gemdeps + with_local_bundler_at(Gem.dir) do + with_rubygems_gemdeps("-") do + Gem.use_gemdeps - assert true # count + assert true # count + end end end def test_use_gemdeps_disabled - with_rubygems_gemdeps("") do - spec = util_spec "a", 1 + with_local_bundler_at(Gem.dir) do + with_rubygems_gemdeps("") do + spec = util_spec "a", 1 - refute spec.activated? + refute spec.activated? - File.open "gem.deps.rb", "w" do |io| - io.write 'gem "a"' - end + File.open "gem.deps.rb", "w" do |io| + io.write 'gem "a"' + end - Gem.use_gemdeps + Gem.use_gemdeps - refute spec.activated? + refute spec.activated? + end end end def test_use_gemdeps_missing_gem - with_rubygems_gemdeps("x") do - File.open "x", "w" do |io| - io.write 'gem "a"' - end + with_local_bundler_at(Gem.dir) do + with_rubygems_gemdeps("x") do + File.open "x", "w" do |io| + io.write 'gem "a"' + end - expected = <<-EXPECTED + expected = <<-EXPECTED Could not find gem 'a' in locally installed gems. You may need to `bundle install` to install missing gems EXPECTED - Gem::Deprecate.skip_during do - actual_stdout, actual_stderr = capture_output do - Gem.use_gemdeps + Gem::Deprecate.skip_during do + actual_stdout, actual_stderr = capture_output do + Gem.use_gemdeps + end + assert_empty actual_stdout + assert_equal(expected, actual_stderr) end - assert_empty actual_stdout - assert_equal(expected, actual_stderr) end end end def test_use_gemdeps_specific - with_rubygems_gemdeps("x") do - spec = util_spec "a", 1 - install_specs spec + with_local_bundler_at(Gem.dir) do + with_rubygems_gemdeps("x") do + spec = util_spec "a", 1 + install_specs spec - spec = Gem::Specification.find {|s| s == spec } - refute spec.activated? + spec = Gem::Specification.find {|s| s == spec } + refute spec.activated? - File.open "x", "w" do |io| - io.write 'gem "a"' - end + File.open "x", "w" do |io| + io.write 'gem "a"' + end - Gem.use_gemdeps + Gem.use_gemdeps - assert_equal add_bundler_full_name(%W[a-1]), loaded_spec_names + assert_equal add_bundler_full_name(%W[a-1]), loaded_spec_names + end end end @@ -2109,4 +2133,22 @@ You may need to `bundle install` to install missing gems ensure ENV["RUBYGEMS_GEMDEPS"] = rubygems_gemdeps end + + def with_local_bundler_at(path) + require "bundler" + + # If bundler gemspec exists, pretend it's installed + bundler_gemspec = File.expand_path("../../bundler/bundler.gemspec", __dir__) + if File.exist?(bundler_gemspec) + target_gemspec_location = "#{path}/specifications/bundler-#{Bundler::VERSION}.gemspec" + + FileUtils.mkdir_p File.dirname(target_gemspec_location) + + File.write target_gemspec_location, Gem::Specification.load(bundler_gemspec).to_ruby_for_cache + end + + yield + ensure + Bundler.reset! + end end diff --git a/test/rubygems/test_gem_commands_owner_command.rb b/test/rubygems/test_gem_commands_owner_command.rb index ca77041000..32bfbb7a66 100644 --- a/test/rubygems/test_gem_commands_owner_command.rb +++ b/test/rubygems/test_gem_commands_owner_command.rb @@ -36,7 +36,7 @@ class TestGemCommandsOwnerCommand < Gem::TestCase - id: 4 EOF - @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners.yaml"] = [response, 200, "OK"] + @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners.yaml"] = HTTPResponseFactory.create(body: response, code: 200, msg: "OK") use_ui @stub_ui do @cmd.show_owners("freewill") @@ -66,7 +66,7 @@ EOF - id: 4 EOF - @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners.yaml"] = [response, 200, "OK"] + @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners.yaml"] = HTTPResponseFactory.create(body: response, code: 200, msg: "OK") assert_raise Psych::DisallowedClass do use_ui @ui do @@ -80,7 +80,7 @@ EOF host = "http://rubygems.example" ENV["RUBYGEMS_HOST"] = host - @stub_fetcher.data["#{host}/api/v1/gems/freewill/owners.yaml"] = [response, 200, "OK"] + @stub_fetcher.data["#{host}/api/v1/gems/freewill/owners.yaml"] = HTTPResponseFactory.create(body: response, code: 200, msg: "OK") use_ui @stub_ui do @cmd.show_owners("freewill") @@ -95,7 +95,7 @@ EOF host = "http://rubygems.example" @cmd.host = host - @stub_fetcher.data["#{host}/api/v1/gems/freewill/owners.yaml"] = [response, 200, "OK"] + @stub_fetcher.data["#{host}/api/v1/gems/freewill/owners.yaml"] = HTTPResponseFactory.create(body: response, code: 200, msg: "OK") use_ui @stub_ui do @cmd.show_owners("freewill") @@ -107,7 +107,7 @@ EOF def test_show_owners_denied response = "You don't have permission to push to this gem" - @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners.yaml"] = [response, 403, "Forbidden"] + @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners.yaml"] = HTTPResponseFactory.create(body: response, code: 403, msg: "Forbidden") assert_raise Gem::MockGemUi::TermError do use_ui @stub_ui do @@ -118,9 +118,32 @@ EOF assert_match response, @stub_ui.output end + def test_show_owners_permanent_redirect + host = "http://rubygems.example" + ENV["RUBYGEMS_HOST"] = host + path = "/api/v1/gems/freewill/owners.yaml" + redirected_uri = "https://rubygems.example#{path}" + + @stub_fetcher.data["#{host}#{path}"] = HTTPResponseFactory.create( + body: "", + code: "301", + msg: "Moved Permanently", + headers: { "location" => redirected_uri } + ) + + assert_raise Gem::MockGemUi::TermError do + use_ui @stub_ui do + @cmd.show_owners("freewill") + end + end + + response = "The request has redirected permanently to #{redirected_uri}. Please check your defined push host URL." + assert_match response, @stub_ui.output + end + def test_show_owners_key response = "- email: user1@example.com\n" - @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners.yaml"] = [response, 200, "OK"] + @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners.yaml"] = HTTPResponseFactory.create(body: response, code: 200, msg: "OK") File.open Gem.configuration.credentials_path, "a" do |f| f.write ":other: 701229f217cdf23b1344c7b4b54ca97" end @@ -134,7 +157,7 @@ EOF def test_add_owners response = "Owner added successfully." - @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = [response, 200, "OK"] + @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = HTTPResponseFactory.create(body: response, code: 200, msg: "OK") use_ui @stub_ui do @cmd.add_owners("freewill", ["user-new1@example.com"]) @@ -149,12 +172,33 @@ EOF def test_add_owners_denied response = "You don't have permission to push to this gem" - @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = [response, 403, "Forbidden"] + @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = HTTPResponseFactory.create(body: response, code: 403, msg: "Forbidden") + + use_ui @stub_ui do + @cmd.add_owners("freewill", ["user-new1@example.com"]) + end + + assert_match response, @stub_ui.output + end + + def test_add_owners_permanent_redirect + host = "http://rubygems.example" + ENV["RUBYGEMS_HOST"] = host + path = "/api/v1/gems/freewill/owners" + redirected_uri = "https://rubygems.example#{path}" + + @stub_fetcher.data["#{host}#{path}"] = HTTPResponseFactory.create( + body: "", + code: "308", + msg: "Permanent Redirect", + headers: { "location" => redirected_uri } + ) use_ui @stub_ui do @cmd.add_owners("freewill", ["user-new1@example.com"]) end + response = "The request has redirected permanently to #{redirected_uri}. Please check your defined push host URL." assert_match response, @stub_ui.output end @@ -162,8 +206,8 @@ EOF host = "http://rubygems.example" add_owner_response = "Owner added successfully." show_owners_response = "- email: user1@example.com\n" - @stub_fetcher.data["#{host}/api/v1/gems/freewill/owners"] = [add_owner_response, 200, "OK"] - @stub_fetcher.data["#{host}/api/v1/gems/freewill/owners.yaml"] = [show_owners_response, 200, "OK"] + @stub_fetcher.data["#{host}/api/v1/gems/freewill/owners"] = HTTPResponseFactory.create(body: add_owner_response, code: 200, msg: "OK") + @stub_fetcher.data["#{host}/api/v1/gems/freewill/owners.yaml"] = HTTPResponseFactory.create(body: show_owners_response, code: 200, msg: "OK") @cmd.handle_options %W[--host #{host} --add user-new1@example.com freewill] @@ -178,7 +222,7 @@ EOF def test_add_owners_key response = "Owner added successfully." - @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = [response, 200, "OK"] + @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = HTTPResponseFactory.create(body: response, code: 200, msg: "OK") File.open Gem.configuration.credentials_path, "a" do |f| f.write ":other: 701229f217cdf23b1344c7b4b54ca97" end @@ -192,7 +236,7 @@ EOF def test_remove_owners response = "Owner removed successfully." - @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = [response, 200, "OK"] + @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = HTTPResponseFactory.create(body: response, code: 200, msg: "OK") use_ui @stub_ui do @cmd.remove_owners("freewill", ["user-remove1@example.com"]) @@ -207,7 +251,7 @@ EOF def test_remove_owners_denied response = "You don't have permission to push to this gem" - @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = [response, 403, "Forbidden"] + @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = HTTPResponseFactory.create(body: response, code: 403, msg: "Forbidden") use_ui @stub_ui do @cmd.remove_owners("freewill", ["user-remove1@example.com"]) @@ -216,9 +260,46 @@ EOF assert_match response, @stub_ui.output end + def test_remove_owners_permanent_redirect + host = "http://rubygems.example" + ENV["RUBYGEMS_HOST"] = host + path = "/api/v1/gems/freewill/owners" + redirected_uri = "https://rubygems.example#{path}" + @stub_fetcher.data["#{host}#{path}"] = HTTPResponseFactory.create( + body: "", + code: "308", + msg: "Permanent Redirect", + headers: { "location" => redirected_uri } + ) + + use_ui @stub_ui do + @cmd.remove_owners("freewill", ["user-remove1@example.com"]) + end + + response = "The request has redirected permanently to #{redirected_uri}. Please check your defined push host URL." + assert_match response, @stub_ui.output + + path = "/api/v1/gems/freewill/owners" + redirected_uri = "https://rubygems.example#{path}" + + @stub_fetcher.data["#{host}#{path}"] = HTTPResponseFactory.create( + body: "", + code: "308", + msg: "Permanent Redirect", + headers: { "location" => redirected_uri } + ) + + use_ui @stub_ui do + @cmd.add_owners("freewill", ["user-new1@example.com"]) + end + + response = "The request has redirected permanently to #{redirected_uri}. Please check your defined push host URL." + assert_match response, @stub_ui.output + end + def test_remove_owners_key response = "Owner removed successfully." - @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = [response, 200, "OK"] + @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = HTTPResponseFactory.create(body: response, code: 200, msg: "OK") File.open Gem.configuration.credentials_path, "a" do |f| f.write ":other: 701229f217cdf23b1344c7b4b54ca97" end @@ -232,7 +313,7 @@ EOF def test_remove_owners_missing response = "Owner could not be found." - @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = [response, 404, "Not Found"] + @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = HTTPResponseFactory.create(body: response, code: 404, msg: "Not Found") use_ui @stub_ui do @cmd.remove_owners("freewill", ["missing@example"]) @@ -246,8 +327,8 @@ EOF response_success = "Owner added successfully." @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = [ - [response_fail, 401, "Unauthorized"], - [response_success, 200, "OK"], + HTTPResponseFactory.create(body: response_fail, code: 401, msg: "Unauthorized"), + HTTPResponseFactory.create(body: response_success, code: 200, msg: "OK"), ] @otp_ui = Gem::MockGemUi.new "111111\n" @@ -263,7 +344,7 @@ EOF def test_otp_verified_failure response = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry." - @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = [response, 401, "Unauthorized"] + @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = HTTPResponseFactory.create(body: response, code: 401, msg: "Unauthorized") @otp_ui = Gem::MockGemUi.new "111111\n" use_ui @otp_ui do @@ -281,10 +362,10 @@ EOF response_success = "Owner removed successfully." @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = [ - [response_forbidden, 403, "Forbidden"], - [response_success, 200, "OK"], + HTTPResponseFactory.create(body: response_forbidden, code: 403, msg: "Forbidden"), + HTTPResponseFactory.create(body: response_success, code: 200, msg: "OK"), ] - @stub_fetcher.data["#{Gem.host}/api/v1/api_key"] = ["", 200, "OK"] + @stub_fetcher.data["#{Gem.host}/api/v1/api_key"] = HTTPResponseFactory.create(body: "", code: 200, msg: "OK") @cmd.instance_variable_set :@scope, :remove_owner @stub_ui = Gem::MockGemUi.new "some@mail.com\npass\n" @@ -305,10 +386,10 @@ EOF response_success = "Owner added successfully." @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = [ - [response_forbidden, 403, "Forbidden"], - [response_success, 200, "OK"], + HTTPResponseFactory.create(body: response_forbidden, code: 403, msg: "Forbidden"), + HTTPResponseFactory.create(body: response_success, code: 200, msg: "OK"), ] - @stub_fetcher.data["#{Gem.host}/api/v1/api_key"] = ["", 200, "OK"] + @stub_fetcher.data["#{Gem.host}/api/v1/api_key"] = HTTPResponseFactory.create(body: "", code: 200, msg: "OK") @cmd.instance_variable_set :@scope, :add_owner @stub_ui = Gem::MockGemUi.new "some@mail.com\npass\n" diff --git a/test/rubygems/test_gem_commands_push_command.rb b/test/rubygems/test_gem_commands_push_command.rb index f38a2ae7a1..ef7730558d 100644 --- a/test/rubygems/test_gem_commands_push_command.rb +++ b/test/rubygems/test_gem_commands_push_command.rb @@ -68,7 +68,7 @@ class TestGemCommandsPushCommand < Gem::TestCase def test_execute @response = "Successfully registered gem: freewill (1.0.0)" - @fetcher.data["#{Gem.host}/api/v1/gems"] = [@response, 200, "OK"] + @fetcher.data["#{Gem.host}/api/v1/gems"] = HTTPResponseFactory.create(body: @response, code: 200, msg: "OK") @cmd.options[:args] = [@path] @@ -84,7 +84,7 @@ class TestGemCommandsPushCommand < Gem::TestCase host = "https://other.example" @response = "Successfully registered gem: freewill (1.0.0)" - @fetcher.data["#{host}/api/v1/gems"] = [@response, 200, "OK"] + @fetcher.data["#{host}/api/v1/gems"] = HTTPResponseFactory.create(body: @response, code: 200, msg: "OK") @fetcher.data["#{Gem.host}/api/v1/gems"] = ["fail", 500, "Internal Server Error"] @@ -105,7 +105,7 @@ class TestGemCommandsPushCommand < Gem::TestCase end @response = "Successfully registered gem: freewill (1.0.0)" - @fetcher.data["#{@spec.metadata['allowed_push_host']}/api/v1/gems"] = [@response, 200, "OK"] + @fetcher.data["#{@spec.metadata['allowed_push_host']}/api/v1/gems"] = HTTPResponseFactory.create(body: @response, code: 200, msg: "OK") @fetcher.data["#{Gem.host}/api/v1/gems"] = ["fail", 500, "Internal Server Error"] @@ -136,7 +136,7 @@ class TestGemCommandsPushCommand < Gem::TestCase ENV["RUBYGEMS_HOST"] = @host Gem.configuration.disable_default_gem_server = true @response = "Successfully registered gem: freewill (1.0.0)" - @fetcher.data["#{@host}/api/v1/gems"] = [@response, 200, "OK"] + @fetcher.data["#{@host}/api/v1/gems"] = HTTPResponseFactory.create(body: @response, code: 200, msg: "OK") send_battery end @@ -163,14 +163,14 @@ class TestGemCommandsPushCommand < Gem::TestCase FileUtils.rm Gem.configuration.credentials_path @response = "Successfully registered gem: freebird (1.0.1)" - @fetcher.data["#{@host}/api/v1/gems"] = [@response, 200, "OK"] + @fetcher.data["#{@host}/api/v1/gems"] = HTTPResponseFactory.create(body: @response, code: 200, msg: "OK") send_battery end def test_sending_gem @response = "Successfully registered gem: freewill (1.0.0)" - @fetcher.data["#{@host}/api/v1/gems"] = [@response, 200, "OK"] + @fetcher.data["#{@host}/api/v1/gems"] = HTTPResponseFactory.create(body: @response, code: 200, msg: "OK") send_battery end @@ -197,7 +197,7 @@ class TestGemCommandsPushCommand < Gem::TestCase FileUtils.rm Gem.configuration.credentials_path @response = "Successfully registered gem: freebird (1.0.1)" - @fetcher.data["#{@host}/api/v1/gems"] = [@response, 200, "OK"] + @fetcher.data["#{@host}/api/v1/gems"] = HTTPResponseFactory.create(body: @response, code: 200, msg: "OK") send_battery end @@ -212,7 +212,7 @@ class TestGemCommandsPushCommand < Gem::TestCase ENV["GEM_HOST_API_KEY"] = "PRIVKEY" @response = "Successfully registered gem: freebird (1.0.1)" - @fetcher.data["#{@host}/api/v1/gems"] = [@response, 200, "OK"] + @fetcher.data["#{@host}/api/v1/gems"] = HTTPResponseFactory.create(body: @response, code: 200, msg: "OK") send_battery end @@ -238,7 +238,7 @@ class TestGemCommandsPushCommand < Gem::TestCase FileUtils.rm Gem.configuration.credentials_path @response = "Successfully registered gem: freebird (1.0.1)" - @fetcher.data["#{@host}/api/v1/gems"] = [@response, 200, "OK"] + @fetcher.data["#{@host}/api/v1/gems"] = HTTPResponseFactory.create(body: @response, code: 200, msg: "OK") send_battery end @@ -309,7 +309,7 @@ class TestGemCommandsPushCommand < Gem::TestCase FileUtils.rm Gem.configuration.credentials_path @response = "Successfully registered gem: freebird (1.0.1)" - @fetcher.data["#{host}/api/v1/gems"] = [@response, 200, "OK"] + @fetcher.data["#{host}/api/v1/gems"] = HTTPResponseFactory.create(body: @response, code: 200, msg: "OK") # do not set @host use_ui(@ui) { @cmd.send_gem(@path) } @@ -325,6 +325,27 @@ class TestGemCommandsPushCommand < Gem::TestCase assert_match @response, @ui.output end + def test_sending_gem_to_host_permanent_redirect + @host = "http://rubygems.example" + redirected_uri = "https://rubygems.example/api/v1/gems" + @fetcher.data["#{@host}/api/v1/gems"] = HTTPResponseFactory.create( + body: "", + code: 308, + msg: "Permanent Redirect", + headers: { "Location" => redirected_uri } + ) + + assert_raise Gem::MockGemUi::TermError do + use_ui @ui do + @cmd.instance_variable_set :@host, @host + @cmd.send_gem(@path) + end + end + + response = "The request has redirected permanently to #{redirected_uri}. Please check your defined push host URL." + assert_match response, @ui.output + end + def test_raises_error_with_no_arguments def @cmd.sign_in(*); end assert_raise Gem::CommandLineError do @@ -334,7 +355,7 @@ class TestGemCommandsPushCommand < Gem::TestCase def test_sending_gem_denied response = "You don't have permission to push to this gem" - @fetcher.data["#{@host}/api/v1/gems"] = [response, 403, "Forbidden"] + @fetcher.data["#{@host}/api/v1/gems"] = HTTPResponseFactory.create(body: response, code: 403, msg: "Forbidden") @cmd.instance_variable_set :@host, @host assert_raise Gem::MockGemUi::TermError do @@ -348,7 +369,7 @@ class TestGemCommandsPushCommand < Gem::TestCase def test_sending_gem_key @response = "Successfully registered gem: freewill (1.0.0)" - @fetcher.data["#{@host}/api/v1/gems"] = [@response, 200, "OK"] + @fetcher.data["#{@host}/api/v1/gems"] = HTTPResponseFactory.create(body: @response, code: 200, msg: "OK") File.open Gem.configuration.credentials_path, "a" do |f| f.write ":other: 701229f217cdf23b1344c7b4b54ca97" end @@ -367,8 +388,8 @@ class TestGemCommandsPushCommand < Gem::TestCase response_success = "Successfully registered gem: freewill (1.0.0)" @fetcher.data["#{Gem.host}/api/v1/gems"] = [ - [response_fail, 401, "Unauthorized"], - [response_success, 200, "OK"], + HTTPResponseFactory.create(body: response_fail, code: 401, msg: "Unauthorized"), + HTTPResponseFactory.create(body: response_success, code: 200, msg: "OK"), ] @otp_ui = Gem::MockGemUi.new "111111\n" @@ -384,7 +405,7 @@ class TestGemCommandsPushCommand < Gem::TestCase def test_otp_verified_failure response = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry." - @fetcher.data["#{Gem.host}/api/v1/gems"] = [response, 401, "Unauthorized"] + @fetcher.data["#{Gem.host}/api/v1/gems"] = HTTPResponseFactory.create(body: response, code: 401, msg: "Unauthorized") @otp_ui = Gem::MockGemUi.new "111111\n" assert_raise Gem::MockGemUi::TermError do @@ -405,12 +426,12 @@ class TestGemCommandsPushCommand < Gem::TestCase response_success = "Successfully registered gem: freewill (1.0.0)" @fetcher.data["#{@host}/api/v1/gems"] = [ - [response_mfa_enabled, 401, "Unauthorized"], - [response_forbidden, 403, "Forbidden"], - [response_success, 200, "OK"], + HTTPResponseFactory.create(body: response_mfa_enabled, code: 401, msg: "Unauthorized"), + HTTPResponseFactory.create(body: response_forbidden, code: 403, msg: "Forbidden"), + HTTPResponseFactory.create(body: response_success, code: 200, msg: "OK"), ] - @fetcher.data["#{@host}/api/v1/api_key"] = ["", 200, "OK"] + @fetcher.data["#{@host}/api/v1/api_key"] = HTTPResponseFactory.create(body: "", code: 200, msg: "OK") @cmd.instance_variable_set :@host, @host @cmd.instance_variable_set :@scope, :push_rubygem @@ -438,16 +459,16 @@ class TestGemCommandsPushCommand < Gem::TestCase response_profile = "mfa: disabled\n" @fetcher.data["#{@host}/api/v1/gems"] = [ - [response_success, 200, "OK"], + HTTPResponseFactory.create(body: response_success, code: 200, msg: "OK"), ] @fetcher.data["#{@host}/api/v1/api_key"] = [ - [response_mfa_enabled, 401, "Unauthorized"], - ["", 200, "OK"], + HTTPResponseFactory.create(body: response_mfa_enabled, code: 401, msg: "Unauthorized"), + HTTPResponseFactory.create(body: "", code: 200, msg: "OK"), ] @fetcher.data["#{@host}/api/v1/profile/me.yaml"] = [ - [response_profile, 200, "OK"], + HTTPResponseFactory.create(body: response_profile, code: 200, msg: "OK"), ] @cmd.instance_variable_set :@scope, :push_rubygem diff --git a/test/rubygems/test_gem_commands_signin_command.rb b/test/rubygems/test_gem_commands_signin_command.rb index ce745bff20..281e4f9eac 100644 --- a/test/rubygems/test_gem_commands_signin_command.rb +++ b/test/rubygems/test_gem_commands_signin_command.rb @@ -71,6 +71,31 @@ class TestGemCommandsSigninCommand < Gem::TestCase assert_equal api_key, credentials[host] end + def test_execute_with_host_permanent_redirect + host = "http://rubygems.example/" + ENV["RUBYGEMS_HOST"] = host + path = "/api/v1/api_key" + redirected_uri = "http://rubygems.example#{path}" + fetcher = Gem::FakeFetcher.new + fetcher.data["#{host}#{path}"] = HTTPResponseFactory.create( + body: "", + code: "308", + msg: "Permanent Redirect", + headers: { "location" => redirected_uri } + ) + Gem::RemoteFetcher.fetcher = fetcher + ui = Gem::MockGemUi.new("you@example.com\nsecret\n\n\n\n\n\n\n\n\n") + + assert_raise Gem::MockGemUi::TermError do + use_ui ui do + @cmd.execute + end + end + + response = "The request has redirected permanently to #{redirected_uri}. Please check your defined push host URL." + assert_match response, ui.output + end + def test_execute_with_valid_creds_set_for_default_host util_capture { @cmd.execute } @@ -186,7 +211,7 @@ class TestGemCommandsSigninCommand < Gem::TestCase # Set the expected response for the Web-API supplied ENV["RUBYGEMS_HOST"] = host data_key = "#{ENV['RUBYGEMS_HOST']}/api/v1/api_key" - fetcher.data[data_key] = [api_key, 200, "OK"] + fetcher.data[data_key] = HTTPResponseFactory.create(body: api_key, code: 200, msg: "OK") use_ui key_name_ui do @cmd.execute @@ -209,8 +234,8 @@ class TestGemCommandsSigninCommand < Gem::TestCase def util_capture(ui_stub = nil, host = nil, api_key = nil, fetcher = Gem::FakeFetcher.new, mfa_level = "disabled", warning = nil) api_key ||= "a5fdbb6ba150cbb83aad2bb2fede64cf040453903" - response = [api_key, 200, "OK"] - profile_response = [ "mfa: #{mfa_level}\nwarning: #{warning}" , 200, "OK"] + response = HTTPResponseFactory.create(body: api_key, code: 200, msg: "OK") + profile_response = HTTPResponseFactory.create(body: "mfa: #{mfa_level}\nwarning: #{warning}", code: 200, msg: "OK") email = "you@example.com" password = "secret" diff --git a/test/rubygems/test_gem_commands_yank_command.rb b/test/rubygems/test_gem_commands_yank_command.rb index 878b52416e..d14395a75e 100644 --- a/test/rubygems/test_gem_commands_yank_command.rb +++ b/test/rubygems/test_gem_commands_yank_command.rb @@ -43,7 +43,7 @@ class TestGemCommandsYankCommand < Gem::TestCase def test_execute yank_uri = "http://example/api/v1/gems/yank" - @fetcher.data[yank_uri] = ["Successfully yanked", 200, "OK"] + @fetcher.data[yank_uri] = HTTPResponseFactory.create(body: "Successfully yanked", code: 200, msg: "OK") @cmd.options[:args] = %w[a] @cmd.options[:added_platform] = true @@ -69,8 +69,8 @@ class TestGemCommandsYankCommand < Gem::TestCase response_fail = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry." yank_uri = "http://example/api/v1/gems/yank" @fetcher.data[yank_uri] = [ - [response_fail, 401, "Unauthorized"], - ["Successfully yanked", 200, "OK"], + HTTPResponseFactory.create(body: response_fail, code: 401, msg: "Unauthorized"), + HTTPResponseFactory.create(body: "Successfully yanked", code: 200, msg: "OK"), ] @cmd.options[:args] = %w[a] @@ -92,7 +92,7 @@ class TestGemCommandsYankCommand < Gem::TestCase def test_execute_with_otp_failure response = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry." yank_uri = "http://example/api/v1/gems/yank" - @fetcher.data[yank_uri] = [response, 401, "Unauthorized"] + @fetcher.data[yank_uri] = HTTPResponseFactory.create(body: response, code: 401, msg: "Unauthorized") @cmd.options[:args] = %w[a] @cmd.options[:added_platform] = true @@ -111,7 +111,7 @@ class TestGemCommandsYankCommand < Gem::TestCase def test_execute_key yank_uri = "http://example/api/v1/gems/yank" - @fetcher.data[yank_uri] = ["Successfully yanked", 200, "OK"] + @fetcher.data[yank_uri] = HTTPResponseFactory.create(body: "Successfully yanked", code: 200, msg: "OK") @cmd.options[:args] = %w[a] @cmd.options[:version] = req("= 1.0") @@ -129,7 +129,7 @@ class TestGemCommandsYankCommand < Gem::TestCase def test_execute_host host = "https://other.example" yank_uri = "#{host}/api/v1/gems/yank" - @fetcher.data[yank_uri] = ["Successfully yanked", 200, "OK"] + @fetcher.data[yank_uri] = HTTPResponseFactory.create(body: "Successfully yanked", code: 200, msg: "OK") @cmd.options[:args] = %w[a] @cmd.options[:version] = req("= 1.0") @@ -154,11 +154,11 @@ class TestGemCommandsYankCommand < Gem::TestCase host = "http://example" @fetcher.data["#{host}/api/v1/gems/yank"] = [ - [response_forbidden, 403, "Forbidden"], - [response_success, 200, "OK"], + HTTPResponseFactory.create(body: response_forbidden, code: 403, msg: "Forbidden"), + HTTPResponseFactory.create(body: response_success, code: 200, msg: "OK"), ] - @fetcher.data["#{host}/api/v1/api_key"] = ["", 200, "OK"] + @fetcher.data["#{host}/api/v1/api_key"] = HTTPResponseFactory.create(body: "", code: 200, msg: "OK") @cmd.options[:args] = %w[a] @cmd.options[:added_platform] = true @cmd.options[:version] = req("= 1.0") diff --git a/test/rubygems/test_gem_gemcutter_utilities.rb b/test/rubygems/test_gem_gemcutter_utilities.rb index 2ca5b402d9..5e59733d5a 100644 --- a/test/rubygems/test_gem_gemcutter_utilities.rb +++ b/test/rubygems/test_gem_gemcutter_utilities.rb @@ -93,7 +93,7 @@ class TestGemGemcutterUtilities < Gem::TestCase def test_sign_in api_key = "a5fdbb6ba150cbb83aad2bb2fede64cf040453903" - util_sign_in [api_key, 200, "OK"] + util_sign_in HTTPResponseFactory.create(body: api_key, code: 200, msg: "OK") assert_match %r{Enter your RubyGems.org credentials.}, @sign_in_ui.output assert @fetcher.last_request["authorization"] @@ -106,7 +106,7 @@ class TestGemGemcutterUtilities < Gem::TestCase def test_sign_in_with_host api_key = "a5fdbb6ba150cbb83aad2bb2fede64cf040453903" - util_sign_in [api_key, 200, "OK"], "http://example.com", ["http://example.com"] + util_sign_in HTTPResponseFactory.create(body: api_key, code: 200, msg: "OK"), "http://example.com", ["http://example.com"] assert_match "Enter your http://example.com credentials.", @sign_in_ui.output @@ -120,7 +120,7 @@ class TestGemGemcutterUtilities < Gem::TestCase def test_sign_in_with_host_nil api_key = "a5fdbb6ba150cbb83aad2bb2fede64cf040453903" - util_sign_in [api_key, 200, "OK"], nil, [nil] + util_sign_in HTTPResponseFactory.create(body: api_key, code: 200, msg: "OK"), nil, [nil] assert_match "Enter your RubyGems.org credentials.", @sign_in_ui.output @@ -133,7 +133,7 @@ class TestGemGemcutterUtilities < Gem::TestCase def test_sign_in_with_host_ENV api_key = "a5fdbb6ba150cbb83aad2bb2fede64cf040453903" - util_sign_in [api_key, 200, "OK"], "http://example.com" + util_sign_in HTTPResponseFactory.create(body: api_key, code: 200, msg: "OK"), "http://example.com" assert_match "Enter your http://example.com credentials.", @sign_in_ui.output @@ -148,7 +148,7 @@ class TestGemGemcutterUtilities < Gem::TestCase api_key = "a5fdbb6ba150cbb83aad2bb2fede64cf040453903" Gem.configuration.rubygems_api_key = api_key - util_sign_in [api_key, 200, "OK"] + util_sign_in HTTPResponseFactory.create(body: api_key, code: 200, msg: "OK") assert_equal "", @sign_in_ui.output end @@ -157,7 +157,7 @@ class TestGemGemcutterUtilities < Gem::TestCase api_key = "a5fdbb6ba150cbb83aad2bb2fede64cf040453903" Gem.configuration.api_keys[:KEY] = "other" @cmd.options[:key] = :KEY - util_sign_in [api_key, 200, "OK"] + util_sign_in HTTPResponseFactory.create(body: api_key, code: 200, msg: "OK") assert_equal "", @sign_in_ui.output end @@ -169,7 +169,7 @@ class TestGemGemcutterUtilities < Gem::TestCase File.open Gem.configuration.credentials_path, "w" do |f| f.write Hash[:other_api_key, other_api_key].to_yaml end - util_sign_in [api_key, 200, "OK"] + util_sign_in HTTPResponseFactory.create(body: api_key, code: 200, msg: "OK") assert_match %r{Enter your RubyGems.org credentials.}, @sign_in_ui.output assert_match %r{Signed in.}, @sign_in_ui.output @@ -181,7 +181,7 @@ class TestGemGemcutterUtilities < Gem::TestCase def test_sign_in_with_bad_credentials assert_raise Gem::MockGemUi::TermError do - util_sign_in ["Access Denied.", 403, "Forbidden"] + util_sign_in HTTPResponseFactory.create(body: "Access Denied.", code: 403, msg: "Forbidden") end assert_match %r{Enter your RubyGems.org credentials.}, @sign_in_ui.output @@ -192,7 +192,7 @@ class TestGemGemcutterUtilities < Gem::TestCase ENV["GEM_HOST_OTP_CODE"] = "111111" api_key = "a5fdbb6ba150cbb83aad2bb2fede64cf040453903" - util_sign_in [api_key, 200, "OK"] + util_sign_in HTTPResponseFactory.create(body: api_key, code: 200, msg: "OK") assert_match "Signed in with API key:", @sign_in_ui.output assert_equal "111111", @fetcher.last_request["OTP"] @@ -204,7 +204,11 @@ class TestGemGemcutterUtilities < Gem::TestCase util_sign_in(proc do @call_count ||= 0 - (@call_count += 1).odd? ? [response_fail, 401, "Unauthorized"] : [api_key, 200, "OK"] + if (@call_count += 1).odd? + HTTPResponseFactory.create(body: response_fail, code: 401, msg: "Unauthorized") + else + HTTPResponseFactory.create(body: api_key, code: 200, msg: "OK") + end end, nil, [], "111111\n") assert_match "You have enabled multi-factor authentication. Please enter OTP code.", @sign_in_ui.output @@ -217,7 +221,7 @@ class TestGemGemcutterUtilities < Gem::TestCase response = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry." assert_raise Gem::MockGemUi::TermError do - util_sign_in [response, 401, "Unauthorized"], nil, [], "111111\n" + util_sign_in HTTPResponseFactory.create(body: response, code: 401, msg: "Unauthorized"), nil, [], "111111\n" end assert_match "You have enabled multi-factor authentication. Please enter OTP code.", @sign_in_ui.output @@ -229,7 +233,7 @@ class TestGemGemcutterUtilities < Gem::TestCase def util_sign_in(response, host = nil, args = [], extra_input = "") email = "you@example.com" password = "secret" - profile_response = [ "mfa: disabled\n" , 200, "OK"] + profile_response = HTTPResponseFactory.create(body: "mfa: disabled\n", code: 200, msg: "OK") if host ENV["RUBYGEMS_HOST"] = host diff --git a/test/rubygems/test_gem_package.rb b/test/rubygems/test_gem_package.rb index 9295f42dba..eebe4d86d0 100644 --- a/test/rubygems/test_gem_package.rb +++ b/test/rubygems/test_gem_package.rb @@ -510,6 +510,21 @@ class TestGemPackage < Gem::Package::TarTestCase assert_path_exist @destination end + def test_extract_file_permissions + pend "chmod not supported" if win_platform? + + gem_with_long_permissions = File.expand_path("packages/Bluebie-legs-0.6.2.gem", __dir__) + + package = Gem::Package.new gem_with_long_permissions + + package.extract_files @destination + + filepath = File.join @destination, "README.rdoc" + assert_path_exist filepath + + assert_equal 0104444, File.stat(filepath).mode + end + def test_extract_tar_gz_absolute package = Gem::Package.new @gem diff --git a/test/rubygems/test_gem_platform.rb b/test/rubygems/test_gem_platform.rb index 576f150219..61547d8972 100644 --- a/test/rubygems/test_gem_platform.rb +++ b/test/rubygems/test_gem_platform.rb @@ -333,6 +333,34 @@ class TestGemPlatform < Gem::TestCase refute(arm_linux_uclibceabi === arm_linux_eabi, "linux-uclibceabi =~ linux-eabi") end + def test_eabi_and_nil_version_combination_strictness + arm_linux = Gem::Platform.new "arm-linux" + arm_linux_eabi = Gem::Platform.new "arm-linux-eabi" + arm_linux_eabihf = Gem::Platform.new "arm-linux-eabihf" + arm_linux_gnueabi = Gem::Platform.new "arm-linux-gnueabi" + arm_linux_gnueabihf = Gem::Platform.new "arm-linux-gnueabihf" + arm_linux_musleabi = Gem::Platform.new "arm-linux-musleabi" + arm_linux_musleabihf = Gem::Platform.new "arm-linux-musleabihf" + arm_linux_uclibceabi = Gem::Platform.new "arm-linux-uclibceabi" + arm_linux_uclibceabihf = Gem::Platform.new "arm-linux-uclibceabihf" + + # generic arm host runtime with eabi modifier accepts generic arm gems + assert(arm_linux === arm_linux_eabi, "arm-linux =~ arm-linux-eabi") + assert(arm_linux === arm_linux_eabihf, "arm-linux =~ arm-linux-eabihf") + + # explicit gnu arm host runtime with eabi modifier accepts generic arm gems + assert(arm_linux === arm_linux_gnueabi, "arm-linux =~ arm-linux-gnueabi") + assert(arm_linux === arm_linux_gnueabihf, "arm-linux =~ arm-linux-gnueabihf") + + # musl arm host runtime accepts libc-generic or statically linked gems... + assert(arm_linux === arm_linux_musleabi, "arm-linux =~ arm-linux-musleabi") + assert(arm_linux === arm_linux_musleabihf, "arm-linux =~ arm-linux-musleabihf") + + # other libc arm hosts are not glibc compatible + refute(arm_linux === arm_linux_uclibceabi, "arm-linux =~ arm-linux-uclibceabi") + refute(arm_linux === arm_linux_uclibceabihf, "arm-linux =~ arm-linux-uclibceabihf") + end + def test_equals3_cpu_arm arm = Gem::Platform.new "arm-linux" armv5 = Gem::Platform.new "armv5-linux" @@ -452,6 +480,13 @@ class TestGemPlatform < Gem::TestCase assert_equal 1, result.scan(/@version=/).size end + def test_gem_platform_match_with_string_argument + util_set_arch "x86_64-linux-musl" + + assert(Gem::Platform.match(Gem::Platform.new("x86_64-linux")), "should match Gem::Platform") + assert(Gem::Platform.match("x86_64-linux"), "should match String platform") + end + def assert_local_match(name) assert_match Gem::Platform.local, name end diff --git a/test/rubygems/test_gem_resolver.rb b/test/rubygems/test_gem_resolver.rb index c816d5484b..54497c6e4f 100644 --- a/test/rubygems/test_gem_resolver.rb +++ b/test/rubygems/test_gem_resolver.rb @@ -391,6 +391,39 @@ class TestGemResolver < Gem::TestCase end end + def test_pick_generic_linux_variants_on_musl_linux + util_set_arch "aarch64-linux-musl" do + is = Gem::Resolver::IndexSpecification + + linux = Gem::Platform.new("aarch64-linux") + + spec_fetcher do |fetcher| + fetcher.spec "libv8-node", "15.14.0.1" do |s| + s.platform = linux + end + + fetcher.spec "libv8-node", "15.14.0.1" + end + + v15 = v("15.14.0.1") + source = Gem::Source.new @gem_repo + + s = set + + v15_ruby = is.new s, "libv8-node", v15, source, Gem::Platform::RUBY + v15_linux = is.new s, "libv8-node", v15, source, linux.to_s + + s.add v15_linux + s.add v15_ruby + + ad = make_dep "libv8-node", "= 15.14.0.1" + + res = Gem::Resolver.new([ad], s) + + assert_resolves_to [v15_linux.spec], res + end + end + def test_only_returns_spec_once a1 = util_spec "a", "1", "c" => "= 1" b1 = util_spec "b", "1", "c" => "= 1" diff --git a/test/rubygems/test_require.rb b/test/rubygems/test_require.rb index 6135acea92..222bdcfb28 100644 --- a/test/rubygems/test_require.rb +++ b/test/rubygems/test_require.rb @@ -252,9 +252,9 @@ class TestGemRequire < Gem::TestCase # Activates a-1, but not b-1 and b-2 assert_require "test_gem_require_a" assert_equal %w[a-1], loaded_spec_names - assert $LOAD_PATH.include? a1.load_paths[0] - refute $LOAD_PATH.include? b1.load_paths[0] - refute $LOAD_PATH.include? b2.load_paths[0] + assert $LOAD_PATH.include? a1.full_require_paths[0] + refute $LOAD_PATH.include? b1.full_require_paths[0] + refute $LOAD_PATH.include? b2.full_require_paths[0] assert_equal unresolved_names, ["b (>= 1)"] @@ -265,13 +265,13 @@ class TestGemRequire < Gem::TestCase # and as a result #gem_original_require returns false. refute require("benchmark"), "the benchmark stdlib should be recognized as already loaded" - assert_includes $LOAD_PATH, b2.load_paths[0] + assert_includes $LOAD_PATH, b2.full_require_paths[0] assert_includes $LOAD_PATH, rubylibdir message = proc { "this test relies on the b-2 gem lib/ to be before stdlib to make sense\n" + $LOAD_PATH.pretty_inspect } - assert_operator $LOAD_PATH.index(b2.load_paths[0]), :<, $LOAD_PATH.index(rubylibdir), message + assert_operator $LOAD_PATH.index(b2.full_require_paths[0]), :<, $LOAD_PATH.index(rubylibdir), message # We detected that we should activate b-2, so we did so, but # then #gem_original_require decided "I've already got some benchmark.rb" loaded. diff --git a/test/rubygems/utilities.rb b/test/rubygems/utilities.rb index c01f7acd48..8b9fa98e3d 100644 --- a/test/rubygems/utilities.rb +++ b/test/rubygems/utilities.rb @@ -54,13 +54,21 @@ class Gem::FakeFetcher raise Gem::RemoteFetcher::FetchError.new("no data for #{path}", path) end - if @data[path].kind_of?(Array) && @data[path].first.kind_of?(Array) + if @data[path].kind_of?(Array) @data[path].shift else @data[path] end end + def create_response(uri) + data = find_data(uri) + response = data.respond_to?(:call) ? data.call : data + raise TypeError, "#{response.class} is not a type of Net::HTTPResponse" unless response.kind_of?(Net::HTTPResponse) + + response + end + def fetch_path(path, mtime = nil, head = false) data = find_data(path) @@ -85,26 +93,16 @@ class Gem::FakeFetcher # Thanks, FakeWeb! def open_uri_or_path(path) - data = find_data(path) - body, code, msg = data + find_data(path) - response = Net::HTTPResponse.send(:response_class, code.to_s).new("1.0", code.to_s, msg) - response.instance_variable_set(:@body, body) - response.instance_variable_set(:@read, true) - response + create_response(uri) end def request(uri, request_class, last_modified = nil) - data = find_data(uri) - body, code, msg = (data.respond_to?(:call) ? data.call : data) - @last_request = request_class.new uri.request_uri yield @last_request if block_given? - response = Net::HTTPResponse.send(:response_class, code.to_s).new("1.0", code.to_s, msg) - response.instance_variable_set(:@body, body) - response.instance_variable_set(:@read, true) - response + create_response(uri) end def pretty_print(q) # :nodoc: @@ -164,6 +162,30 @@ class Gem::FakeFetcher end end +## +# The HTTPResponseFactory allows easy creation of Net::HTTPResponse instances in RubyGems tests: +# +# Example: +# +# HTTPResponseFactory.create( +# body: "", +# code: 301, +# msg: "Moved Permanently", +# headers: { "location" => "http://example.com" } +# ) +# + +class HTTPResponseFactory + def self.create(body:, code:, msg:, headers: {}) + response = Net::HTTPResponse.send(:response_class, code.to_s).new("1.0", code.to_s, msg) + response.instance_variable_set(:@body, body) + response.instance_variable_set(:@read, true) + headers.each {|name, value| response[name] = value } + + response + end +end + # :stopdoc: class Gem::RemoteFetcher def self.fetcher=(fetcher) diff --git a/tool/bundler/dev_gems.rb.lock b/tool/bundler/dev_gems.rb.lock index 03dceb8816..5fac17bcfd 100644 --- a/tool/bundler/dev_gems.rb.lock +++ b/tool/bundler/dev_gems.rb.lock @@ -53,4 +53,4 @@ DEPENDENCIES webrick (~> 1.6) BUNDLED WITH - 2.3.22 + 2.3.23 diff --git a/tool/bundler/rubocop_gems.rb.lock b/tool/bundler/rubocop_gems.rb.lock index 3325a5a18b..b64bbf0e60 100644 --- a/tool/bundler/rubocop_gems.rb.lock +++ b/tool/bundler/rubocop_gems.rb.lock @@ -47,11 +47,13 @@ PLATFORMS aarch64-linux arm64-darwin-20 arm64-darwin-21 + arm64-darwin-22 universal-java-11 universal-java-18 x64-mingw-ucrt x86_64-darwin-19 x86_64-darwin-20 + x86_64-darwin-21 x86_64-linux DEPENDENCIES @@ -63,4 +65,4 @@ DEPENDENCIES test-unit BUNDLED WITH - 2.3.22 + 2.3.23 diff --git a/tool/bundler/standard_gems.rb.lock b/tool/bundler/standard_gems.rb.lock index 0fb3ada1f0..0c9bfcfa2d 100644 --- a/tool/bundler/standard_gems.rb.lock +++ b/tool/bundler/standard_gems.rb.lock @@ -53,11 +53,13 @@ PLATFORMS aarch64-linux arm64-darwin-20 arm64-darwin-21 + arm64-darwin-22 universal-java-11 universal-java-18 x64-mingw-ucrt x86_64-darwin-19 x86_64-darwin-20 + x86_64-darwin-21 x86_64-linux DEPENDENCIES @@ -69,4 +71,4 @@ DEPENDENCIES test-unit BUNDLED WITH - 2.3.22 + 2.3.23 diff --git a/tool/bundler/test_gems.rb.lock b/tool/bundler/test_gems.rb.lock index a0a4529dff..0fdf9240b4 100644 --- a/tool/bundler/test_gems.rb.lock +++ b/tool/bundler/test_gems.rb.lock @@ -43,4 +43,4 @@ DEPENDENCIES webrick (= 1.7.0) BUNDLED WITH - 2.3.22 + 2.3.23 |