diff options
-rw-r--r-- | lib/bundler/cli/install.rb | 19 | ||||
-rw-r--r-- | lib/bundler/resolver.rb | 2 | ||||
-rw-r--r-- | lib/bundler/version.rb | 2 | ||||
-rw-r--r-- | lib/rubygems.rb | 2 | ||||
-rw-r--r-- | lib/rubygems/commands/owner_command.rb | 1 | ||||
-rw-r--r-- | lib/rubygems/commands/push_command.rb | 1 | ||||
-rw-r--r-- | lib/rubygems/commands/yank_command.rb | 1 | ||||
-rw-r--r-- | lib/rubygems/ext/rake_builder.rb | 2 | ||||
-rw-r--r-- | lib/rubygems/gemcutter_utilities.rb | 35 | ||||
-rw-r--r-- | lib/rubygems/test_utilities.rb | 11 | ||||
-rw-r--r-- | spec/bundler/commands/console_spec.rb | 8 | ||||
-rw-r--r-- | spec/bundler/commands/lock_spec.rb | 41 | ||||
-rw-r--r-- | spec/bundler/install/gemfile/groups_spec.rb | 20 | ||||
-rw-r--r-- | spec/bundler/realworld/fixtures/warbler/Gemfile.lock | 2 | ||||
-rw-r--r-- | test/rubygems/test_gem_commands_push_command.rb | 43 | ||||
-rw-r--r-- | test/rubygems/test_gem_ext_rake_builder.rb | 25 |
16 files changed, 175 insertions, 40 deletions
diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb index edf86fe1ba..c702eb14d1 100644 --- a/lib/bundler/cli/install.rb +++ b/lib/bundler/cli/install.rb @@ -152,18 +152,27 @@ module Bundler check_for_group_conflicts_in_cli_options + Bundler.settings.set_command_option :with, nil if options[:with] == [] + Bundler.settings.set_command_option :without, nil if options[:without] == [] + with = options.fetch(:with, []) with |= Bundler.settings[:with].map(&:to_s) with -= options[:without] if options[:without] - with = nil if options[:with] == [] without = options.fetch(:without, []) without |= Bundler.settings[:without].map(&:to_s) without -= options[:with] if options[:with] - without = nil if options[:without] == [] - Bundler.settings.set_command_option :without, without - Bundler.settings.set_command_option :with, with + options[:with] = with + options[:without] = without + + unless Bundler.settings[:without] == options[:without] && Bundler.settings[:with] == options[:with] + # need to nil them out first to get around validation for backwards compatibility + Bundler.settings.set_command_option :without, nil + Bundler.settings.set_command_option :with, nil + Bundler.settings.set_command_option :without, options[:without] - options[:with] + Bundler.settings.set_command_option :with, options[:with] + end end def normalize_settings @@ -190,7 +199,7 @@ module Bundler Bundler.settings.set_command_option_if_given :clean, options["clean"] - normalize_groups if options[:without] || options[:with] + normalize_groups options[:force] = options[:redownload] end diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index 4bbcbd1162..636dc8af46 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -155,6 +155,8 @@ module Bundler search.each do |sg| next unless sg.for?(platform) sg_all_platforms = sg.copy_for(self.class.sort_platforms(@platforms).reverse) + next unless sg_all_platforms + selected_sgs << sg_all_platforms next if sg_all_platforms.activated_platforms == [Gem::Platform::RUBY] diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb index b8b331d85e..c730934258 100644 --- a/lib/bundler/version.rb +++ b/lib/bundler/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false module Bundler - VERSION = "2.2.1".freeze + VERSION = "2.2.2".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 7596585482..5da8b6904b 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -8,7 +8,7 @@ require 'rbconfig' module Gem - VERSION = "3.2.1".freeze + VERSION = "3.2.2".freeze end # Must be first since it unloads the prelude from 1.9.2 diff --git a/lib/rubygems/commands/owner_command.rb b/lib/rubygems/commands/owner_command.rb index 46172854cf..dd49027469 100644 --- a/lib/rubygems/commands/owner_command.rb +++ b/lib/rubygems/commands/owner_command.rb @@ -105,7 +105,6 @@ permission to. rubygems_api_request method, "api/v1/gems/#{name}/owners", scope: get_owner_scope(method: method) do |request| request.set_form_data 'email' => owner request.add_field "Authorization", api_key - request.add_field "OTP", options[:otp] if options[:otp] end end diff --git a/lib/rubygems/commands/push_command.rb b/lib/rubygems/commands/push_command.rb index 8885269ecb..1a9a1932f8 100644 --- a/lib/rubygems/commands/push_command.rb +++ b/lib/rubygems/commands/push_command.rb @@ -91,7 +91,6 @@ The push command will use ~/.gem/credentials to authenticate to a server, but yo request.add_field "Content-Length", request.body.size request.add_field "Content-Type", "application/octet-stream" request.add_field "Authorization", api_key - request.add_field "OTP", options[:otp] if options[:otp] end end diff --git a/lib/rubygems/commands/yank_command.rb b/lib/rubygems/commands/yank_command.rb index 0e08bbfd5d..7e8b66b300 100644 --- a/lib/rubygems/commands/yank_command.rb +++ b/lib/rubygems/commands/yank_command.rb @@ -74,7 +74,6 @@ data you will need to change them immediately and yank your gem. name = get_one_gem_name response = rubygems_api_request(method, api, host, scope: get_yank_scope) do |request| request.add_field("Authorization", api_key) - request.add_field("OTP", options[:otp]) if options[:otp] data = { 'gem_name' => name, diff --git a/lib/rubygems/ext/rake_builder.rb b/lib/rubygems/ext/rake_builder.rb index 34c3922f2f..64a6c0eb80 100644 --- a/lib/rubygems/ext/rake_builder.rb +++ b/lib/rubygems/ext/rake_builder.rb @@ -19,7 +19,7 @@ class Gem::Ext::RakeBuilder < Gem::Ext::Builder rake = rake.shellsplit else begin - rake = [Gem.ruby, "-I#{File.expand_path("..", __dir__)}", "-rrubygems", Gem.bin_path('rake', 'rake')] + rake = [Gem.ruby, "-I#{File.expand_path("../..", __dir__)}", "-rrubygems", Gem.bin_path('rake', 'rake')] rescue Gem::Exception rake = [Gem.default_exec_format % 'rake'] end diff --git a/lib/rubygems/gemcutter_utilities.rb b/lib/rubygems/gemcutter_utilities.rb index d021f47e24..8751a79d63 100644 --- a/lib/rubygems/gemcutter_utilities.rb +++ b/lib/rubygems/gemcutter_utilities.rb @@ -94,20 +94,16 @@ module Gem::GemcutterUtilities end uri = URI.parse "#{self.host}/#{path}" - - request_method = Net::HTTP.const_get method.to_s.capitalize - response = Gem::RemoteFetcher.fetcher.request(uri, request_method, &block) + response = request_with_otp(method, uri, &block) if mfa_unauthorized?(response) - response = Gem::RemoteFetcher.fetcher.request(uri, request_method) do |req| - req.add_field "OTP", get_otp - block.call(req) - end + ask_otp + response = request_with_otp(method, uri, &block) end if api_key_forbidden?(response) update_scope(scope) - Gem::RemoteFetcher.fetcher.request(uri, request_method, &block) + request_with_otp(method, uri, &block) else response end @@ -117,11 +113,6 @@ module Gem::GemcutterUtilities response.kind_of?(Net::HTTPUnauthorized) && response.body.start_with?('You have enabled multifactor authentication') end - def get_otp - say 'You have enabled multi-factor authentication. Please enter OTP code.' - ask 'Code: ' - end - def update_scope(scope) sign_in_host = self.host pretty_host = pretty_host(sign_in_host) @@ -135,7 +126,7 @@ module Gem::GemcutterUtilities response = rubygems_api_request(:put, "api/v1/api_key", sign_in_host, scope: scope) do |request| request.basic_auth email, password - request.add_field "OTP", options[:otp] if options[:otp] + request["OTP"] = options[:otp] if options[:otp] request.body = URI.encode_www_form({:api_key => api_key }.merge(update_scope_params)) end @@ -168,7 +159,7 @@ module Gem::GemcutterUtilities response = rubygems_api_request(:post, "api/v1/api_key", sign_in_host, scope: scope) do |request| request.basic_auth email, password - request.add_field "OTP", options[:otp] if options[:otp] + request["OTP"] = options[:otp] if options[:otp] request.body = URI.encode_www_form({ name: key_name }.merge(scope_params)) end @@ -229,6 +220,20 @@ module Gem::GemcutterUtilities private + def request_with_otp(method, uri, &block) + request_method = Net::HTTP.const_get method.to_s.capitalize + + Gem::RemoteFetcher.fetcher.request(uri, request_method) do |req| + req["OTP"] = options[:otp] if options[:otp] + block.call(req) + end + end + + def ask_otp + say 'You have enabled multi-factor authentication. Please enter OTP code.' + options[:otp] = ask 'Code: ' + end + def pretty_host(host) if Gem::DEFAULT_HOST == host 'RubyGems.org' diff --git a/lib/rubygems/test_utilities.rb b/lib/rubygems/test_utilities.rb index 3bbe68ca0c..1371ae9b14 100644 --- a/lib/rubygems/test_utilities.rb +++ b/lib/rubygems/test_utilities.rb @@ -38,7 +38,7 @@ class Gem::FakeFetcher @paths = [] end - def find_data(path, nargs = 3) + def find_data(path) return Gem.read_binary path.path if URI === path and 'file' == path.scheme if URI === path and "URI::#{path.scheme.upcase}" != path.class.name @@ -54,10 +54,11 @@ class Gem::FakeFetcher raise Gem::RemoteFetcher::FetchError.new("no data for #{path}", path) end - data = @data[path] - - data.flatten! and return data.shift(nargs) if data.respond_to?(:flatten!) - data + if @data[path].kind_of?(Array) && @data[path].first.kind_of?(Array) + @data[path].shift + else + @data[path] + end end def fetch_path(path, mtime = nil, head = false) diff --git a/spec/bundler/commands/console_spec.rb b/spec/bundler/commands/console_spec.rb index 6f1e96261e..aa76096e3d 100644 --- a/spec/bundler/commands/console_spec.rb +++ b/spec/bundler/commands/console_spec.rb @@ -55,10 +55,10 @@ RSpec.describe "bundle console", :bundler => "< 3", :readline => true do it "uses IRB as default console" do bundle "console" do |input, _, _| - input.puts("__method__") + input.puts("__FILE__") input.puts("exit") end - expect(out).to include(":irb_binding") + expect(out).to include("(irb)") end it "starts another REPL if configured as such" do @@ -80,10 +80,10 @@ RSpec.describe "bundle console", :bundler => "< 3", :readline => true do # make sure pry isn't there bundle "console" do |input, _, _| - input.puts("__method__") + input.puts("__FILE__") input.puts("exit") end - expect(out).to include(":irb_binding") + expect(out).to include("(irb)") end it "doesn't load any other groups" do diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb index cc56c34952..6400152039 100644 --- a/spec/bundler/commands/lock_spec.rb +++ b/spec/bundler/commands/lock_spec.rb @@ -342,6 +342,47 @@ RSpec.describe "bundle lock" do G end + it "doesn't crash when an update candidate doesn't have any matching platform" do + build_repo4 do + build_gem "libv8", "8.4.255.0" + build_gem "libv8", "8.4.255.0" do |s| + s.platform = "x86_64-darwin-19" + end + + build_gem "libv8", "15.0.71.48.1beta2" do |s| + s.platform = "x86_64-linux" + end + end + + gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + + gem "libv8" + G + + lockfile <<-G + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + libv8 (8.4.255.0) + libv8 (8.4.255.0-x86_64-darwin-19) + + PLATFORMS + ruby + x86_64-darwin-19 + + DEPENDENCIES + libv8 + + BUNDLED WITH + #{Bundler::VERSION} + G + + simulate_platform(Gem::Platform.new("x86_64-darwin-19")) { bundle "lock --update" } + + expect(out).to match(/Writing lockfile to.+Gemfile\.lock/) + end + context "when an update is available" do let(:repo) { gem_repo2 } diff --git a/spec/bundler/install/gemfile/groups_spec.rb b/spec/bundler/install/gemfile/groups_spec.rb index 4e7484ddbd..567a9b1172 100644 --- a/spec/bundler/install/gemfile/groups_spec.rb +++ b/spec/bundler/install/gemfile/groups_spec.rb @@ -91,8 +91,17 @@ RSpec.describe "bundle install with groups" do expect(the_bundle).to include_gems "rack 1.0.0", :groups => [:default] end - it "respects global `without` configuration, but does not save it locally" do - bundle "config without emo" + it "respects global `without` configuration, and saves it locally", :bundler => "< 3" do + bundle "config set without emo" + bundle :install + expect(the_bundle).to include_gems "rack 1.0.0", :groups => [:default] + bundle "config list" + expect(out).to include("Set for your local app (#{bundled_app(".bundle/config")}): [:emo]") + expect(out).to include("Set for the current user (#{home(".bundle/config")}): [:emo]") + end + + it "respects global `without` configuration, but does not save it locally", :bundler => "3" do + bundle "config set without emo" bundle :install expect(the_bundle).to include_gems "rack 1.0.0", :groups => [:default] bundle "config list" @@ -100,6 +109,13 @@ RSpec.describe "bundle install with groups" do expect(out).to include("Set for the current user (#{home(".bundle/config")}): [:emo]") end + it "allows running application where groups where configured by a different user", :bundler => "< 3" do + bundle "config set without emo" + bundle :install + bundle "exec ruby -e 'puts 42'", :env => { "BUNDLE_USER_HOME" => tmp("new_home").to_s } + expect(out).to include("42") + end + it "does not install gems from the excluded group" do bundle "config --local without emo" bundle :install diff --git a/spec/bundler/realworld/fixtures/warbler/Gemfile.lock b/spec/bundler/realworld/fixtures/warbler/Gemfile.lock index bcf0799494..6945be3ed2 100644 --- a/spec/bundler/realworld/fixtures/warbler/Gemfile.lock +++ b/spec/bundler/realworld/fixtures/warbler/Gemfile.lock @@ -6,7 +6,7 @@ PATH GEM remote: https://rubygems.org/ specs: - jruby-jars (9.2.11.1) + jruby-jars (9.2.14.0) jruby-rack (1.1.21) rake (13.0.1) rubyzip (1.3.0) diff --git a/test/rubygems/test_gem_commands_push_command.rb b/test/rubygems/test_gem_commands_push_command.rb index 68681af22f..55dd51e6ad 100644 --- a/test/rubygems/test_gem_commands_push_command.rb +++ b/test/rubygems/test_gem_commands_push_command.rb @@ -404,11 +404,13 @@ class TestGemCommandsPushCommand < Gem::TestCase assert_equal '111111', @fetcher.last_request['OTP'] end - def test_sending_gem_unathorized_api_key + def test_sending_gem_unathorized_api_key_with_mfa_enabled + response_mfa_enabled = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry." response_forbidden = "The API key doesn't have access" 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"], ] @@ -417,17 +419,54 @@ class TestGemCommandsPushCommand < Gem::TestCase @cmd.instance_variable_set :@host, @host @cmd.instance_variable_set :@scope, :push_rubygem - @ui = Gem::MockGemUi.new "some@mail.com\npass\n" + @ui = Gem::MockGemUi.new "11111\nsome@mail.com\npass\n" use_ui @ui do @cmd.send_gem(@path) end + mfa_notice = "You have enabled multi-factor authentication. Please enter OTP code." access_notice = "The existing key doesn't have access of push_rubygem on https://rubygems.example. Please sign in to update access." + assert_match mfa_notice, @ui.output assert_match access_notice, @ui.output assert_match "Email:", @ui.output assert_match "Password:", @ui.output assert_match "Added push_rubygem scope to the existing API key", @ui.output assert_match response_success, @ui.output + assert_equal '11111', @fetcher.last_request['OTP'] + end + + def test_sending_gem_with_no_local_creds + Gem.configuration.rubygems_api_key = nil + + response_mfa_enabled = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry." + response_success = 'Successfully registered gem: freewill (1.0.0)' + + @fetcher.data["#{@host}/api/v1/gems"] = [ + [response_success, 200, "OK"], + ] + + @fetcher.data["#{@host}/api/v1/api_key"] = [ + [response_mfa_enabled, 401, 'Unauthorized'], + ["", 200, "OK"], + ] + + @cmd.instance_variable_set :@scope, :push_rubygem + @cmd.options[:args] = [@path] + @cmd.options[:host] = @host + + @ui = Gem::MockGemUi.new "some@mail.com\npass\n11111\n" + use_ui @ui do + @cmd.execute + end + + mfa_notice = "You have enabled multi-factor authentication. Please enter OTP code." + assert_match mfa_notice, @ui.output + assert_match "Enter your https://rubygems.example credentials.", @ui.output + assert_match "Email:", @ui.output + assert_match "Password:", @ui.output + assert_match "Signed in with API key:", @ui.output + assert_match response_success, @ui.output + assert_equal '11111', @fetcher.last_request['OTP'] end private diff --git a/test/rubygems/test_gem_ext_rake_builder.rb b/test/rubygems/test_gem_ext_rake_builder.rb index 8cb96f7dd3..094581890a 100644 --- a/test/rubygems/test_gem_ext_rake_builder.rb +++ b/test/rubygems/test_gem_ext_rake_builder.rb @@ -47,6 +47,31 @@ class TestGemExtRakeBuilder < Gem::TestCase end end + def test_class_no_openssl_override + create_temp_mkrf_file('task :default') + + rake = util_spec 'rake' do |s| + s.executables = %w[rake] + s.files = %w[bin/rake] + end + + output = [] + + write_file File.join(@tempdir, 'bin', 'rake') do |fp| + fp.puts "#!/usr/bin/ruby" + fp.puts "require 'openssl'; puts OpenSSL" + end + + install_gem rake + + Gem::Ext::RakeBuilder.build 'mkrf_conf.rb', @dest_path, output, [''], nil, @ext + + output = output.join "\n" + + assert_match "OpenSSL", output + assert_match %r{^#{Regexp.escape Gem.ruby} mkrf_conf\.rb}, output + end + def test_class_build_no_mkrf_passes_args output = [] |