summaryrefslogtreecommitdiff
path: root/spec/bundler
diff options
context:
space:
mode:
Diffstat (limited to 'spec/bundler')
-rw-r--r--spec/bundler/bundler/bundler_spec.rb251
-rw-r--r--spec/bundler/bundler/ci_detector_spec.rb21
-rw-r--r--spec/bundler/bundler/cli_spec.rb96
-rw-r--r--spec/bundler/bundler/compact_index_client/updater_spec.rb215
-rw-r--r--spec/bundler/bundler/definition_spec.rb129
-rw-r--r--spec/bundler/bundler/dep_proxy_spec.rb32
-rw-r--r--spec/bundler/bundler/dependency_spec.rb167
-rw-r--r--spec/bundler/bundler/digest_spec.rb24
-rw-r--r--spec/bundler/bundler/dsl_spec.rb149
-rw-r--r--spec/bundler/bundler/endpoint_specification_spec.rb48
-rw-r--r--spec/bundler/bundler/env_spec.rb36
-rw-r--r--spec/bundler/bundler/environment_preserver_spec.rb16
-rw-r--r--spec/bundler/bundler/fetcher/base_spec.rb11
-rw-r--r--spec/bundler/bundler/fetcher/compact_index_spec.rb9
-rw-r--r--spec/bundler/bundler/fetcher/dependency_spec.rb43
-rw-r--r--spec/bundler/bundler/fetcher/downloader_spec.rb90
-rw-r--r--spec/bundler/bundler/fetcher/index_spec.rb30
-rw-r--r--spec/bundler/bundler/fetcher_spec.rb130
-rw-r--r--spec/bundler/bundler/friendly_errors_spec.rb20
-rw-r--r--spec/bundler/bundler/gem_helper_spec.rb58
-rw-r--r--spec/bundler/bundler/gem_version_promoter_spec.rb246
-rw-r--r--spec/bundler/bundler/installer/gem_installer_spec.rb20
-rw-r--r--spec/bundler/bundler/installer/parallel_installer_spec.rb80
-rw-r--r--spec/bundler/bundler/installer/spec_installation_spec.rb18
-rw-r--r--spec/bundler/bundler/lockfile_parser_spec.rb78
-rw-r--r--spec/bundler/bundler/mirror_spec.rb16
-rw-r--r--spec/bundler/bundler/plugin/api/source_spec.rb4
-rw-r--r--spec/bundler/bundler/plugin/dsl_spec.rb6
-rw-r--r--spec/bundler/bundler/plugin/index_spec.rb10
-rw-r--r--spec/bundler/bundler/plugin/installer_spec.rb23
-rw-r--r--spec/bundler/bundler/plugin_spec.rb39
-rw-r--r--spec/bundler/bundler/psyched_yaml_spec.rb9
-rw-r--r--spec/bundler/bundler/remote_specification_spec.rb14
-rw-r--r--spec/bundler/bundler/resolver/candidate_spec.rb21
-rw-r--r--spec/bundler/bundler/ruby_dsl_spec.rb115
-rw-r--r--spec/bundler/bundler/ruby_version_spec.rb46
-rw-r--r--spec/bundler/bundler/rubygems_integration_spec.rb49
-rw-r--r--spec/bundler/bundler/settings/validator_spec.rb6
-rw-r--r--spec/bundler/bundler/settings_spec.rb27
-rw-r--r--spec/bundler/bundler/shared_helpers_spec.rb84
-rw-r--r--spec/bundler/bundler/source/git/git_proxy_spec.rb139
-rw-r--r--spec/bundler/bundler/source/git_spec.rb45
-rw-r--r--spec/bundler/bundler/source/rubygems/remote_spec.rb20
-rw-r--r--spec/bundler/bundler/source_list_spec.rb6
-rw-r--r--spec/bundler/bundler/source_spec.rb58
-rw-r--r--spec/bundler/bundler/spec_set_spec.rb18
-rw-r--r--spec/bundler/bundler/specifications/foo.gemspec13
-rw-r--r--spec/bundler/bundler/stub_specification_spec.rb11
-rw-r--r--spec/bundler/bundler/uri_credentials_filter_spec.rb10
-rw-r--r--spec/bundler/bundler/vendored_persistent_spec.rb77
-rw-r--r--spec/bundler/bundler/version_ranges_spec.rb40
-rw-r--r--spec/bundler/bundler/yaml_serializer_spec.rb57
-rw-r--r--spec/bundler/cache/gems_spec.rb109
-rw-r--r--spec/bundler/cache/git_spec.rb85
-rw-r--r--spec/bundler/cache/path_spec.rb10
-rw-r--r--spec/bundler/cache/platform_spec.rb2
-rw-r--r--spec/bundler/commands/add_spec.rb147
-rw-r--r--spec/bundler/commands/binstubs_spec.rb125
-rw-r--r--spec/bundler/commands/cache_spec.rb38
-rw-r--r--spec/bundler/commands/check_spec.rb179
-rw-r--r--spec/bundler/commands/clean_spec.rb64
-rw-r--r--spec/bundler/commands/config_spec.rb132
-rw-r--r--spec/bundler/commands/console_spec.rb2
-rw-r--r--spec/bundler/commands/doctor_spec.rb25
-rw-r--r--spec/bundler/commands/exec_spec.rb174
-rw-r--r--spec/bundler/commands/fund_spec.rb16
-rw-r--r--spec/bundler/commands/help_spec.rb13
-rw-r--r--spec/bundler/commands/info_spec.rb78
-rw-r--r--spec/bundler/commands/init_spec.rb60
-rw-r--r--spec/bundler/commands/inject_spec.rb12
-rw-r--r--spec/bundler/commands/install_spec.rb739
-rw-r--r--spec/bundler/commands/list_spec.rb12
-rw-r--r--spec/bundler/commands/lock_spec.rb1149
-rw-r--r--spec/bundler/commands/newgem_spec.rb336
-rw-r--r--spec/bundler/commands/open_spec.rb90
-rw-r--r--spec/bundler/commands/outdated_spec.rb382
-rw-r--r--spec/bundler/commands/platform_spec.rb (renamed from spec/bundler/other/platform_spec.rb)237
-rw-r--r--spec/bundler/commands/post_bundle_message_spec.rb17
-rw-r--r--spec/bundler/commands/pristine_spec.rb24
-rw-r--r--spec/bundler/commands/remove_spec.rb113
-rw-r--r--spec/bundler/commands/show_spec.rb26
-rw-r--r--spec/bundler/commands/update_spec.rb918
-rw-r--r--spec/bundler/commands/version_spec.rb16
-rw-r--r--spec/bundler/commands/viz_spec.rb20
-rw-r--r--spec/bundler/install/allow_offline_install_spec.rb23
-rw-r--r--spec/bundler/install/binstubs_spec.rb4
-rw-r--r--spec/bundler/install/bundler_spec.rb101
-rw-r--r--spec/bundler/install/deploy_spec.rb270
-rw-r--r--spec/bundler/install/failure_spec.rb4
-rw-r--r--spec/bundler/install/gemfile/eval_gemfile_spec.rb8
-rw-r--r--spec/bundler/install/gemfile/force_ruby_platform_spec.rb146
-rw-r--r--spec/bundler/install/gemfile/gemspec_spec.rb373
-rw-r--r--spec/bundler/install/gemfile/git_spec.rb340
-rw-r--r--spec/bundler/install/gemfile/groups_spec.rb55
-rw-r--r--spec/bundler/install/gemfile/install_if_spec.rb11
-rw-r--r--spec/bundler/install/gemfile/lockfile_spec.rb5
-rw-r--r--spec/bundler/install/gemfile/path_spec.rb369
-rw-r--r--spec/bundler/install/gemfile/platform_spec.rb227
-rw-r--r--spec/bundler/install/gemfile/ruby_spec.rb76
-rw-r--r--spec/bundler/install/gemfile/sources_spec.rb758
-rw-r--r--spec/bundler/install/gemfile/specific_platform_spec.rb1256
-rw-r--r--spec/bundler/install/gemfile_spec.rb12
-rw-r--r--spec/bundler/install/gems/compact_index_spec.rb415
-rw-r--r--spec/bundler/install/gems/dependency_api_spec.rb181
-rw-r--r--spec/bundler/install/gems/flex_spec.rb141
-rw-r--r--spec/bundler/install/gems/fund_spec.rb43
-rw-r--r--spec/bundler/install/gems/native_extensions_spec.rb6
-rw-r--r--spec/bundler/install/gems/resolving_spec.rb429
-rw-r--r--spec/bundler/install/gems/standalone_spec.rb210
-rw-r--r--spec/bundler/install/gems/sudo_spec.rb205
-rw-r--r--spec/bundler/install/gemspecs_spec.rb33
-rw-r--r--spec/bundler/install/git_spec.rb147
-rw-r--r--spec/bundler/install/global_cache_spec.rb60
-rw-r--r--spec/bundler/install/path_spec.rb38
-rw-r--r--spec/bundler/install/process_lock_spec.rb22
-rw-r--r--spec/bundler/install/redownload_spec.rb2
-rw-r--r--spec/bundler/install/security_policy_spec.rb12
-rw-r--r--spec/bundler/install/yanked_spec.rb174
-rw-r--r--spec/bundler/lock/git_spec.rb127
-rw-r--r--spec/bundler/lock/lockfile_spec.rb724
-rw-r--r--spec/bundler/other/cli_dispatch_spec.rb6
-rw-r--r--spec/bundler/other/ext_spec.rb28
-rw-r--r--spec/bundler/other/major_deprecation_spec.rb294
-rw-r--r--spec/bundler/plugins/command_spec.rb6
-rw-r--r--spec/bundler/plugins/hook_spec.rb99
-rw-r--r--spec/bundler/plugins/install_spec.rb122
-rw-r--r--spec/bundler/plugins/source/example_spec.rb32
-rw-r--r--spec/bundler/plugins/uninstall_spec.rb25
-rw-r--r--spec/bundler/quality_es_spec.rb4
-rw-r--r--spec/bundler/quality_spec.rb70
-rw-r--r--spec/bundler/realworld/dependency_api_spec.rb16
-rw-r--r--spec/bundler/realworld/double_check_spec.rb6
-rw-r--r--spec/bundler/realworld/edgecases_spec.rb495
-rw-r--r--spec/bundler/realworld/ffi_spec.rb57
-rw-r--r--spec/bundler/realworld/fixtures/warbler/Gemfile2
-rw-r--r--spec/bundler/realworld/fixtures/warbler/Gemfile.lock2
-rw-r--r--spec/bundler/realworld/gemfile_source_header_spec.rb18
-rw-r--r--spec/bundler/realworld/git_spec.rb11
-rw-r--r--spec/bundler/realworld/mirror_probe_spec.rb57
-rw-r--r--spec/bundler/realworld/parallel_spec.rb10
-rw-r--r--spec/bundler/realworld/slow_perf_spec.rb132
-rw-r--r--spec/bundler/resolver/basic_spec.rb108
-rw-r--r--spec/bundler/resolver/platform_spec.rb161
-rw-r--r--spec/bundler/runtime/executable_spec.rb22
-rw-r--r--spec/bundler/runtime/gem_tasks_spec.rb16
-rw-r--r--spec/bundler/runtime/inline_spec.rb299
-rw-r--r--spec/bundler/runtime/load_spec.rb2
-rw-r--r--spec/bundler/runtime/platform_spec.rb197
-rw-r--r--spec/bundler/runtime/require_spec.rb14
-rw-r--r--spec/bundler/runtime/requiring_spec.rb15
-rw-r--r--spec/bundler/runtime/self_management_spec.rb159
-rw-r--r--spec/bundler/runtime/setup_spec.rb446
-rw-r--r--spec/bundler/runtime/with_unbundled_env_spec.rb22
-rw-r--r--spec/bundler/spec_helper.rb46
-rw-r--r--spec/bundler/support/activate.rb9
-rw-r--r--spec/bundler/support/api_request_limit_hax.rb16
-rw-r--r--spec/bundler/support/artifice/compact_index.rb118
-rw-r--r--spec/bundler/support/artifice/compact_index_api_missing.rb13
-rw-r--r--spec/bundler/support/artifice/compact_index_basic_authentication.rb6
-rw-r--r--spec/bundler/support/artifice/compact_index_checksum_mismatch.rb10
-rw-r--r--spec/bundler/support/artifice/compact_index_concurrent_download.rb13
-rw-r--r--spec/bundler/support/artifice/compact_index_creds_diff_host.rb6
-rw-r--r--spec/bundler/support/artifice/compact_index_etag_match.rb16
-rw-r--r--spec/bundler/support/artifice/compact_index_extra.rb35
-rw-r--r--spec/bundler/support/artifice/compact_index_extra_api.rb50
-rw-r--r--spec/bundler/support/artifice/compact_index_extra_api_missing.rb6
-rw-r--r--spec/bundler/support/artifice/compact_index_extra_missing.rb6
-rw-r--r--spec/bundler/support/artifice/compact_index_forbidden.rb6
-rw-r--r--spec/bundler/support/artifice/compact_index_host_redirect.rb8
-rw-r--r--spec/bundler/support/artifice/compact_index_no_gem.rb6
-rw-r--r--spec/bundler/support/artifice/compact_index_partial_update.rb8
-rw-r--r--spec/bundler/support/artifice/compact_index_partial_update_bad_digest.rb40
-rw-r--r--spec/bundler/support/artifice/compact_index_partial_update_no_digest_not_incremental.rb (renamed from spec/bundler/support/artifice/compact_index_partial_update_no_etag_not_incremental.rb)20
-rw-r--r--spec/bundler/support/artifice/compact_index_precompiled_before.rb25
-rw-r--r--spec/bundler/support/artifice/compact_index_range_ignored.rb40
-rw-r--r--spec/bundler/support/artifice/compact_index_range_not_satisfiable.rb6
-rw-r--r--spec/bundler/support/artifice/compact_index_rate_limited.rb6
-rw-r--r--spec/bundler/support/artifice/compact_index_redirects.rb6
-rw-r--r--spec/bundler/support/artifice/compact_index_strict_basic_authentication.rb8
-rw-r--r--spec/bundler/support/artifice/compact_index_wrong_dependencies.rb6
-rw-r--r--spec/bundler/support/artifice/compact_index_wrong_gem_checksum.rb9
-rw-r--r--spec/bundler/support/artifice/endpoint.rb113
-rw-r--r--spec/bundler/support/artifice/endpoint_500.rb7
-rw-r--r--spec/bundler/support/artifice/endpoint_api_forbidden.rb6
-rw-r--r--spec/bundler/support/artifice/endpoint_api_missing.rb18
-rw-r--r--spec/bundler/support/artifice/endpoint_basic_authentication.rb6
-rw-r--r--spec/bundler/support/artifice/endpoint_creds_diff_host.rb6
-rw-r--r--spec/bundler/support/artifice/endpoint_extra.rb6
-rw-r--r--spec/bundler/support/artifice/endpoint_extra_api.rb6
-rw-r--r--spec/bundler/support/artifice/endpoint_extra_missing.rb6
-rw-r--r--spec/bundler/support/artifice/endpoint_fallback.rb6
-rw-r--r--spec/bundler/support/artifice/endpoint_host_redirect.rb8
-rw-r--r--spec/bundler/support/artifice/endpoint_marshal_fail.rb11
-rw-r--r--spec/bundler/support/artifice/endpoint_marshal_fail_basic_authentication.rb6
-rw-r--r--spec/bundler/support/artifice/endpoint_mirror_source.rb6
-rw-r--r--spec/bundler/support/artifice/endpoint_redirect.rb6
-rw-r--r--spec/bundler/support/artifice/endpoint_strict_basic_authentication.rb8
-rw-r--r--spec/bundler/support/artifice/endpoint_timeout.rb6
-rw-r--r--spec/bundler/support/artifice/fail.rb25
-rw-r--r--spec/bundler/support/artifice/helpers/artifice.rb30
-rw-r--r--spec/bundler/support/artifice/helpers/compact_index.rb121
-rw-r--r--spec/bundler/support/artifice/helpers/compact_index_extra.rb33
-rw-r--r--spec/bundler/support/artifice/helpers/compact_index_extra_api.rb48
-rw-r--r--spec/bundler/support/artifice/helpers/endpoint.rb112
-rw-r--r--spec/bundler/support/artifice/helpers/endpoint_extra.rb29
-rw-r--r--spec/bundler/support/artifice/helpers/endpoint_fallback.rb15
-rw-r--r--spec/bundler/support/artifice/helpers/endpoint_marshal_fail.rb9
-rw-r--r--spec/bundler/support/artifice/helpers/rack_request.rb100
-rw-r--r--spec/bundler/support/artifice/vcr.rb47
-rw-r--r--spec/bundler/support/artifice/windows.rb7
-rw-r--r--spec/bundler/support/build_metadata.rb14
-rw-r--r--spec/bundler/support/builders.rb163
-rw-r--r--spec/bundler/support/bundle.rb7
-rw-r--r--spec/bundler/support/checksums.rb114
-rw-r--r--spec/bundler/support/command_execution.rb15
-rw-r--r--spec/bundler/support/filters.rb29
-rw-r--r--spec/bundler/support/hax.rb46
-rw-r--r--spec/bundler/support/helpers.rb191
-rw-r--r--spec/bundler/support/indexes.rb51
-rw-r--r--spec/bundler/support/matchers.rb16
-rw-r--r--spec/bundler/support/path.rb66
-rw-r--r--spec/bundler/support/platforms.rb45
-rw-r--r--spec/bundler/support/rubygems_ext.rb44
-rw-r--r--spec/bundler/support/rubygems_version_manager.rb23
-rw-r--r--spec/bundler/support/sudo.rb18
-rw-r--r--spec/bundler/update/gemfile_spec.rb10
-rw-r--r--spec/bundler/update/gems/fund_spec.rb18
-rw-r--r--spec/bundler/update/gems/post_install_spec.rb4
-rw-r--r--spec/bundler/update/git_spec.rb121
-rw-r--r--spec/bundler/update/path_spec.rb4
-rw-r--r--spec/bundler/update/redownload_spec.rb14
231 files changed, 14973 insertions, 5681 deletions
diff --git a/spec/bundler/bundler/bundler_spec.rb b/spec/bundler/bundler/bundler_spec.rb
index d164b5d3c6..6a2e435e54 100644
--- a/spec/bundler/bundler/bundler_spec.rb
+++ b/spec/bundler/bundler/bundler_spec.rb
@@ -4,6 +4,71 @@ require "bundler"
require "tmpdir"
RSpec.describe Bundler do
+ describe "#load_marshal" do
+ it "is a private method and raises an error" do
+ data = Marshal.dump(Bundler)
+ expect { Bundler.load_marshal(data) }.to raise_error(NoMethodError, /private method [`']load_marshal' called/)
+ end
+
+ it "loads any data" do
+ data = Marshal.dump(Bundler)
+ expect(Bundler.send(:load_marshal, data)).to eq(Bundler)
+ end
+ end
+
+ describe "#safe_load_marshal" do
+ it "fails on unexpected class" do
+ data = Marshal.dump(Bundler)
+ expect { Bundler.safe_load_marshal(data) }.to raise_error(Bundler::MarshalError)
+ end
+
+ it "loads simple structure" do
+ simple_structure = { "name" => [:development] }
+ data = Marshal.dump(simple_structure)
+ expect(Bundler.safe_load_marshal(data)).to eq(simple_structure)
+ end
+
+ it "loads Gem::Specification" do
+ gem_spec = Gem::Specification.new do |s|
+ s.name = "bundler"
+ s.version = Gem::Version.new("2.4.7")
+ s.installed_by_version = Gem::Version.new("0")
+ s.authors = ["André Arko",
+ "Samuel Giddins",
+ "Colby Swandale",
+ "Hiroshi Shibata",
+ "David Rodríguez",
+ "Grey Baker",
+ "Stephanie Morillo",
+ "Chris Morris",
+ "James Wen",
+ "Tim Moore",
+ "André Medeiros",
+ "Jessica Lynn Suttles",
+ "Terence Lee",
+ "Carl Lerche",
+ "Yehuda Katz"]
+ s.date = Time.utc(2023, 2, 15)
+ s.description = "Bundler manages an application's dependencies through its entire life, across many machines, systematically and repeatably"
+ s.email = ["team@bundler.io"]
+ s.homepage = "https://bundler.io"
+ s.metadata = { "bug_tracker_uri" => "https://github.com/rubygems/rubygems/issues?q=is%3Aopen+is%3Aissue+label%3ABundler",
+ "changelog_uri" => "https://github.com/rubygems/rubygems/blob/master/bundler/CHANGELOG.md",
+ "homepage_uri" => "https://bundler.io/",
+ "source_code_uri" => "https://github.com/rubygems/rubygems/tree/master/bundler" }
+ s.require_paths = ["lib"]
+ s.required_ruby_version = Gem::Requirement.new([">= 2.6.0"])
+ s.required_rubygems_version = Gem::Requirement.new([">= 3.0.1"])
+ s.rubygems_version = "3.4.7"
+ s.specification_version = 4
+ s.summary = "The best way to manage your application's dependencies"
+ s.license = false
+ end
+ data = Marshal.dump(gem_spec)
+ expect(Bundler.safe_load_marshal(data)).to eq(gem_spec)
+ end
+ end
+
describe "#load_gemspec_uncached" do
let(:app_gemspec_path) { tmp("test.gemspec") }
subject { Bundler.load_gemspec_uncached(app_gemspec_path) }
@@ -11,7 +76,7 @@ RSpec.describe Bundler do
context "with incorrect YAML file" do
before do
File.open(app_gemspec_path, "wb") do |f|
- f.write strip_whitespace(<<-GEMSPEC)
+ f.write <<~GEMSPEC
---
{:!00 ao=gu\g1= 7~f
GEMSPEC
@@ -21,33 +86,9 @@ RSpec.describe Bundler do
it "catches YAML syntax errors" do
expect { subject }.to raise_error(Bundler::GemspecError, /error while loading `test.gemspec`/)
end
-
- context "on Rubies with a settable YAML engine", :if => defined?(YAML::ENGINE) do
- context "with Syck as YAML::Engine" do
- it "raises a GemspecError after YAML load throws ArgumentError" do
- orig_yamler = YAML::ENGINE.yamler
- YAML::ENGINE.yamler = "syck"
-
- expect { subject }.to raise_error(Bundler::GemspecError)
-
- YAML::ENGINE.yamler = orig_yamler
- end
- end
-
- context "with Psych as YAML::Engine" do
- it "raises a GemspecError after YAML load throws Psych::SyntaxError" do
- orig_yamler = YAML::ENGINE.yamler
- YAML::ENGINE.yamler = "psych"
-
- expect { subject }.to raise_error(Bundler::GemspecError)
-
- YAML::ENGINE.yamler = orig_yamler
- end
- end
- end
end
- context "with correct YAML file", :if => defined?(Encoding) do
+ context "with correct YAML file", if: defined?(Encoding) do
it "can load a gemspec with unicode characters with default ruby encoding" do
# spec_helper forces the external encoding to UTF-8 but that's not the
# default until Ruby 2.0
@@ -58,7 +99,7 @@ RSpec.describe Bundler do
$VERBOSE = verbose
File.open(app_gemspec_path, "wb") do |file|
- file.puts <<-GEMSPEC.gsub(/^\s+/, "")
+ file.puts <<~GEMSPEC
# -*- encoding: utf-8 -*-
Gem::Specification.new do |gem|
gem.author = "André the Giant"
@@ -98,7 +139,7 @@ RSpec.describe Bundler do
end
GEMSPEC
end
- expect(Bundler.rubygems).to receive(:validate).with have_attributes(:name => "validated")
+ expect(Bundler.rubygems).to receive(:validate).with have_attributes(name: "validated")
subject
end
end
@@ -106,7 +147,7 @@ RSpec.describe Bundler do
context "with gemspec containing local variables" do
before do
File.open(app_gemspec_path, "wb") do |f|
- f.write strip_whitespace(<<-GEMSPEC)
+ f.write <<~GEMSPEC
must_not_leak = true
Gem::Specification.new do |gem|
gem.name = "leak check"
@@ -176,29 +217,9 @@ RSpec.describe Bundler do
describe "configuration" do
context "disable_shared_gems" do
it "should unset GEM_PATH with empty string" do
- env = {}
expect(Bundler).to receive(:use_system_gems?).and_return(false)
- Bundler.send(:configure_gem_path, env)
- expect(env.keys).to include("GEM_PATH")
- expect(env["GEM_PATH"]).to eq ""
- end
- end
- end
-
- describe "#rm_rf" do
- context "the directory is world writable" do
- let(:bundler_ui) { Bundler.ui }
- it "should raise a friendly error" do
- allow(File).to receive(:exist?).and_return(true)
- allow(::Bundler::FileUtils).to receive(:remove_entry_secure).and_raise(ArgumentError)
- allow(File).to receive(:world_writable?).and_return(true)
- message = <<EOF
-It is a security vulnerability to allow your home directory to be world-writable, and bundler can not continue.
-You should probably consider fixing this issue by running `chmod o-w ~` on *nix.
-Please refer to https://ruby-doc.org/stdlib-2.1.2/libdoc/fileutils/rdoc/FileUtils.html#method-c-remove_entry_secure for details.
-EOF
- expect(bundler_ui).to receive(:warn).with(message)
- expect { Bundler.send(:rm_rf, bundled_app) }.to raise_error(Bundler::PathError)
+ Bundler.send(:configure_gem_path)
+ expect(ENV["GEM_PATH"]).to eq ""
end
end
end
@@ -215,22 +236,6 @@ EOF
Bundler.mkdir_p(bundled_app.join("foo", "bar"))
expect(bundled_app.join("foo", "bar")).to exist
end
-
- context "when mkdir_p requires sudo" do
- it "creates a new folder using sudo" do
- expect(Bundler).to receive(:requires_sudo?).and_return(true)
- expect(Bundler).to receive(:sudo).and_return true
- Bundler.mkdir_p(bundled_app.join("foo"))
- end
- end
-
- context "with :no_sudo option" do
- it "forces mkdir_p to not use sudo" do
- expect(Bundler).to receive(:requires_sudo?).and_return(true)
- expect(Bundler).to_not receive(:sudo)
- Bundler.mkdir_p(bundled_app.join("foo"), :no_sudo => true)
- end
- end
end
describe "#user_home" do
@@ -294,118 +299,6 @@ EOF
end
end
- describe "#requires_sudo?" do
- let!(:tmpdir) { Dir.mktmpdir }
- let(:bundle_path) { Pathname("#{tmpdir}/bundle") }
-
- def clear_cached_requires_sudo
- return unless Bundler.instance_variable_defined?(:@requires_sudo_ran)
- Bundler.remove_instance_variable(:@requires_sudo_ran)
- Bundler.remove_instance_variable(:@requires_sudo)
- end
-
- before do
- clear_cached_requires_sudo
- allow(Bundler).to receive(:which).with("sudo").and_return("/usr/bin/sudo")
- allow(Bundler).to receive(:bundle_path).and_return(bundle_path)
- end
-
- after do
- FileUtils.rm_rf(tmpdir)
- clear_cached_requires_sudo
- end
-
- subject { Bundler.requires_sudo? }
-
- context "bundle_path doesn't exist" do
- it { should be false }
-
- context "and parent dir can't be written" do
- before do
- FileUtils.chmod(0o500, tmpdir)
- end
-
- it { should be true }
- end
-
- context "with unwritable files in a parent dir" do
- # Regression test for https://github.com/rubygems/bundler/pull/6316
- # It doesn't matter if there are other unwritable files so long as
- # bundle_path can be created
- before do
- file = File.join(tmpdir, "unrelated_file")
- FileUtils.touch(file)
- FileUtils.chmod(0o400, file)
- end
-
- it { should be false }
- end
- end
-
- context "bundle_path exists" do
- before do
- FileUtils.mkdir_p(bundle_path)
- end
-
- it { should be false }
-
- context "and is unwritable" do
- before do
- FileUtils.chmod(0o500, bundle_path)
- end
-
- it { should be true }
- end
- end
-
- context "path writability" do
- before do
- FileUtils.mkdir_p("tmp/vendor/bundle")
- FileUtils.mkdir_p("tmp/vendor/bin_dir")
- end
- after do
- FileUtils.rm_rf("tmp/vendor/bundle")
- FileUtils.rm_rf("tmp/vendor/bin_dir")
- end
- context "writable paths" do
- it "should return false and display nothing" do
- allow(Bundler).to receive(:bundle_path).and_return(Pathname("tmp/vendor/bundle"))
- expect(Bundler.ui).to_not receive(:warn)
- expect(Bundler.requires_sudo?).to eq(false)
- end
- end
- context "unwritable paths" do
- before do
- FileUtils.touch("tmp/vendor/bundle/unwritable1.txt")
- FileUtils.touch("tmp/vendor/bundle/unwritable2.txt")
- FileUtils.touch("tmp/vendor/bin_dir/unwritable3.txt")
- FileUtils.chmod(0o400, "tmp/vendor/bundle/unwritable1.txt")
- FileUtils.chmod(0o400, "tmp/vendor/bundle/unwritable2.txt")
- FileUtils.chmod(0o400, "tmp/vendor/bin_dir/unwritable3.txt")
- end
- it "should return true and display warn message" do
- allow(Bundler).to receive(:bundle_path).and_return(Pathname("tmp/vendor/bundle"))
- bin_dir = Pathname("tmp/vendor/bin_dir/")
-
- # allow File#writable? to be called with args other than the stubbed on below
- allow(File).to receive(:writable?).and_call_original
-
- # fake make the directory unwritable
- allow(File).to receive(:writable?).with(bin_dir).and_return(false)
- allow(Bundler).to receive(:system_bindir).and_return(Pathname("tmp/vendor/bin_dir/"))
- message = <<-MESSAGE.chomp
-Following files may not be writable, so sudo is needed:
- tmp/vendor/bin_dir/
- tmp/vendor/bundle/unwritable1.txt
- tmp/vendor/bundle/unwritable2.txt
-MESSAGE
- expect(Bundler.ui).to receive(:warn).with(message)
- expect(Bundler.requires_sudo?).to eq(true)
- end
- end
- end
- end
-
context "user cache dir" do
let(:home_path) { Pathname.new(ENV["HOME"]) }
diff --git a/spec/bundler/bundler/ci_detector_spec.rb b/spec/bundler/bundler/ci_detector_spec.rb
new file mode 100644
index 0000000000..299d8005e8
--- /dev/null
+++ b/spec/bundler/bundler/ci_detector_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+RSpec.describe Bundler::CIDetector do
+ # This is properly tested in rubygems, under the name Gem::CIDetector
+ # But the test that confirms that our version _stays in sync_ with that version
+ # will live here.
+
+ it "stays in sync with the rubygems implementation" do
+ rubygems_implementation_path = File.join(git_root, "lib", "rubygems", "ci_detector.rb")
+ expect(File.exist?(rubygems_implementation_path)).to be_truthy
+ rubygems_code = File.read(rubygems_implementation_path)
+ denamespaced_rubygems_code = rubygems_code.sub("Gem", "NAMESPACE")
+
+ bundler_implementation_path = File.join(source_lib_dir, "bundler", "ci_detector.rb")
+ expect(File.exist?(bundler_implementation_path)).to be_truthy
+ bundler_code = File.read(bundler_implementation_path)
+ denamespaced_bundler_code = bundler_code.sub("Bundler", "NAMESPACE")
+
+ expect(denamespaced_bundler_code).to eq(denamespaced_rubygems_code)
+ end
+end
diff --git a/spec/bundler/bundler/cli_spec.rb b/spec/bundler/bundler/cli_spec.rb
index c9dd101f55..c71fc8e9e7 100644
--- a/spec/bundler/bundler/cli_spec.rb
+++ b/spec/bundler/bundler/cli_spec.rb
@@ -4,12 +4,12 @@ require "bundler/cli"
RSpec.describe "bundle executable" do
it "returns non-zero exit status when passed unrecognized options" do
- bundle "--invalid_argument", :raise_on_error => false
+ bundle "--invalid_argument", raise_on_error: false
expect(exitstatus).to_not be_zero
end
it "returns non-zero exit status when passed unrecognized task" do
- bundle "unrecognized-task", :raise_on_error => false
+ bundle "unrecognized-task", raise_on_error: false
expect(exitstatus).to_not be_zero
end
@@ -87,7 +87,7 @@ RSpec.describe "bundle executable" do
end
context "with no arguments" do
- it "prints a concise help message", :bundler => "3" do
+ it "prints a concise help message", bundler: "3" do
bundle ""
expect(err).to be_empty
expect(out).to include("Bundler version #{Bundler::VERSION}").
@@ -105,50 +105,80 @@ RSpec.describe "bundle executable" do
gem 'rack'
G
- bundle :install, :env => { "BUNDLE_GEMFILE" => "" }
+ bundle :install, env: { "BUNDLE_GEMFILE" => "" }
expect(the_bundle).to include_gems "rack 1.0.0"
end
end
- context "when ENV['RUBYGEMS_GEMDEPS'] is set" do
- it "displays a warning" do
- gemfile bundled_app_gemfile, <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem 'rack'
- G
-
- bundle :install, :env => { "RUBYGEMS_GEMDEPS" => "foo" }
- expect(err).to include("RUBYGEMS_GEMDEPS")
- expect(err).to include("conflict with Bundler")
-
- bundle :install, :env => { "RUBYGEMS_GEMDEPS" => "" }
- expect(err).not_to include("RUBYGEMS_GEMDEPS")
- end
- end
-
context "with --verbose" do
it "prints the running command" do
gemfile "source \"#{file_uri_for(gem_repo1)}\""
- bundle "info bundler", :verbose => true
+ bundle "info bundler", verbose: true
expect(out).to start_with("Running `bundle info bundler --verbose` with bundler #{Bundler::VERSION}")
end
it "doesn't print defaults" do
- install_gemfile "source \"#{file_uri_for(gem_repo1)}\"", :verbose => true
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"", verbose: true
expect(out).to start_with("Running `bundle install --verbose` with bundler #{Bundler::VERSION}")
end
it "doesn't print defaults" do
- install_gemfile "source \"#{file_uri_for(gem_repo1)}\"", :verbose => true
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"", verbose: true
expect(out).to start_with("Running `bundle install --verbose` with bundler #{Bundler::VERSION}")
end
end
+ describe "bundle outdated" do
+ let(:run_command) do
+ bundle "install"
+
+ bundle "outdated #{flags}", raise_on_error: false
+ end
+
+ before do
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", '0.9.1'
+ G
+ end
+
+ context "with --groups flag" do
+ let(:flags) { "--groups" }
+
+ it "prints a message when there are outdated gems" do
+ run_command
+
+ expect(out).to include("Gem Current Latest Requested Groups")
+ expect(out).to include("rack 0.9.1 1.0.0 = 0.9.1 default")
+ end
+ end
+
+ context "with --parseable" do
+ let(:flags) { "--parseable" }
+
+ it "prints a message when there are outdated gems" do
+ run_command
+
+ expect(out).to include("rack (newest 1.0.0, installed 0.9.1, requested = 0.9.1)")
+ end
+ end
+
+ context "with --groups and --parseable" do
+ let(:flags) { "--groups --parseable" }
+
+ it "prints a simplified message when there are outdated gems" do
+ run_command
+
+ expect(out).to include("rack (newest 1.0.0, installed 0.9.1, requested = 0.9.1)")
+ end
+ end
+ end
+
describe "printing the outdated warning" do
shared_examples_for "no warning" do
it "prints no warning" do
- bundle "fail", :env => { "BUNDLER_VERSION" => bundler_version }, :raise_on_error => false
+ bundle "fail", env: { "BUNDLER_VERSION" => bundler_version }, raise_on_error: false
expect(last_command.stdboth).to eq("Could not find command \"fail\".")
end
end
@@ -183,24 +213,24 @@ RSpec.describe "bundle executable" do
context "when the latest version is greater than the current version" do
let(:latest_version) { "222.0" }
it "prints the version warning" do
- bundle "fail", :env => { "BUNDLER_VERSION" => bundler_version }, :raise_on_error => false
+ bundle "fail", env: { "BUNDLER_VERSION" => bundler_version }, raise_on_error: false
expect(err).to start_with(<<-EOS.strip)
The latest bundler is #{latest_version}, but you are currently running #{bundler_version}.
-To install the latest version, run `gem install bundler`
+To update to the most recent version, run `bundle update --bundler`
EOS
end
context "and disable_version_check is set" do
- before { bundle "config set disable_version_check true", :env => { "BUNDLER_VERSION" => bundler_version } }
+ before { bundle "config set disable_version_check true", env: { "BUNDLER_VERSION" => bundler_version } }
include_examples "no warning"
end
context "running a parseable command" do
it "prints no warning" do
- bundle "config get --parseable foo", :env => { "BUNDLER_VERSION" => bundler_version }
+ bundle "config get --parseable foo", env: { "BUNDLER_VERSION" => bundler_version }
expect(last_command.stdboth).to eq ""
- bundle "platform --ruby", :env => { "BUNDLER_VERSION" => bundler_version }, :raise_on_error => false
+ bundle "platform --ruby", env: { "BUNDLER_VERSION" => bundler_version }, raise_on_error: false
expect(last_command.stdboth).to eq "Could not locate Gemfile"
end
end
@@ -208,10 +238,10 @@ To install the latest version, run `gem install bundler`
context "and is a pre-release" do
let(:latest_version) { "222.0.0.pre.4" }
it "prints the version warning" do
- bundle "fail", :env => { "BUNDLER_VERSION" => bundler_version }, :raise_on_error => false
+ bundle "fail", env: { "BUNDLER_VERSION" => bundler_version }, raise_on_error: false
expect(err).to start_with(<<-EOS.strip)
The latest bundler is #{latest_version}, but you are currently running #{bundler_version}.
-To install the latest version, run `gem install bundler --pre`
+To update to the most recent version, run `bundle update --bundler`
EOS
end
end
@@ -220,12 +250,12 @@ To install the latest version, run `gem install bundler --pre`
end
RSpec.describe "bundler executable" do
- it "shows the bundler version just as the `bundle` executable does", :bundler => "< 3" do
+ it "shows the bundler version just as the `bundle` executable does", bundler: "< 3" do
bundler "--version"
expect(out).to eq("Bundler version #{Bundler::VERSION}")
end
- it "shows the bundler version just as the `bundle` executable does", :bundler => "3" do
+ it "shows the bundler version just as the `bundle` executable does", bundler: "3" do
bundler "--version"
expect(out).to eq(Bundler::VERSION)
end
diff --git a/spec/bundler/bundler/compact_index_client/updater_spec.rb b/spec/bundler/bundler/compact_index_client/updater_spec.rb
index 4acd7dbc63..6eed88ca9e 100644
--- a/spec/bundler/bundler/compact_index_client/updater_spec.rb
+++ b/spec/bundler/bundler/compact_index_client/updater_spec.rb
@@ -1,53 +1,224 @@
# frozen_string_literal: true
-require "net/http"
+require "bundler/vendored_net_http"
require "bundler/compact_index_client"
require "bundler/compact_index_client/updater"
require "tmpdir"
RSpec.describe Bundler::CompactIndexClient::Updater do
+ subject(:updater) { described_class.new(fetcher) }
+
let(:fetcher) { double(:fetcher) }
- let(:local_path) { Pathname.new Dir.mktmpdir("localpath") }
+ let(:local_path) { Pathname.new(Dir.mktmpdir("localpath")).join("versions") }
+ let(:etag_path) { Pathname.new(Dir.mktmpdir("localpath-etags")).join("versions.etag") }
let(:remote_path) { double(:remote_path) }
- let!(:updater) { described_class.new(fetcher) }
+ let(:full_body) { "abc123" }
+ let(:response) { double(:response, body: full_body, is_a?: false) }
+ let(:digest) { Digest::SHA256.base64digest(full_body) }
+
+ context "when the local path does not exist" do
+ before do
+ allow(response).to receive(:[]).with("Repr-Digest") { nil }
+ allow(response).to receive(:[]).with("Digest") { nil }
+ allow(response).to receive(:[]).with("ETag") { '"thisisanetag"' }
+ end
+
+ it "downloads the file without attempting append" do
+ expect(fetcher).to receive(:call).once.with(remote_path, {}) { response }
+
+ updater.update(remote_path, local_path, etag_path)
+
+ expect(local_path.read).to eq(full_body)
+ expect(etag_path.read).to eq("thisisanetag")
+ end
+
+ it "fails immediately on bad checksum" do
+ expect(fetcher).to receive(:call).once.with(remote_path, {}) { response }
+ allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:baddigest:" }
+
+ expect do
+ updater.update(remote_path, local_path, etag_path)
+ end.to raise_error(Bundler::CompactIndexClient::Updater::MismatchedChecksumError)
+ end
+ end
+
+ context "when the local path exists" do
+ let(:local_body) { "abc" }
+
+ before do
+ local_path.open("w") {|f| f.write(local_body) }
+ end
+
+ context "with an etag" do
+ before do
+ etag_path.open("w") {|f| f.write("LocalEtag") }
+ end
+
+ let(:headers) do
+ {
+ "If-None-Match" => '"LocalEtag"',
+ "Range" => "bytes=2-",
+ }
+ end
+
+ it "does nothing if etags match" do
+ expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
+ allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { false }
+ allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { true }
+
+ updater.update(remote_path, local_path, etag_path)
+
+ expect(local_path.read).to eq("abc")
+ expect(etag_path.read).to eq("LocalEtag")
+ end
+
+ it "appends the file if etags do not match" do
+ expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
+ allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" }
+ allow(response).to receive(:[]).with("ETag") { '"NewEtag"' }
+ allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { true }
+ allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { false }
+ allow(response).to receive(:body) { "c123" }
+
+ updater.update(remote_path, local_path, etag_path)
+
+ expect(local_path.read).to eq(full_body)
+ expect(etag_path.read).to eq("NewEtag")
+ end
+
+ it "replaces the file if response ignores range" do
+ expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
+ allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" }
+ allow(response).to receive(:[]).with("ETag") { '"NewEtag"' }
+ allow(response).to receive(:body) { full_body }
+
+ updater.update(remote_path, local_path, etag_path)
+
+ expect(local_path.read).to eq(full_body)
+ expect(etag_path.read).to eq("NewEtag")
+ end
+
+ it "tries the request again if the partial response fails digest check" do
+ allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:baddigest:" }
+ allow(response).to receive(:body) { "the beginning of the file changed" }
+ allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { true }
+ expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
+
+ full_response = double(:full_response, body: full_body, is_a?: false)
+ allow(full_response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" }
+ allow(full_response).to receive(:[]).with("ETag") { '"NewEtag"' }
+ expect(fetcher).to receive(:call).once.with(remote_path, { "If-None-Match" => '"LocalEtag"' }).and_return(full_response)
+
+ updater.update(remote_path, local_path, etag_path)
+
+ expect(local_path.read).to eq(full_body)
+ expect(etag_path.read).to eq("NewEtag")
+ end
+ end
+
+ context "without an etag file" do
+ let(:headers) do
+ {
+ "Range" => "bytes=2-",
+ # This MD5 feature should be deleted after sufficient time has passed since release.
+ # From then on, requests that still don't have a saved etag will be made without this header.
+ "If-None-Match" => %("#{Digest::MD5.hexdigest(local_body)}"),
+ }
+ end
+
+ it "saves only the etag_path if generated etag matches" do
+ expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
+ allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { false }
+ allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { true }
+
+ updater.update(remote_path, local_path, etag_path)
+
+ expect(local_path.read).to eq("abc")
+ expect(%("#{etag_path.read}")).to eq(headers["If-None-Match"])
+ end
+
+ it "appends the file" do
+ expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
+ allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" }
+ allow(response).to receive(:[]).with("ETag") { '"OpaqueEtag"' }
+ allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { true }
+ allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { false }
+ allow(response).to receive(:body) { "c123" }
+
+ updater.update(remote_path, local_path, etag_path)
+
+ expect(local_path.read).to eq(full_body)
+ expect(etag_path.read).to eq("OpaqueEtag")
+ end
+
+ it "replaces the file on full file response that ignores range request" do
+ expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
+ allow(response).to receive(:[]).with("Repr-Digest") { nil }
+ allow(response).to receive(:[]).with("Digest") { nil }
+ allow(response).to receive(:[]).with("ETag") { '"OpaqueEtag"' }
+ allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { false }
+ allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { false }
+ allow(response).to receive(:body) { full_body }
+
+ updater.update(remote_path, local_path, etag_path)
+
+ expect(local_path.read).to eq(full_body)
+ expect(etag_path.read).to eq("OpaqueEtag")
+ end
+
+ it "tries the request again if the partial response fails digest check" do
+ allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:baddigest:" }
+ allow(response).to receive(:body) { "the beginning of the file changed" }
+ allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { true }
+ expect(fetcher).to receive(:call).once.with(remote_path, headers) do
+ # During the failed first request, we simulate another process writing the etag.
+ # This ensures the second request doesn't generate the md5 etag again but just uses whatever is written.
+ etag_path.open("w") {|f| f.write("LocalEtag") }
+ response
+ end
+
+ full_response = double(:full_response, body: full_body, is_a?: false)
+ allow(full_response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" }
+ allow(full_response).to receive(:[]).with("ETag") { '"NewEtag"' }
+ expect(fetcher).to receive(:call).once.with(remote_path, { "If-None-Match" => '"LocalEtag"' }).and_return(full_response)
+
+ updater.update(remote_path, local_path, etag_path)
+
+ expect(local_path.read).to eq(full_body)
+ expect(etag_path.read).to eq("NewEtag")
+ end
+ end
+ end
context "when the ETag header is missing" do
# Regression test for https://github.com/rubygems/bundler/issues/5463
- let(:response) { double(:response, :body => "abc123") }
+ let(:response) { double(:response, body: full_body) }
it "treats the response as an update" do
- expect(response).to receive(:[]).with("ETag") { nil }
+ allow(response).to receive(:[]).with("Repr-Digest") { nil }
+ allow(response).to receive(:[]).with("Digest") { nil }
+ allow(response).to receive(:[]).with("ETag") { nil }
expect(fetcher).to receive(:call) { response }
- updater.update(local_path, remote_path)
+ updater.update(remote_path, local_path, etag_path)
end
end
context "when the download is corrupt" do
- let(:response) { double(:response, :body => "") }
+ let(:response) { double(:response, body: "") }
it "raises HTTPError" do
expect(fetcher).to receive(:call).and_raise(Zlib::GzipFile::Error)
expect do
- updater.update(local_path, remote_path)
+ updater.update(remote_path, local_path, etag_path)
end.to raise_error(Bundler::HTTPError)
end
end
- context "when bundler doesn't have permissions on Dir.tmpdir" do
- it "Errno::EACCES is raised" do
- allow(Bundler::Dir).to receive(:mktmpdir) { raise Errno::EACCES }
-
- expect do
- updater.update(local_path, remote_path)
- end.to raise_error(Bundler::PermissionError)
- end
- end
-
context "when receiving non UTF-8 data and default internal encoding set to ASCII" do
- let(:response) { double(:response, :body => "\x8B".b) }
+ let(:response) { double(:response, body: "\x8B".b) }
it "works just fine" do
old_verbose = $VERBOSE
@@ -56,10 +227,12 @@ RSpec.describe Bundler::CompactIndexClient::Updater do
begin
$VERBOSE = false
Encoding.default_internal = "ASCII"
- expect(response).to receive(:[]).with("ETag") { nil }
+ allow(response).to receive(:[]).with("Repr-Digest") { nil }
+ allow(response).to receive(:[]).with("Digest") { nil }
+ allow(response).to receive(:[]).with("ETag") { nil }
expect(fetcher).to receive(:call) { response }
- updater.update(local_path, remote_path)
+ updater.update(remote_path, local_path, etag_path)
ensure
Encoding.default_internal = previous_internal_encoding
$VERBOSE = old_verbose
diff --git a/spec/bundler/bundler/definition_spec.rb b/spec/bundler/bundler/definition_spec.rb
index bf000c468a..28c04e0860 100644
--- a/spec/bundler/bundler/definition_spec.rb
+++ b/spec/bundler/bundler/definition_spec.rb
@@ -5,61 +5,63 @@ require "bundler/definition"
RSpec.describe Bundler::Definition do
describe "#lock" do
before do
- allow(Bundler).to receive(:settings) { Bundler::Settings.new(".") }
- allow(Bundler::SharedHelpers).to receive(:find_gemfile) { Pathname.new("Gemfile") }
- allow(Bundler).to receive(:ui) { double("UI", :info => "", :debug => "") }
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile) { bundled_app_gemfile }
+ allow(Bundler).to receive(:ui) { double("UI", info: "", debug: "") }
end
- context "when it's not possible to write to the file" do
- subject { Bundler::Definition.new(nil, [], Bundler::SourceList.new, []) }
+ subject { Bundler::Definition.new(bundled_app_lock, [], Bundler::SourceList.new, {}) }
+
+ context "when it's not possible to write to the file" do
it "raises an PermissionError with explanation" do
allow(File).to receive(:open).and_call_original
- expect(File).to receive(:open).with("Gemfile.lock", "wb").
+ expect(File).to receive(:open).with(bundled_app_lock, "wb").
and_raise(Errno::EACCES)
- expect { subject.lock("Gemfile.lock") }.
+ expect { subject.lock }.
to raise_error(Bundler::PermissionError, /Gemfile\.lock/)
end
end
context "when a temporary resource access issue occurs" do
- subject { Bundler::Definition.new(nil, [], Bundler::SourceList.new, []) }
-
it "raises a TemporaryResourceError with explanation" do
allow(File).to receive(:open).and_call_original
- expect(File).to receive(:open).with("Gemfile.lock", "wb").
+ expect(File).to receive(:open).with(bundled_app_lock, "wb").
and_raise(Errno::EAGAIN)
- expect { subject.lock("Gemfile.lock") }.
+ expect { subject.lock }.
to raise_error(Bundler::TemporaryResourceError, /temporarily unavailable/)
end
end
context "when Bundler::Definition.no_lock is set to true" do
- subject { Bundler::Definition.new(nil, [], Bundler::SourceList.new, []) }
before { Bundler::Definition.no_lock = true }
after { Bundler::Definition.no_lock = false }
it "does not create a lock file" do
- subject.lock("Gemfile.lock")
- expect(File.file?("Gemfile.lock")).to eq false
+ subject.lock
+ expect(bundled_app_lock).not_to be_file
end
end
end
describe "detects changes" do
it "for a path gem with changes" do
- build_lib "foo", "1.0", :path => lib_path("foo")
+ build_lib "foo", "1.0", path: lib_path("foo")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
- build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ build_lib "foo", "1.0", path: lib_path("foo") do |s|
s.add_dependency "rack", "1.0"
end
- bundle :install, :env => { "DEBUG" => "1" }
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ c.checksum gem_repo1, "rack", "1.0.0"
+ end
+
+ bundle :install, env: { "DEBUG" => "1" }
expect(out).to match(/re-resolving dependencies/)
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
PATH
remote: #{lib_path("foo")}
specs:
@@ -76,27 +78,47 @@ RSpec.describe Bundler::Definition do
DEPENDENCIES
foo!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
+ it "with an explicit update" do
+ build_repo4 do
+ build_gem("ffi", "1.9.23") {|s| s.platform = "java" }
+ build_gem("ffi", "1.9.23")
+ end
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "ffi"
+ G
+
+ bundle "lock --add-platform java"
+
+ bundle "update ffi", env: { "DEBUG" => "1" }
+
+ expect(out).to match(/because bundler is unlocking gems: \(ffi\)/)
+ end
+
it "for a path gem with deps and no changes" do
- build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ build_lib "foo", "1.0", path: lib_path("foo") do |s|
s.add_dependency "rack", "1.0"
s.add_development_dependency "net-ssh", "1.0"
end
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ c.checksum gem_repo1, "rack", "1.0.0"
+ end
+
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
- bundle :check, :env => { "DEBUG" => "1" }
-
- expect(out).to match(/using resolution from the lockfile/)
- lockfile_should_be <<-G
+ expected_lockfile = <<~G
PATH
remote: #{lib_path("foo")}
specs:
@@ -113,50 +135,64 @@ RSpec.describe Bundler::Definition do
DEPENDENCIES
foo!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
+
+ expect(lockfile).to eq(expected_lockfile)
+
+ bundle :check, env: { "DEBUG" => "1" }
+
+ expect(out).to match(/using resolution from the lockfile/)
+ expect(lockfile).to eq(expected_lockfile)
end
it "for a locked gem for another platform" do
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "only_java", "1.1", "java"
+ end
+
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "only_java", platform: :jruby
G
bundle "lock --add-platform java"
- bundle :check, :env => { "DEBUG" => "1" }
+ bundle :check, env: { "DEBUG" => "1" }
expect(out).to match(/using resolution from the lockfile/)
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
only_java (1.1-java)
PLATFORMS
- java
- #{lockfile_platforms}
+ #{lockfile_platforms("java")}
DEPENDENCIES
only_java
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "for a rubygems gem" do
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo1, "foo", "1.0"
+ end
+
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "foo"
G
- bundle :check, :env => { "DEBUG" => "1" }
+ bundle :check, env: { "DEBUG" => "1" }
expect(out).to match(/using resolution from the lockfile/)
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
@@ -167,7 +203,7 @@ RSpec.describe Bundler::Definition do
DEPENDENCIES
foo
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -176,31 +212,6 @@ RSpec.describe Bundler::Definition do
describe "initialize" do
context "gem version promoter" do
- context "with lockfile" do
- before do
- install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "foo"
- G
-
- allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- end
-
- it "should get a locked specs list when updating all" do
- definition = Bundler::Definition.new(bundled_app_lock, [], Bundler::SourceList.new, true)
- locked_specs = definition.gem_version_promoter.locked_specs
- expect(locked_specs.to_a.map(&:name)).to eq ["foo"]
- expect(definition.instance_variable_get("@locked_specs").empty?).to eq true
- end
- end
-
- context "without gemfile or lockfile" do
- it "should not attempt to parse empty lockfile contents" do
- definition = Bundler::Definition.new(nil, [], mock_source_list, true)
- expect(definition.gem_version_promoter.locked_specs.to_a).to eq []
- end
- end
-
context "eager unlock" do
let(:source_list) do
Bundler::SourceList.new.tap do |source_list|
@@ -268,7 +279,7 @@ RSpec.describe Bundler::Definition do
bundled_app_lock,
updated_deps_in_gemfile,
source_list,
- :gems => ["shared_owner_a"], :conservative => true
+ gems: ["shared_owner_a"], conservative: true
)
locked = definition.send(:converge_locked_specs).map(&:name)
expect(locked).to eq %w[isolated_dep isolated_owner shared_dep shared_owner_b]
diff --git a/spec/bundler/bundler/dep_proxy_spec.rb b/spec/bundler/bundler/dep_proxy_spec.rb
deleted file mode 100644
index 8d02a33725..0000000000
--- a/spec/bundler/bundler/dep_proxy_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Bundler::DepProxy do
- let(:dep) { Bundler::Dependency.new("rake", ">= 0") }
- subject { described_class.get_proxy(dep, Gem::Platform::RUBY) }
- let(:same) { subject }
- let(:other) { described_class.get_proxy(dep, Gem::Platform::RUBY) }
- let(:different) { described_class.get_proxy(dep, Gem::Platform::JAVA) }
-
- describe "#eql?" do
- it { expect(subject.eql?(same)).to be true }
- it { expect(subject.eql?(other)).to be true }
- it { expect(subject.eql?(different)).to be false }
- it { expect(subject.eql?(nil)).to be false }
- it { expect(subject.eql?("foobar")).to be false }
- end
-
- describe "must use factory methods" do
- it { expect { described_class.new(dep, Gem::Platform::RUBY) }.to raise_error NoMethodError }
- it { expect { subject.dup }.to raise_error NoMethodError }
- it { expect { subject.clone }.to raise_error NoMethodError }
- end
-
- describe "frozen" do
- if Gem.ruby_version >= Gem::Version.new("2.5.0")
- error = Object.const_get("FrozenError")
- else
- error = RuntimeError
- end
- it { expect { subject.instance_variable_set(:@__platform, {}) }.to raise_error error }
- end
-end
diff --git a/spec/bundler/bundler/dependency_spec.rb b/spec/bundler/bundler/dependency_spec.rb
new file mode 100644
index 0000000000..a953372742
--- /dev/null
+++ b/spec/bundler/bundler/dependency_spec.rb
@@ -0,0 +1,167 @@
+# frozen_string_literal: true
+
+RSpec.describe Bundler::Dependency do
+ let(:options) do
+ {}
+ end
+ let(:dependency) do
+ described_class.new(
+ "test_gem",
+ "1.0.0",
+ options
+ )
+ end
+
+ describe "to_lock" do
+ it "returns formatted string" do
+ expect(dependency.to_lock).to eq(" test_gem (= 1.0.0)")
+ end
+
+ it "matches format of Gem::Dependency#to_lock" do
+ gem_dependency = Gem::Dependency.new("test_gem", "1.0.0")
+ expect(dependency.to_lock).to eq(gem_dependency.to_lock)
+ end
+
+ context "when source is passed" do
+ let(:options) do
+ {
+ "source" => Bundler::Source::Git.new({}),
+ }
+ end
+
+ it "returns formatted string with exclamation mark" do
+ expect(dependency.to_lock).to eq(" test_gem (= 1.0.0)!")
+ end
+ end
+ end
+
+ describe "PLATFORM_MAP" do
+ subject { described_class::PLATFORM_MAP }
+
+ # rubocop:disable Naming/VariableNumber
+ let(:platforms) do
+ { ruby: Gem::Platform::RUBY,
+ ruby_18: Gem::Platform::RUBY,
+ ruby_19: Gem::Platform::RUBY,
+ ruby_20: Gem::Platform::RUBY,
+ ruby_21: Gem::Platform::RUBY,
+ ruby_22: Gem::Platform::RUBY,
+ ruby_23: Gem::Platform::RUBY,
+ ruby_24: Gem::Platform::RUBY,
+ ruby_25: Gem::Platform::RUBY,
+ ruby_26: Gem::Platform::RUBY,
+ ruby_27: Gem::Platform::RUBY,
+ ruby_30: Gem::Platform::RUBY,
+ ruby_31: Gem::Platform::RUBY,
+ ruby_32: Gem::Platform::RUBY,
+ ruby_33: Gem::Platform::RUBY,
+ ruby_34: Gem::Platform::RUBY,
+ mri: Gem::Platform::RUBY,
+ mri_18: Gem::Platform::RUBY,
+ mri_19: Gem::Platform::RUBY,
+ mri_20: Gem::Platform::RUBY,
+ mri_21: Gem::Platform::RUBY,
+ mri_22: Gem::Platform::RUBY,
+ mri_23: Gem::Platform::RUBY,
+ mri_24: Gem::Platform::RUBY,
+ mri_25: Gem::Platform::RUBY,
+ mri_26: Gem::Platform::RUBY,
+ mri_27: Gem::Platform::RUBY,
+ mri_30: Gem::Platform::RUBY,
+ mri_31: Gem::Platform::RUBY,
+ mri_32: Gem::Platform::RUBY,
+ mri_33: Gem::Platform::RUBY,
+ mri_34: Gem::Platform::RUBY,
+ rbx: Gem::Platform::RUBY,
+ truffleruby: Gem::Platform::RUBY,
+ jruby: Gem::Platform::JAVA,
+ jruby_18: Gem::Platform::JAVA,
+ jruby_19: Gem::Platform::JAVA,
+ windows: Gem::Platform::WINDOWS,
+ windows_18: Gem::Platform::WINDOWS,
+ windows_19: Gem::Platform::WINDOWS,
+ windows_20: Gem::Platform::WINDOWS,
+ windows_21: Gem::Platform::WINDOWS,
+ windows_22: Gem::Platform::WINDOWS,
+ windows_23: Gem::Platform::WINDOWS,
+ windows_24: Gem::Platform::WINDOWS,
+ windows_25: Gem::Platform::WINDOWS,
+ windows_26: Gem::Platform::WINDOWS,
+ windows_27: Gem::Platform::WINDOWS,
+ windows_30: Gem::Platform::WINDOWS,
+ windows_31: Gem::Platform::WINDOWS,
+ windows_32: Gem::Platform::WINDOWS,
+ windows_33: Gem::Platform::WINDOWS,
+ windows_34: Gem::Platform::WINDOWS }
+ end
+
+ let(:deprecated) do
+ { mswin: Gem::Platform::MSWIN,
+ mswin_18: Gem::Platform::MSWIN,
+ mswin_19: Gem::Platform::MSWIN,
+ mswin_20: Gem::Platform::MSWIN,
+ mswin_21: Gem::Platform::MSWIN,
+ mswin_22: Gem::Platform::MSWIN,
+ mswin_23: Gem::Platform::MSWIN,
+ mswin_24: Gem::Platform::MSWIN,
+ mswin_25: Gem::Platform::MSWIN,
+ mswin_26: Gem::Platform::MSWIN,
+ mswin_27: Gem::Platform::MSWIN,
+ mswin_30: Gem::Platform::MSWIN,
+ mswin_31: Gem::Platform::MSWIN,
+ mswin_32: Gem::Platform::MSWIN,
+ mswin_33: Gem::Platform::MSWIN,
+ mswin_34: Gem::Platform::MSWIN,
+ mswin64: Gem::Platform::MSWIN64,
+ mswin64_19: Gem::Platform::MSWIN64,
+ mswin64_20: Gem::Platform::MSWIN64,
+ mswin64_21: Gem::Platform::MSWIN64,
+ mswin64_22: Gem::Platform::MSWIN64,
+ mswin64_23: Gem::Platform::MSWIN64,
+ mswin64_24: Gem::Platform::MSWIN64,
+ mswin64_25: Gem::Platform::MSWIN64,
+ mswin64_26: Gem::Platform::MSWIN64,
+ mswin64_27: Gem::Platform::MSWIN64,
+ mswin64_30: Gem::Platform::MSWIN64,
+ mswin64_31: Gem::Platform::MSWIN64,
+ mswin64_32: Gem::Platform::MSWIN64,
+ mswin64_33: Gem::Platform::MSWIN64,
+ mswin64_34: Gem::Platform::MSWIN64,
+ mingw: Gem::Platform::MINGW,
+ mingw_18: Gem::Platform::MINGW,
+ mingw_19: Gem::Platform::MINGW,
+ mingw_20: Gem::Platform::MINGW,
+ mingw_21: Gem::Platform::MINGW,
+ mingw_22: Gem::Platform::MINGW,
+ mingw_23: Gem::Platform::MINGW,
+ mingw_24: Gem::Platform::MINGW,
+ mingw_25: Gem::Platform::MINGW,
+ mingw_26: Gem::Platform::MINGW,
+ mingw_27: Gem::Platform::MINGW,
+ mingw_30: Gem::Platform::MINGW,
+ mingw_31: Gem::Platform::MINGW,
+ mingw_32: Gem::Platform::MINGW,
+ mingw_33: Gem::Platform::MINGW,
+ mingw_34: Gem::Platform::MINGW,
+ x64_mingw: Gem::Platform::X64_MINGW,
+ x64_mingw_20: Gem::Platform::X64_MINGW,
+ x64_mingw_21: Gem::Platform::X64_MINGW,
+ x64_mingw_22: Gem::Platform::X64_MINGW,
+ x64_mingw_23: Gem::Platform::X64_MINGW,
+ x64_mingw_24: Gem::Platform::X64_MINGW,
+ x64_mingw_25: Gem::Platform::X64_MINGW,
+ x64_mingw_26: Gem::Platform::X64_MINGW,
+ x64_mingw_27: Gem::Platform::X64_MINGW,
+ x64_mingw_30: Gem::Platform::X64_MINGW,
+ x64_mingw_31: Gem::Platform::X64_MINGW,
+ x64_mingw_32: Gem::Platform::X64_MINGW,
+ x64_mingw_33: Gem::Platform::X64_MINGW,
+ x64_mingw_34: Gem::Platform::X64_MINGW }
+ end
+ # rubocop:enable Naming/VariableNumber
+
+ it "includes all platforms" do
+ expect(subject).to eq(platforms.merge(deprecated))
+ end
+ end
+end
diff --git a/spec/bundler/bundler/digest_spec.rb b/spec/bundler/bundler/digest_spec.rb
new file mode 100644
index 0000000000..f876827964
--- /dev/null
+++ b/spec/bundler/bundler/digest_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require "openssl"
+require "bundler/digest"
+
+RSpec.describe Bundler::Digest do
+ context "SHA1" do
+ subject { Bundler::Digest }
+ let(:stdlib) { OpenSSL::Digest::SHA1 }
+
+ it "is compatible with stdlib" do
+ random_strings = ["foo", "skfjsdlkfjsdf", "3924m", "ldskfj"]
+
+ # https://www.rfc-editor.org/rfc/rfc3174#section-7.3
+ rfc3174_test_cases = ["abc", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "a", "01234567" * 8]
+
+ (random_strings + rfc3174_test_cases).each do |payload|
+ sha1 = subject.sha1(payload)
+ sha1_stdlib = stdlib.hexdigest(payload)
+ expect(sha1).to be == sha1_stdlib, "#{payload}'s sha1 digest (#{sha1}) did not match stlib's result (#{sha1_stdlib})"
+ end
+ end
+ end
+end
diff --git a/spec/bundler/bundler/dsl_spec.rb b/spec/bundler/bundler/dsl_spec.rb
index e6cd43ab59..3c3b6c26c3 100644
--- a/spec/bundler/bundler/dsl_spec.rb
+++ b/spec/bundler/bundler/dsl_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe Bundler::Dsl do
it "registers custom hosts" do
subject.git_source(:example) {|repo_name| "git@git.example.com:#{repo_name}.git" }
subject.git_source(:foobar) {|repo_name| "git@foobar.com:#{repo_name}.git" }
- subject.gem("dobry-pies", :example => "strzalek/dobry-pies")
+ subject.gem("dobry-pies", example: "strzalek/dobry-pies")
example_uri = "git@git.example.com:strzalek/dobry-pies.git"
expect(subject.dependencies.first.source.uri).to eq(example_uri)
end
@@ -25,47 +25,137 @@ RSpec.describe Bundler::Dsl do
expect { subject.git_source(:example) }.to raise_error(Bundler::InvalidOption)
end
- context "default hosts", :bundler => "< 3" do
+ it "converts :github PR to URI using https" do
+ subject.gem("sparks", github: "https://github.com/indirect/sparks/pull/5")
+ github_uri = "https://github.com/indirect/sparks.git"
+ expect(subject.dependencies.first.source.uri).to eq(github_uri)
+ expect(subject.dependencies.first.source.ref).to eq("refs/pull/5/head")
+ end
+
+ it "converts :gitlab PR to URI using https" do
+ subject.gem("sparks", gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5")
+ gitlab_uri = "https://gitlab.com/indirect/sparks.git"
+ expect(subject.dependencies.first.source.uri).to eq(gitlab_uri)
+ expect(subject.dependencies.first.source.ref).to eq("refs/merge-requests/5/head")
+ end
+
+ it "rejects :github PR URI with a branch, ref or tag" do
+ expect do
+ subject.gem("sparks", github: "https://github.com/indirect/sparks/pull/5", branch: "foo")
+ end.to raise_error(
+ Bundler::GemfileError,
+ %(The :branch option can't be used with `github: "https://github.com/indirect/sparks/pull/5"`),
+ )
+
+ expect do
+ subject.gem("sparks", github: "https://github.com/indirect/sparks/pull/5", ref: "foo")
+ end.to raise_error(
+ Bundler::GemfileError,
+ %(The :ref option can't be used with `github: "https://github.com/indirect/sparks/pull/5"`),
+ )
+
+ expect do
+ subject.gem("sparks", github: "https://github.com/indirect/sparks/pull/5", tag: "foo")
+ end.to raise_error(
+ Bundler::GemfileError,
+ %(The :tag option can't be used with `github: "https://github.com/indirect/sparks/pull/5"`),
+ )
+ end
+
+ it "rejects :gitlab PR URI with a branch, ref or tag" do
+ expect do
+ subject.gem("sparks", gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5", branch: "foo")
+ end.to raise_error(
+ Bundler::GemfileError,
+ %(The :branch option can't be used with `gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5"`),
+ )
+
+ expect do
+ subject.gem("sparks", gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5", ref: "foo")
+ end.to raise_error(
+ Bundler::GemfileError,
+ %(The :ref option can't be used with `gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5"`),
+ )
+
+ expect do
+ subject.gem("sparks", gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5", tag: "foo")
+ end.to raise_error(
+ Bundler::GemfileError,
+ %(The :tag option can't be used with `gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5"`),
+ )
+ end
+
+ it "rejects :github with :git" do
+ expect do
+ subject.gem("sparks", github: "indirect/sparks", git: "https://github.com/indirect/sparks.git")
+ end.to raise_error(
+ Bundler::GemfileError,
+ %(The :git option can't be used with `github: "indirect/sparks"`),
+ )
+ end
+
+ it "rejects :gitlab with :git" do
+ expect do
+ subject.gem("sparks", gitlab: "indirect/sparks", git: "https://gitlab.com/indirect/sparks.git")
+ end.to raise_error(
+ Bundler::GemfileError,
+ %(The :git option can't be used with `gitlab: "indirect/sparks"`),
+ )
+ end
+
+ context "default hosts", bundler: "< 3" do
it "converts :github to URI using https" do
- subject.gem("sparks", :github => "indirect/sparks")
+ subject.gem("sparks", github: "indirect/sparks")
github_uri = "https://github.com/indirect/sparks.git"
expect(subject.dependencies.first.source.uri).to eq(github_uri)
end
it "converts :github shortcut to URI using https" do
- subject.gem("sparks", :github => "rails")
+ subject.gem("sparks", github: "rails")
github_uri = "https://github.com/rails/rails.git"
expect(subject.dependencies.first.source.uri).to eq(github_uri)
end
+ it "converts :gitlab to URI using https" do
+ subject.gem("sparks", gitlab: "indirect/sparks")
+ gitlab_uri = "https://gitlab.com/indirect/sparks.git"
+ expect(subject.dependencies.first.source.uri).to eq(gitlab_uri)
+ end
+
+ it "converts :gitlab shortcut to URI using https" do
+ subject.gem("sparks", gitlab: "rails")
+ gitlab_uri = "https://gitlab.com/rails/rails.git"
+ expect(subject.dependencies.first.source.uri).to eq(gitlab_uri)
+ end
+
it "converts numeric :gist to :git" do
- subject.gem("not-really-a-gem", :gist => 2_859_988)
+ subject.gem("not-really-a-gem", gist: 2_859_988)
github_uri = "https://gist.github.com/2859988.git"
expect(subject.dependencies.first.source.uri).to eq(github_uri)
end
it "converts :gist to :git" do
- subject.gem("not-really-a-gem", :gist => "2859988")
+ subject.gem("not-really-a-gem", gist: "2859988")
github_uri = "https://gist.github.com/2859988.git"
expect(subject.dependencies.first.source.uri).to eq(github_uri)
end
it "converts :bitbucket to :git" do
- subject.gem("not-really-a-gem", :bitbucket => "mcorp/flatlab-rails")
+ subject.gem("not-really-a-gem", bitbucket: "mcorp/flatlab-rails")
bitbucket_uri = "https://mcorp@bitbucket.org/mcorp/flatlab-rails.git"
expect(subject.dependencies.first.source.uri).to eq(bitbucket_uri)
end
it "converts 'mcorp' to 'mcorp/mcorp'" do
- subject.gem("not-really-a-gem", :bitbucket => "mcorp")
+ subject.gem("not-really-a-gem", bitbucket: "mcorp")
bitbucket_uri = "https://mcorp@bitbucket.org/mcorp/mcorp.git"
expect(subject.dependencies.first.source.uri).to eq(bitbucket_uri)
end
end
context "default git sources" do
- it "has bitbucket, gist, and github" do
- expect(subject.instance_variable_get(:@git_sources).keys.sort).to eq(%w[bitbucket gist github])
+ it "has bitbucket, gist, github, and gitlab" do
+ expect(subject.instance_variable_get(:@git_sources).keys.sort).to eq(%w[bitbucket gist github gitlab])
end
end
end
@@ -95,18 +185,37 @@ RSpec.describe Bundler::Dsl do
expect { subject.eval_gemfile("Gemfile") }.
to raise_error(Bundler::GemfileError, /There was an error evaluating `Gemfile`: ruby_version must match the :engine_version for MRI/)
end
+
+ it "populates __dir__ and __FILE__ correctly" do
+ abs_path = source_root.join("../fragment.rb").to_s
+ expect(Bundler).to receive(:read_file).with(abs_path).and_return(<<~RUBY)
+ @fragment_dir = __dir__
+ @fragment_file = __FILE__
+ RUBY
+ subject.eval_gemfile("../fragment.rb")
+ expect(subject.instance_variable_get(:@fragment_dir)).to eq(source_root.dirname.to_s)
+ expect(subject.instance_variable_get(:@fragment_file)).to eq(abs_path)
+ end
end
describe "#gem" do
- [:ruby, :ruby_18, :ruby_19, :ruby_20, :ruby_21, :ruby_22, :ruby_23, :ruby_24, :ruby_25, :ruby_26, :mri, :mri_18, :mri_19,
- :mri_20, :mri_21, :mri_22, :mri_23, :mri_24, :mri_25, :mri_26, :jruby, :rbx, :truffleruby].each do |platform|
+ # rubocop:disable Naming/VariableNumber
+ [:ruby, :ruby_18, :ruby_19, :ruby_20, :ruby_21, :ruby_22, :ruby_23, :ruby_24, :ruby_25, :ruby_26, :ruby_27,
+ :ruby_30, :ruby_31, :ruby_32, :ruby_33, :mri, :mri_18, :mri_19, :mri_20, :mri_21, :mri_22, :mri_23, :mri_24,
+ :mri_25, :mri_26, :mri_27, :mri_30, :mri_31, :mri_32, :mri_33, :jruby, :rbx, :truffleruby].each do |platform|
it "allows #{platform} as a valid platform" do
- subject.gem("foo", :platform => platform)
+ subject.gem("foo", platform: platform)
end
end
+ # rubocop:enable Naming/VariableNumber
+
+ it "allows platforms matching the running Ruby version" do
+ platform = "ruby_#{RbConfig::CONFIG["MAJOR"]}#{RbConfig::CONFIG["MINOR"]}"
+ subject.gem("foo", platform: platform)
+ end
it "rejects invalid platforms" do
- expect { subject.gem("foo", :platform => :bogus) }.
+ expect { subject.gem("foo", platform: :bogus) }.
to raise_error(Bundler::GemfileError, /is not a valid platform/)
end
@@ -156,19 +265,19 @@ RSpec.describe Bundler::Dsl do
end
it "rejects branch option on non-git gems" do
- expect { subject.gem("foo", :branch => "test") }.
+ expect { subject.gem("foo", branch: "test") }.
to raise_error(Bundler::GemfileError, /The `branch` option for `gem 'foo'` is not allowed. Only gems with a git source can specify a branch/)
end
it "allows specifying a branch on git gems" do
- subject.gem("foo", :branch => "test", :git => "http://mytestrepo")
+ subject.gem("foo", branch: "test", git: "http://mytestrepo")
dep = subject.dependencies.last
expect(dep.name).to eq "foo"
end
it "allows specifying a branch on git gems with a git_source" do
subject.git_source(:test_source) {|n| "https://github.com/#{n}" }
- subject.gem("foo", :branch => "test", :test_source => "bundler/bundler")
+ subject.gem("foo", branch: "test", test_source: "bundler/bundler")
dep = subject.dependencies.last
expect(dep.name).to eq "foo"
end
@@ -233,7 +342,7 @@ RSpec.describe Bundler::Dsl do
allow(Bundler).to receive(:default_gemfile).and_return(Pathname.new("./Gemfile"))
subject.source("https://other-source.org") do
- subject.gem("dobry-pies", :path => "foo")
+ subject.gem("dobry-pies", path: "foo")
subject.gem("foo")
end
@@ -245,12 +354,12 @@ RSpec.describe Bundler::Dsl do
describe "#check_primary_source_safety" do
context "when a global source is not defined implicitly" do
it "will raise a major deprecation warning" do
- not_a_global_source = double("not-a-global-source", :no_remotes? => true)
+ not_a_global_source = double("not-a-global-source", no_remotes?: true)
allow(Bundler::Source::Rubygems).to receive(:new).and_return(not_a_global_source)
warning = "This Gemfile does not include an explicit global source. " \
"Not using an explicit global source may result in a different lockfile being generated depending on " \
- "the gems you have installed locally before bundler is run." \
+ "the gems you have installed locally before bundler is run. " \
"Instead, define a global source in your Gemfile like this: source \"https://rubygems.org\"."
expect(Bundler::SharedHelpers).to receive(:major_deprecation).with(2, warning)
diff --git a/spec/bundler/bundler/endpoint_specification_spec.rb b/spec/bundler/bundler/endpoint_specification_spec.rb
index a9371f6617..e7e10730cf 100644
--- a/spec/bundler/bundler/endpoint_specification_spec.rb
+++ b/spec/bundler/bundler/endpoint_specification_spec.rb
@@ -5,9 +5,10 @@ RSpec.describe Bundler::EndpointSpecification do
let(:version) { "1.0.0" }
let(:platform) { Gem::Platform::RUBY }
let(:dependencies) { [] }
+ let(:spec_fetcher) { double(:spec_fetcher) }
let(:metadata) { nil }
- subject(:spec) { described_class.new(name, version, platform, dependencies, metadata) }
+ subject(:spec) { described_class.new(name, version, platform, spec_fetcher, dependencies, metadata) }
describe "#build_dependency" do
let(:name) { "foo" }
@@ -32,22 +33,6 @@ RSpec.describe Bundler::EndpointSpecification do
)
end
end
-
- context "when there is an ill formed requirement" do
- before do
- allow(Gem::Dependency).to receive(:new).with(name, [requirement1, requirement2]) {
- raise ArgumentError.new("Ill-formed requirement [\"#<YAML::Syck::DefaultKey")
- }
- # Eliminate extra line break in rspec output due to `puts` in `#build_dependency`
- allow(subject).to receive(:puts) {}
- end
-
- it "should raise a Bundler::GemspecError with invalid gemspec message" do
- expect { subject.send(:build_dependency, name, [requirement1, requirement2]) }.to raise_error(
- Bundler::GemspecError, /Unfortunately, the gem foo \(1\.0\.0\) has an invalid gemspec/
- )
- end
- end
end
describe "#parse_metadata" do
@@ -63,8 +48,35 @@ RSpec.describe Bundler::EndpointSpecification do
end
end
+ describe "#required_ruby_version" do
+ context "required_ruby_version is already set on endpoint specification" do
+ existing_value = "already set value"
+ let(:required_ruby_version) { existing_value }
+
+ it "should return the current value when already set on endpoint specification" do
+ expect(spec.required_ruby_version). eql?(existing_value)
+ end
+ end
+
+ it "should return the remote spec value when not set on endpoint specification and remote spec has one" do
+ remote_value = "remote_value"
+ remote_spec = double(:remote_spec, required_ruby_version: remote_value, required_rubygems_version: nil)
+ allow(spec_fetcher).to receive(:fetch_spec).and_return(remote_spec)
+
+ expect(spec.required_ruby_version). eql?(remote_value)
+ end
+
+ it "should use the default Gem Requirement value when not set on endpoint specification and not set on remote spec" do
+ remote_spec = double(:remote_spec, required_ruby_version: nil, required_rubygems_version: nil)
+ allow(spec_fetcher).to receive(:fetch_spec).and_return(remote_spec)
+ expect(spec.required_ruby_version). eql?(Gem::Requirement.default)
+ end
+ end
+
it "supports equality comparison" do
- other_spec = described_class.new("bar", version, platform, dependencies, metadata)
+ remote_spec = double(:remote_spec, required_ruby_version: nil, required_rubygems_version: nil)
+ allow(spec_fetcher).to receive(:fetch_spec).and_return(remote_spec)
+ other_spec = described_class.new("bar", version, platform, spec_fetcher, dependencies, metadata)
expect(spec).to eql(spec)
expect(spec).to_not eql(other_spec)
end
diff --git a/spec/bundler/bundler/env_spec.rb b/spec/bundler/bundler/env_spec.rb
index 5d3aeec226..7997cb0c40 100644
--- a/spec/bundler/bundler/env_spec.rb
+++ b/spec/bundler/bundler/env_spec.rb
@@ -4,7 +4,7 @@ require "bundler/settings"
require "openssl"
RSpec.describe Bundler::Env do
- let(:git_proxy_stub) { Bundler::Source::Git::GitProxy.new(nil, nil, nil) }
+ let(:git_proxy_stub) { Bundler::Source::Git::GitProxy.new(nil, nil) }
describe "#report" do
it "prints the environment" do
@@ -34,8 +34,6 @@ RSpec.describe Bundler::Env do
end
it "prints user home" do
- skip "needs to use a valid HOME" if Gem.win_platform? && RUBY_VERSION < "2.6.0"
-
with_clear_paths("HOME", "/a/b/c") do
out = described_class.report
expect(out).to include("User Home /a/b/c")
@@ -43,8 +41,6 @@ RSpec.describe Bundler::Env do
end
it "prints user path" do
- skip "needs to use a valid HOME" if Gem.win_platform? && RUBY_VERSION < "2.6.0"
-
with_clear_paths("HOME", "/a/b/c") do
allow(File).to receive(:exist?)
allow(File).to receive(:exist?).with("/a/b/c/.gem").and_return(true)
@@ -92,7 +88,7 @@ RSpec.describe Bundler::Env do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
end
- let(:output) { described_class.report(:print_gemfile => true) }
+ let(:output) { described_class.report(print_gemfile: true) }
it "prints the Gemfile" do
expect(output).to include("Gemfile")
@@ -106,7 +102,7 @@ RSpec.describe Bundler::Env do
end
context "when there no Gemfile and print_gemfile is true" do
- let(:output) { described_class.report(:print_gemfile => true) }
+ let(:output) { described_class.report(print_gemfile: true) }
it "prints the environment" do
expect(output).to start_with("## Environment")
@@ -118,7 +114,7 @@ RSpec.describe Bundler::Env do
bundle "config set https://localgemserver.test/ user:pass"
end
- let(:output) { described_class.report(:print_gemfile => true) }
+ let(:output) { described_class.report(print_gemfile: true) }
it "prints the config with redacted values" do
expect(output).to include("https://localgemserver.test")
@@ -127,9 +123,23 @@ RSpec.describe Bundler::Env do
end
end
+ context "when there's bundler config with OAuth token credentials" do
+ before do
+ bundle "config set https://localgemserver.test/ api_token:x-oauth-basic"
+ 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("[REDACTED]:x-oauth-basic")
+ expect(output).to_not include("api_token:x-oauth-basic")
+ end
+ end
+
context "when Gemfile contains a gemspec and print_gemspecs is true" do
let(:gemspec) do
- strip_whitespace(<<-GEMSPEC)
+ <<~GEMSPEC
Gem::Specification.new do |gem|
gem.name = "foo"
gem.author = "Fumofu"
@@ -148,7 +158,7 @@ RSpec.describe Bundler::Env do
end
it "prints the gemspec" do
- output = described_class.report(:print_gemspecs => true)
+ output = described_class.report(print_gemspecs: true)
expect(output).to include("foo.gemspec")
expect(output).to include(gemspec)
@@ -167,8 +177,8 @@ RSpec.describe Bundler::Env do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
allow(Bundler::SharedHelpers).to receive(:pwd).and_return(bundled_app)
- output = described_class.report(:print_gemspecs => true)
- expect(output).to include(strip_whitespace(<<-ENV))
+ output = described_class.report(print_gemspecs: true)
+ expect(output).to include(<<~ENV)
## Gemfile
### Gemfile
@@ -207,7 +217,7 @@ RSpec.describe Bundler::Env do
context "when the git version is OS specific" do
it "includes OS specific information with the version number" do
- expect(git_proxy_stub).to receive(:git).with("--version").
+ expect(git_proxy_stub).to receive(:git_local).with("--version").
and_return("git version 1.2.3 (Apple Git-BS)")
expect(Bundler::Source::Git::GitProxy).to receive(:new).and_return(git_proxy_stub)
diff --git a/spec/bundler/bundler/environment_preserver_spec.rb b/spec/bundler/bundler/environment_preserver_spec.rb
index 530ca6f835..6c7066d0c6 100644
--- a/spec/bundler/bundler/environment_preserver_spec.rb
+++ b/spec/bundler/bundler/environment_preserver_spec.rb
@@ -27,8 +27,12 @@ RSpec.describe Bundler::EnvironmentPreserver do
context "when a key is empty" do
let(:env) { { "foo" => "" } }
- it "should not create backup entries" do
- expect(subject).not_to have_key "BUNDLER_ORIG_foo"
+ it "should keep the original entry" do
+ expect(subject["foo"]).to be_empty
+ end
+
+ it "should still create backup entries" do
+ expect(subject).to have_key "BUNDLER_ORIG_foo"
end
end
@@ -71,8 +75,12 @@ RSpec.describe Bundler::EnvironmentPreserver do
context "when the original key is empty" do
let(:env) { { "foo" => "my-foo", "BUNDLER_ORIG_foo" => "" } }
- it "should keep the current value" do
- expect(subject["foo"]).to eq("my-foo")
+ it "should restore the original value" do
+ expect(subject["foo"]).to be_empty
+ end
+
+ it "should delete the backup value" do
+ expect(subject.key?("BUNDLER_ORIG_foo")).to eq(false)
end
end
end
diff --git a/spec/bundler/bundler/fetcher/base_spec.rb b/spec/bundler/bundler/fetcher/base_spec.rb
index 02506591f3..b8c6b57b10 100644
--- a/spec/bundler/bundler/fetcher/base_spec.rb
+++ b/spec/bundler/bundler/fetcher/base_spec.rb
@@ -4,15 +4,16 @@ RSpec.describe Bundler::Fetcher::Base do
let(:downloader) { double(:downloader) }
let(:remote) { double(:remote) }
let(:display_uri) { "http://sample_uri.com" }
+ let(:gem_remote_fetcher) { nil }
class TestClass < described_class; end
- subject { TestClass.new(downloader, remote, display_uri) }
+ subject { TestClass.new(downloader, remote, display_uri, gem_remote_fetcher) }
describe "#initialize" do
context "with the abstract Base class" do
it "should raise an error" do
- expect { described_class.new(downloader, remote, display_uri) }.to raise_error(RuntimeError, "Abstract class")
+ expect { described_class.new(downloader, remote, display_uri, gem_remote_fetcher) }.to raise_error(RuntimeError, "Abstract class")
end
end
@@ -36,7 +37,7 @@ RSpec.describe Bundler::Fetcher::Base do
end
describe "#fetch_uri" do
- let(:remote_uri_obj) { Bundler::URI("http://rubygems.org") }
+ let(:remote_uri_obj) { Gem::URI("http://rubygems.org") }
before { allow(subject).to receive(:remote_uri).and_return(remote_uri_obj) }
@@ -49,10 +50,10 @@ RSpec.describe Bundler::Fetcher::Base do
end
context "when the remote uri's host is not rubygems.org" do
- let(:remote_uri_obj) { Bundler::URI("http://otherhost.org") }
+ let(:remote_uri_obj) { Gem::URI("http://otherhost.org") }
it "should return the remote uri" do
- expect(subject.fetch_uri).to eq(Bundler::URI("http://otherhost.org"))
+ expect(subject.fetch_uri).to eq(Gem::URI("http://otherhost.org"))
end
end
diff --git a/spec/bundler/bundler/fetcher/compact_index_spec.rb b/spec/bundler/bundler/fetcher/compact_index_spec.rb
index 00eb27edea..a988171f34 100644
--- a/spec/bundler/bundler/fetcher/compact_index_spec.rb
+++ b/spec/bundler/bundler/fetcher/compact_index_spec.rb
@@ -5,9 +5,10 @@ require "bundler/compact_index_client"
RSpec.describe Bundler::Fetcher::CompactIndex do
let(:downloader) { double(:downloader) }
- let(:display_uri) { Bundler::URI("http://sampleuri.com") }
- let(:remote) { double(:remote, :cache_slug => "lsjdf", :uri => display_uri) }
- let(:compact_index) { described_class.new(downloader, remote, display_uri) }
+ let(:display_uri) { Gem::URI("http://sampleuri.com") }
+ let(:remote) { double(:remote, cache_slug: "lsjdf", uri: display_uri) }
+ let(:gem_remote_fetcher) { nil }
+ let(:compact_index) { described_class.new(downloader, remote, display_uri, gem_remote_fetcher) }
before do
allow(compact_index).to receive(:log_specs) {}
@@ -33,7 +34,7 @@ RSpec.describe Bundler::Fetcher::CompactIndex do
describe "#available?" do
before do
allow(compact_index).to receive(:compact_index_client).
- and_return(double(:compact_index_client, :update_and_parse_checksums! => true))
+ and_return(double(:compact_index_client, update_and_parse_checksums!: true))
end
it "returns true" do
diff --git a/spec/bundler/bundler/fetcher/dependency_spec.rb b/spec/bundler/bundler/fetcher/dependency_spec.rb
index 53249116cd..c420b7c07f 100644
--- a/spec/bundler/bundler/fetcher/dependency_spec.rb
+++ b/spec/bundler/bundler/fetcher/dependency_spec.rb
@@ -2,10 +2,11 @@
RSpec.describe Bundler::Fetcher::Dependency do
let(:downloader) { double(:downloader) }
- let(:remote) { double(:remote, :uri => Bundler::URI("http://localhost:5000")) }
+ let(:remote) { double(:remote, uri: Gem::URI("http://localhost:5000")) }
let(:display_uri) { "http://sample_uri.com" }
+ let(:gem_remote_fetcher) { nil }
- subject { described_class.new(downloader, remote, display_uri) }
+ subject { described_class.new(downloader, remote, display_uri, gem_remote_fetcher) }
describe "#available?" do
let(:dependency_api_uri) { double(:dependency_api_uri) }
@@ -155,9 +156,9 @@ RSpec.describe Bundler::Fetcher::Dependency do
end
end
- shared_examples_for "the error suggests retrying with the full index" do
- it "should log the inability to fetch from API at debug level" do
- expect(Bundler).to receive_message_chain(:ui, :debug).with("could not fetch from the dependency API\nit's suggested to retry using the full index via `bundle install --full-index`")
+ shared_examples_for "the error is logged" do
+ it "should log the inability to fetch from API at debug level, and mention retrying" do
+ expect(Bundler).to receive_message_chain(:ui, :debug).with("could not fetch from the dependency API, trying the full index")
subject.specs(gem_names, full_dependency_list, last_spec_list)
end
end
@@ -166,25 +167,21 @@ RSpec.describe Bundler::Fetcher::Dependency do
before { allow(subject).to receive(:dependency_specs) { raise Bundler::HTTPError.new } }
it_behaves_like "the error is properly handled"
- it_behaves_like "the error suggests retrying with the full index"
+ it_behaves_like "the error is logged"
end
context "when a GemspecError occurs" do
before { allow(subject).to receive(:dependency_specs) { raise Bundler::GemspecError.new } }
it_behaves_like "the error is properly handled"
- it_behaves_like "the error suggests retrying with the full index"
+ it_behaves_like "the error is logged"
end
context "when a MarshalError occurs" do
before { allow(subject).to receive(:dependency_specs) { raise Bundler::MarshalError.new } }
it_behaves_like "the error is properly handled"
-
- it "should log the inability to fetch from API and mention retrying" do
- expect(Bundler).to receive_message_chain(:ui, :debug).with("could not fetch from the dependency API, trying the full index")
- subject.specs(gem_names, full_dependency_list, last_spec_list)
- end
+ it_behaves_like "the error is logged"
end
end
@@ -214,7 +211,7 @@ RSpec.describe Bundler::Fetcher::Dependency do
let(:gem_names) { [%w[foo bar], %w[bundler rubocop]] }
let(:dep_api_uri) { double(:dep_api_uri) }
let(:unmarshalled_gems) { double(:unmarshalled_gems) }
- let(:fetch_response) { double(:fetch_response, :body => double(:body)) }
+ let(:fetch_response) { double(:fetch_response, body: double(:body)) }
let(:rubygems_limit) { 50 }
before { allow(subject).to receive(:dependency_api_uri).with(gem_names).and_return(dep_api_uri) }
@@ -222,7 +219,7 @@ RSpec.describe Bundler::Fetcher::Dependency do
it "should fetch dependencies from RubyGems and unmarshal them" do
expect(gem_names).to receive(:each_slice).with(rubygems_limit).and_call_original
expect(downloader).to receive(:fetch).with(dep_api_uri).and_return(fetch_response)
- expect(Bundler).to receive(:load_marshal).with(fetch_response.body).and_return([unmarshalled_gems])
+ expect(Bundler).to receive(:safe_load_marshal).with(fetch_response.body).and_return([unmarshalled_gems])
expect(subject.unmarshalled_dep_gems(gem_names)).to eq([unmarshalled_gems])
end
end
@@ -231,20 +228,20 @@ RSpec.describe Bundler::Fetcher::Dependency do
let(:gem_list) do
[
{
- :dependencies => {
+ dependencies: {
"resque" => "req3,req4",
},
- :name => "typhoeus",
- :number => "1.0.1",
- :platform => "ruby",
+ name: "typhoeus",
+ number: "1.0.1",
+ platform: "ruby",
},
{
- :dependencies => {
+ dependencies: {
"faraday" => "req1,req2",
},
- :name => "grape",
- :number => "2.0.2",
- :platform => "jruby",
+ name: "grape",
+ number: "2.0.2",
+ platform: "jruby",
},
]
end
@@ -258,7 +255,7 @@ RSpec.describe Bundler::Fetcher::Dependency do
end
describe "#dependency_api_uri" do
- let(:uri) { Bundler::URI("http://gem-api.com") }
+ let(:uri) { Gem::URI("http://gem-api.com") }
context "with gem names" do
let(:gem_names) { %w[foo bar bundler rubocop] }
diff --git a/spec/bundler/bundler/fetcher/downloader_spec.rb b/spec/bundler/bundler/fetcher/downloader_spec.rb
index 4d3dff3a89..d5c32f4730 100644
--- a/spec/bundler/bundler/fetcher/downloader_spec.rb
+++ b/spec/bundler/bundler/fetcher/downloader_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe Bundler::Fetcher::Downloader do
let(:connection) { double(:connection) }
let(:redirect_limit) { 5 }
- let(:uri) { Bundler::URI("http://www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Gem::URI("http://www.uri-to-fetch.com/api/v2/endpoint") }
let(:options) { double(:options) }
subject { described_class.new(connection, redirect_limit) }
@@ -27,7 +27,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
context "logging" do
- let(:http_response) { Net::HTTPSuccess.new("1.1", 200, "Success") }
+ let(:http_response) { Gem::Net::HTTPSuccess.new("1.1", 200, "Success") }
it "should log the HTTP response code and message to debug" do
expect(Bundler).to receive_message_chain(:ui, :debug).with("HTTP 200 Success #{uri}")
@@ -35,48 +35,48 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
end
- context "when the request response is a Net::HTTPRedirection" do
- let(:http_response) { Net::HTTPRedirection.new(httpv, 308, "Moved") }
+ context "when the request response is a Gem::Net::HTTPRedirection" do
+ let(:http_response) { Gem::Net::HTTPRedirection.new(httpv, 308, "Moved") }
before { http_response["location"] = "http://www.redirect-uri.com/api/v2/endpoint" }
it "should try to fetch the redirect uri and iterate the # requests counter" do
- expect(subject).to receive(:fetch).with(Bundler::URI("http://www.uri-to-fetch.com/api/v2/endpoint"), options, 0).and_call_original
- expect(subject).to receive(:fetch).with(Bundler::URI("http://www.redirect-uri.com/api/v2/endpoint"), options, 1)
+ expect(subject).to receive(:fetch).with(Gem::URI("http://www.uri-to-fetch.com/api/v2/endpoint"), options, 0).and_call_original
+ expect(subject).to receive(:fetch).with(Gem::URI("http://www.redirect-uri.com/api/v2/endpoint"), options, 1)
subject.fetch(uri, options, counter)
end
context "when the redirect uri and original uri are the same" do
- let(:uri) { Bundler::URI("ssh://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Gem::URI("ssh://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
before { http_response["location"] = "ssh://www.uri-to-fetch.com/api/v1/endpoint" }
it "should set the same user and password for the redirect uri" do
- expect(subject).to receive(:fetch).with(Bundler::URI("ssh://username:password@www.uri-to-fetch.com/api/v2/endpoint"), options, 0).and_call_original
- expect(subject).to receive(:fetch).with(Bundler::URI("ssh://username:password@www.uri-to-fetch.com/api/v1/endpoint"), options, 1)
+ expect(subject).to receive(:fetch).with(Gem::URI("ssh://username:password@www.uri-to-fetch.com/api/v2/endpoint"), options, 0).and_call_original
+ expect(subject).to receive(:fetch).with(Gem::URI("ssh://username:password@www.uri-to-fetch.com/api/v1/endpoint"), options, 1)
subject.fetch(uri, options, counter)
end
end
end
- context "when the request response is a Net::HTTPSuccess" do
- let(:http_response) { Net::HTTPSuccess.new("1.1", 200, "Success") }
+ context "when the request response is a Gem::Net::HTTPSuccess" do
+ let(:http_response) { Gem::Net::HTTPSuccess.new("1.1", 200, "Success") }
it "should return the response body" do
expect(subject.fetch(uri, options, counter)).to eq(http_response)
end
end
- context "when the request response is a Net::HTTPRequestEntityTooLarge" do
- let(:http_response) { Net::HTTPRequestEntityTooLarge.new("1.1", 413, "Too Big") }
+ context "when the request response is a Gem::Net::HTTPRequestEntityTooLarge" do
+ let(:http_response) { Gem::Net::HTTPRequestEntityTooLarge.new("1.1", 413, "Too Big") }
it "should raise a Bundler::Fetcher::FallbackError with the response body" do
expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::Fetcher::FallbackError, "Body with info")
end
end
- context "when the request response is a Net::HTTPUnauthorized" do
- let(:http_response) { Net::HTTPUnauthorized.new("1.1", 401, "Unauthorized") }
+ context "when the request response is a Gem::Net::HTTPUnauthorized" do
+ let(:http_response) { Gem::Net::HTTPUnauthorized.new("1.1", 401, "Unauthorized") }
it "should raise a Bundler::Fetcher::AuthenticationRequiredError with the uri host" do
expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::Fetcher::AuthenticationRequiredError,
@@ -89,7 +89,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
context "when the there are credentials provided in the request" do
- let(:uri) { Bundler::URI("http://user:password@www.uri-to-fetch.com") }
+ let(:uri) { Gem::URI("http://user:password@www.uri-to-fetch.com") }
it "should raise a Bundler::Fetcher::BadAuthenticationError that doesn't contain the password" do
expect { subject.fetch(uri, options, counter) }.
@@ -98,29 +98,39 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
end
- context "when the request response is a Net::HTTPNotFound" do
- let(:http_response) { Net::HTTPNotFound.new("1.1", 404, "Not Found") }
+ context "when the request response is a Gem::Net::HTTPForbidden" do
+ let(:http_response) { Gem::Net::HTTPForbidden.new("1.1", 403, "Forbidden") }
+ let(:uri) { Gem::URI("http://user:password@www.uri-to-fetch.com") }
- it "should raise a Bundler::Fetcher::FallbackError with Net::HTTPNotFound" do
+ it "should raise a Bundler::Fetcher::AuthenticationForbiddenError with the uri host" do
+ expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::Fetcher::AuthenticationForbiddenError,
+ /Access token could not be authenticated for www.uri-to-fetch.com/)
+ end
+ end
+
+ context "when the request response is a Gem::Net::HTTPNotFound" do
+ let(:http_response) { Gem::Net::HTTPNotFound.new("1.1", 404, "Not Found") }
+
+ it "should raise a Bundler::Fetcher::FallbackError with Gem::Net::HTTPNotFound" do
expect { subject.fetch(uri, options, counter) }.
- to raise_error(Bundler::Fetcher::FallbackError, "Net::HTTPNotFound: http://www.uri-to-fetch.com/api/v2/endpoint")
+ to raise_error(Bundler::Fetcher::FallbackError, "Gem::Net::HTTPNotFound: http://www.uri-to-fetch.com/api/v2/endpoint")
end
context "when the there are credentials provided in the request" do
- let(:uri) { Bundler::URI("http://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Gem::URI("http://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
it "should raise a Bundler::Fetcher::FallbackError that doesn't contain the password" do
expect { subject.fetch(uri, options, counter) }.
- to raise_error(Bundler::Fetcher::FallbackError, "Net::HTTPNotFound: http://username@www.uri-to-fetch.com/api/v2/endpoint")
+ to raise_error(Bundler::Fetcher::FallbackError, "Gem::Net::HTTPNotFound: http://username@www.uri-to-fetch.com/api/v2/endpoint")
end
end
end
context "when the request response is some other type" do
- let(:http_response) { Net::HTTPBadGateway.new("1.1", 500, "Fatal Error") }
+ let(:http_response) { Gem::Net::HTTPBadGateway.new("1.1", 500, "Fatal Error") }
it "should raise a Bundler::HTTPError with the response class and body" do
- expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::HTTPError, "Net::HTTPBadGateway: Body with info")
+ expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::HTTPError, "Gem::Net::HTTPBadGateway: Body with info")
end
end
end
@@ -130,7 +140,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
let(:response) { double(:response) }
before do
- allow(Net::HTTP::Get).to receive(:new).with("/api/v2/endpoint", options).and_return(net_http_get)
+ allow(Gem::Net::HTTP::Get).to receive(:new).with("/api/v2/endpoint", options).and_return(net_http_get)
allow(connection).to receive(:request).with(uri, net_http_get).and_return(response)
end
@@ -142,7 +152,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
context "when there is a user provided in the request" do
context "and there is also a password provided" do
context "that contains cgi escaped characters" do
- let(:uri) { Bundler::URI("http://username:password%24@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Gem::URI("http://username:password%24@www.uri-to-fetch.com/api/v2/endpoint") }
it "should request basic authentication with the username and password" do
expect(net_http_get).to receive(:basic_auth).with("username", "password$")
@@ -151,7 +161,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
context "that is all unescaped characters" do
- let(:uri) { Bundler::URI("http://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Gem::URI("http://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
it "should request basic authentication with the username and proper cgi compliant password" do
expect(net_http_get).to receive(:basic_auth).with("username", "password")
subject.request(uri, options)
@@ -160,7 +170,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
context "and there is no password provided" do
- let(:uri) { Bundler::URI("http://username@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Gem::URI("http://username@www.uri-to-fetch.com/api/v2/endpoint") }
it "should request basic authentication with just the user" do
expect(net_http_get).to receive(:basic_auth).with("username", nil)
@@ -169,7 +179,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
context "that contains cgi escaped characters" do
- let(:uri) { Bundler::URI("http://username%24@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Gem::URI("http://username%24@www.uri-to-fetch.com/api/v2/endpoint") }
it "should request basic authentication with the proper cgi compliant password user" do
expect(net_http_get).to receive(:basic_auth).with("username$", nil)
@@ -178,26 +188,6 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
end
- context "when the request response causes a NoMethodError" do
- before { allow(connection).to receive(:request).with(uri, net_http_get) { raise NoMethodError.new(message) } }
-
- context "and the error message is about use_ssl=" do
- let(:message) { "undefined method 'use_ssl='" }
-
- it "should raise a LoadError about openssl" do
- expect { subject.request(uri, options) }.to raise_error(LoadError, "cannot load such file -- openssl")
- end
- end
-
- context "and the error message is not about use_ssl=" do
- let(:message) { "undefined method 'undefined_method_call'" }
-
- it "should raise the original NoMethodError" do
- expect { subject.request(uri, options) }.to raise_error(NoMethodError, "undefined method 'undefined_method_call'")
- end
- end
- end
-
context "when the request response causes a OpenSSL::SSL::SSLError" do
before { allow(connection).to receive(:request).with(uri, net_http_get) { raise OpenSSL::SSL::SSLError.new } }
@@ -240,7 +230,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
context "when the there are credentials provided in the request" do
- let(:uri) { Bundler::URI("http://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Gem::URI("http://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
before do
allow(net_http_get).to receive(:basic_auth).with("username", "password")
end
diff --git a/spec/bundler/bundler/fetcher/index_spec.rb b/spec/bundler/bundler/fetcher/index_spec.rb
index f0db07583c..dff9ccc3cc 100644
--- a/spec/bundler/bundler/fetcher/index_spec.rb
+++ b/spec/bundler/bundler/fetcher/index_spec.rb
@@ -8,8 +8,9 @@ RSpec.describe Bundler::Fetcher::Index do
let(:display_uri) { "http://sample_uri.com" }
let(:rubygems) { double(:rubygems) }
let(:gem_names) { %w[foo bar] }
+ let(:gem_remote_fetcher) { nil }
- subject { described_class.new(downloader, remote, display_uri) }
+ subject { described_class.new(downloader, remote, display_uri, gem_remote_fetcher) }
before { allow(Bundler).to receive(:rubygems).and_return(rubygems) }
@@ -19,7 +20,7 @@ RSpec.describe Bundler::Fetcher::Index do
end
context "error handling" do
- let(:remote_uri) { Bundler::URI("http://remote-uri.org") }
+ let(:remote_uri) { Gem::URI("http://remote-uri.org") }
before do
allow(rubygems).to receive(:fetch_all_remote_specs) { raise Gem::RemoteFetcher::FetchError.new(error_message, display_uri) }
allow(subject).to receive(:remote_uri).and_return(remote_uri)
@@ -63,33 +64,16 @@ RSpec.describe Bundler::Fetcher::Index do
context "when a 403 response occurs" do
let(:error_message) { "403" }
- before do
- allow(remote_uri).to receive(:userinfo).and_return(userinfo)
- end
-
- context "and there was userinfo" do
- let(:userinfo) { double(:userinfo) }
-
- it "should raise a Bundler::Fetcher::BadAuthenticationError" do
- expect { subject.specs(gem_names) }.to raise_error(Bundler::Fetcher::BadAuthenticationError,
- %r{Bad username or password for http://remote-uri.org})
- end
- end
-
- context "and there was no userinfo" do
- let(:userinfo) { nil }
-
- it "should raise a Bundler::Fetcher::AuthenticationRequiredError" do
- expect { subject.specs(gem_names) }.to raise_error(Bundler::Fetcher::AuthenticationRequiredError,
- %r{Authentication is required for http://remote-uri.org})
- end
+ it "should raise a Bundler::Fetcher::AuthenticationForbiddenError" do
+ expect { subject.specs(gem_names) }.to raise_error(Bundler::Fetcher::AuthenticationForbiddenError,
+ %r{Access token could not be authenticated for http://remote-uri.org})
end
end
context "any other message is returned" do
let(:error_message) { "You get an error, you get an error!" }
- before { allow(Bundler).to receive(:ui).and_return(double(:trace => nil)) }
+ before { allow(Bundler).to receive(:ui).and_return(double(trace: nil)) }
it "should raise a Bundler::HTTPError" do
expect { subject.specs(gem_names) }.to raise_error(Bundler::HTTPError, "Could not fetch specs from http://sample_uri.com due to underlying error <You get an error, you get an error! (http://sample_uri.com)>")
diff --git a/spec/bundler/bundler/fetcher_spec.rb b/spec/bundler/bundler/fetcher_spec.rb
index 256d342775..e20f7e7c48 100644
--- a/spec/bundler/bundler/fetcher_spec.rb
+++ b/spec/bundler/bundler/fetcher_spec.rb
@@ -3,8 +3,8 @@
require "bundler/fetcher"
RSpec.describe Bundler::Fetcher do
- let(:uri) { Bundler::URI("https://example.com") }
- let(:remote) { double("remote", :uri => uri, :original_uri => nil) }
+ let(:uri) { Gem::URI("https://example.com") }
+ let(:remote) { double("remote", uri: uri, original_uri: nil) }
subject(:fetcher) { Bundler::Fetcher.new(remote) }
@@ -26,7 +26,7 @@ RSpec.describe Bundler::Fetcher do
context "when Gem.configuration specifies http_proxy " do
let(:proxy) { "http://proxy-example2.com" }
before do
- allow(Bundler.rubygems.configuration).to receive(:[]).with(:http_proxy).and_return(proxy)
+ allow(Gem.configuration).to receive(:[]).with(:http_proxy).and_return(proxy)
end
it "consider Gem.configuration when determine proxy" do
expect(fetcher.http_proxy).to match("http://proxy-example2.com")
@@ -45,9 +45,9 @@ RSpec.describe Bundler::Fetcher do
end
context "when a rubygems source mirror is set" do
- let(:orig_uri) { Bundler::URI("http://zombo.com") }
+ let(:orig_uri) { Gem::URI("http://zombo.com") }
let(:remote_with_mirror) do
- double("remote", :uri => uri, :original_uri => orig_uri, :anonymized_uri => uri)
+ double("remote", uri: uri, original_uri: orig_uri, anonymized_uri: uri)
end
let(:fetcher) { Bundler::Fetcher.new(remote_with_mirror) }
@@ -61,7 +61,7 @@ RSpec.describe Bundler::Fetcher do
context "when there is no rubygems source mirror set" do
let(:remote_no_mirror) do
- double("remote", :uri => uri, :original_uri => nil, :anonymized_uri => uri)
+ double("remote", uri: uri, original_uri: nil, anonymized_uri: uri)
end
let(:fetcher) { Bundler::Fetcher.new(remote_no_mirror) }
@@ -113,10 +113,10 @@ RSpec.describe Bundler::Fetcher do
context "when gem ssl configuration is set" do
before do
- allow(Bundler.rubygems.configuration).to receive_messages(
- :http_proxy => nil,
- :ssl_client_cert => "cert",
- :ssl_ca_cert => "ca"
+ allow(Gem.configuration).to receive_messages(
+ http_proxy: nil,
+ ssl_client_cert: "cert",
+ ssl_ca_cert: "ca"
)
expect(File).to receive(:read).and_return("")
expect(OpenSSL::X509::Certificate).to receive(:new).and_return("cert")
@@ -143,20 +143,118 @@ RSpec.describe Bundler::Fetcher do
describe "include CI information" do
it "from one CI" do
- with_env_vars("JENKINS_URL" => "foo") do
+ with_env_vars("CI" => nil, "JENKINS_URL" => "foo") do
ci_part = fetcher.user_agent.split(" ").find {|x| x.start_with?("ci/") }
- expect(ci_part).to match("jenkins")
+ cis = ci_part.split("/").last.split(",")
+ expect(cis).to include("jenkins")
+ expect(cis).not_to include("ci")
end
end
it "from many CI" do
- with_env_vars("TRAVIS" => "foo", "GITLAB_CI" => "gitlab", "CI_NAME" => "my_ci") do
+ with_env_vars("CI" => "true", "SEMAPHORE" => nil, "TRAVIS" => "foo", "GITLAB_CI" => "gitlab", "CI_NAME" => "MY_ci") do
ci_part = fetcher.user_agent.split(" ").find {|x| x.start_with?("ci/") }
- expect(ci_part).to match("travis")
- expect(ci_part).to match("gitlab")
- expect(ci_part).to match("my_ci")
+ cis = ci_part.split("/").last.split(",")
+ expect(cis).to include("ci", "gitlab", "my_ci", "travis")
+ expect(cis).not_to include("semaphore")
end
end
end
end
+
+ describe "#fetch_spec" do
+ let(:name) { "name" }
+ let(:version) { "1.3.17" }
+ let(:platform) { "platform" }
+ let(:downloader) { double("downloader") }
+ let(:body) { double(Gem::Net::HTTP::Get, body: downloaded_data) }
+
+ context "when attempting to load a Gem::Specification" do
+ let(:spec) { Gem::Specification.new(name, version) }
+ let(:downloaded_data) { Zlib::Deflate.deflate(Marshal.dump(spec)) }
+
+ it "returns the spec" do
+ expect(Bundler::Fetcher::Downloader).to receive(:new).and_return(downloader)
+ expect(downloader).to receive(:fetch).once.and_return(body)
+ result = fetcher.fetch_spec([name, version, platform])
+ expect(result).to eq(spec)
+ end
+ end
+
+ context "when attempting to load an unexpected class" do
+ let(:downloaded_data) { Zlib::Deflate.deflate(Marshal.dump(3)) }
+
+ it "raises a HTTPError error" do
+ expect(Bundler::Fetcher::Downloader).to receive(:new).and_return(downloader)
+ expect(downloader).to receive(:fetch).once.and_return(body)
+ expect { fetcher.fetch_spec([name, version, platform]) }.to raise_error(Bundler::HTTPError, /Gemspec .* contained invalid data/i)
+ end
+ end
+ end
+
+ describe "#specs_with_retry" do
+ let(:downloader) { double(:downloader) }
+ let(:remote) { double(:remote, cache_slug: "slug", uri: uri, original_uri: nil, anonymized_uri: uri) }
+ let(:compact_index) { double(Bundler::Fetcher::CompactIndex, available?: true, api_fetcher?: true) }
+ let(:dependency) { double(Bundler::Fetcher::Dependency, available?: true, api_fetcher?: true) }
+ let(:index) { double(Bundler::Fetcher::Index, available?: true, api_fetcher?: false) }
+
+ before do
+ allow(Bundler::Fetcher::CompactIndex).to receive(:new).and_return(compact_index)
+ allow(Bundler::Fetcher::Dependency).to receive(:new).and_return(dependency)
+ allow(Bundler::Fetcher::Index).to receive(:new).and_return(index)
+ end
+
+ it "picks the first fetcher that works" do
+ expect(compact_index).to receive(:specs).with("name").and_return([["name", "1.2.3", "ruby"]])
+ expect(dependency).not_to receive(:specs)
+ expect(index).not_to receive(:specs)
+ fetcher.specs_with_retry("name", double(Bundler::Source::Rubygems))
+ end
+
+ context "when APIs are not available" do
+ before do
+ allow(compact_index).to receive(:available?).and_return(false)
+ allow(dependency).to receive(:available?).and_return(false)
+ end
+
+ it "uses the index" do
+ expect(compact_index).not_to receive(:specs)
+ expect(dependency).not_to receive(:specs)
+ expect(index).to receive(:specs).with("name").and_return([["name", "1.2.3", "ruby"]])
+
+ fetcher.specs_with_retry("name", double(Bundler::Source::Rubygems))
+ end
+ end
+ end
+
+ describe "#api_fetcher?" do
+ let(:downloader) { double(:downloader) }
+ let(:remote) { double(:remote, cache_slug: "slug", uri: uri, original_uri: nil, anonymized_uri: uri) }
+ let(:compact_index) { double(Bundler::Fetcher::CompactIndex, available?: false, api_fetcher?: true) }
+ let(:dependency) { double(Bundler::Fetcher::Dependency, available?: false, api_fetcher?: true) }
+ let(:index) { double(Bundler::Fetcher::Index, available?: true, api_fetcher?: false) }
+
+ before do
+ allow(Bundler::Fetcher::CompactIndex).to receive(:new).and_return(compact_index)
+ allow(Bundler::Fetcher::Dependency).to receive(:new).and_return(dependency)
+ allow(Bundler::Fetcher::Index).to receive(:new).and_return(index)
+ end
+
+ context "when an api fetcher is available" do
+ before do
+ allow(compact_index).to receive(:available?).and_return(true)
+ end
+
+ it "is truthy" do
+ expect(fetcher).to be_api_fetcher
+ end
+ end
+
+ context "when only the index fetcher is available" do
+ it "is falsey" do
+ expect(fetcher).not_to be_api_fetcher
+ end
+ end
+ end
end
diff --git a/spec/bundler/bundler/friendly_errors_spec.rb b/spec/bundler/bundler/friendly_errors_spec.rb
index 496191f891..cda2ef31de 100644
--- a/spec/bundler/bundler/friendly_errors_spec.rb
+++ b/spec/bundler/bundler/friendly_errors_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe Bundler, "friendly errors" do
gem "rack"
G
- bundle :install, :env => { "DEBUG" => "true" }
+ bundle :install, env: { "DEBUG" => "true" }
expect(err).to include("Failed to load #{home(".gemrc")}")
end
@@ -101,29 +101,15 @@ RSpec.describe Bundler, "friendly errors" do
context "BundlerError" do
it "Bundler.ui receive error" do
error = Bundler::BundlerError.new
- expect(Bundler.ui).to receive(:error).with(error.message, :wrap => true)
+ expect(Bundler.ui).to receive(:error).with(error.message, wrap: true)
Bundler::FriendlyErrors.log_error(error)
end
- it_behaves_like "Bundler.ui receive trace", Bundler::BundlerError.new
end
context "Thor::Error" do
it_behaves_like "Bundler.ui receive error", Bundler::Thor::Error.new
end
- context "LoadError" do
- let(:error) { LoadError.new("cannot load such file -- openssl") }
-
- before do
- allow(error).to receive(:backtrace).and_return(["backtrace"])
- end
-
- it "Bundler.ui receive error" do
- expect(Bundler.ui).to receive(:error).with("\nCould not load OpenSSL. LoadError: cannot load such file -- openssl\nbacktrace")
- Bundler::FriendlyErrors.log_error(error)
- end
- end
-
context "Interrupt" do
it "Bundler.ui receive error" do
expect(Bundler.ui).to receive(:error).with("\nQuitting...")
@@ -135,7 +121,7 @@ RSpec.describe Bundler, "friendly errors" do
context "Gem::InvalidSpecificationException" do
it "Bundler.ui receive error" do
error = Gem::InvalidSpecificationException.new
- expect(Bundler.ui).to receive(:error).with(error.message, :wrap => true)
+ expect(Bundler.ui).to receive(:error).with(error.message, wrap: true)
Bundler::FriendlyErrors.log_error(error)
end
end
diff --git a/spec/bundler/bundler/gem_helper_spec.rb b/spec/bundler/bundler/gem_helper_spec.rb
index 6c3ac3e035..940e5df9de 100644
--- a/spec/bundler/bundler/gem_helper_spec.rb
+++ b/spec/bundler/bundler/gem_helper_spec.rb
@@ -11,6 +11,7 @@ RSpec.describe Bundler::GemHelper do
before(:each) do
global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__LINTER" => "false",
"BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__CHANGELOG" => "false"
+ sys_exec("git config --global init.defaultBranch main")
bundle "gem #{app_name}"
prepare_gemspec(app_gemspec_path)
end
@@ -66,6 +67,10 @@ RSpec.describe Bundler::GemHelper do
mock_confirm_message message
end
+ def sha512_hexdigest(path)
+ Digest::SHA512.file(path).hexdigest
+ end
+
subject! { Bundler::GemHelper.new(app_path) }
let(:app_version) { "0.1.0" }
let(:app_gem_dir) { app_path.join("pkg") }
@@ -169,12 +174,21 @@ RSpec.describe Bundler::GemHelper do
end
describe "#build_checksum" do
+ it "calculates SHA512 of the content" do
+ FileUtils.mkdir_p(app_gem_dir)
+ File.write(app_gem_path, "")
+ mock_checksum_message app_name, app_version
+ subject.build_checksum(app_gem_path)
+ expect(File.read(app_sha_path).chomp).to eql(Digest::SHA512.hexdigest(""))
+ end
+
context "when build was successful" do
it "creates .sha512 file" do
mock_build_message app_name, app_version
mock_checksum_message app_name, app_version
subject.build_checksum
expect(app_sha_path).to exist
+ expect(File.read(app_sha_path).chomp).to eql(sha512_hexdigest(app_gem_path))
end
end
context "when building in the current working directory" do
@@ -185,6 +199,7 @@ RSpec.describe Bundler::GemHelper do
Bundler::GemHelper.new.build_checksum
end
expect(app_sha_path).to exist
+ expect(File.read(app_sha_path).chomp).to eql(sha512_hexdigest(app_gem_path))
end
end
context "when building in a location relative to the current working directory" do
@@ -195,6 +210,7 @@ RSpec.describe Bundler::GemHelper do
Bundler::GemHelper.new(File.basename(app_path)).build_checksum
end
expect(app_sha_path).to exist
+ expect(File.read(app_sha_path).chomp).to eql(sha512_hexdigest(app_gem_path))
end
end
end
@@ -219,7 +235,7 @@ RSpec.describe Bundler::GemHelper do
FileUtils.touch app_gem_path
app_gem_path
end
- expect { subject.install_gem }.to raise_error(/Couldn't install gem/)
+ expect { subject.install_gem }.to raise_error(/Running `#{gem_bin} install #{app_gem_path}` failed/)
end
end
end
@@ -237,11 +253,11 @@ RSpec.describe Bundler::GemHelper do
end
before do
- sys_exec("git init", :dir => app_path)
- sys_exec("git config user.email \"you@example.com\"", :dir => app_path)
- sys_exec("git config user.name \"name\"", :dir => app_path)
- sys_exec("git config commit.gpgsign false", :dir => app_path)
- sys_exec("git config push.default simple", :dir => app_path)
+ sys_exec("git init", dir: app_path)
+ sys_exec("git config user.email \"you@example.com\"", dir: app_path)
+ sys_exec("git config user.name \"name\"", dir: app_path)
+ sys_exec("git config commit.gpgsign false", dir: app_path)
+ sys_exec("git config push.default simple", dir: app_path)
# silence messages
allow(Bundler.ui).to receive(:confirm)
@@ -255,23 +271,23 @@ RSpec.describe Bundler::GemHelper do
end
it "when there are uncommitted files" do
- sys_exec("git add .", :dir => app_path)
+ sys_exec("git add .", dir: app_path)
expect { Rake.application["release"].invoke }.
to raise_error("There are files that need to be committed first.")
end
it "when there is no git remote" do
- sys_exec("git commit -a -m \"initial commit\"", :dir => app_path)
+ sys_exec("git commit -a -m \"initial commit\"", dir: app_path)
expect { Rake.application["release"].invoke }.to raise_error(RuntimeError)
end
end
context "succeeds" do
- let(:repo) { build_git("foo", :bare => true) }
+ let(:repo) { build_git("foo", bare: true) }
before do
- sys_exec("git remote add origin #{file_uri_for(repo.path)}", :dir => app_path)
- sys_exec('git commit -a -m "initial commit"', :dir => app_path)
+ sys_exec("git remote add origin #{file_uri_for(repo.path)}", dir: app_path)
+ sys_exec('git commit -a -m "initial commit"', dir: app_path)
end
context "on releasing" do
@@ -280,7 +296,7 @@ RSpec.describe Bundler::GemHelper do
mock_confirm_message "Tagged v#{app_version}."
mock_confirm_message "Pushed git commits and release tag."
- sys_exec("git push -u origin master", :dir => app_path)
+ sys_exec("git push -u origin main", dir: app_path)
end
it "calls rubygem_push with proper arguments" do
@@ -298,8 +314,8 @@ RSpec.describe Bundler::GemHelper do
it "also works when releasing from an ambiguous reference" do
# Create a branch with the same name as the tag
- sys_exec("git checkout -b v#{app_version}", :dir => app_path)
- sys_exec("git push -u origin v#{app_version}", :dir => app_path)
+ sys_exec("git checkout -b v#{app_version}", dir: app_path)
+ sys_exec("git push -u origin v#{app_version}", dir: app_path)
expect(subject).to receive(:rubygem_push).with(app_gem_path.to_s)
@@ -307,7 +323,7 @@ RSpec.describe Bundler::GemHelper do
end
it "also works with releasing from a branch not yet pushed" do
- sys_exec("git checkout -b module_function", :dir => app_path)
+ sys_exec("git checkout -b module_function", dir: app_path)
expect(subject).to receive(:rubygem_push).with(app_gem_path.to_s)
@@ -321,7 +337,7 @@ RSpec.describe Bundler::GemHelper do
mock_build_message app_name, app_version
mock_confirm_message "Pushed git commits and release tag."
- sys_exec("git push -u origin master", :dir => app_path)
+ sys_exec("git push -u origin main", dir: app_path)
expect(subject).to receive(:rubygem_push).with(app_gem_path.to_s)
end
@@ -337,7 +353,7 @@ RSpec.describe Bundler::GemHelper do
mock_confirm_message "Tag v#{app_version} has already been created."
expect(subject).to receive(:rubygem_push).with(app_gem_path.to_s)
- sys_exec("git tag -a -m \"Version #{app_version}\" v#{app_version}", :dir => app_path)
+ sys_exec("git tag -a -m \"Version #{app_version}\" v#{app_version}", dir: app_path)
Rake.application["release"].invoke
end
@@ -358,10 +374,10 @@ RSpec.describe Bundler::GemHelper do
end
before do
- sys_exec("git init", :dir => app_path)
- sys_exec("git config user.email \"you@example.com\"", :dir => app_path)
- sys_exec("git config user.name \"name\"", :dir => app_path)
- sys_exec("git config push.gpgsign simple", :dir => app_path)
+ sys_exec("git init", dir: app_path)
+ sys_exec("git config user.email \"you@example.com\"", dir: app_path)
+ sys_exec("git config user.name \"name\"", dir: app_path)
+ sys_exec("git config push.gpgsign simple", dir: app_path)
# silence messages
allow(Bundler.ui).to receive(:confirm)
diff --git a/spec/bundler/bundler/gem_version_promoter_spec.rb b/spec/bundler/bundler/gem_version_promoter_spec.rb
index 43a3630bbb..917daba95d 100644
--- a/spec/bundler/bundler/gem_version_promoter_spec.rb
+++ b/spec/bundler/bundler/gem_version_promoter_spec.rb
@@ -1,178 +1,162 @@
# frozen_string_literal: true
RSpec.describe Bundler::GemVersionPromoter do
- context "conservative resolver" do
- def versions(result)
- result.flatten.map(&:version).map(&:to_s)
+ let(:gvp) { described_class.new }
+
+ # Rightmost (highest array index) in result is most preferred.
+ # Leftmost (lowest array index) in result is least preferred.
+ # `build_candidates` has all versions of gem in index.
+ # `build_spec` is the version currently in the .lock file.
+ #
+ # In default (not strict) mode, all versions in the index will
+ # be returned, allowing Bundler the best chance to resolve all
+ # dependencies, but sometimes resulting in upgrades that some
+ # would not consider conservative.
+
+ describe "#sort_versions" do
+ def build_candidates(versions)
+ versions.map do |v|
+ Bundler::Resolver::Candidate.new(v)
+ end
end
- def make_instance(*args)
- @gvp = Bundler::GemVersionPromoter.new(*args).tap do |gvp|
- gvp.class.class_eval { public :filter_dep_specs, :sort_dep_specs }
- end
+ def build_package(name, version, locked = [])
+ Bundler::Resolver::Package.new(name, [], locked_specs: Bundler::SpecSet.new(build_spec(name, version)), unlock: locked)
end
- def unlocking(options)
- make_instance(Bundler::SpecSet.new([]), ["foo"]).tap do |p|
- p.level = options[:level] if options[:level]
- p.strict = options[:strict] if options[:strict]
- end
+ def sorted_versions(candidates:, current:, name: "foo", locked: [])
+ gvp.sort_versions(
+ build_package(name, current, locked),
+ build_candidates(candidates)
+ ).flatten.map(&:version).map(&:to_s)
end
- def keep_locked(options)
- make_instance(Bundler::SpecSet.new([]), ["bar"]).tap do |p|
- p.level = options[:level] if options[:level]
- p.strict = options[:strict] if options[:strict]
- end
+ it "numerically sorts versions" do
+ versions = sorted_versions(candidates: %w[1.7.7 1.7.8 1.7.9 1.7.15 1.8.0], current: "1.7.8")
+ expect(versions).to eq %w[1.8.0 1.7.15 1.7.9 1.7.8 1.7.7]
end
- def build_spec_groups(name, versions)
- versions.map do |v|
- Bundler::Resolver::SpecGroup.create_for({ Gem::Platform::RUBY => build_spec(name, v) }, [Gem::Platform::RUBY], Gem::Platform::RUBY)
+ context "with no options" do
+ it "defaults to level=:major, strict=false, pre=false" do
+ versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
+ expect(versions).to eq %w[2.1.0 2.0.1 1.0.0 0.9.0 0.3.1 0.3.0 0.2.0]
end
end
- # Rightmost (highest array index) in result is most preferred.
- # Leftmost (lowest array index) in result is least preferred.
- # `build_spec_groups` has all versions of gem in index.
- # `build_spec` is the version currently in the .lock file.
- #
- # In default (not strict) mode, all versions in the index will
- # be returned, allowing Bundler the best chance to resolve all
- # dependencies, but sometimes resulting in upgrades that some
- # would not consider conservative.
- context "filter specs (strict) level patch" do
- it "when keeping build_spec, keep current, next release" do
- keep_locked(:level => :patch)
- res = @gvp.filter_dep_specs(
- build_spec_groups("foo", %w[1.7.8 1.7.9 1.8.0]),
- build_spec("foo", "1.7.8").first
- )
- expect(versions(res)).to eq %w[1.7.9 1.7.8]
- end
+ context "when strict" do
+ before { gvp.strict = true }
- it "when unlocking prefer next release first" do
- unlocking(:level => :patch)
- res = @gvp.filter_dep_specs(
- build_spec_groups("foo", %w[1.7.8 1.7.9 1.8.0]),
- build_spec("foo", "1.7.8").first
- )
- expect(versions(res)).to eq %w[1.7.8 1.7.9]
- end
+ context "when level is major" do
+ before { gvp.level = :major }
- it "when unlocking keep current when already at latest release" do
- unlocking(:level => :patch)
- res = @gvp.filter_dep_specs(
- build_spec_groups("foo", %w[1.7.9 1.8.0 2.0.0]),
- build_spec("foo", "1.7.9").first
- )
- expect(versions(res)).to eq %w[1.7.9]
+ it "keeps downgrades" do
+ versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
+ expect(versions).to eq %w[2.1.0 2.0.1 1.0.0 0.9.0 0.3.1 0.3.0 0.2.0]
+ end
end
- end
- context "filter specs (strict) level minor" do
- it "when unlocking favor next releases, remove minor and major increases" do
- unlocking(:level => :minor)
- res = @gvp.filter_dep_specs(
- build_spec_groups("foo", %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.0 2.0.1]),
- build_spec("foo", "0.2.0").first
- )
- expect(versions(res)).to eq %w[0.2.0 0.3.0 0.3.1 0.9.0]
+ context "when level is minor" do
+ before { gvp.level = :minor }
+
+ it "sorts highest minor within same major in first position" do
+ versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
+ expect(versions).to eq %w[0.9.0 0.3.1 0.3.0 1.0.0 2.1.0 2.0.1 0.2.0]
+ end
end
- it "when keep locked, keep current, then favor next release, remove minor and major increases" do
- keep_locked(:level => :minor)
- res = @gvp.filter_dep_specs(
- build_spec_groups("foo", %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.0 2.0.1]),
- build_spec("foo", "0.2.0").first
- )
- expect(versions(res)).to eq %w[0.3.0 0.3.1 0.9.0 0.2.0]
+ context "when level is patch" do
+ before { gvp.level = :patch }
+
+ it "sorts highest patch within same minor in first position" do
+ versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
+ expect(versions).to eq %w[0.3.1 0.3.0 0.9.0 1.0.0 2.0.1 2.1.0 0.2.0]
+ end
end
end
- context "sort specs (not strict) level patch" do
- it "when not unlocking, same order but make sure build_spec version is most preferred to stay put" do
- keep_locked(:level => :patch)
- res = @gvp.sort_dep_specs(
- build_spec_groups("foo", %w[1.5.4 1.6.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 2.0.0 2.0.1]),
- build_spec("foo", "1.7.7").first
- )
- expect(versions(res)).to eq %w[1.5.4 1.6.5 1.7.6 2.0.0 2.0.1 1.8.0 1.8.1 1.7.8 1.7.9 1.7.7]
- end
+ context "when not strict" do
+ before { gvp.strict = false }
- it "when unlocking favor next release, then current over minor increase" do
- unlocking(:level => :patch)
- res = @gvp.sort_dep_specs(
- build_spec_groups("foo", %w[1.7.7 1.7.8 1.7.9 1.8.0]),
- build_spec("foo", "1.7.8").first
- )
- expect(versions(res)).to eq %w[1.7.7 1.8.0 1.7.8 1.7.9]
+ context "when level is major" do
+ before { gvp.level = :major }
+
+ it "orders by version" do
+ versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
+ expect(versions).to eq %w[2.1.0 2.0.1 1.0.0 0.9.0 0.3.1 0.3.0 0.2.0]
+ end
end
- it "when unlocking do proper integer comparison, not string" do
- unlocking(:level => :patch)
- res = @gvp.sort_dep_specs(
- build_spec_groups("foo", %w[1.7.7 1.7.8 1.7.9 1.7.15 1.8.0]),
- build_spec("foo", "1.7.8").first
- )
- expect(versions(res)).to eq %w[1.7.7 1.8.0 1.7.8 1.7.9 1.7.15]
+ context "when level is minor" do
+ before { gvp.level = :minor }
+
+ it "favors minor upgrades, then patch upgrades, then major upgrades, then downgrades" do
+ versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
+ expect(versions).to eq %w[0.9.0 0.3.1 0.3.0 1.0.0 2.1.0 2.0.1 0.2.0]
+ end
end
- it "leave current when unlocking but already at latest release" do
- unlocking(:level => :patch)
- res = @gvp.sort_dep_specs(
- build_spec_groups("foo", %w[1.7.9 1.8.0 2.0.0]),
- build_spec("foo", "1.7.9").first
- )
- expect(versions(res)).to eq %w[2.0.0 1.8.0 1.7.9]
+ context "when level is patch" do
+ before { gvp.level = :patch }
+
+ it "favors patch upgrades, then minor upgrades, then major upgrades, then downgrades" do
+ versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
+ expect(versions).to eq %w[0.3.1 0.3.0 0.9.0 1.0.0 2.0.1 2.1.0 0.2.0]
+ end
end
end
- context "sort specs (not strict) level minor" do
- it "when unlocking favor next release, then minor increase over current" do
- unlocking(:level => :minor)
- res = @gvp.sort_dep_specs(
- build_spec_groups("foo", %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.0 2.0.1]),
- build_spec("foo", "0.2.0").first
- )
- expect(versions(res)).to eq %w[2.0.0 2.0.1 1.0.0 0.2.0 0.3.0 0.3.1 0.9.0]
+ context "when pre" do
+ before { gvp.pre = true }
+
+ it "sorts regardless of prerelease status" do
+ versions = sorted_versions(candidates: %w[1.7.7.pre 1.8.0 1.8.1.pre 1.8.1 2.0.0.pre 2.0.0], current: "1.8.0")
+ expect(versions).to eq %w[2.0.0 2.0.0.pre 1.8.1 1.8.1.pre 1.8.0 1.7.7.pre]
end
end
- context "level error handling" do
- subject { Bundler::GemVersionPromoter.new }
+ context "when not pre" do
+ before { gvp.pre = false }
- it "should raise if not major, minor or patch is passed" do
- expect { subject.level = :minjor }.to raise_error ArgumentError
+ it "deprioritizes prerelease gems" do
+ versions = sorted_versions(candidates: %w[1.7.7.pre 1.8.0 1.8.1.pre 1.8.1 2.0.0.pre 2.0.0], current: "1.8.0")
+ expect(versions).to eq %w[2.0.0 1.8.1 1.8.0 2.0.0.pre 1.8.1.pre 1.7.7.pre]
end
+ end
- it "should raise if invalid classes passed" do
- [123, nil].each do |value|
- expect { subject.level = value }.to raise_error ArgumentError
- end
+ context "when locking and not major" do
+ before { gvp.level = :minor }
+
+ it "keeps the current version first" do
+ versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.1.0 2.0.1], current: "0.3.0", locked: ["bar"])
+ expect(versions.first).to eq("0.3.0")
end
+ end
+ end
- it "should accept major, minor patch symbols" do
- [:major, :minor, :patch].each do |value|
- subject.level = value
- expect(subject.level).to eq value
- end
+ describe "#level=" do
+ subject { described_class.new }
+
+ it "should raise if not major, minor or patch is passed" do
+ expect { subject.level = :minjor }.to raise_error ArgumentError
+ end
+
+ it "should raise if invalid classes passed" do
+ [123, nil].each do |value|
+ expect { subject.level = value }.to raise_error ArgumentError
end
+ end
- it "should accept major, minor patch strings" do
- %w[major minor patch].each do |value|
- subject.level = value
- expect(subject.level).to eq value.to_sym
- end
+ it "should accept major, minor patch symbols" do
+ [:major, :minor, :patch].each do |value|
+ subject.level = value
+ expect(subject.level).to eq value
end
end
- context "debug output" do
- it "should not kerblooie on its own debug output" do
- gvp = unlocking(:level => :patch)
- dep = Bundler::DepProxy.get_proxy(dep("foo", "1.2.0").first, "ruby")
- result = gvp.send(:debug_format_result, dep, build_spec_groups("foo", %w[1.2.0 1.3.0]))
- expect(result.class).to eq Array
+ it "should accept major, minor patch strings" do
+ %w[major minor patch].each do |value|
+ subject.level = value
+ expect(subject.level).to eq value.to_sym
end
end
end
diff --git a/spec/bundler/bundler/installer/gem_installer_spec.rb b/spec/bundler/bundler/installer/gem_installer_spec.rb
index 8f8d1c6d15..4b6a07f344 100644
--- a/spec/bundler/bundler/installer/gem_installer_spec.rb
+++ b/spec/bundler/bundler/installer/gem_installer_spec.rb
@@ -3,15 +3,19 @@
require "bundler/installer/gem_installer"
RSpec.describe Bundler::GemInstaller do
- let(:installer) { instance_double("Installer") }
+ let(:definition) { instance_double("Definition", locked_gems: nil) }
+ let(:installer) { instance_double("Installer", definition: definition) }
let(:spec_source) { instance_double("SpecSource") }
- let(:spec) { instance_double("Specification", :name => "dummy", :version => "0.0.1", :loaded_from => "dummy", :source => spec_source) }
+ let(:spec) { instance_double("Specification", name: "dummy", version: "0.0.1", loaded_from: "dummy", source: spec_source) }
subject { described_class.new(spec, installer) }
context "spec_settings is nil" do
it "invokes install method with empty build_args" do
- allow(spec_source).to receive(:install).with(spec, :force => false, :ensure_builtin_gems_cached => false, :build_args => [])
+ allow(spec_source).to receive(:install).with(
+ spec,
+ { force: false, ensure_builtin_gems_cached: false, build_args: [], previous_spec: nil }
+ )
subject.install_from_spec
end
end
@@ -22,7 +26,10 @@ RSpec.describe Bundler::GemInstaller do
allow(Bundler.settings).to receive(:[]).with(:inline)
allow(Bundler.settings).to receive(:[]).with(:forget_cli_options)
allow(Bundler.settings).to receive(:[]).with("build.dummy").and_return("--with-dummy-config=dummy")
- expect(spec_source).to receive(:install).with(spec, :force => false, :ensure_builtin_gems_cached => false, :build_args => ["--with-dummy-config=dummy"])
+ expect(spec_source).to receive(:install).with(
+ spec,
+ { force: false, ensure_builtin_gems_cached: false, build_args: ["--with-dummy-config=dummy"], previous_spec: nil }
+ )
subject.install_from_spec
end
end
@@ -33,7 +40,10 @@ RSpec.describe Bundler::GemInstaller do
allow(Bundler.settings).to receive(:[]).with(:inline)
allow(Bundler.settings).to receive(:[]).with(:forget_cli_options)
allow(Bundler.settings).to receive(:[]).with("build.dummy").and_return("--with-dummy-config=dummy --with-another-dummy-config")
- expect(spec_source).to receive(:install).with(spec, :force => false, :ensure_builtin_gems_cached => false, :build_args => ["--with-dummy-config=dummy", "--with-another-dummy-config"])
+ expect(spec_source).to receive(:install).with(
+ spec,
+ { force: false, ensure_builtin_gems_cached: false, build_args: ["--with-dummy-config=dummy", "--with-another-dummy-config"], previous_spec: nil }
+ )
subject.install_from_spec
end
end
diff --git a/spec/bundler/bundler/installer/parallel_installer_spec.rb b/spec/bundler/bundler/installer/parallel_installer_spec.rb
deleted file mode 100644
index e680633862..0000000000
--- a/spec/bundler/bundler/installer/parallel_installer_spec.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-# frozen_string_literal: true
-
-require "bundler/installer/parallel_installer"
-
-RSpec.describe Bundler::ParallelInstaller do
- let(:installer) { instance_double("Installer") }
- let(:all_specs) { [] }
- let(:size) { 1 }
- let(:standalone) { false }
- let(:force) { false }
-
- subject { described_class.new(installer, all_specs, size, standalone, force) }
-
- context "when dependencies that are not on the overall installation list are the only ones not installed" do
- let(:all_specs) do
- [
- build_spec("alpha", "1.0") {|s| s.runtime "a", "1" },
- ].flatten
- end
-
- it "prints a warning" do
- expect(Bundler.ui).to receive(:warn).with(<<-W.strip)
-Your lockfile was created by an old Bundler that left some things out.
-You can fix this by adding the missing gems to your Gemfile, running bundle install, and then removing the gems from your Gemfile.
-The missing gems are:
-* a depended upon by alpha
- W
- subject.check_for_corrupt_lockfile
- end
-
- context "when size > 1" do
- let(:size) { 500 }
-
- it "prints a warning and sets size to 1" do
- expect(Bundler.ui).to receive(:warn).with(<<-W.strip)
-Your lockfile was created by an old Bundler that left some things out.
-Because of the missing DEPENDENCIES, we can only install gems one at a time, instead of installing 500 at a time.
-You can fix this by adding the missing gems to your Gemfile, running bundle install, and then removing the gems from your Gemfile.
-The missing gems are:
-* a depended upon by alpha
- W
- subject.check_for_corrupt_lockfile
- expect(subject.size).to eq(1)
- end
- end
- end
-
- context "when the spec set is not a valid resolution" do
- let(:all_specs) do
- [
- build_spec("cucumber", "4.1.0") {|s| s.runtime "diff-lcs", "< 1.4" },
- build_spec("diff-lcs", "1.4.4"),
- ].flatten
- end
-
- it "prints a warning" do
- expect(Bundler.ui).to receive(:warn).with(<<-W.strip)
-Your lockfile doesn't include a valid resolution.
-You can fix this by regenerating your lockfile or trying to manually editing the bad locked gems to a version that satisfies all dependencies.
-The unmet dependencies are:
-* diff-lcs (< 1.4), depended upon cucumber-4.1.0, unsatisfied by diff-lcs-1.4.4
- W
- subject.check_for_unmet_dependencies
- end
- end
-
- context "when the spec set is a valid resolution" do
- let(:all_specs) do
- [
- build_spec("cucumber", "4.1.0") {|s| s.runtime "diff-lcs", "< 1.4" },
- build_spec("diff-lcs", "1.3"),
- ].flatten
- end
-
- it "doesn't print a warning" do
- expect(Bundler.ui).not_to receive(:warn)
- subject.check_for_unmet_dependencies
- end
- end
-end
diff --git a/spec/bundler/bundler/installer/spec_installation_spec.rb b/spec/bundler/bundler/installer/spec_installation_spec.rb
index e63ef26cb3..cbe2589b99 100644
--- a/spec/bundler/bundler/installer/spec_installation_spec.rb
+++ b/spec/bundler/bundler/installer/spec_installation_spec.rb
@@ -42,24 +42,26 @@ RSpec.describe Bundler::ParallelInstaller::SpecInstallation do
context "when all dependencies are installed" do
it "returns true" do
dependencies = []
- dependencies << instance_double("SpecInstallation", :spec => "alpha", :name => "alpha", :installed? => true, :all_dependencies => [], :type => :production)
- dependencies << instance_double("SpecInstallation", :spec => "beta", :name => "beta", :installed? => true, :all_dependencies => [], :type => :production)
- all_specs = dependencies + [instance_double("SpecInstallation", :spec => "gamma", :name => "gamma", :installed? => false, :all_dependencies => [], :type => :production)]
+ dependencies << instance_double("SpecInstallation", spec: "alpha", name: "alpha", installed?: true, all_dependencies: [], type: :production)
+ dependencies << instance_double("SpecInstallation", spec: "beta", name: "beta", installed?: true, all_dependencies: [], type: :production)
+ all_specs = dependencies + [instance_double("SpecInstallation", spec: "gamma", name: "gamma", installed?: false, all_dependencies: [], type: :production)]
spec = described_class.new(dep)
allow(spec).to receive(:all_dependencies).and_return(dependencies)
- expect(spec.dependencies_installed?(all_specs)).to be_truthy
+ installed_specs = all_specs.select(&:installed?).map {|s| [s.name, true] }.to_h
+ expect(spec.dependencies_installed?(installed_specs)).to be_truthy
end
end
context "when all dependencies are not installed" do
it "returns false" do
dependencies = []
- dependencies << instance_double("SpecInstallation", :spec => "alpha", :name => "alpha", :installed? => false, :all_dependencies => [], :type => :production)
- dependencies << instance_double("SpecInstallation", :spec => "beta", :name => "beta", :installed? => true, :all_dependencies => [], :type => :production)
- all_specs = dependencies + [instance_double("SpecInstallation", :spec => "gamma", :name => "gamma", :installed? => false, :all_dependencies => [], :type => :production)]
+ dependencies << instance_double("SpecInstallation", spec: "alpha", name: "alpha", installed?: false, all_dependencies: [], type: :production)
+ dependencies << instance_double("SpecInstallation", spec: "beta", name: "beta", installed?: true, all_dependencies: [], type: :production)
+ all_specs = dependencies + [instance_double("SpecInstallation", spec: "gamma", name: "gamma", installed?: false, all_dependencies: [], type: :production)]
spec = described_class.new(dep)
allow(spec).to receive(:all_dependencies).and_return(dependencies)
- expect(spec.dependencies_installed?(all_specs)).to be_falsey
+ installed_specs = all_specs.select(&:installed?).map {|s| [s.name, true] }.to_h
+ expect(spec.dependencies_installed?(installed_specs)).to be_falsey
end
end
end
diff --git a/spec/bundler/bundler/lockfile_parser_spec.rb b/spec/bundler/bundler/lockfile_parser_spec.rb
index 3a6d61336f..88932bf009 100644
--- a/spec/bundler/bundler/lockfile_parser_spec.rb
+++ b/spec/bundler/bundler/lockfile_parser_spec.rb
@@ -3,7 +3,7 @@
require "bundler/lockfile_parser"
RSpec.describe Bundler::LockfileParser do
- let(:lockfile_contents) { strip_whitespace(<<-L) }
+ let(:lockfile_contents) { <<~L }
GIT
remote: https://github.com/alloy/peiji-san.git
revision: eca485d8dc95f12aaec1a434b49d295c7e91844b
@@ -22,6 +22,9 @@ RSpec.describe Bundler::LockfileParser do
peiji-san!
rake
+ CHECKSUMS
+ rake (10.3.2) sha256=814828c34f1315d7e7b7e8295184577cc4e969bad6156ac069d02d63f58d82e8
+
RUBY VERSION
ruby 2.1.3p242
@@ -33,13 +36,13 @@ RSpec.describe Bundler::LockfileParser do
it "returns the attributes" do
attributes = described_class.sections_in_lockfile(lockfile_contents)
expect(attributes).to contain_exactly(
- "BUNDLED WITH", "DEPENDENCIES", "GEM", "GIT", "PLATFORMS", "RUBY VERSION"
+ "BUNDLED WITH", "CHECKSUMS", "DEPENDENCIES", "GEM", "GIT", "PLATFORMS", "RUBY VERSION"
)
end
end
describe ".unknown_sections_in_lockfile" do
- let(:lockfile_contents) { strip_whitespace(<<-L) }
+ let(:lockfile_contents) { <<~L }
UNKNOWN ATTR
UNKNOWN ATTR 2
@@ -60,7 +63,7 @@ RSpec.describe Bundler::LockfileParser do
it "returns the same as > 1.0" do
expect(subject).to contain_exactly(
- described_class::BUNDLED, described_class::RUBY, described_class::PLUGIN
+ described_class::BUNDLED, described_class::CHECKSUMS, described_class::RUBY, described_class::PLUGIN
)
end
end
@@ -70,7 +73,7 @@ RSpec.describe Bundler::LockfileParser do
it "returns the same as for the release version" do
expect(subject).to contain_exactly(
- described_class::RUBY, described_class::PLUGIN
+ described_class::CHECKSUMS, described_class::RUBY, described_class::PLUGIN
)
end
end
@@ -115,6 +118,14 @@ RSpec.describe Bundler::LockfileParser do
let(:platforms) { [rb] }
let(:bundler_version) { Gem::Version.new("1.12.0.rc.2") }
let(:ruby_version) { "ruby 2.1.3p242" }
+ let(:lockfile_path) { Bundler.default_lockfile.relative_path_from(Dir.pwd) }
+ let(:rake_sha256_checksum) do
+ Bundler::Checksum.from_lock(
+ "sha256=814828c34f1315d7e7b7e8295184577cc4e969bad6156ac069d02d63f58d82e8",
+ "#{lockfile_path}:20:17"
+ )
+ end
+ let(:rake_checksums) { [rake_sha256_checksum] }
shared_examples_for "parsing" do
it "parses correctly" do
@@ -125,6 +136,9 @@ RSpec.describe Bundler::LockfileParser do
expect(subject.platforms).to eq platforms
expect(subject.bundler_version).to eq bundler_version
expect(subject.ruby_version).to eq ruby_version
+ rake_spec = specs.last
+ checksums = subject.sources.last.checksum_store.to_lock(specs.last)
+ expect(checksums).to eq("#{rake_spec.name_tuple.lock_name} #{rake_checksums.map(&:to_lock).sort.join(",")}")
end
end
@@ -149,5 +163,59 @@ RSpec.describe Bundler::LockfileParser do
let(:lockfile_contents) { super().sub("peiji-san!", "peiji-san!\n foo: bar") }
include_examples "parsing"
end
+
+ context "when the checksum is urlsafe base64 encoded" do
+ let(:lockfile_contents) do
+ super().sub(
+ "sha256=814828c34f1315d7e7b7e8295184577cc4e969bad6156ac069d02d63f58d82e8",
+ "sha256=gUgow08TFdfnt-gpUYRXfMTpabrWFWrAadAtY_WNgug="
+ )
+ end
+ include_examples "parsing"
+ end
+
+ context "when the checksum is of an unknown algorithm" do
+ let(:rake_sha512_checksum) do
+ Bundler::Checksum.from_lock(
+ "sha512=pVDn9GLmcFkz8vj1ueiVxj5uGKkAyaqYjEX8zG6L5O4BeVg3wANaKbQdpj/B82Nd/MHVszy6polHcyotUdwilQ==",
+ "#{lockfile_path}:20:17"
+ )
+ end
+ let(:lockfile_contents) do
+ super().sub(
+ "sha256=",
+ "sha512=pVDn9GLmcFkz8vj1ueiVxj5uGKkAyaqYjEX8zG6L5O4BeVg3wANaKbQdpj/B82Nd/MHVszy6polHcyotUdwilQ==,sha256="
+ )
+ end
+ let(:rake_checksums) { [rake_sha256_checksum, rake_sha512_checksum] }
+ include_examples "parsing"
+ end
+
+ context "when CHECKSUMS has duplicate checksums in the lockfile that don't match" do
+ let(:bad_checksum) { "sha256=c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11" }
+ let(:lockfile_contents) { super().split(/(?<=CHECKSUMS\n)/m).insert(1, " rake (10.3.2) #{bad_checksum}\n").join }
+
+ it "raises a security error" do
+ expect { subject }.to raise_error(Bundler::SecurityError) do |e|
+ expect(e.message).to match <<~MESSAGE
+ Bundler found mismatched checksums. This is a potential security risk.
+ rake (10.3.2) #{bad_checksum}
+ from the lockfile CHECKSUMS at #{lockfile_path}:20:17
+ rake (10.3.2) #{rake_sha256_checksum.to_lock}
+ from the lockfile CHECKSUMS at #{lockfile_path}:21:17
+
+ To resolve this issue you can either:
+ 1. remove the matching checksum in #{lockfile_path}:21:17
+ 2. run `bundle install`
+ or if you are sure that the new checksum from the lockfile CHECKSUMS at #{lockfile_path}:21:17 is correct:
+ 1. remove the matching checksum in #{lockfile_path}:20:17
+ 2. run `bundle install`
+
+ To ignore checksum security warnings, disable checksum validation with
+ `bundle config set --local disable_checksum_validation true`
+ MESSAGE
+ end
+ end
+ end
end
end
diff --git a/spec/bundler/bundler/mirror_spec.rb b/spec/bundler/bundler/mirror_spec.rb
index 1eaf1e9a8e..ba1c6ed413 100644
--- a/spec/bundler/bundler/mirror_spec.rb
+++ b/spec/bundler/bundler/mirror_spec.rb
@@ -36,12 +36,12 @@ RSpec.describe Bundler::Settings::Mirror do
it "takes a string for the uri but returns an uri object" do
mirror.uri = "http://localhost:9292"
- expect(mirror.uri).to eq(Bundler::URI("http://localhost:9292"))
+ expect(mirror.uri).to eq(Gem::URI("http://localhost:9292"))
end
it "takes an uri object for the uri" do
- mirror.uri = Bundler::URI("http://localhost:9293")
- expect(mirror.uri).to eq(Bundler::URI("http://localhost:9293"))
+ mirror.uri = Gem::URI("http://localhost:9293")
+ expect(mirror.uri).to eq(Gem::URI("http://localhost:9293"))
end
context "without a uri" do
@@ -145,7 +145,7 @@ RSpec.describe Bundler::Settings::Mirror do
end
RSpec.describe Bundler::Settings::Mirrors do
- let(:localhost_uri) { Bundler::URI("http://localhost:9292") }
+ let(:localhost_uri) { Gem::URI("http://localhost:9292") }
context "with a just created mirror" do
let(:mirrors) do
@@ -260,7 +260,7 @@ RSpec.describe Bundler::Settings::Mirrors do
before { mirrors.parse("mirror.all.fallback_timeout", "true") }
it "returns the source uri, not localhost" do
- expect(mirrors.for("http://whatever.com").uri).to eq(Bundler::URI("http://whatever.com/"))
+ expect(mirrors.for("http://whatever.com").uri).to eq(Gem::URI("http://whatever.com/"))
end
end
end
@@ -270,7 +270,7 @@ RSpec.describe Bundler::Settings::Mirrors do
context "without a fallback timeout" do
it "returns the uri that is not mirrored" do
- expect(mirrors.for("http://whatever.com").uri).to eq(Bundler::URI("http://whatever.com/"))
+ expect(mirrors.for("http://whatever.com").uri).to eq(Gem::URI("http://whatever.com/"))
end
it "returns localhost for rubygems.org" do
@@ -282,11 +282,11 @@ RSpec.describe Bundler::Settings::Mirrors do
before { mirrors.parse("mirror.http://rubygems.org/.fallback_timeout", "true") }
it "returns the uri that is not mirrored" do
- expect(mirrors.for("http://whatever.com").uri).to eq(Bundler::URI("http://whatever.com/"))
+ expect(mirrors.for("http://whatever.com").uri).to eq(Gem::URI("http://whatever.com/"))
end
it "returns rubygems.org for rubygems.org" do
- expect(mirrors.for("http://rubygems.org/").uri).to eq(Bundler::URI("http://rubygems.org/"))
+ expect(mirrors.for("http://rubygems.org/").uri).to eq(Gem::URI("http://rubygems.org/"))
end
end
end
diff --git a/spec/bundler/bundler/plugin/api/source_spec.rb b/spec/bundler/bundler/plugin/api/source_spec.rb
index 428ceb220a..ae02e08bea 100644
--- a/spec/bundler/bundler/plugin/api/source_spec.rb
+++ b/spec/bundler/bundler/plugin/api/source_spec.rb
@@ -51,7 +51,7 @@ RSpec.describe Bundler::Plugin::API::Source do
context "to_lock" do
it "returns the string with remote and type" do
- expected = strip_whitespace <<-L
+ expected = <<~L
PLUGIN SOURCE
remote: #{uri}
type: #{type}
@@ -67,7 +67,7 @@ RSpec.describe Bundler::Plugin::API::Source do
end
it "includes them" do
- expected = strip_whitespace <<-L
+ expected = <<~L
PLUGIN SOURCE
remote: #{uri}
type: #{type}
diff --git a/spec/bundler/bundler/plugin/dsl_spec.rb b/spec/bundler/bundler/plugin/dsl_spec.rb
index 00e39dca69..235a549735 100644
--- a/spec/bundler/bundler/plugin/dsl_spec.rb
+++ b/spec/bundler/bundler/plugin/dsl_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe Bundler::Plugin::DSL do
it "adds #source with :type to list and also inferred_plugins list" do
expect(dsl).to receive(:plugin).with("bundler-source-news").once
- dsl.source("some_random_url", :type => "news") {}
+ dsl.source("some_random_url", type: "news") {}
expect(dsl.inferred_plugins).to eq(["bundler-source-news"])
end
@@ -31,8 +31,8 @@ RSpec.describe Bundler::Plugin::DSL 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") {}
- dsl.source("another_random_url", :type => "news") {}
+ dsl.source("some_random_url", type: "news") {}
+ dsl.source("another_random_url", type: "news") {}
end
end
end
diff --git a/spec/bundler/bundler/plugin/index_spec.rb b/spec/bundler/bundler/plugin/index_spec.rb
index d34b0de342..5a7047459f 100644
--- a/spec/bundler/bundler/plugin/index_spec.rb
+++ b/spec/bundler/bundler/plugin/index_spec.rb
@@ -140,7 +140,7 @@ RSpec.describe Bundler::Plugin::Index do
describe "after conflict" do
let(:commands) { ["foo"] }
let(:sources) { ["bar"] }
- let(:hooks) { ["hoook"] }
+ let(:hooks) { ["thehook"] }
shared_examples "it cleans up" do
it "the path" do
@@ -156,7 +156,7 @@ RSpec.describe Bundler::Plugin::Index do
end
it "the hook" do
- expect(index.hook_plugins("xhoook")).to be_empty
+ expect(index.hook_plugins("xthehook")).to be_empty
end
end
@@ -164,7 +164,7 @@ RSpec.describe Bundler::Plugin::Index do
before do
expect do
path = lib_path("cplugin")
- index.register_plugin("cplugin", path.to_s, [path.join("lib").to_s], ["foo"], ["xbar"], ["xhoook"])
+ index.register_plugin("cplugin", path.to_s, [path.join("lib").to_s], ["foo"], ["xbar"], ["xthehook"])
end.to raise_error(Index::CommandConflict)
end
@@ -175,7 +175,7 @@ RSpec.describe Bundler::Plugin::Index do
before do
expect do
path = lib_path("cplugin")
- index.register_plugin("cplugin", path.to_s, [path.join("lib").to_s], ["xfoo"], ["bar"], ["xhoook"])
+ index.register_plugin("cplugin", path.to_s, [path.join("lib").to_s], ["xfoo"], ["bar"], ["xthehook"])
end.to raise_error(Index::SourceConflict)
end
@@ -186,7 +186,7 @@ RSpec.describe Bundler::Plugin::Index do
before do
expect do
path = lib_path("cplugin")
- index.register_plugin("cplugin", path.to_s, [path.join("lib").to_s], ["foo"], ["bar"], ["xhoook"])
+ index.register_plugin("cplugin", path.to_s, [path.join("lib").to_s], ["foo"], ["bar"], ["xthehook"])
end.to raise_error(Index::CommandConflict)
end
diff --git a/spec/bundler/bundler/plugin/installer_spec.rb b/spec/bundler/bundler/plugin/installer_spec.rb
index e89720f6f7..ed40029f5a 100644
--- a/spec/bundler/bundler/plugin/installer_spec.rb
+++ b/spec/bundler/bundler/plugin/installer_spec.rb
@@ -6,8 +6,7 @@ RSpec.describe Bundler::Plugin::Installer do
describe "cli install" do
it "uses Gem.sources when non of the source is provided" do
sources = double(:sources)
- Bundler.settings # initialize it before we have to touch rubygems.ext_lock
- allow(Bundler).to receive_message_chain("rubygems.sources") { sources }
+ allow(Gem).to receive(:sources) { sources }
allow(installer).to receive(:install_rubygems).
with("new-plugin", [">= 0"], sources).once
@@ -21,15 +20,15 @@ RSpec.describe Bundler::Plugin::Installer do
allow(installer).to receive(:install_git).
and_return("new-plugin" => spec)
- expect(installer.install(["new-plugin"], :git => "https://some.ran/dom")).
+ expect(installer.install(["new-plugin"], git: "https://some.ran/dom")).
to eq("new-plugin" => spec)
end
it "returns the installed spec after installing local git plugins" do
- allow(installer).to receive(:install_local_git).
+ allow(installer).to receive(:install_git).
and_return("new-plugin" => spec)
- expect(installer.install(["new-plugin"], :local_git => "/phony/path/repo")).
+ expect(installer.install(["new-plugin"], git: "/phony/path/repo")).
to eq("new-plugin" => spec)
end
@@ -37,7 +36,7 @@ RSpec.describe Bundler::Plugin::Installer do
allow(installer).to receive(:install_rubygems).
and_return("new-plugin" => spec)
- expect(installer.install(["new-plugin"], :source => "https://some.ran/dom")).
+ expect(installer.install(["new-plugin"], source: "https://some.ran/dom")).
to eq("new-plugin" => spec)
end
end
@@ -52,13 +51,13 @@ RSpec.describe Bundler::Plugin::Installer do
context "git plugins" do
before do
- build_git "ga-plugin", :path => lib_path("ga-plugin") do |s|
+ build_git "ga-plugin", path: lib_path("ga-plugin") do |s|
s.write "plugins.rb"
end
end
let(:result) do
- installer.install(["ga-plugin"], :git => file_uri_for(lib_path("ga-plugin")))
+ installer.install(["ga-plugin"], git: file_uri_for(lib_path("ga-plugin")))
end
it "returns the installed spec after installing" do
@@ -75,13 +74,13 @@ RSpec.describe Bundler::Plugin::Installer do
context "local git plugins" do
before do
- build_git "ga-plugin", :path => lib_path("ga-plugin") do |s|
+ build_git "ga-plugin", path: lib_path("ga-plugin") do |s|
s.write "plugins.rb"
end
end
let(:result) do
- installer.install(["ga-plugin"], :local_git => lib_path("ga-plugin").to_s)
+ installer.install(["ga-plugin"], git: lib_path("ga-plugin").to_s)
end
it "returns the installed spec after installing" do
@@ -98,7 +97,7 @@ RSpec.describe Bundler::Plugin::Installer do
context "rubygems plugins" do
let(:result) do
- installer.install(["re-plugin"], :source => file_uri_for(gem_repo2))
+ installer.install(["re-plugin"], source: file_uri_for(gem_repo2))
end
it "returns the installed spec after installing " do
@@ -113,7 +112,7 @@ RSpec.describe Bundler::Plugin::Installer do
context "multiple plugins" do
let(:result) do
- installer.install(["re-plugin", "ma-plugin"], :source => file_uri_for(gem_repo2))
+ installer.install(["re-plugin", "ma-plugin"], source: file_uri_for(gem_repo2))
end
it "returns the installed spec after installing " do
diff --git a/spec/bundler/bundler/plugin_spec.rb b/spec/bundler/bundler/plugin_spec.rb
index d1a05bbad7..f41b4eff3a 100644
--- a/spec/bundler/bundler/plugin_spec.rb
+++ b/spec/bundler/bundler/plugin_spec.rb
@@ -9,11 +9,11 @@ RSpec.describe Bundler::Plugin do
let(:spec2) { double(:spec2) }
before do
- build_lib "new-plugin", :path => lib_path("new-plugin") do |s|
+ build_lib "new-plugin", path: lib_path("new-plugin") do |s|
s.write "plugins.rb"
end
- build_lib "another-plugin", :path => lib_path("another-plugin") do |s|
+ build_lib "another-plugin", path: lib_path("another-plugin") do |s|
s.write "plugins.rb"
end
@@ -65,6 +65,8 @@ RSpec.describe Bundler::Plugin do
end
it "passes the name and options to installer" do
+ allow(index).to receive(:installed?).
+ with("new-plugin")
allow(installer).to receive(:install).with(["new-plugin"], opts) do
{ "new-plugin" => spec }
end.once
@@ -73,6 +75,8 @@ RSpec.describe Bundler::Plugin do
end
it "validates the installed plugin" do
+ allow(index).to receive(:installed?).
+ with("new-plugin")
allow(subject).
to receive(:validate_plugin!).with(lib_path("new-plugin")).once
@@ -80,6 +84,8 @@ RSpec.describe Bundler::Plugin do
end
it "registers the plugin with index" do
+ allow(index).to receive(:installed?).
+ with("new-plugin")
allow(index).to receive(:register_plugin).
with("new-plugin", lib_path("new-plugin").to_s, [lib_path("new-plugin").join("lib").to_s], []).once
subject.install ["new-plugin"], opts
@@ -96,6 +102,7 @@ RSpec.describe Bundler::Plugin do
end.once
allow(subject).to receive(:validate_plugin!).twice
+ allow(index).to receive(:installed?).twice
allow(index).to receive(:register_plugin).twice
subject.install ["new-plugin", "another-plugin"], opts
end
@@ -218,7 +225,7 @@ RSpec.describe Bundler::Plugin do
end
end
- describe "#source_from_lock" do
+ describe "#from_lock" do
it "returns instance of registered class initialized with locked opts" do
opts = { "type" => "l_source", "remote" => "xyz", "other" => "random" }
allow(index).to receive(:source_plugin).with("l_source") { "plugin_name" }
@@ -229,7 +236,7 @@ RSpec.describe Bundler::Plugin do
expect(SClass).to receive(:new).
with(hash_including("type" => "l_source", "uri" => "xyz", "other" => "random")) { s_instance }
- expect(subject.source_from_lock(opts)).to be(s_instance)
+ expect(subject.from_lock(opts)).to be(s_instance)
end
end
@@ -268,17 +275,17 @@ RSpec.describe Bundler::Plugin do
describe "#hook" do
before do
path = lib_path("foo-plugin")
- build_lib "foo-plugin", :path => path do |s|
+ build_lib "foo-plugin", path: path do |s|
s.write "plugins.rb", code
end
Bundler::Plugin::Events.send(:reset)
- Bundler::Plugin::Events.send(:define, :EVENT_1, "event-1")
- Bundler::Plugin::Events.send(:define, :EVENT_2, "event-2")
+ Bundler::Plugin::Events.send(:define, :EVENT1, "event-1")
+ Bundler::Plugin::Events.send(:define, :EVENT2, "event-2")
- allow(index).to receive(:hook_plugins).with(Bundler::Plugin::Events::EVENT_1).
+ allow(index).to receive(:hook_plugins).with(Bundler::Plugin::Events::EVENT1).
and_return(["foo-plugin", "", nil])
- allow(index).to receive(:hook_plugins).with(Bundler::Plugin::Events::EVENT_2).
+ allow(index).to receive(:hook_plugins).with(Bundler::Plugin::Events::EVENT2).
and_return(["foo-plugin"])
allow(index).to receive(:plugin_path).with("foo-plugin").and_return(path)
allow(index).to receive(:load_paths).with("foo-plugin").and_return([])
@@ -296,33 +303,33 @@ RSpec.describe Bundler::Plugin do
it "executes the hook" do
expect do
- Plugin.hook(Bundler::Plugin::Events::EVENT_1)
+ Plugin.hook(Bundler::Plugin::Events::EVENT1)
end.to output("hook for event 1\n").to_stdout
end
context "single plugin declaring more than one hook" do
let(:code) { <<-RUBY }
- Bundler::Plugin::API.hook(Bundler::Plugin::Events::EVENT_1) {}
- Bundler::Plugin::API.hook(Bundler::Plugin::Events::EVENT_2) {}
+ Bundler::Plugin::API.hook(Bundler::Plugin::Events::EVENT1) {}
+ Bundler::Plugin::API.hook(Bundler::Plugin::Events::EVENT2) {}
puts "loaded"
RUBY
it "evals plugins.rb once" do
expect do
- Plugin.hook(Bundler::Plugin::Events::EVENT_1)
- Plugin.hook(Bundler::Plugin::Events::EVENT_2)
+ Plugin.hook(Bundler::Plugin::Events::EVENT1)
+ Plugin.hook(Bundler::Plugin::Events::EVENT2)
end.to output("loaded\n").to_stdout
end
end
context "a block is passed" do
let(:code) { <<-RUBY }
- Bundler::Plugin::API.hook(Bundler::Plugin::Events::EVENT_1) { |&blk| blk.call }
+ Bundler::Plugin::API.hook(Bundler::Plugin::Events::EVENT1) { |&blk| blk.call }
RUBY
it "is passed to the hook" do
expect do
- Plugin.hook(Bundler::Plugin::Events::EVENT_1) { puts "win" }
+ Plugin.hook(Bundler::Plugin::Events::EVENT1) { puts "win" }
end.to output("win\n").to_stdout
end
end
diff --git a/spec/bundler/bundler/psyched_yaml_spec.rb b/spec/bundler/bundler/psyched_yaml_spec.rb
deleted file mode 100644
index d5d68c5cc3..0000000000
--- a/spec/bundler/bundler/psyched_yaml_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-
-require "bundler/psyched_yaml"
-
-RSpec.describe "Bundler::YamlLibrarySyntaxError" do
- it "is raised on YAML parse errors" do
- expect { YAML.parse "{foo" }.to raise_error(Bundler::YamlLibrarySyntaxError)
- end
-end
diff --git a/spec/bundler/bundler/remote_specification_spec.rb b/spec/bundler/bundler/remote_specification_spec.rb
index 8115e026d8..f35b231d58 100644
--- a/spec/bundler/bundler/remote_specification_spec.rb
+++ b/spec/bundler/bundler/remote_specification_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe Bundler::RemoteSpecification do
end
describe "#fetch_platform" do
- let(:remote_spec) { double(:remote_spec, :platform => "jruby") }
+ let(:remote_spec) { double(:remote_spec, platform: "jruby") }
before { allow(spec_fetcher).to receive(:fetch_spec).and_return(remote_spec) }
@@ -45,7 +45,7 @@ RSpec.describe Bundler::RemoteSpecification do
let(:platform) { "jruby" }
it "should return the spec name, version, and platform" do
- expect(subject.full_name).to eq("foo-1.0.0-jruby")
+ expect(subject.full_name).to eq("foo-1.0.0-java")
end
end
end
@@ -113,7 +113,7 @@ RSpec.describe Bundler::RemoteSpecification do
context "comparing a non sortable object" do
let(:other) { Object.new }
- let(:remote_spec) { double(:remote_spec, :platform => "jruby") }
+ let(:remote_spec) { double(:remote_spec, platform: "jruby") }
before do
allow(spec_fetcher).to receive(:fetch_spec).and_return(remote_spec)
@@ -127,8 +127,8 @@ RSpec.describe Bundler::RemoteSpecification do
end
describe "#__swap__" do
- let(:spec) { double(:spec, :dependencies => []) }
- let(:new_spec) { double(:new_spec, :dependencies => [], :runtime_dependencies => []) }
+ let(:spec) { double(:spec, dependencies: []) }
+ let(:new_spec) { double(:new_spec, dependencies: [], runtime_dependencies: []) }
before { subject.instance_variable_set(:@_remote_specification, spec) }
@@ -157,7 +157,7 @@ RSpec.describe Bundler::RemoteSpecification do
describe "method missing" do
context "and is present in Gem::Specification" do
- let(:remote_spec) { double(:remote_spec, :authors => "abcd") }
+ let(:remote_spec) { double(:remote_spec, authors: "abcd") }
before do
allow(subject).to receive(:_remote_specification).and_return(remote_spec)
@@ -172,7 +172,7 @@ RSpec.describe Bundler::RemoteSpecification do
describe "respond to missing?" do
context "and is present in Gem::Specification" do
- let(:remote_spec) { double(:remote_spec, :authors => "abcd") }
+ let(:remote_spec) { double(:remote_spec, authors: "abcd") }
before do
allow(subject).to receive(:_remote_specification).and_return(remote_spec)
diff --git a/spec/bundler/bundler/resolver/candidate_spec.rb b/spec/bundler/bundler/resolver/candidate_spec.rb
new file mode 100644
index 0000000000..f7b378d32b
--- /dev/null
+++ b/spec/bundler/bundler/resolver/candidate_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+RSpec.describe Bundler::Resolver::Candidate do
+ it "compares fine" do
+ version1 = described_class.new("1.12.5", specs: [Gem::Specification.new("foo", "1.12.5") {|s| s.platform = Gem::Platform::RUBY }])
+ version2 = described_class.new("1.12.5") # passing no specs creates a platform specific candidate, so sorts higher
+
+ expect(version2 >= version1).to be true
+
+ expect(version1.generic! == version2.generic!).to be true
+ expect(version1.platform_specific! == version2.platform_specific!).to be true
+
+ expect(version1.platform_specific! >= version2.generic!).to be true
+ expect(version2.platform_specific! >= version1.generic!).to be true
+
+ version1 = described_class.new("1.12.5", specs: [Gem::Specification.new("foo", "1.12.5") {|s| s.platform = Gem::Platform::RUBY }])
+ version2 = described_class.new("1.12.5", specs: [Gem::Specification.new("foo", "1.12.5") {|s| s.platform = Gem::Platform::X64_LINUX }])
+
+ expect(version2 >= version1).to be true
+ end
+end
diff --git a/spec/bundler/bundler/ruby_dsl_spec.rb b/spec/bundler/bundler/ruby_dsl_spec.rb
index bc1ca98457..384ac4b8b2 100644
--- a/spec/bundler/bundler/ruby_dsl_spec.rb
+++ b/spec/bundler/bundler/ruby_dsl_spec.rb
@@ -7,28 +7,37 @@ RSpec.describe Bundler::RubyDsl do
include Bundler::RubyDsl
attr_reader :ruby_version
+ attr_accessor :gemfile
end
let(:dsl) { MockDSL.new }
let(:ruby_version) { "2.0.0" }
+ let(:ruby_version_arg) { ruby_version }
let(:version) { "2.0.0" }
let(:engine) { "jruby" }
let(:engine_version) { "9000" }
let(:patchlevel) { "100" }
let(:options) do
- { :patchlevel => patchlevel,
- :engine => engine,
- :engine_version => engine_version }
+ { patchlevel: patchlevel,
+ engine: engine,
+ engine_version: engine_version }
end
+ let(:project_root) { Pathname.new("/path/to/project") }
+ let(:gemfile) { project_root.join("Gemfile") }
+ before { allow(Bundler).to receive(:root).and_return(project_root) }
let(:invoke) do
proc do
- args = Array(ruby_version) + [options]
+ args = []
+ args << ruby_version_arg if ruby_version_arg
+ args << options
+
dsl.ruby(*args)
end
end
subject do
+ dsl.gemfile = gemfile
invoke.call
dsl.ruby_version
end
@@ -59,6 +68,15 @@ RSpec.describe Bundler::RubyDsl do
it_behaves_like "it stores the ruby version"
end
+ context "with a preview version" do
+ let(:ruby_version) { "3.3.0-preview2" }
+
+ it "stores the version" do
+ expect(subject.versions).to eq(Array("3.3.0.preview2"))
+ expect(subject.gem_version.version).to eq("3.3.0.preview2")
+ end
+ end
+
context "with two requirements in the same string" do
let(:ruby_version) { ">= 2.0.0, < 3.0" }
it "raises an error" do
@@ -91,5 +109,94 @@ RSpec.describe Bundler::RubyDsl do
it_behaves_like "it stores the ruby version"
end
end
+
+ context "with a file option" do
+ let(:file) { ".ruby-version" }
+ let(:ruby_version_file_path) { gemfile.dirname.join(file) }
+ let(:options) do
+ { file: file,
+ patchlevel: patchlevel,
+ engine: engine,
+ engine_version: engine_version }
+ end
+ let(:ruby_version_arg) { nil }
+ let(:file_content) { "#{version}\n" }
+
+ before do
+ allow(Bundler).to receive(:read_file) do |path|
+ raise Errno::ENOENT, <<~ERROR unless path == ruby_version_file_path
+ #{file} not found in specs:
+ expected: #{ruby_version_file_path}
+ received: #{path}
+ ERROR
+ file_content
+ end
+ end
+
+ it_behaves_like "it stores the ruby version"
+
+ context "with the Gemfile ruby file: path is relative to the Gemfile in a subdir" do
+ let(:gemfile) { project_root.join("subdir", "Gemfile") }
+ let(:file) { "../.ruby-version" }
+ let(:ruby_version_file_path) { gemfile.dirname.join(file) }
+
+ it_behaves_like "it stores the ruby version"
+ end
+
+ context "with bundler root in a subdir of the project" do
+ let(:project_root) { Pathname.new("/path/to/project/subdir") }
+ let(:gemfile) { project_root.parent.join("Gemfile") }
+
+ it_behaves_like "it stores the ruby version"
+ end
+
+ context "with the ruby- prefix in the file" do
+ let(:file_content) { "ruby-#{version}\n" }
+
+ it_behaves_like "it stores the ruby version"
+ end
+
+ context "and a version" do
+ let(:ruby_version_arg) { version }
+
+ it "raises an error" do
+ expect { subject }.to raise_error(Bundler::GemfileError, "Do not pass version argument when using :file option")
+ end
+ end
+
+ context "with a @gemset" do
+ let(:file_content) { "ruby-#{version}@gemset\n" }
+
+ it "raises an error" do
+ expect { subject }.to raise_error(Gem::Requirement::BadRequirementError, "Illformed requirement [\"#{version}@gemset\"]")
+ end
+ end
+
+ context "with a .tool-versions file format" do
+ let(:file) { ".tool-versions" }
+ let(:ruby_version_arg) { nil }
+ let(:file_content) do
+ <<~TOOLS
+ nodejs 18.16.0
+ ruby #{version} # This is a comment
+ pnpm 8.6.12
+ TOOLS
+ end
+
+ it_behaves_like "it stores the ruby version"
+
+ context "with extra spaces and a very cozy comment" do
+ let(:file_content) do
+ <<~TOOLS
+ nodejs 18.16.0
+ ruby #{version}# This is a cozy comment
+ pnpm 8.6.12
+ TOOLS
+ end
+
+ it_behaves_like "it stores the ruby version"
+ end
+ end
+ end
end
end
diff --git a/spec/bundler/bundler/ruby_version_spec.rb b/spec/bundler/bundler/ruby_version_spec.rb
index 8c6c071d7f..39d0571361 100644
--- a/spec/bundler/bundler/ruby_version_spec.rb
+++ b/spec/bundler/bundler/ruby_version_spec.rb
@@ -400,19 +400,19 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
let(:bundler_system_ruby_version) { subject }
around do |example|
- if Bundler::RubyVersion.instance_variable_defined?("@ruby_version")
+ if Bundler::RubyVersion.instance_variable_defined?("@system")
begin
- old_ruby_version = Bundler::RubyVersion.instance_variable_get("@ruby_version")
- Bundler::RubyVersion.remove_instance_variable("@ruby_version")
+ old_ruby_version = Bundler::RubyVersion.instance_variable_get("@system")
+ Bundler::RubyVersion.remove_instance_variable("@system")
example.run
ensure
- Bundler::RubyVersion.instance_variable_set("@ruby_version", old_ruby_version)
+ Bundler::RubyVersion.instance_variable_set("@system", old_ruby_version)
end
else
begin
example.run
ensure
- Bundler::RubyVersion.remove_instance_variable("@ruby_version")
+ Bundler::RubyVersion.remove_instance_variable("@system")
end
end
end
@@ -427,9 +427,8 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
end
describe "#version" do
- it "should return a copy of the value of RUBY_VERSION" do
- expect(subject.versions).to eq([RUBY_VERSION])
- expect(subject.versions.first).to_not be(RUBY_VERSION)
+ it "should return the value of Gem.ruby_version as a string" do
+ expect(subject.versions).to eq([Gem.ruby_version.to_s])
end
end
@@ -446,13 +445,12 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
describe "#engine_version" do
context "engine is ruby" do
before do
- stub_const("RUBY_ENGINE_VERSION", "2.2.4")
+ allow(Gem).to receive(:ruby_version).and_return(Gem::Version.new("2.2.4"))
stub_const("RUBY_ENGINE", "ruby")
end
- it "should return a copy of the value of RUBY_ENGINE_VERSION" do
+ it "should return the value of Gem.ruby_version as a string" do
expect(bundler_system_ruby_version.engine_versions).to eq(["2.2.4"])
- expect(bundler_system_ruby_version.engine_versions.first).to_not be(RUBY_ENGINE_VERSION)
end
end
@@ -498,31 +496,5 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
end
end
end
-
- describe "#to_gem_version_with_patchlevel" do
- shared_examples_for "the patchlevel is omitted" do
- it "does not include a patch level" do
- expect(subject.to_gem_version_with_patchlevel.to_s).to eq(version)
- end
- end
-
- context "with nil patch number" do
- let(:patchlevel) { nil }
-
- it_behaves_like "the patchlevel is omitted"
- end
-
- context "with negative patch number" do
- let(:patchlevel) { -1 }
-
- it_behaves_like "the patchlevel is omitted"
- end
-
- context "with a valid patch number" do
- it "uses the specified patchlevel as patchlevel" do
- expect(subject.to_gem_version_with_patchlevel.to_s).to eq("#{version}.#{patchlevel}")
- end
- end
- end
end
end
diff --git a/spec/bundler/bundler/rubygems_integration_spec.rb b/spec/bundler/bundler/rubygems_integration_spec.rb
index 11fa2f4e0d..b6bda9f43e 100644
--- a/spec/bundler/bundler/rubygems_integration_spec.rb
+++ b/spec/bundler/bundler/rubygems_integration_spec.rb
@@ -1,10 +1,6 @@
# frozen_string_literal: true
RSpec.describe Bundler::RubygemsIntegration do
- it "uses the same chdir lock as rubygems" do
- expect(Bundler.rubygems.ext_lock).to eq(Gem::Ext::Builder::CHDIR_MONITOR)
- end
-
context "#validate" do
let(:spec) do
Gem::Specification.new do |s|
@@ -34,35 +30,24 @@ RSpec.describe Bundler::RubygemsIntegration do
end
end
- describe "#configuration" do
- it "handles Gem::SystemExitException errors" do
- allow(Gem).to receive(:configuration) { raise Gem::SystemExitException.new(1) }
- expect { Bundler.rubygems.configuration }.to raise_error(Gem::SystemExitException)
- end
- end
-
describe "#download_gem" do
let(:bundler_retry) { double(Bundler::Retry) }
- let(:retry) { double("Bundler::Retry") }
- let(:uri) { Bundler::URI.parse("https://foo.bar") }
- let(:path) { Gem.path.first }
+ let(:uri) { Gem::URI.parse("https://foo.bar") }
+ let(:cache_dir) { "#{Gem.path.first}/cache" }
let(:spec) do
- spec = Bundler::RemoteSpecification.new("Foo", Gem::Version.new("2.5.2"),
- Gem::Platform::RUBY, nil)
+ spec = Gem::Specification.new("Foo", Gem::Version.new("2.5.2"))
spec.remote = Bundler::Source::Rubygems::Remote.new(uri.to_s)
spec
end
let(:fetcher) { double("gem_remote_fetcher") }
it "successfully downloads gem with retries" do
- expect(Bundler.rubygems).to receive(:gem_remote_fetcher).and_return(fetcher)
- expect(fetcher).to receive(:headers=).with("X-Gemfile-Source" => "https://foo.bar")
expect(Bundler::Retry).to receive(:new).with("download gem from #{uri}/").
and_return(bundler_retry)
expect(bundler_retry).to receive(:attempts).and_yield
- expect(fetcher).to receive(:download).with(spec, uri, path)
+ expect(fetcher).to receive(:cache_update_path)
- Bundler.rubygems.download_gem(spec, uri, path)
+ Bundler.rubygems.download_gem(spec, uri, cache_dir, fetcher)
end
end
@@ -73,30 +58,36 @@ RSpec.describe Bundler::RubygemsIntegration do
let(:prerelease_specs_response) { Marshal.dump(["prerelease_specs"]) }
context "when a rubygems source mirror is set" do
- let(:orig_uri) { Bundler::URI("http://zombo.com") }
- let(:remote_with_mirror) { double("remote", :uri => uri, :original_uri => orig_uri) }
+ let(:orig_uri) { Gem::URI("http://zombo.com") }
+ let(:remote_with_mirror) { double("remote", uri: uri, original_uri: orig_uri) }
it "sets the 'X-Gemfile-Source' header containing the original source" do
- expect(Bundler.rubygems).to receive(:gem_remote_fetcher).twice.and_return(fetcher)
- expect(fetcher).to receive(:headers=).with("X-Gemfile-Source" => "http://zombo.com").twice
expect(fetcher).to receive(:fetch_path).with(uri + "specs.4.8.gz").and_return(specs_response)
expect(fetcher).to receive(:fetch_path).with(uri + "prerelease_specs.4.8.gz").and_return(prerelease_specs_response)
- result = Bundler.rubygems.fetch_all_remote_specs(remote_with_mirror)
+ result = Bundler.rubygems.fetch_all_remote_specs(remote_with_mirror, fetcher)
expect(result).to eq(%w[specs prerelease_specs])
end
end
context "when there is no rubygems source mirror set" do
- let(:remote_no_mirror) { double("remote", :uri => uri, :original_uri => nil) }
+ let(:remote_no_mirror) { double("remote", uri: uri, original_uri: nil) }
it "does not set the 'X-Gemfile-Source' header" do
- expect(Bundler.rubygems).to receive(:gem_remote_fetcher).twice.and_return(fetcher)
- expect(fetcher).to_not receive(:headers=)
expect(fetcher).to receive(:fetch_path).with(uri + "specs.4.8.gz").and_return(specs_response)
expect(fetcher).to receive(:fetch_path).with(uri + "prerelease_specs.4.8.gz").and_return(prerelease_specs_response)
- result = Bundler.rubygems.fetch_all_remote_specs(remote_no_mirror)
+ result = Bundler.rubygems.fetch_all_remote_specs(remote_no_mirror, fetcher)
expect(result).to eq(%w[specs prerelease_specs])
end
end
+
+ context "when loading an unexpected class" do
+ let(:remote_no_mirror) { double("remote", uri: uri, original_uri: nil) }
+ let(:unexpected_specs_response) { Marshal.dump(3) }
+
+ it "raises a MarshalError error" do
+ expect(fetcher).to receive(:fetch_path).with(uri + "specs.4.8.gz").and_return(unexpected_specs_response)
+ expect { Bundler.rubygems.fetch_all_remote_specs(remote_no_mirror, fetcher) }.to raise_error(Bundler::MarshalError, /unexpected class/i)
+ end
+ end
end
end
diff --git a/spec/bundler/bundler/settings/validator_spec.rb b/spec/bundler/bundler/settings/validator_spec.rb
index e4ffd89435..b252ba59a0 100644
--- a/spec/bundler/bundler/settings/validator_spec.rb
+++ b/spec/bundler/bundler/settings/validator_spec.rb
@@ -44,14 +44,14 @@ RSpec.describe Bundler::Settings::Validator do
validate!("without", "b:c", "BUNDLE_WITH" => "a")
end.not_to raise_error
- expect { validate!("with", "b:c", "BUNDLE_WITHOUT" => "c:d") }.to raise_error Bundler::InvalidOption, strip_whitespace(<<-EOS).strip
+ expect { validate!("with", "b:c", "BUNDLE_WITHOUT" => "c:d") }.to raise_error Bundler::InvalidOption, <<~EOS.strip
Setting `with` to "b:c" failed:
- a group cannot be in both `with` & `without` simultaneously
- `without` is current set to [:c, :d]
- the `c` groups conflict
EOS
- expect { validate!("without", "b:c", "BUNDLE_WITH" => "c:d") }.to raise_error Bundler::InvalidOption, strip_whitespace(<<-EOS).strip
+ expect { validate!("without", "b:c", "BUNDLE_WITH" => "c:d") }.to raise_error Bundler::InvalidOption, <<~EOS.strip
Setting `without` to "b:c" failed:
- a group cannot be in both `with` & `without` simultaneously
- `with` is current set to [:c, :d]
@@ -74,7 +74,7 @@ RSpec.describe Bundler::Settings::Validator do
describe "#fail!" do
it "raises with a helpful message" do
- expect { subject.fail!("key", "value", "reason1", "reason2") }.to raise_error Bundler::InvalidOption, strip_whitespace(<<-EOS).strip
+ expect { subject.fail!("key", "value", "reason1", "reason2") }.to raise_error Bundler::InvalidOption, <<~EOS.strip
Setting `key` to "value" failed:
- rule description
- reason1
diff --git a/spec/bundler/bundler/settings_spec.rb b/spec/bundler/bundler/settings_spec.rb
index 24e3de7ba8..634e0faf91 100644
--- a/spec/bundler/bundler/settings_spec.rb
+++ b/spec/bundler/bundler/settings_spec.rb
@@ -27,7 +27,7 @@ RSpec.describe Bundler::Settings do
"gem.mit" => "false",
"gem.test" => "minitest",
"thingy" => <<-EOS.tr("\n", " "),
---asdf --fdsa --ty=oh man i hope this doesnt break bundler because
+--asdf --fdsa --ty=oh man i hope this doesn't break bundler because
that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
--very-important-option=DontDeleteRoo
--very-important-option=DontDeleteRoo
@@ -131,7 +131,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
Bundler.settings.set_command_option :no_install, true
- Bundler.settings.temporary(:no_install => false) do
+ Bundler.settings.temporary(no_install: false) do
expect(Bundler.settings[:no_install]).to eq false
end
@@ -147,12 +147,12 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
context "when called without a block" do
it "leaves the setting changed" do
- Bundler.settings.temporary(:foo => :random)
+ Bundler.settings.temporary(foo: :random)
expect(Bundler.settings[:foo]).to eq "random"
end
it "returns nil" do
- expect(Bundler.settings.temporary(:foo => :bar)).to be_nil
+ expect(Bundler.settings.temporary(foo: :bar)).to be_nil
end
end
end
@@ -179,7 +179,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
end
describe "#mirror_for" do
- let(:uri) { Bundler::URI("https://rubygems.org/") }
+ let(:uri) { Gem::URI("https://rubygems.org/") }
context "with no configured mirror" do
it "returns the original URI" do
@@ -192,7 +192,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
end
context "with a configured mirror" do
- let(:mirror_uri) { Bundler::URI("https://rubygems-mirror.org/") }
+ let(:mirror_uri) { Gem::URI("https://rubygems-mirror.org/") }
before { settings.set_local "mirror.https://rubygems.org/", mirror_uri.to_s }
@@ -213,7 +213,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
end
context "with a file URI" do
- let(:mirror_uri) { Bundler::URI("file:/foo/BAR/baz/qUx/") }
+ let(:mirror_uri) { Gem::URI("file:/foo/BAR/baz/qUx/") }
it "returns the mirror URI" do
expect(settings.mirror_for(uri)).to eq(mirror_uri)
@@ -231,7 +231,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
end
describe "#credentials_for" do
- let(:uri) { Bundler::URI("https://gemserver.example.org/") }
+ let(:uri) { Gem::URI("https://gemserver.example.org/") }
let(:credentials) { "username:password" }
context "with no configured credentials" do
@@ -291,7 +291,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
it "reads older keys without trailing slashes" do
settings.set_local "mirror.https://rubygems.org", "http://rubygems-mirror.org"
expect(settings.mirror_for("https://rubygems.org/")).to eq(
- Bundler::URI("http://rubygems-mirror.org/")
+ Gem::URI("http://rubygems-mirror.org/")
)
end
@@ -319,6 +319,15 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
expect(settings["mirror.https://rubygems.org/"]).to eq("http://rubygems-mirror.org")
end
+ it "ignores commented out keys" do
+ create_file bundled_app(".bundle/config"), <<~C
+ # BUNDLE_MY-PERSONAL-SERVER__ORG: my-personal-server.org
+ C
+
+ expect(Bundler.ui).not_to receive(:warn)
+ expect(settings.all).to be_empty
+ end
+
it "converts older keys with dashes" do
config("BUNDLE_MY-PERSONAL-SERVER__ORG" => "my-personal-server.org")
expect(Bundler.ui).to receive(:warn).with(
diff --git a/spec/bundler/bundler/shared_helpers_spec.rb b/spec/bundler/bundler/shared_helpers_spec.rb
index 68a24be31c..918f73b337 100644
--- a/spec/bundler/bundler/shared_helpers_spec.rb
+++ b/spec/bundler/bundler/shared_helpers_spec.rb
@@ -1,12 +1,8 @@
# frozen_string_literal: true
RSpec.describe Bundler::SharedHelpers do
- let(:ext_lock_double) { double(:ext_lock) }
-
before do
pwd_stub
- allow(Bundler.rubygems).to receive(:ext_lock).and_return(ext_lock_double)
- allow(ext_lock_double).to receive(:synchronize) {|&block| block.call }
end
let(:pwd_stub) { allow(subject).to receive(:pwd).and_return(bundled_app) }
@@ -242,7 +238,14 @@ RSpec.describe Bundler::SharedHelpers do
shared_examples_for "ENV['RUBYOPT'] gets set correctly" do
it "ensures -rbundler/setup is at the beginning of ENV['RUBYOPT']" do
subject.set_bundle_environment
- expect(ENV["RUBYOPT"].split(" ")).to start_with("-r#{source_lib_dir}/bundler/setup")
+ expect(ENV["RUBYOPT"].split(" ")).to start_with("-r#{install_path}/bundler/setup")
+ end
+ end
+
+ shared_examples_for "ENV['BUNDLER_SETUP'] gets set correctly" do
+ it "ensures bundler/setup is set in ENV['BUNDLER_SETUP']" do
+ subject.set_bundle_environment
+ expect(ENV["BUNDLER_SETUP"]).to eq("#{source_lib_dir}/bundler/setup")
end
end
@@ -281,7 +284,7 @@ RSpec.describe Bundler::SharedHelpers do
if Gem.respond_to?(:path_separator)
allow(Gem).to receive(:path_separator).and_return(":")
else
- stub_const("File::PATH_SEPARATOR", ":".freeze)
+ stub_const("File::PATH_SEPARATOR", ":")
end
allow(Bundler).to receive(:bundle_path) { Pathname.new("so:me/dir/bin") }
expect { subject.send(:validate_bundle_path) }.to raise_error(
@@ -358,20 +361,41 @@ RSpec.describe Bundler::SharedHelpers do
end
end
- context "ENV['RUBYOPT'] does not exist" do
- before { ENV.delete("RUBYOPT") }
+ context "when bundler install path is standard" do
+ let(:install_path) { source_lib_dir }
- it_behaves_like "ENV['RUBYOPT'] gets set correctly"
- end
+ context "ENV['RUBYOPT'] does not exist" do
+ before { ENV.delete("RUBYOPT") }
- context "ENV['RUBYOPT'] exists without -rbundler/setup" do
- before { ENV["RUBYOPT"] = "-I/some_app_path/lib" }
+ it_behaves_like "ENV['RUBYOPT'] gets set correctly"
+ end
- it_behaves_like "ENV['RUBYOPT'] gets set correctly"
+ context "ENV['RUBYOPT'] exists without -rbundler/setup" do
+ before { ENV["RUBYOPT"] = "-I/some_app_path/lib" }
+
+ it_behaves_like "ENV['RUBYOPT'] gets set correctly"
+ end
+
+ context "ENV['RUBYOPT'] exists and contains -rbundler/setup" do
+ before { ENV["RUBYOPT"] = "-rbundler/setup" }
+
+ it_behaves_like "ENV['RUBYOPT'] gets set correctly"
+ end
end
- context "ENV['RUBYOPT'] exists and contains -rbundler/setup" do
- before { ENV["RUBYOPT"] = "-rbundler/setup" }
+ context "when bundler install path contains special characters" do
+ let(:install_path) { "/opt/ruby3.3.0-preview2/lib/ruby/3.3.0+0" }
+
+ before do
+ ENV["RUBYOPT"] = "-r#{install_path}/bundler/setup"
+ allow(File).to receive(:expand_path).and_return("#{install_path}/bundler/setup")
+ allow(Gem).to receive(:bin_path).and_return("#{install_path}/bundler/setup")
+ end
+
+ it "ensures -rbundler/setup is not duplicated" do
+ subject.set_bundle_environment
+ expect(ENV["RUBYOPT"].split(" ").grep(%r{-r.*/bundler/setup}).length).to eq(1)
+ end
it_behaves_like "ENV['RUBYOPT'] gets set correctly"
end
@@ -494,4 +518,34 @@ RSpec.describe Bundler::SharedHelpers do
end
end
end
+
+ describe "#major_deprecation" do
+ before { allow(Bundler).to receive(:bundler_major_version).and_return(37) }
+ before { allow(Bundler.ui).to receive(:warn) }
+
+ it "prints and raises nothing below the deprecated major version" do
+ subject.major_deprecation(38, "Message")
+ subject.major_deprecation(39, "Message", removed_message: "Removal", print_caller_location: true)
+ expect(Bundler.ui).not_to have_received(:warn)
+ end
+
+ it "prints but does not raise _at_ the deprecated major version" do
+ subject.major_deprecation(37, "Message")
+ subject.major_deprecation(37, "Message", removed_message: "Removal")
+ expect(Bundler.ui).to have_received(:warn).with("[DEPRECATED] Message").twice
+
+ subject.major_deprecation(37, "Message", print_caller_location: true)
+ expect(Bundler.ui).to have_received(:warn).
+ with(a_string_matching(/^\[DEPRECATED\] Message \(called at .*:\d+\)$/))
+ end
+
+ it "raises the appropriate errors when _past_ the deprecated major version" do
+ expect { subject.major_deprecation(36, "Message") }.
+ to raise_error(Bundler::DeprecatedError, "[REMOVED] Message")
+ expect { subject.major_deprecation(36, "Message", removed_message: "Removal") }.
+ to raise_error(Bundler::DeprecatedError, "[REMOVED] Removal")
+ expect { subject.major_deprecation(35, "Message", removed_message: "Removal", print_caller_location: true) }.
+ to raise_error(Bundler::DeprecatedError, /^\[REMOVED\] Removal \(called at .*:\d+\)$/)
+ end
+ end
end
diff --git a/spec/bundler/bundler/source/git/git_proxy_spec.rb b/spec/bundler/bundler/source/git/git_proxy_spec.rb
index 97f06973cb..1450316d59 100644
--- a/spec/bundler/bundler/source/git/git_proxy_spec.rb
+++ b/spec/bundler/bundler/source/git/git_proxy_spec.rb
@@ -3,29 +3,84 @@
RSpec.describe Bundler::Source::Git::GitProxy do
let(:path) { Pathname("path") }
let(:uri) { "https://github.com/rubygems/rubygems.git" }
- let(:ref) { "HEAD" }
+ let(:ref) { nil }
+ let(:branch) { nil }
+ let(:tag) { nil }
+ let(:options) { { "ref" => ref, "branch" => branch, "tag" => tag }.compact }
let(:revision) { nil }
let(:git_source) { nil }
- subject { described_class.new(path, uri, ref, revision, git_source) }
+ let(:clone_result) { double(Process::Status, success?: true) }
+ let(:base_clone_args) { ["clone", "--bare", "--no-hardlinks", "--quiet", "--no-tags", "--depth", "1", "--single-branch"] }
+ subject(:git_proxy) { described_class.new(path, uri, options, revision, git_source) }
+
+ context "with explicit ref" do
+ context "with branch only" do
+ let(:branch) { "main" }
+ it "sets explicit ref to branch" do
+ expect(git_proxy.explicit_ref).to eq(branch)
+ end
+ end
+
+ context "with ref only" do
+ let(:ref) { "HEAD" }
+ it "sets explicit ref to ref" do
+ expect(git_proxy.explicit_ref).to eq(ref)
+ end
+ end
+
+ context "with tag only" do
+ let(:tag) { "v1.0" }
+ it "sets explicit ref to ref" do
+ expect(git_proxy.explicit_ref).to eq(tag)
+ end
+ end
+
+ context "with tag and branch" do
+ let(:tag) { "v1.0" }
+ let(:branch) { "main" }
+ it "raises error" do
+ expect { git_proxy }.to raise_error(Bundler::Source::Git::AmbiguousGitReference)
+ end
+ end
+
+ context "with tag and ref" do
+ let(:tag) { "v1.0" }
+ let(:ref) { "HEAD" }
+ it "raises error" do
+ expect { git_proxy }.to raise_error(Bundler::Source::Git::AmbiguousGitReference)
+ end
+ end
+
+ context "with branch and ref" do
+ let(:branch) { "main" }
+ let(:ref) { "HEAD" }
+ it "honors ref over branch" do
+ expect(git_proxy.explicit_ref).to eq(ref)
+ end
+ end
+ end
context "with configured credentials" do
it "adds username and password to URI" do
Bundler.settings.temporary(uri => "u:p") do
- expect(subject).to receive(:git_retry).with("clone", "https://u:p@github.com/rubygems/rubygems.git", any_args)
+ allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(git_proxy).to receive(:capture).with([*base_clone_args, "--", "https://u:p@github.com/rubygems/rubygems.git", path.to_s], nil).and_return(["", "", clone_result])
subject.checkout
end
end
it "adds username and password to URI for host" do
Bundler.settings.temporary("github.com" => "u:p") do
- expect(subject).to receive(:git_retry).with("clone", "https://u:p@github.com/rubygems/rubygems.git", any_args)
+ allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(git_proxy).to receive(:capture).with([*base_clone_args, "--", "https://u:p@github.com/rubygems/rubygems.git", path.to_s], nil).and_return(["", "", clone_result])
subject.checkout
end
end
it "does not add username and password to mismatched URI" do
Bundler.settings.temporary("https://u:p@github.com/rubygems/rubygems-mismatch.git" => "u:p") do
- expect(subject).to receive(:git_retry).with("clone", uri, any_args)
+ allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(git_proxy).to receive(:capture).with([*base_clone_args, "--", uri, path.to_s], nil).and_return(["", "", clone_result])
subject.checkout
end
end
@@ -33,9 +88,10 @@ RSpec.describe Bundler::Source::Git::GitProxy do
it "keeps original userinfo" do
Bundler.settings.temporary("github.com" => "u:p") do
original = "https://orig:info@github.com/rubygems/rubygems.git"
- subject = described_class.new(Pathname("path"), original, "HEAD")
- expect(subject).to receive(:git_retry).with("clone", original, any_args)
- subject.checkout
+ git_proxy = described_class.new(Pathname("path"), original, options)
+ allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(git_proxy).to receive(:capture).with([*base_clone_args, "--", original, path.to_s], nil).and_return(["", "", clone_result])
+ git_proxy.checkout
end
end
end
@@ -43,46 +99,46 @@ RSpec.describe Bundler::Source::Git::GitProxy do
describe "#version" do
context "with a normal version number" do
before do
- expect(subject).to receive(:git).with("--version").
+ expect(git_proxy).to receive(:git_local).with("--version").
and_return("git version 1.2.3")
end
it "returns the git version number" do
- expect(subject.version).to eq("1.2.3")
+ expect(git_proxy.version).to eq("1.2.3")
end
it "does not raise an error when passed into Gem::Version.create" do
- expect { Gem::Version.create subject.version }.not_to raise_error
+ expect { Gem::Version.create git_proxy.version }.not_to raise_error
end
end
context "with a OSX version number" do
before do
- expect(subject).to receive(:git).with("--version").
+ expect(git_proxy).to receive(:git_local).with("--version").
and_return("git version 1.2.3 (Apple Git-BS)")
end
it "strips out OSX specific additions in the version string" do
- expect(subject.version).to eq("1.2.3")
+ expect(git_proxy.version).to eq("1.2.3")
end
it "does not raise an error when passed into Gem::Version.create" do
- expect { Gem::Version.create subject.version }.not_to raise_error
+ expect { Gem::Version.create git_proxy.version }.not_to raise_error
end
end
context "with a msysgit version number" do
before do
- expect(subject).to receive(:git).with("--version").
+ expect(git_proxy).to receive(:git_local).with("--version").
and_return("git version 1.2.3.msysgit.0")
end
it "strips out msysgit specific additions in the version string" do
- expect(subject.version).to eq("1.2.3")
+ expect(git_proxy.version).to eq("1.2.3")
end
it "does not raise an error when passed into Gem::Version.create" do
- expect { Gem::Version.create subject.version }.not_to raise_error
+ expect { Gem::Version.create git_proxy.version }.not_to raise_error
end
end
end
@@ -90,62 +146,55 @@ RSpec.describe Bundler::Source::Git::GitProxy do
describe "#full_version" do
context "with a normal version number" do
before do
- expect(subject).to receive(:git).with("--version").
+ expect(git_proxy).to receive(:git_local).with("--version").
and_return("git version 1.2.3")
end
it "returns the git version number" do
- expect(subject.full_version).to eq("1.2.3")
+ expect(git_proxy.full_version).to eq("1.2.3")
end
end
context "with a OSX version number" do
before do
- expect(subject).to receive(:git).with("--version").
+ expect(git_proxy).to receive(:git_local).with("--version").
and_return("git version 1.2.3 (Apple Git-BS)")
end
it "does not strip out OSX specific additions in the version string" do
- expect(subject.full_version).to eq("1.2.3 (Apple Git-BS)")
+ expect(git_proxy.full_version).to eq("1.2.3 (Apple Git-BS)")
end
end
context "with a msysgit version number" do
before do
- expect(subject).to receive(:git).with("--version").
+ expect(git_proxy).to receive(:git_local).with("--version").
and_return("git version 1.2.3.msysgit.0")
end
it "does not strip out msysgit specific additions in the version string" do
- expect(subject.full_version).to eq("1.2.3.msysgit.0")
+ expect(git_proxy.full_version).to eq("1.2.3.msysgit.0")
end
end
end
- describe "#copy_to" do
- let(:cache) { tmpdir("cache_path") }
- let(:destination) { tmpdir("copy_to_path") }
- let(:submodules) { false }
+ it "doesn't allow arbitrary code execution through Gemfile uris with a leading dash" do
+ gemfile <<~G
+ gem "poc", git: "-u./pay:load.sh"
+ G
- context "when given a SHA as a revision" do
- let(:revision) { "abcd" * 10 }
- let(:command) { ["reset", "--hard", revision] }
- let(:command_for_display) { "git #{command.shelljoin}" }
+ file = bundled_app("pay:load.sh")
- it "fails gracefully when resetting to the revision fails" do
- expect(subject).to receive(:git_retry).with("clone", any_args) { destination.mkpath }
- expect(subject).to receive(:git_retry).with("fetch", any_args, :dir => destination)
- expect(subject).to receive(:git).with(*command, :dir => destination).and_raise(Bundler::Source::Git::GitCommandError.new(command_for_display, destination))
- expect(subject).not_to receive(:git)
+ create_file file, <<~RUBY
+ #!/bin/sh
- expect { subject.copy_to(destination, submodules) }.
- to raise_error(
- Bundler::Source::Git::MissingGitRevisionError,
- "Git error: command `#{command_for_display}` in directory #{destination} has failed.\n" \
- "Revision #{revision} does not exist in the repository #{uri}. Maybe you misspelled it?\n" \
- "If this error persists you could try removing the cache directory '#{destination}'"
- )
- end
- end
+ touch #{bundled_app("canary")}
+ RUBY
+
+ FileUtils.chmod("+x", file)
+
+ bundle :lock, raise_on_error: false
+
+ expect(Pathname.new(bundled_app("canary"))).not_to exist
end
end
diff --git a/spec/bundler/bundler/source/git_spec.rb b/spec/bundler/bundler/source/git_spec.rb
index 6668b6e69a..feef54bbf4 100644
--- a/spec/bundler/bundler/source/git_spec.rb
+++ b/spec/bundler/bundler/source/git_spec.rb
@@ -24,5 +24,50 @@ RSpec.describe Bundler::Source::Git do
expect(subject.to_s).to eq "https://x-oauth-basic@github.com/foo/bar.git"
end
end
+
+ context "when the source has a glob specifier" do
+ let(:glob) { "bar/baz/*.gemspec" }
+ let(:options) do
+ { "uri" => uri, "glob" => glob }
+ end
+
+ it "includes it" do
+ expect(subject.to_s).to eq "https://github.com/foo/bar.git (glob: bar/baz/*.gemspec)"
+ end
+ end
+
+ context "when the source has a reference" do
+ let(:git_proxy_stub) do
+ instance_double(Bundler::Source::Git::GitProxy, revision: "123abc", branch: "v1.0.0")
+ end
+ let(:options) do
+ { "uri" => uri, "ref" => "v1.0.0" }
+ end
+
+ before do
+ allow(Bundler::Source::Git::GitProxy).to receive(:new).and_return(git_proxy_stub)
+ end
+
+ it "includes it" do
+ expect(subject.to_s).to eq "https://github.com/foo/bar.git (at v1.0.0@123abc)"
+ end
+ end
+
+ context "when the source has both reference and glob specifiers" do
+ let(:git_proxy_stub) do
+ instance_double(Bundler::Source::Git::GitProxy, revision: "123abc", branch: "v1.0.0")
+ end
+ let(:options) do
+ { "uri" => uri, "ref" => "v1.0.0", "glob" => "gems/foo/*.gemspec" }
+ end
+
+ before do
+ allow(Bundler::Source::Git::GitProxy).to receive(:new).and_return(git_proxy_stub)
+ end
+
+ it "includes both" do
+ expect(subject.to_s).to eq "https://github.com/foo/bar.git (at v1.0.0@123abc, glob: gems/foo/*.gemspec)"
+ end
+ end
end
end
diff --git a/spec/bundler/bundler/source/rubygems/remote_spec.rb b/spec/bundler/bundler/source/rubygems/remote_spec.rb
index 07ce4f968e..56f3bee459 100644
--- a/spec/bundler/bundler/source/rubygems/remote_spec.rb
+++ b/spec/bundler/bundler/source/rubygems/remote_spec.rb
@@ -11,8 +11,8 @@ RSpec.describe Bundler::Source::Rubygems::Remote do
allow(Digest(:MD5)).to receive(:hexdigest).with(duck_type(:to_s)) {|string| "MD5HEX(#{string})" }
end
- let(:uri_no_auth) { Bundler::URI("https://gems.example.com") }
- let(:uri_with_auth) { Bundler::URI("https://#{credentials}@gems.example.com") }
+ let(:uri_no_auth) { Gem::URI("https://gems.example.com") }
+ let(:uri_with_auth) { Gem::URI("https://#{credentials}@gems.example.com") }
let(:credentials) { "username:password" }
context "when the original URI has no credentials" do
@@ -89,11 +89,11 @@ RSpec.describe Bundler::Source::Rubygems::Remote do
end
context "when the original URI has only a username" do
- let(:uri) { Bundler::URI("https://SeCrEt-ToKeN@gem.fury.io/me/") }
+ let(:uri) { Gem::URI("https://SeCrEt-ToKeN@gem.fury.io/me/") }
describe "#anonymized_uri" do
it "returns the URI without username and password" do
- expect(remote(uri).anonymized_uri).to eq(Bundler::URI("https://gem.fury.io/me/"))
+ expect(remote(uri).anonymized_uri).to eq(Gem::URI("https://gem.fury.io/me/"))
end
end
@@ -105,9 +105,9 @@ RSpec.describe Bundler::Source::Rubygems::Remote do
end
context "when a mirror with inline credentials is configured for the URI" do
- let(:uri) { Bundler::URI("https://rubygems.org/") }
- let(:mirror_uri_with_auth) { Bundler::URI("https://username:password@rubygems-mirror.org/") }
- let(:mirror_uri_no_auth) { Bundler::URI("https://rubygems-mirror.org/") }
+ let(:uri) { Gem::URI("https://rubygems.org/") }
+ let(:mirror_uri_with_auth) { Gem::URI("https://username:password@rubygems-mirror.org/") }
+ let(:mirror_uri_no_auth) { Gem::URI("https://rubygems-mirror.org/") }
before { Bundler.settings.temporary("mirror.https://rubygems.org/" => mirror_uri_with_auth.to_s) }
@@ -131,9 +131,9 @@ RSpec.describe Bundler::Source::Rubygems::Remote do
end
context "when a mirror with configured credentials is configured for the URI" do
- let(:uri) { Bundler::URI("https://rubygems.org/") }
- let(:mirror_uri_with_auth) { Bundler::URI("https://#{credentials}@rubygems-mirror.org/") }
- let(:mirror_uri_no_auth) { Bundler::URI("https://rubygems-mirror.org/") }
+ let(:uri) { Gem::URI("https://rubygems.org/") }
+ let(:mirror_uri_with_auth) { Gem::URI("https://#{credentials}@rubygems-mirror.org/") }
+ let(:mirror_uri_no_auth) { Gem::URI("https://rubygems-mirror.org/") }
before do
Bundler.settings.temporary("mirror.https://rubygems.org/" => mirror_uri_no_auth.to_s)
diff --git a/spec/bundler/bundler/source_list_spec.rb b/spec/bundler/bundler/source_list_spec.rb
index f860e9ff58..13453cb2a3 100644
--- a/spec/bundler/bundler/source_list_spec.rb
+++ b/spec/bundler/bundler/source_list_spec.rb
@@ -85,7 +85,7 @@ RSpec.describe Bundler::SourceList do
end
it "ignores git protocols on request" do
- Bundler.settings.temporary(:"git.allow_insecure" => true)
+ Bundler.settings.temporary("git.allow_insecure": true)
expect(Bundler.ui).to_not receive(:warn).with(msg)
source_list.add_git_source("uri" => "git://existing-git.org/path.git")
end
@@ -125,8 +125,8 @@ RSpec.describe Bundler::SourceList do
it "adds the provided remote to the beginning of the aggregate source" do
source_list.add_global_rubygems_remote("https://othersource.org")
expect(returned_source.remotes).to eq [
- Bundler::URI("https://othersource.org/"),
- Bundler::URI("https://rubygems.org/"),
+ Gem::URI("https://othersource.org/"),
+ Gem::URI("https://rubygems.org/"),
]
end
end
diff --git a/spec/bundler/bundler/source_spec.rb b/spec/bundler/bundler/source_spec.rb
index af370bb45c..3b49c37431 100644
--- a/spec/bundler/bundler/source_spec.rb
+++ b/spec/bundler/bundler/source_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe Bundler::Source do
end
describe "#version_message" do
- let(:spec) { double(:spec, :name => "nokogiri", :version => ">= 1.6", :platform => rb) }
+ let(:spec) { double(:spec, name: "nokogiri", version: ">= 1.6", platform: rb) }
shared_examples_for "the lockfile specs are not relevant" do
it "should return a string with the spec name and version" do
@@ -30,31 +30,21 @@ RSpec.describe Bundler::Source do
end
context "when there are locked gems" do
- let(:locked_gems) { double(:locked_gems) }
-
- before { allow(Bundler).to receive(:locked_gems).and_return(locked_gems) }
-
context "that contain the relevant gem spec" do
- before do
- specs = double(:specs)
- allow(locked_gems).to receive(:specs).and_return(specs)
- allow(specs).to receive(:find).and_return(locked_gem)
- end
-
context "without a version" do
- let(:locked_gem) { double(:locked_gem, :name => "nokogiri", :version => nil) }
+ let(:locked_gem) { double(:locked_gem, name: "nokogiri", version: nil) }
it_behaves_like "the lockfile specs are not relevant"
end
context "with the same version" do
- let(:locked_gem) { double(:locked_gem, :name => "nokogiri", :version => ">= 1.6") }
+ let(:locked_gem) { double(:locked_gem, name: "nokogiri", version: ">= 1.6") }
it_behaves_like "the lockfile specs are not relevant"
end
context "with a different version" do
- let(:locked_gem) { double(:locked_gem, :name => "nokogiri", :version => "< 1.5") }
+ let(:locked_gem) { double(:locked_gem, name: "nokogiri", version: "< 1.5") }
context "with color", :no_color_tty do
before do
@@ -62,7 +52,7 @@ RSpec.describe Bundler::Source do
end
it "should return a string with the spec name and version and locked spec version" do
- expect(subject.version_message(spec)).to eq("nokogiri >= 1.6\e[32m (was < 1.5)\e[0m")
+ expect(subject.version_message(spec, locked_gem)).to eq("nokogiri >= 1.6\e[32m (was < 1.5)\e[0m")
end
end
@@ -74,14 +64,14 @@ RSpec.describe Bundler::Source do
end
it "should return a string with the spec name and version and locked spec version" do
- expect(subject.version_message(spec)).to eq("nokogiri >= 1.6 (was < 1.5)")
+ expect(subject.version_message(spec, locked_gem)).to eq("nokogiri >= 1.6 (was < 1.5)")
end
end
end
context "with a more recent version" do
- let(:spec) { double(:spec, :name => "nokogiri", :version => "1.6.1", :platform => rb) }
- let(:locked_gem) { double(:locked_gem, :name => "nokogiri", :version => "1.7.0") }
+ let(:spec) { double(:spec, name: "nokogiri", version: "1.6.1", platform: rb) }
+ let(:locked_gem) { double(:locked_gem, name: "nokogiri", version: "1.7.0") }
context "with color", :no_color_tty do
before do
@@ -89,7 +79,7 @@ RSpec.describe Bundler::Source do
end
it "should return a string with the locked spec version in yellow" do
- expect(subject.version_message(spec)).to eq("nokogiri 1.6.1\e[33m (was 1.7.0)\e[0m")
+ expect(subject.version_message(spec, locked_gem)).to eq("nokogiri 1.6.1\e[33m (was 1.7.0)\e[0m")
end
end
@@ -101,14 +91,14 @@ RSpec.describe Bundler::Source do
end
it "should return a string with the locked spec version in yellow" do
- expect(subject.version_message(spec)).to eq("nokogiri 1.6.1 (was 1.7.0)")
+ expect(subject.version_message(spec, locked_gem)).to eq("nokogiri 1.6.1 (was 1.7.0)")
end
end
end
context "with an older version" do
- let(:spec) { double(:spec, :name => "nokogiri", :version => "1.7.1", :platform => rb) }
- let(:locked_gem) { double(:locked_gem, :name => "nokogiri", :version => "1.7.0") }
+ let(:spec) { double(:spec, name: "nokogiri", version: "1.7.1", platform: rb) }
+ let(:locked_gem) { double(:locked_gem, name: "nokogiri", version: "1.7.0") }
context "with color", :no_color_tty do
before do
@@ -116,7 +106,7 @@ RSpec.describe Bundler::Source do
end
it "should return a string with the locked spec version in green" do
- expect(subject.version_message(spec)).to eq("nokogiri 1.7.1\e[32m (was 1.7.0)\e[0m")
+ expect(subject.version_message(spec, locked_gem)).to eq("nokogiri 1.7.1\e[32m (was 1.7.0)\e[0m")
end
end
@@ -128,33 +118,17 @@ RSpec.describe Bundler::Source do
end
it "should return a string with the locked spec version in yellow" do
- expect(subject.version_message(spec)).to eq("nokogiri 1.7.1 (was 1.7.0)")
+ expect(subject.version_message(spec, locked_gem)).to eq("nokogiri 1.7.1 (was 1.7.0)")
end
end
end
end
-
- context "that do not contain the relevant gem spec" do
- before do
- specs = double(:specs)
- allow(locked_gems).to receive(:specs).and_return(specs)
- allow(specs).to receive(:find).and_return(nil)
- end
-
- it_behaves_like "the lockfile specs are not relevant"
- end
- end
-
- context "when there are no locked gems" do
- before { allow(Bundler).to receive(:locked_gems).and_return(nil) }
-
- it_behaves_like "the lockfile specs are not relevant"
end
end
describe "#can_lock?" do
context "when the passed spec's source is equivalent" do
- let(:spec) { double(:spec, :source => subject) }
+ let(:spec) { double(:spec, source: subject) }
it "should return true" do
expect(subject.can_lock?(spec)).to be_truthy
@@ -162,7 +136,7 @@ RSpec.describe Bundler::Source do
end
context "when the passed spec's source is not equivalent" do
- let(:spec) { double(:spec, :source => double(:other_source)) }
+ let(:spec) { double(:spec, source: double(:other_source)) }
it "should return false" do
expect(subject.can_lock?(spec)).to be_falsey
diff --git a/spec/bundler/bundler/spec_set_spec.rb b/spec/bundler/bundler/spec_set_spec.rb
index 6fedd38b50..c4b6676223 100644
--- a/spec/bundler/bundler/spec_set_spec.rb
+++ b/spec/bundler/bundler/spec_set_spec.rb
@@ -45,24 +45,6 @@ RSpec.describe Bundler::SpecSet do
end
end
- describe "#merge" do
- let(:other_specs) do
- [
- build_spec("f", "1.0"),
- build_spec("g", "2.0"),
- ].flatten
- end
-
- let(:other_spec_set) { described_class.new(other_specs) }
-
- it "merges the items in each gemspec" do
- new_spec_set = subject.merge(other_spec_set)
- specs = new_spec_set.to_a.map(&:full_name)
- expect(specs).to include("a-1.0")
- expect(specs).to include("f-1.0")
- end
- end
-
describe "#to_a" do
it "returns the specs in order" do
expect(subject.to_a.map(&:full_name)).to eq %w[
diff --git a/spec/bundler/bundler/specifications/foo.gemspec b/spec/bundler/bundler/specifications/foo.gemspec
new file mode 100644
index 0000000000..46eb068cd1
--- /dev/null
+++ b/spec/bundler/bundler/specifications/foo.gemspec
@@ -0,0 +1,13 @@
+# rubocop:disable Style/FrozenStringLiteralComment
+# stub: foo 1.0.0 ruby lib
+
+# The first line would be '# -*- encoding: utf-8 -*-' in a real stub gemspec
+
+Gem::Specification.new do |s|
+ s.name = "foo"
+ s.version = "1.0.0"
+ s.loaded_from = __FILE__
+ s.extensions = "ext/foo"
+ s.required_ruby_version = ">= 3.0.0"
+end
+# rubocop:enable Style/FrozenStringLiteralComment
diff --git a/spec/bundler/bundler/stub_specification_spec.rb b/spec/bundler/bundler/stub_specification_spec.rb
index fb612813c2..dae9f3cfba 100644
--- a/spec/bundler/bundler/stub_specification_spec.rb
+++ b/spec/bundler/bundler/stub_specification_spec.rb
@@ -19,6 +19,17 @@ RSpec.describe Bundler::StubSpecification do
end
end
+ describe "#gem_build_complete_path" do
+ it "StubSpecification should have equal gem_build_complete_path as Specification" do
+ spec_path = File.join(File.dirname(__FILE__), "specifications", "foo.gemspec")
+ spec = Gem::Specification.load(spec_path)
+ gem_stub = Gem::StubSpecification.new(spec_path, File.dirname(__FILE__),"","")
+
+ stub = described_class.from_stub(gem_stub)
+ expect(stub.gem_build_complete_path).to eq spec.gem_build_complete_path
+ end
+ end
+
describe "#manually_installed?" do
it "returns true if installed_by_version is nil or 0" do
stub = described_class.from_stub(with_bundler_stub_spec)
diff --git a/spec/bundler/bundler/uri_credentials_filter_spec.rb b/spec/bundler/bundler/uri_credentials_filter_spec.rb
index 466c1b8594..ed24744a1c 100644
--- a/spec/bundler/bundler/uri_credentials_filter_spec.rb
+++ b/spec/bundler/bundler/uri_credentials_filter_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe Bundler::URICredentialsFilter do
let(:credentials) { "oauth_token:x-oauth-basic@" }
it "returns the uri without the oauth token" do
- expect(subject.credential_filtered_uri(uri).to_s).to eq(Bundler::URI("https://x-oauth-basic@github.com/company/private-repo").to_s)
+ expect(subject.credential_filtered_uri(uri).to_s).to eq(Gem::URI("https://x-oauth-basic@github.com/company/private-repo").to_s)
end
it_behaves_like "original type of uri is maintained"
@@ -26,7 +26,7 @@ RSpec.describe Bundler::URICredentialsFilter do
let(:credentials) { "oauth_token:x@" }
it "returns the uri without the oauth token" do
- expect(subject.credential_filtered_uri(uri).to_s).to eq(Bundler::URI("https://x@github.com/company/private-repo").to_s)
+ expect(subject.credential_filtered_uri(uri).to_s).to eq(Gem::URI("https://x@github.com/company/private-repo").to_s)
end
it_behaves_like "original type of uri is maintained"
@@ -37,7 +37,7 @@ RSpec.describe Bundler::URICredentialsFilter do
let(:credentials) { "username1:hunter3@" }
it "returns the uri without the password" do
- expect(subject.credential_filtered_uri(uri).to_s).to eq(Bundler::URI("https://username1@github.com/company/private-repo").to_s)
+ expect(subject.credential_filtered_uri(uri).to_s).to eq(Gem::URI("https://username1@github.com/company/private-repo").to_s)
end
it_behaves_like "original type of uri is maintained"
@@ -55,7 +55,7 @@ RSpec.describe Bundler::URICredentialsFilter do
end
context "uri is a uri object" do
- let(:uri) { Bundler::URI("https://#{credentials}github.com/company/private-repo") }
+ let(:uri) { Gem::URI("https://#{credentials}github.com/company/private-repo") }
it_behaves_like "sensitive credentials in uri are filtered out"
end
@@ -90,7 +90,7 @@ RSpec.describe Bundler::URICredentialsFilter do
describe "#credential_filtered_string" do
let(:str_to_filter) { "This is a git message containing a uri #{uri}!" }
let(:credentials) { "" }
- let(:uri) { Bundler::URI("https://#{credentials}github.com/company/private-repo") }
+ let(:uri) { Gem::URI("https://#{credentials}github.com/company/private-repo") }
context "with a uri that contains credentials" do
let(:credentials) { "oauth_token:x-oauth-basic@" }
diff --git a/spec/bundler/bundler/vendored_persistent_spec.rb b/spec/bundler/bundler/vendored_persistent_spec.rb
deleted file mode 100644
index 3ed899dbcf..0000000000
--- a/spec/bundler/bundler/vendored_persistent_spec.rb
+++ /dev/null
@@ -1,77 +0,0 @@
-# frozen_string_literal: true
-
-require "bundler/vendored_persistent"
-
-RSpec.describe Bundler::PersistentHTTP do
- describe "#warn_old_tls_version_rubygems_connection" do
- let(:uri) { "https://index.rubygems.org" }
- let(:connection) { instance_double(Bundler::Persistent::Net::HTTP::Persistent::Connection) }
- let(:tls_version) { "TLSv1.2" }
- let(:socket) { double("Socket") }
- let(:socket_io) { double("SocketIO") }
-
- before do
- allow(connection).to receive_message_chain(:http, :use_ssl?).and_return(!tls_version.nil?)
- allow(socket).to receive(:io).and_return(socket_io) if socket
- connection.instance_variable_set(:@socket, socket)
-
- if tls_version
- allow(socket_io).to receive(:ssl_version).and_return(tls_version)
- end
- end
-
- shared_examples_for "does not warn" do
- it "does not warn" do
- allow(Bundler.ui).to receive(:warn).never
- subject.warn_old_tls_version_rubygems_connection(Bundler::URI(uri), connection)
- end
- end
-
- shared_examples_for "does warn" do |*expected|
- it "warns" do
- expect(Bundler.ui).to receive(:warn).with(*expected)
- subject.warn_old_tls_version_rubygems_connection(Bundler::URI(uri), connection)
- end
- end
-
- context "an HTTPS uri with TLSv1.2" do
- include_examples "does not warn"
- end
-
- context "without SSL" do
- let(:tls_version) { nil }
-
- include_examples "does not warn"
- end
-
- context "without a socket" do
- let(:socket) { nil }
-
- include_examples "does not warn"
- end
-
- context "with a different TLD" do
- let(:uri) { "https://foo.bar" }
- include_examples "does not warn"
-
- context "and an outdated TLS version" do
- let(:tls_version) { "TLSv1" }
- include_examples "does not warn"
- end
- end
-
- context "with a nonsense TLS version" do
- let(:tls_version) { "BlahBlah2.0Blah" }
- include_examples "does not warn"
- end
-
- context "with an outdated TLS version" do
- let(:tls_version) { "TLSv1" }
- include_examples "does warn",
- "Warning: Your Ruby version is compiled against a copy of OpenSSL that is very old. " \
- "Starting in January 2018, RubyGems.org will refuse connection requests from these very old versions of OpenSSL. " \
- "If you will need to continue installing gems after January 2018, please follow this guide to upgrade: http://ruby.to/tls-outdated.",
- :wrap => true
- end
- end
-end
diff --git a/spec/bundler/bundler/version_ranges_spec.rb b/spec/bundler/bundler/version_ranges_spec.rb
deleted file mode 100644
index bca044b0c0..0000000000
--- a/spec/bundler/bundler/version_ranges_spec.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-
-require "bundler/version_ranges"
-
-RSpec.describe Bundler::VersionRanges do
- describe ".empty?" do
- shared_examples_for "empty?" do |exp, *req|
- it "returns #{exp} for #{req}" do
- r = Gem::Requirement.new(*req)
- ranges = described_class.for(r)
- expect(described_class.empty?(*ranges)).to eq(exp), "expected `#{r}` #{exp ? "" : "not "}to be empty"
- end
- end
-
- include_examples "empty?", false
- include_examples "empty?", false, "!= 1"
- include_examples "empty?", false, "!= 1", "= 2"
- include_examples "empty?", false, "!= 1", "> 1"
- include_examples "empty?", false, "!= 1", ">= 1"
- include_examples "empty?", false, "= 1", ">= 0.1", "<= 1.1"
- include_examples "empty?", false, "= 1", ">= 1", "<= 1"
- include_examples "empty?", false, "= 1", "~> 1"
- include_examples "empty?", false, ">= 0.z", "= 0"
- include_examples "empty?", false, ">= 0"
- include_examples "empty?", false, ">= 1.0.0", "< 2.0.0"
- include_examples "empty?", false, "~> 1"
- include_examples "empty?", false, "~> 2.0", "~> 2.1"
- include_examples "empty?", true, ">= 4.1.0", "< 5.0", "= 5.2.1"
- include_examples "empty?", true, "< 5.0", "< 5.3", "< 6.0", "< 6", "= 5.2.0", "> 2", ">= 3.0", ">= 3.1", ">= 3.2", ">= 4.0.0", ">= 4.1.0", ">= 4.2.0", ">= 4.2", ">= 4"
- include_examples "empty?", true, "!= 1", "< 2", "> 2"
- include_examples "empty?", true, "!= 1", "<= 1", ">= 1"
- include_examples "empty?", true, "< 2", "> 2"
- include_examples "empty?", true, "< 2", "> 2", "= 2"
- include_examples "empty?", true, "= 1", "!= 1"
- include_examples "empty?", true, "= 1", "= 2"
- include_examples "empty?", true, "= 1", "~> 2"
- include_examples "empty?", true, ">= 0", "<= 0.a"
- include_examples "empty?", true, "~> 2.0", "~> 3"
- end
-end
diff --git a/spec/bundler/bundler/yaml_serializer_spec.rb b/spec/bundler/bundler/yaml_serializer_spec.rb
index 1241c74bbf..de437f764a 100644
--- a/spec/bundler/bundler/yaml_serializer_spec.rb
+++ b/spec/bundler/bundler/yaml_serializer_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Bundler::YAMLSerializer do
it "works for simple hash" do
hash = { "Q" => "Where does Thursday come before Wednesday? In the dictionary. :P" }
- expected = strip_whitespace <<-YAML
+ expected = <<~YAML
---
Q: "Where does Thursday come before Wednesday? In the dictionary. :P"
YAML
@@ -24,7 +24,7 @@ RSpec.describe Bundler::YAMLSerializer do
},
}
- expected = strip_whitespace <<-YAML
+ expected = <<~YAML
---
nice-one:
read_ahead: "All generalizations are false, including this one"
@@ -45,7 +45,7 @@ RSpec.describe Bundler::YAMLSerializer do
},
}
- expected = strip_whitespace <<-YAML
+ expected = <<~YAML
---
nested_hash:
contains_array:
@@ -57,11 +57,24 @@ RSpec.describe Bundler::YAMLSerializer do
expect(serializer.dump(hash)).to eq(expected)
end
+
+ it "handles empty array" do
+ hash = {
+ "empty_array" => [],
+ }
+
+ expected = <<~YAML
+ ---
+ empty_array: []
+ YAML
+
+ expect(serializer.dump(hash)).to eq(expected)
+ end
end
describe "#load" do
it "works for simple hash" do
- yaml = strip_whitespace <<-YAML
+ yaml = <<~YAML
---
Jon: "Air is free dude!"
Jack: "Yes.. until you buy a bag of chips!"
@@ -76,7 +89,7 @@ RSpec.describe Bundler::YAMLSerializer do
end
it "works for nested hash" do
- yaml = strip_whitespace <<-YAML
+ yaml = <<~YAML
---
baa:
baa: "black sheep"
@@ -98,7 +111,7 @@ RSpec.describe Bundler::YAMLSerializer do
end
it "handles colon in key/value" do
- yaml = strip_whitespace <<-YAML
+ yaml = <<~YAML
BUNDLE_MIRROR__HTTPS://RUBYGEMS__ORG/: http://rubygems-mirror.org
YAML
@@ -106,7 +119,7 @@ RSpec.describe Bundler::YAMLSerializer do
end
it "handles arrays inside hashes" do
- yaml = strip_whitespace <<-YAML
+ yaml = <<~YAML
---
nested_hash:
contains_array:
@@ -127,7 +140,7 @@ RSpec.describe Bundler::YAMLSerializer do
end
it "handles windows-style CRLF line endings" do
- yaml = strip_whitespace(<<-YAML).gsub("\n", "\r\n")
+ yaml = <<~YAML.gsub("\n", "\r\n")
---
nested_hash:
contains_array:
@@ -148,6 +161,34 @@ RSpec.describe Bundler::YAMLSerializer do
expect(serializer.load(yaml)).to eq(hash)
end
+
+ it "handles empty array" do
+ yaml = <<~YAML
+ ---
+ empty_array: []
+ YAML
+
+ hash = {
+ "empty_array" => [],
+ }
+
+ expect(serializer.load(yaml)).to eq(hash)
+ end
+
+ it "skip commented out words" do
+ yaml = <<~YAML
+ ---
+ foo: bar
+ buzz: foo # bar
+ YAML
+
+ hash = {
+ "foo" => "bar",
+ "buzz" => "foo",
+ }
+
+ expect(serializer.load(yaml)).to eq(hash)
+ end
end
describe "against yaml lib" do
diff --git a/spec/bundler/cache/gems_spec.rb b/spec/bundler/cache/gems_spec.rb
index 72e372fb41..abbc2c3cf2 100644
--- a/spec/bundler/cache/gems_spec.rb
+++ b/spec/bundler/cache/gems_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe "bundle cache" do
gem 'rack'
G
- system_gems "rack-1.0.0", :path => path
+ system_gems "rack-1.0.0", path: path
bundle :cache
end
@@ -17,7 +17,7 @@ RSpec.describe "bundle cache" do
end
it "uses the cache as a source when installing gems" do
- build_gem "omg", :path => bundled_app("vendor/cache")
+ build_gem "omg", path: bundled_app("vendor/cache")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -28,14 +28,14 @@ RSpec.describe "bundle cache" do
end
it "uses the cache as a source when installing gems with --local" do
- system_gems [], :path => default_bundle_path
+ system_gems [], path: default_bundle_path
bundle "install --local"
expect(the_bundle).to include_gems("rack 1.0.0")
end
it "does not reinstall gems from the cache if they exist on the system" do
- build_gem "rack", "1.0.0", :path => bundled_app("vendor/cache") do |s|
+ build_gem "rack", "1.0.0", path: bundled_app("vendor/cache") do |s|
s.write "lib/rack.rb", "RACK = 'FAIL'"
end
@@ -48,18 +48,18 @@ RSpec.describe "bundle cache" do
end
it "does not reinstall gems from the cache if they exist in the bundle" do
- system_gems "rack-1.0.0", :path => default_bundle_path
+ system_gems "rack-1.0.0", path: default_bundle_path
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
G
- build_gem "rack", "1.0.0", :path => bundled_app("vendor/cache") do |s|
+ build_gem "rack", "1.0.0", path: bundled_app("vendor/cache") do |s|
s.write "lib/rack.rb", "RACK = 'FAIL'"
end
- bundle :install, :local => true
+ bundle :install, local: true
expect(the_bundle).to include_gems("rack 1.0.0")
end
@@ -89,39 +89,49 @@ RSpec.describe "bundle cache" do
it_behaves_like "when there are only gemsources"
end
- describe "when there is a built-in gem" do
+ describe "when there is a built-in gem", :ruby_repo do
+ let(:default_json_version) { ruby "gem 'json'; require 'json'; puts JSON::VERSION" }
+
before :each do
build_repo2 do
- build_gem "builtin_gem", "1.0.2"
+ build_gem "json", default_json_version
end
- build_gem "builtin_gem", "1.0.2", :to_system => true do |s|
- s.summary = "This builtin_gem is bundled with Ruby"
- end
-
- FileUtils.rm("#{system_gem_path}/cache/builtin_gem-1.0.2.gem")
+ build_gem "json", default_json_version, to_system: true, default: true
end
it "uses builtin gems when installing to system gems" do
bundle "config set path.system true"
- install_gemfile %(source "#{file_uri_for(gem_repo1)}"; gem 'builtin_gem', '1.0.2')
- expect(the_bundle).to include_gems("builtin_gem 1.0.2")
+ install_gemfile %(source "#{file_uri_for(gem_repo1)}"; gem 'json', '#{default_json_version}'), verbose: true
+ expect(out).to include("Using json #{default_json_version}")
end
it "caches remote and builtin gems" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
- gem 'builtin_gem', '1.0.2'
+ gem 'json', '#{default_json_version}'
gem 'rack', '1.0.0'
G
bundle :cache
expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
- expect(bundled_app("vendor/cache/builtin_gem-1.0.2.gem")).to exist
+ expect(bundled_app("vendor/cache/json-#{default_json_version}.gem")).to exist
+ end
+
+ it "caches builtin gems when cache_all_platforms is set" do
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
+ gem "json"
+ G
+
+ bundle "config set cache_all_platforms true"
+
+ bundle :cache
+ expect(bundled_app("vendor/cache/json-#{default_json_version}.gem")).to exist
end
it "doesn't make remote request after caching the gem" do
- build_gem "builtin_gem_2", "1.0.2", :path => bundled_app("vendor/cache") do |s|
+ build_gem "builtin_gem_2", "1.0.2", path: bundled_app("vendor/cache") do |s|
s.summary = "This builtin_gem is bundled with Ruby"
end
@@ -139,12 +149,12 @@ RSpec.describe "bundle cache" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem 'builtin_gem', '1.0.2'
+ gem 'json', '#{default_json_version}'
G
- bundle :cache, :raise_on_error => false
+ bundle :cache, raise_on_error: false
expect(exitstatus).to_not eq(0)
- expect(err).to include("builtin_gem-1.0.2 is built in to Ruby, and can't be cached")
+ expect(err).to include("json-#{default_json_version} is built in to Ruby, and can't be cached")
end
end
@@ -208,7 +218,7 @@ RSpec.describe "bundle cache" do
end
end
- bundle "update", :all => true
+ bundle "update", all: true
expect(cached_gem("rack-1.2")).to exist
expect(cached_gem("rack-1.0.0")).not_to exist
end
@@ -269,10 +279,57 @@ RSpec.describe "bundle cache" do
it "doesn't remove gems with mismatched :rubygems_version or :date" do
cached_gem("rack-1.0.0").rmtree
build_gem "rack", "1.0.0",
- :path => bundled_app("vendor/cache"),
- :rubygems_version => "1.3.2"
+ path: bundled_app("vendor/cache"),
+ rubygems_version: "1.3.2"
+ # This test is only really valid if the checksum isn't saved. It otherwise can't be the same gem. Tested below.
+ bundled_app_lock.write remove_checksums_from_lockfile(bundled_app_lock.read, "rack (1.0.0)")
+ simulate_new_machine
+
+ bundle :install
+ expect(cached_gem("rack-1.0.0")).to exist
+ end
+
+ it "raises an error when the gem is altered and produces a different checksum" do
+ cached_gem("rack-1.0.0").rmtree
+ build_gem "rack", "1.0.0", path: bundled_app("vendor/cache")
+
+ checksums = checksums_section do |c|
+ c.checksum gem_repo1, "rack", "1.0.0"
+ end
+
simulate_new_machine
+ lockfile <<-L
+ GEM
+ remote: #{file_uri_for(gem_repo2)}/
+ specs:
+ rack (1.0.0)
+ #{checksums}
+ L
+
+ bundle :install, raise_on_error: false
+ expect(exitstatus).to eq(37)
+ expect(err).to include("Bundler found mismatched checksums.")
+ expect(err).to include("1. remove the gem at #{cached_gem("rack-1.0.0")}")
+
+ expect(cached_gem("rack-1.0.0")).to exist
+ cached_gem("rack-1.0.0").rmtree
+ bundle :install
+ expect(cached_gem("rack-1.0.0")).to exist
+ end
+
+ it "installs a modified gem with a non-matching checksum when checksums is not opted in" do
+ cached_gem("rack-1.0.0").rmtree
+ build_gem "rack", "1.0.0", path: bundled_app("vendor/cache")
+ simulate_new_machine
+
+ lockfile <<-L
+ GEM
+ remote: #{file_uri_for(gem_repo2)}/
+ specs:
+ rack (1.0.0)
+ L
+
bundle :install
expect(cached_gem("rack-1.0.0")).to exist
end
@@ -304,7 +361,7 @@ RSpec.describe "bundle cache" do
it "should install gems with the name bundler in them (that aren't bundler)" do
build_gem "foo-bundler", "1.0",
- :path => bundled_app("vendor/cache")
+ path: bundled_app("vendor/cache")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
diff --git a/spec/bundler/cache/git_spec.rb b/spec/bundler/cache/git_spec.rb
index b88993e9b1..4b3cd4d2eb 100644
--- a/spec/bundler/cache/git_spec.rb
+++ b/spec/bundler/cache/git_spec.rb
@@ -15,7 +15,7 @@ end
RSpec.describe "bundle cache with git" do
it "copies repository to vendor cache and uses it" do
git = build_git "foo"
- ref = git.ref_for("master", 11)
+ ref = git.ref_for("main", 11)
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -34,7 +34,7 @@ RSpec.describe "bundle cache with git" do
it "copies repository to vendor cache and uses it even when configured with `path`" do
git = build_git "foo"
- ref = git.ref_for("master", 11)
+ ref = git.ref_for("main", 11)
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -72,7 +72,7 @@ RSpec.describe "bundle cache with git" do
it "tracks updates" do
git = build_git "foo"
- old_ref = git.ref_for("master", 11)
+ old_ref = git.ref_for("main", 11)
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -86,11 +86,10 @@ RSpec.describe "bundle cache with git" do
s.write "lib/foo.rb", "puts :CACHE"
end
- ref = git.ref_for("master", 11)
+ ref = git.ref_for("main", 11)
expect(ref).not_to eq(old_ref)
- bundle "update", :all => true
- bundle "config set cache_all true"
+ bundle "update", all: true
bundle :cache
expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist
@@ -103,7 +102,7 @@ RSpec.describe "bundle cache with git" do
it "tracks updates when specifying the gem" do
git = build_git "foo"
- old_ref = git.ref_for("master", 11)
+ old_ref = git.ref_for("main", 11)
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -117,7 +116,7 @@ RSpec.describe "bundle cache with git" do
s.write "lib/foo.rb", "puts :CACHE"
end
- ref = git.ref_for("master", 11)
+ ref = git.ref_for("main", 11)
expect(ref).not_to eq(old_ref)
bundle "update foo"
@@ -132,11 +131,11 @@ RSpec.describe "bundle cache with git" do
it "uses the local repository to generate the cache" do
git = build_git "foo"
- ref = git.ref_for("master", 11)
+ ref = git.ref_for("main", 11)
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "foo", :git => '#{lib_path("foo-invalid")}', :branch => :master
+ gem "foo", :git => '#{lib_path("foo-invalid")}', :branch => :main
G
bundle %(config set local.foo #{lib_path("foo-1.0")})
@@ -156,14 +155,17 @@ RSpec.describe "bundle cache with git" do
end
it "copies repository to vendor cache, including submodules" do
+ # CVE-2022-39253: https://lore.kernel.org/lkml/xmqq4jw1uku5.fsf@gitster.g/
+ system(*%W[git config --global protocol.file.allow always])
+
build_git "submodule", "1.0"
git = build_git "has_submodule", "1.0" do |s|
s.add_dependency "submodule"
end
- sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0")
- sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0")
+ sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", dir: lib_path("has_submodule-1.0")
+ sys_exec "git commit -m \"submodulator\"", dir: lib_path("has_submodule-1.0")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -172,7 +174,7 @@ RSpec.describe "bundle cache with git" do
end
G
- ref = git.ref_for("master", 11)
+ ref = git.ref_for("main", 11)
bundle "config set cache_all true"
bundle :cache
@@ -196,7 +198,7 @@ RSpec.describe "bundle cache with git" do
bundle "config set cache_all true"
bundle :cache
- ref = git.ref_for("master", 11)
+ ref = git.ref_for("main", 11)
gemspec = bundled_app("vendor/cache/foo-1.0-#{ref}/foo.gemspec").read
expect(gemspec).to_not match("`echo bob`")
end
@@ -214,8 +216,61 @@ RSpec.describe "bundle cache with git" do
simulate_new_machine
with_path_as "" do
bundle "config set deployment true"
- bundle :install, :local => true
+ bundle :install, local: true
expect(the_bundle).to include_gem "foo 1.0"
end
end
+
+ it "respects the --no-install flag" do
+ git = build_git "foo", &:add_c_extension
+ ref = git.ref_for("main", 11)
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => '#{lib_path("foo-1.0")}'
+ G
+ bundle "config set cache_all true"
+
+ # The algorithm for the cache location for a git checkout is
+ # in Bundle::Source::Git#cache_path
+ cache_path_name = "foo-1.0-#{Digest(:SHA1).hexdigest(lib_path("foo-1.0").to_s)}"
+
+ # Run this test twice. This is because materially different codepaths
+ # will get hit the second time around.
+ # The first time, Bundler::Sources::Git#install_path is set to the system
+ # wide cache directory bundler/gems; the second time, it's set to the
+ # vendor/cache directory. We don't want the native extension to appear in
+ # either of these places, so run the `bundle cache` command twice.
+ 2.times do
+ bundle :cache, "all-platforms" => true, :install => false
+
+ # it did _NOT_ actually install the gem - neither in $GEM_HOME (bundler 2 mode),
+ # nor in .bundle (bundler 3 mode)
+ expect(Pathname.new(File.join(default_bundle_path, "gems/foo-1.0-#{ref}"))).to_not exist
+ # it _did_ cache the gem in vendor/
+ expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist
+ # it did _NOT_ build the gems extensions in the vendor/ dir
+ expect(Dir[bundled_app("vendor/cache/foo-1.0-#{ref}/lib/foo_c*")]).to be_empty
+ # it _did_ cache the git checkout
+ expect(default_cache_path("git", cache_path_name)).to exist
+ # And the checkout is a bare checkout
+ expect(default_cache_path("git", cache_path_name, "HEAD")).to exist
+ end
+
+ # Subsequently installing the gem should compile it.
+ # _currently_, the gem gets compiled in vendor/cache, and vendor/cache is added
+ # to the $LOAD_PATH for git extensions, so it all kind of "works". However, in the
+ # future we would like to stop adding vendor/cache to the $LOAD_PATH for git extensions
+ # and instead treat them identically to normal gems (where the gem install location,
+ # not the cache location, is added to $LOAD_PATH).
+ # Verify that the compilation worked and the result is in $LOAD_PATH by simply attempting
+ # to require it; that should make sure this spec does not break if the load path behaviour
+ # is changed.
+ bundle :install, local: true
+ ruby <<~R, raise_on_error: false
+ require 'bundler/setup'
+ require 'foo_c'
+ R
+ expect(last_command).to_not be_failure
+ end
end
diff --git a/spec/bundler/cache/path_spec.rb b/spec/bundler/cache/path_spec.rb
index 2ad136a008..2c8a52617a 100644
--- a/spec/bundler/cache/path_spec.rb
+++ b/spec/bundler/cache/path_spec.rb
@@ -2,7 +2,7 @@
RSpec.describe "bundle cache with path" do
it "is no-op when the path is within the bundle" do
- build_lib "foo", :path => bundled_app("lib/foo")
+ build_lib "foo", path: bundled_app("lib/foo")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -35,7 +35,7 @@ RSpec.describe "bundle cache with path" do
libname = File.basename(bundled_app) + "_gem"
libpath = File.join(File.dirname(bundled_app), libname)
- build_lib libname, :path => libpath
+ build_lib libname, path: libpath
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -97,7 +97,7 @@ RSpec.describe "bundle cache with path" do
expect(bundled_app("vendor/cache/foo-1.0")).not_to exist
end
- it "does not cache path gems by default", :bundler => "< 3" do
+ it "does not cache path gems by default", bundler: "< 3" do
build_lib "foo"
install_gemfile <<-G
@@ -110,7 +110,7 @@ RSpec.describe "bundle cache with path" do
expect(bundled_app("vendor/cache/foo-1.0")).not_to exist
end
- it "caches path gems by default", :bundler => "3" do
+ it "caches path gems by default", bundler: "3" do
build_lib "foo"
install_gemfile <<-G
@@ -163,7 +163,7 @@ RSpec.describe "bundle cache with path" do
gem "baz", :path => '#{lib_path("baz-1.0")}'
G
- bundle "cache --no-all", :raise_on_error => false
+ bundle "cache --no-all", raise_on_error: false
expect(bundled_app("vendor/cache/baz-1.0")).not_to exist
end
end
diff --git a/spec/bundler/cache/platform_spec.rb b/spec/bundler/cache/platform_spec.rb
index 128278956c..36db954c79 100644
--- a/spec/bundler/cache/platform_spec.rb
+++ b/spec/bundler/cache/platform_spec.rb
@@ -41,7 +41,7 @@ RSpec.describe "bundle cache with multiple platforms" do
end
it "ensures that a successful bundle update does not delete gems for other platforms" do
- bundle "update", :all => true
+ bundle "update", all: true
expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
expect(bundled_app("vendor/cache/activesupport-2.3.5.gem")).to exist
diff --git a/spec/bundler/commands/add_spec.rb b/spec/bundler/commands/add_spec.rb
index 4c533652ca..36e286793b 100644
--- a/spec/bundler/commands/add_spec.rb
+++ b/spec/bundler/commands/add_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe "bundle add" do
build_gem "bar", "0.12.3"
build_gem "cat", "0.12.3.pre"
build_gem "dog", "1.1.3.pre"
+ build_gem "lemur", "3.1.1.pre.2023.1.1"
end
build_git "foo", "2.0"
@@ -21,7 +22,7 @@ RSpec.describe "bundle add" do
context "when no gems are specified" do
it "shows error" do
- bundle "add", :raise_on_error => false
+ bundle "add", raise_on_error: false
expect(err).to include("Please specify gems to add")
end
@@ -51,6 +52,13 @@ RSpec.describe "bundle add" do
expect(bundled_app_gemfile.read).to match(/gem "dog", "~> 1.1.pre"/)
expect(the_bundle).to include_gems "dog 1.1.3.pre"
end
+
+ it "version requirement becomes ~> major.minor.pre.tail when resolved version has a very long tail pre version" do
+ bundle "add 'lemur'"
+ # the trailing pre purposely matches the release version to ensure that subbing the release doesn't change the pre.version"
+ expect(bundled_app_gemfile.read).to match(/gem "lemur", "~> 3.1.pre.2023.1.1"/)
+ expect(the_bundle).to include_gems "lemur 3.1.1.pre.2023.1.1"
+ end
end
describe "with --version" do
@@ -63,11 +71,23 @@ RSpec.describe "bundle add" do
it "adds multiple version constraints when specified" do
requirements = ["< 3.0", "> 1.0"]
bundle "add 'foo' --version='#{requirements.join(", ")}'"
- expect(bundled_app_gemfile.read).to match(/gem "foo", #{Gem::Requirement.new(requirements).as_list.map(&:dump).join(', ')}/)
+ expect(bundled_app_gemfile.read).to match(/gem "foo", #{Gem::Requirement.new(requirements).as_list.map(&:dump).join(", ")}/)
expect(the_bundle).to include_gems "foo 2.0"
end
end
+ describe "with --require" do
+ it "adds the require param for the gem" do
+ bundle "add 'foo' --require=foo/engine"
+ expect(bundled_app_gemfile.read).to match(%r{gem "foo",(?: .*,) :require => "foo\/engine"})
+ end
+
+ it "converts false to a boolean" do
+ bundle "add 'foo' --require=false"
+ expect(bundled_app_gemfile.read).to match(/gem "foo",(?: .*,) :require => false/)
+ end
+ end
+
describe "with --group" do
it "adds dependency for the specified group" do
bundle "add 'foo' --group='development'"
@@ -91,8 +111,17 @@ RSpec.describe "bundle add" do
end
end
+ describe "with --path" do
+ it "adds dependency with specified path" do
+ bundle "add 'foo' --path='#{lib_path("foo-2.0")}'"
+
+ expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", :path => "#{lib_path("foo-2.0")}"/)
+ expect(the_bundle).to include_gems "foo 2.0"
+ end
+ end
+
describe "with --git" do
- it "adds dependency with specified github source" do
+ it "adds dependency with specified git source" do
bundle "add foo --git=#{lib_path("foo-2.0")}"
expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", :git => "#{lib_path("foo-2.0")}"/)
@@ -102,10 +131,10 @@ RSpec.describe "bundle add" do
describe "with --git and --branch" do
before do
- update_git "foo", "2.0", :branch => "test"
+ update_git "foo", "2.0", branch: "test"
end
- it "adds dependency with specified github source and branch" do
+ it "adds dependency with specified git source and branch" do
bundle "add foo --git=#{lib_path("foo-2.0")} --branch=test"
expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", :git => "#{lib_path("foo-2.0")}", :branch => "test"/)
@@ -113,6 +142,94 @@ RSpec.describe "bundle add" do
end
end
+ describe "with --git and --ref" do
+ it "adds dependency with specified git source and branch" do
+ bundle "add foo --git=#{lib_path("foo-2.0")} --ref=#{revision_for(lib_path("foo-2.0"))}"
+
+ expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2\.0", :git => "#{lib_path("foo-2.0")}", :ref => "#{revision_for(lib_path("foo-2.0"))}"/)
+ expect(the_bundle).to include_gems "foo 2.0"
+ end
+ end
+
+ describe "with --github" do
+ it "adds dependency with specified github source", :realworld do
+ bundle "add rake --github=ruby/rake"
+
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake"})
+ end
+ end
+
+ describe "with --github and --branch" do
+ it "adds dependency with specified github source and branch", :realworld do
+ bundle "add rake --github=ruby/rake --branch=master"
+
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :branch => "master"})
+ end
+ end
+
+ describe "with --github and --ref" do
+ it "adds dependency with specified github source and ref", :realworld do
+ bundle "add rake --github=ruby/rake --ref=5c60da8"
+
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :ref => "5c60da8"})
+ end
+ end
+
+ describe "with --git and --glob" do
+ it "adds dependency with specified git source" do
+ bundle "add foo --git=#{lib_path("foo-2.0")} --glob='./*.gemspec'"
+
+ expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2.0", :git => "#{lib_path("foo-2.0")}", :glob => "\./\*\.gemspec"})
+ expect(the_bundle).to include_gems "foo 2.0"
+ end
+ end
+
+ describe "with --git and --branch and --glob" do
+ before do
+ update_git "foo", "2.0", branch: "test"
+ end
+
+ it "adds dependency with specified git source and branch" do
+ bundle "add foo --git=#{lib_path("foo-2.0")} --branch=test --glob='./*.gemspec'"
+
+ expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2.0", :git => "#{lib_path("foo-2.0")}", :branch => "test", :glob => "\./\*\.gemspec"})
+ expect(the_bundle).to include_gems "foo 2.0"
+ end
+ end
+
+ describe "with --git and --ref and --glob" do
+ it "adds dependency with specified git source and branch" do
+ bundle "add foo --git=#{lib_path("foo-2.0")} --ref=#{revision_for(lib_path("foo-2.0"))} --glob='./*.gemspec'"
+
+ expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2\.0", :git => "#{lib_path("foo-2.0")}", :ref => "#{revision_for(lib_path("foo-2.0"))}", :glob => "\./\*\.gemspec"})
+ expect(the_bundle).to include_gems "foo 2.0"
+ end
+ end
+
+ describe "with --github and --glob" do
+ it "adds dependency with specified github source", :realworld do
+ bundle "add rake --github=ruby/rake --glob='./*.gemspec'"
+
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :glob => "\.\/\*\.gemspec"})
+ end
+ end
+
+ describe "with --github and --branch --and glob" do
+ it "adds dependency with specified github source and branch", :realworld do
+ bundle "add rake --github=ruby/rake --branch=master --glob='./*.gemspec'"
+
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :branch => "master", :glob => "\.\/\*\.gemspec"})
+ end
+ end
+
+ describe "with --github and --ref and --glob" do
+ it "adds dependency with specified github source and ref", :realworld do
+ bundle "add rake --github=ruby/rake --ref=5c60da8 --glob='./*.gemspec'"
+
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :ref => "5c60da8", :glob => "\.\/\*\.gemspec"})
+ end
+ end
+
describe "with --skip-install" do
it "adds gem to Gemfile but is not installed" do
bundle "add foo --skip-install --version=2.0"
@@ -129,24 +246,24 @@ RSpec.describe "bundle add" do
end
it "shows error message when version is not formatted correctly" do
- bundle "add 'foo' -v='~>1 . 0'", :raise_on_error => false
+ bundle "add 'foo' -v='~>1 . 0'", raise_on_error: false
expect(err).to match("Invalid gem requirement pattern '~>1 . 0'")
end
it "shows error message when gem cannot be found" do
bundle "config set force_ruby_platform true"
- bundle "add 'werk_it'", :raise_on_error => false
+ bundle "add 'werk_it'", raise_on_error: false
expect(err).to match("Could not find gem 'werk_it' in")
- bundle "add 'werk_it' -s='#{file_uri_for(gem_repo2)}'", :raise_on_error => false
+ bundle "add 'werk_it' -s='#{file_uri_for(gem_repo2)}'", raise_on_error: false
expect(err).to match("Could not find gem 'werk_it' in rubygems repository")
end
it "shows error message when source cannot be reached" do
- bundle "add 'baz' --source='http://badhostasdf'", :raise_on_error => false
+ bundle "add 'baz' --source='http://badhostasdf'", raise_on_error: false
expect(err).to include("Could not reach host badhostasdf. Check your network connection and try again.")
- bundle "add 'baz' --source='file://does/not/exist'", :raise_on_error => false
+ bundle "add 'baz' --source='file://does/not/exist'", raise_on_error: false
expect(err).to include("Could not fetch specs from file://does/not/exist/")
end
@@ -176,7 +293,7 @@ RSpec.describe "bundle add" do
describe "with --optimistic and --strict" do
it "throws error" do
- bundle "add 'foo' --strict --optimistic", :raise_on_error => false
+ bundle "add 'foo' --strict --optimistic", raise_on_error: false
expect(err).to include("You can not specify `--strict` and `--optimistic` at the same time")
end
@@ -191,7 +308,7 @@ RSpec.describe "bundle add" do
end
it "throws error if any of the specified gems are present in the gemfile with different version" do
- bundle "add weakling bar", :raise_on_error => false
+ bundle "add weakling bar", raise_on_error: false
expect(err).to include("You cannot specify the same gem twice with different version requirements")
expect(err).to include("You specified: weakling (~> 0.0.1) and weakling (>= 0).")
@@ -205,7 +322,7 @@ RSpec.describe "bundle add" do
gem "rack", "1.0"
G
- bundle "add 'rack' --version=1.1", :raise_on_error => false
+ bundle "add 'rack' --version=1.1", raise_on_error: false
expect(err).to include("You cannot specify the same gem twice with different version requirements")
expect(err).to include("If you want to update the gem version, run `bundle update rack`. You may also need to change the version requirement specified in the Gemfile if it's too restrictive")
@@ -217,7 +334,7 @@ RSpec.describe "bundle add" do
gem "rack", "1.0"
G
- bundle "add 'rack'", :raise_on_error => false
+ bundle "add 'rack'", raise_on_error: false
expect(err).to include("Gem already added.")
expect(err).to include("You cannot specify the same gem twice with different version requirements")
@@ -232,7 +349,7 @@ RSpec.describe "bundle add" do
gem "rack"
G
- bundle "add 'rack' --version=1.1", :raise_on_error => false
+ bundle "add 'rack' --version=1.1", raise_on_error: false
expect(err).to include("You cannot specify the same gem twice with different version requirements")
expect(err).to include("If you want to update the gem version, run `bundle update rack`.")
diff --git a/spec/bundler/commands/binstubs_spec.rb b/spec/bundler/commands/binstubs_spec.rb
index fb5da98bf3..6c3dc7bb2d 100644
--- a/spec/bundler/commands/binstubs_spec.rb
+++ b/spec/bundler/commands/binstubs_spec.rb
@@ -45,7 +45,7 @@ RSpec.describe "bundle binstubs <gem>" do
gem "rails"
G
- bundle :binstubs, :all => true
+ bundle :binstubs, all: true
expect(bundled_app("bin/rails")).to exist
expect(bundled_app("bin/rake")).to exist
@@ -69,7 +69,7 @@ RSpec.describe "bundle binstubs <gem>" do
gem "rack"
G
- bundle "binstubs", :raise_on_error => false
+ bundle "binstubs", raise_on_error: false
expect(exitstatus).to eq(1)
expect(err).to include("`bundle binstubs` needs at least one gem to run.")
end
@@ -80,7 +80,7 @@ RSpec.describe "bundle binstubs <gem>" do
gem "rack"
G
- bundle "binstubs rack", :all => true, :raise_on_error => false
+ bundle "binstubs rack", all: true, raise_on_error: false
expect(last_command).to be_failure
expect(err).to include("Cannot specify --all with specific gems")
end
@@ -98,7 +98,7 @@ RSpec.describe "bundle binstubs <gem>" do
file.print "OMG"
end
- sys_exec "bin/rackup", :raise_on_error => false
+ sys_exec "bin/rackup", raise_on_error: false
expect(err).to include("was not generated by Bundler")
end
@@ -116,7 +116,7 @@ RSpec.describe "bundle binstubs <gem>" do
s.executables = "print_loaded_gems"
s.bindir = "exe"
s.write "exe/print_loaded_gems", <<-R
- specs = Gem.loaded_specs.values.reject {|s| Bundler.rubygems.spec_default_gem?(s) }
+ specs = Gem.loaded_specs.values.reject {|s| s.default_gem? }
puts specs.map(&:full_name).sort.inspect
R
end
@@ -132,13 +132,13 @@ RSpec.describe "bundle binstubs <gem>" do
let(:system_bundler_version) { Bundler::VERSION }
it "runs bundler" do
- sys_exec "bin/bundle install", :env => { "DEBUG" => "1" }
+ sys_exec "bin/bundle install", env: { "DEBUG" => "1" }
expect(out).to include %(Using bundler #{system_bundler_version}\n)
end
context "when BUNDLER_VERSION is set" do
it "runs the correct version of bundler" do
- sys_exec "bin/bundle install", :env => { "BUNDLER_VERSION" => "999.999.999" }, :raise_on_error => false
+ sys_exec "bin/bundle install", env: { "BUNDLER_VERSION" => "999.999.999" }, raise_on_error: false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (999.999.999) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '999.999.999'`")
@@ -147,7 +147,7 @@ RSpec.describe "bundle binstubs <gem>" do
it "runs the correct version of bundler even if a higher version is installed" do
system_gems "bundler-999.999.998", "bundler-999.999.999"
- sys_exec "bin/bundle install", :env => { "BUNDLER_VERSION" => "999.999.998", "DEBUG" => "1" }, :raise_on_error => false
+ sys_exec "bin/bundle install", env: { "BUNDLER_VERSION" => "999.999.998", "DEBUG" => "1" }, raise_on_error: false
expect(out).to include %(Using bundler 999.999.998\n)
end
end
@@ -159,7 +159,22 @@ RSpec.describe "bundle binstubs <gem>" do
end
it "runs the correct version of bundler" do
- sys_exec "bin/bundle install", :raise_on_error => false
+ sys_exec "bin/bundle install", raise_on_error: false
+ expect(exitstatus).to eq(42)
+ expect(err).to include("Activating bundler (~> 999.999) failed:").
+ and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 999.999'`")
+ end
+ end
+
+ context "and the version is newer when given `gems.rb` and `gems.locked`" do
+ before do
+ gemfile bundled_app("gems.rb"), gemfile
+ lockfile bundled_app("gems.locked"), lockfile.gsub(system_bundler_version, "999.999")
+ end
+
+ it "runs the correct version of bundler" do
+ sys_exec "bin/bundle install", env: { "BUNDLE_GEMFILE" => "gems.rb" }, raise_on_error: false
+
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 999.999) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 999.999'`")
@@ -174,7 +189,23 @@ RSpec.describe "bundle binstubs <gem>" do
end
it "runs the correct version of bundler" do
- sys_exec "bin/bundle install", :raise_on_error => false
+ sys_exec "bin/bundle install", raise_on_error: false
+ expect(exitstatus).to eq(42)
+ expect(err).to include("Activating bundler (~> 44.0) failed:").
+ and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 44.0'`")
+ end
+ end
+
+ context "and the version is older and a different major when given `gems.rb` and `gems.locked`" do
+ let(:system_bundler_version) { "55" }
+
+ before do
+ gemfile bundled_app("gems.rb"), gemfile
+ lockfile bundled_app("gems.locked"), lockfile.gsub(/BUNDLED WITH\n .*$/m, "BUNDLED WITH\n 44.0")
+ end
+
+ it "runs the correct version of bundler" do
+ sys_exec "bin/bundle install", env: { "BUNDLE_GEMFILE" => "gems.rb" }, raise_on_error: false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 44.0) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 44.0'`")
@@ -182,16 +213,26 @@ RSpec.describe "bundle binstubs <gem>" do
end
context "and the version is older and the same major" do
- let(:system_bundler_version) { "55.1" }
+ let(:system_bundler_version) { "2.999.999" }
before do
- lockfile lockfile.gsub(/BUNDLED WITH\n .*$/m, "BUNDLED WITH\n 55.0")
+ lockfile lockfile.gsub(/BUNDLED WITH\n .*$/m, "BUNDLED WITH\n 2.3.0")
end
- it "runs the available version of bundler when the version is older and the same major" do
- sys_exec "bin/bundle install"
+ it "installs and runs the exact version of bundler", rubygems: ">= 3.3.0.dev", realworld: true do
+ sys_exec "bin/bundle install --verbose", artifice: "vcr"
expect(exitstatus).not_to eq(42)
- expect(err).not_to include("Activating bundler (~> 55.0) failed:")
+ expect(out).to include("Bundler 2.999.999 is running, but your lockfile was generated with 2.3.0. Installing Bundler 2.3.0 and restarting using that version.")
+ expect(out).to include("Using bundler 2.3.0")
+ expect(err).not_to include("Activating bundler (~> 2.3.0) failed:")
+ end
+
+ it "runs the available version of bundler", rubygems: "< 3.3.0.dev" do
+ sys_exec "bin/bundle install --verbose"
+ expect(exitstatus).not_to eq(42)
+ expect(out).not_to include("Bundler 2.999.999 is running, but your lockfile was generated with 2.3.0. Installing Bundler 2.3.0 and restarting using that version.")
+ expect(out).to include("Using bundler 2.999.999")
+ expect(err).not_to include("Activating bundler (~> 2.3.0) failed:")
end
end
@@ -203,7 +244,7 @@ RSpec.describe "bundle binstubs <gem>" do
end
it "runs the correct version of bundler when the version is a pre-release" do
- sys_exec "bin/bundle install", :raise_on_error => false
+ sys_exec "bin/bundle install", raise_on_error: false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 2.12.a) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 2.12.a'`")
@@ -214,13 +255,16 @@ RSpec.describe "bundle binstubs <gem>" do
context "when update --bundler is called" do
before { lockfile.gsub(system_bundler_version, "1.1.1") }
- it "calls through to the latest bundler version" do
- sys_exec "bin/bundle update --bundler", :env => { "DEBUG" => "1" }
- expect(out).to include %(Using bundler #{system_bundler_version}\n)
+ it "calls through to the latest bundler version", :realworld do
+ sys_exec "bin/bundle update --bundler", env: { "DEBUG" => "1" }
+ using_bundler_line = /Using bundler ([\w\.]+)\n/.match(out)
+ expect(using_bundler_line).to_not be_nil
+ latest_version = using_bundler_line[1]
+ expect(Gem::Version.new(latest_version)).to be >= Gem::Version.new(system_bundler_version)
end
it "calls through to the explicit bundler version" do
- sys_exec "bin/bundle update --bundler=999.999.999", :raise_on_error => false
+ sys_exec "bin/bundle update --bundler=999.999.999", raise_on_error: false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (999.999.999) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '999.999.999'`")
@@ -230,7 +274,7 @@ RSpec.describe "bundle binstubs <gem>" do
context "without a lockfile" do
it "falls back to the latest installed bundler" do
FileUtils.rm bundled_app_lock
- sys_exec "bin/bundle install", :env => { "DEBUG" => "1" }
+ sys_exec "bin/bundle install", env: { "DEBUG" => "1" }
expect(out).to include "Using bundler #{system_bundler_version}\n"
end
end
@@ -245,7 +289,7 @@ RSpec.describe "bundle binstubs <gem>" do
before { lockfile lockfile.gsub(Bundler::VERSION, "999.999.999") }
it "attempts to load that version" do
- sys_exec bundled_app("bin/rackup").to_s, :raise_on_error => false
+ sys_exec bundled_app("bin/rackup").to_s, raise_on_error: false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 999.999) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 999.999'`")
@@ -257,7 +301,7 @@ RSpec.describe "bundle binstubs <gem>" do
it "installs binstubs from git gems" do
FileUtils.mkdir_p(lib_path("foo/bin"))
FileUtils.touch(lib_path("foo/bin/foo"))
- build_git "foo", "1.0", :path => lib_path("foo") do |s|
+ build_git "foo", "1.0", path: lib_path("foo") do |s|
s.executables = %w[foo]
end
install_gemfile <<-G
@@ -273,7 +317,7 @@ RSpec.describe "bundle binstubs <gem>" do
it "installs binstubs from path gems" do
FileUtils.mkdir_p(lib_path("foo/bin"))
FileUtils.touch(lib_path("foo/bin/foo"))
- build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ build_lib "foo", "1.0", path: lib_path("foo") do |s|
s.executables = %w[foo]
end
install_gemfile <<-G
@@ -287,8 +331,6 @@ RSpec.describe "bundle binstubs <gem>" do
end
it "sets correct permissions for binstubs" do
- skip "https://github.com/rubygems/rubygems/issues/3352" if Gem.win_platform?
-
with_umask(0o002) do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -297,7 +339,7 @@ RSpec.describe "bundle binstubs <gem>" do
bundle "binstubs rack"
binary = bundled_app("bin/rackup")
- expect(File.stat(binary).mode.to_s(8)).to eq("100775")
+ expect(File.stat(binary).mode.to_s(8)).to eq(Gem.win_platform? ? "100644" : "100775")
end
end
@@ -320,7 +362,7 @@ RSpec.describe "bundle binstubs <gem>" do
source "#{file_uri_for(gem_repo1)}"
G
- bundle "binstubs doesnt_exist", :raise_on_error => false
+ bundle "binstubs doesnt_exist", raise_on_error: false
expect(exitstatus).to eq(7)
expect(err).to include("Could not find gem 'doesnt_exist'.")
@@ -339,14 +381,14 @@ RSpec.describe "bundle binstubs <gem>" do
expect(bundled_app("exec/rackup")).to exist
end
- it "setting is saved for bundle install", :bundler => "< 3" do
+ it "setting is saved for bundle install", bundler: "< 3" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
gem "rails"
G
- bundle "binstubs rack", :path => "exec"
+ bundle "binstubs rack", path: "exec"
bundle :install
expect(bundled_app("exec/rails")).to exist
@@ -358,6 +400,7 @@ RSpec.describe "bundle binstubs <gem>" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
+ gem "rails"
G
end
@@ -385,6 +428,26 @@ RSpec.describe "bundle binstubs <gem>" do
expect(bundled_app("bin/rackup.cmd")).to exist
end
end
+
+ context "when the gem is bundler" do
+ it "warns without generating a standalone binstub" do
+ bundle "binstubs bundler --standalone"
+ expect(bundled_app("bin/bundle")).not_to exist
+ expect(bundled_app("bin/bundler")).not_to exist
+ expect(err).to include("Sorry, Bundler can only be run via RubyGems.")
+ end
+ end
+
+ context "when specified --all option" do
+ it "generates standalone binstubs for all gems except bundler" do
+ bundle "binstubs --standalone --all"
+ expect(bundled_app("bin/rackup")).to exist
+ expect(bundled_app("bin/rails")).to exist
+ expect(bundled_app("bin/bundle")).not_to exist
+ expect(bundled_app("bin/bundler")).not_to exist
+ expect(err).not_to include("Sorry, Bundler can only be run via RubyGems.")
+ end
+ end
end
context "when the bin already exists" do
@@ -486,7 +549,7 @@ RSpec.describe "bundle binstubs <gem>" do
G
bundle "config set auto_install 1"
- bundle "binstubs rack", :env => { "BUNDLE_INSTALL" => "1" }
+ bundle "binstubs rack", env: { "BUNDLE_INSTALL" => "1" }
expect(out).not_to include("Installing rack 1.0.0")
end
end
diff --git a/spec/bundler/commands/cache_spec.rb b/spec/bundler/commands/cache_spec.rb
index 4f9c1c26c4..70e2c84961 100644
--- a/spec/bundler/commands/cache_spec.rb
+++ b/spec/bundler/commands/cache_spec.rb
@@ -158,7 +158,7 @@ RSpec.describe "bundle cache" do
end
end
- context "with --path", :bundler => "< 3" do
+ context "with --path", bundler: "< 3" do
it "sets root directory for gems" do
gemfile <<-D
source "#{file_uri_for(gem_repo1)}"
@@ -211,7 +211,17 @@ RSpec.describe "bundle cache" do
end
context "with --all-platforms" do
- it "puts the gems in vendor/cache even for other rubies" do
+ it "puts the gems in vendor/cache even for other rubies", bundler: ">= 2.4.0" do
+ gemfile <<-D
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack', :platforms => [:ruby_20, :windows_20]
+ D
+
+ bundle "cache --all-platforms"
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
+ end
+
+ it "puts the gems in vendor/cache even for legacy windows rubies", bundler: ">= 2.4.0" do
gemfile <<-D
source "#{file_uri_for(gem_repo1)}"
gem 'rack', :platforms => [:ruby_20, :x64_mingw_20]
@@ -262,7 +272,7 @@ RSpec.describe "bundle cache" do
end
G
- bundle :lock, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
+ 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
@@ -279,7 +289,7 @@ RSpec.describe "bundle cache" do
subject do
bundle "config set --local frozen true"
- bundle :cache, :raise_on_error => false
+ bundle :cache, raise_on_error: false
end
it "tries to install with frozen" do
@@ -291,7 +301,7 @@ RSpec.describe "bundle cache" do
G
subject
expect(exitstatus).to eq(16)
- expect(err).to include("deployment mode")
+ expect(err).to include("frozen mode")
expect(err).to include("You have added to the Gemfile")
expect(err).to include("* rack-obama")
bundle "env"
@@ -383,7 +393,7 @@ RSpec.describe "bundle install with gem sources" do
G
bundle :cache
- build_gem "rack", "1.0.0", :path => bundled_app("vendor/cache") do |s|
+ build_gem "rack", "1.0.0", path: bundled_app("vendor/cache") do |s|
s.write "lib/rack.rb", "raise 'omg'"
end
@@ -403,14 +413,14 @@ RSpec.describe "bundle install with gem sources" do
simulate_new_machine
- simulate_platform "ruby" do
- install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "platform_specific"
- G
- run "require 'platform_specific' ; puts PLATFORM_SPECIFIC"
- expect(out).to eq("1.0.0 RUBY")
- end
+ bundle "config set --local force_ruby_platform true"
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "platform_specific"
+ G
+ run "require 'platform_specific' ; puts PLATFORM_SPECIFIC"
+ expect(out).to eq("1.0.0 RUBY")
end
it "does not update the cache if --no-cache is passed" do
diff --git a/spec/bundler/commands/check_spec.rb b/spec/bundler/commands/check_spec.rb
index c48220f8df..02f9bb5b7a 100644
--- a/spec/bundler/commands/check_spec.rb
+++ b/spec/bundler/commands/check_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe "bundle check" do
gem "rails"
G
- bundle "check --gemfile bundled_app/Gemfile", :dir => tmp
+ bundle "check --gemfile bundled_app/Gemfile", dir: tmp
expect(out).to include("The Gemfile's dependencies are satisfied")
end
@@ -55,7 +55,7 @@ RSpec.describe "bundle check" do
gem "rails"
G
- bundle :check, :raise_on_error => false
+ bundle :check, raise_on_error: false
expect(err).to include("Bundler can't satisfy your Gemfile's dependencies.")
end
@@ -65,7 +65,7 @@ RSpec.describe "bundle check" do
gem "rails"
G
- bundle :check, :raise_on_error => false
+ bundle :check, raise_on_error: false
expect(exitstatus).to be > 0
expect(err).to include("Bundler can't satisfy your Gemfile's dependencies.")
end
@@ -88,11 +88,11 @@ RSpec.describe "bundle check" do
gem "rails_pinned_to_old_activesupport"
G
- bundle :check, :raise_on_error => false
+ bundle :check, raise_on_error: false
expect(err).to include("Bundler can't satisfy your Gemfile's dependencies.")
end
- it "remembers --without option from install", :bundler => "< 3" do
+ it "remembers --without option from install", bundler: "< 3" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
group :foo do
@@ -132,7 +132,23 @@ RSpec.describe "bundle check" do
gem "rack"
G
- bundle "check", :raise_on_error => false
+ bundle "check", raise_on_error: false
+ expect(err).to include("* rack (1.0.0)")
+ expect(exitstatus).to eq(1)
+ end
+
+ it "ensures that gems are actually installed and not just cached in applications' cache" do
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ G
+
+ bundle "config set --local path vendor/bundle"
+ bundle :cache
+
+ gem_command "uninstall rack", env: { "GEM_HOME" => vendored_gems.to_s }
+
+ bundle "check", raise_on_error: false
expect(err).to include("* rack (1.0.0)")
expect(exitstatus).to eq(1)
end
@@ -146,7 +162,7 @@ RSpec.describe "bundle check" do
end
G
- system_gems "rack-1.0.0", :path => default_bundle_path
+ system_gems "rack-1.0.0", path: default_bundle_path
lockfile <<-G
GEM
@@ -156,7 +172,7 @@ RSpec.describe "bundle check" do
rack (1.0.0)
PLATFORMS
- #{local}
+ #{generic_local_platform}
#{not_local}
DEPENDENCIES
@@ -177,7 +193,7 @@ RSpec.describe "bundle check" do
end
G
- system_gems "rack-1.0.0", :path => default_bundle_path
+ system_gems "rack-1.0.0", path: default_bundle_path
lockfile <<-G
GEM
@@ -187,7 +203,7 @@ RSpec.describe "bundle check" do
rack (1.0.0)
PLATFORMS
- #{local}
+ #{generic_local_platform}
#{not_local}
DEPENDENCIES
@@ -200,13 +216,13 @@ RSpec.describe "bundle check" do
end
it "outputs an error when the default Gemfile is not found" do
- bundle :check, :raise_on_error => false
+ bundle :check, raise_on_error: false
expect(exitstatus).to eq(10)
expect(err).to include("Could not locate Gemfile")
end
it "does not output fatal error message" do
- bundle :check, :raise_on_error => false
+ bundle :check, raise_on_error: false
expect(exitstatus).to eq(10)
expect(err).not_to include("Unfortunately, a fatal error has occurred. ")
end
@@ -221,11 +237,11 @@ RSpec.describe "bundle check" do
bundle "install"
FileUtils.rm(bundled_app_lock)
- bundle :check, :raise_on_error => false
+ bundle :check, raise_on_error: false
expect(last_command).to be_failure
end
- context "--path", :bundler => "< 3" do
+ context "--path", bundler: "< 3" do
context "after installing gems in the proper directory" do
before do
gemfile <<-G
@@ -255,7 +271,7 @@ RSpec.describe "bundle check" do
gem "rails"
G
- bundle "check --path vendor/bundle", :raise_on_error => false
+ bundle "check --path vendor/bundle", raise_on_error: false
end
it "returns false" do
@@ -282,7 +298,7 @@ RSpec.describe "bundle check" do
it "shows what is missing with the current Gemfile if it is not satisfied" do
simulate_new_machine
- bundle :check, :raise_on_error => false
+ bundle :check, raise_on_error: false
expect(err).to match(/The following gems are missing/)
expect(err).to include("* rack (1.0")
end
@@ -310,7 +326,43 @@ RSpec.describe "bundle check" do
end
it "shows what is missing with the current Gemfile without duplications" do
- bundle :check, :raise_on_error => false
+ bundle :check, raise_on_error: false
+ expect(err).to match(/The following gems are missing/)
+ expect(err).to include("* rack (1.0").once
+ end
+ end
+
+ describe "when locked under multiple platforms" do
+ before :each do
+ build_repo4 do
+ build_gem "rack"
+ end
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ rack (1.0)
+
+ PLATFORMS
+ ruby
+ #{local_platform}
+
+ DEPENDENCIES
+ rack
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "shows what is missing with the current Gemfile without duplications" do
+ bundle :check, raise_on_error: false
expect(err).to match(/The following gems are missing/)
expect(err).to include("* rack (1.0").once
end
@@ -327,7 +379,7 @@ RSpec.describe "bundle check" do
end
it "returns success when the Gemfile is satisfied" do
- system_gems "rack-1.0.0", :path => default_bundle_path
+ system_gems "rack-1.0.0", path: default_bundle_path
bundle :check
expect(out).to include("The Gemfile's dependencies are satisfied")
end
@@ -352,8 +404,14 @@ RSpec.describe "bundle check" do
end
it "returns success when the Gemfile is satisfied and generates a correct lockfile" do
- system_gems "depends_on_rack-1.0", "rack-1.0", :gem_repo => gem_repo4, :path => default_bundle_path
+ system_gems "depends_on_rack-1.0", "rack-1.0", gem_repo: gem_repo4, path: default_bundle_path
bundle :check
+
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "depends_on_rack", "1.0"
+ c.no_checksum "rack", "1.0"
+ end
+
expect(out).to include("The Gemfile's dependencies are satisfied")
expect(lockfile).to eq <<~L
GEM
@@ -372,7 +430,76 @@ RSpec.describe "bundle check" do
DEPENDENCIES
depends_on_rack!
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ context "with gemspec directive and scoped sources" do
+ before do
+ build_repo4 do
+ build_gem "awesome_print"
+ end
+
+ build_repo2 do
+ build_gem "dex-dispatch-engine"
+ end
+
+ build_lib("bundle-check-issue", path: tmp.join("bundle-check-issue")) do |s|
+ s.write "Gemfile", <<-G
+ source "https://localgemserver.test"
+
+ gemspec
+
+ source "https://localgemserver.test/extra" do
+ gem "dex-dispatch-engine"
+ end
+ G
+ s.add_dependency "awesome_print"
+ end
+
+ bundle "install", artifice: "compact_index_extra", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }, dir: tmp.join("bundle-check-issue")
+ end
+
+ it "does not corrupt lockfile when changing version" do
+ version_file = tmp.join("bundle-check-issue/bundle-check-issue.gemspec")
+ File.write(version_file, File.read(version_file).gsub(/s\.version = .+/, "s.version = '9999'"))
+
+ bundle "check --verbose", dir: tmp.join("bundle-check-issue")
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "awesome_print", "1.0"
+ c.no_checksum "bundle-check-issue", "9999"
+ c.checksum gem_repo2, "dex-dispatch-engine", "1.0"
+ end
+
+ expect(File.read(tmp.join("bundle-check-issue/Gemfile.lock"))).to eq <<~L
+ PATH
+ remote: .
+ specs:
+ bundle-check-issue (9999)
+ awesome_print
+
+ GEM
+ remote: https://localgemserver.test/
+ specs:
+ awesome_print (1.0)
+
+ GEM
+ remote: https://localgemserver.test/extra/
+ specs:
+ dex-dispatch-engine (1.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ bundle-check-issue!
+ dex-dispatch-engine!
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -381,7 +508,7 @@ RSpec.describe "bundle check" do
describe "BUNDLED WITH" do
def lock_with(bundler_version = nil)
- lock = <<-L
+ lock = <<~L
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
@@ -395,7 +522,7 @@ RSpec.describe "bundle check" do
L
if bundler_version
- lock += "\n BUNDLED WITH\n #{bundler_version}\n"
+ lock += "\nBUNDLED WITH\n #{bundler_version}\n"
end
lock
@@ -414,16 +541,16 @@ RSpec.describe "bundle check" do
it "does not change the lock" do
lockfile lock_with(nil)
bundle :check
- lockfile_should_be lock_with(nil)
+ expect(lockfile).to eq lock_with(nil)
end
end
context "is newer" do
- it "does not change the lock but warns" do
+ it "does not change the lock and does not warn" do
lockfile lock_with(Bundler::VERSION.succ)
bundle :check
- expect(err).to include("the running version of Bundler (#{Bundler::VERSION}) is older than the version that created the lockfile (#{Bundler::VERSION.succ})")
- lockfile_should_be lock_with(Bundler::VERSION.succ)
+ expect(err).to be_empty
+ expect(lockfile).to eq lock_with(Bundler::VERSION.succ)
end
end
@@ -432,7 +559,7 @@ RSpec.describe "bundle check" do
system_gems "bundler-1.18.0"
lockfile lock_with("1.18.0")
bundle :check
- lockfile_should_be lock_with("1.18.0")
+ expect(lockfile).to eq lock_with("1.18.0")
end
end
end
diff --git a/spec/bundler/commands/clean_spec.rb b/spec/bundler/commands/clean_spec.rb
index 4c04853bd3..0b559a87c8 100644
--- a/spec/bundler/commands/clean_spec.rb
+++ b/spec/bundler/commands/clean_spec.rb
@@ -156,7 +156,7 @@ RSpec.describe "bundle clean" do
end
it "removes unused git gems" do
- build_git "foo", :path => lib_path("foo")
+ build_git "foo", path: lib_path("foo")
git_path = lib_path("foo")
revision = revision_for(git_path)
@@ -194,7 +194,7 @@ RSpec.describe "bundle clean" do
end
it "keeps used git gems even if installed to a symlinked location" do
- build_git "foo", :path => lib_path("foo")
+ build_git "foo", path: lib_path("foo")
git_path = lib_path("foo")
revision = revision_for(git_path)
@@ -208,7 +208,7 @@ RSpec.describe "bundle clean" do
G
FileUtils.mkdir_p(bundled_app("real-path"))
- FileUtils.ln_sf(bundled_app("real-path"), bundled_app("symlink-path"))
+ File.symlink(bundled_app("real-path"), bundled_app("symlink-path"))
bundle "config set path #{bundled_app("symlink-path")}"
bundle "install"
@@ -221,7 +221,7 @@ RSpec.describe "bundle clean" do
end
it "removes old git gems" do
- build_git "foo-bar", :path => lib_path("foo-bar")
+ build_git "foo-bar", path: lib_path("foo-bar")
revision = revision_for(lib_path("foo-bar"))
gemfile <<-G
@@ -236,10 +236,10 @@ RSpec.describe "bundle clean" do
bundle "config set path vendor/bundle"
bundle "install"
- update_git "foo", :path => lib_path("foo-bar")
+ update_git "foo-bar", path: lib_path("foo-bar")
revision2 = revision_for(lib_path("foo-bar"))
- bundle "update", :all => true
+ bundle "update", all: true
bundle :clean
expect(out).to include("Removing foo-bar (#{revision[0..11]})")
@@ -254,8 +254,8 @@ RSpec.describe "bundle clean" do
end
it "does not remove nested gems in a git repo" do
- build_lib "activesupport", "3.0", :path => lib_path("rails/activesupport")
- build_git "rails", "3.0", :path => lib_path("rails") do |s|
+ build_lib "activesupport", "3.0", path: lib_path("rails/activesupport")
+ build_git "rails", "3.0", path: lib_path("rails") do |s|
s.add_dependency "activesupport", "= 3.0"
end
revision = revision_for(lib_path("rails"))
@@ -274,7 +274,7 @@ RSpec.describe "bundle clean" do
end
it "does not remove git sources that are in without groups" do
- build_git "foo", :path => lib_path("foo")
+ build_git "foo", path: lib_path("foo")
git_path = lib_path("foo")
revision = revision_for(git_path)
@@ -326,7 +326,7 @@ RSpec.describe "bundle clean" do
gem "rack", "1.0.0"
G
- bundle :clean, :raise_on_error => false
+ bundle :clean, raise_on_error: false
expect(exitstatus).to eq(15)
expect(err).to include("--force")
@@ -383,7 +383,7 @@ RSpec.describe "bundle clean" do
expect(out).to include("rack (1.0.0)").and include("thin (1.0)")
end
- it "--clean should override the bundle setting on install", :bundler => "< 3" do
+ it "--clean should override the bundle setting on install", bundler: "< 3" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -405,7 +405,7 @@ RSpec.describe "bundle clean" do
should_not_have_gems "thin-1.0"
end
- it "--clean should override the bundle setting on update", :bundler => "< 3" do
+ it "--clean should override the bundle setting on update", bundler: "< 3" do
build_repo2
gemfile <<-G
@@ -421,13 +421,13 @@ RSpec.describe "bundle clean" do
build_gem "foo", "1.0.1"
end
- bundle "update", :all => true
+ bundle "update", all: true
should_have_gems "foo-1.0.1"
should_not_have_gems "foo-1.0"
end
- it "automatically cleans when path has not been set", :bundler => "3" do
+ it "automatically cleans when path has not been set", bundler: "3" do
build_repo2
install_gemfile <<-G
@@ -440,7 +440,7 @@ RSpec.describe "bundle clean" do
build_gem "foo", "1.0.1"
end
- bundle "update", :all => true
+ bundle "update", all: true
files = Pathname.glob(bundled_app(".bundle", Bundler.ruby_scope, "*", "*"))
files.map! {|f| f.to_s.sub(bundled_app(".bundle", Bundler.ruby_scope).to_s, "") }
@@ -486,7 +486,7 @@ RSpec.describe "bundle clean" do
build_gem "foo", "1.0.1"
end
- bundle :update, :all => true
+ bundle :update, all: true
should_have_gems "foo-1.0", "foo-1.0.1"
end
@@ -505,7 +505,7 @@ RSpec.describe "bundle clean" do
update_repo2 do
build_gem "foo", "1.0.1"
end
- bundle :update, :all => true
+ bundle :update, all: true
gem_command :list
expect(out).to include("foo (1.0.1, 1.0)")
@@ -560,7 +560,7 @@ RSpec.describe "bundle clean" do
FileUtils.chmod(0o500, system_cache_path)
- bundle :clean, :force => true, :raise_on_error => false
+ bundle :clean, force: true, raise_on_error: false
expect(err).to include(system_gem_path.to_s)
expect(err).to include("grant write permissions")
@@ -625,28 +625,22 @@ RSpec.describe "bundle clean" do
expect(out).to eq("1.0")
end
- it "when using --force, it doesn't remove default gem binaries" do
- skip "does not work on ruby 3.0 because it changes the path to look for default gems, tsort is a default gem there, and we can't install it either like we do with fiddle because it doesn't yet exist" unless RUBY_VERSION < "3.0.0"
-
- skip "does not work on rubygems versions where `--install_dir` doesn't respect --default" unless Gem::Installer.for_spec(loaded_gemspec, :install_dir => "/foo").default_spec_file == "/foo/specifications/default/bundler-#{Bundler::VERSION}.gemspec" # Since rubygems 3.2.0.rc.2
-
- default_irb_version = ruby "gem 'irb', '< 999999'; require 'irb'; puts IRB::VERSION", :raise_on_error => false
+ it "when using --force, it doesn't remove default gem binaries", :realworld do
+ default_irb_version = ruby "gem 'irb', '< 999999'; require 'irb'; puts IRB::VERSION", raise_on_error: false
skip "irb isn't a default gem" if default_irb_version.empty?
- build_repo2 do
- # simulate executable for default gem
- build_gem "irb", default_irb_version, :to_system => true, :default => true do |s|
- s.executables = "irb"
- end
+ # simulate executable for default gem
+ build_gem "irb", default_irb_version, to_system: true, default: true do |s|
+ s.executables = "irb"
end
- realworld_system_gems "fiddle --version 1.0.0"
+ realworld_system_gems "tsort --version 0.1.0", "pathname --version 0.1.0", "set --version 1.0.1"
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
G
- bundle "clean --force", :env => { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }
+ bundle "clean --force", env: { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }
expect(out).not_to include("Removing irb")
end
@@ -789,7 +783,7 @@ RSpec.describe "bundle clean" do
should_not_have_gems "foo-1.0"
end
- it "doesn't remove extensions artifacts from bundled git gems after clean", :ruby_repo do
+ it "doesn't remove extensions artifacts from bundled git gems after clean" do
build_git "very_simple_git_binary", &:add_c_extension
revision = revision_for(lib_path("very_simple_git_binary-1.0"))
@@ -812,7 +806,7 @@ RSpec.describe "bundle clean" do
expect(vendored_gems("bundler/gems/very_simple_git_binary-1.0-#{revision[0..11]}")).to exist
end
- it "removes extension directories", :ruby_repo do
+ it "removes extension directories" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -848,7 +842,7 @@ RSpec.describe "bundle clean" do
expect(simple_binary_extensions_dir).to exist
end
- it "removes git extension directories", :ruby_repo do
+ it "removes git extension directories" do
build_git "very_simple_git_binary", &:add_c_extension
revision = revision_for(lib_path("very_simple_git_binary-1.0"))
@@ -907,7 +901,7 @@ RSpec.describe "bundle clean" do
bundle :lock
bundle "config set without development"
bundle "config set path vendor/bundle"
- bundle "install"
+ bundle "install", verbose: true
bundle :clean
very_simple_binary_extensions_dir =
diff --git a/spec/bundler/commands/config_spec.rb b/spec/bundler/commands/config_spec.rb
index 1ef84c8195..547fd2d869 100644
--- a/spec/bundler/commands/config_spec.rb
+++ b/spec/bundler/commands/config_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe ".bundle/config" do
context "with env overwrite" do
it "prints config with env" do
- bundle "config list --parseable", :env => { "BUNDLE_FOO" => "bar3" }
+ bundle "config list --parseable", env: { "BUNDLE_FOO" => "bar3" }
expect(out).to include("foo=bar3")
end
end
@@ -43,6 +43,12 @@ RSpec.describe ".bundle/config" do
G
end
+ it "is local by default" do
+ bundle "config set foo bar"
+ expect(bundled_app(".bundle/config")).to exist
+ expect(home(".bundle/config")).not_to exist
+ end
+
it "can be moved with an environment variable" do
ENV["BUNDLE_APP_CONFIG"] = tmp("foo/bar").to_s
bundle "config set --local path vendor/bundle"
@@ -58,15 +64,21 @@ RSpec.describe ".bundle/config" do
ENV["BUNDLE_APP_CONFIG"] = "../foo"
bundle "config set --local path vendor/bundle"
- bundle "install", :dir => bundled_app("omg")
+ bundle "install", dir: bundled_app("omg")
expect(bundled_app(".bundle")).not_to exist
expect(bundled_app("../foo/config")).to exist
- expect(the_bundle).to include_gems "rack 1.0.0", :dir => bundled_app("omg")
+ expect(the_bundle).to include_gems "rack 1.0.0", dir: bundled_app("omg")
end
end
describe "location without a gemfile" do
+ it "is global by default" do
+ bundle "config set foo bar"
+ expect(bundled_app(".bundle/config")).not_to exist
+ expect(home(".bundle/config")).to exist
+ end
+
it "works with an absolute path" do
ENV["BUNDLE_APP_CONFIG"] = tmp("foo/bar").to_s
bundle "config set --local path vendor/bundle"
@@ -76,6 +88,30 @@ RSpec.describe ".bundle/config" do
end
end
+ describe "config location" do
+ let(:bundle_user_config) { File.join(Dir.home, ".config/bundler") }
+
+ before do
+ Dir.mkdir File.dirname(bundle_user_config)
+ end
+
+ it "can be configured through BUNDLE_USER_CONFIG" do
+ bundle "config set path vendor", env: { "BUNDLE_USER_CONFIG" => bundle_user_config }
+ bundle "config get path", env: { "BUNDLE_USER_CONFIG" => bundle_user_config }
+ expect(out).to include("Set for the current user (#{bundle_user_config}): \"vendor\"")
+ end
+
+ context "when not explicitly configured, but BUNDLE_USER_HOME set" do
+ let(:bundle_user_home) { bundled_app(".bundle").to_s }
+
+ it "uses the right location" do
+ bundle "config set path vendor", env: { "BUNDLE_USER_HOME" => bundle_user_home }
+ bundle "config get path", env: { "BUNDLE_USER_HOME" => bundle_user_home }
+ expect(out).to include("Set for the current user (#{bundle_user_home}/config): \"vendor\"")
+ end
+ end
+ end
+
describe "global" do
before(:each) do
install_gemfile <<-G
@@ -107,17 +143,15 @@ RSpec.describe ".bundle/config" do
end
it "has lower precedence than env" do
- begin
- ENV["BUNDLE_FOO"] = "env"
+ ENV["BUNDLE_FOO"] = "env"
- bundle "config set --global foo global"
- expect(out).to match(/You have a bundler environment variable for foo set to "env"/)
+ bundle "config set --global foo global"
+ expect(out).to match(/You have a bundler environment variable for foo set to "env"/)
- run "puts Bundler.settings[:foo]"
- expect(out).to eq("env")
- ensure
- ENV.delete("BUNDLE_FOO")
- end
+ run "puts Bundler.settings[:foo]"
+ expect(out).to eq("env")
+ ensure
+ ENV.delete("BUNDLE_FOO")
end
it "can be deleted" do
@@ -185,15 +219,13 @@ RSpec.describe ".bundle/config" do
end
it "has higher precedence than env" do
- begin
- ENV["BUNDLE_FOO"] = "env"
- bundle "config set --local foo local"
-
- run "puts Bundler.settings[:foo]"
- expect(out).to eq("local")
- ensure
- ENV.delete("BUNDLE_FOO")
- end
+ ENV["BUNDLE_FOO"] = "env"
+ bundle "config set --local foo local"
+
+ run "puts Bundler.settings[:foo]"
+ expect(out).to eq("local")
+ ensure
+ ENV.delete("BUNDLE_FOO")
end
it "can be deleted" do
@@ -335,7 +367,7 @@ E
it "doesn't return quotes around values" do
bundle "config set foo '1'"
- run "puts Bundler.settings.send(:global_config_file).read"
+ run "puts Bundler.settings.send(:local_config_file).read"
expect(out).to include('"1"')
run "puts Bundler.settings[:foo]"
expect(out).to eq("1")
@@ -399,21 +431,57 @@ E
end
end
+ describe "commented out settings with urls" do
+ before do
+ bundle "config set #mirror.https://rails-assets.org http://localhost:9292"
+ end
+
+ it "does not make bundler crash and ignores the configuration" do
+ bundle "config list --parseable"
+
+ expect(out).to eq("#mirror.https://rails-assets.org/=http://localhost:9292")
+ expect(err).to be_empty
+
+ ruby(<<~RUBY)
+ require "bundler"
+ print Bundler.settings.mirror_for("https://rails-assets.org")
+ RUBY
+ expect(out).to eq("https://rails-assets.org/")
+ expect(err).to be_empty
+
+ bundle "config set mirror.all http://localhost:9293"
+ ruby(<<~RUBY)
+ require "bundler"
+ print Bundler.settings.mirror_for("https://rails-assets.org")
+ RUBY
+ expect(out).to eq("http://localhost:9293/")
+ expect(err).to be_empty
+ end
+ end
+
describe "subcommands" do
it "list" do
- bundle "config list"
- expect(out).to eq "Settings are listed in order of priority. The top value will be used.\nspec_run\nSet via BUNDLE_SPEC_RUN: \"true\""
+ bundle "config list", env: { "BUNDLE_FOO" => "bar" }
+ expect(out).to eq "Settings are listed in order of priority. The top value will be used.\nfoo\nSet via BUNDLE_FOO: \"bar\""
- bundle "config list", :parseable => true
- expect(out).to eq "spec_run=true"
+ bundle "config list", env: { "BUNDLE_FOO" => "bar" }, parseable: true
+ expect(out).to eq "foo=bar"
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", 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]\""
+
+ bundle "config list", parseable: true, env: { "BUNDLE_GEMS__MYSERVER__COM" => "user:password" }
+ expect(out).to eq "gems.myserver.com=user:password"
+ end
+
+ it "list with API token credentials" do
+ bundle "config list", env: { "BUNDLE_GEMS__MYSERVER__COM" => "api_token:x-oauth-basic" }
+ 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: \"[REDACTED]:x-oauth-basic\""
- bundle "config list", :parseable => true, :env => { "BUNDLE_GEMS__MYSERVER__COM" => "user:password" }
- expect(out).to eq "gems.myserver.com=user:password\nspec_run=true"
+ bundle "config list", parseable: true, env: { "BUNDLE_GEMS__MYSERVER__COM" => "api_token:x-oauth-basic" }
+ expect(out).to eq "gems.myserver.com=api_token:x-oauth-basic"
end
it "get" do
@@ -447,7 +515,7 @@ E
bundle "config set --local foo 4.1"
expect(out).to eq "You are replacing the current local value of foo, which is currently \"4\""
- bundle "config set --global --local foo 5", :raise_on_error => false
+ bundle "config set --global --local foo 5", raise_on_error: false
expect(last_command).to be_failure
expect(err).to eq "The options global and local were specified. Please only use one of the switches at a time."
end
@@ -487,7 +555,7 @@ E
expect(out).to eq ""
expect(bundle("config get foo")).to eq "Settings for `foo` in order of priority. The top value will be used\nYou have not configured a value for `foo`"
- bundle "config unset foo --local --global", :raise_on_error => false
+ bundle "config unset foo --local --global", raise_on_error: false
expect(last_command).to be_failure
expect(err).to eq "The options global and local were specified. Please only use one of the switches at a time."
end
diff --git a/spec/bundler/commands/console_spec.rb b/spec/bundler/commands/console_spec.rb
index aa76096e3d..a41432b88a 100644
--- a/spec/bundler/commands/console_spec.rb
+++ b/spec/bundler/commands/console_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe "bundle console", :bundler => "< 3", :readline => true do
+RSpec.describe "bundle console", bundler: "< 3", readline: true do
before :each do
build_repo2 do
# A minimal fake pry console
diff --git a/spec/bundler/commands/doctor_spec.rb b/spec/bundler/commands/doctor_spec.rb
index a59ccc540a..666b23a141 100644
--- a/spec/bundler/commands/doctor_spec.rb
+++ b/spec/bundler/commands/doctor_spec.rb
@@ -38,6 +38,11 @@ RSpec.describe "bundle doctor" do
allow(stat).to receive(:uid) { Process.uid }
allow(File).to receive(:writable?).with(unwritable_file) { true }
allow(File).to receive(:readable?).with(unwritable_file) { true }
+
+ # The following lines are for `Gem::PathSupport#initialize`.
+ allow(File).to receive(:exist?).with(Gem.default_dir)
+ allow(File).to receive(:writable?).with(Gem.default_dir)
+ allow(File).to receive(:writable?).with(File.expand_path("..", Gem.default_dir))
end
it "exits with no message if the installed gem has no C extensions" do
@@ -49,8 +54,8 @@ RSpec.describe "bundle doctor" do
doctor = Bundler::CLI::Doctor.new({})
expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/rack/rack.bundle"]
expect(doctor).to receive(:dylibs).exactly(2).times.and_return ["/usr/lib/libSystem.dylib"]
- allow(File).to receive(:exist?).with("/usr/lib/libSystem.dylib").and_return(true)
- expect { doctor.run }.not_to(raise_error, @stdout.string)
+ allow(Fiddle).to receive(:dlopen).with("/usr/lib/libSystem.dylib").and_return(true)
+ expect { doctor.run }.not_to raise_error
expect(@stdout.string).to be_empty
end
@@ -58,8 +63,8 @@ RSpec.describe "bundle doctor" do
doctor = Bundler::CLI::Doctor.new({})
expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/rack/rack.bundle"]
expect(doctor).to receive(:dylibs).exactly(2).times.and_return ["/usr/local/opt/icu4c/lib/libicui18n.57.1.dylib"]
- allow(File).to receive(:exist?).with("/usr/local/opt/icu4c/lib/libicui18n.57.1.dylib").and_return(false)
- expect { doctor.run }.to raise_error(Bundler::ProductionError, strip_whitespace(<<-E).strip), @stdout.string
+ allow(Fiddle).to receive(:dlopen).with("/usr/local/opt/icu4c/lib/libicui18n.57.1.dylib").and_raise(Fiddle::DLError)
+ expect { doctor.run }.to raise_error(Bundler::ProductionError, <<~E.strip), @stdout.string
The following gems are missing OS dependencies:
* bundler: /usr/local/opt/icu4c/lib/libicui18n.57.1.dylib
* rack: /usr/local/opt/icu4c/lib/libicui18n.57.1.dylib
@@ -79,7 +84,7 @@ RSpec.describe "bundle doctor" do
it "exits with an error if home contains files that are not readable/writable" do
expect { Bundler::CLI::Doctor.new({}).run }.not_to raise_error
expect(@stdout.string).to include(
- "Broken links exist in the Bundler home. Please report them to the offending gem's upstream repo. These files are:\n - #{@unwritable_file}"
+ "Broken links exist in the Bundler home. Please report them to the offending gem's upstream repo. These files are:\n - #{@broken_symlink}"
)
expect(@stdout.string).not_to include("No issues")
end
@@ -133,4 +138,14 @@ RSpec.describe "bundle doctor" do
end
end
end
+
+ context "when home contains filenames with special characters" do
+ it "escape filename before command execute" do
+ doctor = Bundler::CLI::Doctor.new({})
+ expect(doctor).to receive(:`).with("/usr/bin/otool -L \\$\\(date\\)\\ \\\"\\'\\\\.bundle").and_return("dummy string")
+ doctor.dylibs_darwin('$(date) "\'\.bundle')
+ expect(doctor).to receive(:`).with("/usr/bin/ldd \\$\\(date\\)\\ \\\"\\'\\\\.bundle").and_return("dummy string")
+ doctor.dylibs_ldd('$(date) "\'\.bundle')
+ end
+ end
end
diff --git a/spec/bundler/commands/exec_spec.rb b/spec/bundler/commands/exec_spec.rb
index 2c83ec8e11..d59b690d2f 100644
--- a/spec/bundler/commands/exec_spec.rb
+++ b/spec/bundler/commands/exec_spec.rb
@@ -2,11 +2,10 @@
RSpec.describe "bundle exec" do
let(:system_gems_to_install) { %w[rack-1.0.0 rack-0.9.1] }
- before :each do
- system_gems(system_gems_to_install, :path => default_bundle_path)
- end
it "works with --gemfile flag" do
+ system_gems(system_gems_to_install, path: default_bundle_path)
+
create_file "CustomGemfile", <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack", "1.0.0"
@@ -17,6 +16,8 @@ RSpec.describe "bundle exec" do
end
it "activates the correct gem" do
+ system_gems(system_gems_to_install, path: default_bundle_path)
+
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack", "0.9.1"
@@ -27,12 +28,14 @@ RSpec.describe "bundle exec" do
end
it "works and prints no warnings when HOME is not writable" do
+ system_gems(system_gems_to_install, path: default_bundle_path)
+
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack", "0.9.1"
G
- bundle "exec rackup", :env => { "HOME" => "/" }
+ bundle "exec rackup", env: { "HOME" => "/" }
expect(out).to eq("0.9.1")
expect(err).to be_empty
end
@@ -105,7 +108,7 @@ RSpec.describe "bundle exec" do
2.1.4
L
- bundle "exec bundle cache", :env => { "BUNDLER_VERSION" => Bundler::VERSION }
+ bundle "exec bundle cache", env: { "BUNDLER_VERSION" => Bundler::VERSION }
expect(out).to include("Updating files in vendor/cache")
end
@@ -195,7 +198,7 @@ RSpec.describe "bundle exec" do
gem "rack", "0.9.1"
G
- install_gemfile bundled_app2("Gemfile"), <<-G, :dir => bundled_app2
+ install_gemfile bundled_app2("Gemfile"), <<-G, dir: bundled_app2
source "#{file_uri_for(gem_repo2)}"
gem "rack_two", "1.0.0"
G
@@ -204,14 +207,12 @@ RSpec.describe "bundle exec" do
expect(out).to eq("0.9.1")
- bundle "exec rackup", :dir => bundled_app2
+ bundle "exec rackup", dir: bundled_app2
expect(out).to eq("1.0.0")
end
context "with default gems" do
- let(:system_gems_to_install) { [] }
-
- let(:default_irb_version) { ruby "gem 'irb', '< 999999'; require 'irb'; puts IRB::VERSION", :raise_on_error => false }
+ let(:default_irb_version) { ruby "gem 'irb', '< 999999'; require 'irb'; puts IRB::VERSION", raise_on_error: false }
context "when not specified in Gemfile" do
before do
@@ -291,14 +292,14 @@ RSpec.describe "bundle exec" do
end
end
- bundle "config set path.system true"
+ bundle "config set --global path.system true"
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack", "0.9.1"
G
- install_gemfile bundled_app2("Gemfile"), <<-G, :dir => bundled_app2
+ install_gemfile bundled_app2("Gemfile"), <<-G, dir: bundled_app2
source "#{file_uri_for(gem_repo2)}"
gem "rack_two", "1.0.0"
G
@@ -343,7 +344,7 @@ RSpec.describe "bundle exec" do
bundle "exec 'echo $RUBYOPT'"
expect(out.split(" ").count(bundler_setup_opt)).to eq(1)
- bundle "exec 'echo $RUBYOPT'", :env => { "RUBYOPT" => rubyopt }
+ bundle "exec 'echo $RUBYOPT'", env: { "RUBYOPT" => rubyopt }
expect(out.split(" ").count(bundler_setup_opt)).to eq(1)
end
@@ -362,7 +363,7 @@ RSpec.describe "bundle exec" do
bundle "exec 'echo $RUBYLIB'"
expect(out).to include(rubylib)
- bundle "exec 'echo $RUBYLIB'", :env => { "RUBYLIB" => rubylib }
+ bundle "exec 'echo $RUBYLIB'", env: { "RUBYLIB" => rubylib }
expect(out).to include(rubylib)
end
@@ -372,7 +373,7 @@ RSpec.describe "bundle exec" do
gem "rack"
G
- bundle "exec foobarbaz", :raise_on_error => false
+ bundle "exec foobarbaz", raise_on_error: false
expect(exitstatus).to eq(127)
expect(err).to include("bundler: command not found: foobarbaz")
expect(err).to include("Install missing gem executables with `bundle install`")
@@ -385,7 +386,7 @@ RSpec.describe "bundle exec" do
G
bundle "exec touch foo"
- bundle "exec ./foo", :raise_on_error => false
+ bundle "exec ./foo", raise_on_error: false
expect(exitstatus).to eq(126)
expect(err).to include("bundler: not executable: ./foo")
end
@@ -396,12 +397,14 @@ RSpec.describe "bundle exec" do
gem "rack"
G
- bundle "exec", :raise_on_error => false
+ bundle "exec", raise_on_error: false
expect(exitstatus).to eq(128)
expect(err).to include("bundler: exec needs a command to run")
end
it "raises a helpful error when exec'ing to something outside of the bundle" do
+ system_gems(system_gems_to_install, path: default_bundle_path)
+
bundle "config set clean false" # want to keep the rackup binstub
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -409,7 +412,7 @@ RSpec.describe "bundle exec" do
G
[true, false].each do |l|
bundle "config set disable_exec_load #{l}"
- bundle "exec rackup", :raise_on_error => false
+ bundle "exec rackup", raise_on_error: false
expect(err).to include "can't find executable rackup for gem rack. rack is not currently included in the bundle, perhaps you meant to add it to your Gemfile?"
end
end
@@ -528,7 +531,7 @@ RSpec.describe "bundle exec" do
describe "from gems bundled via :path" do
before(:each) do
- build_lib "fizz", :path => home("fizz") do |s|
+ build_lib "fizz", path: home("fizz") do |s|
s.executables = "fizz"
end
@@ -577,7 +580,7 @@ RSpec.describe "bundle exec" do
describe "from gems bundled via :git with no gemspec" do
before(:each) do
- build_git "fizz_no_gemspec", :gemspec => false do |s|
+ build_git "fizz_no_gemspec", gemspec: false do |s|
s.executables = "fizz_no_gemspec"
end
@@ -612,6 +615,53 @@ RSpec.describe "bundle exec" do
expect(out).to include("Installing foo 1.0")
end
+ it "performs an automatic bundle install with git gems" do
+ build_git "foo" do |s|
+ s.executables = "foo"
+ end
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
+ gem "foo", :git => "#{lib_path("foo-1.0")}"
+ G
+
+ bundle "config set auto_install 1"
+ bundle "exec foo"
+ expect(out).to include("Fetching rack 0.9.1")
+ expect(out).to include("Fetching #{lib_path("foo-1.0")}")
+ expect(out.lines).to end_with("1.0")
+ end
+
+ it "loads the correct optparse when `auto_install` is set, and optparse is a dependency" do
+ if Gem.rubygems_version < Gem::Version.new("3.3.0.a")
+ skip "optparse is a default gem, and rubygems loads it during install"
+ end
+
+ build_repo4 do
+ build_gem "fastlane", "2.192.0" do |s|
+ s.executables = "fastlane"
+ s.add_dependency "optparse", "~> 999.999.999"
+ end
+
+ build_gem "optparse", "999.999.998"
+ build_gem "optparse", "999.999.999"
+ end
+
+ system_gems "optparse-999.999.998", gem_repo: gem_repo4
+
+ bundle "config set auto_install 1"
+ bundle "config set --local path vendor/bundle"
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "fastlane"
+ G
+
+ bundle "exec fastlane"
+ expect(out).to include("Installing optparse 999.999.999")
+ expect(out).to include("2.192.0")
+ end
+
describe "with gems bundled via :path with invalid gemspecs" do
it "outputs the gemspec validation errors" do
build_lib "foo"
@@ -633,7 +683,7 @@ RSpec.describe "bundle exec" do
gem "foo", :path => "#{lib_path("foo-1.0")}"
G
- bundle "exec irb", :raise_on_error => false
+ bundle "exec irb", raise_on_error: false
expect(err).to match("The gemspec at #{lib_path("foo-1.0").join("foo.gemspec")} is not valid")
expect(err).to match('"TODO" is not a summary')
@@ -656,7 +706,7 @@ RSpec.describe "bundle exec" do
G
bundle "config set path.system true"
bundle "install"
- bundle "exec ruby -e '`bundle -v`; puts $?.success?'", :env => { "BUNDLER_VERSION" => Bundler::VERSION }
+ bundle "exec ruby -e '`bundle -v`; puts $?.success?'", env: { "BUNDLER_VERSION" => Bundler::VERSION }
expect(out).to match("true")
end
end
@@ -664,7 +714,7 @@ RSpec.describe "bundle exec" do
context "`load`ing a ruby file instead of `exec`ing" do
let(:path) { bundled_app("ruby_executable") }
let(:shebang) { "#!/usr/bin/env ruby" }
- let(:executable) { <<-RUBY.gsub(/^ */, "").strip }
+ let(:executable) { <<~RUBY.strip }
#{shebang}
require "rack"
@@ -676,6 +726,8 @@ RSpec.describe "bundle exec" do
RUBY
before do
+ system_gems(system_gems_to_install, path: default_bundle_path)
+
bundled_app(path).open("w") {|f| f << executable }
bundled_app(path).chmod(0o755)
@@ -697,7 +749,7 @@ RSpec.describe "bundle exec" do
let(:expected) { [exec, args, rack, process].join("\n") }
let(:expected_err) { "" }
- subject { bundle "exec #{path} arg1 arg2", :raise_on_error => false }
+ subject { bundle "exec #{path} arg1 arg2", raise_on_error: false }
it "runs" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
@@ -745,9 +797,7 @@ RSpec.describe "bundle exec" do
end
let(:expected_err) { "" }
let(:exit_code) do
- # signal mask 128 + plus signal 15 -> TERM
- # this is specified by C99
- 128 + 15
+ exit_status_for_signal(Signal.list["TERM"])
end
it "runs" do
@@ -781,8 +831,7 @@ RSpec.describe "bundle exec" do
let(:executable) { super() << "\nraise 'ERROR'" }
let(:exit_code) { 1 }
let(:expected_err) do
- "bundler: failed to load command: #{path} (#{path})" \
- "\n#{path}:10:in `<top (required)>': ERROR (RuntimeError)"
+ /\Abundler: failed to load command: #{Regexp.quote(path.to_s)} \(#{Regexp.quote(path.to_s)}\)\n#{Regexp.quote(path.to_s)}:10:in [`']<top \(required\)>': ERROR \(RuntimeError\)/
end
it "runs like a normally executed executable" do
@@ -790,7 +839,7 @@ RSpec.describe "bundle exec" do
subject
expect(exitstatus).to eq(exit_code)
- expect(err).to start_with(expected_err)
+ expect(err).to match(expected_err)
expect(out).to eq(expected)
end
end
@@ -824,7 +873,7 @@ RSpec.describe "bundle exec" do
end
end
- context "when Bundler.setup fails", :bundler => "< 3" do
+ context "when Bundler.setup fails", bundler: "< 3" do
before do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -836,9 +885,12 @@ RSpec.describe "bundle exec" do
let(:exit_code) { Bundler::GemNotFound.new.status_code }
let(:expected) { "" }
let(:expected_err) { <<-EOS.strip }
-\e[31mCould not find gem 'rack (= 2)' in rubygems repository #{file_uri_for(gem_repo1)}/ or installed locally.
-The source contains the following versions of 'rack': 0.9.1, 1.0.0\e[0m
-\e[33mRun `bundle install` to install missing gems.\e[0m
+Could not find gem 'rack (= 2)' in cached gems or installed locally.
+
+The source contains the following gems matching 'rack':
+ * rack-0.9.1
+ * rack-1.0.0
+Run `bundle install` to install missing gems.
EOS
it "runs" do
@@ -851,7 +903,7 @@ The source contains the following versions of 'rack': 0.9.1, 1.0.0\e[0m
end
end
- context "when Bundler.setup fails", :bundler => "3" do
+ context "when Bundler.setup fails", bundler: "3" do
before do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -863,9 +915,11 @@ The source contains the following versions of 'rack': 0.9.1, 1.0.0\e[0m
let(:exit_code) { Bundler::GemNotFound.new.status_code }
let(:expected) { "" }
let(:expected_err) { <<-EOS.strip }
-\e[31mCould not find gem 'rack (= 2)' in rubygems repository #{file_uri_for(gem_repo1)}/ or installed locally.
-The source contains the following versions of 'rack': 1.0.0\e[0m
-\e[33mRun `bundle install` to install missing gems.\e[0m
+Could not find gem 'rack (= 2)' in cached gems or installed locally.
+
+The source contains the following gems matching 'rack':
+ * rack-1.0.0
+Run `bundle install` to install missing gems.
EOS
it "runs" do
@@ -878,6 +932,30 @@ The source contains the following versions of 'rack': 1.0.0\e[0m
end
end
+ context "when Bundler.setup fails and Gemfile is not the default" do
+ before do
+ create_file "CustomGemfile", <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack', '2'
+ G
+ ENV["BUNDLER_FORCE_TTY"] = "true"
+ ENV["BUNDLE_GEMFILE"] = "CustomGemfile"
+ ENV["BUNDLER_ORIG_BUNDLE_GEMFILE"] = nil
+ end
+
+ let(:exit_code) { Bundler::GemNotFound.new.status_code }
+ let(:expected) { "" }
+
+ it "prints proper suggestion" do
+ skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
+
+ subject
+ expect(exitstatus).to eq(exit_code)
+ expect(err).to include("Run `bundle install --gemfile CustomGemfile` to install missing gems.")
+ expect(out).to eq(expected)
+ end
+ end
+
context "when the executable exits non-zero via at_exit" do
let(:executable) { super() + "\n\nat_exit { $! ? raise($!) : exit(1) }" }
let(:exit_code) { 1 }
@@ -962,7 +1040,7 @@ __FILE__: #{path.to_s.inspect}
end
context "signals being trapped by bundler" do
- let(:executable) { strip_whitespace <<-RUBY }
+ let(:executable) { <<~RUBY }
#{shebang}
begin
Thread.new do
@@ -989,7 +1067,7 @@ __FILE__: #{path.to_s.inspect}
end
context "signals not being trapped by bunder" do
- let(:executable) { strip_whitespace <<-RUBY }
+ let(:executable) { <<~RUBY }
#{shebang}
signals = #{test_signals.inspect}
@@ -1034,7 +1112,7 @@ __FILE__: #{path.to_s.inspect}
puts `bundle exec echo foo`
RUBY
file.chmod(0o777)
- bundle "exec #{file}", :env => { "PATH" => path }
+ bundle "exec #{file}", env: { "PATH" => path }
expect(out).to eq("foo")
end
end
@@ -1127,7 +1205,7 @@ __FILE__: #{path.to_s.inspect}
context "with a system gem that shadows a default gem" do
let(:openssl_version) { "99.9.9" }
- let(:expected) { ruby "gem 'openssl', '< 999999'; require 'openssl'; puts OpenSSL::VERSION", :artifice => nil, :raise_on_error => false }
+ let(:expected) { ruby "gem 'openssl', '< 999999'; require 'openssl'; puts OpenSSL::VERSION", artifice: nil, raise_on_error: false }
it "only leaves the default gem in the stdlib available" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
@@ -1143,7 +1221,7 @@ __FILE__: #{path.to_s.inspect}
end
end
- system_gems("openssl-#{openssl_version}", :gem_repo => gem_repo4)
+ system_gems("openssl-#{openssl_version}", gem_repo: gem_repo4)
file = bundled_app("require_openssl.rb")
create_file(file, <<-RUBY)
@@ -1156,15 +1234,15 @@ __FILE__: #{path.to_s.inspect}
env = { "PATH" => path }
aggregate_failures do
- expect(bundle("exec #{file}", :artifice => nil, :env => env)).to eq(expected)
- expect(bundle("exec bundle exec #{file}", :artifice => nil, :env => env)).to eq(expected)
- expect(bundle("exec ruby #{file}", :artifice => nil, :env => env)).to eq(expected)
- expect(run(file.read, :artifice => nil, :env => env)).to eq(expected)
+ expect(bundle("exec #{file}", artifice: nil, env: env)).to eq(expected)
+ expect(bundle("exec bundle exec #{file}", artifice: nil, env: env)).to eq(expected)
+ expect(bundle("exec ruby #{file}", artifice: nil, env: env)).to eq(expected)
+ expect(run(file.read, artifice: nil, env: env)).to eq(expected)
end
skip "ruby_core has openssl and rubygems in the same folder, and this test needs rubygems require but default openssl not in a directly added entry in $LOAD_PATH" if ruby_core?
# sanity check that we get the newer, custom version without bundler
- sys_exec "#{Gem.ruby} #{file}", :env => env, :raise_on_error => false
+ sys_exec "#{Gem.ruby} #{file}", env: env, raise_on_error: false
expect(err).to include("custom openssl should not be loaded")
end
end
diff --git a/spec/bundler/commands/fund_spec.rb b/spec/bundler/commands/fund_spec.rb
index 5a0c5411da..5415b88eeb 100644
--- a/spec/bundler/commands/fund_spec.rb
+++ b/spec/bundler/commands/fund_spec.rb
@@ -5,20 +5,20 @@ RSpec.describe "bundle fund" do
build_repo2 do
build_gem "has_funding_and_other_metadata" do |s|
s.metadata = {
- "bug_tracker_uri" => "https://example.com/user/bestgemever/issues",
- "changelog_uri" => "https://example.com/user/bestgemever/CHANGELOG.md",
+ "bug_tracker_uri" => "https://example.com/user/bestgemever/issues",
+ "changelog_uri" => "https://example.com/user/bestgemever/CHANGELOG.md",
"documentation_uri" => "https://www.example.info/gems/bestgemever/0.0.1",
- "homepage_uri" => "https://bestgemever.example.io",
- "mailing_list_uri" => "https://groups.example.com/bestgemever",
- "funding_uri" => "https://example.com/has_funding_and_other_metadata/funding",
- "source_code_uri" => "https://example.com/user/bestgemever",
- "wiki_uri" => "https://example.com/user/bestgemever/wiki",
+ "homepage_uri" => "https://bestgemever.example.io",
+ "mailing_list_uri" => "https://groups.example.com/bestgemever",
+ "funding_uri" => "https://example.com/has_funding_and_other_metadata/funding",
+ "source_code_uri" => "https://example.com/user/bestgemever",
+ "wiki_uri" => "https://example.com/user/bestgemever/wiki",
}
end
build_gem "has_funding", "1.2.3" do |s|
s.metadata = {
- "funding_uri" => "https://example.com/has_funding/funding",
+ "funding_uri" => "https://example.com/has_funding/funding",
}
end
diff --git a/spec/bundler/commands/help_spec.rb b/spec/bundler/commands/help_spec.rb
index f72763900e..0c7031e813 100644
--- a/spec/bundler/commands/help_spec.rb
+++ b/spec/bundler/commands/help_spec.rb
@@ -15,6 +15,13 @@ RSpec.describe "bundle help" do
expect(out).to eq(%(["#{man_dir}/bundle-install.1"]))
end
+ it "prexifes bundle commands with bundle- and resolves aliases when finding the man files" do
+ with_fake_man do
+ bundle "help package"
+ end
+ expect(out).to eq(%(["#{man_dir}/bundle-cache.1"]))
+ end
+
it "simply outputs the human readable file when there is no man on the path" do
with_path_as("") do
bundle "help install"
@@ -23,8 +30,8 @@ RSpec.describe "bundle help" do
end
it "still outputs the old help for commands that do not have man pages yet" do
- bundle "help version"
- expect(out).to include("Prints the bundler's version information")
+ bundle "help fund"
+ expect(out).to include("Lists information about gems seeking funding assistance")
end
it "looks for a binary and executes it with --help option if it's named bundler-<task>" do
@@ -71,7 +78,7 @@ RSpec.describe "bundle help" do
it "has helpful output when using --help flag for a non-existent command" do
with_fake_man do
- bundle "instill -h", :raise_on_error => false
+ bundle "instill -h", raise_on_error: false
end
expect(err).to include('Could not find command "instill".')
end
diff --git a/spec/bundler/commands/info_spec.rb b/spec/bundler/commands/info_spec.rb
index 906349cacf..a5a09bc147 100644
--- a/spec/bundler/commands/info_spec.rb
+++ b/spec/bundler/commands/info_spec.rb
@@ -6,13 +6,13 @@ RSpec.describe "bundle info" do
build_repo2 do
build_gem "has_metadata" do |s|
s.metadata = {
- "bug_tracker_uri" => "https://example.com/user/bestgemever/issues",
- "changelog_uri" => "https://example.com/user/bestgemever/CHANGELOG.md",
+ "bug_tracker_uri" => "https://example.com/user/bestgemever/issues",
+ "changelog_uri" => "https://example.com/user/bestgemever/CHANGELOG.md",
"documentation_uri" => "https://www.example.info/gems/bestgemever/0.0.1",
- "homepage_uri" => "https://bestgemever.example.io",
- "mailing_list_uri" => "https://groups.example.com/bestgemever",
- "source_code_uri" => "https://example.com/user/bestgemever",
- "wiki_uri" => "https://example.com/user/bestgemever/wiki",
+ "homepage_uri" => "https://bestgemever.example.io",
+ "mailing_list_uri" => "https://groups.example.com/bestgemever",
+ "source_code_uri" => "https://example.com/user/bestgemever",
+ "wiki_uri" => "https://example.com/user/bestgemever/wiki",
}
end
end
@@ -21,6 +21,7 @@ RSpec.describe "bundle info" do
source "#{file_uri_for(gem_repo2)}"
gem "rails"
gem "has_metadata"
+ gem "thin"
G
end
@@ -50,8 +51,21 @@ RSpec.describe "bundle info" do
expect(out).to eq(root.to_s)
end
+ it "prints gem version if exists in bundle" do
+ bundle "info rails --version"
+ expect(out).to eq("2.3.2")
+ end
+
+ it "doesn't claim that bundler has been deleted, even if using a custom path without bundler there" do
+ bundle "config set --local path vendor/bundle"
+ bundle "install"
+ bundle "info bundler"
+ expect(out).to include("\tPath: #{root}")
+ expect(err).not_to match(/The gem bundler has been deleted/i)
+ end
+
it "complains if gem not in bundle" do
- bundle "info missing", :raise_on_error => false
+ bundle "info missing", raise_on_error: false
expect(err).to eq("Could not find gem 'missing'.")
end
@@ -60,8 +74,16 @@ RSpec.describe "bundle info" do
bundle "info rails --path"
- expect(err).to match(/has been deleted/i)
- expect(err).to match(default_bundle_path("gems", "rails-2.3.2").to_s)
+ expect(err).to include("The gem rails has been deleted.")
+ expect(err).to include(default_bundle_path("gems", "rails-2.3.2").to_s)
+
+ bundle "info rail --path"
+ expect(err).to include("The gem rails has been deleted.")
+ expect(err).to include(default_bundle_path("gems", "rails-2.3.2").to_s)
+
+ bundle "info rails"
+ expect(err).to include("The gem rails has been deleted.")
+ expect(err).to include(default_bundle_path("gems", "rails-2.3.2").to_s)
end
context "given a default gem shippped in ruby", :ruby_repo do
@@ -102,6 +124,30 @@ RSpec.describe "bundle info" do
expect(out).to_not include("Homepage:")
end
end
+
+ context "when gem has a reverse dependency on any version" do
+ it "prints the details" do
+ bundle "info rack"
+
+ expect(out).to include("Reverse Dependencies: \n\t\tthin (1.0) depends on rack (>= 0)")
+ end
+ end
+
+ context "when gem has a reverse dependency on a specific version" do
+ it "prints the details" do
+ bundle "info actionpack"
+
+ expect(out).to include("Reverse Dependencies: \n\t\trails (2.3.2) depends on actionpack (= 2.3.2)")
+ end
+ end
+
+ context "when gem has no reverse dependencies" do
+ it "excludes the reverse dependencies field from the output" do
+ bundle "info rails"
+
+ expect(out).not_to include("Reverse Dependencies:")
+ end
+ end
end
context "with a git repo in the Gemfile" do
@@ -117,11 +163,11 @@ RSpec.describe "bundle info" do
expect(the_bundle).to include_gems "foo 1.0"
bundle "info foo"
- expect(out).to include("foo (1.0 #{@git.ref_for("master", 6)}")
+ expect(out).to include("foo (1.0 #{@git.ref_for("main", 6)}")
end
- it "prints out branch names other than master" do
- update_git "foo", :branch => "omg" do |s|
+ it "prints out branch names other than main" do
+ update_git "foo", branch: "omg" do |s|
s.write "lib/foo.rb", "FOO = '1.0.omg'"
end
@revision = revision_for(lib_path("foo-1.0"))[0...6]
@@ -148,7 +194,7 @@ RSpec.describe "bundle info" do
end
it "handles when a version is a '-' prerelease" do
- @git = build_git("foo", "1.0.0-beta.1", :path => lib_path("foo"))
+ @git = build_git("foo", "1.0.0-beta.1", path: lib_path("foo"))
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "foo", "1.0.0-beta.1", :git => "#{lib_path("foo")}"
@@ -169,7 +215,7 @@ RSpec.describe "bundle info" do
G
bundle "info rac"
- expect(out).to match(/\A1 : rack\n2 : rack-obama\n0 : - exit -(\n>)?\z/)
+ expect(out).to match(/\A1 : rack\n2 : rack-obama\n0 : - exit -(\n>.*)?\z/)
end
end
@@ -182,7 +228,7 @@ RSpec.describe "bundle info" do
invalid_regexp = "[]"
- bundle "info #{invalid_regexp}", :raise_on_error => false
+ bundle "info #{invalid_regexp}", raise_on_error: false
expect(err).to include("Could not find gem '#{invalid_regexp}'.")
end
end
@@ -196,7 +242,7 @@ RSpec.describe "bundle info" do
gem "rails", group: :test
G
- bundle "info rails", :raise_on_error => false
+ bundle "info rails", raise_on_error: false
expect(err).to include("Could not find gem 'rails', because it's in the group 'test', configured to be ignored.")
end
end
diff --git a/spec/bundler/commands/init_spec.rb b/spec/bundler/commands/init_spec.rb
index 683a453c7d..0a1336572a 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
@@ -15,11 +38,11 @@ RSpec.describe "bundle init" do
end
it "does not change existing Gemfiles" do
- expect { bundle :init, :raise_on_error => false }.not_to change { File.read(bundled_app_gemfile) }
+ expect { bundle :init, raise_on_error: false }.not_to change { File.read(bundled_app_gemfile) }
end
it "notifies the user that an existing Gemfile already exists" do
- bundle :init, :raise_on_error => false
+ bundle :init, raise_on_error: false
expect(err).to include("Gemfile already exists")
end
end
@@ -32,7 +55,7 @@ RSpec.describe "bundle init" do
FileUtils.mkdir bundled_app(subdir)
- bundle :init, :dir => bundled_app(subdir)
+ bundle :init, dir: bundled_app(subdir)
expect(out).to include("Writing new Gemfile")
expect(bundled_app("#{subdir}/Gemfile")).to be_file
@@ -42,13 +65,13 @@ RSpec.describe "bundle init" do
context "when the dir is not writable by the current user" do
let(:subdir) { "child_dir" }
- it "notifies the user that it can not write to it" do
+ it "notifies the user that it cannot write to it" do
FileUtils.mkdir bundled_app(subdir)
# chmod a-w it
mode = File.stat(bundled_app(subdir)).mode ^ 0o222
FileUtils.chmod mode, bundled_app(subdir)
- bundle :init, :dir => bundled_app(subdir), :raise_on_error => false
+ bundle :init, dir: bundled_app(subdir), raise_on_error: false
expect(err).to include("directory is not writable")
expect(Dir[bundled_app("#{subdir}/*")]).to be_empty
@@ -69,7 +92,7 @@ RSpec.describe "bundle init" do
S
end
- bundle :init, :gemspec => spec_file
+ bundle :init, gemspec: spec_file
gemfile = bundled_app_gemfile.read
expect(gemfile).to match(%r{source 'https://rubygems.org'})
@@ -89,7 +112,7 @@ RSpec.describe "bundle init" do
S
end
- bundle :init, :gemspec => spec_file, :raise_on_error => false
+ bundle :init, gemspec: spec_file, raise_on_error: false
expect(err).to include("There was an error while loading `test.gemspec`")
end
end
@@ -112,11 +135,11 @@ RSpec.describe "bundle init" do
end
it "does not change existing Gemfiles" do
- expect { bundle :init, :raise_on_error => false }.not_to change { File.read(bundled_app("gems.rb")) }
+ expect { bundle :init, raise_on_error: false }.not_to change { File.read(bundled_app("gems.rb")) }
end
it "notifies the user that an existing gems.rb already exists" do
- bundle :init, :raise_on_error => false
+ bundle :init, raise_on_error: false
expect(err).to include("gems.rb already exists")
end
end
@@ -129,7 +152,7 @@ RSpec.describe "bundle init" do
FileUtils.mkdir bundled_app(subdir)
- bundle :init, :dir => bundled_app(subdir)
+ bundle :init, dir: bundled_app(subdir)
expect(out).to include("Writing new gems.rb")
expect(bundled_app("#{subdir}/gems.rb")).to be_file
@@ -152,7 +175,7 @@ RSpec.describe "bundle init" do
end
it "should generate from an existing gemspec" do
- bundle :init, :gemspec => spec_file
+ bundle :init, gemspec: spec_file
gemfile = bundled_app("gems.rb").read
expect(gemfile).to match(%r{source 'https://rubygems.org'})
@@ -162,10 +185,23 @@ RSpec.describe "bundle init" do
end
it "prints message to user" do
- bundle :init, :gemspec => spec_file
+ bundle :init, gemspec: spec_file
expect(out).to include("Writing new gems.rb")
end
end
end
+
+ describe "using the --gemfile" do
+ it "should use the --gemfile value to name the gemfile" do
+ custom_gemfile_name = "NiceGemfileName"
+
+ bundle :init, gemfile: custom_gemfile_name
+
+ expect(out).to include("Writing new #{custom_gemfile_name}")
+ used_template = File.read("#{source_root}/lib/bundler/templates/Gemfile")
+ generated_gemfile = bundled_app(custom_gemfile_name).read
+ expect(generated_gemfile).to eq(used_template)
+ end
+ end
end
diff --git a/spec/bundler/commands/inject_spec.rb b/spec/bundler/commands/inject_spec.rb
index 2d97bf6ff0..255a03c135 100644
--- a/spec/bundler/commands/inject_spec.rb
+++ b/spec/bundler/commands/inject_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe "bundle inject", :bundler => "< 3" do
+RSpec.describe "bundle inject", bundler: "< 3" do
before :each do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -36,14 +36,14 @@ RSpec.describe "bundle inject", :bundler => "< 3" do
context "with injected gems already in the Gemfile" do
it "doesn't add existing gems" do
- bundle "inject 'rack' '> 0'", :raise_on_error => false
+ bundle "inject 'rack' '> 0'", raise_on_error: false
expect(err).to match(/cannot specify the same gem twice/i)
end
end
context "incorrect arguments" do
it "fails when more than 2 arguments are passed" do
- bundle "inject gem_name 1 v", :raise_on_error => false
+ bundle "inject gem_name 1 v", raise_on_error: false
expect(err).to eq(<<-E.strip)
ERROR: "bundle inject" was called with arguments ["gem_name", "1", "v"]
Usage: "bundle inject GEM VERSION"
@@ -99,7 +99,7 @@ Usage: "bundle inject GEM VERSION"
it "restores frozen afterwards" do
bundle "inject 'rack-obama' '> 0'"
- config = YAML.load(bundled_app(".bundle/config").read)
+ config = Psych.load(bundled_app(".bundle/config").read)
expect(config["BUNDLE_DEPLOYMENT"] || config["BUNDLE_FROZEN"]).to eq("true")
end
@@ -108,8 +108,8 @@ Usage: "bundle inject GEM VERSION"
source "#{file_uri_for(gem_repo1)}"
gem "rack-obama"
G
- bundle "inject 'rack' '> 0'", :raise_on_error => false
- expect(err).to match(/trying to install in deployment mode after changing/)
+ bundle "inject 'rack' '> 0'", raise_on_error: false
+ expect(err).to match(/the lockfile can't be updated because frozen mode is set/)
expect(bundled_app_lock.read).not_to match(/rack-obama/)
end
diff --git a/spec/bundler/commands/install_spec.rb b/spec/bundler/commands/install_spec.rb
index 412000341f..f0c9aaea8e 100644
--- a/spec/bundler/commands/install_spec.rb
+++ b/spec/bundler/commands/install_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "does not make a lockfile if the install fails" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
raise StandardError, "FAIL"
G
@@ -29,7 +29,7 @@ RSpec.describe "bundle install with gem sources" do
expect(bundled_app_lock).to exist
end
- it "does not create ./.bundle by default", :bundler => "< 3" do
+ it "does not create ./.bundle by default", bundler: "< 3" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -45,7 +45,7 @@ RSpec.describe "bundle install with gem sources" do
gem "rack"
G
- bundle :install, :env => { "BUNDLE_PATH__SYSTEM" => "true" } # can't use install_gemfile since it sets retry
+ bundle :install, env: { "BUNDLE_PATH__SYSTEM" => "true" } # can't use install_gemfile since it sets retry
expect(bundled_app(".bundle")).not_to exist
end
@@ -68,7 +68,7 @@ RSpec.describe "bundle install with gem sources" do
lockfile = File.read(bundled_app_lock)
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
raise StandardError, "FAIL"
G
@@ -94,6 +94,21 @@ RSpec.describe "bundle install with gem sources" do
expect(the_bundle).to include_gems("rack 1.0.0")
end
+ it "auto-heals missing gems" do
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
+ G
+
+ FileUtils.rm_rf(default_bundle_path("gems/rack-1.0.0"))
+
+ bundle "install --verbose"
+
+ expect(out).to include("Installing rack 1.0.0")
+ expect(default_bundle_path("gems/rack-1.0.0")).to exist
+ expect(the_bundle).to include_gems("rack 1.0.0")
+ end
+
it "fetches gems when multiple versions are specified" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -115,7 +130,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "raises an appropriate error when gems are specified using symbols" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem :rack
G
@@ -182,7 +197,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "does not reinstall any gem that is already available locally" do
- system_gems "activesupport-2.3.2", :path => default_bundle_path
+ system_gems "activesupport-2.3.2", path: default_bundle_path
build_repo2 do
build_gem "activesupport", "2.3.2" do |s|
@@ -199,7 +214,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "works when the gemfile specifies gems that only exist in the system" do
- build_gem "foo", :to_bundle => true
+ build_gem "foo", to_bundle: true
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -210,7 +225,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "prioritizes local gems over remote gems" do
- build_gem "rack", "1.0.0", :to_bundle => true do |s|
+ build_gem "rack", "1.0.0", to_bundle: true do |s|
s.add_dependency "activesupport", "2.3.5"
end
@@ -226,7 +241,7 @@ RSpec.describe "bundle install with gem sources" do
plugin_msg = "hello from an env plugin!"
create_file "plugins/rubygems_plugin.rb", "puts '#{plugin_msg}'"
rubylib = ENV["RUBYLIB"].to_s.split(File::PATH_SEPARATOR).unshift(bundled_app("plugins").to_s).join(File::PATH_SEPARATOR)
- install_gemfile <<-G, :env => { "RUBYLIB" => rubylib }
+ install_gemfile <<-G, env: { "RUBYLIB" => rubylib }
source "#{file_uri_for(gem_repo1)}"
gem "rack"
G
@@ -270,7 +285,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "installs gems for windows" do
- simulate_platform mswin
+ simulate_platform x86_mswin32
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -278,7 +293,7 @@ RSpec.describe "bundle install with gem sources" do
G
run "require 'platform_specific' ; puts PLATFORM_SPECIFIC"
- expect(out).to eq("1.0.0 MSWIN")
+ expect(out).to eq("1.0 x86-mswin32")
end
end
@@ -296,14 +311,14 @@ RSpec.describe "bundle install with gem sources" do
expect(the_bundle).to include_gems "rack 1.0"
end
- it "allows running bundle install --system without deleting foo", :bundler => "< 3" do
+ it "allows running bundle install --system without deleting foo", bundler: "< 3" do
bundle "install --path vendor"
bundle "install --system"
FileUtils.rm_rf(bundled_app("vendor"))
expect(the_bundle).to include_gems "rack 1.0"
end
- it "allows running bundle install --system after deleting foo", :bundler => "< 3" do
+ it "allows running bundle install --system after deleting foo", bundler: "< 3" do
bundle "install --path vendor"
FileUtils.rm_rf(bundled_app("vendor"))
bundle "install --system"
@@ -311,7 +326,7 @@ RSpec.describe "bundle install with gem sources" do
end
end
- it "finds gems in multiple sources", :bundler => "< 3" do
+ it "finds gems in multiple sources", bundler: "< 3" do
build_repo2 do
build_gem "rack", "1.2" do |s|
s.executables = "rackup"
@@ -330,13 +345,13 @@ RSpec.describe "bundle install with gem sources" do
end
it "gives a useful error if no sources are set" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
gem "rack"
G
expect(err).to include("This Gemfile does not include an explicit global source. " \
"Not using an explicit global source may result in a different lockfile being generated depending on " \
- "the gems you have installed locally before bundler is run." \
+ "the gems you have installed locally before bundler is run. " \
"Instead, define a global source in your Gemfile like this: source \"https://rubygems.org\".")
end
@@ -349,7 +364,9 @@ RSpec.describe "bundle install with gem sources" do
end
it "throws a warning if a gem is added twice in Gemfile without version requirements" do
- install_gemfile <<-G, :raise_on_error => false
+ build_repo2
+
+ install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
gem "rack"
gem "rack"
@@ -361,7 +378,9 @@ RSpec.describe "bundle install with gem sources" do
end
it "throws a warning if a gem is added twice in Gemfile with same versions" do
- install_gemfile <<-G, :raise_on_error => false
+ build_repo2
+
+ install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
gem "rack", "1.0"
gem "rack", "1.0"
@@ -372,8 +391,24 @@ RSpec.describe "bundle install with gem sources" do
expect(err).to include("While it's not a problem now, it could cause errors if you change the version of one of them later.")
end
+ it "throws a warning if a gem is added twice under different platforms and does not crash when using the generated lockfile" do
+ build_repo2
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack", :platform => :jruby
+ gem "rack"
+ G
+
+ bundle "install"
+
+ expect(err).to include("Your Gemfile lists the gem rack (>= 0) more than once.")
+ expect(err).to include("Remove any duplicate entries and specify the gem only once.")
+ expect(err).to include("While it's not a problem now, it could cause errors if you change the version of one of them later.")
+ end
+
it "does not throw a warning if a gem is added once in Gemfile and also inside a gemspec as a development dependency" do
- build_lib "my-gem", :path => bundled_app do |s|
+ build_lib "my-gem", path: bundled_app do |s|
s.add_development_dependency "my-private-gem"
end
@@ -395,8 +430,155 @@ RSpec.describe "bundle install with gem sources" do
expect(the_bundle).to include_gems("my-private-gem 1.0")
end
+ it "throws a warning if a gem is added once in Gemfile and also inside a gemspec as a development dependency, with different requirements" do
+ build_lib "my-gem", path: bundled_app do |s|
+ s.add_development_dependency "rubocop", "~> 1.36.0"
+ end
+
+ build_repo4 do
+ build_gem "rubocop", "1.36.0"
+ build_gem "rubocop", "1.37.1"
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gemspec
+
+ gem "rubocop", group: :development
+ G
+
+ bundle :install
+
+ expect(err).to include("A gemspec development dependency (rubocop, ~> 1.36.0) is being overridden by a Gemfile dependency (rubocop, >= 0).")
+ expect(err).to include("This behaviour may change in the future. Please remove either of them, or make sure they both have the same requirement")
+
+ # This is not the best behavior I believe, it would be better if both
+ # requirements are considered if they are compatible, and a version
+ # satisfying both is chosen. But not sure about changing it right now, so
+ # I went with a warning for the time being.
+ expect(the_bundle).to include_gems("rubocop 1.37.1")
+ end
+
+ it "includes the gem without warning if two gemspecs add it with the same requirement" do
+ gem1 = tmp.join("my-gem-1")
+ gem2 = tmp.join("my-gem-2")
+
+ build_lib "my-gem", path: gem1 do |s|
+ s.add_development_dependency "rubocop", "~> 1.36.0"
+ end
+
+ build_lib "my-gem-2", path: gem2 do |s|
+ s.add_development_dependency "rubocop", "~> 1.36.0"
+ end
+
+ build_repo4 do
+ build_gem "rubocop", "1.36.0"
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gemspec path: "#{gem1}"
+ gemspec path: "#{gem2}"
+ G
+
+ bundle :install
+
+ expect(err).to be_empty
+ expect(the_bundle).to include_gems("rubocop 1.36.0")
+ end
+
+ it "warns when a Gemfile dependency is overriding a gemspec development dependency, with different requirements" do
+ build_lib "my-gem", path: bundled_app do |s|
+ s.add_development_dependency "rails", ">= 5"
+ end
+
+ build_repo4 do
+ build_gem "rails", "7.0.8"
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "rails", "~> 7.0.8"
+
+ gemspec
+ G
+
+ bundle :install
+
+ expect(err).to include("A gemspec development dependency (rails, >= 5) is being overridden by a Gemfile dependency (rails, ~> 7.0.8).")
+ expect(err).to include("This behaviour may change in the future. Please remove either of them, or make sure they both have the same requirement")
+
+ # This is not the best behavior I believe, it would be better if both
+ # requirements are considered if they are compatible, and a version
+ # satisfying both is chosen. But not sure about changing it right now, so
+ # I went with a warning for the time being.
+ expect(the_bundle).to include_gems("rails 7.0.8")
+ end
+
+ it "does not warn if a gem is added once in Gemfile and also inside a gemspec as a development dependency, with same requirements, and different sources" do
+ build_lib "my-gem", path: bundled_app do |s|
+ s.add_development_dependency "activesupport"
+ end
+
+ build_repo4 do
+ build_gem "activesupport"
+ end
+
+ build_git "activesupport", "1.0", path: lib_path("activesupport")
+
+ install_gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gemspec
+
+ gem "activesupport", :git => "#{file_uri_for(lib_path("activesupport"))}"
+ G
+
+ expect(err).to be_empty
+ expect(the_bundle).to include_gems "activesupport 1.0", source: "git@#{lib_path("activesupport")}"
+
+ # if the Gemfile dependency is specified first
+ install_gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "activesupport", :git => "#{file_uri_for(lib_path("activesupport"))}"
+
+ gemspec
+ G
+
+ expect(err).to be_empty
+ expect(the_bundle).to include_gems "activesupport 1.0", source: "git@#{lib_path("activesupport")}"
+ end
+
+ it "considers both dependencies for resolution if a gem is added once in Gemfile and also inside a local gemspec as a runtime dependency, with different requirements" do
+ build_lib "my-gem", path: bundled_app do |s|
+ s.add_dependency "rubocop", "~> 1.36.0"
+ end
+
+ build_repo4 do
+ build_gem "rubocop", "1.36.0"
+ build_gem "rubocop", "1.37.1"
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gemspec
+
+ gem "rubocop"
+ G
+
+ bundle :install
+
+ expect(err).to be_empty
+ expect(the_bundle).to include_gems("rubocop 1.36.0")
+ end
+
it "throws an error if a gem is added twice in Gemfile when version of one dependency is not specified" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo2)}"
gem "rack"
gem "rack", "1.0"
@@ -407,7 +589,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "throws an error if a gem is added twice in Gemfile when different versions of both dependencies are specified" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo2)}"
gem "rack", "1.0"
gem "rack", "1.1"
@@ -420,7 +602,7 @@ RSpec.describe "bundle install with gem sources" do
it "gracefully handles error when rubygems server is unavailable" do
skip "networking issue" if Gem.win_platform?
- install_gemfile <<-G, :artifice => nil, :raise_on_error => false
+ install_gemfile <<-G, artifice: nil, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
source "http://0.0.0.0:9384" do
gem 'foo'
@@ -432,8 +614,8 @@ RSpec.describe "bundle install with gem sources" do
end
it "fails gracefully when downloading an invalid specification from the full index" do
- build_repo2 do
- build_gem "ajp-rails", "0.0.0", :gemspec => false, :skip_validation => true do |s|
+ build_repo2(build_compact_index: false) do
+ build_gem "ajp-rails", "0.0.0", gemspec: false, skip_validation: true do |s|
bad_deps = [["ruby-ajp", ">= 0.2.0"], ["rails", ">= 0.14"]]
s.
instance_variable_get(:@spec).
@@ -444,7 +626,7 @@ RSpec.describe "bundle install with gem sources" do
build_gem "ruby-ajp", "1.0.0"
end
- install_gemfile <<-G, :full_index => true, :raise_on_error => false
+ install_gemfile <<-G, full_index: true, raise_on_error: false
source "#{file_uri_for(gem_repo2)}"
gem "ajp-rails", "0.0.0"
@@ -479,31 +661,27 @@ RSpec.describe "bundle install with gem sources" do
end
describe "Ruby version in Gemfile.lock" do
- include Bundler::GemHelpers
-
context "and using an unsupported Ruby version" do
it "prints an error" do
- install_gemfile <<-G, :raise_on_error => false
- ::RUBY_VERSION = '2.0.1'
- ruby '~> 2.2'
+ install_gemfile <<-G, raise_on_error: false
+ ruby '~> 1.2'
source "#{file_uri_for(gem_repo1)}"
G
- expect(err).to include("Your Ruby version is 2.0.1, but your Gemfile specified ~> 2.2")
+ expect(err).to include("Your Ruby version is #{Gem.ruby_version}, but your Gemfile specified ~> 1.2")
end
end
context "and using a supported Ruby version" do
before do
install_gemfile <<-G
- ::RUBY_VERSION = '2.1.3'
- ::RUBY_PATCHLEVEL = 100
- ruby '~> 2.1.0'
+ ruby '~> #{Gem.ruby_version}'
source "#{file_uri_for(gem_repo1)}"
G
end
it "writes current Ruby version to Gemfile.lock" do
- lockfile_should_be <<-L
+ checksums = checksums_section_when_existing
+ expect(lockfile).to eq <<~L
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
@@ -512,24 +690,24 @@ RSpec.describe "bundle install with gem sources" do
#{lockfile_platforms}
DEPENDENCIES
-
+ #{checksums}
RUBY VERSION
- ruby 2.1.3p100
+ #{Bundler::RubyVersion.system}
BUNDLED WITH
#{Bundler::VERSION}
L
end
- it "updates Gemfile.lock with updated incompatible ruby version" do
+ it "updates Gemfile.lock with updated yet still compatible ruby version" do
install_gemfile <<-G
- ::RUBY_VERSION = '2.2.3'
- ::RUBY_PATCHLEVEL = 100
- ruby '~> 2.2.0'
+ ruby '~> #{current_ruby_minor}'
source "#{file_uri_for(gem_repo1)}"
G
- lockfile_should_be <<-L
+ checksums = checksums_section_when_existing
+
+ expect(lockfile).to eq <<~L
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
@@ -538,9 +716,9 @@ RSpec.describe "bundle install with gem sources" do
#{lockfile_platforms}
DEPENDENCIES
-
+ #{checksums}
RUBY VERSION
- ruby 2.2.3p100
+ #{Bundler::RubyVersion.system}
BUNDLED WITH
#{Bundler::VERSION}
@@ -575,7 +753,7 @@ RSpec.describe "bundle install with gem sources" do
file.puts gemfile
end
- bundle :install, :dir => root_dir
+ bundle :install, dir: root_dir
end
it "doesn't blow up when using the `gemspec` DSL" do
@@ -583,7 +761,7 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.mkdir_p(root_dir)
- build_lib "foo", :path => root_dir
+ build_lib "foo", path: root_dir
gemfile = <<-G
source "#{file_uri_for(gem_repo1)}"
gemspec
@@ -592,7 +770,7 @@ RSpec.describe "bundle install with gem sources" do
file.puts gemfile
end
- bundle :install, :dir => root_dir
+ bundle :install, dir: root_dir
end
end
@@ -605,7 +783,7 @@ RSpec.describe "bundle install with gem sources" do
gem 'rack'
G
- bundle :install, :quiet => true
+ bundle :install, quiet: true
expect(out).to be_empty
expect(err).to be_empty
end
@@ -635,7 +813,7 @@ RSpec.describe "bundle install with gem sources" do
gem 'non-existing-gem'
G
- bundle :install, :quiet => true, :raise_on_error => false, :env => { "RUBYOPT" => "-r#{bundled_app("install_with_warning.rb")}" }
+ bundle :install, quiet: true, raise_on_error: false, env: { "RUBYOPT" => "-r#{bundled_app("install_with_warning.rb")}" }
expect(out).to be_empty
expect(err).to include("Could not find gem 'non-existing-gem'")
expect(err).to include("BOOOOO")
@@ -657,12 +835,174 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.chmod(0o500, bundle_path)
bundle "config set --local path vendor"
- bundle :install, :raise_on_error => false
+ bundle :install, raise_on_error: false
expect(err).to include(bundle_path.to_s)
expect(err).to include("grant write permissions")
end
end
+ describe "when bundle gems path does not have write access", :permissions do
+ let(:gems_path) { bundled_app("vendor/#{Bundler.ruby_scope}/gems") }
+
+ before do
+ FileUtils.mkdir_p(gems_path)
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
+ G
+ end
+
+ it "should display a proper message to explain the problem" do
+ FileUtils.chmod("-x", gems_path)
+ bundle "config set --local path vendor"
+
+ begin
+ bundle :install, raise_on_error: false
+ ensure
+ FileUtils.chmod("+x", gems_path)
+ end
+
+ expect(err).not_to include("ERROR REPORT TEMPLATE")
+
+ expect(err).to include(
+ "There was an error while trying to create `#{gems_path.join("rack-1.0.0")}`. " \
+ "It is likely that you need to grant executable permissions for all parent directories and write permissions for `#{gems_path}`."
+ )
+ end
+ end
+
+ describe "when bundle extensions path does not have write access", :permissions do
+ let(:extensions_path) { bundled_app("vendor/#{Bundler.ruby_scope}/extensions/#{Gem::Platform.local}/#{Gem.extension_api_version}") }
+
+ before do
+ FileUtils.mkdir_p(extensions_path)
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'simple_binary'
+ G
+ end
+
+ it "should display a proper message to explain the problem" do
+ FileUtils.chmod("-x", extensions_path)
+ bundle "config set --local path vendor"
+
+ begin
+ bundle :install, raise_on_error: false
+ ensure
+ FileUtils.chmod("+x", extensions_path)
+ end
+
+ expect(err).not_to include("ERROR REPORT TEMPLATE")
+
+ expect(err).to include(
+ "There was an error while trying to create `#{extensions_path.join("simple_binary-1.0")}`. " \
+ "It is likely that you need to grant executable permissions for all parent directories and write permissions for `#{extensions_path}`."
+ )
+ end
+ end
+
+ describe "when the path of a specific gem is not writable", :permissions do
+ let(:gems_path) { bundled_app("vendor/#{Bundler.ruby_scope}/gems") }
+ let(:foo_path) { gems_path.join("foo-1.0.0") }
+
+ before do
+ build_repo4 do
+ build_gem "foo", "1.0.0" do |s|
+ s.write "CHANGELOG.md", "foo"
+ end
+ end
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem 'foo'
+ G
+ end
+
+ it "should display a proper message to explain the problem" do
+ bundle "config set --local path vendor"
+ bundle :install
+ expect(out).to include("Bundle complete!")
+ expect(err).to be_empty
+
+ FileUtils.chmod("-x", foo_path)
+
+ begin
+ bundle "install --redownload", raise_on_error: false
+ ensure
+ FileUtils.chmod("+x", foo_path)
+ end
+
+ expect(err).not_to include("ERROR REPORT TEMPLATE")
+ expect(err).to include("Could not delete previous installation of `#{foo_path}`.")
+ expect(err).to include("The underlying error was Errno::EACCES")
+ end
+ end
+
+ describe "when gem home does not have the writable bit set, yet it's still writable", :permissions do
+ let(:gem_home) { bundled_app("vendor/#{Bundler.ruby_scope}") }
+
+ before do
+ build_repo4 do
+ build_gem "foo", "1.0.0" do |s|
+ s.write "CHANGELOG.md", "foo"
+ end
+ end
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem 'foo'
+ G
+ end
+
+ it "should display a proper message to explain the problem" do
+ bundle "config set --local path vendor"
+ bundle :install
+ expect(out).to include("Bundle complete!")
+ expect(err).to be_empty
+
+ FileUtils.chmod("-w", gem_home)
+
+ begin
+ bundle "install --redownload"
+ ensure
+ FileUtils.chmod("+w", gem_home)
+ end
+
+ expect(out).to include("Bundle complete!")
+ expect(err).to be_empty
+ end
+ end
+
+ describe "when gems path is world writable (no sticky bit set)", :permissions do
+ let(:gems_path) { bundled_app("vendor/#{Bundler.ruby_scope}/gems") }
+
+ before do
+ build_repo4 do
+ build_gem "foo", "1.0.0" do |s|
+ s.write "CHANGELOG.md", "foo"
+ end
+ end
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem 'foo'
+ G
+ end
+
+ it "should display a proper message to explain the problem" do
+ bundle "config set --local path vendor"
+ bundle :install
+ expect(out).to include("Bundle complete!")
+ expect(err).to be_empty
+
+ FileUtils.chmod(0o777, gems_path)
+
+ bundle "install --redownload", raise_on_error: false
+
+ expect(err).to include("The installation path is insecure. Bundler cannot continue.")
+ end
+ end
+
describe "when bundle cache path does not have write access", :permissions do
let(:cache_path) { bundled_app("vendor/#{Bundler.ruby_scope}/cache") }
@@ -678,7 +1018,7 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.chmod(0o500, cache_path)
bundle "config set --local path vendor"
- bundle :install, :raise_on_error => false
+ bundle :install, raise_on_error: false
expect(err).to include(cache_path.to_s)
expect(err).to include("grant write permissions")
end
@@ -691,13 +1031,13 @@ RSpec.describe "bundle install with gem sources" do
gem "rack"
G
bundle "config set --local path bundle"
- bundle "install", :standalone => true
+ bundle "install", standalone: true
end
it "includes the standalone path" do
- bundle "binstubs rack", :standalone => true
+ bundle "binstubs rack", standalone: true
standalone_line = File.read(bundled_app("bin/rackup")).each_line.find {|line| line.include? "$:.unshift" }.strip
- expect(standalone_line).to eq %($:.unshift File.expand_path "../../bundle", path.realpath)
+ expect(standalone_line).to eq %($:.unshift File.expand_path "../bundle", __dir__)
end
end
@@ -710,7 +1050,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "should display a helpful message explaining how to fix it" do
- bundle :install, :env => { "BUNDLE_RUBYGEMS__ORG" => "user:pass{word" }, :raise_on_error => false
+ bundle :install, env: { "BUNDLE_RUBYGEMS__ORG" => "user:pass{word" }, raise_on_error: false
expect(exitstatus).to eq(17)
expect(err).to eq("Please CGI escape your usernames and passwords before " \
"setting them for authentication.")
@@ -751,12 +1091,297 @@ RSpec.describe "bundle install with gem sources" do
end
it "should fail loudly if the lockfile platforms don't include the current platform" do
- simulate_platform(Gem::Platform.new("x86_64-linux")) { bundle "install", :raise_on_error => false }
+ simulate_platform(Gem::Platform.new("x86_64-linux")) { bundle "install", raise_on_error: false }
expect(err).to eq(
"Your bundle only supports platforms [\"x86_64-darwin-19\"] but your local platform is x86_64-linux. " \
- "Add the current platform to the lockfile with `bundle lock --add-platform x86_64-linux` and try again."
+ "Add the current platform to the lockfile with\n`bundle lock --add-platform x86_64-linux` and try again."
)
end
end
+
+ context "with missing platform specific gems in lockfile" do
+ before do
+ build_repo4 do
+ build_gem "racca", "1.5.2"
+
+ build_gem "nokogiri", "1.12.4" do |s|
+ s.platform = "x86_64-darwin"
+ s.add_runtime_dependency "racca", "~> 1.4"
+ end
+
+ build_gem "nokogiri", "1.12.4" do |s|
+ s.platform = "x86_64-linux"
+ s.add_runtime_dependency "racca", "~> 1.4"
+ end
+
+ build_gem "crass", "1.0.6"
+
+ build_gem "loofah", "2.12.0" do |s|
+ s.add_runtime_dependency "crass", "~> 1.0.2"
+ s.add_runtime_dependency "nokogiri", ">= 1.5.9"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo4"
+
+ ruby "#{Gem.ruby_version}"
+
+ gem "loofah", "~> 2.12.0"
+ G
+
+ checksums = checksums_section do |c|
+ c.checksum gem_repo4, "crass", "1.0.6"
+ c.checksum gem_repo4, "loofah", "2.12.0"
+ c.checksum gem_repo4, "nokogiri", "1.12.4", "x86_64-darwin"
+ c.checksum gem_repo4, "racca", "1.5.2"
+ end
+
+ lockfile <<-L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ crass (1.0.6)
+ loofah (2.12.0)
+ crass (~> 1.0.2)
+ nokogiri (>= 1.5.9)
+ nokogiri (1.12.4-x86_64-darwin)
+ racca (~> 1.4)
+ racca (1.5.2)
+
+ PLATFORMS
+ x86_64-darwin-20
+ x86_64-linux
+
+ DEPENDENCIES
+ loofah (~> 2.12.0)
+ #{checksums}
+ RUBY VERSION
+ #{Bundler::RubyVersion.system}
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "automatically fixes the lockfile" do
+ bundle "config set --local path vendor/bundle"
+
+ simulate_platform "x86_64-linux" do
+ bundle "install", artifice: "compact_index"
+ end
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "crass", "1.0.6"
+ c.checksum gem_repo4, "loofah", "2.12.0"
+ c.checksum gem_repo4, "nokogiri", "1.12.4", "x86_64-darwin"
+ c.checksum gem_repo4, "racca", "1.5.2"
+ c.checksum gem_repo4, "nokogiri", "1.12.4", "x86_64-linux"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ crass (1.0.6)
+ loofah (2.12.0)
+ crass (~> 1.0.2)
+ nokogiri (>= 1.5.9)
+ nokogiri (1.12.4-x86_64-darwin)
+ racca (~> 1.4)
+ nokogiri (1.12.4-x86_64-linux)
+ racca (~> 1.4)
+ racca (1.5.2)
+
+ PLATFORMS
+ x86_64-darwin-20
+ x86_64-linux
+
+ DEPENDENCIES
+ loofah (~> 2.12.0)
+ #{checksums}
+ RUBY VERSION
+ #{Bundler::RubyVersion.system}
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ context "with --local flag" do
+ before do
+ system_gems "rack-1.0.0", path: default_bundle_path
+ end
+
+ it "respects installed gems without fetching any remote sources" do
+ install_gemfile <<-G, local: true
+ source "#{file_uri_for(gem_repo1)}"
+
+ source "https://not-existing-source" do
+ gem "rack"
+ end
+ G
+
+ expect(last_command).to be_success
+ end
+ end
+
+ context "with only option" do
+ before do
+ bundle "config set only a:b"
+ end
+
+ it "installs only gems of the specified groups" do
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rails"
+ gem "rack", group: :a
+ gem "rake", group: :b
+ gem "yard", group: :c
+ G
+
+ expect(out).to include("Installing rack")
+ expect(out).to include("Installing rake")
+ expect(out).not_to include("Installing yard")
+ end
+ end
+
+ context "with --prefer-local flag" do
+ before do
+ build_repo4 do
+ build_gem "foo", "1.0.1"
+ build_gem "foo", "1.0.0"
+ build_gem "bar", "1.0.0"
+ end
+
+ system_gems "foo-1.0.0", path: default_bundle_path, gem_repo: gem_repo4
+ end
+
+ it "fetches remote sources only when not available locally" do
+ install_gemfile <<-G, "prefer-local": true, verbose: true
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "foo"
+ gem "bar"
+ G
+
+ expect(out).to include("Using foo 1.0.0").and include("Fetching bar 1.0.0").and include("Installing bar 1.0.0")
+ expect(last_command).to be_success
+ end
+ end
+
+ context "with a symlinked configured as bundle path and a gem with symlinks" do
+ before do
+ symlinked_bundled_app = tmp("bundled_app-symlink")
+ File.symlink(bundled_app, symlinked_bundled_app)
+ bundle "config path #{File.join(symlinked_bundled_app, ".vendor")}"
+
+ binman_path = tmp("binman")
+ FileUtils.mkdir_p binman_path
+
+ readme_path = File.join(binman_path, "README.markdown")
+ FileUtils.touch(readme_path)
+
+ man_path = File.join(binman_path, "man", "man0")
+ FileUtils.mkdir_p man_path
+
+ File.symlink("../../README.markdown", File.join(man_path, "README.markdown"))
+
+ build_repo4 do
+ build_gem "binman", path: gem_repo4("gems"), lib_path: binman_path, no_default: true do |s|
+ s.files = ["README.markdown", "man/man0/README.markdown"]
+ end
+ end
+ end
+
+ it "installs fine" do
+ install_gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "binman"
+ G
+ end
+ end
+
+ context "when a gem has equivalent versions with inconsistent dependencies" do
+ before do
+ build_repo4 do
+ build_gem "autobuild", "1.10.rc2" do |s|
+ s.add_dependency "utilrb", ">= 1.6.0"
+ end
+
+ build_gem "autobuild", "1.10.0.rc2" do |s|
+ s.add_dependency "utilrb", ">= 2.0"
+ end
+ end
+ end
+
+ it "does not crash unexpectedly" do
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "autobuild", "1.10.rc2"
+ G
+
+ bundle "install --jobs 1", raise_on_error: false
+
+ expect(err).not_to include("ERROR REPORT TEMPLATE")
+ expect(err).to include("Could not find compatible versions")
+ end
+ end
+
+ context "when a lockfile has unmet dependencies, and the Gemfile has no resolution" do
+ before do
+ build_repo4 do
+ build_gem "aaa", "0.2.0" do |s|
+ s.add_dependency "zzz", "< 0.2.0"
+ end
+
+ build_gem "zzz", "0.2.0"
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "aaa"
+ gem "zzz"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ aaa (0.2.0)
+ zzz (< 0.2.0)
+ zzz (0.2.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ aaa!
+ zzz!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "does not install, but raises a resolution error" do
+ bundle "install", raise_on_error: false
+ expect(err).to include("Could not find compatible versions")
+ end
+ end
+
+ context "when --jobs option given" do
+ before do
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"", jobs: 1
+ end
+
+ it "does not save the flag to config" do
+ expect(bundled_app(".bundle/config")).not_to exist
+ end
+ end
end
diff --git a/spec/bundler/commands/list_spec.rb b/spec/bundler/commands/list_spec.rb
index 66930ded75..5ac2077d81 100644
--- a/spec/bundler/commands/list_spec.rb
+++ b/spec/bundler/commands/list_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe "bundle list" do
context "with name-only and paths option" do
it "raises an error" do
- bundle "list --name-only --paths", :raise_on_error => false
+ bundle "list --name-only --paths", raise_on_error: false
expect(err).to eq "The `--name-only` and `--paths` options cannot be used together"
end
@@ -11,7 +11,7 @@ RSpec.describe "bundle list" do
context "with without-group and only-group option" do
it "raises an error" do
- bundle "list --without-group dev --only-group test", :raise_on_error => false
+ bundle "list --without-group dev --only-group test", raise_on_error: false
expect(err).to eq "The `--only-group` and `--without-group` options cannot be used together"
end
@@ -40,7 +40,7 @@ RSpec.describe "bundle list" do
context "when group is not found" do
it "raises an error" do
- bundle "list --without-group random", :raise_on_error => false
+ bundle "list --without-group random", raise_on_error: false
expect(err).to eq "`random` group could not be found."
end
@@ -79,7 +79,7 @@ RSpec.describe "bundle list" do
context "when group is not found" do
it "raises an error" do
- bundle "list --only-group random", :raise_on_error => false
+ bundle "list --only-group random", raise_on_error: false
expect(err).to eq "`random` group could not be found."
end
@@ -124,9 +124,9 @@ RSpec.describe "bundle list" do
build_gem "bar"
end
- build_git "git_test", "1.0.0", :path => lib_path("git_test")
+ build_git "git_test", "1.0.0", path: lib_path("git_test")
- build_lib("gemspec_test", :path => tmp.join("gemspec_test")) do |s|
+ build_lib("gemspec_test", path: tmp.join("gemspec_test")) do |s|
s.add_dependency "bar", "=1.0.0"
end
diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb
index 21eb6e5456..f6793d393b 100644
--- a/spec/bundler/commands/lock_spec.rb
+++ b/spec/bundler/commands/lock_spec.rb
@@ -1,14 +1,6 @@
# frozen_string_literal: true
RSpec.describe "bundle lock" do
- def strip_lockfile(lockfile)
- strip_whitespace(lockfile).sub(/\n\Z/, "")
- end
-
- def read_lockfile(file = "Gemfile.lock")
- strip_lockfile bundled_app(file).read
- end
-
let(:repo) { gem_repo1 }
before :each do
@@ -19,7 +11,19 @@ RSpec.describe "bundle lock" do
gem "foo"
G
- @lockfile = strip_lockfile(<<-L)
+ checksums = checksums_section_when_existing do |c|
+ c.checksum repo, "actionmailer", "2.3.2"
+ c.checksum repo, "actionpack", "2.3.2"
+ c.checksum repo, "activerecord", "2.3.2"
+ c.checksum repo, "activeresource", "2.3.2"
+ c.checksum repo, "activesupport", "2.3.2"
+ c.checksum repo, "foo", "1.0"
+ c.checksum repo, "rails", "2.3.2"
+ c.checksum repo, "rake", rake_version
+ c.checksum repo, "weakling", "0.0.3"
+ end
+
+ @lockfile = <<~L
GEM
remote: #{file_uri_for(repo)}/
specs:
@@ -38,8 +42,8 @@ RSpec.describe "bundle lock" do
actionpack (= 2.3.2)
activerecord (= 2.3.2)
activeresource (= 2.3.2)
- rake (= 13.0.1)
- rake (13.0.1)
+ rake (= #{rake_version})
+ rake (#{rake_version})
weakling (0.0.3)
PLATFORMS
@@ -49,7 +53,7 @@ RSpec.describe "bundle lock" do
foo
rails
weakling
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -58,15 +62,23 @@ RSpec.describe "bundle lock" do
it "prints a lockfile when there is no existing lockfile with --print" do
bundle "lock --print"
- expect(out).to eq(@lockfile)
+ expect(out).to eq(@lockfile.chomp)
end
it "prints a lockfile when there is an existing lockfile with --print" do
+ lockfile remove_checksums_section_from_lockfile(@lockfile)
+
+ bundle "lock --print"
+
+ expect(out).to eq(remove_checksums_section_from_lockfile(@lockfile).chomp)
+ end
+
+ it "prints a lockfile when there is an existing checksums lockfile with --print" do
lockfile @lockfile
bundle "lock --print"
- expect(out).to eq(@lockfile)
+ expect(out).to eq(@lockfile.chomp)
end
it "writes a lockfile when there is no existing lockfile" do
@@ -75,7 +87,39 @@ RSpec.describe "bundle lock" do
expect(read_lockfile).to eq(@lockfile)
end
+ it "prints a lockfile without fetching new checksums if the existing lockfile had no checksums" do
+ lockfile remove_checksums_from_lockfile(@lockfile)
+
+ bundle "lock --print"
+
+ expect(out).to eq(remove_checksums_from_lockfile(@lockfile).chomp)
+ end
+
+ it "touches the lockfile when there is an existing lockfile that does not need changes" do
+ lockfile @lockfile
+
+ expect do
+ bundle "lock"
+ end.to change { bundled_app_lock.mtime }
+ end
+
+ it "does not touch lockfile with --print" do
+ lockfile @lockfile
+
+ expect do
+ bundle "lock --print"
+ end.not_to change { bundled_app_lock.mtime }
+ end
+
it "writes a lockfile when there is an outdated lockfile using --update" do
+ lockfile remove_checksums_from_lockfile(@lockfile.gsub("2.3.2", "2.3.1"), " (2.3.1)")
+
+ bundle "lock --update"
+
+ expect(read_lockfile).to eq(remove_checksums_from_lockfile(@lockfile))
+ end
+
+ it "writes a lockfile with checksums on --update when checksums exist" do
lockfile @lockfile.gsub("2.3.2", "2.3.1")
bundle "lock --update"
@@ -83,10 +127,27 @@ RSpec.describe "bundle lock" do
expect(read_lockfile).to eq(@lockfile)
end
+ it "writes a lockfile when there is an outdated lockfile and bundle is frozen" do
+ lockfile @lockfile.gsub("2.3.2", "2.3.1")
+
+ bundle "lock --update", env: { "BUNDLE_FROZEN" => "true" }
+
+ expect(read_lockfile).to eq(@lockfile)
+ end
+
it "does not fetch remote specs when using the --local option" do
- bundle "lock --update --local", :raise_on_error => false
+ bundle "lock --update --local", raise_on_error: false
- expect(err).to match(/installed locally/)
+ expect(err).to match(/cached gems or installed locally/)
+ end
+
+ it "does not fetch remote checksums with --local" do
+ lockfile remove_checksums_from_lockfile(@lockfile)
+
+ bundle "lock --print --local"
+
+ # No checksums because --local prevents fetching them
+ expect(out).to eq(remove_checksums_from_lockfile(@lockfile).chomp)
end
it "works with --gemfile flag" do
@@ -94,7 +155,11 @@ RSpec.describe "bundle lock" do
source "#{file_uri_for(repo)}"
gem "foo"
G
- lockfile = strip_lockfile(<<-L)
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ end
+
+ lockfile = <<~L
GEM
remote: #{file_uri_for(repo)}/
specs:
@@ -105,7 +170,7 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
foo
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -120,7 +185,7 @@ RSpec.describe "bundle lock" do
bundle "lock --lockfile=lock"
expect(out).to match(/Writing lockfile to.+lock/)
- expect(read_lockfile("lock")).to eq(@lockfile)
+ expect(read_lockfile("lock")).to eq(remove_checksums_from_lockfile(@lockfile))
expect { read_lockfile }.to raise_error(Errno::ENOENT)
end
@@ -128,22 +193,135 @@ RSpec.describe "bundle lock" do
bundle "install"
bundle "lock --lockfile=lock"
+ checksums = checksums_section_when_existing do |c|
+ c.checksum repo, "actionmailer", "2.3.2"
+ c.checksum repo, "actionpack", "2.3.2"
+ c.checksum repo, "activerecord", "2.3.2"
+ c.checksum repo, "activeresource", "2.3.2"
+ c.checksum repo, "activesupport", "2.3.2"
+ c.checksum repo, "foo", "1.0"
+ c.checksum repo, "rails", "2.3.2"
+ c.checksum repo, "rake", rake_version
+ c.checksum repo, "weakling", "0.0.3"
+ end
+
+ lockfile = <<~L
+ GEM
+ remote: #{file_uri_for(repo)}/
+ specs:
+ actionmailer (2.3.2)
+ activesupport (= 2.3.2)
+ actionpack (2.3.2)
+ activesupport (= 2.3.2)
+ activerecord (2.3.2)
+ activesupport (= 2.3.2)
+ activeresource (2.3.2)
+ activesupport (= 2.3.2)
+ activesupport (2.3.2)
+ foo (1.0)
+ rails (2.3.2)
+ actionmailer (= 2.3.2)
+ actionpack (= 2.3.2)
+ activerecord (= 2.3.2)
+ activeresource (= 2.3.2)
+ rake (= #{rake_version})
+ rake (#{rake_version})
+ weakling (0.0.3)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ foo
+ rails
+ weakling
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
expect(out).to match(/Writing lockfile to.+lock/)
- expect(read_lockfile("lock")).to eq(@lockfile)
+ expect(read_lockfile("lock")).to eq(lockfile)
end
it "update specific gems using --update" do
- lockfile @lockfile.gsub("2.3.2", "2.3.1").gsub("13.0.1", "10.0.1")
+ lockfile @lockfile.gsub("2.3.2", "2.3.1").gsub(rake_version, "10.0.1")
bundle "lock --update rails rake"
- expect(read_lockfile).to eq(@lockfile)
+ expect(read_lockfile).to eq(remove_checksums_from_lockfile(@lockfile, "(2.3.2)", "(#{rake_version})"))
+ end
+
+ it "preserves unknown checksum algorithms" do
+ lockfile @lockfile.gsub(/(sha256=[a-f0-9]+)$/, "constant=true,\\1,xyz=123")
+
+ previous_lockfile = read_lockfile
+
+ bundle "lock"
+
+ expect(read_lockfile).to eq(previous_lockfile)
+ end
+
+ it "does not unlock git sources when only uri shape changes" do
+ build_git("foo")
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo-1.0"))}"
+ G
+
+ # Change uri format to end with "/" and reinstall
+ install_gemfile <<-G, verbose: true
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo-1.0"))}/"
+ G
+
+ expect(out).to include("using resolution from the lockfile")
+ expect(out).not_to include("re-resolving dependencies because the list of sources changed")
+ end
+
+ it "updates specific gems using --update using the locked revision of unrelated git gems for resolving" do
+ ref = build_git("foo").ref_for("HEAD")
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rake"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo-1.0"))}", :branch => "deadbeef"
+ G
+
+ lockfile <<~L
+ GIT
+ remote: #{file_uri_for(lib_path("foo-1.0"))}
+ revision: #{ref}
+ branch: deadbeef
+ specs:
+ foo (1.0)
+
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+ rake (10.0.1)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ foo!
+ rake
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "lock --update rake --verbose"
+ expect(out).to match(/Writing lockfile to.+lock/)
+ expect(lockfile).to include("rake (#{rake_version})")
end
it "errors when updating a missing specific gems using --update" do
lockfile @lockfile
- bundle "lock --update blahblah", :raise_on_error => false
+ bundle "lock --update blahblah", raise_on_error: false
expect(err).to eq("Could not find gem 'blahblah'.")
expect(read_lockfile).to eq(@lockfile)
@@ -157,9 +335,9 @@ RSpec.describe "bundle lock" do
gem "rack_middleware", :group => "test"
G
bundle "config set without test"
- bundle "config set path .bundle"
- bundle "lock"
- expect(bundled_app(".bundle")).not_to exist
+ bundle "config set path vendor/bundle"
+ bundle "lock", verbose: true
+ expect(bundled_app("vendor/bundle")).not_to exist
end
# see update_spec for more coverage on same options. logic is shared so it's not necessary
@@ -176,7 +354,10 @@ RSpec.describe "bundle lock" do
build_gem "foo", %w[1.5.1] do |s|
s.add_dependency "bar", "~> 3.0"
end
- build_gem "bar", %w[2.0.3 2.0.4 2.0.5 2.1.0 2.1.1 3.0.0]
+ build_gem "foo", %w[2.0.0.pre] do |s|
+ s.add_dependency "bar"
+ end
+ build_gem "bar", %w[2.0.3 2.0.4 2.0.5 2.1.0 2.1.1 2.1.2.pre 3.0.0 3.1.0.pre 4.0.0.pre]
build_gem "qux", %w[1.0.0 1.0.1 1.1.0 2.0.0]
end
@@ -210,6 +391,112 @@ RSpec.describe "bundle lock" do
expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[foo-1.5.0 bar-2.1.1 qux-1.1.0].sort)
end
+
+ it "shows proper error when Gemfile changes forbid patch upgrades, and --patch --strict is given" do
+ # force next minor via Gemfile
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem 'foo', '1.5.0'
+ gem 'qux'
+ G
+
+ bundle "lock --update foo --patch --strict", raise_on_error: false
+
+ expect(err).to include(
+ "foo is locked to 1.4.3, while Gemfile is requesting foo (= 1.5.0). " \
+ "--strict --patch was specified, but there are no patch level upgrades from 1.4.3 satisfying foo (= 1.5.0), so version solving has failed"
+ )
+ end
+
+ context "pre" do
+ it "defaults to major" do
+ bundle "lock --update --pre"
+
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[foo-2.0.0.pre bar-4.0.0.pre qux-2.0.0].sort)
+ end
+
+ it "patch preferred" do
+ bundle "lock --update --patch --pre"
+
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[foo-1.4.5 bar-2.1.2.pre qux-1.0.1].sort)
+ end
+
+ it "minor preferred" do
+ bundle "lock --update --minor --pre"
+
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[foo-1.5.1 bar-3.1.0.pre qux-1.1.0].sort)
+ end
+
+ it "major preferred" do
+ bundle "lock --update --major --pre"
+
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[foo-2.0.0.pre bar-4.0.0.pre qux-2.0.0].sort)
+ end
+ end
+ end
+
+ context "conservative updates when minor update adds a new dependency" do
+ before do
+ build_repo4 do
+ build_gem "sequel", "5.71.0"
+ build_gem "sequel", "5.72.0" do |s|
+ s.add_dependency "bigdecimal", ">= 0"
+ end
+ build_gem "bigdecimal", %w[1.4.4 99.1.4]
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+ gem 'sequel'
+ G
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ sequel (5.71.0)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ sequel
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
+ end
+
+ it "adds the latest version of the new dependency" do
+ bundle "lock --minor --update sequel"
+
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[sequel-5.72.0 bigdecimal-99.1.4].sort)
+ end
+ end
+
+ it "updates the bundler version in the lockfile to the latest bundler version" do
+ build_repo4 do
+ build_gem "bundler", "55"
+ end
+
+ system_gems "bundler-55", gem_repo: gem_repo4
+
+ install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ source "https://gems.repo4"
+ G
+ lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, '\11.0.0\2')
+
+ bundle "lock --update --bundler --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ expect(lockfile).to end_with("BUNDLED WITH\n 55\n")
+
+ update_repo4 do
+ build_gem "bundler", "99"
+ end
+
+ bundle "lock --update --bundler --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ expect(lockfile).to end_with("BUNDLED WITH\n 99\n")
end
it "supports adding new platforms" do
@@ -217,7 +504,7 @@ RSpec.describe "bundle lock" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
lockfile = Bundler::LockfileParser.new(read_lockfile)
- expect(lockfile.platforms).to match_array(local_platforms.unshift(java, mingw).uniq)
+ expect(lockfile.platforms).to match_array(default_platform_list(java, x86_mingw32))
end
it "supports adding new platforms with force_ruby_platform = true" do
@@ -226,11 +513,11 @@ RSpec.describe "bundle lock" do
remote: #{file_uri_for(gem_repo1)}/
specs:
platform_specific (1.0)
- platform_specific (1.0-x86-linux)
+ platform_specific (1.0-x86-64_linux)
PLATFORMS
ruby
- x86-linux
+ x86_64-linux
DEPENDENCIES
platform_specific
@@ -241,7 +528,7 @@ RSpec.describe "bundle lock" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
lockfile = Bundler::LockfileParser.new(read_lockfile)
- expect(lockfile.platforms).to contain_exactly(rb, linux, java, mingw)
+ expect(lockfile.platforms).to contain_exactly(rb, linux, java, x86_mingw32)
end
it "supports adding the `ruby` platform" do
@@ -249,7 +536,7 @@ RSpec.describe "bundle lock" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
lockfile = Bundler::LockfileParser.new(read_lockfile)
- expect(lockfile.platforms).to match_array(local_platforms.unshift("ruby").uniq)
+ expect(lockfile.platforms).to match_array(default_platform_list("ruby"))
end
it "warns when adding an unknown platform" do
@@ -262,16 +549,78 @@ RSpec.describe "bundle lock" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
lockfile = Bundler::LockfileParser.new(read_lockfile)
- expect(lockfile.platforms).to match_array(local_platforms.unshift(java, mingw).uniq)
+ expect(lockfile.platforms).to match_array(default_platform_list(java, x86_mingw32))
bundle "lock --remove-platform java"
lockfile = Bundler::LockfileParser.new(read_lockfile)
- expect(lockfile.platforms).to match_array(local_platforms.unshift(mingw).uniq)
+ expect(lockfile.platforms).to match_array(default_platform_list(x86_mingw32))
+ end
+
+ it "also cleans up redundant platform gems when removing platforms" do
+ build_repo4 do
+ build_gem "nokogiri", "1.12.0"
+ build_gem "nokogiri", "1.12.0" do |s|
+ s.platform = "x86_64-darwin"
+ end
+ end
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "nokogiri", "1.12.0"
+ c.checksum gem_repo4, "nokogiri", "1.12.0", "x86_64-darwin"
+ end
+
+ simulate_platform "x86_64-darwin-22" do
+ install_gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "nokogiri"
+ G
+ end
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ nokogiri (1.12.0)
+ nokogiri (1.12.0-x86_64-darwin)
+
+ PLATFORMS
+ ruby
+ x86_64-darwin
+
+ DEPENDENCIES
+ nokogiri
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ checksums.delete("nokogiri", Gem::Platform::RUBY)
+
+ simulate_platform "x86_64-darwin-22" do
+ bundle "lock --remove-platform ruby"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ nokogiri (1.12.0-x86_64-darwin)
+
+ PLATFORMS
+ x86_64-darwin
+
+ DEPENDENCIES
+ nokogiri
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
end
it "errors when removing all platforms" do
- bundle "lock --remove-platform #{local_platforms.join(" ")}", :raise_on_error => false
+ bundle "lock --remove-platform #{local_platform}", raise_on_error: false
expect(err).to include("Removing all platforms from the bundle is not allowed")
end
@@ -280,7 +629,7 @@ RSpec.describe "bundle lock" do
build_repo4 do
build_gem "ffi", "1.9.14"
build_gem "ffi", "1.9.14" do |s|
- s.platform = mingw
+ s.platform = x86_mingw32
end
build_gem "gssapi", "0.1"
@@ -312,9 +661,16 @@ RSpec.describe "bundle lock" do
gem "gssapi"
G
- simulate_platform(mingw) { bundle :lock }
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "ffi", "1.9.14", "x86-mingw32"
+ c.no_checksum "gssapi", "1.2.0"
+ c.no_checksum "mixlib-shellout", "2.2.6", "universal-mingw32"
+ c.no_checksum "win32-process", "0.8.3"
+ end
- lockfile_should_be <<-G
+ simulate_platform(x86_mingw32) { bundle :lock }
+
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo4)}/
specs:
@@ -332,14 +688,18 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
gssapi
mixlib-shellout
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
- simulate_platform(rb) { bundle :lock }
+ bundle "config set --local force_ruby_platform true"
+ bundle :lock
+
+ checksums.no_checksum "ffi", "1.9.14"
+ checksums.no_checksum "mixlib-shellout", "2.2.6"
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo4)}/
specs:
@@ -360,7 +720,7 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
gssapi
mixlib-shellout
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -424,9 +784,14 @@ RSpec.describe "bundle lock" do
gem "libv8"
G
- simulate_platform(Gem::Platform.new("x86_64-darwin")) { bundle "lock" }
+ simulate_platform(Gem::Platform.new("x86_64-darwin-19")) { bundle "lock" }
+
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "libv8", "8.4.255.0", "x86_64-darwin-19"
+ c.no_checksum "libv8", "8.4.255.0", "x86_64-darwin-20"
+ end
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo4)}/
specs:
@@ -434,11 +799,12 @@ RSpec.describe "bundle lock" do
libv8 (8.4.255.0-x86_64-darwin-20)
PLATFORMS
- x86_64-darwin
+ x86_64-darwin-19
+ x86_64-darwin-20
DEPENDENCIES
libv8
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -455,6 +821,11 @@ RSpec.describe "bundle lock" do
end
end
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "libv8", "8.4.255.0", "x86_64-darwin-19"
+ c.checksum gem_repo4, "libv8", "8.4.255.0", "x86_64-darwin-20"
+ end
+
gemfile <<-G
source "#{file_uri_for(gem_repo4)}"
@@ -473,7 +844,7 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
libv8
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -492,22 +863,25 @@ RSpec.describe "bundle lock" do
end
it "does not conflict on ruby requirements when adding new platforms" do
- next_minor = Gem.ruby_version.segments[0..1].map.with_index {|s, i| i == 1 ? s + 1 : s }.join(".")
-
build_repo4 do
build_gem "raygun-apm", "1.0.78" do |s|
s.platform = "x86_64-linux"
- s.required_ruby_version = "< #{next_minor}.dev"
+ s.required_ruby_version = "< #{next_ruby_minor}.dev"
end
build_gem "raygun-apm", "1.0.78" do |s|
s.platform = "universal-darwin"
- s.required_ruby_version = "< #{next_minor}.dev"
+ s.required_ruby_version = "< #{next_ruby_minor}.dev"
end
build_gem "raygun-apm", "1.0.78" do |s|
s.platform = "x64-mingw32"
- s.required_ruby_version = "< #{next_minor}.dev"
+ s.required_ruby_version = "< #{next_ruby_minor}.dev"
+ end
+
+ build_gem "raygun-apm", "1.0.78" do |s|
+ s.platform = "x64-mingw-ucrt"
+ s.required_ruby_version = "< #{next_ruby_minor}.dev"
end
end
@@ -533,30 +907,687 @@ RSpec.describe "bundle lock" do
#{Bundler::VERSION}
L
- bundle "lock --add-platform x86_64-linux", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ bundle "lock --add-platform x86_64-linux", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
end
- context "when an update is available" do
- let(:repo) { gem_repo2 }
+ it "does not crash on conflicting ruby requirements between platform versions in two different gems" do
+ build_repo4 do
+ build_gem "unf_ext", "0.0.8.2"
- before do
- lockfile(@lockfile)
+ build_gem "unf_ext", "0.0.8.2" do |s|
+ s.required_ruby_version = [">= 2.4", "< #{previous_ruby_minor}"]
+ s.platform = "x64-mingw32"
+ end
+
+ build_gem "unf_ext", "0.0.8.2" do |s|
+ s.required_ruby_version = [">= #{previous_ruby_minor}", "< #{current_ruby_minor}"]
+ s.platform = "x64-mingw-ucrt"
+ end
+
+ build_gem "google-protobuf", "3.21.12"
+
+ build_gem "google-protobuf", "3.21.12" do |s|
+ s.required_ruby_version = [">= 2.5", "< #{previous_ruby_minor}"]
+ s.platform = "x64-mingw32"
+ end
+
+ build_gem "google-protobuf", "3.21.12" do |s|
+ s.required_ruby_version = [">= #{previous_ruby_minor}", "< #{current_ruby_minor}"]
+ s.platform = "x64-mingw-ucrt"
+ end
+ end
+
+ gemfile <<~G
+ source "https://gem.repo4"
+
+ gem "google-protobuf"
+ gem "unf_ext"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ google-protobuf (3.21.12)
+ unf_ext (0.0.8.2)
+
+ PLATFORMS
+ x64-mingw-ucrt
+ x64-mingw32
+
+ DEPENDENCIES
+ google-protobuf
+ unf_ext
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s, "DEBUG_RESOLVER" => "1" }
+ end
+
+ it "respects lower bound ruby requirements" do
+ build_repo4 do
+ build_gem "our_private_gem", "0.1.0" do |s|
+ s.required_ruby_version = ">= #{Gem.ruby_version}"
+ end
+ end
+
+ gemfile <<-G
+ source "https://localgemserver.test"
+
+ gem "our_private_gem"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://localgemserver.test/
+ specs:
+ our_private_gem (0.1.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ our_private_gem
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ end
+
+ context "when an update is available" do
+ let(:repo) do
build_repo2 do
build_gem "foo", "2.0"
end
+ gem_repo2
+ end
+
+ before do
+ lockfile(@lockfile)
end
it "does not implicitly update" do
bundle "lock"
- expect(read_lockfile).to eq(@lockfile)
+ checksums = checksums_section_when_existing do |c|
+ c.checksum repo, "actionmailer", "2.3.2"
+ c.checksum repo, "actionpack", "2.3.2"
+ c.checksum repo, "activerecord", "2.3.2"
+ c.checksum repo, "activeresource", "2.3.2"
+ c.checksum repo, "activesupport", "2.3.2"
+ c.checksum repo, "foo", "1.0"
+ c.checksum repo, "rails", "2.3.2"
+ c.checksum repo, "rake", rake_version
+ c.checksum repo, "weakling", "0.0.3"
+ end
+
+ expected_lockfile = <<~L
+ GEM
+ remote: #{file_uri_for(repo)}/
+ specs:
+ actionmailer (2.3.2)
+ activesupport (= 2.3.2)
+ actionpack (2.3.2)
+ activesupport (= 2.3.2)
+ activerecord (2.3.2)
+ activesupport (= 2.3.2)
+ activeresource (2.3.2)
+ activesupport (= 2.3.2)
+ activesupport (2.3.2)
+ foo (1.0)
+ rails (2.3.2)
+ actionmailer (= 2.3.2)
+ actionpack (= 2.3.2)
+ activerecord (= 2.3.2)
+ activeresource (= 2.3.2)
+ rake (= #{rake_version})
+ rake (#{rake_version})
+ weakling (0.0.3)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ foo
+ rails
+ weakling
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ expect(read_lockfile).to eq(expected_lockfile)
end
it "accounts for changes in the gemfile" do
gemfile gemfile.gsub('"foo"', '"foo", "2.0"')
bundle "lock"
- expect(read_lockfile).to eq(@lockfile.sub("foo (1.0)", "foo (2.0)").sub(/foo$/, "foo (= 2.0)"))
+ checksums = checksums_section_when_existing do |c|
+ c.checksum repo, "actionmailer", "2.3.2"
+ c.checksum repo, "actionpack", "2.3.2"
+ c.checksum repo, "activerecord", "2.3.2"
+ c.checksum repo, "activeresource", "2.3.2"
+ c.checksum repo, "activesupport", "2.3.2"
+ c.no_checksum "foo", "2.0"
+ c.checksum repo, "rails", "2.3.2"
+ c.checksum repo, "rake", rake_version
+ c.checksum repo, "weakling", "0.0.3"
+ end
+
+ expected_lockfile = <<~L
+ GEM
+ remote: #{file_uri_for(repo)}/
+ specs:
+ actionmailer (2.3.2)
+ activesupport (= 2.3.2)
+ actionpack (2.3.2)
+ activesupport (= 2.3.2)
+ activerecord (2.3.2)
+ activesupport (= 2.3.2)
+ activeresource (2.3.2)
+ activesupport (= 2.3.2)
+ activesupport (2.3.2)
+ foo (2.0)
+ rails (2.3.2)
+ actionmailer (= 2.3.2)
+ actionpack (= 2.3.2)
+ activerecord (= 2.3.2)
+ activeresource (= 2.3.2)
+ rake (= #{rake_version})
+ rake (#{rake_version})
+ weakling (0.0.3)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ foo (= 2.0)
+ rails
+ weakling
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ expect(read_lockfile).to eq(expected_lockfile)
+ end
+ end
+
+ context "when a system gem has incorrect dependencies, different from the lockfile" do
+ before do
+ build_repo4 do
+ build_gem "debug", "1.6.3" do |s|
+ s.add_dependency "irb", ">= 1.3.6"
+ end
+
+ build_gem "irb", "1.5.0"
+ end
+
+ system_gems "irb-1.5.0", gem_repo: gem_repo4
+ system_gems "debug-1.6.3", gem_repo: gem_repo4
+
+ # simulate gemspec with wrong empty dependencies
+ debug_gemspec_path = system_gem_path("specifications/debug-1.6.3.gemspec")
+ debug_gemspec = Gem::Specification.load(debug_gemspec_path.to_s)
+ debug_gemspec.dependencies.clear
+ File.write(debug_gemspec_path, debug_gemspec.to_ruby)
+ end
+
+ it "respects the existing lockfile, even when reresolving" do
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "debug"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ debug (1.6.3)
+ irb (>= 1.3.6)
+ irb (1.5.0)
+
+ PLATFORMS
+ x86_64-linux
+
+ DEPENDENCIES
+ debug
+ #{checksums_section}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ simulate_platform "arm64-darwin-22" do
+ bundle "lock"
+ end
+
+ checksums = checksums_section do |c|
+ c.no_checksum "debug", "1.6.3"
+ c.no_checksum "irb", "1.5.0"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ debug (1.6.3)
+ irb (>= 1.3.6)
+ irb (1.5.0)
+
+ PLATFORMS
+ arm64-darwin-22
+ x86_64-linux
+
+ DEPENDENCIES
+ debug
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ it "properly shows resolution errors including OR requirements" do
+ build_repo4 do
+ build_gem "activeadmin", "2.13.1" do |s|
+ s.add_dependency "railties", ">= 6.1", "< 7.1"
+ end
+ build_gem "actionpack", "6.1.4"
+ build_gem "actionpack", "7.0.3.1"
+ build_gem "actionpack", "7.0.4"
+ build_gem "railties", "6.1.4" do |s|
+ s.add_dependency "actionpack", "6.1.4"
+ end
+ build_gem "rails", "7.0.3.1" do |s|
+ s.add_dependency "railties", "7.0.3.1"
+ end
+ build_gem "rails", "7.0.4" do |s|
+ s.add_dependency "railties", "7.0.4"
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "rails", ">= 7.0.3.1"
+ gem "activeadmin", "2.13.1"
+ G
+
+ bundle "lock", raise_on_error: false
+
+ expect(err).to eq <<~ERR.strip
+ Could not find compatible versions
+
+ Because rails >= 7.0.4 depends on railties = 7.0.4
+ and rails < 7.0.4 depends on railties = 7.0.3.1,
+ railties = 7.0.3.1 OR = 7.0.4 is required.
+ So, because railties = 7.0.3.1 OR = 7.0.4 could not be found in rubygems repository #{file_uri_for(gem_repo4)}/, cached gems or installed locally,
+ version solving has failed.
+ ERR
+ end
+
+ it "is able to display some explanation on crazy irresolvable cases" do
+ build_repo4 do
+ build_gem "activeadmin", "2.13.1" do |s|
+ s.add_dependency "ransack", "= 3.1.0"
+ end
+
+ # Activemodel is missing as a dependency in lockfile
+ build_gem "ransack", "3.1.0" do |s|
+ s.add_dependency "activemodel", ">= 6.0.4"
+ s.add_dependency "activesupport", ">= 6.0.4"
+ end
+
+ %w[6.0.4 7.0.2.3 7.0.3.1 7.0.4].each do |version|
+ build_gem "activesupport", version
+
+ # Activemodel is only available on 6.0.4
+ if version == "6.0.4"
+ build_gem "activemodel", version do |s|
+ s.add_dependency "activesupport", version
+ end
+ end
+
+ build_gem "rails", version do |s|
+ # Depednencies of Rails 7.0.2.3 are in reverse order
+ if version == "7.0.2.3"
+ s.add_dependency "activesupport", version
+ s.add_dependency "activemodel", version
+ else
+ s.add_dependency "activemodel", version
+ s.add_dependency "activesupport", version
+ end
+ end
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "rails", ">= 7.0.2.3"
+ gem "activeadmin", "= 2.13.1"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ activeadmin (2.13.1)
+ ransack (= 3.1.0)
+ ransack (3.1.0)
+ activemodel (>= 6.0.4)
+
+ PLATFORMS
+ #{local_platform}
+
+ DEPENDENCIES
+ activeadmin (= 2.13.1)
+ ransack (= 3.1.0)
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "lock", raise_on_error: false
+
+ expect(err).to eq <<~ERR.strip
+ Could not find compatible versions
+
+ Because every version of activemodel depends on activesupport = 6.0.4
+ and rails >= 7.0.2.3, < 7.0.3.1 depends on activesupport = 7.0.2.3,
+ every version of activemodel is incompatible with rails >= 7.0.2.3, < 7.0.3.1.
+ And because rails >= 7.0.2.3, < 7.0.3.1 depends on activemodel = 7.0.2.3,
+ rails >= 7.0.2.3, < 7.0.3.1 cannot be used.
+ (1) So, because rails >= 7.0.3.1, < 7.0.4 depends on activemodel = 7.0.3.1
+ and rails >= 7.0.4 depends on activemodel = 7.0.4,
+ rails >= 7.0.2.3 requires activemodel = 7.0.3.1 OR = 7.0.4.
+
+ Because rails >= 7.0.2.3, < 7.0.3.1 depends on activemodel = 7.0.2.3
+ and rails >= 7.0.3.1, < 7.0.4 depends on activesupport = 7.0.3.1,
+ rails >= 7.0.2.3, < 7.0.4 requires activemodel = 7.0.2.3 or activesupport = 7.0.3.1.
+ And because rails >= 7.0.4 depends on activesupport = 7.0.4
+ and every version of activemodel depends on activesupport = 6.0.4,
+ activemodel != 7.0.2.3 is incompatible with rails >= 7.0.2.3.
+ And because rails >= 7.0.2.3 requires activemodel = 7.0.3.1 OR = 7.0.4 (1),
+ rails >= 7.0.2.3 cannot be used.
+ So, because Gemfile depends on rails >= 7.0.2.3,
+ version solving has failed.
+ ERR
+
+ lockfile lockfile.gsub(/PLATFORMS\n #{local_platform}/m, "PLATFORMS\n #{lockfile_platforms("ruby")}")
+
+ bundle "lock", raise_on_error: false
+
+ expect(err).to eq <<~ERR.strip
+ Could not find compatible versions
+
+ Because rails >= 7.0.3.1, < 7.0.4 depends on activemodel = 7.0.3.1
+ and rails >= 7.0.2.3, < 7.0.3.1 depends on activemodel = 7.0.2.3,
+ rails >= 7.0.2.3, < 7.0.4 requires activemodel = 7.0.2.3 OR = 7.0.3.1.
+ And because every version of activemodel depends on activesupport = 6.0.4,
+ rails >= 7.0.2.3, < 7.0.4 requires activesupport = 6.0.4.
+ Because rails >= 7.0.3.1, < 7.0.4 depends on activesupport = 7.0.3.1
+ and rails >= 7.0.2.3, < 7.0.3.1 depends on activesupport = 7.0.2.3,
+ rails >= 7.0.2.3, < 7.0.4 requires activesupport = 7.0.2.3 OR = 7.0.3.1.
+ Thus, rails >= 7.0.2.3, < 7.0.4 cannot be used.
+ And because rails >= 7.0.4 depends on activemodel = 7.0.4,
+ rails >= 7.0.2.3 requires activemodel = 7.0.4.
+ So, because activemodel = 7.0.4 could not be found in rubygems repository #{file_uri_for(gem_repo4)}/, cached gems or installed locally
+ and Gemfile depends on rails >= 7.0.2.3,
+ version solving has failed.
+ ERR
+ end
+
+ it "does not accidentally resolves to prereleases" do
+ build_repo4 do
+ build_gem "autoproj", "2.0.3" do |s|
+ s.add_dependency "autobuild", ">= 1.10.0.a"
+ s.add_dependency "tty-prompt"
+ end
+
+ build_gem "tty-prompt", "0.6.0"
+ build_gem "tty-prompt", "0.7.0"
+
+ build_gem "autobuild", "1.10.0.b3"
+ build_gem "autobuild", "1.10.1" do |s|
+ s.add_dependency "tty-prompt", "~> 0.6.0"
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "autoproj", ">= 2.0.0"
+ G
+
+ bundle "lock"
+ expect(lockfile).to_not include("autobuild (1.10.0.b3)")
+ expect(lockfile).to include("autobuild (1.10.1)")
+ end
+
+ # Newer rails depends on Bundler, while ancient Rails does not. Bundler tries
+ # a first resolution pass that does not consider pre-releases. However, when
+ # using a pre-release Bundler (like the .dev version), that results in that
+ # pre-release being ignored and resolving to a version that does not depend on
+ # Bundler at all. We should avoid that and still consider .dev Bundler.
+ #
+ it "does not ignore prereleases with there's only one candidate" do
+ build_repo4 do
+ build_gem "rails", "7.4.0.2" do |s|
+ s.add_dependency "bundler", ">= 1.15.0"
+ end
+
+ build_gem "rails", "2.3.18"
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rails"
+ G
+
+ bundle "lock"
+ expect(lockfile).to_not include("rails (2.3.18)")
+ expect(lockfile).to include("rails (7.4.0.2)")
+ end
+
+ it "deals with platform specific incompatibilities" do
+ build_repo4 do
+ build_gem "activerecord", "6.0.6"
+ build_gem "activerecord-jdbc-adapter", "60.4" do |s|
+ s.platform = "java"
+ s.add_dependency "activerecord", "~> 6.0.0"
+ end
+ build_gem "activerecord-jdbc-adapter", "61.0" do |s|
+ s.platform = "java"
+ s.add_dependency "activerecord", "~> 6.1.0"
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "activerecord", "6.0.6"
+ gem "activerecord-jdbc-adapter", "61.0"
+ G
+
+ simulate_platform "universal-java-19" do
+ bundle "lock", raise_on_error: false
+ end
+
+ expect(err).to include("Could not find compatible versions")
+ expect(err).not_to include("ERROR REPORT TEMPLATE")
+ end
+
+ context "when re-resolving to include prereleases" do
+ before do
+ build_repo4 do
+ build_gem "tzinfo-data", "1.2022.7"
+ build_gem "rails", "7.1.0.alpha" do |s|
+ s.add_dependency "activesupport"
+ end
+ build_gem "activesupport", "7.1.0.alpha"
+ end
+ end
+
+ it "does not end up including gems scoped to other platforms in the lockfile" do
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rails"
+ gem "tzinfo-data", platform: :windows
+ G
+
+ simulate_platform "x86_64-darwin-22" do
+ bundle "lock"
+ end
+
+ expect(lockfile).not_to include("tzinfo-data (1.2022.7)")
+ end
+ end
+
+ context "when resolving platform specific gems as indirect dependencies on truffleruby", :truffleruby_only do
+ before do
+ build_lib "foo", path: bundled_app do |s|
+ s.add_dependency "nokogiri"
+ end
+
+ build_repo4 do
+ build_gem "nokogiri", "1.14.2"
+ build_gem "nokogiri", "1.14.2" do |s|
+ s.platform = "x86_64-linux"
+ end
+ end
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gemspec
+ G
+ end
+
+ it "locks ruby specs" do
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ c.no_checksum "nokogiri", "1.14.2"
+ end
+
+ simulate_platform "x86_64-linux" do
+ bundle "lock"
+ end
+
+ expect(lockfile).to eq <<~L
+ PATH
+ remote: .
+ specs:
+ foo (1.0)
+ nokogiri
+
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ nokogiri (1.14.2)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ foo!
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ context "when adding a new gem that requires unlocking other transitive deps" do
+ before do
+ build_repo4 do
+ build_gem "govuk_app_config", "0.1.0"
+
+ build_gem "govuk_app_config", "4.13.0" do |s|
+ s.add_dependency "railties", ">= 5.0"
+ end
+
+ %w[7.0.4.1 7.0.4.3].each do |v|
+ build_gem "railties", v do |s|
+ s.add_dependency "actionpack", v
+ s.add_dependency "activesupport", v
+ end
+
+ build_gem "activesupport", v
+ build_gem "actionpack", v
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "govuk_app_config"
+ gem "activesupport", "7.0.4.3"
+ G
+
+ # Simulate out of sync lockfile because top level dependency on
+ # activesuport has just been added to the Gemfile, and locked to a higher
+ # version
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ actionpack (7.0.4.1)
+ activesupport (7.0.4.1)
+ govuk_app_config (4.13.0)
+ railties (>= 5.0)
+ railties (7.0.4.1)
+ actionpack (= 7.0.4.1)
+ activesupport (= 7.0.4.1)
+
+ PLATFORMS
+ arm64-darwin-22
+
+ DEPENDENCIES
+ govuk_app_config
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "does not downgrade top level dependencies" do
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "actionpack", "7.0.4.3"
+ c.no_checksum "activesupport", "7.0.4.3"
+ c.no_checksum "govuk_app_config", "4.13.0"
+ c.no_checksum "railties", "7.0.4.3"
+ end
+
+ simulate_platform "arm64-darwin-22" do
+ bundle "lock"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ actionpack (7.0.4.3)
+ activesupport (7.0.4.3)
+ govuk_app_config (4.13.0)
+ railties (>= 5.0)
+ railties (7.0.4.3)
+ actionpack (= 7.0.4.3)
+ activesupport (= 7.0.4.3)
+
+ PLATFORMS
+ arm64-darwin-22
+
+ DEPENDENCIES
+ activesupport (= 7.0.4.3)
+ govuk_app_config
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
end
end
end
diff --git a/spec/bundler/commands/newgem_spec.rb b/spec/bundler/commands/newgem_spec.rb
index 56fea008ec..199340b131 100644
--- a/spec/bundler/commands/newgem_spec.rb
+++ b/spec/bundler/commands/newgem_spec.rb
@@ -12,14 +12,14 @@ RSpec.describe "bundle gem" do
def bundle_exec_rubocop
prepare_gemspec(bundled_app(gem_name, "#{gem_name}.gemspec"))
- bundle "config set path #{rubocop_gems}", :dir => bundled_app(gem_name)
- bundle "exec rubocop --debug --config .rubocop.yml", :dir => bundled_app(gem_name)
+ bundle "config set path #{rubocop_gems}", dir: bundled_app(gem_name)
+ bundle "exec rubocop --debug --config .rubocop.yml", dir: bundled_app(gem_name)
end
def bundle_exec_standardrb
prepare_gemspec(bundled_app(gem_name, "#{gem_name}.gemspec"))
- bundle "config set path #{standard_gems}", :dir => bundled_app(gem_name)
- bundle "exec standardrb --debug", :dir => bundled_app(gem_name)
+ bundle "config set path #{standard_gems}", dir: bundled_app(gem_name)
+ bundle "exec standardrb --debug", dir: bundled_app(gem_name)
end
let(:generated_gemspec) { Bundler.load_gemspec_uncached(bundled_app(gem_name).join("#{gem_name}.gemspec")) }
@@ -28,6 +28,10 @@ RSpec.describe "bundle gem" do
let(:require_path) { "mygem" }
+ let(:minitest_test_file_path) { "test/test_mygem.rb" }
+
+ let(:minitest_test_class_name) { "class TestMygem < Minitest::Test" }
+
before do
sys_exec("git config --global user.name 'Bundler User'")
sys_exec("git config --global user.email user@example.com")
@@ -35,36 +39,32 @@ RSpec.describe "bundle gem" do
end
describe "git repo initialization" do
- shared_examples_for "a gem with an initial git repo" do
- before do
- bundle "gem #{gem_name} #{flags}"
- end
-
- it "generates a gem skeleton with a .git folder", :readline do
- gem_skeleton_assertions
- expect(bundled_app("#{gem_name}/.git")).to exist
- end
+ it "generates a gem skeleton with a .git folder", :readline do
+ bundle "gem #{gem_name}"
+ gem_skeleton_assertions
+ expect(bundled_app("#{gem_name}/.git")).to exist
end
- context "when using the default" do
- it_behaves_like "a gem with an initial git repo" do
- let(:flags) { "" }
- end
+ it "generates a gem skeleton with a .git folder when passing --git", :readline do
+ bundle "gem #{gem_name} --git"
+ gem_skeleton_assertions
+ expect(bundled_app("#{gem_name}/.git")).to exist
end
- context "when explicitly passing --git" do
- it_behaves_like "a gem with an initial git repo" do
- let(:flags) { "--git" }
- end
+ it "generates a gem skeleton without a .git folder when passing --no-git", :readline do
+ bundle "gem #{gem_name} --no-git"
+ gem_skeleton_assertions
+ expect(bundled_app("#{gem_name}/.git")).not_to exist
end
- context "when passing --no-git", :readline do
+ context "on a path with spaces" do
before do
- bundle "gem #{gem_name} --no-git"
+ Dir.mkdir(bundled_app("path with spaces"))
end
- it "generates a gem skeleton without a .git folder" do
- gem_skeleton_assertions
- expect(bundled_app("#{gem_name}/.git")).not_to exist
+
+ it "properly initializes git repo", :readline do
+ bundle "gem #{gem_name}", dir: bundled_app("path with spaces")
+ expect(bundled_app("path with spaces/#{gem_name}/.git")).to exist
end
end
end
@@ -103,7 +103,7 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/README.md").read).to match(%r{https://github\.com/bundleuser/#{gem_name}/blob/.*/CODE_OF_CONDUCT.md})
end
- it "generates the README with a section for the Code of Conduct, respecting the configured git default branch", :git => ">= 2.28.0" do
+ it "generates the README with a section for the Code of Conduct, respecting the configured git default branch", git: ">= 2.28.0" do
sys_exec("git config --global init.defaultBranch main")
bundle "gem #{gem_name} --coc"
@@ -148,7 +148,7 @@ RSpec.describe "bundle gem" do
end
shared_examples_for "--rubocop flag" do
- context "is deprecated", :bundler => "< 3" do
+ context "is deprecated", bundler: "< 3" do
before do
bundle "gem #{gem_name} --rubocop"
end
@@ -179,7 +179,7 @@ RSpec.describe "bundle gem" do
end
shared_examples_for "--no-rubocop flag" do
- context "is deprecated", :bundler => "< 3" do
+ context "is deprecated", bundler: "< 3" do
define_negated_matcher :exclude, :include
before do
@@ -310,30 +310,30 @@ RSpec.describe "bundle gem" do
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext and --linter=rubocop flag", :readline do
+ it "has no rubocop offenses when using --ext=c and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
- bundle "gem #{gem_name} --ext --linter=rubocop"
+ bundle "gem #{gem_name} --ext=c --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext, --test=minitest, and --linter=rubocop flag", :readline do
+ it "has no rubocop offenses when using --ext=c, --test=minitest, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
- bundle "gem #{gem_name} --ext --test=minitest --linter=rubocop"
+ bundle "gem #{gem_name} --ext=c --test=minitest --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext, --test=rspec, and --linter=rubocop flag", :readline do
+ it "has no rubocop offenses when using --ext=c, --test=rspec, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
- bundle "gem #{gem_name} --ext --test=rspec --linter=rubocop"
+ bundle "gem #{gem_name} --ext=c --test=rspec --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext, --ext=test-unit, and --linter=rubocop flag", :readline do
+ it "has no rubocop offenses when using --ext=c, --test=test-unit, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
- bundle "gem #{gem_name} --ext --test=test-unit --linter=rubocop"
+ bundle "gem #{gem_name} --ext=c --test=test-unit --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
@@ -345,10 +345,45 @@ RSpec.describe "bundle gem" do
expect(last_command).to be_success
end
+ it "has no rubocop offenses when using --ext=rust and --linter=rubocop flag", :readline do
+ skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
+ skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version
+
+ bundle "gem #{gem_name} --ext=rust --linter=rubocop"
+ bundle_exec_rubocop
+ expect(last_command).to be_success
+ end
+
+ it "has no rubocop offenses when using --ext=rust, --test=minitest, and --linter=rubocop flag", :readline do
+ skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
+ skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version
+
+ bundle "gem #{gem_name} --ext=rust --test=minitest --linter=rubocop"
+ bundle_exec_rubocop
+ expect(last_command).to be_success
+ end
+
+ it "has no rubocop offenses when using --ext=rust, --test=rspec, and --linter=rubocop flag", :readline do
+ skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
+ skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version
+
+ bundle "gem #{gem_name} --ext=rust --test=rspec --linter=rubocop"
+ bundle_exec_rubocop
+ expect(last_command).to be_success
+ end
+
+ it "has no rubocop offenses when using --ext=rust, --test=test-unit, and --linter=rubocop flag", :readline do
+ skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
+ skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version
+
+ bundle "gem #{gem_name} --ext=rust --test=test-unit --linter=rubocop"
+ bundle_exec_rubocop
+ expect(last_command).to be_success
+ end
+
shared_examples_for "CI config is absent" do
it "does not create any CI files" do
expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to_not exist
- expect(bundled_app("#{gem_name}/.travis.yml")).to_not exist
expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to_not exist
expect(bundled_app("#{gem_name}/.circleci/config.yml")).to_not exist
end
@@ -400,7 +435,7 @@ RSpec.describe "bundle gem" do
load_paths = [lib_dir, spec_dir]
load_path_str = "-I#{load_paths.join(File::PATH_SEPARATOR)}"
- sys_exec "#{Gem.ruby} #{load_path_str} #{bindir.join("bundle")} gem #{gem_name}", :env => { "PATH" => "" }
+ sys_exec "#{Gem.ruby} #{load_path_str} #{bindir.join("bundle")} gem #{gem_name}", env: { "PATH" => "" }
end
it "creates the gem without the need for git" do
@@ -421,10 +456,10 @@ RSpec.describe "bundle gem" do
prepare_gemspec(bundled_app("newgem", "newgem.gemspec"))
- gems = ["rake-13.0.1"]
- path = Bundler.feature_flag.default_install_uses_path? ? local_gem_path(:base => bundled_app("newgem")) : system_gem_path
- system_gems gems, :path => path
- bundle "exec rake build", :dir => bundled_app("newgem")
+ gems = ["rake-#{rake_version}"]
+ path = Bundler.feature_flag.default_install_uses_path? ? local_gem_path(base: bundled_app("newgem")) : system_gem_path
+ system_gems gems, path: path
+ bundle "exec rake build", dir: bundled_app("newgem")
expect(last_command.stdboth).not_to include("ERROR")
end
@@ -433,7 +468,7 @@ RSpec.describe "bundle gem" do
it "resolves ." do
create_temporary_dir("tmp")
- bundle "gem .", :dir => bundled_app("tmp")
+ bundle "gem .", dir: bundled_app("tmp")
expect(bundled_app("tmp/lib/tmp.rb")).to exist
end
@@ -441,7 +476,7 @@ RSpec.describe "bundle gem" do
it "resolves .." do
create_temporary_dir("temp/empty_dir")
- bundle "gem ..", :dir => bundled_app("temp/empty_dir")
+ bundle "gem ..", dir: bundled_app("temp/empty_dir")
expect(bundled_app("temp/lib/temp.rb")).to exist
end
@@ -449,7 +484,7 @@ RSpec.describe "bundle gem" do
it "resolves relative directory" do
create_temporary_dir("tmp/empty/tmp")
- bundle "gem ../../empty", :dir => bundled_app("tmp/empty/tmp")
+ bundle "gem ../../empty", dir: bundled_app("tmp/empty/tmp")
expect(bundled_app("tmp/empty/lib/empty.rb")).to exist
end
@@ -517,6 +552,7 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/Rakefile")).to exist
expect(bundled_app("#{gem_name}/lib/#{require_path}.rb")).to exist
expect(bundled_app("#{gem_name}/lib/#{require_path}/version.rb")).to exist
+ expect(bundled_app("#{gem_name}/sig/#{require_path}.rbs")).to exist
expect(bundled_app("#{gem_name}/.gitignore")).to exist
expect(bundled_app("#{gem_name}/bin/setup")).to exist
@@ -533,6 +569,12 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/lib/#{require_path}/version.rb").read).to match(/VERSION = "0.1.0"/)
end
+ it "declare String type for VERSION constant" do
+ bundle "gem #{gem_name}"
+
+ expect(bundled_app("#{gem_name}/sig/#{require_path}.rbs").read).to match(/VERSION: String/)
+ end
+
context "git config user.{name,email} is set" do
before do
bundle "gem #{gem_name}"
@@ -567,13 +609,13 @@ RSpec.describe "bundle gem" do
bundle "gem #{gem_name}"
expect(generated_gemspec.metadata["allowed_push_host"]).
- to match(/mygemserver\.com/)
+ to match(/example\.com/)
end
it "sets a minimum ruby version" do
bundle "gem #{gem_name}"
- expect(generated_gemspec.required_ruby_version).to eq(Gem::Requirement.new(Gem.ruby_version < Gem::Version.new("2.4.a") ? ">= 2.3.0" : ">= 2.4.0"))
+ expect(generated_gemspec.required_ruby_version.to_s).to start_with(">=")
end
it "requires the version file" do
@@ -588,12 +630,28 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/lib/#{require_path}.rb").read).to match(/class Error < StandardError; end$/)
end
+ it "does not include the gemspec file in files" do
+ bundle "gem #{gem_name}"
+
+ bundler_gemspec = Bundler::GemHelper.new(bundled_app(gem_name), gem_name).gemspec
+
+ expect(bundler_gemspec.files).not_to include("#{gem_name}.gemspec")
+ end
+
+ it "does not include the Gemfile file in files" do
+ bundle "gem #{gem_name}"
+
+ bundler_gemspec = Bundler::GemHelper.new(bundled_app(gem_name), gem_name).gemspec
+
+ expect(bundler_gemspec.files).not_to include("Gemfile")
+ end
+
it "runs rake without problems" do
bundle "gem #{gem_name}"
- system_gems ["rake-13.0.1"]
+ system_gems ["rake-#{rake_version}"]
- rakefile = strip_whitespace <<-RAKEFILE
+ rakefile = <<~RAKEFILE
task :default do
puts 'SUCCESS'
end
@@ -602,7 +660,7 @@ RSpec.describe "bundle gem" do
file.puts rakefile
end
- sys_exec(rake, :dir => bundled_app(gem_name))
+ sys_exec(rake, dir: bundled_app(gem_name))
expect(out).to include("SUCCESS")
end
@@ -691,7 +749,7 @@ RSpec.describe "bundle gem" do
end
it "builds spec skeleton" do
- expect(bundled_app("#{gem_name}/test/test_#{require_path}.rb")).to exist
+ expect(bundled_app("#{gem_name}/#{minitest_test_file_path}")).to exist
expect(bundled_app("#{gem_name}/test/test_helper.rb")).to exist
end
end
@@ -711,7 +769,7 @@ RSpec.describe "bundle gem" do
end
it "builds spec skeleton" do
- expect(bundled_app("#{gem_name}/test/test_#{require_path}.rb")).to exist
+ expect(bundled_app("#{gem_name}/#{minitest_test_file_path}")).to exist
expect(bundled_app("#{gem_name}/test/test_helper.rb")).to exist
end
@@ -720,11 +778,15 @@ RSpec.describe "bundle gem" do
end
it "requires 'test_helper'" do
- expect(bundled_app("#{gem_name}/test/test_#{require_path}.rb").read).to include(%(require "test_helper"))
+ expect(bundled_app("#{gem_name}/#{minitest_test_file_path}").read).to include(%(require "test_helper"))
+ end
+
+ it "defines valid test class name" do
+ expect(bundled_app("#{gem_name}/#{minitest_test_file_path}").read).to include(minitest_test_class_name)
end
it "creates a default test which fails" do
- expect(bundled_app("#{gem_name}/test/test_#{require_path}.rb").read).to include("assert false")
+ expect(bundled_app("#{gem_name}/#{minitest_test_file_path}").read).to include("assert false")
end
end
@@ -735,17 +797,13 @@ RSpec.describe "bundle gem" do
end
it "creates a default rake task to run the test suite" do
- rakefile = strip_whitespace <<-RAKEFILE
+ rakefile = <<~RAKEFILE
# frozen_string_literal: true
require "bundler/gem_tasks"
- require "rake/testtask"
+ require "minitest/test_task"
- Rake::TestTask.new(:test) do |t|
- t.libs << "test"
- t.libs << "lib"
- t.test_files = FileList["test/**/test_*.rb"]
- end
+ Minitest::TestTask.create
task default: :test
RAKEFILE
@@ -793,7 +851,7 @@ RSpec.describe "bundle gem" do
end
it "creates a default rake task to run the test suite" do
- rakefile = strip_whitespace <<-RAKEFILE
+ rakefile = <<~RAKEFILE
# frozen_string_literal: true
require "bundler/gem_tasks"
@@ -869,7 +927,6 @@ RSpec.describe "bundle gem" do
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to_not exist
- expect(bundled_app("#{gem_name}/.travis.yml")).to_not exist
expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to_not exist
expect(bundled_app("#{gem_name}/.circleci/config.yml")).to_not exist
end
@@ -881,6 +938,12 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to exist
end
+
+ it "contained .gitlab-ci.yml into ignore list" do
+ bundle "gem #{gem_name} --ci=github"
+
+ expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include(".git .github appveyor")
+ end
end
context "--ci set to gitlab" do
@@ -889,6 +952,12 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to exist
end
+
+ it "contained .gitlab-ci.yml into ignore list" do
+ bundle "gem #{gem_name} --ci=gitlab"
+
+ expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include(".git .gitlab-ci.yml appveyor")
+ end
end
context "--ci set to circle" do
@@ -897,20 +966,17 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/.circleci/config.yml")).to exist
end
- end
- context "--ci set to travis" do
- it "generates a Travis CI config file" do
- bundle "gem #{gem_name} --ci=travis"
+ it "contained .circleci into ignore list" do
+ bundle "gem #{gem_name} --ci=circle"
- expect(bundled_app("#{gem_name}/.travis.yml")).to exist
+ expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include(".git .circleci appveyor")
end
end
context "gem.ci setting set to none" do
it "doesn't generate any CI config" do
expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to_not exist
- expect(bundled_app("#{gem_name}/.travis.yml")).to_not exist
expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to_not exist
expect(bundled_app("#{gem_name}/.circleci/config.yml")).to_not exist
end
@@ -925,15 +991,6 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.ci setting set to travis" do
- it "generates a Travis CI config file" do
- bundle "config set gem.ci travis"
- bundle "gem #{gem_name}"
-
- expect(bundled_app("#{gem_name}/.travis.yml")).to exist
- end
- end
-
context "gem.ci setting set to gitlab" do
it "generates a GitLab CI config file" do
bundle "config set gem.ci gitlab"
@@ -1052,7 +1109,7 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.rubocop setting set to true", :bundler => "< 3" do
+ context "gem.rubocop setting set to true", bundler: "< 3" do
before do
bundle "config set gem.rubocop true"
bundle "gem #{gem_name}"
@@ -1289,6 +1346,10 @@ RSpec.describe "bundle gem" do
let(:require_relative_path) { "test_gem" }
+ let(:minitest_test_file_path) { "test/test_test_gem.rb" }
+
+ let(:minitest_test_class_name) { "class TestTestGem < Minitest::Test" }
+
let(:flags) { nil }
it "does not nest constants" do
@@ -1299,25 +1360,50 @@ RSpec.describe "bundle gem" do
include_examples "generating a gem"
- context "--ext parameter set" do
- let(:flags) { "--ext" }
+ context "--ext parameter with no value" do
+ context "is deprecated", bundler: "< 3" do
+ it "prints deprecation when used after gem name" do
+ bundle ["gem", "--ext", gem_name].compact.join(" ")
+ expect(err).to include "[DEPRECATED]"
+ expect(err).to include "`--ext` with no arguments has been deprecated"
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c")).to exist
+ end
+
+ it "prints deprecation when used before gem name" do
+ bundle ["gem", gem_name, "--ext"].compact.join(" ")
+ expect(err).to include "[DEPRECATED]"
+ expect(err).to include "`--ext` with no arguments has been deprecated"
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c")).to exist
+ end
+ end
+ end
+
+ context "--ext parameter set with C" do
+ let(:flags) { "--ext=c" }
before do
bundle ["gem", gem_name, flags].compact.join(" ")
end
+ it "is not deprecated" do
+ expect(err).not_to include "[DEPRECATED] Option `--ext` without explicit value is deprecated."
+ end
+
it "builds ext skeleton" do
expect(bundled_app("#{gem_name}/ext/#{gem_name}/extconf.rb")).to exist
expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.h")).to exist
expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c")).to exist
end
- it "includes rake-compiler" do
+ it "includes rake-compiler, but no Rust related changes" do
expect(bundled_app("#{gem_name}/Gemfile").read).to include('gem "rake-compiler"')
+
+ expect(bundled_app("#{gem_name}/Gemfile").read).to_not include('gem "rb_sys"')
+ expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to_not include('spec.required_rubygems_version = ">= ')
end
it "depends on compile task for build" do
- rakefile = strip_whitespace <<-RAKEFILE
+ rakefile = <<~RAKEFILE
# frozen_string_literal: true
require "bundler/gem_tasks"
@@ -1325,7 +1411,9 @@ RSpec.describe "bundle gem" do
task build: :compile
- Rake::ExtensionTask.new("#{gem_name}") do |ext|
+ GEMSPEC = Gem::Specification.load("#{gem_name}.gemspec")
+
+ Rake::ExtensionTask.new("#{gem_name}", GEMSPEC) do |ext|
ext.lib_dir = "lib/#{gem_name}"
end
@@ -1335,6 +1423,66 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/Rakefile").read).to eq(rakefile)
end
end
+
+ context "--ext parameter set with rust and old RubyGems" do
+ it "fails in friendly way" do
+ if ::Gem::Version.new("3.3.11") <= ::Gem.rubygems_version
+ skip "RubyGems compatible with Rust builder"
+ end
+
+ expect do
+ bundle ["gem", gem_name, "--ext=rust"].compact.join(" ")
+ end.to raise_error(RuntimeError, /too old to build Rust extension/)
+ end
+ end
+
+ context "--ext parameter set with rust" do
+ let(:flags) { "--ext=rust" }
+
+ before do
+ skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version
+
+ bundle ["gem", gem_name, flags].compact.join(" ")
+ end
+
+ it "is not deprecated" do
+ expect(err).not_to include "[DEPRECATED] Option `--ext` without explicit value is deprecated."
+ end
+
+ it "builds ext skeleton" do
+ expect(bundled_app("#{gem_name}/Cargo.toml")).to exist
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/Cargo.toml")).to exist
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/extconf.rb")).to exist
+ expect(bundled_app("#{gem_name}/ext/#{gem_name}/src/lib.rs")).to exist
+ end
+
+ it "includes rake-compiler, rb_sys gems and required_rubygems_version constraint" do
+ expect(bundled_app("#{gem_name}/Gemfile").read).to include('gem "rake-compiler"')
+ expect(bundled_app("#{gem_name}/Gemfile").read).to include('gem "rb_sys"')
+ expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include('spec.required_rubygems_version = ">= ')
+ end
+
+ it "depends on compile task for build" do
+ rakefile = <<~RAKEFILE
+ # frozen_string_literal: true
+
+ require "bundler/gem_tasks"
+ require "rb_sys/extensiontask"
+
+ task build: :compile
+
+ GEMSPEC = Gem::Specification.load("#{gem_name}.gemspec")
+
+ RbSys::ExtensionTask.new("#{gem_name}", GEMSPEC) do |ext|
+ ext.lib_dir = "lib/#{gem_name}"
+ end
+
+ task default: :compile
+ RAKEFILE
+
+ expect(bundled_app("#{gem_name}/Rakefile").read).to eq(rakefile)
+ end
+ end
end
context "gem naming with dashed", :readline do
@@ -1344,6 +1492,10 @@ RSpec.describe "bundle gem" do
let(:require_relative_path) { "gem" }
+ let(:minitest_test_file_path) { "test/test/test_gem.rb" }
+
+ let(:minitest_test_class_name) { "class Test::TestGem < Minitest::Test" }
+
it "nests constants so they work" do
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/lib/#{require_path}/version.rb").read).to match(/module Test\n module Gem/)
@@ -1361,22 +1513,22 @@ RSpec.describe "bundle gem" do
end
it "fails gracefully with a ." do
- bundle "gem foo.gemspec", :raise_on_error => false
+ bundle "gem foo.gemspec", raise_on_error: false
expect(err).to end_with("Invalid gem name foo.gemspec -- `Foo.gemspec` is an invalid constant name")
end
it "fails gracefully with a ^" do
- bundle "gem ^", :raise_on_error => false
+ bundle "gem ^", raise_on_error: false
expect(err).to end_with("Invalid gem name ^ -- `^` is an invalid constant name")
end
it "fails gracefully with a space" do
- bundle "gem 'foo bar'", :raise_on_error => false
+ bundle "gem 'foo bar'", raise_on_error: false
expect(err).to end_with("Invalid gem name foo bar -- `Foo bar` is an invalid constant name")
end
it "fails gracefully when multiple names are passed" do
- bundle "gem foo bar baz", :raise_on_error => false
+ bundle "gem foo bar baz", raise_on_error: false
expect(err).to eq(<<-E.strip)
ERROR: "bundle gem" was called with arguments ["foo", "bar", "baz"]
Usage: "bundle gem NAME [OPTIONS]"
@@ -1386,7 +1538,7 @@ Usage: "bundle gem NAME [OPTIONS]"
describe "#ensure_safe_gem_name", :readline do
before do
- bundle "gem #{subject}", :raise_on_error => false
+ bundle "gem #{subject}", raise_on_error: false
end
context "with an existing const name" do
@@ -1419,7 +1571,7 @@ Usage: "bundle gem NAME [OPTIONS]"
end
expect(bundled_app("foobar/spec/spec_helper.rb")).to exist
- rakefile = strip_whitespace <<-RAKEFILE
+ rakefile = <<~RAKEFILE
# frozen_string_literal: true
require "bundler/gem_tasks"
@@ -1481,7 +1633,7 @@ Usage: "bundle gem NAME [OPTIONS]"
context "on conflicts with a previously created file", :readline do
it "should fail gracefully" do
FileUtils.touch(bundled_app("conflict-foobar"))
- bundle "gem conflict-foobar", :raise_on_error => false
+ bundle "gem conflict-foobar", raise_on_error: false
expect(err).to eq("Couldn't create a new gem named `conflict-foobar` because there's an existing file named `conflict-foobar`.")
expect(exitstatus).to eql(32)
end
diff --git a/spec/bundler/commands/open_spec.rb b/spec/bundler/commands/open_spec.rb
index 53dc35c2c7..97374f30c3 100644
--- a/spec/bundler/commands/open_spec.rb
+++ b/spec/bundler/commands/open_spec.rb
@@ -10,66 +10,124 @@ RSpec.describe "bundle open" do
end
it "opens the gem with BUNDLER_EDITOR as highest priority" do
- bundle "open rails", :env => { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
+ bundle "open rails", env: { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
expect(out).to include("bundler_editor #{default_bundle_path("gems", "rails-2.3.2")}")
end
it "opens the gem with VISUAL as 2nd highest priority" do
- bundle "open rails", :env => { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "" }
+ bundle "open rails", env: { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "" }
expect(out).to include("visual #{default_bundle_path("gems", "rails-2.3.2")}")
end
it "opens the gem with EDITOR as 3rd highest priority" do
- bundle "open rails", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open rails", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to include("editor #{default_bundle_path("gems", "rails-2.3.2")}")
end
it "complains if no EDITOR is set" do
- bundle "open rails", :env => { "EDITOR" => "", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open rails", env: { "EDITOR" => "", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to eq("To open a bundled gem, set $EDITOR or $BUNDLER_EDITOR")
end
it "complains if gem not in bundle" do
- bundle "open missing", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, :raise_on_error => false
+ bundle "open missing", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
expect(err).to match(/could not find gem 'missing'/i)
end
it "does not blow up if the gem to open does not have a Gemfile" do
git = build_git "foo"
- ref = git.ref_for("master", 11)
+ ref = git.ref_for("main", 11)
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => "#{lib_path("foo-1.0")}"
G
- bundle "open foo", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
- expect(out).to match("editor #{default_bundle_path.join("bundler/gems/foo-1.0-#{ref}")}")
+ bundle "open foo", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ expect(out).to include("editor #{default_bundle_path.join("bundler", "gems", "foo-1.0-#{ref}")}")
end
it "suggests alternatives for similar-sounding gems" do
- bundle "open Rails", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, :raise_on_error => false
+ bundle "open Rails", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
expect(err).to match(/did you mean rails\?/i)
end
it "opens the gem with short words" do
- bundle "open rec", :env => { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
+ bundle "open rec", env: { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
expect(out).to include("bundler_editor #{default_bundle_path("gems", "activerecord-2.3.2")}")
end
+ it "opens subpath of the gem" do
+ bundle "open activerecord --path lib/activerecord", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ expect(out).to include("editor #{default_bundle_path("gems", "activerecord-2.3.2")}/lib/activerecord")
+ end
+
+ it "opens subpath file of the gem" do
+ bundle "open activerecord --path lib/version.rb", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ expect(out).to include("editor #{default_bundle_path("gems", "activerecord-2.3.2")}/lib/version.rb")
+ end
+
+ it "opens deep subpath of the gem" do
+ bundle "open activerecord --path lib/active_record", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ expect(out).to include("editor #{default_bundle_path("gems", "activerecord-2.3.2")}/lib/active_record")
+ end
+
+ it "requires value for --path arg" do
+ bundle "open activerecord --path", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
+ expect(err).to eq "Cannot specify `--path` option without a value"
+ end
+
+ it "suggests alternatives for similar-sounding gems when using subpath" do
+ bundle "open Rails --path README.md", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
+ expect(err).to match(/did you mean rails\?/i)
+ end
+
+ it "suggests alternatives for similar-sounding gems when using deep subpath" do
+ bundle "open Rails --path some/path/here", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
+ expect(err).to match(/did you mean rails\?/i)
+ end
+
+ it "opens subpath of the short worded gem" do
+ bundle "open rec --path CHANGELOG.md", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ expect(out).to include("editor #{default_bundle_path("gems", "activerecord-2.3.2")}/CHANGELOG.md")
+ end
+
+ it "opens deep subpath of the short worded gem" do
+ bundle "open rec --path lib/activerecord", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ expect(out).to include("editor #{default_bundle_path("gems", "activerecord-2.3.2")}/lib/activerecord")
+ end
+
+ it "opens subpath of the selected matching gem", :readline do
+ env = { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
+ bundle "open active --path CHANGELOG.md", env: env do |input, _, _|
+ input.puts "2"
+ end
+
+ expect(out).to include("bundler_editor #{default_bundle_path("gems", "activerecord-2.3.2").join("CHANGELOG.md")}")
+ end
+
+ it "opens deep subpath of the selected matching gem", :readline do
+ env = { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
+ bundle "open active --path lib/activerecord/version.rb", env: env do |input, _, _|
+ input.puts "2"
+ end
+
+ expect(out).to include("bundler_editor #{default_bundle_path("gems", "activerecord-2.3.2").join("lib", "activerecord", "version.rb")}")
+ end
+
it "select the gem from many match gems", :readline do
env = { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
- bundle "open active", :env => env do |input, _, _|
+ bundle "open active", env: env do |input, _, _|
input.puts "2"
end
- expect(out).to match(/bundler_editor #{default_bundle_path('gems', 'activerecord-2.3.2')}\z/)
+ expect(out).to include("bundler_editor #{default_bundle_path("gems", "activerecord-2.3.2")}")
end
it "allows selecting exit from many match gems", :readline do
env = { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
- bundle "open active", :env => env do |input, _, _|
+ bundle "open active", env: env do |input, _, _|
input.puts "0"
end
end
@@ -82,12 +140,12 @@ RSpec.describe "bundle open" do
G
bundle "config set auto_install 1"
- bundle "open rails", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open rails", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to include("Installing foo 1.0")
end
it "opens the editor with a clean env" do
- bundle "open", :env => { "EDITOR" => "sh -c 'env'", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, :raise_on_error => false
+ bundle "open", env: { "EDITOR" => "sh -c 'env'", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
expect(out).not_to include("BUNDLE_GEMFILE=")
end
end
@@ -111,7 +169,7 @@ RSpec.describe "bundle open" do
end
it "throws proper error when trying to open default gem" do
- bundle "open json", :env => { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
+ bundle "open json", env: { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
expect(out).to include("Unable to open json because it's a default gem, so the directory it would normally be installed to does not exist.")
end
end
diff --git a/spec/bundler/commands/outdated_spec.rb b/spec/bundler/commands/outdated_spec.rb
index 731d67af1b..e7edc67e57 100644
--- a/spec/bundler/commands/outdated_spec.rb
+++ b/spec/bundler/commands/outdated_spec.rb
@@ -4,8 +4,8 @@ RSpec.describe "bundle outdated" do
describe "with no arguments" do
before do
build_repo2 do
- build_git "foo", :path => lib_path("foo")
- build_git "zebra", :path => lib_path("zebra")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
end
install_gemfile <<-G
@@ -23,11 +23,11 @@ RSpec.describe "bundle outdated" do
update_repo2 do
build_gem "activesupport", "3.0"
build_gem "weakling", "0.2"
- update_git "foo", :path => lib_path("foo")
- update_git "zebra", :path => lib_path("zebra")
+ update_git "foo", path: lib_path("foo")
+ update_git "zebra", path: lib_path("zebra")
end
- bundle "outdated", :raise_on_error => false
+ bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
Gem Current Latest Requested Groups
@@ -50,7 +50,7 @@ RSpec.describe "bundle outdated" do
gem "AAA", "1.0.0"
G
- bundle "outdated", :raise_on_error => false
+ bundle "outdated", raise_on_error: false
expected_output = <<~TABLE
Gem Current Latest Requested Groups
@@ -63,10 +63,10 @@ RSpec.describe "bundle outdated" do
it "returns non zero exit status if outdated gems present" do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", :path => lib_path("foo")
+ update_git "foo", path: lib_path("foo")
end
- bundle "outdated", :raise_on_error => false
+ bundle "outdated", raise_on_error: false
expect(exitstatus).to_not be_zero
end
@@ -89,7 +89,7 @@ RSpec.describe "bundle outdated" do
update_repo2 { build_gem "activesupport", "3.0" }
update_repo2 { build_gem "terranova", "9" }
- bundle "outdated", :raise_on_error => false
+ bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -104,8 +104,8 @@ RSpec.describe "bundle outdated" do
describe "with --verbose option" do
before do
build_repo2 do
- build_git "foo", :path => lib_path("foo")
- build_git "zebra", :path => lib_path("zebra")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
end
install_gemfile <<-G
@@ -139,7 +139,7 @@ RSpec.describe "bundle outdated" do
gem 'activesupport', '2.3.5'
G
- bundle "outdated --verbose", :raise_on_error => false
+ bundle "outdated --verbose", raise_on_error: false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups Path
@@ -151,7 +151,7 @@ RSpec.describe "bundle outdated" do
end
end
- describe "with multiple, duplicated sources, with lockfile in old format", :bundler => "< 3" do
+ describe "with multiple, duplicated sources, with lockfile in old format", bundler: "< 3" do
before do
build_repo2 do
build_gem "dotenv", "2.7.6"
@@ -192,7 +192,7 @@ RSpec.describe "bundle outdated" do
vcr (6.0.0)
PLATFORMS
- #{specific_local_platform}
+ #{local_platform}
DEPENDENCIES
dotenv
@@ -205,8 +205,8 @@ RSpec.describe "bundle outdated" do
end
it "works" do
- bundle :install, :artifice => "compact_index"
- bundle :outdated, :artifice => "compact_index", :raise_on_error => false
+ bundle :install, artifice: "compact_index"
+ bundle :outdated, artifice: "compact_index", raise_on_error: false
expected_output = <<~TABLE
Gem Current Latest Requested Groups
@@ -220,8 +220,8 @@ RSpec.describe "bundle outdated" do
describe "with --group option" do
before do
build_repo2 do
- build_git "foo", :path => lib_path("foo")
- build_git "zebra", :path => lib_path("zebra")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
end
install_gemfile <<-G
@@ -243,7 +243,7 @@ RSpec.describe "bundle outdated" do
build_gem "duradura", "8.0"
end
- bundle "outdated --group #{group}", :raise_on_error => false
+ bundle "outdated --group #{group}", raise_on_error: false
end
it "works when the bundle is up to date" do
@@ -290,8 +290,8 @@ RSpec.describe "bundle outdated" do
describe "with --groups option and outdated transitive dependencies" do
before do
build_repo2 do
- build_git "foo", :path => lib_path("foo")
- build_git "zebra", :path => lib_path("zebra")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
build_gem "bar", %w[2.0.0]
@@ -312,7 +312,7 @@ RSpec.describe "bundle outdated" do
end
it "returns a sorted list of outdated gems" do
- bundle "outdated --groups", :raise_on_error => false
+ bundle "outdated --groups", raise_on_error: false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -326,8 +326,8 @@ 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")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
end
install_gemfile <<-G
@@ -354,7 +354,7 @@ RSpec.describe "bundle outdated" do
build_gem "duradura", "8.0"
end
- bundle "outdated --groups", :raise_on_error => false
+ bundle "outdated --groups", raise_on_error: false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -370,8 +370,8 @@ RSpec.describe "bundle outdated" do
describe "with --local option" do
before do
build_repo2 do
- build_git "foo", :path => lib_path("foo")
- build_git "zebra", :path => lib_path("zebra")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
end
install_gemfile <<-G
@@ -398,7 +398,7 @@ RSpec.describe "bundle outdated" do
gem "activesupport", "2.3.4"
G
- bundle "outdated --local", :raise_on_error => false
+ bundle "outdated --local", raise_on_error: false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -420,8 +420,8 @@ RSpec.describe "bundle outdated" do
context "and gems are outdated" do
before do
build_repo2 do
- build_git "foo", :path => lib_path("foo")
- build_git "zebra", :path => lib_path("zebra")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
build_gem "activesupport", "3.0"
build_gem "weakling", "0.2"
@@ -455,13 +455,13 @@ RSpec.describe "bundle outdated" do
end
describe "with --parseable option" do
- subject { bundle "outdated --parseable", :raise_on_error => false }
+ subject { bundle "outdated --parseable", raise_on_error: false }
it_behaves_like "a minimal output is desired"
end
describe "with aliased --porcelain option" do
- subject { bundle "outdated --porcelain", :raise_on_error => false }
+ subject { bundle "outdated --porcelain", raise_on_error: false }
it_behaves_like "a minimal output is desired"
end
@@ -469,8 +469,8 @@ 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")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
end
install_gemfile <<-G
@@ -485,10 +485,10 @@ RSpec.describe "bundle outdated" do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", :path => lib_path("foo")
+ update_git "foo", path: lib_path("foo")
end
- bundle "outdated foo", :raise_on_error => false
+ bundle "outdated foo", raise_on_error: false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
Gem Current Latest Requested Groups
@@ -502,8 +502,8 @@ RSpec.describe "bundle outdated" do
describe "pre-release gems" do
before do
build_repo2 do
- build_git "foo", :path => lib_path("foo")
- build_git "zebra", :path => lib_path("zebra")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
end
install_gemfile <<-G
@@ -535,7 +535,7 @@ RSpec.describe "bundle outdated" do
build_gem "activesupport", "3.0.0.beta"
end
- bundle "outdated --pre", :raise_on_error => false
+ bundle "outdated --pre", raise_on_error: false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -558,7 +558,7 @@ RSpec.describe "bundle outdated" do
gem "activesupport", "3.0.0.beta.1"
G
- bundle "outdated", :raise_on_error => false
+ bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -570,12 +570,11 @@ RSpec.describe "bundle outdated" do
end
end
- filter_strict_option = Bundler.feature_flag.bundler_2_mode? ? :"filter-strict" : :strict
- describe "with --#{filter_strict_option} option" do
+ describe "with --filter-strict option" do
before do
build_repo2 do
- build_git "foo", :path => lib_path("foo")
- build_git "zebra", :path => lib_path("zebra")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
end
install_gemfile <<-G
@@ -595,7 +594,23 @@ RSpec.describe "bundle outdated" do
build_gem "weakling", "0.0.5"
end
- bundle :outdated, filter_strict_option => true, :raise_on_error => false
+ bundle :outdated, "filter-strict": true, raise_on_error: false
+
+ expected_output = <<~TABLE.strip
+ Gem Current Latest Requested Groups
+ weakling 0.0.3 0.0.5 ~> 0.0.1 default
+ TABLE
+
+ expect(out).to end_with(expected_output)
+ end
+
+ it "only reports gems that have a newer version that matches the specified dependency version requirements, using --strict alias" do
+ update_repo2 do
+ build_gem "activesupport", "3.0"
+ build_gem "weakling", "0.0.5"
+ end
+
+ bundle :outdated, strict: true, raise_on_error: false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -611,7 +626,7 @@ RSpec.describe "bundle outdated" do
gem "activesupport", platforms: [:ruby_22]
G
- bundle :outdated, filter_strict_option => true
+ bundle :outdated, "filter-strict": true
expect(out).to end_with("Bundle up to date!")
end
@@ -622,7 +637,7 @@ RSpec.describe "bundle outdated" do
gem "rack_middleware", "1.0"
G
- bundle :outdated, filter_strict_option => true
+ bundle :outdated, "filter-strict": true
expect(out).to end_with("Bundle up to date!")
end
@@ -640,7 +655,7 @@ RSpec.describe "bundle outdated" do
build_gem "weakling", "0.0.5"
end
- bundle :outdated, filter_strict_option => true, "filter-patch" => true, :raise_on_error => false
+ bundle :outdated, :"filter-strict" => true, "filter-patch" => true, :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -662,7 +677,7 @@ RSpec.describe "bundle outdated" do
build_gem "weakling", "0.1.5"
end
- bundle :outdated, filter_strict_option => true, "filter-minor" => true, :raise_on_error => false
+ bundle :outdated, :"filter-strict" => true, "filter-minor" => true, :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -684,7 +699,7 @@ RSpec.describe "bundle outdated" do
build_gem "weakling", "1.1.5"
end
- bundle :outdated, filter_strict_option => true, "filter-major" => true, :raise_on_error => false
+ bundle :outdated, :"filter-strict" => true, "filter-major" => true, :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -699,8 +714,8 @@ RSpec.describe "bundle outdated" do
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")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
end
install_gemfile <<-G
@@ -715,12 +730,12 @@ RSpec.describe "bundle outdated" do
end
it "returns could not find gem name" do
- bundle "outdated invalid_gem_name", :raise_on_error => false
+ bundle "outdated invalid_gem_name", raise_on_error: false
expect(err).to include("Could not find gem 'invalid_gem_name'.")
end
it "returns non-zero exit code" do
- bundle "outdated invalid_gem_name", :raise_on_error => false
+ bundle "outdated invalid_gem_name", raise_on_error: false
expect(exitstatus).to_not be_zero
end
end
@@ -733,11 +748,11 @@ RSpec.describe "bundle outdated" do
G
bundle "config set auto_install 1"
- bundle :outdated, :raise_on_error => false
+ bundle :outdated, raise_on_error: false
expect(out).to include("Installing foo 1.0")
end
- context "after bundle install --deployment", :bundler => "< 3" do
+ context "after bundle install --deployment", bundler: "< 3" do
before do
build_repo2
@@ -748,13 +763,13 @@ RSpec.describe "bundle outdated" do
gem "foo"
G
bundle :lock
- bundle :install, :deployment => true
+ bundle :install, deployment: true
end
it "outputs a helpful message about being in deployment mode" do
update_repo2 { build_gem "activesupport", "3.0" }
- bundle "outdated", :raise_on_error => false
+ bundle "outdated", raise_on_error: false
expect(last_command).to be_failure
expect(err).to include("You are trying to check outdated gems in deployment mode.")
expect(err).to include("Run `bundle outdated` elsewhere.")
@@ -766,8 +781,8 @@ 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")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
end
install_gemfile <<-G
@@ -782,7 +797,7 @@ RSpec.describe "bundle outdated" do
it "outputs a helpful message about being in deployment mode" do
update_repo2 { build_gem "activesupport", "3.0" }
- bundle "outdated", :raise_on_error => false
+ bundle "outdated", raise_on_error: false
expect(last_command).to be_failure
expect(err).to include("You are trying to check outdated gems in deployment mode.")
expect(err).to include("Run `bundle outdated` elsewhere.")
@@ -822,13 +837,13 @@ RSpec.describe "bundle outdated" do
expect(out).to end_with("Bundle up to date!")
end
- it "reports that updates are available if the JRuby platform is used", :jruby do
+ it "reports that updates are available if the JRuby platform is used", :jruby_only do
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
gem "laduradura", '= 5.15.2', :platforms => [:ruby, :jruby]
G
- bundle "outdated", :raise_on_error => false
+ bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -852,8 +867,8 @@ 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")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
end
install_gemfile <<-G
@@ -878,8 +893,8 @@ 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")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
end
install_gemfile <<-G
@@ -894,22 +909,22 @@ RSpec.describe "bundle outdated" do
simulate_new_machine
- update_git "foo", :path => lib_path("foo")
+ update_git "foo", path: lib_path("foo")
update_repo2 do
build_gem "activesupport", "3.3.5"
build_gem "weakling", "0.8.0"
end
end
- subject { bundle "outdated", :raise_on_error => false }
+ subject { bundle "outdated", raise_on_error: false }
it_behaves_like "version update is detected"
end
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")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
end
install_gemfile <<-G
@@ -934,8 +949,8 @@ 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")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
end
install_gemfile <<-G
@@ -967,8 +982,8 @@ 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")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
end
install_gemfile <<-G
@@ -993,8 +1008,8 @@ 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")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
end
install_gemfile <<-G
@@ -1019,8 +1034,8 @@ 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")
+ build_git "foo", path: lib_path("foo")
+ build_git "zebra", path: lib_path("zebra")
end
install_gemfile <<-G
@@ -1043,7 +1058,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-major option" do
- subject { bundle "outdated --filter-major", :raise_on_error => false }
+ subject { bundle "outdated --filter-major", raise_on_error: false }
it_behaves_like "major version updates are detected"
it_behaves_like "minor version is ignored"
@@ -1051,7 +1066,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-minor option" do
- subject { bundle "outdated --filter-minor", :raise_on_error => false }
+ subject { bundle "outdated --filter-minor", raise_on_error: false }
it_behaves_like "minor version updates are detected"
it_behaves_like "major version is ignored"
@@ -1059,7 +1074,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-patch option" do
- subject { bundle "outdated --filter-patch", :raise_on_error => false }
+ subject { bundle "outdated --filter-patch", raise_on_error: false }
it_behaves_like "patch version updates are detected"
it_behaves_like "major version is ignored"
@@ -1067,7 +1082,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-minor --filter-patch options" do
- subject { bundle "outdated --filter-minor --filter-patch", :raise_on_error => false }
+ subject { bundle "outdated --filter-minor --filter-patch", raise_on_error: false }
it_behaves_like "minor version updates are detected"
it_behaves_like "patch version updates are detected"
@@ -1075,7 +1090,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-major --filter-minor options" do
- subject { bundle "outdated --filter-major --filter-minor", :raise_on_error => false }
+ subject { bundle "outdated --filter-major --filter-minor", raise_on_error: false }
it_behaves_like "major version updates are detected"
it_behaves_like "minor version updates are detected"
@@ -1083,7 +1098,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-major --filter-patch options" do
- subject { bundle "outdated --filter-major --filter-patch", :raise_on_error => false }
+ subject { bundle "outdated --filter-major --filter-patch", raise_on_error: false }
it_behaves_like "major version updates are detected"
it_behaves_like "patch version updates are detected"
@@ -1091,7 +1106,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-major --filter-minor --filter-patch options" do
- subject { bundle "outdated --filter-major --filter-minor --filter-patch", :raise_on_error => false }
+ subject { bundle "outdated --filter-major --filter-minor --filter-patch", raise_on_error: false }
it_behaves_like "major version updates are detected"
it_behaves_like "minor version updates are detected"
@@ -1099,116 +1114,125 @@ RSpec.describe "bundle outdated" do
end
context "conservative updates" do
- context "without update-strict" do
- before do
- build_repo4 do
- build_gem "patch", %w[1.0.0 1.0.1]
- build_gem "minor", %w[1.0.0 1.0.1 1.1.0]
- build_gem "major", %w[1.0.0 1.0.1 1.1.0 2.0.0]
- end
+ before do
+ build_repo4 do
+ build_gem "patch", %w[1.0.0 1.0.1]
+ build_gem "minor", %w[1.0.0 1.0.1 1.1.0]
+ build_gem "major", %w[1.0.0 1.0.1 1.1.0 2.0.0]
+ end
- # establish a lockfile set to 1.0.0
- install_gemfile <<-G
- source "#{file_uri_for(gem_repo4)}"
- gem 'patch', '1.0.0'
- gem 'minor', '1.0.0'
- gem 'major', '1.0.0'
- G
+ # establish a lockfile set to 1.0.0
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem 'patch', '1.0.0'
+ gem 'minor', '1.0.0'
+ gem 'major', '1.0.0'
+ G
- # remove 1.4.3 requirement and bar altogether
- # to setup update specs below
- gemfile <<-G
- source "#{file_uri_for(gem_repo4)}"
- gem 'patch'
- gem 'minor'
- gem 'major'
- G
- end
+ # remove all version requirements
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem 'patch'
+ gem 'minor'
+ gem 'major'
+ G
+ end
- it "shows nothing when patching and filtering to minor" do
- bundle "outdated --patch --filter-minor"
+ it "shows nothing when patching and filtering to minor" do
+ bundle "outdated --patch --filter-minor"
- expect(out).to end_with("No minor updates to display.")
- end
+ expect(out).to end_with("No minor updates to display.")
+ end
- it "shows all gems when patching and filtering to patch" do
- bundle "outdated --patch --filter-patch", :raise_on_error => false
+ it "shows all gems when patching and filtering to patch" do
+ bundle "outdated --patch --filter-patch", raise_on_error: false
- expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
- major 1.0.0 1.0.1 >= 0 default
- minor 1.0.0 1.0.1 >= 0 default
- patch 1.0.0 1.0.1 >= 0 default
- TABLE
+ expected_output = <<~TABLE.strip
+ Gem Current Latest Requested Groups
+ major 1.0.0 1.0.1 >= 0 default
+ minor 1.0.0 1.0.1 >= 0 default
+ patch 1.0.0 1.0.1 >= 0 default
+ TABLE
- expect(out).to end_with(expected_output)
- end
+ expect(out).to end_with(expected_output)
+ end
- it "shows minor and major when updating to minor and filtering to patch and minor" do
- bundle "outdated --minor --filter-minor", :raise_on_error => false
+ it "shows minor and major when updating to minor and filtering to patch and minor" do
+ bundle "outdated --minor --filter-minor", raise_on_error: false
- expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
- major 1.0.0 1.1.0 >= 0 default
- minor 1.0.0 1.1.0 >= 0 default
- TABLE
+ expected_output = <<~TABLE.strip
+ Gem Current Latest Requested Groups
+ major 1.0.0 1.1.0 >= 0 default
+ minor 1.0.0 1.1.0 >= 0 default
+ TABLE
- expect(out).to end_with(expected_output)
- end
+ expect(out).to end_with(expected_output)
+ end
- it "shows minor when updating to major and filtering to minor with parseable" do
- bundle "outdated --major --filter-minor --parseable", :raise_on_error => false
+ it "shows minor when updating to major and filtering to minor with parseable" do
+ bundle "outdated --major --filter-minor --parseable", raise_on_error: false
- expect(out).not_to include("patch (newest")
- expect(out).to include("minor (newest")
- expect(out).not_to include("major (newest")
- end
+ expect(out).not_to include("patch (newest")
+ expect(out).to include("minor (newest")
+ expect(out).not_to include("major (newest")
end
+ end
- context "with update-strict" do
- before do
- build_repo4 do
- build_gem "foo", %w[1.4.3 1.4.4] do |s|
- s.add_dependency "bar", "~> 2.0"
- end
- build_gem "foo", %w[1.4.5 1.5.0] do |s|
- s.add_dependency "bar", "~> 2.1"
- end
- build_gem "foo", %w[1.5.1] do |s|
- s.add_dependency "bar", "~> 3.0"
- end
- build_gem "bar", %w[2.0.3 2.0.4 2.0.5 2.1.0 2.1.1 3.0.0]
- build_gem "qux", %w[1.0.0 1.1.0 2.0.0]
+ context "tricky conservative updates" do
+ before do
+ build_repo4 do
+ build_gem "foo", %w[1.4.3 1.4.4] do |s|
+ s.add_dependency "bar", "~> 2.0"
+ end
+ build_gem "foo", %w[1.4.5 1.5.0] do |s|
+ s.add_dependency "bar", "~> 2.1"
end
+ build_gem "foo", %w[1.5.1] do |s|
+ s.add_dependency "bar", "~> 3.0"
+ end
+ build_gem "bar", %w[2.0.3 2.0.4 2.0.5 2.1.0 2.1.1 3.0.0]
+ build_gem "qux", %w[1.0.0 1.1.0 2.0.0]
+ end
- # establish a lockfile set to 1.4.3
- install_gemfile <<-G
- source "#{file_uri_for(gem_repo4)}"
- gem 'foo', '1.4.3'
- gem 'bar', '2.0.3'
- gem 'qux', '1.0.0'
- G
+ # establish a lockfile set to 1.4.3
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem 'foo', '1.4.3'
+ gem 'bar', '2.0.3'
+ gem 'qux', '1.0.0'
+ G
- # remove 1.4.3 requirement and bar altogether
- # to setup update specs below
- gemfile <<-G
- source "#{file_uri_for(gem_repo4)}"
- gem 'foo'
- gem 'qux'
- G
- end
+ # remove 1.4.3 requirement and bar altogether
+ # to setup update specs below
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem 'foo'
+ gem 'qux'
+ G
+ end
- it "shows gems with update-strict updating to patch and filtering to patch" do
- bundle "outdated --patch --update-strict --filter-patch", :raise_on_error => false
+ it "shows gems updating to patch and filtering to patch" do
+ bundle "outdated --patch --filter-patch", raise_on_error: false, env: { "DEBUG_RESOLVER" => "1" }
- expected_output = <<~TABLE.strip
- Gem Current Latest Requested Groups
- bar 2.0.3 2.0.5
- foo 1.4.3 1.4.4 >= 0 default
- TABLE
+ expected_output = <<~TABLE.strip
+ Gem Current Latest Requested Groups
+ bar 2.0.3 2.0.5
+ foo 1.4.3 1.4.4 >= 0 default
+ TABLE
- expect(out).to end_with(expected_output)
- end
+ expect(out).to end_with(expected_output)
+ end
+
+ it "shows gems updating to patch and filtering to patch, in debug mode" do
+ bundle "outdated --patch --filter-patch", raise_on_error: false, env: { "DEBUG" => "1" }
+
+ expected_output = <<~TABLE.strip
+ Gem Current Latest Requested Groups Path
+ bar 2.0.3 2.0.5
+ foo 1.4.3 1.4.4 >= 0 default
+ TABLE
+
+ expect(out).to end_with(expected_output)
end
end
@@ -1232,7 +1256,7 @@ RSpec.describe "bundle outdated" do
gem 'weakling'
G
- bundle "outdated --only-explicit", :raise_on_error => false
+ bundle "outdated --only-explicit", raise_on_error: false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -1282,7 +1306,7 @@ RSpec.describe "bundle outdated" do
end
it "reports a single entry per gem" do
- bundle "outdated", :raise_on_error => false
+ bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -1331,7 +1355,7 @@ RSpec.describe "bundle outdated" do
end
it "works" do
- bundle "outdated", :raise_on_error => false
+ bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
diff --git a/spec/bundler/other/platform_spec.rb b/spec/bundler/commands/platform_spec.rb
index 5693d6bce6..61e615acae 100644
--- a/spec/bundler/other/platform_spec.rb
+++ b/spec/bundler/commands/platform_spec.rb
@@ -2,10 +2,6 @@
RSpec.describe "bundle platform" do
context "without flags" do
- let(:bundle_platform_platforms_string) do
- local_platforms.reverse.map {|pl| "* #{pl}" }.join("\n")
- end
-
it "returns all the output" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -17,13 +13,13 @@ RSpec.describe "bundle platform" do
bundle "platform"
expect(out).to eq(<<-G.chomp)
-Your platform is: #{RUBY_PLATFORM}
+Your platform is: #{Gem::Platform.local}
Your app has gems that work on these platforms:
-#{bundle_platform_platforms_string}
+* #{local_platform}
Your Gemfile specifies a Ruby version requirement:
-* ruby #{RUBY_VERSION}
+* ruby #{Gem.ruby_version}
Your current platform satisfies the Ruby version requirement.
G
@@ -40,13 +36,13 @@ G
bundle "platform"
expect(out).to eq(<<-G.chomp)
-Your platform is: #{RUBY_PLATFORM}
+Your platform is: #{Gem::Platform.local}
Your app has gems that work on these platforms:
-#{bundle_platform_platforms_string}
+* #{local_platform}
Your Gemfile specifies a Ruby version requirement:
-* ruby #{RUBY_VERSION}p#{RUBY_PATCHLEVEL}
+* #{Bundler::RubyVersion.system.single_version_string}
Your current platform satisfies the Ruby version requirement.
G
@@ -61,10 +57,10 @@ G
bundle "platform"
expect(out).to eq(<<-G.chomp)
-Your platform is: #{RUBY_PLATFORM}
+Your platform is: #{Gem::Platform.local}
Your app has gems that work on these platforms:
-#{bundle_platform_platforms_string}
+* #{local_platform}
Your Gemfile does not specify a Ruby version requirement.
G
@@ -81,15 +77,15 @@ G
bundle "platform"
expect(out).to eq(<<-G.chomp)
-Your platform is: #{RUBY_PLATFORM}
+Your platform is: #{Gem::Platform.local}
Your app has gems that work on these platforms:
-#{bundle_platform_platforms_string}
+* #{local_platform}
Your Gemfile specifies a Ruby version requirement:
* ruby #{not_local_ruby_version}
-Your Ruby version is #{RUBY_VERSION}, but your Gemfile specified #{not_local_ruby_version}
+Your Ruby version is #{Gem.ruby_version}, but your Gemfile specified #{not_local_ruby_version}
G
end
end
@@ -168,7 +164,7 @@ G
gem "foo"
G
- bundle "platform", :raise_on_error => false
+ bundle "platform", raise_on_error: false
expect(exitstatus).not_to eq(0)
end
@@ -181,7 +177,7 @@ G
gem "foo"
G
- bundle "platform", :raise_on_error => false
+ bundle "platform", raise_on_error: false
expect(exitstatus).not_to eq(0)
end
@@ -194,7 +190,7 @@ G
gem "foo"
G
- bundle "platform", :raise_on_error => false
+ bundle "platform", raise_on_error: false
expect(exitstatus).not_to eq(0)
end
@@ -235,7 +231,30 @@ G
L
bundle "platform --ruby"
- expect(out).to eq("ruby 1.0.0p127")
+ expect(out).to eq("ruby 1.0.0")
+ end
+
+ it "handles when there is a lockfile with no requirement" do
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "platform --ruby"
+ expect(out).to eq("No ruby version specified")
end
it "handles when there is a requirement in the gemfile" do
@@ -259,18 +278,18 @@ G
end
end
- let(:ruby_version_correct) { "ruby \"#{RUBY_VERSION}\", :engine => \"#{local_ruby_engine}\", :engine_version => \"#{local_engine_version}\"" }
- let(:ruby_version_correct_engineless) { "ruby \"#{RUBY_VERSION}\"" }
+ let(:ruby_version_correct) { "ruby \"#{Gem.ruby_version}\", :engine => \"#{local_ruby_engine}\", :engine_version => \"#{local_engine_version}\"" }
+ let(:ruby_version_correct_engineless) { "ruby \"#{Gem.ruby_version}\"" }
let(:ruby_version_correct_patchlevel) { "#{ruby_version_correct}, :patchlevel => '#{RUBY_PATCHLEVEL}'" }
let(:ruby_version_incorrect) { "ruby \"#{not_local_ruby_version}\", :engine => \"#{local_ruby_engine}\", :engine_version => \"#{not_local_ruby_version}\"" }
- let(:engine_incorrect) { "ruby \"#{RUBY_VERSION}\", :engine => \"#{not_local_tag}\", :engine_version => \"#{RUBY_VERSION}\"" }
- let(:engine_version_incorrect) { "ruby \"#{RUBY_VERSION}\", :engine => \"#{local_ruby_engine}\", :engine_version => \"#{not_local_engine_version}\"" }
+ let(:engine_incorrect) { "ruby \"#{Gem.ruby_version}\", :engine => \"#{not_local_tag}\", :engine_version => \"#{Gem.ruby_version}\"" }
+ let(:engine_version_incorrect) { "ruby \"#{Gem.ruby_version}\", :engine => \"#{local_ruby_engine}\", :engine_version => \"#{not_local_engine_version}\"" }
let(:patchlevel_incorrect) { "#{ruby_version_correct}, :patchlevel => '#{not_local_patchlevel}'" }
let(:patchlevel_fixnum) { "#{ruby_version_correct}, :patchlevel => #{RUBY_PATCHLEVEL}1" }
def should_be_ruby_version_incorrect
expect(exitstatus).to eq(18)
- expect(err).to be_include("Your Ruby version is #{RUBY_VERSION}, but your Gemfile specified #{not_local_ruby_version}")
+ expect(err).to be_include("Your Ruby version is #{Gem.ruby_version}, but your Gemfile specified #{not_local_ruby_version}")
end
def should_be_engine_incorrect
@@ -305,7 +324,7 @@ G
expect(bundled_app_lock).to exist
end
- it "installs fine with any engine", :jruby do
+ it "installs fine with any engine", :jruby_only do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -328,7 +347,7 @@ G
end
it "doesn't install when the ruby version doesn't match" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -340,7 +359,7 @@ G
end
it "doesn't install when engine doesn't match" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -351,8 +370,8 @@ G
should_be_engine_incorrect
end
- it "doesn't install when engine version doesn't match", :jruby do
- install_gemfile <<-G, :raise_on_error => false
+ it "doesn't install when engine version doesn't match", :jruby_only do
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -364,7 +383,7 @@ G
end
it "doesn't install when patchlevel doesn't match" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -394,7 +413,7 @@ G
expect(out).to match(/\AResolving dependencies\.\.\.\.*\nThe Gemfile's dependencies are satisfied\z/)
end
- it "checks fine with any engine", :jruby do
+ it "checks fine with any engine", :jruby_only do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -424,7 +443,7 @@ G
#{ruby_version_incorrect}
G
- bundle :check, :raise_on_error => false
+ bundle :check, raise_on_error: false
should_be_ruby_version_incorrect
end
@@ -441,11 +460,11 @@ G
#{engine_incorrect}
G
- bundle :check, :raise_on_error => false
+ bundle :check, raise_on_error: false
should_be_engine_incorrect
end
- it "fails when engine version doesn't match", :jruby do
+ it "fails when engine version doesn't match", :jruby_only do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -458,7 +477,7 @@ G
#{engine_version_incorrect}
G
- bundle :check, :raise_on_error => false
+ bundle :check, raise_on_error: false
should_be_engine_version_incorrect
end
@@ -475,7 +494,7 @@ G
#{patchlevel_incorrect}
G
- bundle :check, :raise_on_error => false
+ bundle :check, raise_on_error: false
should_be_patchlevel_incorrect
end
end
@@ -507,11 +526,11 @@ G
build_gem "activesupport", "3.0"
end
- bundle "update", :all => true
+ bundle "update", all: true
expect(the_bundle).to include_gems "rack 1.2", "rack-obama 1.0", "activesupport 3.0"
end
- it "updates fine with any engine", :jruby do
+ it "updates fine with any engine", :jruby_only do
gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
@@ -527,7 +546,7 @@ G
build_gem "activesupport", "3.0"
end
- bundle "update", :all => true
+ bundle "update", all: true
expect(the_bundle).to include_gems "rack 1.2", "rack-obama 1.0", "activesupport 3.0"
end
@@ -543,11 +562,11 @@ G
build_gem "activesupport", "3.0"
end
- bundle :update, :all => true, :raise_on_error => false
+ bundle :update, all: true, raise_on_error: false
should_be_ruby_version_incorrect
end
- it "fails when ruby engine doesn't match", :jruby do
+ it "fails when ruby engine doesn't match", :jruby_only do
gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
@@ -559,11 +578,11 @@ G
build_gem "activesupport", "3.0"
end
- bundle :update, :all => true, :raise_on_error => false
+ bundle :update, all: true, raise_on_error: false
should_be_engine_incorrect
end
- it "fails when ruby engine version doesn't match", :jruby do
+ it "fails when ruby engine version doesn't match", :jruby_only do
gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
@@ -575,7 +594,7 @@ G
build_gem "activesupport", "3.0"
end
- bundle :update, :all => true, :raise_on_error => false
+ bundle :update, all: true, raise_on_error: false
should_be_engine_version_incorrect
end
@@ -590,7 +609,7 @@ G
build_gem "activesupport", "3.0"
end
- bundle :update, :all => true, :raise_on_error => false
+ bundle :update, all: true, raise_on_error: false
should_be_patchlevel_incorrect
end
end
@@ -615,7 +634,7 @@ G
expect(out).to eq(default_bundle_path("gems", "rails-2.3.2").to_s)
end
- it "prints path if ruby version is correct for any engine", :jruby do
+ it "prints path if ruby version is correct for any engine", :jruby_only do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rails"
@@ -627,7 +646,7 @@ G
expect(out).to eq(default_bundle_path("gems", "rails-2.3.2").to_s)
end
- it "fails if ruby version doesn't match", :bundler => "< 3" do
+ it "fails if ruby version doesn't match", bundler: "< 3" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rails"
@@ -635,11 +654,11 @@ G
#{ruby_version_incorrect}
G
- bundle "show rails", :raise_on_error => false
+ bundle "show rails", raise_on_error: false
should_be_ruby_version_incorrect
end
- it "fails if engine doesn't match", :bundler => "< 3" do
+ it "fails if engine doesn't match", bundler: "< 3" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rails"
@@ -647,11 +666,11 @@ G
#{engine_incorrect}
G
- bundle "show rails", :raise_on_error => false
+ bundle "show rails", raise_on_error: false
should_be_engine_incorrect
end
- it "fails if engine version doesn't match", :bundler => "< 3", :jruby => true do
+ it "fails if engine version doesn't match", bundler: "< 3", jruby_only: true do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rails"
@@ -659,11 +678,11 @@ G
#{engine_version_incorrect}
G
- bundle "show rails", :raise_on_error => false
+ bundle "show rails", raise_on_error: false
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match", :bundler => "< 3" do
+ it "fails when patchlevel doesn't match", bundler: "< 3" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -674,7 +693,7 @@ G
build_gem "activesupport", "3.0"
end
- bundle "show rails", :raise_on_error => false
+ bundle "show rails", raise_on_error: false
should_be_patchlevel_incorrect
end
end
@@ -699,7 +718,7 @@ G
expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
- it "copies the .gem file to vendor/cache when ruby version matches for any engine", :jruby do
+ it "copies the .gem file to vendor/cache when ruby version matches for any engine", :jruby_only do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem 'rack'
@@ -719,7 +738,7 @@ G
#{ruby_version_incorrect}
G
- bundle :cache, :raise_on_error => false
+ bundle :cache, raise_on_error: false
should_be_ruby_version_incorrect
end
@@ -731,11 +750,11 @@ G
#{engine_incorrect}
G
- bundle :cache, :raise_on_error => false
+ bundle :cache, raise_on_error: false
should_be_engine_incorrect
end
- it "fails if the engine version doesn't match", :jruby do
+ it "fails if the engine version doesn't match", :jruby_only do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem 'rack'
@@ -743,7 +762,7 @@ G
#{engine_version_incorrect}
G
- bundle :cache, :raise_on_error => false
+ bundle :cache, raise_on_error: false
should_be_engine_version_incorrect
end
@@ -755,7 +774,7 @@ G
#{patchlevel_incorrect}
G
- bundle :cache, :raise_on_error => false
+ bundle :cache, raise_on_error: false
should_be_patchlevel_incorrect
end
end
@@ -780,7 +799,7 @@ G
expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
- it "copies the .gem file to vendor/cache when ruby version matches any engine", :jruby do
+ it "copies the .gem file to vendor/cache when ruby version matches any engine", :jruby_only do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem 'rack'
@@ -800,7 +819,7 @@ G
#{ruby_version_incorrect}
G
- bundle :cache, :raise_on_error => false
+ bundle :cache, raise_on_error: false
should_be_ruby_version_incorrect
end
@@ -812,11 +831,11 @@ G
#{engine_incorrect}
G
- bundle :cache, :raise_on_error => false
+ bundle :cache, raise_on_error: false
should_be_engine_incorrect
end
- it "fails if the engine version doesn't match", :jruby do
+ it "fails if the engine version doesn't match", :jruby_only do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem 'rack'
@@ -824,7 +843,7 @@ G
#{engine_version_incorrect}
G
- bundle :cache, :raise_on_error => false
+ bundle :cache, raise_on_error: false
should_be_engine_version_incorrect
end
@@ -836,7 +855,7 @@ G
#{patchlevel_incorrect}
G
- bundle :cache, :raise_on_error => false
+ bundle :cache, raise_on_error: false
should_be_patchlevel_incorrect
end
end
@@ -844,7 +863,7 @@ G
context "bundle exec" do
before do
ENV["BUNDLER_FORCE_TTY"] = "true"
- system_gems "rack-1.0.0", "rack-0.9.1", :path => default_bundle_path
+ system_gems "rack-1.0.0", "rack-0.9.1", path: default_bundle_path
end
it "activates the correct gem when ruby version matches" do
@@ -859,8 +878,8 @@ G
expect(out).to include("0.9.1")
end
- it "activates the correct gem when ruby version matches any engine", :jruby do
- system_gems "rack-1.0.0", "rack-0.9.1", :path => default_bundle_path
+ it "activates the correct gem when ruby version matches any engine", :jruby_only do
+ system_gems "rack-1.0.0", "rack-0.9.1", path: default_bundle_path
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack", "0.9.1"
@@ -880,7 +899,7 @@ G
#{ruby_version_incorrect}
G
- bundle "exec rackup", :raise_on_error => false
+ bundle "exec rackup", raise_on_error: false
should_be_ruby_version_incorrect
end
@@ -892,11 +911,11 @@ G
#{engine_incorrect}
G
- bundle "exec rackup", :raise_on_error => false
+ bundle "exec rackup", raise_on_error: false
should_be_engine_incorrect
end
- # it "fails when the engine version doesn't match", :jruby do
+ # it "fails when the engine version doesn't match", :jruby_only do
# gemfile <<-G
# gem "rack", "0.9.1"
#
@@ -915,12 +934,12 @@ G
#{patchlevel_incorrect}
G
- bundle "exec rackup", :raise_on_error => false
+ bundle "exec rackup", raise_on_error: false
should_be_patchlevel_incorrect
end
end
- context "bundle console", :bundler => "< 3" do
+ context "bundle console", bundler: "< 3" do
before do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -947,7 +966,7 @@ G
expect(out).to include("0.9.1")
end
- it "starts IRB with the default group loaded when ruby version matches", :readline, :jruby do
+ it "starts IRB with the default group loaded when ruby version matches", :readline, :jruby_only do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -974,7 +993,7 @@ G
#{ruby_version_incorrect}
G
- bundle "console", :raise_on_error => false
+ bundle "console", raise_on_error: false
should_be_ruby_version_incorrect
end
@@ -988,11 +1007,11 @@ G
#{engine_incorrect}
G
- bundle "console", :raise_on_error => false
+ bundle "console", raise_on_error: false
should_be_engine_incorrect
end
- it "fails when engine version doesn't match", :jruby do
+ it "fails when engine version doesn't match", :jruby_only do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -1002,7 +1021,7 @@ G
#{engine_version_incorrect}
G
- bundle "console", :raise_on_error => false
+ bundle "console", raise_on_error: false
should_be_engine_version_incorrect
end
@@ -1016,7 +1035,7 @@ G
#{patchlevel_incorrect}
G
- bundle "console", :raise_on_error => false
+ bundle "console", raise_on_error: false
should_be_patchlevel_incorrect
end
end
@@ -1047,7 +1066,7 @@ G
expect(bundled_app_lock).to exist
end
- it "makes a Gemfile.lock if setup succeeds for any engine", :jruby do
+ it "makes a Gemfile.lock if setup succeeds for any engine", :jruby_only do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "yard"
@@ -1063,7 +1082,7 @@ G
end
it "fails when ruby version doesn't match" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem "yard"
gem "rack"
@@ -1073,14 +1092,14 @@ G
FileUtils.rm(bundled_app_lock)
- ruby "require 'bundler/setup'", :env => { "BUNDLER_VERSION" => Bundler::VERSION }, :raise_on_error => false
+ ruby "require 'bundler/setup'", env: { "BUNDLER_VERSION" => Bundler::VERSION }, raise_on_error: false
expect(bundled_app_lock).not_to exist
should_be_ruby_version_incorrect
end
it "fails when engine doesn't match" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem "yard"
gem "rack"
@@ -1090,14 +1109,14 @@ G
FileUtils.rm(bundled_app_lock)
- ruby "require 'bundler/setup'", :env => { "BUNDLER_VERSION" => Bundler::VERSION }, :raise_on_error => false
+ ruby "require 'bundler/setup'", env: { "BUNDLER_VERSION" => Bundler::VERSION }, raise_on_error: false
expect(bundled_app_lock).not_to exist
should_be_engine_incorrect
end
- it "fails when engine version doesn't match", :jruby do
- install_gemfile <<-G, :raise_on_error => false
+ it "fails when engine version doesn't match", :jruby_only do
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem "yard"
gem "rack"
@@ -1107,14 +1126,14 @@ G
FileUtils.rm(bundled_app_lock)
- ruby "require 'bundler/setup'", :env => { "BUNDLER_VERSION" => Bundler::VERSION }, :raise_on_error => false
+ ruby "require 'bundler/setup'", env: { "BUNDLER_VERSION" => Bundler::VERSION }, raise_on_error: false
expect(bundled_app_lock).not_to exist
should_be_engine_version_incorrect
end
it "fails when patchlevel doesn't match" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem "yard"
gem "rack"
@@ -1124,7 +1143,7 @@ G
FileUtils.rm(bundled_app_lock)
- ruby "require 'bundler/setup'", :env => { "BUNDLER_VERSION" => Bundler::VERSION }, :raise_on_error => false
+ ruby "require 'bundler/setup'", env: { "BUNDLER_VERSION" => Bundler::VERSION }, raise_on_error: false
expect(bundled_app_lock).not_to exist
should_be_patchlevel_incorrect
@@ -1134,7 +1153,7 @@ G
context "bundle outdated" do
before do
build_repo2 do
- build_git "foo", :path => lib_path("foo")
+ build_git "foo", path: lib_path("foo")
end
install_gemfile <<-G
@@ -1147,7 +1166,7 @@ G
it "returns list of outdated gems when the ruby version matches" do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", :path => lib_path("foo")
+ update_git "foo", path: lib_path("foo")
end
gemfile <<-G
@@ -1158,7 +1177,7 @@ G
#{ruby_version_correct}
G
- bundle "outdated", :raise_on_error => false
+ bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
Gem Current Latest Requested Groups
@@ -1169,11 +1188,11 @@ G
expect(out).to match(Regexp.new(expected_output))
end
- it "returns list of outdated gems when the ruby version matches for any engine", :jruby do
+ it "returns list of outdated gems when the ruby version matches for any engine", :jruby_only do
bundle :install
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", :path => lib_path("foo")
+ update_git "foo", path: lib_path("foo")
end
gemfile <<-G
@@ -1184,7 +1203,7 @@ G
#{ruby_version_correct_engineless}
G
- bundle "outdated", :raise_on_error => false
+ bundle "outdated", raise_on_error: false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
Gem Current Latest Requested Groups
@@ -1198,7 +1217,7 @@ G
it "fails when the ruby version doesn't match" do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", :path => lib_path("foo")
+ update_git "foo", path: lib_path("foo")
end
gemfile <<-G
@@ -1209,14 +1228,14 @@ G
#{ruby_version_incorrect}
G
- bundle "outdated", :raise_on_error => false
+ bundle "outdated", raise_on_error: false
should_be_ruby_version_incorrect
end
it "fails when the engine doesn't match" do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", :path => lib_path("foo")
+ update_git "foo", path: lib_path("foo")
end
gemfile <<-G
@@ -1227,14 +1246,14 @@ G
#{engine_incorrect}
G
- bundle "outdated", :raise_on_error => false
+ bundle "outdated", raise_on_error: false
should_be_engine_incorrect
end
- it "fails when the engine version doesn't match", :jruby do
+ it "fails when the engine version doesn't match", :jruby_only do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", :path => lib_path("foo")
+ update_git "foo", path: lib_path("foo")
end
gemfile <<-G
@@ -1245,14 +1264,14 @@ G
#{engine_version_incorrect}
G
- bundle "outdated", :raise_on_error => false
+ bundle "outdated", raise_on_error: false
should_be_engine_version_incorrect
end
- it "fails when the patchlevel doesn't match", :jruby do
+ it "fails when the patchlevel doesn't match", :jruby_only do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", :path => lib_path("foo")
+ update_git "foo", path: lib_path("foo")
end
gemfile <<-G
@@ -1263,14 +1282,14 @@ G
#{patchlevel_incorrect}
G
- bundle "outdated", :raise_on_error => false
+ bundle "outdated", raise_on_error: false
should_be_patchlevel_incorrect
end
- it "fails when the patchlevel is a fixnum", :jruby do
+ it "fails when the patchlevel is a fixnum", :jruby_only do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", :path => lib_path("foo")
+ update_git "foo", path: lib_path("foo")
end
gemfile <<-G
@@ -1281,7 +1300,7 @@ G
#{patchlevel_fixnum}
G
- bundle "outdated", :raise_on_error => false
+ bundle "outdated", raise_on_error: false
should_be_patchlevel_fixnum
end
end
diff --git a/spec/bundler/commands/post_bundle_message_spec.rb b/spec/bundler/commands/post_bundle_message_spec.rb
index 72f8020b44..07fd5a79e9 100644
--- a/spec/bundler/commands/post_bundle_message_spec.rb
+++ b/spec/bundler/commands/post_bundle_message_spec.rb
@@ -114,14 +114,13 @@ RSpec.describe "post bundle message" do
end
it "should report a helpful error message" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem "rack"
gem "not-a-gem", :group => :development
G
expect(err).to include <<-EOS.strip
-Could not find gem 'not-a-gem' in rubygems repository #{file_uri_for(gem_repo1)}/ or installed locally.
-The source does not contain any versions of 'not-a-gem'
+Could not find gem 'not-a-gem' in rubygems repository #{file_uri_for(gem_repo1)}/, cached gems or installed locally.
EOS
end
@@ -132,7 +131,7 @@ The source does not contain any versions of 'not-a-gem'
G
bundle :cache
expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem "rack"
gem "not-a-gem", :group => :development
@@ -143,7 +142,7 @@ The source does not contain any versions of 'not-a-gem'
end
end
- describe "for second bundle install run", :bundler => "< 3" do
+ describe "for second bundle install run", bundler: "< 3" do
it "without any options" do
2.times { bundle :install }
expect(out).to include(bundle_show_message)
@@ -180,25 +179,25 @@ The source does not contain any versions of 'not-a-gem'
describe "for bundle update" do
it "shows proper messages according to the configured groups" do
- bundle :update, :all => true
+ bundle :update, all: true
expect(out).not_to include("Gems in the groups")
expect(out).to include(bundle_updated_message)
bundle "config set --local without emo"
bundle :install
- bundle :update, :all => true
+ bundle :update, all: true
expect(out).to include("Gems in the group 'emo' were not updated")
expect(out).to include(bundle_updated_message)
bundle "config set --local without emo test"
bundle :install
- bundle :update, :all => true
+ bundle :update, all: true
expect(out).to include("Gems in the groups 'emo' and 'test' were not updated")
expect(out).to include(bundle_updated_message)
bundle "config set --local without emo obama test"
bundle :install
- bundle :update, :all => true
+ bundle :update, all: true
expect(out).to include("Gems in the groups 'emo', 'obama' and 'test' were not updated")
expect(out).to include(bundle_updated_message)
end
diff --git a/spec/bundler/commands/pristine_spec.rb b/spec/bundler/commands/pristine_spec.rb
index 2f730bd4e2..1aec37f850 100644
--- a/spec/bundler/commands/pristine_spec.rb
+++ b/spec/bundler/commands/pristine_spec.rb
@@ -2,9 +2,9 @@
require "bundler/vendored_fileutils"
-RSpec.describe "bundle pristine", :ruby_repo do
+RSpec.describe "bundle pristine" do
before :each do
- build_lib "baz", :path => bundled_app do |s|
+ build_lib "baz", path: bundled_app do |s|
s.version = "1.0.0"
s.add_development_dependency "baz-dev", "=1.0.0"
end
@@ -13,16 +13,16 @@ RSpec.describe "bundle pristine", :ruby_repo do
build_gem "weakling"
build_gem "baz-dev", "1.0.0"
build_gem "very_simple_binary", &:add_c_extension
- build_git "foo", :path => lib_path("foo")
- build_git "git_with_ext", :path => lib_path("git_with_ext"), &:add_c_extension
- build_lib "bar", :path => lib_path("bar")
+ build_git "foo", path: lib_path("foo")
+ build_git "git_with_ext", path: lib_path("git_with_ext"), &:add_c_extension
+ build_lib "bar", path: lib_path("bar")
end
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
gem "weakling"
gem "very_simple_binary"
- gem "foo", :git => "#{lib_path("foo")}", :branch => "master"
+ gem "foo", :git => "#{lib_path("foo")}", :branch => "main"
gem "git_with_ext", :git => "#{lib_path("git_with_ext")}"
gem "bar", :path => "#{lib_path("bar")}"
@@ -164,7 +164,7 @@ RSpec.describe "bundle pristine", :ruby_repo do
end
it "raises when one of them is not in the lockfile" do
- bundle "pristine abcabcabc", :raise_on_error => false
+ bundle "pristine abcabcabc", raise_on_error: false
expect(err).to include("Could not find gem 'abcabcabc'.")
end
end
@@ -181,8 +181,8 @@ RSpec.describe "bundle pristine", :ruby_repo do
bundle "pristine"
makefile_contents = File.read(c_ext_dir.join("Makefile").to_s)
- expect(makefile_contents).to match(/libpath =.*#{c_ext_dir}/)
- expect(makefile_contents).to match(/LIBPATH =.*-L#{c_ext_dir}/)
+ expect(makefile_contents).to match(/libpath =.*#{Regexp.escape(c_ext_dir.to_s)}/)
+ expect(makefile_contents).to match(/LIBPATH =.*-L#{Regexp.escape(c_ext_dir.to_s)}/)
end
end
@@ -198,14 +198,14 @@ RSpec.describe "bundle pristine", :ruby_repo do
bundle "pristine"
makefile_contents = File.read(c_ext_dir.join("Makefile").to_s)
- expect(makefile_contents).to match(/libpath =.*#{c_ext_dir}/)
- expect(makefile_contents).to match(/LIBPATH =.*-L#{c_ext_dir}/)
+ expect(makefile_contents).to match(/libpath =.*#{Regexp.escape(c_ext_dir.to_s)}/)
+ expect(makefile_contents).to match(/LIBPATH =.*-L#{Regexp.escape(c_ext_dir.to_s)}/)
end
end
context "when BUNDLE_GEMFILE doesn't exist" do
before do
- bundle "pristine", :env => { "BUNDLE_GEMFILE" => "does/not/exist" }, :raise_on_error => false
+ bundle "pristine", env: { "BUNDLE_GEMFILE" => "does/not/exist" }, raise_on_error: false
end
it "shows a meaningful error" do
diff --git a/spec/bundler/commands/remove_spec.rb b/spec/bundler/commands/remove_spec.rb
index 170545f80c..197fcde091 100644
--- a/spec/bundler/commands/remove_spec.rb
+++ b/spec/bundler/commands/remove_spec.rb
@@ -7,13 +7,43 @@ RSpec.describe "bundle remove" do
source "#{file_uri_for(gem_repo1)}"
G
- bundle "remove", :raise_on_error => false
+ bundle "remove", raise_on_error: false
expect(err).to include("Please specify gems to remove.")
end
end
- context "when --install flag is specified" do
+ context "after 'bundle install' is run" do
+ describe "running 'bundle remove GEM_NAME'" do
+ it "removes it from the lockfile" do
+ rack_dep = <<~L
+
+ DEPENDENCIES
+ rack
+
+ L
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+
+ gem "rack"
+ G
+
+ bundle "install"
+
+ expect(lockfile).to include(rack_dep)
+
+ bundle "remove rack"
+
+ expect(gemfile).to eq <<~G
+ source "#{file_uri_for(gem_repo1)}"
+ G
+ expect(lockfile).to_not include(rack_dep)
+ end
+ end
+ end
+
+ context "when --install flag is specified", bundler: "< 3" do
it "removes gems from .bundle" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -40,27 +70,30 @@ RSpec.describe "bundle remove" do
bundle "remove rack"
expect(out).to include("rack was removed.")
- gemfile_should_be <<-G
+ expect(the_bundle).to_not include_gems "rack"
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
G
end
context "when gem is specified in multiple lines" do
it "shows success for removed gem" do
+ build_git "rack"
+
gemfile <<-G
source '#{file_uri_for(gem_repo1)}'
gem 'git'
gem 'rack',
- git: 'https://github.com/rack/rack',
- branch: 'master'
+ git: "#{lib_path("rack-1.0")}",
+ branch: 'main'
gem 'nokogiri'
G
bundle "remove rack"
expect(out).to include("rack was removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source '#{file_uri_for(gem_repo1)}'
gem 'git'
@@ -76,7 +109,7 @@ RSpec.describe "bundle remove" do
source "#{file_uri_for(gem_repo1)}"
G
- bundle "remove rack", :raise_on_error => false
+ bundle "remove rack", raise_on_error: false
expect(err).to include("`rack` is not specified in #{bundled_app_gemfile} so it could not be removed.")
end
@@ -97,7 +130,7 @@ RSpec.describe "bundle remove" do
expect(out).to include("rack was removed.")
expect(out).to include("rails was removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
G
end
@@ -113,10 +146,10 @@ RSpec.describe "bundle remove" do
gem "rspec"
G
- bundle "remove rails rack minitest", :raise_on_error => false
+ bundle "remove rails rack minitest", raise_on_error: false
expect(err).to include("`rack` is not specified in #{bundled_app_gemfile} so it could not be removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
gem "rails"
@@ -138,7 +171,7 @@ RSpec.describe "bundle remove" do
bundle "remove rack"
expect(out).to include("rack was removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
G
end
@@ -158,7 +191,7 @@ RSpec.describe "bundle remove" do
bundle "remove rspec"
expect(out).to include("rspec was removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
G
end
@@ -178,7 +211,7 @@ RSpec.describe "bundle remove" do
bundle "remove rack"
expect(out).to include("rack was removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
group :test do
@@ -204,7 +237,7 @@ RSpec.describe "bundle remove" do
bundle "remove rspec"
expect(out).to include("rspec was removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
G
end
@@ -223,7 +256,7 @@ RSpec.describe "bundle remove" do
bundle "remove rspec"
expect(out).to include("rspec was removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
G
end
@@ -246,7 +279,7 @@ RSpec.describe "bundle remove" do
bundle "remove rspec"
expect(out).to include("rspec was removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
G
end
@@ -269,7 +302,7 @@ RSpec.describe "bundle remove" do
bundle "remove rspec"
expect(out).to include("rspec was removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
G
end
@@ -292,7 +325,7 @@ RSpec.describe "bundle remove" do
bundle "remove rspec"
expect(out).to include("rspec was removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
group :test do
@@ -319,7 +352,7 @@ RSpec.describe "bundle remove" do
bundle "remove rspec"
expect(out).to include("rspec was removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
group :test do
@@ -340,10 +373,10 @@ RSpec.describe "bundle remove" do
gem "rack"; gem "rails"
G
- bundle "remove rails", :raise_on_error => false
+ bundle "remove rails", raise_on_error: false
expect(err).to include("Gems could not be removed. rack (>= 0) would also have been removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
gem "rack"; gem "rails"
G
@@ -352,7 +385,7 @@ RSpec.describe "bundle remove" do
context "when some gems could not be removed" do
it "shows warning for gems not removed and success for those removed" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem"rack"
gem"rspec"
@@ -365,7 +398,7 @@ RSpec.describe "bundle remove" do
expect(out).to include("rails was removed.")
expect(out).to include("minitest was removed.")
expect(out).to include("rack, rspec could not be removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
gem"rack"
gem"rspec"
@@ -397,7 +430,7 @@ RSpec.describe "bundle remove" do
bundle "remove rspec"
expect(out).to include("rspec was removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -458,7 +491,7 @@ RSpec.describe "bundle remove" do
eval_gemfile "Gemfile-other"
G
- bundle "remove rack", :raise_on_error => false
+ bundle "remove rack", raise_on_error: false
expect(err).to include("`rack` is not specified in #{bundled_app_gemfile} so it could not be removed.")
end
@@ -477,11 +510,11 @@ RSpec.describe "bundle remove" do
gem "rack"
G
- bundle "remove rack", :raise_on_error => false
+ bundle "remove rack", raise_on_error: false
expect(out).to include("rack was removed.")
expect(err).to include("`rack` is not specified in #{bundled_app("Gemfile-other")} so it could not be removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
@@ -489,7 +522,7 @@ RSpec.describe "bundle remove" do
end
end
- context "when gems can not be removed from other gemfile" do
+ context "when gems cannot be removed from other gemfile" do
it "shows error" do
create_file "Gemfile-other", <<-G
gem "rails"; gem "rack"
@@ -502,11 +535,11 @@ RSpec.describe "bundle remove" do
gem "rack"
G
- bundle "remove rack", :raise_on_error => false
+ bundle "remove rack", raise_on_error: false
expect(out).to include("rack was removed.")
expect(err).to include("Gems could not be removed. rails (>= 0) would also have been removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
@@ -527,11 +560,11 @@ RSpec.describe "bundle remove" do
gem "rails"; gem "rack"
G
- bundle "remove rack", :raise_on_error => false
+ bundle "remove rack", raise_on_error: false
expect(err).to include("Gems could not be removed. rails (>= 0) would also have been removed.")
expect(bundled_app("Gemfile-other").read).to include("gem \"rack\"")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
@@ -541,7 +574,7 @@ RSpec.describe "bundle remove" do
end
context "when gem present in gemfiles but could not be removed from one from one of them" do
- it "removes gem which can be removed and shows warning for file from which it can not be removed" do
+ it "removes gem which can be removed and shows warning for file from which it cannot be removed" do
create_file "Gemfile-other", <<-G
gem "rack"
G
@@ -574,7 +607,7 @@ RSpec.describe "bundle remove" do
bundle "remove rack"
expect(out).to include("rack was removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
G
end
@@ -593,7 +626,7 @@ RSpec.describe "bundle remove" do
bundle "remove rack"
expect(out).to include("rack was removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
G
end
@@ -601,7 +634,7 @@ RSpec.describe "bundle remove" do
context "with gemspec" do
it "should not remove the gem" do
- build_lib("foo", :path => tmp.join("foo")) do |s|
+ build_lib("foo", path: tmp.join("foo")) do |s|
s.write("foo.gemspec", "")
s.add_dependency "rack"
end
@@ -630,7 +663,7 @@ RSpec.describe "bundle remove" do
bundle "remove rack"
expect(out).to include("rack was removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
# gem "rack" might be used in the future
@@ -649,7 +682,7 @@ RSpec.describe "bundle remove" do
bundle "remove rack"
expect(out).to include("rack was removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
G
end
@@ -668,7 +701,7 @@ RSpec.describe "bundle remove" do
expect(out).to_not include("puma was removed.")
expect(out).to include("rack was removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
gem "puma" # implements interface provided by gem "rack"
G
@@ -688,7 +721,7 @@ RSpec.describe "bundle remove" do
expect(out).to include("puma was removed.")
expect(out).to_not include("rack was removed.")
- gemfile_should_be <<-G
+ expect(gemfile).to eq <<~G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
diff --git a/spec/bundler/commands/show_spec.rb b/spec/bundler/commands/show_spec.rb
index 2adb121616..2b6d4d2d00 100644
--- a/spec/bundler/commands/show_spec.rb
+++ b/spec/bundler/commands/show_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe "bundle show", :bundler => "< 3" do
+RSpec.describe "bundle show", bundler: "< 3" do
context "with a standard Gemfile" do
before :each do
install_gemfile <<-G
@@ -50,14 +50,14 @@ RSpec.describe "bundle show", :bundler => "< 3" do
end
it "complains if gem not in bundle" do
- bundle "show missing", :raise_on_error => false
+ bundle "show missing", raise_on_error: false
expect(err).to match(/could not find gem 'missing'/i)
end
it "prints path of all gems in bundle sorted by name" do
bundle "show --paths"
- expect(out).to include(default_bundle_path("gems", "rake-13.0.1").to_s)
+ expect(out).to include(default_bundle_path("gems", "rake-#{rake_version}").to_s)
expect(out).to include(default_bundle_path("gems", "rails-2.3.2").to_s)
# Gem names are the last component of their path.
@@ -100,11 +100,11 @@ RSpec.describe "bundle show", :bundler => "< 3" do
expect(the_bundle).to include_gems "foo 1.0"
bundle :show
- expect(out).to include("foo (1.0 #{@git.ref_for("master", 6)}")
+ expect(out).to include("foo (1.0 #{@git.ref_for("main", 6)}")
end
- it "prints out branch names other than master" do
- update_git "foo", :branch => "omg" do |s|
+ it "prints out branch names other than main" do
+ update_git "foo", branch: "omg" do |s|
s.write "lib/foo.rb", "FOO = '1.0.omg'"
end
@revision = revision_for(lib_path("foo-1.0"))[0...6]
@@ -129,7 +129,7 @@ RSpec.describe "bundle show", :bundler => "< 3" do
end
it "handles when a version is a '-' prerelease" do
- @git = build_git("foo", "1.0.0-beta.1", :path => lib_path("foo"))
+ @git = build_git("foo", "1.0.0-beta.1", path: lib_path("foo"))
install_gemfile <<-G
gem "foo", "1.0.0-beta.1", :git => "#{lib_path("foo")}"
G
@@ -142,13 +142,13 @@ RSpec.describe "bundle show", :bundler => "< 3" do
context "in a fresh gem in a blank git repo" do
before :each do
- build_git "foo", :path => lib_path("foo")
+ build_git "foo", path: lib_path("foo")
File.open(lib_path("foo/Gemfile"), "w") {|f| f.puts "gemspec" }
- sys_exec "rm -rf .git && git init", :dir => lib_path("foo")
+ sys_exec "rm -rf .git && git init", dir: lib_path("foo")
end
it "does not output git errors" do
- bundle :show, :dir => lib_path("foo")
+ bundle :show, dir: lib_path("foo")
expect(err_without_deprecations).to be_empty
end
end
@@ -173,7 +173,7 @@ RSpec.describe "bundle show", :bundler => "< 3" do
G
bundle "show rac"
- expect(out).to match(/\A1 : rack\n2 : rack-obama\n0 : - exit -(\n>)?\z/)
+ expect(out).to match(/\A1 : rack\n2 : rack-obama\n0 : - exit -(\n>.*)?\z/)
end
end
@@ -186,7 +186,7 @@ RSpec.describe "bundle show", :bundler => "< 3" do
invalid_regexp = "[]"
- bundle "show #{invalid_regexp}", :raise_on_error => false
+ bundle "show #{invalid_regexp}", raise_on_error: false
expect(err).to include("Could not find gem '#{invalid_regexp}'.")
end
end
@@ -219,6 +219,6 @@ RSpec.describe "bundle show", :bundler => "< 3" do
end
end
-RSpec.describe "bundle show", :bundler => "3" do
+RSpec.describe "bundle show", bundler: "3" do
pending "shows a friendly error about the command removal"
end
diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb
index 14fe3e245b..cfb86ebb54 100644
--- a/spec/bundler/commands/update_spec.rb
+++ b/spec/bundler/commands/update_spec.rb
@@ -34,7 +34,7 @@ RSpec.describe "bundle update" do
gem "rack-obama"
exit!
G
- bundle "update", :raise_on_error => false
+ bundle "update", raise_on_error: false
expect(bundled_app_lock).to exist
end
end
@@ -60,7 +60,7 @@ RSpec.describe "bundle update" do
build_gem "activesupport", "3.0"
end
- bundle "update", :all => true
+ bundle "update", all: true
expect(out).to include("Bundle updated!")
expect(the_bundle).to include_gems "rack 1.2", "rack-obama 1.0", "activesupport 3.0"
end
@@ -74,7 +74,7 @@ RSpec.describe "bundle update" do
gem "rack-obama"
exit!
G
- bundle "update", :all => true, :raise_on_error => false
+ bundle "update", all: true, raise_on_error: false
expect(bundled_app_lock).to exist
end
end
@@ -86,7 +86,7 @@ RSpec.describe "bundle update" do
gem "rack", "1.0"
G
- bundle "update --gemfile OmgFile", :all => true
+ bundle "update --gemfile OmgFile", all: true
expect(bundled_app("OmgFile.lock")).to exist
end
@@ -97,13 +97,13 @@ RSpec.describe "bundle update" do
it "errors when passed nothing" do
install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
- bundle :update, :raise_on_error => false
+ bundle :update, raise_on_error: false
expect(err).to eq("To update everything, pass the `--all` flag.")
end
it "errors when passed --all and another option" do
install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
- bundle "update --all foo", :raise_on_error => false
+ bundle "update --all foo", raise_on_error: false
expect(err).to eq("Cannot specify --all along with specific options.")
end
@@ -171,11 +171,11 @@ RSpec.describe "bundle update" do
end
it "should inform the user" do
- bundle "update halting-problem-solver", :raise_on_error => false
+ bundle "update halting-problem-solver", raise_on_error: false
expect(err).to include "Could not find gem 'halting-problem-solver'"
end
it "should suggest alternatives" do
- bundle "update platformspecific", :raise_on_error => false
+ bundle "update platformspecific", raise_on_error: false
expect(err).to include "Did you mean platform_specific?"
end
end
@@ -236,7 +236,7 @@ RSpec.describe "bundle update" do
end
end
- bundle "update", :all => true
+ bundle "update", all: true
expect(the_bundle).to include_gems("slim 3.0.9", "slim-rails 3.1.3", "slim_lint 0.16.1")
end
@@ -275,6 +275,11 @@ RSpec.describe "bundle update" do
gem "countries"
G
+ checksums = checksums_section_when_existing do |c|
+ c.checksum(gem_repo4, "countries", "3.1.0")
+ c.checksum(gem_repo4, "country_select", "5.1.0")
+ end
+
lockfile <<~L
GEM
remote: #{file_uri_for(gem_repo4)}/
@@ -284,23 +289,145 @@ RSpec.describe "bundle update" do
countries (~> 3.0)
PLATFORMS
- #{specific_local_platform}
+ #{local_platform}
DEPENDENCIES
countries
country_select
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
previous_lockfile = lockfile
- bundle "lock --update"
+ bundle "lock --update", env: { "DEBUG" => "1" }, verbose: true
expect(lockfile).to eq(previous_lockfile)
end
+ it "does not downgrade direct dependencies when run with --conservative" do
+ build_repo4 do
+ build_gem "oauth2", "2.0.6" do |s|
+ s.add_dependency "faraday", ">= 0.17.3", "< 3.0"
+ end
+
+ build_gem "oauth2", "1.4.10" do |s|
+ s.add_dependency "faraday", ">= 0.17.3", "< 3.0"
+ s.add_dependency "multi_json", "~> 1.3"
+ end
+
+ build_gem "faraday", "2.5.2"
+
+ build_gem "multi_json", "1.15.0"
+
+ build_gem "quickbooks-ruby", "1.0.19" do |s|
+ s.add_dependency "oauth2", "~> 1.4"
+ end
+
+ build_gem "quickbooks-ruby", "0.1.9" do |s|
+ s.add_dependency "oauth2"
+ end
+ end
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "oauth2"
+ gem "quickbooks-ruby"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ faraday (2.5.2)
+ multi_json (1.15.0)
+ oauth2 (1.4.10)
+ faraday (>= 0.17.3, < 3.0)
+ multi_json (~> 1.3)
+ quickbooks-ruby (1.0.19)
+ oauth2 (~> 1.4)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ oauth2
+ quickbooks-ruby
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "update --conservative --verbose"
+
+ expect(out).not_to include("Installing quickbooks-ruby 0.1.9")
+ expect(out).to include("Installing quickbooks-ruby 1.0.19").and include("Installing oauth2 1.4.10")
+ end
+
+ it "does not downgrade direct dependencies when using gemspec sources" do
+ create_file("rails.gemspec", <<-G)
+ Gem::Specification.new do |gem|
+ gem.name = "rails"
+ gem.version = "7.1.0.alpha"
+ gem.author = "DHH"
+ gem.summary = "Full-stack web application framework."
+ end
+ G
+
+ build_repo4 do
+ build_gem "rake", "12.3.3"
+ build_gem "rake", "13.0.6"
+
+ build_gem "sneakers", "2.11.0" do |s|
+ s.add_dependency "rake"
+ end
+
+ build_gem "sneakers", "2.12.0" do |s|
+ s.add_dependency "rake", "~> 12.3"
+ end
+ end
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gemspec
+
+ gem "rake"
+ gem "sneakers"
+ G
+
+ lockfile <<~L
+ PATH
+ remote: .
+ specs:
+
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ rake (13.0.6)
+ sneakers (2.11.0)
+ rake
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ rake
+ sneakers
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "update --verbose"
+
+ expect(out).not_to include("Installing sneakers 2.12.0")
+ expect(out).not_to include("Installing rake 12.3.3")
+ expect(out).to include("Installing sneakers 2.11.0").and include("Installing rake 13.0.6")
+ end
+
it "does not downgrade indirect dependencies unnecessarily" do
build_repo4 do
build_gem "a" do |s|
@@ -312,7 +439,7 @@ RSpec.describe "bundle update" do
build_gem "c", "2.0"
end
- install_gemfile <<-G, :verbose => true
+ install_gemfile <<-G, verbose: true
source "#{file_uri_for(gem_repo4)}"
gem "a"
G
@@ -325,7 +452,7 @@ RSpec.describe "bundle update" do
end
end
- bundle "update", :all => true, :verbose => true
+ bundle "update", all: true, verbose: true
expect(the_bundle).to include_gems("a 1.0", "b 1.0", "c 2.0")
end
@@ -354,18 +481,112 @@ RSpec.describe "bundle update" do
expect(the_bundle).to include_gems("a 1.0", "b 1.0")
end
+
+ it "should still downgrade if forced by the Gemfile, when transitive dependencies also need downgrade" do
+ build_repo4 do
+ build_gem "activesupport", "6.1.4.1" do |s|
+ s.add_dependency "tzinfo", "~> 2.0"
+ end
+
+ build_gem "activesupport", "6.0.4.1" do |s|
+ s.add_dependency "tzinfo", "~> 1.1"
+ end
+
+ build_gem "tzinfo", "2.0.4"
+ build_gem "tzinfo", "1.2.9"
+ end
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "activesupport", "~> 6.1.0"
+ G
+
+ expect(the_bundle).to include_gems("activesupport 6.1.4.1", "tzinfo 2.0.4")
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "activesupport", "~> 6.0.0"
+ G
+
+ original_lockfile = lockfile
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "activesupport", "6.0.4.1"
+ c.checksum gem_repo4, "tzinfo", "1.2.9"
+ end
+
+ expected_lockfile = <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ activesupport (6.0.4.1)
+ tzinfo (~> 1.1)
+ tzinfo (1.2.9)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ activesupport (~> 6.0.0)
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "update activesupport"
+ expect(the_bundle).to include_gems("activesupport 6.0.4.1", "tzinfo 1.2.9")
+ expect(lockfile).to eq(expected_lockfile)
+
+ # needed because regressing to versions already present on the system
+ # won't add a checksum
+ expected_lockfile = remove_checksums_from_lockfile(expected_lockfile)
+
+ lockfile original_lockfile
+ bundle "update"
+ expect(the_bundle).to include_gems("activesupport 6.0.4.1", "tzinfo 1.2.9")
+ expect(lockfile).to eq(expected_lockfile)
+
+ lockfile original_lockfile
+ bundle "lock --update"
+ expect(the_bundle).to include_gems("activesupport 6.0.4.1", "tzinfo 1.2.9")
+ expect(lockfile).to eq(expected_lockfile)
+ end
end
describe "with --local option" do
before do
build_repo2
- install_gemfile <<-G
+ gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
gem "rack-obama"
gem "platform_specific"
G
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo2)}/
+ specs:
+ activesupport (2.3.5)
+ platform_specific (1.0-#{local_platform})
+ rack (1.0.0)
+ rack-obama (1.0)
+ rack
+
+ PLATFORMS
+ #{local_platform}
+
+ DEPENDENCIES
+ activesupport
+ platform_specific
+ rack-obama
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install"
end
it "doesn't hit repo2" do
@@ -418,7 +639,7 @@ RSpec.describe "bundle update" do
context "when there is a source with the same name as a gem in a group" do
before do
- build_git "foo", :path => lib_path("activesupport")
+ build_git "foo", path: lib_path("activesupport")
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
gem "activesupport", :group => :development
@@ -428,7 +649,7 @@ RSpec.describe "bundle update" do
it "should not update the gems from that source" do
update_repo2 { build_gem "activesupport", "3.0" }
- update_git "foo", "2.0", :path => lib_path("activesupport")
+ update_git "foo", "2.0", path: lib_path("activesupport")
bundle "update --group development"
expect(the_bundle).to include_gems "activesupport 3.0"
@@ -470,27 +691,33 @@ RSpec.describe "bundle update" do
G
end
- it "should fail loudly", :bundler => "< 3" do
+ it "should fail loudly", bundler: "< 3" do
bundle "install --deployment"
- bundle "update", :all => true, :raise_on_error => false
+ bundle "update", all: true, raise_on_error: false
expect(last_command).to be_failure
- expect(err).to match(/You are trying to install in deployment mode after changing.your Gemfile/m)
- expect(err).to match(/freeze \nby running `bundle config unset deployment`./m)
+ expect(err).to match(/Bundler is unlocking, but the lockfile can't be updated because frozen mode is set/)
+ expect(err).to match(/freeze by running `bundle config set frozen false`./)
end
- it "should suggest different command when frozen is set globally", :bundler => "< 3" do
+ it "should fail loudly when frozen is set globally" do
bundle "config set --global frozen 1"
- bundle "update", :all => true, :raise_on_error => false
- expect(err).to match(/You are trying to install in deployment mode after changing.your Gemfile/m).
- and match(/freeze \nby running `bundle config unset frozen`./m)
+ bundle "update", all: true, raise_on_error: false
+ expect(err).to match(/Bundler is unlocking, but the lockfile can't be updated because frozen mode is set/).
+ and match(/freeze by running `bundle config set frozen false`./)
end
- it "should suggest different command when frozen is set globally", :bundler => "3" do
+ it "should fail loudly when deployment is set globally" do
bundle "config set --global deployment true"
- bundle "update", :all => true, :raise_on_error => false
- expect(err).to match(/You are trying to install in deployment mode after changing.your Gemfile/m).
- and match(/freeze \nby running `bundle config unset deployment`./m)
+ bundle "update", all: true, raise_on_error: false
+ expect(err).to match(/Bundler is unlocking, but the lockfile can't be updated because frozen mode is set/).
+ and match(/freeze by running `bundle config set frozen false`./)
+ end
+
+ it "should not suggest any command to unfreeze bundler if frozen is set through ENV" do
+ bundle "update", all: true, raise_on_error: false, env: { "BUNDLE_FROZEN" => "true" }
+ expect(err).to match(/Bundler is unlocking, but the lockfile can't be updated because frozen mode is set/)
+ expect(err).not_to match(/by running/)
end
end
@@ -583,7 +810,7 @@ RSpec.describe "bundle update" do
end
end
- it "shows the previous version of the gem when updated from rubygems source", :bundler => "< 3" do
+ it "shows the previous version of the gem when updated from rubygems source" do
build_repo2
install_gemfile <<-G
@@ -591,43 +818,39 @@ RSpec.describe "bundle update" do
gem "activesupport"
G
- bundle "update", :all => true
+ bundle "update", all: true, verbose: true
expect(out).to include("Using activesupport 2.3.5")
update_repo2 do
build_gem "activesupport", "3.0"
end
- bundle "update", :all => true
+ 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
+ it "only prints `Using` for versions that have changed" do
+ build_repo4 do
+ build_gem "bar"
+ build_gem "foo"
+ end
- bundle "update", :all => true
- expect(out).to match(/Resolving dependencies\.\.\.\.*\nBundle updated!/)
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "bar"
+ gem "foo"
+ G
- update_repo4 do
- build_gem "foo", "2.0"
- end
+ bundle "update", all: true
+ expect(out).to match(/Resolving dependencies\.\.\.\.*\nBundle updated!/)
- 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/)
+ 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
it "shows error message when Gemfile.lock is not preset and gem is specified" do
@@ -636,12 +859,96 @@ RSpec.describe "bundle update" do
gem "activesupport"
G
- bundle "update nonexisting", :raise_on_error => false
+ 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
+ context "with multiple sources and caching enabled" do
+ before do
+ build_repo2 do
+ build_gem "rack", "1.0.0"
+
+ build_gem "request_store", "1.0.0" do |s|
+ s.add_dependency "rack", "1.0.0"
+ end
+ end
+
+ build_repo4 do
+ # set up repo with no gems
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo2)}"
+
+ gem "request_store"
+
+ source "#{file_uri_for(gem_repo4)}" do
+ end
+ G
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo2)}/
+ specs:
+ rack (1.0.0)
+ request_store (1.0.0)
+ rack (= 1.0.0)
+
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+
+ PLATFORMS
+ #{local_platform}
+
+ DEPENDENCIES
+ request_store
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "works" do
+ bundle :install
+ bundle :cache
+
+ update_repo2 do
+ build_gem "request_store", "1.1.0" do |s|
+ s.add_dependency "rack", "1.0.0"
+ end
+ end
+
+ bundle "update request_store"
+
+ expect(out).to include("Bundle updated!")
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo2)}/
+ specs:
+ rack (1.0.0)
+ request_store (1.1.0)
+ rack (= 1.0.0)
+
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+
+ PLATFORMS
+ #{local_platform}
+
+ DEPENDENCIES
+ request_store
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ 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"
@@ -682,7 +989,7 @@ RSpec.describe "bundle update" do
vcr (6.0.0)
PLATFORMS
- #{specific_local_platform}
+ #{local_platform}
DEPENDENCIES
dotenv
@@ -695,8 +1002,8 @@ RSpec.describe "bundle update" do
end
it "works" do
- bundle :install, :artifice => "compact_index"
- bundle "update oj", :artifice => "compact_index"
+ 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"
@@ -832,7 +1139,7 @@ RSpec.describe "bundle update in more complicated situations" do
end
it "allows updating" do
- bundle :update, :all => true
+ bundle :update, all: true
expect(the_bundle).to include_gem "a 1.1"
end
@@ -888,7 +1195,7 @@ RSpec.describe "bundle update without a Gemfile.lock" do
gem "rack", "1.0"
G
- bundle "update", :all => true
+ bundle "update", all: true
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -911,7 +1218,7 @@ RSpec.describe "bundle update when a gem depends on a newer version of bundler"
end
it "should explain that bundler conflicted and how to resolve the conflict" do
- bundle "update", :all => true, :raise_on_error => false
+ bundle "update", all: true, raise_on_error: false
expect(last_command.stdboth).not_to match(/in snapshot/i)
expect(err).to match(/current Bundler version/i).
and match(/Install the necessary version with `gem install bundler:#{Bundler::VERSION.succ}`/i)
@@ -919,27 +1226,22 @@ RSpec.describe "bundle update when a gem depends on a newer version of bundler"
end
RSpec.describe "bundle update --ruby" do
- before do
- install_gemfile <<-G
- ::RUBY_VERSION = '2.1.3'
- ::RUBY_PATCHLEVEL = 100
- ruby '~> 2.1.0'
- source "#{file_uri_for(gem_repo1)}"
- G
- end
-
context "when the Gemfile removes the ruby" do
before do
+ install_gemfile <<-G
+ ruby '~> #{Gem.ruby_version}'
+ source "#{file_uri_for(gem_repo1)}"
+ G
+
gemfile <<-G
- ::RUBY_VERSION = '2.1.4'
- ::RUBY_PATCHLEVEL = 222
- source "#{file_uri_for(gem_repo1)}"
+ source "#{file_uri_for(gem_repo1)}"
G
end
+
it "removes the Ruby from the Gemfile.lock" do
bundle "update --ruby"
- lockfile_should_be <<-L
+ expect(lockfile).to eq <<~L
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
@@ -957,64 +1259,89 @@ RSpec.describe "bundle update --ruby" do
context "when the Gemfile specified an updated Ruby version" do
before do
+ install_gemfile <<-G
+ ruby '~> #{Gem.ruby_version}'
+ source "#{file_uri_for(gem_repo1)}"
+ G
+
gemfile <<-G
- ::RUBY_VERSION = '2.1.4'
- ::RUBY_PATCHLEVEL = 222
- ruby '~> 2.1.0'
- source "#{file_uri_for(gem_repo1)}"
+ ruby '~> #{current_ruby_minor}'
+ source "#{file_uri_for(gem_repo1)}"
G
end
+
it "updates the Gemfile.lock with the latest version" do
bundle "update --ruby"
- lockfile_should_be <<-L
- GEM
- remote: #{file_uri_for(gem_repo1)}/
- specs:
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
- PLATFORMS
- #{lockfile_platforms}
+ PLATFORMS
+ #{lockfile_platforms}
- DEPENDENCIES
+ DEPENDENCIES
- RUBY VERSION
- ruby 2.1.4p222
+ RUBY VERSION
+ #{Bundler::RubyVersion.system}
- BUNDLED WITH
- #{Bundler::VERSION}
+ BUNDLED WITH
+ #{Bundler::VERSION}
L
end
end
context "when a different Ruby is being used than has been versioned" do
before do
+ install_gemfile <<-G
+ ruby '~> #{Gem.ruby_version}'
+ source "#{file_uri_for(gem_repo1)}"
+ G
+
gemfile <<-G
- ::RUBY_VERSION = '2.2.2'
- ::RUBY_PATCHLEVEL = 505
ruby '~> 2.1.0'
source "#{file_uri_for(gem_repo1)}"
G
end
it "shows a helpful error message" do
- bundle "update --ruby", :raise_on_error => false
+ bundle "update --ruby", raise_on_error: false
- expect(err).to include("Your Ruby version is 2.2.2, but your Gemfile specified ~> 2.1.0")
+ expect(err).to include("Your Ruby version is #{Bundler::RubyVersion.system.gem_version}, but your Gemfile specified ~> 2.1.0")
end
end
context "when updating Ruby version and Gemfile `ruby`" do
before do
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+
+ CHECKSUMS
+
+ RUBY VERSION
+ ruby 2.1.4p222
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
gemfile <<-G
- ::RUBY_VERSION = '1.8.3'
- ::RUBY_PATCHLEVEL = 55
- ruby '~> 1.8.0'
+ ruby '~> #{Gem.ruby_version}'
source "#{file_uri_for(gem_repo1)}"
G
end
+
it "updates the Gemfile.lock with the latest version" do
bundle "update --ruby"
- lockfile_should_be <<-L
+ expect(lockfile).to eq <<~L
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
@@ -1024,8 +1351,10 @@ RSpec.describe "bundle update --ruby" do
DEPENDENCIES
+ CHECKSUMS
+
RUBY VERSION
- ruby 1.8.3p55
+ #{Bundler::RubyVersion.system}
BUNDLED WITH
#{Bundler::VERSION}
@@ -1035,24 +1364,355 @@ RSpec.describe "bundle update --ruby" do
end
RSpec.describe "bundle update --bundler" do
- it "updates the bundler version in the lockfile without re-resolving" do
+ it "updates the bundler version in the lockfile" do
build_repo4 do
build_gem "rack", "1.0"
end
+ checksums = checksums_section_when_existing do |c|
+ c.checksum(gem_repo4, "rack", "1.0")
+ end
+
install_gemfile <<-G
source "#{file_uri_for(gem_repo4)}"
gem "rack"
G
- allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ rack (1.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ rack
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, '\11.0.0\2')
- FileUtils.rm_r gem_repo4
+ bundle :update, bundler: true, artifice: "compact_index", verbose: true
+ expect(out).to include("Using bundler #{Bundler::VERSION}")
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ rack (1.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ rack
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
- bundle :update, :bundler => true, :verbose => true
expect(the_bundle).to include_gem "rack 1.0"
+ end
+
+ it "updates the bundler version in the lockfile without re-resolving if the highest version is already installed" do
+ system_gems "bundler-2.3.9"
+
+ build_repo4 do
+ build_gem "rack", "1.0"
+ end
- expect(the_bundle.locked_gems.bundler_version).to eq v(Bundler::VERSION)
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
+ G
+ lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, "2.3.9")
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum(gem_repo4, "rack", "1.0")
+ end
+
+ bundle :update, bundler: true, artifice: "compact_index", verbose: true
+ expect(out).to include("Using bundler #{Bundler::VERSION}")
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ rack (1.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ rack
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ expect(the_bundle).to include_gem "rack 1.0"
+ end
+
+ it "updates the bundler version in the lockfile even if the latest version is not installed", :ruby_repo do
+ pristine_system_gems "bundler-2.3.9"
+
+ build_repo4 do
+ build_gem "rack", "1.0"
+
+ build_bundler "999.0.0"
+ end
+
+ install_gemfile <<-G, artifice: nil, env: { "BUNDLER_IGNORE_DEFAULT_GEM" => "true" }
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
+ G
+ lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, "2.3.9")
+
+ bundle :update, bundler: true, artifice: "compact_index", verbose: true, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+
+ # Only updates properly on modern RubyGems.
+
+ if Gem.rubygems_version >= Gem::Version.new("3.3.0.dev")
+ expect(out).to include("Updating bundler to 999.0.0")
+ expect(out).to include("Using bundler 999.0.0")
+ expect(out).not_to include("Installing Bundler 2.3.9 and restarting using that version.")
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ rack (1.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ rack
+
+ BUNDLED WITH
+ 999.0.0
+ L
+
+ expect(the_bundle).to include_gems "bundler 999.0.0"
+ expect(the_bundle).to include_gems "rack 1.0"
+ else
+ # Old RubyGems versions do not trampoline but they still change BUNDLED
+ # WITH to the latest bundler version. This means the below check fails
+ # because it tries to use bundler 999.0.0 which did not get installed.
+ # Workaround the bug by forcing the version we know is installed.
+ expect(the_bundle).to include_gems "rack 1.0", env: { "BUNDLER_VERSION" => "2.3.9" }
+ end
+ end
+
+ it "does not claim to update to Bundler version to a wrong version when cached gems are present" do
+ pristine_system_gems "bundler-2.99.0"
+
+ build_repo4 do
+ build_gem "rack", "3.0.9.1"
+
+ build_bundler "2.99.0"
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ rack (3.0.9.1)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ rack
+
+ BUNDLED WITH
+ 2.99.0
+ L
+
+ bundle :cache, verbose: true
+
+ bundle :update, bundler: true, artifice: "compact_index", verbose: true, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+
+ expect(out).not_to include("Updating bundler to")
+ end
+
+ it "does not update the bundler version in the lockfile if the latest version is not compatible with current ruby", :ruby_repo do
+ pristine_system_gems "bundler-2.3.9"
+
+ build_repo4 do
+ build_gem "rack", "1.0"
+
+ build_bundler "2.3.9"
+ build_bundler "999.0.0" do |s|
+ s.required_ruby_version = "> #{Gem.ruby_version}"
+ end
+ end
+
+ install_gemfile <<-G, env: { "BUNDLER_IGNORE_DEFAULT_GEM" => "true" }
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
+ G
+ lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, "2.3.9")
+
+ bundle :update, bundler: true, artifice: "compact_index", verbose: true, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s, "BUNDLER_IGNORE_DEFAULT_GEM" => "true" }
+
+ expect(out).to include("Using bundler 2.3.9")
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ rack (1.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ rack
+
+ BUNDLED WITH
+ 2.3.9
+ L
+
+ expect(the_bundle).to include_gems "bundler 2.3.9"
+ expect(the_bundle).to include_gems "rack 1.0"
+ end
+
+ it "errors if the explicit target version does not exist" do
+ pristine_system_gems "bundler-2.3.9"
+
+ build_repo4 do
+ build_gem "rack", "1.0"
+ end
+
+ install_gemfile <<-G, env: { "BUNDLER_IGNORE_DEFAULT_GEM" => "true" }
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
+ G
+ lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, "2.3.9")
+
+ bundle :update, bundler: "999.999.999", artifice: "compact_index", raise_on_error: false
+
+ # Only gives a meaningful error message on modern RubyGems.
+
+ if Gem.rubygems_version >= Gem::Version.new("3.3.0.dev")
+ expect(last_command).to be_failure
+ expect(err).to include("The `bundle update --bundler` target version (999.999.999) does not exist")
+ end
+ end
+
+ it "allows updating to development versions if already installed locally" do
+ system_gems "bundler-2.3.0.dev"
+
+ build_repo4 do
+ build_gem "rack", "1.0"
+ end
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
+ G
+
+ bundle :update, bundler: "2.3.0.dev", verbose: "true"
+
+ # Only updates properly on modern RubyGems.
+ if Gem.rubygems_version >= Gem::Version.new("3.3.0.dev")
+ checksums = checksums_section_when_existing do |c|
+ c.checksum(gem_repo4, "rack", "1.0")
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ rack (1.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ rack
+ #{checksums}
+ BUNDLED WITH
+ 2.3.0.dev
+ L
+
+ expect(out).to include("Using bundler 2.3.0.dev")
+ end
+ end
+
+ it "does not touch the network if not necessary" do
+ system_gems "bundler-2.3.9"
+
+ build_repo4 do
+ build_gem "rack", "1.0"
+ end
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
+ G
+
+ bundle :update, bundler: "2.3.9", verbose: true
+
+ expect(out).not_to include("Fetching gem metadata from https://rubygems.org/")
+
+ # Only updates properly on modern RubyGems.
+ checksums = checksums_section_when_existing do |c|
+ c.checksum(gem_repo4, "rack", "1.0")
+ end
+
+ if Gem.rubygems_version >= Gem::Version.new("3.3.0.dev")
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ rack (1.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ rack
+ #{checksums}
+ BUNDLED WITH
+ 2.3.9
+ L
+
+ expect(out).to include("Using bundler 2.3.9")
+ end
+ end
+
+ it "prints an error when trying to update bundler in frozen mode" do
+ system_gems "bundler-2.3.9"
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo2)}"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: #{file_uri_for(gem_repo2)}/
+ specs:
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+
+ BUNDLED WITH
+ 2.1.4
+ L
+
+ bundle "update --bundler=2.3.9", env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false
+ expect(err).to include("An update to the version of bundler itself was requested, but the lockfile can't be updated because frozen mode is set")
end
end
@@ -1070,7 +1730,10 @@ RSpec.describe "bundle update conservative" do
build_gem "foo", %w[1.5.1] do |s|
s.add_dependency "bar", "~> 3.0"
end
- build_gem "bar", %w[2.0.3 2.0.4 2.0.5 2.1.0 2.1.1 3.0.0]
+ build_gem "foo", %w[2.0.0.pre] do |s|
+ s.add_dependency "bar"
+ end
+ build_gem "bar", %w[2.0.3 2.0.4 2.0.5 2.1.0 2.1.1 2.1.2.pre 3.0.0 3.1.0.pre 4.0.0.pre]
build_gem "qux", %w[1.0.0 1.0.1 1.1.0 2.0.0]
end
@@ -1108,7 +1771,7 @@ RSpec.describe "bundle update conservative" do
end
it "update all" do
- bundle "update --patch", :all => true
+ bundle "update --patch", all: true
expect(the_bundle).to include_gems "foo 1.4.5", "bar 2.1.1", "qux 1.0.1"
end
@@ -1130,11 +1793,37 @@ RSpec.describe "bundle update conservative" do
end
it "minor preferred" do
- bundle "update --minor --strict", :all => true
+ bundle "update --minor --strict", all: true
expect(the_bundle).to include_gems "foo 1.5.0", "bar 2.1.1", "qux 1.1.0"
end
end
+
+ context "pre" do
+ it "defaults to major" do
+ bundle "update --pre foo bar"
+
+ expect(the_bundle).to include_gems "foo 2.0.0.pre", "bar 4.0.0.pre", "qux 1.0.0"
+ end
+
+ it "patch preferred" do
+ bundle "update --patch --pre foo bar"
+
+ expect(the_bundle).to include_gems "foo 1.4.5", "bar 2.1.2.pre", "qux 1.0.0"
+ end
+
+ it "minor preferred" do
+ bundle "update --minor --pre foo bar"
+
+ expect(the_bundle).to include_gems "foo 1.5.1", "bar 3.1.0.pre", "qux 1.0.0"
+ end
+
+ it "major preferred" do
+ bundle "update --major --pre foo bar"
+
+ expect(the_bundle).to include_gems "foo 2.0.0.pre", "bar 4.0.0.pre", "qux 1.0.0"
+ end
+ end
end
context "eager unlocking" do
@@ -1176,13 +1865,15 @@ RSpec.describe "bundle update conservative" do
shared_dep (~> 5.0)
PLATFORMS
- #{specific_local_platform}
+ #{local_platform}
DEPENDENCIES
isolated_owner
shared_owner_a
shared_owner_b
+ CHECKSUMS
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1229,13 +1920,20 @@ RSpec.describe "bundle update conservative" do
shared_dep (~> 5.0)
PLATFORMS
- #{specific_local_platform}
+ #{local_platform}
DEPENDENCIES
isolated_owner
shared_owner_a
shared_owner_b
+ CHECKSUMS
+ isolated_dep (2.0.1)
+ isolated_owner (1.0.2)
+ shared_dep (5.0.1)
+ shared_owner_a (3.0.2)
+ shared_owner_b (4.0.2)
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1262,7 +1960,7 @@ RSpec.describe "bundle update conservative" do
end
it "raises if too many flags are provided" do
- bundle "update --patch --minor", :all => true, :raise_on_error => false
+ bundle "update --patch --minor", all: true, raise_on_error: false
expect(err).to eq "Provide only one of the following options: minor, patch"
end
diff --git a/spec/bundler/commands/version_spec.rb b/spec/bundler/commands/version_spec.rb
index 53d545f5fa..307058a5dd 100644
--- a/spec/bundler/commands/version_spec.rb
+++ b/spec/bundler/commands/version_spec.rb
@@ -4,42 +4,42 @@ require_relative "../support/path"
RSpec.describe "bundle version" do
if Spec::Path.ruby_core?
- COMMIT_HASH = /unknown|[a-fA-F0-9]{7,}/.freeze
+ COMMIT_HASH = /unknown|[a-fA-F0-9]{7,}/
else
- COMMIT_HASH = /[a-fA-F0-9]{7,}/.freeze
+ COMMIT_HASH = /[a-fA-F0-9]{7,}/
end
context "with -v" do
- it "outputs the version", :bundler => "< 3" do
+ it "outputs the version", bundler: "< 3" do
bundle "-v"
expect(out).to eq("Bundler version #{Bundler::VERSION}")
end
- it "outputs the version", :bundler => "3" do
+ it "outputs the version", bundler: "3" do
bundle "-v"
expect(out).to eq(Bundler::VERSION)
end
end
context "with --version" do
- it "outputs the version", :bundler => "< 3" do
+ it "outputs the version", bundler: "< 3" do
bundle "--version"
expect(out).to eq("Bundler version #{Bundler::VERSION}")
end
- it "outputs the version", :bundler => "3" do
+ it "outputs the version", bundler: "3" do
bundle "--version"
expect(out).to eq(Bundler::VERSION)
end
end
context "with version" do
- it "outputs the version with build metadata", :bundler => "< 3" do
+ it "outputs the version with build metadata", bundler: "< 3" do
bundle "version"
expect(out).to match(/\ABundler version #{Regexp.escape(Bundler::VERSION)} \(\d{4}-\d{2}-\d{2} commit #{COMMIT_HASH}\)\z/)
end
- it "outputs the version with build metadata", :bundler => "3" do
+ it "outputs the version with build metadata", bundler: "3" do
bundle "version"
expect(out).to match(/\A#{Regexp.escape(Bundler::VERSION)} \(\d{4}-\d{2}-\d{2} commit #{COMMIT_HASH}\)\z/)
end
diff --git a/spec/bundler/commands/viz_spec.rb b/spec/bundler/commands/viz_spec.rb
index 0efb24b504..f8b5f7836e 100644
--- a/spec/bundler/commands/viz_spec.rb
+++ b/spec/bundler/commands/viz_spec.rb
@@ -1,10 +1,8 @@
# frozen_string_literal: true
-RSpec.describe "bundle viz", :bundler => "< 3", :if => Bundler.which("dot") do
+RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld: true do
before do
- graphviz_version = RUBY_VERSION >= "2.4" ? "1.2.5" : "1.2.4"
-
- realworld_system_gems "ruby-graphviz --version #{graphviz_version}"
+ realworld_system_gems "ruby-graphviz --version 1.2.5"
end
it "graphs gems from the Gemfile" do
@@ -17,8 +15,8 @@ RSpec.describe "bundle viz", :bundler => "< 3", :if => Bundler.which("dot") do
bundle "viz"
expect(out).to include("gem_graph.png")
- bundle "viz", :format => "debug"
- expect(out).to eq(strip_whitespace(<<-DOT).strip)
+ bundle "viz", format: "debug"
+ expect(out).to eq(<<~DOT.strip)
digraph Gemfile {
concentrate = "true";
normalize = "true";
@@ -51,8 +49,8 @@ RSpec.describe "bundle viz", :bundler => "< 3", :if => Bundler.which("dot") do
bundle "viz"
expect(out).to include("gem_graph.png")
- bundle "viz", :format => :debug, :version => true
- expect(out).to eq(strip_whitespace(<<-EOS).strip)
+ bundle "viz", format: :debug, version: true
+ expect(out).to eq(<<~EOS.strip)
digraph Gemfile {
concentrate = "true";
normalize = "true";
@@ -79,7 +77,7 @@ RSpec.describe "bundle viz", :bundler => "< 3", :if => Bundler.which("dot") do
end
end
- system_gems "graphviz-999", :gem_repo => gem_repo4
+ system_gems "graphviz-999", gem_repo: gem_repo4
end
it "loads the correct ruby-graphviz gem" do
@@ -89,8 +87,8 @@ RSpec.describe "bundle viz", :bundler => "< 3", :if => Bundler.which("dot") do
gem "rack-obama"
G
- bundle "viz", :format => "debug"
- expect(out).to eq(strip_whitespace(<<-DOT).strip)
+ bundle "viz", format: "debug"
+ expect(out).to eq(<<~DOT.strip)
digraph Gemfile {
concentrate = "true";
normalize = "true";
diff --git a/spec/bundler/install/allow_offline_install_spec.rb b/spec/bundler/install/allow_offline_install_spec.rb
index 524363fde5..8da94718e0 100644
--- a/spec/bundler/install/allow_offline_install_spec.rb
+++ b/spec/bundler/install/allow_offline_install_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe "bundle install with :allow_offline_install" do
context "with no cached data locally" do
it "still installs" do
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "http://testgemserver.local"
gem "rack-obama"
G
@@ -15,7 +15,7 @@ RSpec.describe "bundle install with :allow_offline_install" do
end
it "still fails when the network is down" do
- install_gemfile <<-G, :artifice => "fail", :raise_on_error => false
+ install_gemfile <<-G, artifice: "fail", raise_on_error: false
source "http://testgemserver.local"
gem "rack-obama"
G
@@ -26,10 +26,10 @@ RSpec.describe "bundle install with :allow_offline_install" do
context "with cached data locally" do
it "will install from the compact index" do
- system_gems ["rack-1.0.0"], :path => default_bundle_path
+ system_gems ["rack-1.0.0"], path: default_bundle_path
bundle "config set clean false"
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "http://testgemserver.local"
gem "rack-obama"
gem "rack", "< 1.0"
@@ -42,7 +42,7 @@ RSpec.describe "bundle install with :allow_offline_install" do
gem "rack-obama"
G
- bundle :update, :artifice => "fail", :all => true
+ bundle :update, artifice: "fail", all: true
expect(last_command.stdboth).to include "Using the cached data for the new index because of a network error"
expect(the_bundle).to include_gems("rack-obama 1.0", "rack 1.0.0")
@@ -51,9 +51,12 @@ RSpec.describe "bundle install with :allow_offline_install" do
def break_git_remote_ops!
FileUtils.mkdir_p(tmp("broken_path"))
File.open(tmp("broken_path/git"), "w", 0o755) do |f|
- f.puts strip_whitespace(<<-RUBY)
+ f.puts <<~RUBY
#!/usr/bin/env ruby
- if %w(fetch --force --quiet --tags refs/heads/*:refs/heads/*).-(ARGV).empty? || %w(clone --bare --no-hardlinks --quiet).-(ARGV).empty?
+ fetch_args = %w(fetch --force --quiet)
+ clone_args = %w(clone --bare --no-hardlinks --quiet)
+
+ if (fetch_args.-(ARGV).empty? || clone_args.-(ARGV).empty?) && ARGV.any? {|arg| arg.start_with?("file://") }
warn "git remote ops have been disabled"
exit 1
end
@@ -72,14 +75,14 @@ RSpec.describe "bundle install with :allow_offline_install" do
it "will install from a cached git repo" do
skip "doesn't print errors" if Gem.win_platform?
- git = build_git "a", "1.0.0", :path => lib_path("a")
- update_git("a", :path => git.path, :branch => "new_branch")
+ git = build_git "a", "1.0.0", path: lib_path("a")
+ update_git("a", path: git.path, branch: "new_branch")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "a", :git => #{git.path.to_s.dump}
G
- break_git_remote_ops! { bundle :update, :all => true }
+ break_git_remote_ops! { bundle :update, all: true }
expect(err).to include("Using cached git data because of network errors")
expect(the_bundle).to be_locked
diff --git a/spec/bundler/install/binstubs_spec.rb b/spec/bundler/install/binstubs_spec.rb
index 6961171f4f..928ba80b15 100644
--- a/spec/bundler/install/binstubs_spec.rb
+++ b/spec/bundler/install/binstubs_spec.rb
@@ -2,10 +2,8 @@
RSpec.describe "bundle install" do
describe "when system_bindir is set" do
- # On OS X, Gem.bindir defaults to /usr/bin, so system_bindir is useful if
- # you want to avoid sudo installs for system gems with OS X's default ruby
it "overrides Gem.bindir" do
- expect(Pathname.new("/usr/bin")).not_to be_writable unless Process.euid == 0
+ expect(Pathname.new("/usr/bin")).not_to be_writable
gemfile <<-G
def Gem.bindir; "/usr/bin"; end
source "#{file_uri_for(gem_repo1)}"
diff --git a/spec/bundler/install/bundler_spec.rb b/spec/bundler/install/bundler_spec.rb
index 963ce82db8..19911f1154 100644
--- a/spec/bundler/install/bundler_spec.rb
+++ b/spec/bundler/install/bundler_spec.rb
@@ -30,19 +30,18 @@ RSpec.describe "bundle install" do
end
it "causes a conflict if explicitly requesting a different version of bundler" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0"
gem "bundler", "0.9.1"
G
- nice_error = <<-E.strip.gsub(/^ {8}/, "")
- Bundler could not find compatible versions for gem "bundler":
- In Gemfile:
- bundler (= 0.9.1)
+ nice_error = <<~E.strip
+ Could not find compatible versions
- Current Bundler version:
- bundler (#{Bundler::VERSION})
+ Because the current Bundler version (#{Bundler::VERSION}) does not satisfy bundler = 0.9.1
+ and Gemfile depends on bundler = 0.9.1,
+ version solving has failed.
Your bundle requires a different version of Bundler than the one you're running.
Install the necessary version with `gem install bundler:0.9.1` and rerun bundler using `bundle _0.9.1_ install`
@@ -51,19 +50,21 @@ RSpec.describe "bundle install" do
end
it "causes a conflict if explicitly requesting a non matching requirement on bundler" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0"
gem "bundler", "~> 0.8"
G
- nice_error = <<-E.strip.gsub(/^ {8}/, "")
- Bundler could not find compatible versions for gem "bundler":
- In Gemfile:
- bundler (~> 0.8)
+ nice_error = <<~E.strip
+ Could not find compatible versions
- Current Bundler version:
- bundler (#{Bundler::VERSION})
+ Because rails >= 3.0 depends on bundler >= 0.9.0.pre
+ and the current Bundler version (#{Bundler::VERSION}) does not satisfy bundler >= 0.9.0.pre, < 1.A,
+ rails >= 3.0 requires bundler >= 1.A.
+ So, because Gemfile depends on rails = 3.0
+ and Gemfile depends on bundler ~> 0.8,
+ version solving has failed.
Your bundle requires a different version of Bundler than the one you're running.
Install the necessary version with `gem install bundler:0.9.1` and rerun bundler using `bundle _0.9.1_ install`
@@ -72,19 +73,18 @@ RSpec.describe "bundle install" do
end
it "causes a conflict if explicitly requesting a version of bundler that doesn't exist" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0"
gem "bundler", "0.9.2"
G
- nice_error = <<-E.strip.gsub(/^ {8}/, "")
- Bundler could not find compatible versions for gem "bundler":
- In Gemfile:
- bundler (= 0.9.2)
+ nice_error = <<~E.strip
+ Could not find compatible versions
- Current Bundler version:
- bundler (#{Bundler::VERSION})
+ Because the current Bundler version (#{Bundler::VERSION}) does not satisfy bundler = 0.9.2
+ and Gemfile depends on bundler = 0.9.2,
+ version solving has failed.
Your bundle requires a different version of Bundler than the one you're running, and that version could not be found.
E
@@ -143,20 +143,21 @@ RSpec.describe "bundle install" do
end
end
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo2)}"
gem "activemerchant"
gem "rails_pinned_to_old_activesupport"
G
- nice_error = <<-E.strip.gsub(/^ {8}/, "")
- Bundler could not find compatible versions for gem "activesupport":
- In Gemfile:
- activemerchant was resolved to 1.0, which depends on
- activesupport (>= 2.0.0)
+ nice_error = <<~E.strip
+ Could not find compatible versions
- rails_pinned_to_old_activesupport was resolved to 1.0, which depends on
- activesupport (= 1.2.3)
+ Because every version of rails_pinned_to_old_activesupport depends on activesupport = 1.2.3
+ and every version of activemerchant depends on activesupport >= 2.0.0,
+ every version of rails_pinned_to_old_activesupport is incompatible with activemerchant >= 0.
+ So, because Gemfile depends on activemerchant >= 0
+ and Gemfile depends on rails_pinned_to_old_activesupport >= 0,
+ version solving has failed.
E
expect(err).to include(nice_error)
end
@@ -170,19 +171,20 @@ RSpec.describe "bundle install" do
end
end
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo2)}"
gem "rails_pinned_to_old_activesupport"
gem "activesupport", "2.3.5"
G
- nice_error = <<-E.strip.gsub(/^ {8}/, "")
- Bundler could not find compatible versions for gem "activesupport":
- In Gemfile:
- activesupport (= 2.3.5)
+ nice_error = <<~E.strip
+ Could not find compatible versions
- rails_pinned_to_old_activesupport was resolved to 1.0, which depends on
- activesupport (= 1.2.3)
+ Because every version of rails_pinned_to_old_activesupport depends on activesupport = 1.2.3
+ and Gemfile depends on rails_pinned_to_old_activesupport >= 0,
+ activesupport = 1.2.3 is required.
+ So, because Gemfile depends on activesupport = 2.3.5,
+ version solving has failed.
E
expect(err).to include(nice_error)
end
@@ -208,6 +210,33 @@ RSpec.describe "bundle install" do
expect(err).to be_empty
end
+ it "prints the previous version when switching to a previously downloaded gem" do
+ build_repo4 do
+ build_gem "rails", "7.0.3"
+ build_gem "rails", "7.0.4"
+ end
+
+ bundle "config set path.system true"
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem 'rails', "7.0.4"
+ G
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem 'rails', "7.0.3"
+ G
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem 'rails', "7.0.4"
+ G
+
+ expect(out).to include("Using rails 7.0.4 (was 7.0.3)")
+ expect(err).to be_empty
+ end
+
it "can install dependencies with newer bundler version with system gems" do
bundle "config set path.system true"
diff --git a/spec/bundler/install/deploy_spec.rb b/spec/bundler/install/deploy_spec.rb
index 8f2650a932..d89fdea6f1 100644
--- a/spec/bundler/install/deploy_spec.rb
+++ b/spec/bundler/install/deploy_spec.rb
@@ -8,26 +8,26 @@ RSpec.describe "install in deployment or frozen mode" do
G
end
- context "with CLI flags", :bundler => "< 3" do
+ context "with CLI flags", bundler: "< 3" do
it "fails without a lockfile and says that --deployment requires a lock" do
- bundle "install --deployment", :raise_on_error => false
- expect(err).to include("The --deployment flag requires a Gemfile.lock")
+ bundle "install --deployment", raise_on_error: false
+ expect(err).to include("The --deployment flag requires a lockfile")
end
it "fails without a lockfile and says that --frozen requires a lock" do
- bundle "install --frozen", :raise_on_error => false
- expect(err).to include("The --frozen flag requires a Gemfile.lock")
+ bundle "install --frozen", raise_on_error: false
+ expect(err).to include("The --frozen flag requires a lockfile")
end
it "disallows --deployment --system" do
- bundle "install --deployment --system", :raise_on_error => false
+ bundle "install --deployment --system", raise_on_error: false
expect(err).to include("You have specified both --deployment")
expect(err).to include("Please choose only one option")
expect(exitstatus).to eq(15)
end
it "disallows --deployment --path --system" do
- bundle "install --deployment --path . --system", :raise_on_error => false
+ bundle "install --deployment --path . --system", raise_on_error: false
expect(err).to include("You have specified both --path")
expect(err).to include("as well as --system")
expect(err).to include("Please choose only one option")
@@ -35,10 +35,43 @@ RSpec.describe "install in deployment or frozen mode" do
end
it "doesn't mess up a subsequent `bundle install` after you try to deploy without a lock" do
- bundle "install --deployment", :raise_on_error => false
+ bundle "install --deployment", raise_on_error: false
bundle :install
expect(the_bundle).to include_gems "rack 1.0"
end
+
+ it "installs gems by default to vendor/bundle" do
+ bundle :lock
+ bundle "install --deployment"
+ expect(out).to include("vendor/bundle")
+ end
+
+ it "installs gems to custom path if specified" do
+ bundle :lock
+ bundle "install --path vendor/bundle2 --deployment"
+ expect(out).to include("vendor/bundle2")
+ end
+
+ it "works with the --frozen flag" do
+ bundle :lock
+ bundle "install --frozen"
+ end
+
+ it "explodes with the --deployment flag if you make a change and don't check in the lockfile" do
+ bundle :lock
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
+ G
+
+ bundle "install --deployment", raise_on_error: false
+ expect(err).to include("frozen mode")
+ expect(err).to include("You have added to the Gemfile")
+ expect(err).to include("* rack-obama")
+ expect(err).not_to include("You have deleted from the Gemfile")
+ expect(err).not_to include("You have changed in the Gemfile")
+ end
end
it "still works if you are not in the app directory and specify --gemfile" do
@@ -46,7 +79,7 @@ RSpec.describe "install in deployment or frozen mode" do
simulate_new_machine
bundle "config set --local deployment true"
bundle "config set --local path vendor/bundle"
- bundle "install --gemfile #{tmp}/bundled_app/Gemfile", :dir => tmp
+ bundle "install --gemfile #{tmp}/bundled_app/Gemfile", dir: tmp
expect(the_bundle).to include_gems "rack 1.0"
end
@@ -70,12 +103,12 @@ RSpec.describe "install in deployment or frozen mode" do
bundle :install
bundle "config set --local deployment true"
bundle :install
- bundle "exec bundle check", :env => { "PATH" => path }
+ bundle "exec bundle check", env: { "PATH" => path }
end
it "works when using path gems from the same path and the version is specified" do
- build_lib "foo", :path => lib_path("nested/foo")
- build_lib "bar", :path => lib_path("nested/bar")
+ build_lib "foo", path: lib_path("nested/foo")
+ build_lib "bar", path: lib_path("nested/bar")
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "foo", "1.0", :path => "#{lib_path("nested")}"
@@ -88,7 +121,7 @@ RSpec.describe "install in deployment or frozen mode" do
end
it "works when path gems are specified twice" do
- build_lib "foo", :path => lib_path("nested/foo")
+ build_lib "foo", path: lib_path("nested/foo")
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("nested/foo")}"
@@ -101,14 +134,14 @@ RSpec.describe "install in deployment or frozen mode" do
end
it "works when there are credentials in the source URL" do
- install_gemfile(<<-G, :artifice => "endpoint_strict_basic_authentication", :quiet => true)
+ install_gemfile(<<-G, artifice: "endpoint_strict_basic_authentication", quiet: true)
source "http://user:pass@localgemserver.test/"
gem "rack-obama", ">= 1.0"
G
bundle "config set --local deployment true"
- bundle :install, :artifice => "endpoint_strict_basic_authentication"
+ bundle :install, artifice: "endpoint_strict_basic_authentication"
end
it "works with sources given by a block" do
@@ -141,7 +174,7 @@ RSpec.describe "install in deployment or frozen mode" do
rack (1.0.0)
PLATFORMS
- #{local}
+ #{generic_local_platform}
DEPENDENCIES
rack
@@ -150,50 +183,10 @@ RSpec.describe "install in deployment or frozen mode" do
bundle "config set --local deployment true"
end
- it "prevents the replace by default" do
- bundle :install, :raise_on_error => false
-
- expect(err).to match(/The list of sources changed/)
- end
-
- context "when allow_deployment_source_credential_changes is true" do
- before { bundle "config set allow_deployment_source_credential_changes true" }
-
- it "allows the replace" do
- bundle :install
-
- expect(out).to match(/Bundle complete!/)
- end
- end
-
- context "when allow_deployment_source_credential_changes is false" do
- before { bundle "config set allow_deployment_source_credential_changes false" }
-
- it "prevents the replace" do
- bundle :install, :raise_on_error => false
-
- expect(err).to match(/The list of sources changed/)
- end
- end
-
- context "when BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES env var is true" do
- before { ENV["BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES"] = "true" }
-
- it "allows the replace" do
- bundle :install
+ it "allows the replace" do
+ bundle :install
- expect(out).to match(/Bundle complete!/)
- end
- end
-
- context "when BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES env var is false" do
- before { ENV["BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES"] = "false" }
-
- it "prevents the replace" do
- bundle :install, :raise_on_error => false
-
- expect(err).to match(/The list of sources changed/)
- end
+ expect(out).to match(/Bundle complete!/)
end
end
@@ -202,29 +195,41 @@ RSpec.describe "install in deployment or frozen mode" do
bundle "install"
end
- it "installs gems by default to vendor/bundle", :bundler => "< 3" do
- bundle "install --deployment"
+ it "installs gems by default to vendor/bundle" do
+ bundle "config set deployment true"
+ expect do
+ bundle "install"
+ end.not_to change { bundled_app_lock.mtime }
expect(out).to include("vendor/bundle")
end
- it "installs gems to custom path if specified", :bundler => "< 3" do
- bundle "install --path vendor/bundle2 --deployment"
+ it "installs gems to custom path if specified" do
+ bundle "config set path vendor/bundle2"
+ bundle "config set deployment true"
+ bundle "install"
expect(out).to include("vendor/bundle2")
end
- it "works with the --deployment flag if you didn't change anything", :bundler => "< 3" do
- bundle "install --deployment"
+ it "installs gems to custom path if specified, even when configured through ENV" do
+ bundle "config set deployment true"
+ bundle "install", env: { "BUNDLE_PATH" => "vendor/bundle2" }
+ expect(out).to include("vendor/bundle2")
end
- it "works with the --frozen flag if you didn't change anything", :bundler => "< 3" do
- bundle "install --frozen"
+ it "works with the `frozen` setting" do
+ bundle "config set frozen true"
+ expect do
+ bundle "install"
+ end.not_to change { bundled_app_lock.mtime }
end
it "works with BUNDLE_FROZEN if you didn't change anything" do
- bundle :install, :env => { "BUNDLE_FROZEN" => "true" }
+ expect do
+ bundle :install, env: { "BUNDLE_FROZEN" => "true" }
+ end.not_to change { bundled_app_lock.mtime }
end
- it "explodes with the --deployment flag if you make a change and don't check in the lockfile" do
+ it "explodes with the `deployment` setting if you make a change and don't check in the lockfile" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -232,8 +237,8 @@ RSpec.describe "install in deployment or frozen mode" do
G
bundle "config set --local deployment true"
- bundle :install, :raise_on_error => false
- expect(err).to include("deployment mode")
+ bundle :install, raise_on_error: false
+ expect(err).to include("frozen mode")
expect(err).to include("You have added to the Gemfile")
expect(err).to include("* rack-obama")
expect(err).not_to include("You have deleted from the Gemfile")
@@ -253,11 +258,60 @@ RSpec.describe "install in deployment or frozen mode" do
bundle "config set --local path .bundle"
bundle "config set --local without development"
bundle "config set --local deployment true"
- bundle :install, :env => { "DEBUG" => "1" }
+ bundle :install, env: { "DEBUG" => "1" }
run "puts :WIN"
expect(out).to eq("WIN")
end
+ it "works if a gem is missing, but it's on a different platform" do
+ build_repo2
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
+
+ source "#{file_uri_for(gem_repo1)}" do
+ gem "rake", platform: :#{not_local_tag}
+ end
+ G
+
+ bundle :install, env: { "BUNDLE_FROZEN" => "true" }
+ expect(last_command).to be_success
+ end
+
+ it "shows a good error if a gem is missing from the lockfile" do
+ build_repo4 do
+ build_gem "foo"
+ build_gem "bar"
+ end
+
+ gemfile <<-G
+ source "https://gem.repo4"
+
+ gem "foo"
+ gem "bar"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo4/
+ specs:
+ foo (1.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ foo
+ bar
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle :install, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false, artifice: "compact_index"
+ expect(err).to include("Your lock file is missing \"bar\", but the lockfile can't be updated because frozen mode is set")
+ end
+
it "explodes if a path gem is missing" do
build_lib "path_gem"
install_gemfile <<-G
@@ -270,11 +324,11 @@ RSpec.describe "install in deployment or frozen mode" do
bundle "config set --local path .bundle"
bundle "config set --local deployment true"
- bundle :install, :raise_on_error => false
+ bundle :install, raise_on_error: false
expect(err).to include("The path `#{lib_path("path_gem-1.0")}` does not exist.")
end
- it "can have --frozen set via an environment variable", :bundler => "< 3" do
+ it "can have --frozen set via an environment variable" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -282,8 +336,8 @@ RSpec.describe "install in deployment or frozen mode" do
G
ENV["BUNDLE_FROZEN"] = "1"
- bundle "install", :raise_on_error => false
- expect(err).to include("deployment mode")
+ bundle "install", raise_on_error: false
+ expect(err).to include("frozen mode")
expect(err).to include("You have added to the Gemfile")
expect(err).to include("* rack-obama")
expect(err).not_to include("You have deleted from the Gemfile")
@@ -298,21 +352,21 @@ RSpec.describe "install in deployment or frozen mode" do
G
ENV["BUNDLE_DEPLOYMENT"] = "true"
- bundle "install", :raise_on_error => false
- expect(err).to include("deployment mode")
+ bundle "install", raise_on_error: false
+ expect(err).to include("frozen mode")
expect(err).to include("You have added to the Gemfile")
expect(err).to include("* rack-obama")
expect(err).not_to include("You have deleted from the Gemfile")
expect(err).not_to include("You have changed in the Gemfile")
end
- it "installs gems by default to vendor/bundle when deployment mode is set via an environment variable", :bundler => "< 3" do
+ it "installs gems by default to vendor/bundle when deployment mode is set via an environment variable" do
ENV["BUNDLE_DEPLOYMENT"] = "true"
bundle "install"
expect(out).to include("vendor/bundle")
end
- it "installs gems to custom path when deployment mode is set via an environment variable ", :bundler => "< 3" do
+ it "installs gems to custom path when deployment mode is set via an environment variable " do
ENV["BUNDLE_DEPLOYMENT"] = "true"
ENV["BUNDLE_PATH"] = "vendor/bundle2"
bundle "install"
@@ -329,7 +383,7 @@ RSpec.describe "install in deployment or frozen mode" do
ENV["BUNDLE_FROZEN"] = "false"
ENV["BUNDLE_DEPLOYMENT"] = "false"
bundle "install"
- expect(out).not_to include("deployment mode")
+ expect(out).not_to include("frozen mode")
expect(out).not_to include("You have added to the Gemfile")
expect(out).not_to include("* rack-obama")
end
@@ -341,8 +395,8 @@ RSpec.describe "install in deployment or frozen mode" do
G
bundle "config set --local deployment true"
- bundle :install, :raise_on_error => false
- expect(err).to include("deployment mode")
+ bundle :install, raise_on_error: false
+ expect(err).to include("frozen mode")
expect(err).to include("You have added to the Gemfile:\n* activesupport\n\n")
expect(err).to include("You have deleted from the Gemfile:\n* rack")
expect(err).not_to include("You have changed in the Gemfile")
@@ -355,13 +409,13 @@ RSpec.describe "install in deployment or frozen mode" do
G
bundle "config set --local deployment true"
- bundle :install, :raise_on_error => false
- expect(err).to include("deployment mode")
- expect(err).to include("You have added to the Gemfile:\n* source: git://hubz.com")
- expect(err).not_to include("You have changed in the Gemfile")
+ bundle :install, raise_on_error: false
+ expect(err).to include("frozen mode")
+ expect(err).not_to include("You have added to the Gemfile")
+ expect(err).to include("You have changed in the Gemfile:\n* rack from `no specified source` to `git://hubz.com`")
end
- it "explodes if you unpin a source" do
+ it "explodes if you change a source" do
build_git "rack"
install_gemfile <<-G
@@ -375,16 +429,16 @@ RSpec.describe "install in deployment or frozen mode" do
G
bundle "config set --local deployment true"
- bundle :install, :raise_on_error => false
- expect(err).to include("deployment mode")
- expect(err).to include("You have deleted from the Gemfile:\n* source: #{lib_path("rack-1.0")}")
+ bundle :install, raise_on_error: false
+ expect(err).to include("frozen mode")
+ expect(err).not_to include("You have deleted from the Gemfile")
expect(err).not_to include("You have added to the Gemfile")
- expect(err).not_to include("You have changed in the Gemfile")
+ expect(err).to include("You have changed in the Gemfile:\n* rack from `#{lib_path("rack-1.0")}` to `no specified source`")
end
- it "explodes if you unpin a source, leaving it pinned somewhere else" do
- build_lib "foo", :path => lib_path("rack/foo")
- build_git "rack", :path => lib_path("rack")
+ it "explodes if you change a source" do
+ build_lib "foo", path: lib_path("rack/foo")
+ build_git "rack", path: lib_path("rack")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -399,9 +453,9 @@ RSpec.describe "install in deployment or frozen mode" do
G
bundle "config set --local deployment true"
- bundle :install, :raise_on_error => false
- expect(err).to include("deployment mode")
- expect(err).to include("You have changed in the Gemfile:\n* rack from `no specified source` to `#{lib_path("rack")}`")
+ bundle :install, raise_on_error: false
+ expect(err).to include("frozen mode")
+ expect(err).to include("You have changed in the Gemfile:\n* rack from `#{lib_path("rack")}` to `no specified source`")
expect(err).not_to include("You have added to the Gemfile")
expect(err).not_to include("You have deleted from the Gemfile")
end
@@ -417,23 +471,23 @@ RSpec.describe "install in deployment or frozen mode" do
gem "rack-obama"
G
- run "require 'rack'", :raise_on_error => false
- expect(err).to include strip_whitespace(<<-E).strip
-The dependencies in your gemfile changed
+ run "require 'rack'", raise_on_error: false
+ expect(err).to include <<~E.strip
+ The dependencies in your gemfile changed, but the lockfile can't be updated because frozen mode is set (Bundler::ProductionError)
-You have added to the Gemfile:
-* rack (= 1.0.0)
-* rack-obama
+ You have added to the Gemfile:
+ * rack (= 1.0.0)
+ * rack-obama
-You have deleted from the Gemfile:
-* rack
+ You have deleted from the Gemfile:
+ * rack
E
end
end
context "with path in Gemfile and packed" do
it "works fine after bundle package and bundle install --local" do
- build_lib "foo", :path => lib_path("foo")
+ build_lib "foo", path: lib_path("foo")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
@@ -452,7 +506,7 @@ You have deleted from the Gemfile:
simulate_new_machine
bundle "config set --local deployment true"
bundle "install --verbose"
- expect(out).not_to include("You are trying to install in deployment mode after changing your Gemfile")
+ expect(out).not_to include("but the lockfile can't be updated because frozen mode is set")
expect(out).not_to include("You have added to the Gemfile")
expect(out).not_to include("You have deleted from the Gemfile")
expect(out).to include("vendor/cache/foo")
diff --git a/spec/bundler/install/failure_spec.rb b/spec/bundler/install/failure_spec.rb
index 4a9c33754f..f972a37bf6 100644
--- a/spec/bundler/install/failure_spec.rb
+++ b/spec/bundler/install/failure_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe "bundle install" do
end
end
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo2)}"
gem "rails"
G
@@ -39,7 +39,7 @@ In Gemfile:
end
it "removes the downloaded .gem" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo4)}"
gem "a"
G
diff --git a/spec/bundler/install/gemfile/eval_gemfile_spec.rb b/spec/bundler/install/gemfile/eval_gemfile_spec.rb
index 02283291b4..cfa66e5986 100644
--- a/spec/bundler/install/gemfile/eval_gemfile_spec.rb
+++ b/spec/bundler/install/gemfile/eval_gemfile_spec.rb
@@ -2,7 +2,7 @@
RSpec.describe "bundle install with gemfile that uses eval_gemfile" do
before do
- build_lib("gunks", :path => bundled_app.join("gems/gunks")) do |s|
+ build_lib("gunks", path: bundled_app.join("gems/gunks")) do |s|
s.name = "gunks"
s.version = "0.0.1"
end
@@ -24,7 +24,7 @@ RSpec.describe "bundle install with gemfile that uses eval_gemfile" do
expect(out).to include("Resolving dependencies")
expect(out).to include("Bundle complete")
- expect(the_bundle).to include_gem "gunks 0.0.1", :source => "path@#{bundled_app("gems", "gunks")}"
+ expect(the_bundle).to include_gem "gunks 0.0.1", source: "path@#{bundled_app("gems", "gunks")}"
end
end
@@ -64,7 +64,7 @@ RSpec.describe "bundle install with gemfile that uses eval_gemfile" do
context "eval-ed Gemfile has relative-path gems" do
before do
- build_lib("a", :path => bundled_app("gems/a"))
+ build_lib("a", path: bundled_app("gems/a"))
create_file bundled_app("nested/Gemfile-nested"), <<-G
source "#{file_uri_for(gem_repo1)}"
gem "a", :path => "../gems/a"
@@ -102,7 +102,7 @@ RSpec.describe "bundle install with gemfile that uses eval_gemfile" do
expect(out).to include("Resolving dependencies")
expect(out).to include("Bundle complete")
- expect(the_bundle).to include_gem "gunks 0.0.1", :source => "path@#{bundled_app("gems", "gunks")}"
+ expect(the_bundle).to include_gem "gunks 0.0.1", source: "path@#{bundled_app("gems", "gunks")}"
end
end
diff --git a/spec/bundler/install/gemfile/force_ruby_platform_spec.rb b/spec/bundler/install/gemfile/force_ruby_platform_spec.rb
new file mode 100644
index 0000000000..a29b79ad62
--- /dev/null
+++ b/spec/bundler/install/gemfile/force_ruby_platform_spec.rb
@@ -0,0 +1,146 @@
+# frozen_string_literal: true
+
+RSpec.describe "bundle install with force_ruby_platform DSL option", :jruby do
+ context "when no transitive deps" do
+ before do
+ build_repo4 do
+ # Build a gem with platform specific versions
+ build_gem("platform_specific") do |s|
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 RUBY'"
+ end
+
+ build_gem("platform_specific") do |s|
+ s.platform = Bundler.local_platform
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 #{Bundler.local_platform}'"
+ end
+
+ # Build the exact same gem with a different name to compare using vs not using the option
+ build_gem("platform_specific_forced") do |s|
+ s.write "lib/platform_specific_forced.rb", "PLATFORM_SPECIFIC_FORCED = '1.0.0 RUBY'"
+ end
+
+ build_gem("platform_specific_forced") do |s|
+ s.platform = Bundler.local_platform
+ s.write "lib/platform_specific_forced.rb", "PLATFORM_SPECIFIC_FORCED = '1.0.0 #{Bundler.local_platform}'"
+ end
+ end
+ end
+
+ it "pulls the pure ruby variant of the given gem" do
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "platform_specific_forced", :force_ruby_platform => true
+ gem "platform_specific"
+ G
+
+ expect(the_bundle).to include_gems "platform_specific_forced 1.0.0 RUBY"
+ expect(the_bundle).to include_gems "platform_specific 1.0.0 #{Bundler.local_platform}"
+ end
+
+ it "still respects a global `force_ruby_platform` config" do
+ install_gemfile <<-G, env: { "BUNDLE_FORCE_RUBY_PLATFORM" => "true" }
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "platform_specific_forced", :force_ruby_platform => true
+ gem "platform_specific"
+ G
+
+ expect(the_bundle).to include_gems "platform_specific_forced 1.0.0 RUBY"
+ expect(the_bundle).to include_gems "platform_specific 1.0.0 RUBY"
+ end
+ end
+
+ context "when also a transitive dependency" do
+ before do
+ build_repo4 do
+ build_gem("depends_on_platform_specific") {|s| s.add_runtime_dependency "platform_specific" }
+
+ build_gem("platform_specific") do |s|
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 RUBY'"
+ end
+
+ build_gem("platform_specific") do |s|
+ s.platform = Bundler.local_platform
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 #{Bundler.local_platform}'"
+ end
+ end
+ end
+
+ it "still pulls the ruby variant" do
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "depends_on_platform_specific"
+ gem "platform_specific", :force_ruby_platform => true
+ G
+
+ expect(the_bundle).to include_gems "platform_specific 1.0.0 RUBY"
+ end
+ end
+
+ context "with transitive dependencies with platform specific versions" do
+ before do
+ build_repo4 do
+ build_gem("depends_on_platform_specific") do |s|
+ s.add_runtime_dependency "platform_specific"
+ s.write "lib/depends_on_platform_specific.rb", "DEPENDS_ON_PLATFORM_SPECIFIC = '1.0.0 RUBY'"
+ end
+
+ build_gem("depends_on_platform_specific") do |s|
+ s.add_runtime_dependency "platform_specific"
+ s.platform = Bundler.local_platform
+ s.write "lib/depends_on_platform_specific.rb", "DEPENDS_ON_PLATFORM_SPECIFIC = '1.0.0 #{Bundler.local_platform}'"
+ end
+
+ build_gem("platform_specific") do |s|
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 RUBY'"
+ end
+
+ build_gem("platform_specific") do |s|
+ s.platform = Bundler.local_platform
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 #{Bundler.local_platform}'"
+ end
+ end
+ end
+
+ it "ignores ruby variants for the transitive dependencies" do
+ install_gemfile <<-G, env: { "DEBUG_RESOLVER" => "true" }
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "depends_on_platform_specific", :force_ruby_platform => true
+ G
+
+ expect(the_bundle).to include_gems "depends_on_platform_specific 1.0.0 RUBY"
+ expect(the_bundle).to include_gems "platform_specific 1.0.0 #{Bundler.local_platform}"
+ end
+
+ it "reinstalls the ruby variant when a platform specific variant is already installed, the lockile has only RUBY platform, and :force_ruby_platform is used in the Gemfile" do
+ lockfile <<-L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}
+ specs:
+ platform_specific (1.0)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ platform_specific
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ system_gems "platform_specific-1.0-#{Gem::Platform.local}", path: default_bundle_path
+
+ install_gemfile <<-G, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }, artifice: "compact_index"
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "platform_specific", :force_ruby_platform => true
+ G
+
+ expect(the_bundle).to include_gems "platform_specific 1.0.0 RUBY"
+ end
+ end
+end
diff --git a/spec/bundler/install/gemfile/gemspec_spec.rb b/spec/bundler/install/gemfile/gemspec_spec.rb
index 6d9cd2daff..63778567cf 100644
--- a/spec/bundler/install/gemfile/gemspec_spec.rb
+++ b/spec/bundler/install/gemfile/gemspec_spec.rb
@@ -8,8 +8,38 @@ RSpec.describe "bundle install from an existing gemspec" do
end
end
+ let(:x64_mingw_archs) do
+ if RUBY_PLATFORM == "x64-mingw-ucrt"
+ if Gem.rubygems_version >= Gem::Version.new("3.2.28")
+ ["x64-mingw-ucrt", "x64-mingw32"]
+ else
+ ["x64-mingw32", "x64-unknown"]
+ end
+ else
+ ["x64-mingw32"]
+ end
+ end
+
+ let(:x64_mingw_gems) do
+ x64_mingw_archs.map {|p| "platform_specific (1.0-#{p})" }.join("\n ")
+ end
+
+ let(:x64_mingw_platforms) do
+ x64_mingw_archs.join("\n ")
+ end
+
+ def x64_mingw_checksums(checksums)
+ x64_mingw_archs.each do |arch|
+ if arch == "x64-mingw-ucrt"
+ checksums.no_checksum "platform_specific", "1.0", arch
+ else
+ checksums.checksum gem_repo2, "platform_specific", "1.0", arch
+ end
+ end
+ end
+
it "should install runtime and development dependencies" do
- build_lib("foo", :path => tmp.join("foo")) do |s|
+ build_lib("foo", path: tmp.join("foo")) do |s|
s.write("Gemfile", "source :rubygems\ngemspec")
s.add_dependency "bar", "=1.0.0"
s.add_development_dependency "bar-dev", "=1.0.0"
@@ -20,11 +50,11 @@ RSpec.describe "bundle install from an existing gemspec" do
G
expect(the_bundle).to include_gems "bar 1.0.0"
- expect(the_bundle).to include_gems "bar-dev 1.0.0", :groups => :development
+ expect(the_bundle).to include_gems "bar-dev 1.0.0", groups: :development
end
it "that is hidden should install runtime and development dependencies" do
- build_lib("foo", :path => tmp.join("foo")) do |s|
+ build_lib("foo", path: tmp.join("foo")) do |s|
s.write("Gemfile", "source :rubygems\ngemspec")
s.add_dependency "bar", "=1.0.0"
s.add_development_dependency "bar-dev", "=1.0.0"
@@ -37,7 +67,7 @@ RSpec.describe "bundle install from an existing gemspec" do
G
expect(the_bundle).to include_gems "bar 1.0.0"
- expect(the_bundle).to include_gems "bar-dev 1.0.0", :groups => :development
+ expect(the_bundle).to include_gems "bar-dev 1.0.0", groups: :development
end
it "should handle a list of requirements" do
@@ -46,7 +76,7 @@ RSpec.describe "bundle install from an existing gemspec" do
build_gem "baz", "1.1"
end
- build_lib("foo", :path => tmp.join("foo")) do |s|
+ build_lib("foo", path: tmp.join("foo")) do |s|
s.write("Gemfile", "source :rubygems\ngemspec")
s.add_dependency "baz", ">= 1.0", "< 1.1"
end
@@ -59,29 +89,29 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "should raise if there are no gemspecs available" do
- build_lib("foo", :path => tmp.join("foo"), :gemspec => false)
+ build_lib("foo", path: tmp.join("foo"), gemspec: false)
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo2)}"
gemspec :path => '#{tmp.join("foo")}'
G
- expect(err).to match(/There are no gemspecs at #{tmp.join('foo')}/)
+ expect(err).to match(/There are no gemspecs at #{tmp.join("foo")}/)
end
it "should raise if there are too many gemspecs available" do
- build_lib("foo", :path => tmp.join("foo")) do |s|
+ build_lib("foo", path: tmp.join("foo")) do |s|
s.write("foo2.gemspec", build_spec("foo", "4.0").first.to_ruby)
end
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo2)}"
gemspec :path => '#{tmp.join("foo")}'
G
- expect(err).to match(/There are multiple gemspecs at #{tmp.join('foo')}/)
+ expect(err).to match(/There are multiple gemspecs at #{tmp.join("foo")}/)
end
it "should pick a specific gemspec" do
- build_lib("foo", :path => tmp.join("foo")) do |s|
+ build_lib("foo", path: tmp.join("foo")) do |s|
s.write("foo2.gemspec", "")
s.add_dependency "bar", "=1.0.0"
s.add_development_dependency "bar-dev", "=1.0.0"
@@ -93,11 +123,11 @@ RSpec.describe "bundle install from an existing gemspec" do
G
expect(the_bundle).to include_gems "bar 1.0.0"
- expect(the_bundle).to include_gems "bar-dev 1.0.0", :groups => :development
+ expect(the_bundle).to include_gems "bar-dev 1.0.0", groups: :development
end
it "should use a specific group for development dependencies" do
- build_lib("foo", :path => tmp.join("foo")) do |s|
+ build_lib("foo", path: tmp.join("foo")) do |s|
s.write("foo2.gemspec", "")
s.add_dependency "bar", "=1.0.0"
s.add_development_dependency "bar-dev", "=1.0.0"
@@ -109,32 +139,32 @@ RSpec.describe "bundle install from an existing gemspec" do
G
expect(the_bundle).to include_gems "bar 1.0.0"
- expect(the_bundle).not_to include_gems "bar-dev 1.0.0", :groups => :development
- expect(the_bundle).to include_gems "bar-dev 1.0.0", :groups => :dev
+ expect(the_bundle).not_to include_gems "bar-dev 1.0.0", groups: :development
+ expect(the_bundle).to include_gems "bar-dev 1.0.0", groups: :dev
end
it "should match a lockfile even if the gemspec defines development dependencies" do
- build_lib("foo", :path => tmp.join("foo")) do |s|
+ build_lib("foo", path: tmp.join("foo")) do |s|
s.write("Gemfile", "source '#{file_uri_for(gem_repo1)}'\ngemspec")
s.add_dependency "actionpack", "=2.3.2"
- s.add_development_dependency "rake", "=13.0.1"
+ s.add_development_dependency "rake", rake_version
end
- bundle "install", :dir => tmp.join("foo")
+ bundle "install", dir: tmp.join("foo")
# This should really be able to rely on $stderr, but, it's not written
# right, so we can't. In fact, this is a bug negation test, and so it'll
# ghost pass in future, and will only catch a regression if the message
# doesn't change. Exit codes should be used correctly (they can be more
# than just 0 and 1).
bundle "config set --local deployment true"
- output = bundle("install", :dir => tmp.join("foo"))
+ output = bundle("install", dir: tmp.join("foo"))
expect(output).not_to match(/You have added to the Gemfile/)
expect(output).not_to match(/You have deleted from the Gemfile/)
- expect(output).not_to match(/install in deployment mode after changing/)
+ expect(output).not_to match(/the lockfile can't be updated because frozen mode is set/)
end
it "should match a lockfile without needing to re-resolve" do
- build_lib("foo", :path => tmp.join("foo")) do |s|
+ build_lib("foo", path: tmp.join("foo")) do |s|
s.add_dependency "rack"
end
@@ -143,7 +173,7 @@ RSpec.describe "bundle install from an existing gemspec" do
gemspec :path => '#{tmp.join("foo")}'
G
- bundle "install", :verbose => true
+ bundle "install", verbose: true
message = "Found no changes, using resolution from the lockfile"
expect(out.scan(message).size).to eq(1)
@@ -152,7 +182,7 @@ RSpec.describe "bundle install from an existing gemspec" do
it "should match a lockfile without needing to re-resolve with development dependencies" do
simulate_platform java
- build_lib("foo", :path => tmp.join("foo")) do |s|
+ build_lib("foo", path: tmp.join("foo")) do |s|
s.add_dependency "rack"
s.add_development_dependency "thin"
end
@@ -162,34 +192,34 @@ RSpec.describe "bundle install from an existing gemspec" do
gemspec :path => '#{tmp.join("foo")}'
G
- bundle "install", :verbose => true
+ bundle "install", verbose: true
message = "Found no changes, using resolution from the lockfile"
expect(out.scan(message).size).to eq(1)
end
- it "should match a lockfile on non-ruby platforms with a transitive platform dependency", :jruby do
- build_lib("foo", :path => tmp.join("foo")) do |s|
+ it "should match a lockfile on non-ruby platforms with a transitive platform dependency", :jruby_only do
+ build_lib("foo", path: tmp.join("foo")) do |s|
s.add_dependency "platform_specific"
end
- system_gems "platform_specific-1.0-java", :path => default_bundle_path
+ system_gems "platform_specific-1.0-java", path: default_bundle_path
install_gemfile <<-G
gemspec :path => '#{tmp.join("foo")}'
G
- bundle "update --bundler", :verbose => true
+ bundle "update --bundler", artifice: "compact_index", verbose: true
expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 JAVA"
end
it "should evaluate the gemspec in its directory" do
- build_lib("foo", :path => tmp.join("foo"))
+ build_lib("foo", path: tmp.join("foo"))
File.open(tmp.join("foo/foo.gemspec"), "w") do |s|
s.write "raise 'ahh' unless Dir.pwd == '#{tmp.join("foo")}'"
end
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
gemspec :path => '#{tmp.join("foo")}'
G
expect(last_command.stdboth).not_to include("ahh")
@@ -203,7 +233,7 @@ RSpec.describe "bundle install from an existing gemspec" do
# so emulate that
system_gems %w[rack-1.0.0 rack-0.9.1 rack-obama-1.0]
- build_lib("foo", :path => bundled_app)
+ build_lib("foo", path: bundled_app)
gemspec = bundled_app("foo.gemspec").read
bundled_app("foo.gemspec").open("w") do |f|
f.write "#{gemspec.strip}.tap { gem 'rack-obama'; require 'rack/obama' }"
@@ -218,14 +248,14 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "allows conflicts" do
- build_lib("foo", :path => tmp.join("foo")) do |s|
+ build_lib("foo", path: tmp.join("foo")) do |s|
s.version = "1.0.0"
s.add_dependency "bar", "= 1.0.0"
end
- build_gem "deps", :to_bundle => true do |s|
+ build_gem "deps", to_bundle: true do |s|
s.add_dependency "foo", "= 0.0.1"
end
- build_gem "foo", "0.0.1", :to_bundle => true
+ build_gem "foo", "0.0.1", to_bundle: true
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
@@ -237,7 +267,7 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "does not break Gem.finish_resolve with conflicts" do
- build_lib("foo", :path => tmp.join("foo")) do |s|
+ build_lib("foo", path: tmp.join("foo")) do |s|
s.version = "1.0.0"
s.add_dependency "bar", "= 1.0.0"
end
@@ -261,14 +291,14 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "handles downgrades" do
- build_lib "omg", "2.0", :path => lib_path("omg")
+ build_lib "omg", "2.0", path: lib_path("omg")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gemspec :path => "#{lib_path("omg")}"
G
- build_lib "omg", "1.0", :path => lib_path("omg")
+ build_lib "omg", "1.0", path: lib_path("omg")
bundle :install
@@ -278,7 +308,7 @@ RSpec.describe "bundle install from an existing gemspec" do
context "in deployment mode" do
context "when the lockfile was not updated after a change to the gemspec's dependencies" do
it "reports that installation failed" do
- build_lib "cocoapods", :path => bundled_app do |s|
+ build_lib "cocoapods", path: bundled_app do |s|
s.add_dependency "activesupport", ">= 1"
end
@@ -289,12 +319,12 @@ RSpec.describe "bundle install from an existing gemspec" do
expect(the_bundle).to include_gems("cocoapods 1.0", "activesupport 2.3.5")
- build_lib "cocoapods", :path => bundled_app do |s|
+ build_lib "cocoapods", path: bundled_app do |s|
s.add_dependency "activesupport", ">= 1.0.1"
end
bundle "config set --local deployment true"
- bundle :install, :raise_on_error => false
+ bundle :install, raise_on_error: false
expect(err).to include("changed")
end
@@ -304,13 +334,13 @@ RSpec.describe "bundle install from an existing gemspec" do
context "when child gemspecs conflict with a released gemspec" do
before do
# build the "parent" gem that depends on another gem in the same repo
- build_lib "source_conflict", :path => bundled_app do |s|
+ build_lib "source_conflict", path: bundled_app do |s|
s.add_dependency "rack_middleware"
end
# build the "child" gem that is the same version as a released gem, but
# has completely different and conflicting dependency requirements
- build_lib "rack_middleware", "1.0", :path => bundled_app("rack_middleware") do |s|
+ build_lib "rack_middleware", "1.0", path: bundled_app("rack_middleware") do |s|
s.add_dependency "rack", "1.0" # anything other than 0.9.1
end
end
@@ -328,83 +358,69 @@ RSpec.describe "bundle install from an existing gemspec" do
context "with a lockfile and some missing dependencies" do
let(:source_uri) { "http://localgemserver.test" }
- context "previously bundled for Ruby" do
- let(:platform) { "ruby" }
-
- before do
- skip "not installing for some reason" if Gem.win_platform?
-
- build_lib("foo", :path => tmp.join("foo")) do |s|
- s.add_dependency "rack", "=1.0.0"
- end
-
- gemfile <<-G
- source "#{source_uri}"
- gemspec :path => "../foo"
- G
+ before do
+ build_lib("foo", path: tmp.join("foo")) do |s|
+ s.add_dependency "rack", "=1.0.0"
+ end
- lockfile <<-L
- PATH
- remote: ../foo
- specs:
- foo (1.0)
- rack (= 1.0.0)
+ gemfile <<-G
+ source "#{source_uri}"
+ gemspec :path => "../foo"
+ G
- GEM
- remote: #{source_uri}
- specs:
- rack (1.0.0)
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ end
- PLATFORMS
- #{generic_local_platform}
+ lockfile <<-L
+ PATH
+ remote: ../foo
+ specs:
+ foo (1.0)
+ rack (= 1.0.0)
- DEPENDENCIES
- foo!
+ GEM
+ remote: #{source_uri}
+ specs:
+ rack (1.0.0)
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
+ PLATFORMS
+ #{generic_local_platform}
- context "using JRuby with explicit platform", :jruby do
- before do
- create_file(
- tmp.join("foo", "foo-java.gemspec"),
- build_spec("foo", "1.0", "java") do
- dep "rack", "=1.0.0"
- @spec.authors = "authors"
- @spec.summary = "summary"
- end.first.to_ruby
- )
- end
+ DEPENDENCIES
+ foo!
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
- it "should install" do
- results = bundle "install", :artifice => "endpoint"
- expect(results).to include("Installing rack 1.0.0")
- expect(the_bundle).to include_gems "rack 1.0.0"
- end
+ context "using JRuby with explicit platform", :jruby_only do
+ before do
+ create_file(
+ tmp.join("foo", "foo-java.gemspec"),
+ build_spec("foo", "1.0", "java") do
+ dep "rack", "=1.0.0"
+ @spec.authors = "authors"
+ @spec.summary = "summary"
+ end.first.to_ruby
+ )
end
- context "using JRuby", :jruby do
- it "should install" do
- results = bundle "install", :artifice => "endpoint"
- expect(results).to include("Installing rack 1.0.0")
- expect(the_bundle).to include_gems "rack 1.0.0"
- end
+ it "should install" do
+ results = bundle "install", artifice: "endpoint"
+ expect(results).to include("Installing rack 1.0.0")
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
+ end
- context "using Windows" do
- it "should install" do
- simulate_windows do
- results = bundle "install", :artifice => "endpoint"
- expect(results).to include("Installing rack 1.0.0")
- expect(the_bundle).to include_gems "rack 1.0.0"
- end
- end
- end
+ it "should install", :jruby do
+ results = bundle "install", artifice: "endpoint"
+ expect(results).to include("Installing rack 1.0.0")
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
- context "bundled for ruby and jruby" do
+ context "bundled for multiple platforms" do
let(:platform_specific_type) { :runtime }
let(:dependency) { "platform_specific" }
before do
@@ -414,7 +430,7 @@ RSpec.describe "bundle install from an existing gemspec" do
end
end
- build_lib "foo", :path => bundled_app do |s|
+ build_lib "foo", path: bundled_app do |s|
if platform_specific_type == :runtime
s.add_runtime_dependency dependency
elsif platform_specific_type == :development
@@ -429,20 +445,32 @@ RSpec.describe "bundle install from an existing gemspec" do
gemspec
G
- simulate_platform("ruby") { bundle "install" }
+ bundle "config set --local force_ruby_platform true"
+ bundle "install"
+
+ simulate_new_machine
simulate_platform("jruby") { bundle "install" }
+ simulate_platform(x64_mingw32) { bundle "install" }
end
context "on ruby" do
before do
- simulate_platform("ruby")
+ bundle "config set --local force_ruby_platform true"
bundle :install
end
context "as a runtime dependency" do
- it "keeps java dependencies in the lockfile" do
+ it "keeps all platform dependencies in the lockfile" do
expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 RUBY"
- expect(lockfile).to eq strip_whitespace(<<-L)
+
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ c.checksum gem_repo2, "platform_specific", "1.0"
+ c.checksum gem_repo2, "platform_specific", "1.0", "java"
+ x64_mingw_checksums(c)
+ end
+
+ expect(lockfile).to eq <<~L
PATH
remote: .
specs:
@@ -454,14 +482,16 @@ RSpec.describe "bundle install from an existing gemspec" do
specs:
platform_specific (1.0)
platform_specific (1.0-java)
+ #{x64_mingw_gems}
PLATFORMS
java
ruby
+ #{x64_mingw_platforms}
DEPENDENCIES
foo!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -471,9 +501,17 @@ RSpec.describe "bundle install from an existing gemspec" do
context "as a development dependency" do
let(:platform_specific_type) { :development }
- it "keeps java dependencies in the lockfile" do
+ it "keeps all platform dependencies in the lockfile" do
expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 RUBY"
- expect(lockfile).to eq strip_whitespace(<<-L)
+
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ c.checksum gem_repo2, "platform_specific", "1.0"
+ c.checksum gem_repo2, "platform_specific", "1.0", "java"
+ x64_mingw_checksums(c)
+ end
+
+ expect(lockfile).to eq <<~L
PATH
remote: .
specs:
@@ -484,15 +522,17 @@ RSpec.describe "bundle install from an existing gemspec" do
specs:
platform_specific (1.0)
platform_specific (1.0-java)
+ #{x64_mingw_gems}
PLATFORMS
java
ruby
+ #{x64_mingw_platforms}
DEPENDENCIES
foo!
platform_specific
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -503,9 +543,18 @@ RSpec.describe "bundle install from an existing gemspec" do
let(:platform_specific_type) { :development }
let(:dependency) { "indirect_platform_specific" }
- it "keeps java dependencies in the lockfile" do
+ it "keeps all platform dependencies in the lockfile" do
expect(the_bundle).to include_gems "foo 1.0", "indirect_platform_specific 1.0", "platform_specific 1.0 RUBY"
- expect(lockfile).to eq strip_whitespace(<<-L)
+
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ c.checksum gem_repo2, "indirect_platform_specific", "1.0"
+ c.checksum gem_repo2, "platform_specific", "1.0"
+ c.checksum gem_repo2, "platform_specific", "1.0", "java"
+ x64_mingw_checksums(c)
+ end
+
+ expect(lockfile).to eq <<~L
PATH
remote: .
specs:
@@ -518,15 +567,17 @@ RSpec.describe "bundle install from an existing gemspec" do
platform_specific
platform_specific (1.0)
platform_specific (1.0-java)
+ #{x64_mingw_gems}
PLATFORMS
java
ruby
+ #{x64_mingw_platforms}
DEPENDENCIES
foo!
indirect_platform_specific
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -538,7 +589,7 @@ RSpec.describe "bundle install from an existing gemspec" do
context "with multiple platforms" do
before do
- build_lib("foo", :path => tmp.join("foo")) do |s|
+ build_lib("foo", path: tmp.join("foo")) do |s|
s.version = "1.0.0"
s.add_development_dependency "rack"
s.write "foo-universal-java.gemspec", build_spec("foo", "1.0.0", "universal-java") {|sj| sj.runtime "rack", "1.0.0" }.first.to_ruby
@@ -546,7 +597,7 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "installs the ruby platform gemspec" do
- simulate_platform "ruby"
+ bundle "config set --local force_ruby_platform true"
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -557,7 +608,7 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "installs the ruby platform gemspec and skips dev deps with `without development` configured" do
- simulate_platform "ruby"
+ bundle "config set --local force_ruby_platform true"
bundle "config set --local without development"
install_gemfile <<-G
@@ -572,7 +623,7 @@ RSpec.describe "bundle install from an existing gemspec" do
context "with multiple platforms and resolving for more specific platforms" do
before do
- build_lib("chef", :path => tmp.join("chef")) do |s|
+ 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
@@ -590,6 +641,12 @@ RSpec.describe "bundle install from an existing gemspec" do
gemspec :path => "../chef"
G
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "chef", "17.1.17"
+ c.no_checksum "chef", "17.1.17", "universal-mingw32"
+ c.checksum gem_repo4, "win32-api", "1.5.3", "universal-mingw32"
+ end
+
initial_lockfile = <<~L
PATH
remote: ../chef
@@ -605,12 +662,12 @@ RSpec.describe "bundle install from an existing gemspec" do
PLATFORMS
ruby
- x64-mingw32
+ #{x64_mingw_platforms}
x86-mingw32
DEPENDENCIES
chef!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -622,4 +679,70 @@ RSpec.describe "bundle install from an existing gemspec" do
expect(lockfile).to eq initial_lockfile
end
end
+
+ context "with multiple locked platforms" do
+ before do
+ build_lib("activeadmin", path: tmp.join("activeadmin")) do |s|
+ s.version = "2.9.0"
+ s.add_dependency "railties", ">= 5.2", "< 6.2"
+ end
+
+ build_repo4 do
+ build_gem "railties", "6.1.4"
+
+ build_gem "jruby-openssl", "0.10.7" do |s|
+ s.platform = "java"
+ end
+ end
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gemspec :path => "../activeadmin"
+ gem "jruby-openssl", :platform => :jruby
+ G
+
+ bundle "lock --add-platform java"
+ end
+
+ it "does not remove the platform specific specs from the lockfile when re-resolving due to gemspec changes" do
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "activeadmin", "2.9.0"
+ c.no_checksum "jruby-openssl", "0.10.7", "java"
+ c.checksum gem_repo4, "railties", "6.1.4"
+ end
+
+ expect(lockfile).to eq <<~L
+ PATH
+ remote: ../activeadmin
+ specs:
+ activeadmin (2.9.0)
+ railties (>= 5.2, < 6.2)
+
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ jruby-openssl (0.10.7-java)
+ railties (6.1.4)
+
+ PLATFORMS
+ #{lockfile_platforms("java")}
+
+ DEPENDENCIES
+ activeadmin!
+ jruby-openssl
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ gemspec = tmp.join("activeadmin/activeadmin.gemspec")
+ File.write(gemspec, File.read(gemspec).sub(">= 5.2", ">= 6.0"))
+
+ previous_lockfile = lockfile
+
+ bundle "install --local"
+
+ expect(lockfile).to eq(previous_lockfile.sub(">= 5.2", ">= 6.0"))
+ end
+ end
end
diff --git a/spec/bundler/install/gemfile/git_spec.rb b/spec/bundler/install/gemfile/git_spec.rb
index 5ea9eee878..45ee7b44d1 100644
--- a/spec/bundler/install/gemfile/git_spec.rb
+++ b/spec/bundler/install/gemfile/git_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
RSpec.describe "bundle install with git sources" do
- describe "when floating on master" do
+ describe "when floating on main" do
before :each do
build_git "foo" do |s|
s.executables = "foobar"
@@ -26,15 +26,22 @@ RSpec.describe "bundle install with git sources" do
expect(out).to eq("WIN")
end
- it "caches the git repo", :bundler => "< 3" do
- expect(Dir["#{default_bundle_path}/cache/bundler/git/foo-1.0-*"]).to have_attributes :size => 1
+ it "caches the git repo", bundler: "< 3" do
+ expect(Dir["#{default_bundle_path}/cache/bundler/git/foo-1.0-*"]).to have_attributes size: 1
+ end
+
+ it "does not write to cache on bundler/setup" do
+ cache_path = default_bundle_path.join("cache")
+ FileUtils.rm_rf(cache_path)
+ ruby "require 'bundler/setup'"
+ expect(cache_path).not_to exist
end
it "caches the git repo globally and properly uses the cached repo on the next invocation" do
simulate_new_machine
bundle "config set global_gem_cache true"
bundle :install
- expect(Dir["#{home}/.bundle/cache/git/foo-1.0-*"]).to have_attributes :size => 1
+ expect(Dir["#{home}/.bundle/cache/git/foo-1.0-*"]).to have_attributes size: 1
bundle "install --verbose"
expect(err).to be_empty
@@ -51,9 +58,10 @@ RSpec.describe "bundle install with git sources" do
bundle "update foo"
- sha = git.ref_for("master", 11)
- spec_file = default_bundle_path.join("bundler/gems/foo-1.0-#{sha}/foo.gemspec").to_s
- ruby_code = Gem::Specification.load(spec_file).to_ruby
+ sha = git.ref_for("main", 11)
+ spec_file = default_bundle_path.join("bundler/gems/foo-1.0-#{sha}/foo.gemspec")
+ expect(spec_file).to exist
+ ruby_code = Gem::Specification.load(spec_file.to_s).to_ruby
file_code = File.read(spec_file)
expect(file_code).to eq(ruby_code)
end
@@ -61,7 +69,7 @@ RSpec.describe "bundle install with git sources" do
it "does not update the git source implicitly" do
update_git "foo"
- install_gemfile bundled_app2("Gemfile"), <<-G, :dir => bundled_app2
+ install_gemfile bundled_app2("Gemfile"), <<-G, dir: bundled_app2
source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem 'foo'
@@ -84,34 +92,30 @@ RSpec.describe "bundle install with git sources" do
it "complains if pinned specs don't exist in the git repo" do
build_git "foo"
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem "foo", "1.1", :git => "#{lib_path("foo-1.0")}"
G
- expect(err).to include("The source contains the following versions of 'foo': 1.0")
+ expect(err).to include("The source contains the following gems matching 'foo':\n * foo-1.0")
end
- it "complains with version and platform if pinned specs don't exist in the git repo" do
- simulate_platform "java"
-
+ it "complains with version and platform if pinned specs don't exist in the git repo", :jruby_only do
build_git "only_java" do |s|
s.platform = "java"
end
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
platforms :jruby do
gem "only_java", "1.2", :git => "#{lib_path("only_java-1.0-java")}"
end
G
- expect(err).to include("The source contains the following versions of 'only_java': 1.0 java")
+ expect(err).to include("The source contains the following gems matching 'only_java':\n * only_java-1.0-java")
end
- it "complains with multiple versions and platforms if pinned specs don't exist in the git repo" do
- simulate_platform "java"
-
+ it "complains with multiple versions and platforms if pinned specs don't exist in the git repo", :jruby_only do
build_git "only_java", "1.0" do |s|
s.platform = "java"
end
@@ -121,14 +125,14 @@ RSpec.describe "bundle install with git sources" do
s.write "only_java1-0.gemspec", File.read("#{lib_path("only_java-1.0-java")}/only_java.gemspec")
end
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
platforms :jruby do
gem "only_java", "1.2", :git => "#{lib_path("only_java-1.1-java")}"
end
G
- expect(err).to include("The source contains the following versions of 'only_java': 1.0 java, 1.1 java")
+ expect(err).to include("The source contains the following gems matching 'only_java':\n * only_java-1.0-java\n * only_java-1.1-java")
end
it "still works after moving the application directory" do
@@ -137,7 +141,7 @@ RSpec.describe "bundle install with git sources" do
FileUtils.mv bundled_app, tmp("bundled_app.bck")
- expect(the_bundle).to include_gems "foo 1.0", :dir => tmp("bundled_app.bck")
+ expect(the_bundle).to include_gems "foo 1.0", dir: tmp("bundled_app.bck")
end
it "can still install after moving the application directory" do
@@ -146,7 +150,7 @@ RSpec.describe "bundle install with git sources" do
FileUtils.mv bundled_app, tmp("bundled_app.bck")
- update_git "foo", "1.1", :path => lib_path("foo-1.0")
+ update_git "foo", "1.1", path: lib_path("foo-1.0")
gemfile tmp("bundled_app.bck/Gemfile"), <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -157,9 +161,9 @@ RSpec.describe "bundle install with git sources" do
gem "rack", "1.0"
G
- bundle "update foo", :dir => tmp("bundled_app.bck")
+ bundle "update foo", dir: tmp("bundled_app.bck")
- expect(the_bundle).to include_gems "foo 1.1", "rack 1.0", :dir => tmp("bundled_app.bck")
+ expect(the_bundle).to include_gems "foo 1.1", "rack 1.0", dir: tmp("bundled_app.bck")
end
end
@@ -196,6 +200,7 @@ RSpec.describe "bundle install with git sources" do
gem "foo"
end
G
+ expect(err).to be_empty
run <<-RUBY
require 'foo'
@@ -222,17 +227,56 @@ RSpec.describe "bundle install with git sources" do
expect(out).to eq("WIN")
end
+ it "works when an abbreviated revision is added after an initial, potentially shallow clone" do
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ git "#{lib_path("foo-1.0")}" do
+ gem "foo"
+ end
+ G
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ git "#{lib_path("foo-1.0")}", :ref => #{@revision[0..7].inspect} do
+ gem "foo"
+ end
+ G
+ end
+
+ it "works when a tag that does not look like a commit hash is used as the value of :ref" do
+ build_git "foo"
+ @remote = build_git("bar", bare: true)
+ update_git "foo", remote: file_uri_for(@remote.path)
+ update_git "foo", push: "main"
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'foo', :git => "#{@remote.path}"
+ G
+
+ # Create a new tag on the remote that needs fetching
+ update_git "foo", tag: "v1.0.0"
+ update_git "foo", push: "v1.0.0"
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'foo', :git => "#{@remote.path}", :ref => "v1.0.0"
+ G
+
+ expect(err).to be_empty
+ end
+
it "works when the revision is a non-head ref" do
- # want to ensure we don't fallback to master
- update_git "foo", :path => lib_path("foo-1.0") do |s|
+ # want to ensure we don't fallback to main
+ update_git "foo", path: lib_path("foo-1.0") do |s|
s.write("lib/foo.rb", "raise 'FAIL'")
end
- sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 master~1", :dir => lib_path("foo-1.0"))
+ sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 main~1", dir: lib_path("foo-1.0"))
# want to ensure we don't fallback to HEAD
- update_git "foo", :path => lib_path("foo-1.0"), :branch => "rando" do |s|
- s.write("lib/foo.rb", "raise 'FAIL'")
+ update_git "foo", path: lib_path("foo-1.0"), branch: "rando" do |s|
+ s.write("lib/foo.rb", "raise 'FAIL_FROM_RANDO'")
end
install_gemfile <<-G
@@ -259,16 +303,16 @@ RSpec.describe "bundle install with git sources" do
end
G
- # want to ensure we don't fallback to master
- update_git "foo", :path => lib_path("foo-1.0") do |s|
+ # want to ensure we don't fallback to main
+ update_git "foo", path: lib_path("foo-1.0") do |s|
s.write("lib/foo.rb", "raise 'FAIL'")
end
- sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 master~1", :dir => lib_path("foo-1.0"))
+ sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 main~1", dir: lib_path("foo-1.0"))
# want to ensure we don't fallback to HEAD
- update_git "foo", :path => lib_path("foo-1.0"), :branch => "rando" do |s|
- s.write("lib/foo.rb", "raise 'FAIL'")
+ update_git "foo", path: lib_path("foo-1.0"), branch: "rando" do |s|
+ s.write("lib/foo.rb", "raise 'FAIL_FROM_RANDO'")
end
install_gemfile <<-G
@@ -288,7 +332,7 @@ RSpec.describe "bundle install with git sources" do
end
it "does not download random non-head refs" do
- sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 master~1", :dir => lib_path("foo-1.0"))
+ sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 main~1", dir: lib_path("foo-1.0"))
bundle "config set global_gem_cache true"
@@ -300,9 +344,9 @@ RSpec.describe "bundle install with git sources" do
G
# ensure we also git fetch after cloning
- bundle :update, :all => true
+ bundle :update, all: true
- sys_exec("git ls-remote .", :dir => Dir[home(".bundle/cache/git/foo-*")].first)
+ sys_exec("git ls-remote .", dir: Dir[home(".bundle/cache/git/foo-*")].first)
expect(out).not_to include("refs/bundler/1")
end
@@ -313,7 +357,7 @@ RSpec.describe "bundle install with git sources" do
let(:repo) { build_git("foo").path }
it "works" do
- update_git("foo", :path => repo, :branch => branch)
+ update_git("foo", path: repo, branch: branch)
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -330,7 +374,7 @@ RSpec.describe "bundle install with git sources" do
it "works" do
skip "git does not accept this" if Gem.win_platform?
- update_git("foo", :path => repo, :branch => branch)
+ update_git("foo", path: repo, branch: branch)
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -348,7 +392,7 @@ RSpec.describe "bundle install with git sources" do
it "works" do
skip "git does not accept this" if Gem.win_platform?
- update_git("foo", :path => repo, :branch => branch)
+ update_git("foo", path: repo, branch: branch)
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -367,7 +411,7 @@ RSpec.describe "bundle install with git sources" do
let(:repo) { build_git("foo").path }
it "works" do
- update_git("foo", :path => repo, :tag => tag)
+ update_git("foo", path: repo, tag: tag)
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -384,7 +428,7 @@ RSpec.describe "bundle install with git sources" do
it "works" do
skip "git does not accept this" if Gem.win_platform?
- update_git("foo", :path => repo, :tag => tag)
+ update_git("foo", path: repo, tag: tag)
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -402,7 +446,7 @@ RSpec.describe "bundle install with git sources" do
it "works" do
skip "git does not accept this" if Gem.win_platform?
- update_git("foo", :path => repo, :tag => tag)
+ update_git("foo", path: repo, tag: tag)
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -418,16 +462,13 @@ RSpec.describe "bundle install with git sources" do
describe "when specifying local override" do
it "uses the local repository instead of checking a new one out" do
- # We don't generate it because we actually don't need it
- # build_git "rack", "0.8"
-
- build_git "rack", "0.8", :path => lib_path("local-rack") do |s|
+ build_git "rack", "0.8", path: lib_path("local-rack") do |s|
s.write "lib/rack.rb", "puts :LOCAL"
end
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
bundle %(config set local.rack #{lib_path("local-rack")})
@@ -442,13 +483,13 @@ RSpec.describe "bundle install with git sources" do
FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
- update_git "rack", "0.8", :path => lib_path("local-rack") do |s|
+ update_git "rack", "0.8", path: lib_path("local-rack") do |s|
s.write "lib/rack.rb", "puts :LOCAL"
end
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
bundle %(config set local.rack #{lib_path("local-rack")})
@@ -461,14 +502,14 @@ RSpec.describe "bundle install with git sources" do
FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
- update_git "rack", "0.8", :path => lib_path("local-rack") do |s|
+ update_git "rack", "0.8", path: lib_path("local-rack") do |s|
s.write "rack.gemspec", build_spec("rack", "0.8") { runtime "rspec", "> 0" }.first.to_ruby
s.write "lib/rack.rb", "puts :LOCAL"
end
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
bundle %(config set local.rack #{lib_path("local-rack")})
@@ -484,13 +525,13 @@ RSpec.describe "bundle install with git sources" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
lockfile0 = File.read(bundled_app_lock)
FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
- update_git "rack", "0.8", :path => lib_path("local-rack") do |s|
+ update_git "rack", "0.8", path: lib_path("local-rack") do |s|
s.add_dependency "nokogiri", "1.4.2"
end
@@ -506,13 +547,13 @@ RSpec.describe "bundle install with git sources" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
lockfile0 = File.read(bundled_app_lock)
FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
- update_git "rack", "0.8", :path => lib_path("local-rack")
+ update_git "rack", "0.8", path: lib_path("local-rack")
bundle %(config set local.rack #{lib_path("local-rack")})
bundle :install
@@ -526,12 +567,12 @@ RSpec.describe "bundle install with git sources" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
bundle %(config set local.rack #{lib_path("local-rack")})
- bundle :install, :raise_on_error => false
- expect(err).to match(/Cannot use local override for rack-0.8 because #{Regexp.escape(lib_path('local-rack').to_s)} does not exist/)
+ bundle :install, raise_on_error: false
+ expect(err).to match(/Cannot use local override for rack-0.8 because #{Regexp.escape(lib_path("local-rack").to_s)} does not exist/)
solution = "config unset local.rack"
expect(err).to match(/Run `bundle #{solution}` to remove the local override/)
@@ -552,8 +593,8 @@ RSpec.describe "bundle install with git sources" do
G
bundle %(config set local.rack #{lib_path("local-rack")})
- bundle :install, :raise_on_error => false
- expect(err).to match(/Cannot use local override for rack-0.8 at #{Regexp.escape(lib_path('local-rack').to_s)} because :branch is not specified in Gemfile/)
+ bundle :install, raise_on_error: false
+ expect(err).to match(/Cannot use local override for rack-0.8 at #{Regexp.escape(lib_path("local-rack").to_s)} because :branch is not specified in Gemfile/)
solution = "config unset local.rack"
expect(err).to match(/Specify a branch or run `bundle #{solution}` to remove the local override/)
@@ -584,47 +625,47 @@ RSpec.describe "bundle install with git sources" do
FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
- update_git "rack", "0.8", :path => lib_path("local-rack"), :branch => "another" do |s|
+ update_git "rack", "0.8", path: lib_path("local-rack"), branch: "another" do |s|
s.write "lib/rack.rb", "puts :LOCAL"
end
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
bundle %(config set local.rack #{lib_path("local-rack")})
- bundle :install, :raise_on_error => false
- expect(err).to match(/is using branch another but Gemfile specifies master/)
+ bundle :install, raise_on_error: false
+ expect(err).to match(/is using branch another but Gemfile specifies main/)
end
it "explodes on invalid revision on install" do
build_git "rack", "0.8"
- build_git "rack", "0.8", :path => lib_path("local-rack") do |s|
+ build_git "rack", "0.8", path: lib_path("local-rack") do |s|
s.write "lib/rack.rb", "puts :LOCAL"
end
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
bundle %(config set local.rack #{lib_path("local-rack")})
- bundle :install, :raise_on_error => false
+ bundle :install, raise_on_error: false
expect(err).to match(/The Gemfile lock is pointing to revision \w+/)
end
it "does not explode on invalid revision on install" do
build_git "rack", "0.8"
- build_git "rack", "0.8", :path => lib_path("local-rack") do |s|
+ build_git "rack", "0.8", path: lib_path("local-rack") do |s|
s.write "lib/rack.rb", "puts :LOCAL"
end
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
bundle %(config set local.rack #{lib_path("local-rack")})
@@ -665,11 +706,11 @@ RSpec.describe "bundle install with git sources" do
it "installs dependencies from git even if a newer gem is available elsewhere" do
system_gems "rack-1.0.0"
- build_lib "rack", "1.0", :path => lib_path("nested/bar") do |s|
+ build_lib "rack", "1.0", path: lib_path("nested/bar") do |s|
s.write "lib/rack.rb", "puts 'WIN OVERRIDE'"
end
- build_git "foo", :path => lib_path("nested") do |s|
+ build_git "foo", path: lib_path("nested") do |s|
s.add_dependency "rack", "= 1.0"
end
@@ -688,7 +729,7 @@ RSpec.describe "bundle install with git sources" do
gem "rack", "0.9.1"
G
- build_git "rack", :path => lib_path("rack")
+ build_git "rack", path: lib_path("rack")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -704,7 +745,7 @@ RSpec.describe "bundle install with git sources" do
gem "rack"
G
- build_git "rack", "1.2", :path => lib_path("rack")
+ build_git "rack", "1.2", path: lib_path("rack")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -717,8 +758,8 @@ RSpec.describe "bundle install with git sources" do
describe "block syntax" do
it "pulls all gems from a git block" do
- build_lib "omg", :path => lib_path("hi2u/omg")
- build_lib "hi2u", :path => lib_path("hi2u")
+ build_lib "omg", path: lib_path("hi2u/omg")
+ build_lib "hi2u", path: lib_path("hi2u")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -766,7 +807,7 @@ RSpec.describe "bundle install with git sources" do
end
it "runs the gemspec in the context of its parent directory" do
- build_lib "bar", :path => lib_path("foo/bar"), :gemspec => false do |s|
+ build_lib "bar", path: lib_path("foo/bar"), gemspec: false do |s|
s.write lib_path("foo/bar/lib/version.rb"), %(BAR_VERSION = '1.0')
s.write "bar.gemspec", <<-G
$:.unshift Dir.pwd
@@ -781,7 +822,7 @@ RSpec.describe "bundle install with git sources" do
G
end
- build_git "foo", :path => lib_path("foo") do |s|
+ build_git "foo", path: lib_path("foo") do |s|
s.write "bin/foo", ""
end
@@ -796,7 +837,7 @@ RSpec.describe "bundle install with git sources" do
end
it "installs from git even if a rubygems gem is present" do
- build_gem "foo", "1.0", :path => lib_path("fake_foo"), :to_system => true do |s|
+ build_gem "foo", "1.0", path: lib_path("fake_foo"), to_system: true do |s|
s.write "lib/foo.rb", "raise 'FAIL'"
end
@@ -811,7 +852,7 @@ RSpec.describe "bundle install with git sources" do
end
it "fakes the gem out if there is no gemspec" do
- build_git "foo", :gemspec => false
+ build_git "foo", gemspec: false
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -829,7 +870,7 @@ RSpec.describe "bundle install with git sources" do
gem "foo", "1.0", :git => "omgomg"
G
- bundle :install, :raise_on_error => false
+ bundle :install, raise_on_error: false
expect(err).to include("Git error:")
expect(err).to include("fatal")
@@ -837,7 +878,7 @@ RSpec.describe "bundle install with git sources" do
end
it "works when the gem path has spaces in it" do
- build_git "foo", :path => lib_path("foo space-1.0")
+ build_git "foo", path: lib_path("foo space-1.0")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -862,41 +903,47 @@ RSpec.describe "bundle install with git sources" do
s.write "lib/forced.rb", "FORCED = '1.1'"
end
- bundle "update", :all => true
+ bundle "update", all: true
expect(the_bundle).to include_gems "forced 1.1"
- sys_exec("git reset --hard HEAD^", :dir => lib_path("forced-1.0"))
+ sys_exec("git reset --hard HEAD^", dir: lib_path("forced-1.0"))
- bundle "update", :all => true
+ bundle "update", all: true
expect(the_bundle).to include_gems "forced 1.0"
end
it "ignores submodules if :submodule is not passed" do
+ # CVE-2022-39253: https://lore.kernel.org/lkml/xmqq4jw1uku5.fsf@gitster.g/
+ system(*%W[git config --global protocol.file.allow always])
+
build_git "submodule", "1.0"
build_git "has_submodule", "1.0" do |s|
s.add_dependency "submodule"
end
- sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0")
- sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0")
+ sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", dir: lib_path("has_submodule-1.0")
+ sys_exec "git commit -m \"submodulator\"", dir: lib_path("has_submodule-1.0")
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("has_submodule-1.0")}" do
gem "has_submodule"
end
G
- expect(err).to match(/could not find gem 'submodule/i)
+ expect(err).to match(%r{submodule >= 0 could not be found in rubygems repository #{file_uri_for(gem_repo1)}/, cached gems or installed locally})
expect(the_bundle).not_to include_gems "has_submodule 1.0"
end
it "handles repos with submodules" do
+ # CVE-2022-39253: https://lore.kernel.org/lkml/xmqq4jw1uku5.fsf@gitster.g/
+ system(*%W[git config --global protocol.file.allow always])
+
build_git "submodule", "1.0"
build_git "has_submodule", "1.0" do |s|
s.add_dependency "submodule"
end
- sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0")
- sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0")
+ sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", dir: lib_path("has_submodule-1.0")
+ sys_exec "git commit -m \"submodulator\"", dir: lib_path("has_submodule-1.0")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -909,11 +956,14 @@ RSpec.describe "bundle install with git sources" do
end
it "does not warn when deiniting submodules" do
+ # CVE-2022-39253: https://lore.kernel.org/lkml/xmqq4jw1uku5.fsf@gitster.g/
+ system(*%W[git config --global protocol.file.allow always])
+
build_git "submodule", "1.0"
build_git "has_submodule", "1.0"
- sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0")
- sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0")
+ sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", dir: lib_path("has_submodule-1.0")
+ sys_exec "git commit -m \"submodulator\"", dir: lib_path("has_submodule-1.0")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -987,7 +1037,7 @@ RSpec.describe "bundle install with git sources" do
FileUtils.mkdir_p(default_bundle_path)
FileUtils.touch(default_bundle_path("bundler"))
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -999,11 +1049,11 @@ RSpec.describe "bundle install with git sources" do
end
it "does not duplicate git gem sources" do
- build_lib "foo", :path => lib_path("nested/foo")
- build_lib "bar", :path => lib_path("nested/bar")
+ build_lib "foo", path: lib_path("nested/foo")
+ build_lib "bar", path: lib_path("nested/bar")
- build_git "foo", :path => lib_path("nested")
- build_git "bar", :path => lib_path("nested")
+ build_git "foo", path: lib_path("nested")
+ build_git "bar", path: lib_path("nested")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -1016,11 +1066,11 @@ RSpec.describe "bundle install with git sources" do
describe "switching sources" do
it "doesn't explode when switching Path to Git sources" do
- build_gem "foo", "1.0", :to_system => true do |s|
+ build_gem "foo", "1.0", to_system: true do |s|
s.write "lib/foo.rb", "raise 'fail'"
end
- build_lib "foo", "1.0", :path => lib_path("bar/foo")
- build_git "bar", "1.0", :path => lib_path("bar") do |s|
+ build_lib "foo", "1.0", path: lib_path("bar/foo")
+ build_git "bar", "1.0", path: lib_path("bar") do |s|
s.add_dependency "foo"
end
@@ -1095,17 +1145,28 @@ RSpec.describe "bundle install with git sources" do
G
expect(out).to_not match(/Revision.*does not exist/)
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{file_uri_for(lib_path("foo-1.0"))}", :ref => "deadbeef"
G
expect(err).to include("Revision deadbeef does not exist in the repository")
end
+
+ it "gives a helpful error message when the remote branch no longer exists" do
+ build_git "foo"
+
+ install_gemfile <<-G, env: { "LANG" => "en" }, raise_on_error: false
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo-1.0"))}", :branch => "deadbeef"
+ G
+
+ expect(err).to include("Revision deadbeef does not exist in the repository")
+ end
end
describe "bundle install with deployment mode configured and git sources" do
it "works" do
- build_git "valim", :path => lib_path("valim")
+ build_git "valim", path: lib_path("valim")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -1136,7 +1197,7 @@ RSpec.describe "bundle install with git sources" do
end
bundle :install,
- :requires => [lib_path("install_hooks.rb")]
+ requires: [lib_path("install_hooks.rb")]
expect(err_without_deprecations).to eq("Ran pre-install hook: foo-1.0")
end
@@ -1156,7 +1217,7 @@ RSpec.describe "bundle install with git sources" do
end
bundle :install,
- :requires => [lib_path("install_hooks.rb")]
+ requires: [lib_path("install_hooks.rb")]
expect(err_without_deprecations).to eq("Ran post-install hook: foo-1.0")
end
@@ -1175,7 +1236,7 @@ RSpec.describe "bundle install with git sources" do
H
end
- bundle :install, :requires => [lib_path("install_hooks.rb")], :raise_on_error => false
+ bundle :install, requires: [lib_path("install_hooks.rb")], raise_on_error: false
expect(err).to include("failed for foo-1.0")
end
end
@@ -1187,7 +1248,7 @@ RSpec.describe "bundle install with git sources" do
s.extensions << "Rakefile"
s.write "Rakefile", <<-RUBY
task :default do
- path = File.expand_path("../lib", __FILE__)
+ path = File.expand_path("lib", __dir__)
FileUtils.mkdir_p(path)
File.open("\#{path}/foo.rb", "w") do |f|
f.puts "FOO = 'YES'"
@@ -1213,8 +1274,8 @@ RSpec.describe "bundle install with git sources" do
expect(out).to include(Pathname.glob(default_bundle_path("bundler/gems/extensions/**/foo-1.0-*")).first.to_s)
end
- it "does not use old extension after ref changes", :ruby_repo do
- git_reader = build_git "foo", :no_default => true do |s|
+ it "does not use old extension after ref changes" do
+ git_reader = build_git "foo", no_default: true do |s|
s.extensions = ["ext/extconf.rb"]
s.write "ext/extconf.rb", <<-RUBY
require "mkmf"
@@ -1231,7 +1292,7 @@ RSpec.describe "bundle install with git sources" do
void Init_foo() { rb_define_global_function("foo", &foo, 0); }
C
end
- sys_exec("git commit -m \"commit for iteration #{i}\" ext/foo.c", :dir => git_reader.path)
+ sys_exec("git commit -m \"commit for iteration #{i}\" ext/foo.c", dir: git_reader.path)
git_commit_sha = git_reader.ref_for("HEAD")
@@ -1260,7 +1321,7 @@ RSpec.describe "bundle install with git sources" do
RUBY
end
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1280,7 +1341,7 @@ In Gemfile:
s.extensions << "Rakefile"
s.write "Rakefile", <<-RUBY
task :default do
- path = File.expand_path("../lib", __FILE__)
+ path = File.expand_path("lib", __dir__)
FileUtils.mkdir_p(path)
cur_time = Time.now.to_f.to_s
File.open("\#{path}/foo.rb", "w") do |f|
@@ -1321,7 +1382,7 @@ In Gemfile:
s.extensions << "Rakefile"
s.write "Rakefile", <<-RUBY
task :default do
- path = File.expand_path("../lib", __FILE__)
+ path = File.expand_path("lib", __dir__)
FileUtils.mkdir_p(path)
cur_time = Time.now.to_f.to_s
File.open("\#{path}/foo.rb", "w") do |f|
@@ -1364,7 +1425,7 @@ In Gemfile:
s.extensions << "Rakefile"
s.write "Rakefile", <<-RUBY
task :default do
- path = File.expand_path("../lib", __FILE__)
+ path = File.expand_path("lib", __dir__)
FileUtils.mkdir_p(path)
cur_time = Time.now.to_f.to_s
File.open("\#{path}/foo.rb", "w") do |f|
@@ -1386,7 +1447,7 @@ In Gemfile:
installed_time = out
- update_git("foo", :branch => "branch2")
+ update_git("foo", branch: "branch2")
expect(installed_time).to match(/\A\d+\.\d+\z/)
@@ -1436,7 +1497,42 @@ In Gemfile:
end
describe "without git installed" do
- it "prints a better error message" do
+ it "prints a better error message when installing" do
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+
+ gem "rake", git: "https://github.com/ruby/rake"
+ G
+
+ lockfile <<-L
+ GIT
+ remote: https://github.com/ruby/rake
+ revision: 5c60da8644a9e4f655e819252e3b6ca77f42b7af
+ specs:
+ rake (13.0.6)
+
+ GEM
+ remote: https://rubygems.org/
+ specs:
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ rake!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ with_path_as("") do
+ bundle "install", raise_on_error: false
+ end
+ expect(err).
+ to include("You need to install git to be able to use gems from git repositories. For help installing git, please refer to GitHub's tutorial at https://help.github.com/articles/set-up-git")
+ end
+
+ it "prints a better error message when updating" do
build_git "foo"
install_gemfile <<-G
@@ -1447,7 +1543,7 @@ In Gemfile:
G
with_path_as("") do
- bundle "update", :all => true, :raise_on_error => false
+ bundle "update", all: true, raise_on_error: false
end
expect(err).
to include("You need to install git to be able to use gems from git repositories. For help installing git, please refer to GitHub's tutorial at https://help.github.com/articles/set-up-git")
@@ -1466,7 +1562,7 @@ In Gemfile:
bundle :cache
simulate_new_machine
- bundle "install", :env => { "PATH" => "" }
+ bundle "install", env: { "PATH" => "" }
expect(out).to_not include("You need to install git to be able to use gems from git repositories.")
end
end
@@ -1484,11 +1580,11 @@ In Gemfile:
end
it "installs successfully" do
- build_git "foo", "1.0", :path => lib_path("foo")
+ build_git "foo", "1.0", path: lib_path("foo")
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "foo", :git => "#{lib_path("foo")}", :branch => "master"
+ gem "foo", :git => "#{lib_path("foo")}", :branch => "main"
G
bundle :install
@@ -1502,7 +1598,7 @@ In Gemfile:
let(:credentials) { "user1:password1" }
it "does not display the password" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
git "https://#{credentials}@github.com/company/private-repo" do
gem "foo"
@@ -1518,7 +1614,7 @@ In Gemfile:
let(:credentials) { "oauth_token" }
it "displays the oauth scheme but not the oauth token" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
git "https://#{credentials}:x-oauth-basic@github.com/company/private-repo" do
gem "foo"
diff --git a/spec/bundler/install/gemfile/groups_spec.rb b/spec/bundler/install/gemfile/groups_spec.rb
index c92b5dcc57..f7907a9cad 100644
--- a/spec/bundler/install/gemfile/groups_spec.rb
+++ b/spec/bundler/install/gemfile/groups_spec.rb
@@ -88,41 +88,32 @@ RSpec.describe "bundle install with groups" do
it "installs gems in the default group" do
bundle "config set --local without emo"
bundle :install
- expect(the_bundle).to include_gems "rack 1.0.0", :groups => [:default]
+ expect(the_bundle).to include_gems "rack 1.0.0", groups: [:default]
end
- 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"
+ it "respects global `without` configuration, but does not save it locally" do
+ bundle "config set --global without emo"
bundle :install
- expect(the_bundle).to include_gems "rack 1.0.0", :groups => [:default]
+ expect(the_bundle).to include_gems "rack 1.0.0", groups: [:default]
bundle "config list"
expect(out).not_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 "allows running application where groups where configured by a different user", :bundler => "< 3" do
+ 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 }
+ 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 set --local without emo"
bundle :install
- expect(the_bundle).not_to include_gems "activesupport 2.3.5", :groups => [:default]
+ expect(the_bundle).not_to include_gems "activesupport 2.3.5", groups: [:default]
end
- it "remembers previous exclusion with `--without`", :bundler => "< 3" do
+ it "remembers previous exclusion with `--without`", bundler: "< 3" do
bundle "install --without emo"
expect(the_bundle).not_to include_gems "activesupport 2.3.5"
bundle :install
@@ -153,7 +144,7 @@ RSpec.describe "bundle install with groups" do
bundle "config set --local without emo"
bundle :install
- expect(the_bundle).to include_gems "activesupport 2.3.2", :groups => [:default]
+ expect(the_bundle).to include_gems "activesupport 2.3.2", groups: [:default]
end
it "still works when BUNDLE_WITHOUT is set" do
@@ -162,20 +153,20 @@ RSpec.describe "bundle install with groups" do
bundle :install
expect(out).not_to include("activesupport")
- expect(the_bundle).to include_gems "rack 1.0.0", :groups => [:default]
- expect(the_bundle).not_to include_gems "activesupport 2.3.5", :groups => [:default]
+ expect(the_bundle).to include_gems "rack 1.0.0", groups: [:default]
+ expect(the_bundle).not_to include_gems "activesupport 2.3.5", groups: [:default]
ENV["BUNDLE_WITHOUT"] = nil
end
- it "clears --without when passed an empty list", :bundler => "< 3" do
+ it "clears --without when passed an empty list", bundler: "< 3" do
bundle "install --without emo"
bundle "install --without ''"
expect(the_bundle).to include_gems "activesupport 2.3.5"
end
- it "doesn't clear without when nothing is passed", :bundler => "< 3" do
+ it "doesn't clear without when nothing is passed", bundler: "< 3" do
bundle "install --without emo"
bundle :install
@@ -193,7 +184,7 @@ RSpec.describe "bundle install with groups" do
expect(the_bundle).to include_gems "thin 1.0"
end
- it "installs gems from the previously requested group", :bundler => "< 3" do
+ it "installs gems from the previously requested group", bundler: "< 3" do
bundle "install --with debugging"
expect(the_bundle).to include_gems "thin 1.0"
bundle :install
@@ -207,26 +198,26 @@ RSpec.describe "bundle install with groups" do
ENV["BUNDLE_WITH"] = nil
end
- it "clears --with when passed an empty list", :bundler => "< 3" do
+ it "clears --with when passed an empty list", bundler: "< 3" do
bundle "install --with debugging"
bundle "install --with ''"
expect(the_bundle).not_to include_gems "thin 1.0"
end
- it "removes groups from without when passed at --with", :bundler => "< 3" do
+ it "removes groups from without when passed at --with", bundler: "< 3" do
bundle "config set --local without emo"
bundle "install --with emo"
expect(the_bundle).to include_gems "activesupport 2.3.5"
end
- it "removes groups from with when passed at --without", :bundler => "< 3" do
+ it "removes groups from with when passed at --without", bundler: "< 3" do
bundle "config set --local with debugging"
- bundle "install --without debugging", :raise_on_error => false
+ bundle "install --without debugging", raise_on_error: false
expect(the_bundle).not_to include_gem "thin 1.0"
end
- it "errors out when passing a group to with and without via CLI flags", :bundler => "< 3" do
- bundle "install --with emo debugging --without emo", :raise_on_error => false
+ it "errors out when passing a group to with and without via CLI flags", bundler: "< 3" do
+ bundle "install --with emo debugging --without emo", raise_on_error: false
expect(last_command).to be_failure
expect(err).to include("The offending groups are: emo")
end
@@ -244,7 +235,7 @@ RSpec.describe "bundle install with groups" do
expect(the_bundle).to include_gem "thin 1.0"
end
- it "can add and remove a group at the same time", :bundler => "< 3" do
+ it "can add and remove a group at the same time", bundler: "< 3" do
bundle "install --with debugging --without emo"
expect(the_bundle).to include_gems "thin 1.0"
expect(the_bundle).not_to include_gems "activesupport 2.3.5"
@@ -358,7 +349,7 @@ RSpec.describe "bundle install with groups" do
G
ruby <<-R
- require "#{entrypoint}"
+ require "bundler"
Bundler.setup :default
Bundler.require :default
puts RACK
@@ -405,7 +396,7 @@ RSpec.describe "bundle install with groups" do
it "does not hit the remote a second time" do
FileUtils.rm_rf gem_repo2
bundle "config set --local without rack"
- bundle :install, :verbose => true
+ bundle :install, verbose: true
expect(last_command.stdboth).not_to match(/fetching/i)
end
end
diff --git a/spec/bundler/install/gemfile/install_if_spec.rb b/spec/bundler/install/gemfile/install_if_spec.rb
index 786e0e9258..c7640d07e1 100644
--- a/spec/bundler/install/gemfile/install_if_spec.rb
+++ b/spec/bundler/install/gemfile/install_if_spec.rb
@@ -18,7 +18,14 @@ RSpec.describe "bundle install with install_if conditionals" do
expect(the_bundle).not_to include_gems("thin")
expect(the_bundle).not_to include_gems("foo")
- lockfile_should_be <<-L
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo1, "activesupport", "2.3.5"
+ c.no_checksum "foo", "1.0"
+ c.checksum gem_repo1, "rack", "1.0.0"
+ c.no_checksum "thin", "1.0"
+ end
+
+ expect(lockfile).to eq <<~L
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
@@ -36,7 +43,7 @@ RSpec.describe "bundle install with install_if conditionals" do
foo
rack
thin
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
diff --git a/spec/bundler/install/gemfile/lockfile_spec.rb b/spec/bundler/install/gemfile/lockfile_spec.rb
index 313e99d0b8..4601d3e2a8 100644
--- a/spec/bundler/install/gemfile/lockfile_spec.rb
+++ b/spec/bundler/install/gemfile/lockfile_spec.rb
@@ -11,6 +11,11 @@ RSpec.describe "bundle install with a lockfile present" do
install_gemfile(gf)
end
+ it "touches the lockfile on install even when nothing has changed" do
+ subject
+ expect { bundle :install }.to change { bundled_app_lock.mtime }
+ end
+
context "gemfile evaluation" do
let(:gf) { super() + "\n\n File.open('evals', 'a') {|f| f << %(1\n) } unless ENV['BUNDLER_SPEC_NO_APPEND']" }
diff --git a/spec/bundler/install/gemfile/path_spec.rb b/spec/bundler/install/gemfile/path_spec.rb
index 566fdcf65a..a57b7ee560 100644
--- a/spec/bundler/install/gemfile/path_spec.rb
+++ b/spec/bundler/install/gemfile/path_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
RSpec.describe "bundle install with explicit source paths" do
- it "fetches gems with a global path source", :bundler => "< 3" do
+ it "fetches gems with a global path source", bundler: "< 3" do
build_lib "foo"
install_gemfile <<-G
@@ -69,7 +69,7 @@ RSpec.describe "bundle install with explicit source paths" do
username = "some_unexisting_user"
relative_path = lib_path("foo-1.0").relative_path_from(Pathname.new("/home/#{username}").expand_path)
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem 'foo', :path => "~#{username}/#{relative_path}"
G
@@ -78,27 +78,30 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "expands paths relative to Bundler.root" do
- build_lib "foo", :path => bundled_app("foo-1.0")
+ build_lib "foo", path: bundled_app("foo-1.0")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem 'foo', :path => "./foo-1.0"
G
- expect(the_bundle).to include_gems("foo 1.0", :dir => bundled_app("subdir").mkpath)
+ expect(the_bundle).to include_gems("foo 1.0", dir: bundled_app("subdir").mkpath)
end
it "sorts paths consistently on install and update when they start with ./" do
- build_lib "demo", :path => lib_path("demo")
- build_lib "aaa", :path => lib_path("demo/aaa")
+ build_lib "demo", path: lib_path("demo")
+ build_lib "aaa", path: lib_path("demo/aaa")
- gemfile = <<-G
+ gemfile lib_path("demo/Gemfile"), <<-G
source "#{file_uri_for(gem_repo1)}"
gemspec
gem "aaa", :path => "./aaa"
G
- File.open(lib_path("demo/Gemfile"), "w") {|f| f.puts gemfile }
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "aaa", "1.0"
+ c.no_checksum "demo", "1.0"
+ end
lockfile = <<~L
PATH
@@ -121,23 +124,23 @@ RSpec.describe "bundle install with explicit source paths" do
DEPENDENCIES
aaa!
demo!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
- bundle :install, :dir => lib_path("demo")
- expect(lib_path("demo/Gemfile.lock")).to have_lockfile(lockfile)
- bundle :update, :all => true, :dir => lib_path("demo")
- expect(lib_path("demo/Gemfile.lock")).to have_lockfile(lockfile)
+ bundle :install, dir: lib_path("demo")
+ expect(lib_path("demo/Gemfile.lock")).to read_as(lockfile)
+ bundle :update, all: true, dir: lib_path("demo")
+ expect(lib_path("demo/Gemfile.lock")).to read_as(lockfile)
end
it "expands paths when comparing locked paths to Gemfile paths" do
- build_lib "foo", :path => bundled_app("foo-1.0")
+ build_lib "foo", path: bundled_app("foo-1.0")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem 'foo', :path => File.expand_path("../foo-1.0", __FILE__)
+ gem 'foo', :path => File.expand_path("foo-1.0", __dir__)
G
bundle "config set --local frozen true"
@@ -147,11 +150,11 @@ RSpec.describe "bundle install with explicit source paths" do
it "installs dependencies from the path even if a newer gem is available elsewhere" do
system_gems "rack-1.0.0"
- build_lib "rack", "1.0", :path => lib_path("nested/bar") do |s|
+ build_lib "rack", "1.0", path: lib_path("nested/bar") do |s|
s.write "lib/rack.rb", "puts 'WIN OVERRIDE'"
end
- build_lib "foo", :path => lib_path("nested") do |s|
+ build_lib "foo", path: lib_path("nested") do |s|
s.add_dependency "rack", "= 1.0"
end
@@ -165,15 +168,15 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "works" do
- build_gem "foo", "1.0.0", :to_system => true do |s|
+ build_gem "foo", "1.0.0", to_system: true do |s|
s.write "lib/foo.rb", "puts 'FAIL'"
end
- build_lib "omg", "1.0", :path => lib_path("omg") do |s|
+ build_lib "omg", "1.0", path: lib_path("omg") do |s|
s.add_dependency "foo"
end
- build_lib "foo", "1.0.0", :path => lib_path("omg/foo")
+ build_lib "foo", "1.0.0", path: lib_path("omg/foo")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -183,15 +186,81 @@ RSpec.describe "bundle install with explicit source paths" do
expect(the_bundle).to include_gems "foo 1.0"
end
+ it "works when using prereleases of 0.0.0" do
+ build_lib "foo", "0.0.0.dev", path: lib_path("foo")
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :path => "#{lib_path("foo")}"
+ G
+
+ lockfile <<~L
+ PATH
+ remote: #{lib_path("foo")}
+ specs:
+ foo (0.0.0.dev)
+
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ foo!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle :install
+
+ expect(the_bundle).to include_gems "foo 0.0.0.dev"
+ end
+
+ it "works when using uppercase prereleases of 0.0.0" do
+ build_lib "foo", "0.0.0.SNAPSHOT", path: lib_path("foo")
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :path => "#{lib_path("foo")}"
+ G
+
+ lockfile <<~L
+ PATH
+ remote: #{lib_path("foo")}
+ specs:
+ foo (0.0.0.SNAPSHOT)
+
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ foo!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle :install
+
+ expect(the_bundle).to include_gems "foo 0.0.0.SNAPSHOT"
+ end
+
it "handles downgrades" do
- build_lib "omg", "2.0", :path => lib_path("omg")
+ build_lib "omg", "2.0", path: lib_path("omg")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "omg", :path => "#{lib_path("omg")}"
G
- build_lib "omg", "1.0", :path => lib_path("omg")
+ build_lib "omg", "1.0", path: lib_path("omg")
bundle :install
@@ -199,7 +268,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "prefers gemspecs closer to the path root" do
- build_lib "premailer", "1.0.0", :path => lib_path("premailer") do |s|
+ build_lib "premailer", "1.0.0", path: lib_path("premailer") do |s|
s.write "gemfiles/ruby187.gemspec", <<-G
Gem::Specification.new do |s|
s.name = 'premailer'
@@ -232,7 +301,7 @@ RSpec.describe "bundle install with explicit source paths" do
G
end
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo-1.0")}"
G
@@ -244,24 +313,78 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "supports gemspec syntax" do
- build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ build_lib "foo", "1.0", path: lib_path("foo") do |s|
s.add_dependency "rack", "1.0"
end
- gemfile = <<-G
+ gemfile lib_path("foo/Gemfile"), <<-G
source "#{file_uri_for(gem_repo1)}"
gemspec
G
- File.open(lib_path("foo/Gemfile"), "w") {|f| f.puts gemfile }
+ bundle "install", dir: lib_path("foo")
+ expect(the_bundle).to include_gems "foo 1.0", dir: lib_path("foo")
+ expect(the_bundle).to include_gems "rack 1.0", dir: lib_path("foo")
+ end
+
+ it "does not unlock dependencies of path sources" do
+ build_repo4 do
+ build_gem "graphql", "2.0.15"
+ build_gem "graphql", "2.0.16"
+ end
+
+ build_lib "foo", "0.1.0", path: lib_path("foo") do |s|
+ s.add_dependency "graphql", "~> 2.0"
+ end
+
+ gemfile_path = lib_path("foo/Gemfile")
+
+ gemfile gemfile_path, <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gemspec
+ G
+
+ lockfile_path = lib_path("foo/Gemfile.lock")
- bundle "install", :dir => lib_path("foo")
- expect(the_bundle).to include_gems "foo 1.0", :dir => lib_path("foo")
- expect(the_bundle).to include_gems "rack 1.0", :dir => lib_path("foo")
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "0.1.0"
+ c.checksum gem_repo4, "graphql", "2.0.15"
+ end
+
+ original_lockfile = <<~L
+ PATH
+ remote: .
+ specs:
+ foo (0.1.0)
+ graphql (~> 2.0)
+
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ graphql (2.0.15)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ foo!
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ lockfile lockfile_path, original_lockfile
+
+ build_lib "foo", "0.1.1", path: lib_path("foo") do |s|
+ s.add_dependency "graphql", "~> 2.0"
+ end
+
+ bundle "install", dir: lib_path("foo")
+ expect(lockfile_path).to read_as(original_lockfile.gsub("foo (0.1.0)", "foo (0.1.1)"))
end
it "supports gemspec syntax with an alternative path" do
- build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ build_lib "foo", "1.0", path: lib_path("foo") do |s|
s.add_dependency "rack", "1.0"
end
@@ -275,48 +398,48 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "doesn't automatically unlock dependencies when using the gemspec syntax" do
- build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ build_lib "foo", "1.0", path: lib_path("foo") do |s|
s.add_dependency "rack", ">= 1.0"
end
- install_gemfile lib_path("foo/Gemfile"), <<-G, :dir => lib_path("foo")
+ install_gemfile lib_path("foo/Gemfile"), <<-G, dir: lib_path("foo")
source "#{file_uri_for(gem_repo1)}"
gemspec
G
- build_gem "rack", "1.0.1", :to_system => true
+ build_gem "rack", "1.0.1", to_system: true
- bundle "install", :dir => lib_path("foo")
+ bundle "install", dir: lib_path("foo")
- expect(the_bundle).to include_gems "foo 1.0", :dir => lib_path("foo")
- expect(the_bundle).to include_gems "rack 1.0", :dir => lib_path("foo")
+ expect(the_bundle).to include_gems "foo 1.0", dir: lib_path("foo")
+ expect(the_bundle).to include_gems "rack 1.0", dir: lib_path("foo")
end
it "doesn't automatically unlock dependencies when using the gemspec syntax and the gem has development dependencies" do
- build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ build_lib "foo", "1.0", path: lib_path("foo") do |s|
s.add_dependency "rack", ">= 1.0"
s.add_development_dependency "activesupport"
end
- install_gemfile lib_path("foo/Gemfile"), <<-G, :dir => lib_path("foo")
+ install_gemfile lib_path("foo/Gemfile"), <<-G, dir: lib_path("foo")
source "#{file_uri_for(gem_repo1)}"
gemspec
G
- build_gem "rack", "1.0.1", :to_system => true
+ build_gem "rack", "1.0.1", to_system: true
- bundle "install", :dir => lib_path("foo")
+ bundle "install", dir: lib_path("foo")
- expect(the_bundle).to include_gems "foo 1.0", :dir => lib_path("foo")
- expect(the_bundle).to include_gems "rack 1.0", :dir => lib_path("foo")
+ expect(the_bundle).to include_gems "foo 1.0", dir: lib_path("foo")
+ expect(the_bundle).to include_gems "rack 1.0", dir: lib_path("foo")
end
it "raises if there are multiple gemspecs" do
- build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ build_lib "foo", "1.0", path: lib_path("foo") do |s|
s.write "bar.gemspec", build_spec("bar", "1.0").first.to_ruby
end
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gemspec :path => "#{lib_path("foo")}"
G
@@ -326,7 +449,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "allows :name to be specified to resolve ambiguity" do
- build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ build_lib "foo", "1.0", path: lib_path("foo") do |s|
s.write "bar.gemspec"
end
@@ -343,7 +466,7 @@ RSpec.describe "bundle install with explicit source paths" do
s.executables = "foobar"
end
- install_gemfile <<-G, :verbose => true
+ install_gemfile <<-G, verbose: true
source "#{file_uri_for(gem_repo1)}"
path "#{lib_path("foo-1.0")}" do
gem 'foo'
@@ -397,9 +520,9 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "keeps source pinning" do
- build_lib "foo", "1.0", :path => lib_path("foo")
- build_lib "omg", "1.0", :path => lib_path("omg")
- build_lib "foo", "1.0", :path => lib_path("omg/foo") do |s|
+ build_lib "foo", "1.0", path: lib_path("foo")
+ build_lib "omg", "1.0", path: lib_path("omg")
+ build_lib "foo", "1.0", path: lib_path("omg/foo") do |s|
s.write "lib/foo.rb", "puts 'FAIL'"
end
@@ -413,7 +536,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "works when the path does not have a gemspec" do
- build_lib "foo", :gemspec => false
+ build_lib "foo", gemspec: false
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -451,17 +574,17 @@ RSpec.describe "bundle install with explicit source paths" do
gem 'net-ssh', '1.0'
G
- bundle :check, :env => { "DEBUG" => "1" }
+ bundle :check, env: { "DEBUG" => "1" }
expect(out).to match(/using resolution from the lockfile/)
expect(the_bundle).to include_gems "rack-obama 1.0", "net-ssh 1.0"
end
it "source path gems w/deps don't re-resolve without changes" do
- build_lib "rack-obama", "1.0", :path => lib_path("omg") do |s|
+ build_lib "rack-obama", "1.0", path: lib_path("omg") do |s|
s.add_dependency "yard"
end
- build_lib "net-ssh", "1.0", :path => lib_path("omg") do |s|
+ build_lib "net-ssh", "1.0", path: lib_path("omg") do |s|
s.add_dependency "yard"
end
@@ -471,7 +594,7 @@ RSpec.describe "bundle install with explicit source paths" do
gem 'net-ssh', :path => "#{lib_path("omg")}"
G
- bundle :check, :env => { "DEBUG" => "1" }
+ bundle :check, env: { "DEBUG" => "1" }
expect(out).to match(/using resolution from the lockfile/)
expect(the_bundle).to include_gems "rack-obama 1.0", "net-ssh 1.0"
end
@@ -493,10 +616,10 @@ RSpec.describe "bundle install with explicit source paths" do
describe "when the gem version in the path is updated" do
before :each do
- build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ build_lib "foo", "1.0", path: lib_path("foo") do |s|
s.add_dependency "bar"
end
- build_lib "bar", "1.0", :path => lib_path("foo/bar")
+ build_lib "bar", "1.0", path: lib_path("foo/bar")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -505,7 +628,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "unlocks all gems when the top level gem is updated" do
- build_lib "foo", "2.0", :path => lib_path("foo") do |s|
+ build_lib "foo", "2.0", path: lib_path("foo") do |s|
s.add_dependency "bar"
end
@@ -515,7 +638,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "unlocks all gems when a child dependency gem is updated" do
- build_lib "bar", "2.0", :path => lib_path("foo/bar")
+ build_lib "bar", "2.0", path: lib_path("foo/bar")
bundle "install"
@@ -525,7 +648,7 @@ RSpec.describe "bundle install with explicit source paths" do
describe "when dependencies in the path are updated" do
before :each do
- build_lib "foo", "1.0", :path => lib_path("foo")
+ build_lib "foo", "1.0", path: lib_path("foo")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -534,7 +657,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "gets dependencies that are updated in the path" do
- build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ build_lib "foo", "1.0", path: lib_path("foo") do |s|
s.add_dependency "rack"
end
@@ -544,7 +667,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "keeps using the same version if it's compatible" do
- build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ build_lib "foo", "1.0", path: lib_path("foo") do |s|
s.add_dependency "rack", "0.9.1"
end
@@ -552,7 +675,12 @@ RSpec.describe "bundle install with explicit source paths" do
expect(the_bundle).to include_gems "rack 0.9.1"
- lockfile_should_be <<-G
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ c.checksum gem_repo1, "rack", "0.9.1"
+ end
+
+ expect(lockfile).to eq <<~G
PATH
remote: #{lib_path("foo")}
specs:
@@ -569,18 +697,18 @@ RSpec.describe "bundle install with explicit source paths" do
DEPENDENCIES
foo!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
- build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ build_lib "foo", "1.0", path: lib_path("foo") do |s|
s.add_dependency "rack"
end
bundle "install"
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
PATH
remote: #{lib_path("foo")}
specs:
@@ -597,7 +725,7 @@ RSpec.describe "bundle install with explicit source paths" do
DEPENDENCIES
foo!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -606,7 +734,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "keeps using the same version even when another dependency is added" do
- build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ build_lib "foo", "1.0", path: lib_path("foo") do |s|
s.add_dependency "rack", "0.9.1"
end
@@ -614,7 +742,12 @@ RSpec.describe "bundle install with explicit source paths" do
expect(the_bundle).to include_gems "rack 0.9.1"
- lockfile_should_be <<-G
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ c.checksum gem_repo1, "rack", "0.9.1"
+ end
+
+ expect(lockfile).to eq <<~G
PATH
remote: #{lib_path("foo")}
specs:
@@ -631,53 +764,107 @@ RSpec.describe "bundle install with explicit source paths" do
DEPENDENCIES
foo!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
- build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ build_lib "foo", "1.0", path: lib_path("foo") do |s|
s.add_dependency "rack"
- s.add_dependency "rake", "13.0.1"
+ s.add_dependency "rake", rake_version
end
bundle "install"
- lockfile_should_be <<-G
+ checksums.checksum gem_repo1, "rake", rake_version
+
+ expect(lockfile).to eq <<~G
PATH
remote: #{lib_path("foo")}
specs:
foo (1.0)
rack
- rake (= 13.0.1)
+ rake (= #{rake_version})
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
rack (0.9.1)
- rake (13.0.1)
+ rake (#{rake_version})
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
expect(the_bundle).to include_gems "rack 0.9.1"
end
+
+ it "does not remove existing ruby platform" do
+ build_lib "foo", "1.0", path: lib_path("foo") do |s|
+ s.add_dependency "rack", "0.9.1"
+ end
+
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ end
+
+ lockfile <<~L
+ PATH
+ remote: #{lib_path("foo")}
+ specs:
+ foo (1.0)
+
+ PLATFORMS
+ #{lockfile_platforms("ruby")}
+
+ DEPENDENCIES
+ foo!
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "lock"
+
+ checksums.no_checksum "rack", "0.9.1"
+
+ expect(lockfile).to eq <<~G
+ PATH
+ remote: #{lib_path("foo")}
+ specs:
+ foo (1.0)
+ rack (= 0.9.1)
+
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+ rack (0.9.1)
+
+ PLATFORMS
+ #{lockfile_platforms("ruby")}
+
+ DEPENDENCIES
+ foo!
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ G
+ end
end
describe "switching sources" do
it "doesn't switch pinned git sources to rubygems when pinning the parent gem to a path source" do
- build_gem "foo", "1.0", :to_system => true do |s|
+ build_gem "foo", "1.0", to_system: true do |s|
s.write "lib/foo.rb", "raise 'fail'"
end
- build_lib "foo", "1.0", :path => lib_path("bar/foo")
- build_git "bar", "1.0", :path => lib_path("bar") do |s|
+ build_lib "foo", "1.0", path: lib_path("bar/foo")
+ build_git "bar", "1.0", path: lib_path("bar") do |s|
s.add_dependency "foo"
end
@@ -695,8 +882,8 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "switches the source when the gem existed in rubygems and the path was already being used for another gem" do
- build_lib "foo", "1.0", :path => lib_path("foo")
- build_gem "bar", "1.0", :to_bundle => true do |s|
+ build_lib "foo", "1.0", path: lib_path("foo")
+ build_gem "bar", "1.0", to_bundle: true do |s|
s.write "lib/bar.rb", "raise 'fail'"
end
@@ -708,7 +895,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
G
- build_lib "bar", "1.0", :path => lib_path("foo/bar")
+ build_lib "bar", "1.0", path: lib_path("foo/bar")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -724,19 +911,17 @@ RSpec.describe "bundle install with explicit source paths" do
describe "when there are both a gemspec and remote gems" do
it "doesn't query rubygems for local gemspec name" do
- build_lib "private_lib", "2.2", :path => lib_path("private_lib")
- gemfile = <<-G
+ build_lib "private_lib", "2.2", path: lib_path("private_lib")
+ gemfile lib_path("private_lib/Gemfile"), <<-G
source "http://localgemserver.test"
gemspec
gem 'rack'
G
- File.open(lib_path("private_lib/Gemfile"), "w") {|f| f.puts gemfile }
-
- bundle :install, :env => { "DEBUG" => "1" }, :artifice => "endpoint", :dir => lib_path("private_lib")
+ bundle :install, env: { "DEBUG" => "1" }, artifice: "endpoint", dir: lib_path("private_lib")
expect(out).to match(%r{^HTTP GET http://localgemserver\.test/api/v1/dependencies\?gems=rack$})
expect(out).not_to match(/^HTTP GET.*private_lib/)
- expect(the_bundle).to include_gems "private_lib 2.2", :dir => lib_path("private_lib")
- expect(the_bundle).to include_gems "rack 1.0", :dir => lib_path("private_lib")
+ expect(the_bundle).to include_gems "private_lib 2.2", dir: lib_path("private_lib")
+ expect(the_bundle).to include_gems "rack 1.0", dir: lib_path("private_lib")
end
end
@@ -757,7 +942,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
bundle :install,
- :requires => [lib_path("install_hooks.rb")]
+ requires: [lib_path("install_hooks.rb")]
expect(err_without_deprecations).to eq("Ran pre-install hook: foo-1.0")
end
@@ -777,7 +962,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
bundle :install,
- :requires => [lib_path("install_hooks.rb")]
+ requires: [lib_path("install_hooks.rb")]
expect(err_without_deprecations).to eq("Ran post-install hook: foo-1.0")
end
@@ -796,7 +981,7 @@ RSpec.describe "bundle install with explicit source paths" do
H
end
- bundle :install, :requires => [lib_path("install_hooks.rb")], :raise_on_error => false
+ bundle :install, requires: [lib_path("install_hooks.rb")], raise_on_error: false
expect(err).to include("failed for foo-1.0")
end
diff --git a/spec/bundler/install/gemfile/platform_spec.rb b/spec/bundler/install/gemfile/platform_spec.rb
index 7cd06b7e08..d90dacdc02 100644
--- a/spec/bundler/install/gemfile/platform_spec.rb
+++ b/spec/bundler/install/gemfile/platform_spec.rb
@@ -50,7 +50,7 @@ RSpec.describe "bundle install across platforms" do
expect(the_bundle).to include_gems "platform_specific 1.0 JAVA"
end
- it "pulls the pure ruby version on jruby if the java platform is not present in the lockfile and bundler is run in frozen mode", :jruby do
+ it "pulls the pure ruby version on jruby if the java platform is not present in the lockfile and bundler is run in frozen mode", :jruby_only do
lockfile <<-G
GEM
remote: #{file_uri_for(gem_repo1)}
@@ -75,6 +75,81 @@ RSpec.describe "bundle install across platforms" do
expect(the_bundle).to include_gems "platform_specific 1.0 RUBY"
end
+ context "on universal Rubies" do
+ before do
+ build_repo4 do
+ build_gem "darwin_single_arch" do |s|
+ s.platform = "ruby"
+ s.write "lib/darwin_single_arch.rb", "DARWIN_SINGLE_ARCH = '1.0 RUBY'"
+ end
+ build_gem "darwin_single_arch" do |s|
+ s.platform = "arm64-darwin"
+ s.write "lib/darwin_single_arch.rb", "DARWIN_SINGLE_ARCH = '1.0 arm64-darwin'"
+ end
+ build_gem "darwin_single_arch" do |s|
+ s.platform = "x86_64-darwin"
+ s.write "lib/darwin_single_arch.rb", "DARWIN_SINGLE_ARCH = '1.0 x86_64-darwin'"
+ end
+ end
+ end
+
+ it "pulls in the correct architecture gem" do
+ lockfile <<-G
+ GEM
+ remote: #{file_uri_for(gem_repo4)}
+ specs:
+ darwin_single_arch (1.0)
+ darwin_single_arch (1.0-arm64-darwin)
+ darwin_single_arch (1.0-x86_64-darwin)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ darwin_single_arch
+ G
+
+ simulate_platform "universal-darwin-21"
+ simulate_ruby_platform "universal.x86_64-darwin21" do
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "darwin_single_arch"
+ G
+
+ expect(the_bundle).to include_gems "darwin_single_arch 1.0 x86_64-darwin"
+ end
+ end
+
+ it "pulls in the correct architecture gem on arm64e macOS Ruby" do
+ lockfile <<-G
+ GEM
+ remote: #{file_uri_for(gem_repo4)}
+ specs:
+ darwin_single_arch (1.0)
+ darwin_single_arch (1.0-arm64-darwin)
+ darwin_single_arch (1.0-x86_64-darwin)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ darwin_single_arch
+ G
+
+ simulate_platform "universal-darwin-21"
+ simulate_ruby_platform "universal.arm64e-darwin21" do
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "darwin_single_arch"
+ G
+
+ expect(the_bundle).to include_gems "darwin_single_arch 1.0 arm64-darwin"
+ end
+ end
+ end
+
it "works with gems that have different dependencies" do
simulate_platform "java"
install_gemfile <<-G
@@ -86,13 +161,13 @@ RSpec.describe "bundle install across platforms" do
expect(the_bundle).to include_gems "nokogiri 1.4.2 JAVA", "weakling 0.0.3"
simulate_new_machine
-
- simulate_platform "ruby"
+ bundle "config set --local force_ruby_platform true"
bundle "install"
expect(the_bundle).to include_gems "nokogiri 1.4.2"
expect(the_bundle).not_to include_gems "weakling"
+ simulate_new_machine
simulate_platform "java"
bundle "install"
@@ -128,7 +203,16 @@ RSpec.describe "bundle install across platforms" do
gem "pry"
G
- lockfile_should_be <<-L
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "coderay", "1.1.2"
+ c.checksum gem_repo4, "empyrean", "0.1.0"
+ c.checksum gem_repo4, "ffi", "1.9.23", "java"
+ c.checksum gem_repo4, "method_source", "0.9.0"
+ c.checksum gem_repo4, "pry", "0.11.3", "java"
+ c.checksum gem_repo4, "spoon", "0.0.6"
+ end
+
+ expect(lockfile).to eq <<~L
GEM
remote: #{file_uri_for(gem_repo4)}/
specs:
@@ -149,14 +233,14 @@ RSpec.describe "bundle install across platforms" do
DEPENDENCIES
empyrean (= 0.1.0)
pry
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
bundle "lock --add-platform ruby"
- good_lockfile = strip_whitespace(<<-L)
+ good_lockfile = <<~L
GEM
remote: #{file_uri_for(gem_repo4)}/
specs:
@@ -181,14 +265,14 @@ RSpec.describe "bundle install across platforms" do
DEPENDENCIES
empyrean (= 0.1.0)
pry
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
- lockfile_should_be good_lockfile
+ expect(lockfile).to eq good_lockfile
- bad_lockfile = strip_whitespace <<-L
+ bad_lockfile = <<~L
GEM
remote: #{file_uri_for(gem_repo4)}/
specs:
@@ -214,31 +298,31 @@ RSpec.describe "bundle install across platforms" do
DEPENDENCIES
empyrean (= 0.1.0)
pry
-
+ #{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ 1.16.1
L
aggregate_failures do
lockfile bad_lockfile
- bundle :install
- lockfile_should_be good_lockfile
+ bundle :install, env: { "BUNDLER_VERSION" => Bundler::VERSION }
+ expect(lockfile).to eq good_lockfile
lockfile bad_lockfile
- bundle :update, :all => true
- lockfile_should_be good_lockfile
+ bundle :update, all: true, env: { "BUNDLER_VERSION" => Bundler::VERSION }
+ expect(lockfile).to eq good_lockfile
lockfile bad_lockfile
- bundle "update ffi"
- lockfile_should_be good_lockfile
+ bundle "update ffi", env: { "BUNDLER_VERSION" => Bundler::VERSION }
+ expect(lockfile).to eq good_lockfile
lockfile bad_lockfile
- bundle "update empyrean"
- lockfile_should_be good_lockfile
+ bundle "update empyrean", env: { "BUNDLER_VERSION" => Bundler::VERSION }
+ expect(lockfile).to eq good_lockfile
lockfile bad_lockfile
- bundle :lock
- lockfile_should_be good_lockfile
+ bundle :lock, env: { "BUNDLER_VERSION" => Bundler::VERSION }
+ expect(lockfile).to eq good_lockfile
end
end
@@ -288,6 +372,11 @@ RSpec.describe "bundle install across platforms" do
end
it "keeps existing platforms when installing with force_ruby_platform" do
+ checksums = checksums_section do |c|
+ c.no_checksum "platform_specific", "1.0"
+ c.no_checksum "platform_specific", "1.0", "java"
+ end
+
lockfile <<-G
GEM
remote: #{file_uri_for(gem_repo1)}/
@@ -299,6 +388,7 @@ RSpec.describe "bundle install across platforms" do
DEPENDENCIES
platform_specific
+ #{checksums}
G
bundle "config set --local force_ruby_platform true"
@@ -308,9 +398,11 @@ RSpec.describe "bundle install across platforms" do
gem "platform_specific"
G
+ checksums.checksum gem_repo1, "platform_specific", "1.0"
+
expect(the_bundle).to include_gem "platform_specific 1.0 RUBY"
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
@@ -323,7 +415,7 @@ RSpec.describe "bundle install across platforms" do
DEPENDENCIES
platform_specific
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -332,8 +424,6 @@ end
RSpec.describe "bundle install with platform conditionals" do
it "installs gems tagged w/ the current platforms" do
- skip "platform issues" if Gem.win_platform?
-
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -358,9 +448,50 @@ RSpec.describe "bundle install with platform conditionals" do
expect(the_bundle).not_to include_gems "nokogiri 1.4.2"
end
- it "installs gems tagged w/ the current platforms inline" do
- skip "platform issues" if Gem.win_platform?
+ it "installs gems tagged w/ another platform but also dependent on the current one transitively" do
+ build_repo4 do
+ build_gem "activesupport", "6.1.4.1" do |s|
+ s.add_dependency "tzinfo", "~> 2.0"
+ end
+
+ build_gem "tzinfo", "2.0.4"
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "activesupport"
+
+ platforms :#{not_local_tag} do
+ gem "tzinfo", "~> 1.2"
+ end
+ G
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ activesupport (6.1.4.1)
+ tzinfo (~> 2.0)
+ tzinfo (2.0.4)
+
+ PLATFORMS
+ #{local_platform}
+
+ DEPENDENCIES
+ activesupport
+ tzinfo (~> 1.2)
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install --verbose"
+
+ expect(the_bundle).to include_gems "tzinfo 2.0.4"
+ end
+
+ it "installs gems tagged w/ the current platforms inline" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "nokogiri", :platforms => :#{local_tag}
@@ -379,8 +510,6 @@ RSpec.describe "bundle install with platform conditionals" do
end
it "installs gems tagged w/ the current platform inline" do
- skip "platform issues" if Gem.win_platform?
-
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "nokogiri", :platform => :#{local_tag}
@@ -410,7 +539,7 @@ RSpec.describe "bundle install with platform conditionals" do
end
it "does not attempt to install gems from :rbx when using --local" do
- simulate_platform "ruby"
+ bundle "config set --local force_ruby_platform true"
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -422,12 +551,10 @@ RSpec.describe "bundle install with platform conditionals" do
end
it "does not attempt to install gems from other rubies when using --local" do
- simulate_platform "ruby"
- other_ruby_version_tag = RUBY_VERSION =~ /^1\.8/ ? :ruby_19 : :ruby_18
-
+ bundle "config set --local force_ruby_platform true"
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "some_gem", platform: :#{other_ruby_version_tag}
+ gem "some_gem", platform: :ruby_22
G
bundle "install --local"
@@ -435,19 +562,19 @@ RSpec.describe "bundle install with platform conditionals" do
end
it "does not print a warning when a dependency is unused on a platform different from the current one" do
- simulate_platform "ruby"
+ bundle "config set --local force_ruby_platform true"
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "rack", :platform => [:mingw, :mswin, :x64_mingw, :jruby]
+ gem "rack", :platform => [:windows, :mswin, :mswin64, :mingw, :x64_mingw, :jruby]
G
bundle "install"
expect(err).to be_empty
- lockfile_should_be <<-L
+ expect(lockfile).to eq <<~L
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
@@ -457,16 +584,36 @@ RSpec.describe "bundle install with platform conditionals" do
DEPENDENCIES
rack
-
+ #{checksums_section_when_existing}
BUNDLED WITH
#{Bundler::VERSION}
L
end
+
+ it "resolves fine when a dependency is unused on a platform different from the current one, but reintroduced transitively" do
+ bundle "config set --local force_ruby_platform true"
+
+ build_repo4 do
+ build_gem "listen", "3.7.1" do |s|
+ s.add_dependency "ffi"
+ end
+
+ build_gem "ffi", "1.15.5"
+ end
+
+ install_gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "listen"
+ gem "ffi", :platform => :windows
+ G
+ expect(err).to be_empty
+ end
end
RSpec.describe "when a gem has no architecture" do
it "still installs correctly" do
- simulate_platform mswin
+ simulate_platform x86_mswin32
build_repo2 do
# The rcov gem is platform mswin32, but has no arch
@@ -482,7 +629,7 @@ RSpec.describe "when a gem has no architecture" do
gem "rcov"
G
- bundle :install, :artifice => "windows", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ bundle :install, artifice: "windows", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(the_bundle).to include_gems "rcov 1.0.0"
end
end
diff --git a/spec/bundler/install/gemfile/ruby_spec.rb b/spec/bundler/install/gemfile/ruby_spec.rb
index fd4300c042..b64d633fd3 100644
--- a/spec/bundler/install/gemfile/ruby_spec.rb
+++ b/spec/bundler/install/gemfile/ruby_spec.rb
@@ -11,13 +11,13 @@ RSpec.describe "ruby requirement" do
it "allows adding gems" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- ruby "#{RUBY_VERSION}"
+ ruby "#{Gem.ruby_version}"
gem "rack"
G
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- ruby "#{RUBY_VERSION}"
+ ruby "#{Gem.ruby_version}"
gem "rack"
gem "rack-obama"
G
@@ -28,7 +28,7 @@ RSpec.describe "ruby requirement" do
it "allows removing the ruby version requirement" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- ruby "~> #{RUBY_VERSION}"
+ ruby "~> #{Gem.ruby_version}"
gem "rack"
G
@@ -46,18 +46,16 @@ RSpec.describe "ruby requirement" do
it "allows changing the ruby version requirement to something compatible" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- ruby ">= 1.0.0"
+ ruby ">= #{current_ruby_minor}"
gem "rack"
G
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
expect(locked_ruby_version).to eq(Bundler::RubyVersion.system)
- simulate_ruby_version "5100"
-
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- ruby ">= 1.0.1"
+ ruby ">= #{Gem.ruby_version}"
gem "rack"
G
@@ -72,25 +70,41 @@ RSpec.describe "ruby requirement" do
gem "rack"
G
- allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- expect(locked_ruby_version).to eq(Bundler::RubyVersion.system)
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+ rack (1.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ rack
+
+ RUBY VERSION
+ ruby 2.1.4p422
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
- simulate_ruby_version "5100"
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- ruby ">= 5000.0"
+ ruby ">= #{current_ruby_minor}"
gem "rack"
G
expect(the_bundle).to include_gems "rack 1.0.0"
- expect(locked_ruby_version.versions).to eq(["5100"])
+ expect(locked_ruby_version).to eq(Bundler::RubyVersion.system)
end
it "allows requirements with trailing whitespace" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- ruby "#{RUBY_VERSION}\\n \t\\n"
+ ruby "#{Gem.ruby_version}\\n \t\\n"
gem "rack"
G
@@ -98,7 +112,7 @@ RSpec.describe "ruby requirement" do
end
it "fails gracefully with malformed requirements" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
ruby ">= 0", "-.\\0"
gem "rack"
@@ -106,4 +120,38 @@ RSpec.describe "ruby requirement" do
expect(err).to include("There was an error parsing") # i.e. DSL error, not error template
end
+
+ it "allows picking up ruby version from a file" do
+ create_file ".ruby-version", Gem.ruby_version.to_s
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ ruby file: ".ruby-version"
+ gem "rack"
+ G
+
+ expect(lockfile).to include("RUBY VERSION")
+ end
+
+ it "reads the ruby version file from the right folder when nested Gemfiles are involved" do
+ create_file ".ruby-version", Gem.ruby_version.to_s
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ ruby file: ".ruby-version"
+ gem "rack"
+ G
+
+ nested_dir = bundled_app(".ruby-lsp")
+
+ FileUtils.mkdir nested_dir
+
+ create_file ".ruby-lsp/Gemfile", <<-G
+ eval_gemfile(File.expand_path("../Gemfile", __dir__))
+ G
+
+ bundle "install", dir: nested_dir
+
+ expect(bundled_app(".ruby-lsp/Gemfile.lock").read).to include("RUBY VERSION")
+ end
end
diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb
index 8c225afb11..a5ba76f4d9 100644
--- a/spec/bundler/install/gemfile/sources_spec.rb
+++ b/spec/bundler/install/gemfile/sources_spec.rb
@@ -27,18 +27,72 @@ RSpec.describe "bundle install with gems on multiple sources" do
G
end
- it "warns about ambiguous gems, but installs anyway, prioritizing sources last to first", :bundler => "< 3" do
- bundle :install, :artifice => "compact_index"
+ it "refuses to install mismatched checksum because one gem has been tampered with", bundler: "< 3" do
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo3/
+ remote: https://gem.repo1/
+ specs:
+ rack (1.0.0)
- expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
- expect(err).to include("Installed from: https://gem.repo1")
- expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0", :source => "remote1")
+ PLATFORMS
+ #{local_platform}
+
+ DEPENDENCIES
+ depends_on_rack!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle :install, artifice: "compact_index", raise_on_error: false
+
+ expect(exitstatus).to eq(37)
+ expect(err).to eq <<~E.strip
+ [DEPRECATED] Your Gemfile contains multiple global sources. Using `source` more than once without a block is a security risk, and may result in installing unexpected gems. To resolve this warning, use a block to indicate which gems should come from the secondary source.
+ Bundler found mismatched checksums. This is a potential security risk.
+ #{checksum_to_lock(gem_repo1, "rack", "1.0.0")}
+ from the API at https://gem.repo1/
+ #{checksum_to_lock(gem_repo3, "rack", "1.0.0")}
+ from the API at https://gem.repo3/
+
+ Mismatched checksums each have an authoritative source:
+ 1. the API at https://gem.repo1/
+ 2. the API at https://gem.repo3/
+ You may need to alter your Gemfile sources to resolve this issue.
+
+ To ignore checksum security warnings, disable checksum validation with
+ `bundle config set --local disable_checksum_validation true`
+ E
end
- it "fails", :bundler => "3" do
- bundle :instal, :artifice => "compact_index", :raise_on_error => false
- expect(err).to include("Each source after the first must include a block")
- expect(exitstatus).to eq(4)
+ context "when checksum validation is disabled" do
+ before do
+ bundle "config set --local disable_checksum_validation true"
+ end
+
+ it "warns about ambiguous gems, but installs anyway, prioritizing sources last to first", bundler: "< 3" do
+ bundle :install, artifice: "compact_index"
+
+ expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
+ expect(err).to include("Installed from: https://gem.repo1")
+ expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0", source: "remote1")
+ end
+
+ it "does not use the full index unnecessarily", bundler: "< 3" do
+ bundle :install, artifice: "compact_index", verbose: true
+
+ expect(out).to include("https://gem.repo1/versions")
+ expect(out).to include("https://gem.repo3/versions")
+ expect(out).not_to include("https://gem.repo1/quick/Marshal.4.8/")
+ expect(out).not_to include("https://gem.repo3/quick/Marshal.4.8/")
+ end
+
+ it "fails", bundler: "3" do
+ bundle :install, artifice: "compact_index", raise_on_error: false
+ expect(err).to include("Each source after the first must include a block")
+ expect(exitstatus).to eq(4)
+ end
end
end
@@ -54,21 +108,49 @@ RSpec.describe "bundle install with gems on multiple sources" do
G
end
- it "warns about ambiguous gems, but installs anyway", :bundler => "< 3" do
- bundle :install, :artifice => "compact_index"
+ it "warns about ambiguous gems, but installs anyway", bundler: "< 3" do
+ bundle :install, artifice: "compact_index"
expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
expect(err).to include("Installed from: https://gem.repo1")
- expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0", :source => "remote1")
+ expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0", source: "remote1")
end
- it "fails", :bundler => "3" do
- bundle :install, :artifice => "compact_index", :raise_on_error => false
+ it "fails", bundler: "3" do
+ bundle :install, artifice: "compact_index", raise_on_error: false
expect(err).to include("Each source after the first must include a block")
expect(exitstatus).to eq(4)
end
end
end
+ context "without source affinity, and a stdlib gem present in one of the sources", :ruby_repo do
+ let(:default_json_version) { ruby "gem 'json'; require 'json'; puts JSON::VERSION" }
+
+ before do
+ build_repo2 do
+ build_gem "json", default_json_version
+ end
+
+ build_repo4 do
+ build_gem "foo" do |s|
+ s.add_dependency "json", default_json_version
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ source "https://gem.repo4"
+
+ gem "foo"
+ G
+ end
+
+ it "works in standalone mode", bundler: "< 3" do
+ gem_checksum = checksum_digest(gem_repo4, "foo", "1.0")
+ bundle "install --standalone", artifice: "compact_index", env: { "BUNDLER_SPEC_FOO_CHECKSUM" => gem_checksum }
+ end
+ end
+
context "with source affinity" do
context "with sources given by a block" do
before do
@@ -95,20 +177,20 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs the gems without any warning" do
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("rack-obama 1.0.0")
- expect(the_bundle).to include_gems("rack 1.0.0", :source => "remote1")
+ expect(the_bundle).to include_gems("rack 1.0.0", source: "remote1")
end
it "can cache and deploy" do
- bundle :cache, :artifice => "compact_index"
+ bundle :cache, artifice: "compact_index"
expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
expect(bundled_app("vendor/cache/rack-obama-1.0.gem")).to exist
bundle "config set --local deployment true"
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0")
end
@@ -128,7 +210,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
end
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo3"
gem "rack-obama" # should come from repo3!
gem "rack", :source => "https://gem.repo1"
@@ -168,9 +250,9 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs from the same source without any warning" do
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).not_to include("Warning")
- expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", source: "remote3")
end
end
@@ -185,18 +267,18 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs from the same source without any warning" do
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
- expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", source: "remote3")
# In https://github.com/bundler/bundler/issues/3585 this failed
# when there is already a lock file, and the gems are missing, so try again
system_gems []
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
- expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", source: "remote3")
end
end
end
@@ -218,7 +300,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "and not in any other sources" do
before do
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo2"
source "https://gem.repo3" do
gem "depends_on_rack"
@@ -243,11 +325,63 @@ RSpec.describe "bundle install with gems on multiple sources" do
G
end
- it "installs from the other source and warns about ambiguous gems", :bundler => "< 3" do
- bundle :install, :artifice => "compact_index"
+ it "fails when the two sources don't have the same checksum", bundler: "< 3" do
+ bundle :install, artifice: "compact_index", raise_on_error: false
+
+ expect(err).to eq(<<~E.strip)
+ [DEPRECATED] Your Gemfile contains multiple global sources. Using `source` more than once without a block is a security risk, and may result in installing unexpected gems. To resolve this warning, use a block to indicate which gems should come from the secondary source.
+ Bundler found mismatched checksums. This is a potential security risk.
+ #{checksum_to_lock(gem_repo2, "rack", "1.0.0")}
+ from the API at https://gem.repo2/
+ #{checksum_to_lock(gem_repo1, "rack", "1.0.0")}
+ from the API at https://gem.repo1/
+
+ Mismatched checksums each have an authoritative source:
+ 1. the API at https://gem.repo2/
+ 2. the API at https://gem.repo1/
+ You may need to alter your Gemfile sources to resolve this issue.
+
+ To ignore checksum security warnings, disable checksum validation with
+ `bundle config set --local disable_checksum_validation true`
+ E
+ expect(exitstatus).to eq(37)
+ end
+
+ it "fails when the two sources agree, but the local gem calculates a different checksum", bundler: "< 3" do
+ rack_checksum = "c0ffee11" * 8
+ bundle :install, artifice: "compact_index", env: { "BUNDLER_SPEC_RACK_CHECKSUM" => rack_checksum }, raise_on_error: false
+
+ expect(err).to eq(<<~E.strip)
+ [DEPRECATED] Your Gemfile contains multiple global sources. Using `source` more than once without a block is a security risk, and may result in installing unexpected gems. To resolve this warning, use a block to indicate which gems should come from the secondary source.
+ Bundler found mismatched checksums. This is a potential security risk.
+ rack (1.0.0) sha256=#{rack_checksum}
+ from the API at https://gem.repo2/
+ and the API at https://gem.repo1/
+ #{checksum_to_lock(gem_repo2, "rack", "1.0.0")}
+ from the gem at #{default_bundle_path("cache", "rack-1.0.0.gem")}
+
+ If you trust the API at https://gem.repo2/, to resolve this issue you can:
+ 1. remove the gem at #{default_bundle_path("cache", "rack-1.0.0.gem")}
+ 2. run `bundle install`
+
+ To ignore checksum security warnings, disable checksum validation with
+ `bundle config set --local disable_checksum_validation true`
+ E
+ expect(exitstatus).to eq(37)
+ end
+
+ it "installs from the other source and warns about ambiguous gems when the sources have the same checksum", bundler: "< 3" do
+ gem_checksum = checksum_digest(gem_repo2, "rack", "1.0.0")
+ bundle :install, artifice: "compact_index", env: { "BUNDLER_SPEC_RACK_CHECKSUM" => gem_checksum, "DEBUG" => "1" }
+
expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
expect(err).to include("Installed from: https://gem.repo2")
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo3, "depends_on_rack", "1.0.1"
+ c.checksum gem_repo2, "rack", "1.0.0"
+ end
+
expect(lockfile).to eq <<~L
GEM
remote: https://gem.repo1/
@@ -262,11 +396,51 @@ RSpec.describe "bundle install with gems on multiple sources" do
rack
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
depends_on_rack!
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ previous_lockfile = lockfile
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
+ expect(lockfile).to eq(previous_lockfile)
+ end
+
+ it "installs from the other source and warns about ambiguous gems when checksum validation is disabled", bundler: "< 3" do
+ bundle "config set --local disable_checksum_validation true"
+ bundle :install, artifice: "compact_index"
+ expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
+ expect(err).to include("Installed from: https://gem.repo2")
+
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "depends_on_rack", "1.0.1"
+ c.no_checksum "rack", "1.0.0"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: https://gem.repo1/
+ remote: https://gem.repo2/
+ specs:
+ rack (1.0.0)
+
+ GEM
+ remote: https://gem.repo3/
+ specs:
+ depends_on_rack (1.0.1)
+ rack
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ depends_on_rack!
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -276,8 +450,8 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(lockfile).to eq(previous_lockfile)
end
- it "fails", :bundler => "3" do
- bundle :install, :artifice => "compact_index", :raise_on_error => false
+ it "fails", bundler: "3" do
+ bundle :install, artifice: "compact_index", raise_on_error: false
expect(err).to include("Each source after the first must include a block")
expect(exitstatus).to eq(4)
end
@@ -301,8 +475,8 @@ RSpec.describe "bundle install with gems on multiple sources" do
G
end
- it "installs the dependency from the pinned source without warning", :bundler => "< 3" do
- bundle :install, :artifice => "compact_index"
+ it "installs the dependency from the pinned source without warning", bundler: "< 3" do
+ bundle :install, artifice: "compact_index"
expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
@@ -310,14 +484,14 @@ RSpec.describe "bundle install with gems on multiple sources" do
# In https://github.com/rubygems/bundler/issues/3585 this failed
# when there is already a lock file, and the gems are missing, so try again
system_gems []
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
end
- it "fails", :bundler => "3" do
- bundle :install, :artifice => "compact_index", :raise_on_error => false
+ it "fails", bundler: "3" do
+ bundle :install, artifice: "compact_index", raise_on_error: false
expect(err).to include("Each source after the first must include a block")
expect(exitstatus).to eq(4)
end
@@ -345,13 +519,12 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "fails" do
- bundle :install, :artifice => "compact_index", :raise_on_error => false
- expect(err).to include("Could not find gem 'private_gem_1' in rubygems repository https://gem.repo2/ or installed locally.")
- expect(err).to include("The source does not contain any versions of 'private_gem_1'")
+ bundle :install, artifice: "compact_index", raise_on_error: false
+ expect(err).to include("Could not find gem 'private_gem_1' in rubygems repository https://gem.repo2/, cached gems or installed locally.")
end
end
- context "when an indirect dependency can't be found in the aggregate rubygems source", :bundler => "< 3" do
+ context "when an indirect dependency can't be found in the aggregate rubygems source", bundler: "< 3" do
before do
build_repo2
@@ -371,8 +544,16 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "fails" do
- bundle :install, :artifice => "compact_index", :raise_on_error => false
- expect(err).to include("Could not find gem 'missing', which is required by gem 'depends_on_missing', in any of the sources.")
+ bundle :install, artifice: "compact_index", raise_on_error: false
+ expect(err).to end_with <<~E.strip
+ Could not find compatible versions
+
+ Because every version of depends_on_missing depends on missing >= 0
+ and missing >= 0 could not be found in any of the sources,
+ depends_on_missing cannot be used.
+ So, because Gemfile depends on depends_on_missing >= 0,
+ version solving has failed.
+ E
end
end
@@ -407,11 +588,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs the dependency from the top-level source without warning" do
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0")
- expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote2")
- expect(the_bundle).to include_gems("unrelated_gem 1.0.0", :source => "remote3")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", source: "remote2")
+ expect(the_bundle).to include_gems("unrelated_gem 1.0.0", source: "remote3")
end
end
@@ -425,10 +606,16 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "does not find the dependency" do
- bundle :install, :artifice => "compact_index", :raise_on_error => false
- expect(err).to include(
- "Could not find gem 'rack', which is required by gem 'depends_on_rack', in rubygems repository https://gem.repo2/ or installed locally."
- )
+ bundle :install, artifice: "compact_index", raise_on_error: false
+ expect(err).to end_with <<~E.strip
+ Could not find compatible versions
+
+ Because every version of depends_on_rack depends on rack >= 0
+ and rack >= 0 could not be found in rubygems repository https://gem.repo2/, cached gems or installed locally,
+ depends_on_rack cannot be used.
+ So, because Gemfile depends on depends_on_rack >= 0,
+ version solving has failed.
+ E
end
end
@@ -446,12 +633,12 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs the dependency from the top-level source without warning" do
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).not_to include("Warning")
expect(run("require 'rack'; puts RACK")).to eq("1.0.0")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0")
- expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote2")
- expect(the_bundle).to include_gems("unrelated_gem 1.0.0", :source => "remote3")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", source: "remote2")
+ expect(the_bundle).to include_gems("unrelated_gem 1.0.0", source: "remote3")
end
end
end
@@ -485,10 +672,10 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs the dependency from the top-level source" do
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0")
- expect(the_bundle).to include_gems("rack 1.0.0", :source => "remote2")
- expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", :source => "remote3")
+ expect(the_bundle).to include_gems("rack 1.0.0", source: "remote2")
+ expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", source: "remote3")
end
end
@@ -502,8 +689,8 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs the dependency from the pinned source" do
- bundle :install, :artifice => "compact_index"
- expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
+ bundle :install, artifice: "compact_index"
+ expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0", source: "remote3")
end
end
@@ -521,8 +708,8 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs the dependency from the pinned source without warning" do
- bundle :install, :artifice => "compact_index"
- expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
+ bundle :install, artifice: "compact_index"
+ expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0", source: "remote3")
end
end
end
@@ -596,6 +783,21 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
G
+ @locked_checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo2, "activesupport", "6.0.3.4"
+ c.checksum gem_repo2, "concurrent-ruby", "1.1.8"
+ c.checksum gem_repo2, "connection_pool", "2.2.3"
+ c.checksum gem_repo2, "i18n", "1.8.9"
+ c.checksum gem_repo2, "minitest", "5.14.3"
+ c.checksum gem_repo2, "rack", "2.2.3"
+ c.checksum gem_repo2, "redis", "4.2.5"
+ c.checksum gem_repo2, "sidekiq", "6.1.3"
+ c.checksum gem_repo3, "sidekiq-pro", "5.2.1"
+ c.checksum gem_repo2, "thread_safe", "0.3.6"
+ c.checksum gem_repo2, "tzinfo", "1.2.9"
+ c.checksum gem_repo2, "zeitwerk", "2.4.2"
+ end
+
lockfile <<~L
GEM
remote: https://gem.repo2/
@@ -627,19 +829,19 @@ RSpec.describe "bundle install with gems on multiple sources" do
zeitwerk (2.4.2)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
activesupport
sidekiq-pro!
-
+ #{@locked_checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "does not install newer versions but updates the lockfile format when running bundle install in non frozen mode, and doesn't warn" do
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).to be_empty
expect(the_bundle).to include_gems("activesupport 6.0.3.4")
@@ -683,22 +885,22 @@ RSpec.describe "bundle install with gems on multiple sources" do
sidekiq (>= 6.1.0)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
activesupport
sidekiq-pro!
-
+ #{@locked_checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
end
- it "does not install newer versions or generate lockfile changes when running bundle install in frozen mode, and warns", :bundler => "< 3" do
+ it "does not install newer versions or generate lockfile changes when running bundle install in frozen mode, and warns", bundler: "< 3" do
initial_lockfile = lockfile
bundle "config set --local frozen true"
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
@@ -712,11 +914,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(lockfile).to eq(initial_lockfile)
end
- it "fails when running bundle install in frozen mode", :bundler => "3" do
+ it "fails when running bundle install in frozen mode", bundler: "3" do
initial_lockfile = lockfile
bundle "config set --local frozen true"
- bundle :install, :artifice => "compact_index", :raise_on_error => false
+ bundle :install, artifice: "compact_index", raise_on_error: false
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
@@ -724,15 +926,21 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "splits sections and upgrades gems when running bundle update, and doesn't warn" do
- bundle "update --all", :artifice => "compact_index"
+ bundle "update --all", artifice: "compact_index"
expect(err).to be_empty
expect(the_bundle).not_to include_gems("activesupport 6.0.3.4")
expect(the_bundle).to include_gems("activesupport 6.1.2.1")
+ @locked_checksums.checksum gem_repo2, "activesupport", "6.1.2.1"
+
expect(the_bundle).not_to include_gems("tzinfo 1.2.9")
expect(the_bundle).to include_gems("tzinfo 2.0.4")
+ @locked_checksums.checksum gem_repo2, "tzinfo", "2.0.4"
+ @locked_checksums.delete "thread_safe"
+
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8")
expect(the_bundle).to include_gems("concurrent-ruby 1.1.9")
+ @locked_checksums.checksum gem_repo2, "concurrent-ruby", "1.1.9"
expect(lockfile).to eq <<~L
GEM
@@ -767,19 +975,19 @@ RSpec.describe "bundle install with gems on multiple sources" do
sidekiq (>= 6.1.0)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
activesupport
sidekiq-pro!
-
+ #{@locked_checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "upgrades the lockfile format and upgrades the requested gem when running bundle update with an argument" do
- bundle "update concurrent-ruby", :artifice => "compact_index"
+ bundle "update concurrent-ruby", artifice: "compact_index"
expect(err).to be_empty
expect(the_bundle).to include_gems("activesupport 6.0.3.4")
@@ -789,6 +997,8 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(the_bundle).to include_gems("concurrent-ruby 1.1.9")
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8")
+ @locked_checksums.checksum gem_repo2, "concurrent-ruby", "1.1.9"
+
expect(lockfile).to eq <<~L
GEM
remote: https://gem.repo2/
@@ -823,12 +1033,12 @@ RSpec.describe "bundle install with gems on multiple sources" do
sidekiq (>= 6.1.0)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
activesupport
sidekiq-pro!
-
+ #{@locked_checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -837,8 +1047,8 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "when a top-level gem has an indirect dependency present in the default source, but with a different version from the one resolved" do
before do
- build_lib "activesupport", "7.0.0.alpha", :path => lib_path("rails/activesupport")
- build_lib "rails", "7.0.0.alpha", :path => lib_path("rails") do |s|
+ build_lib "activesupport", "7.0.0.alpha", path: lib_path("rails/activesupport")
+ build_lib "rails", "7.0.0.alpha", path: lib_path("rails") do |s|
s.add_dependency "activesupport", "= 7.0.0.alpha"
end
@@ -860,11 +1070,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs all gems without warning" do
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("activesupport 7.0.0.alpha", "rails 7.0.0.alpha")
- expect(the_bundle).to include_gems("activesupport 7.0.0.alpha", :source => "path@#{lib_path("rails/activesupport")}")
- expect(the_bundle).to include_gems("rails 7.0.0.alpha", :source => "path@#{lib_path("rails")}")
+ expect(the_bundle).to include_gems("activesupport 7.0.0.alpha", source: "path@#{lib_path("rails/activesupport")}")
+ expect(the_bundle).to include_gems("rails 7.0.0.alpha", source: "path@#{lib_path("rails")}")
end
end
@@ -896,6 +1106,12 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs from the default source without any warnings or errors and generates a proper lockfile" do
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo3, "handsoap", "0.2.5.5"
+ c.checksum gem_repo2, "nokogiri", "1.11.1"
+ c.checksum gem_repo2, "racca", "1.5.2"
+ end
+
expected_lockfile = <<~L
GEM
remote: https://gem.repo2/
@@ -911,30 +1127,30 @@ RSpec.describe "bundle install with gems on multiple sources" do
nokogiri (>= 1.2.3)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
handsoap!
nokogiri
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
- bundle "install --verbose", :artifice => "compact_index"
+ bundle "install --verbose", artifice: "compact_index"
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("handsoap 0.2.5.5", "nokogiri 1.11.1", "racca 1.5.2")
- expect(the_bundle).to include_gems("handsoap 0.2.5.5", :source => "remote3")
- expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", :source => "remote2")
+ expect(the_bundle).to include_gems("handsoap 0.2.5.5", source: "remote3")
+ expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", source: "remote2")
expect(lockfile).to eq(expected_lockfile)
# Even if the gems are already installed
FileUtils.rm bundled_app_lock
- bundle "install --verbose", :artifice => "compact_index"
+ bundle "install --verbose", artifice: "compact_index"
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("handsoap 0.2.5.5", "nokogiri 1.11.1", "racca 1.5.2")
- expect(the_bundle).to include_gems("handsoap 0.2.5.5", :source => "remote3")
- expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", :source => "remote2")
+ expect(the_bundle).to include_gems("handsoap 0.2.5.5", source: "remote3")
+ expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", source: "remote2")
expect(lockfile).to eq(expected_lockfile)
end
end
@@ -945,7 +1161,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "not_in_repo1", "1.0.0"
end
- install_gemfile <<-G, :artifice => "compact_index", :raise_on_error => false
+ install_gemfile <<-G, artifice: "compact_index", raise_on_error: false
source "https://gem.repo3"
gem "not_in_repo1", :source => "https://gem.repo1"
G
@@ -958,7 +1174,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "with an existing lockfile" do
before do
- system_gems "rack-0.9.1", "rack-1.0.0", :path => default_bundle_path
+ system_gems "rack-0.9.1", "rack-1.0.0", path: default_bundle_path
lockfile <<-L
GEM
@@ -971,7 +1187,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
rack (0.9.1)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
rack!
@@ -1001,11 +1217,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
rack (0.9.1)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
rack!
-
+ #{checksums_section}
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1023,7 +1239,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
rack (0.9.1)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
rack!
@@ -1048,20 +1264,48 @@ RSpec.describe "bundle install with gems on multiple sources" do
lockfile aggregate_gem_section_lockfile
end
- it "installs the existing lockfile but prints a warning", :bundler => "< 3" do
+ it "installs the existing lockfile but prints a warning when checksum validation is disabled", bundler: "< 3" do
bundle "config set --local deployment true"
+ bundle "config set --local disable_checksum_validation true"
- bundle "install", :artifice => "compact_index"
+ bundle "install", artifice: "compact_index"
expect(lockfile).to eq(aggregate_gem_section_lockfile)
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
- expect(the_bundle).to include_gems("rack 0.9.1", :source => "remote3")
+ expect(the_bundle).to include_gems("rack 0.9.1", source: "remote3")
end
- it "refuses to install the existing lockfile and prints an error", :bundler => "3" do
+ it "prints a checksum warning when the checksums from both sources do not match", bundler: "< 3" do
bundle "config set --local deployment true"
- bundle "install", :artifice => "compact_index", :raise_on_error =>false
+ bundle "install", artifice: "compact_index", raise_on_error: false
+
+ api_checksum1 = checksum_digest(gem_repo1, "rack", "0.9.1")
+ api_checksum3 = checksum_digest(gem_repo3, "rack", "0.9.1")
+
+ expect(exitstatus).to eq(37)
+ expect(err).to eq(<<~E.strip)
+ [DEPRECATED] Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure.
+ Bundler found mismatched checksums. This is a potential security risk.
+ rack (0.9.1) sha256=#{api_checksum3}
+ from the API at https://gem.repo3/
+ rack (0.9.1) sha256=#{api_checksum1}
+ from the API at https://gem.repo1/
+
+ Mismatched checksums each have an authoritative source:
+ 1. the API at https://gem.repo3/
+ 2. the API at https://gem.repo1/
+ You may need to alter your Gemfile sources to resolve this issue.
+
+ To ignore checksum security warnings, disable checksum validation with
+ `bundle config set --local disable_checksum_validation true`
+ E
+ end
+
+ it "refuses to install the existing lockfile and prints an error", bundler: "3" do
+ bundle "config set --local deployment true"
+
+ bundle "install", artifice: "compact_index", raise_on_error: false
expect(lockfile).to eq(aggregate_gem_section_lockfile)
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
@@ -1081,7 +1325,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "does not unlock the non-path gem after install" do
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
bundle %(exec ruby -e 'puts "OK"')
@@ -1094,7 +1338,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
before do
system_gems "rack-0.9.1"
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo1"
gem "rack" # should come from repo1!
G
@@ -1123,7 +1367,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
G
bundle "config set --local path ../gems/system"
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
# And then we add some new versions...
update_repo4 do
@@ -1134,7 +1378,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
it "allows them to be unlocked separately" do
# And install this gemfile, updating only foo.
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source 'https://gem.repo1'
gem 'rack'
gem 'foo', '~> 0.2', :source => 'https://gem.repo4'
@@ -1158,7 +1402,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_git "git1"
build_git "git2"
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo1"
gem "rails"
@@ -1174,7 +1418,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "does not re-resolve" do
- bundle :install, :artifice => "compact_index", :verbose => true
+ bundle :install, artifice: "compact_index", verbose: true
expect(out).to include("using resolution from the lockfile")
expect(out).not_to include("re-resolving dependencies")
end
@@ -1183,7 +1427,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "when a gem is installed to system gems" do
before do
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo1"
gem "rack"
G
@@ -1197,7 +1441,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
# When this gemfile is installed...
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo1"
source "https://gem.repo4" do
@@ -1219,14 +1463,14 @@ RSpec.describe "bundle install with gems on multiple sources" do
G
# But we should still be able to find rack 2.0.1.1.forked and install it
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
end
end
end
describe "source changed to one containing a higher version of a dependency" do
before do
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo1"
gem "rack"
@@ -1240,19 +1484,45 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "bar"
end
- build_lib("gemspec_test", :path => tmp.join("gemspec_test")) do |s|
+ build_lib("gemspec_test", path: tmp.join("gemspec_test")) do |s|
s.add_dependency "bar", "=1.0.0"
end
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo2"
gem "rack"
gemspec :path => "#{tmp.join("gemspec_test")}"
G
end
- it "installs the higher version in the new repo" do
- expect(the_bundle).to include_gems("rack 1.2")
+ it "conservatively installs the existing locked version" do
+ expect(the_bundle).to include_gems("rack 1.0.0")
+ end
+ end
+
+ context "when Gemfile overrides a gemspec development dependency to change the default source" do
+ before do
+ build_repo4 do
+ build_gem "bar"
+ end
+
+ build_lib("gemspec_test", path: tmp.join("gemspec_test")) do |s|
+ s.add_development_dependency "bar"
+ end
+
+ install_gemfile <<-G, artifice: "compact_index"
+ source "https://gem.repo1"
+
+ source "https://gem.repo4" do
+ gem "bar"
+ end
+
+ gemspec :path => "#{tmp.join("gemspec_test")}"
+ G
+ end
+
+ it "does not print warnings" do
+ expect(err).to be_empty
end
end
@@ -1265,7 +1535,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "example", "1.0.2"
end
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo4"
gem "example", :source => "https://gem.repo2"
@@ -1274,14 +1544,14 @@ RSpec.describe "bundle install with gems on multiple sources" do
bundle "info example"
expect(out).to include("example (0.1.0)")
- system_gems "example-1.0.2", :path => default_bundle_path, :gem_repo => gem_repo4
+ system_gems "example-1.0.2", path: default_bundle_path, gem_repo: gem_repo4
- bundle "update example --verbose", :artifice => "compact_index"
+ bundle "update example --verbose", artifice: "compact_index"
expect(out).not_to include("Using example 1.0.2")
expect(out).to include("Using example 0.1.0")
end
- it "fails inmmediately with a helpful error when a non retriable network error happens while resolving sources" do
+ it "fails immediately with a helpful error when a rubygems source does not exist and bundler/setup is required" do
gemfile <<-G
source "https://gem.repo1"
@@ -1290,17 +1560,30 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
G
- simulate_bundler_version_when_missing_prerelease_default_gem_activation do
- ruby <<~R, :raise_on_error => false
- require 'bundler/setup'
- R
- end
+ ruby <<~R, raise_on_error: false
+ require 'bundler/setup'
+ R
+
+ expect(last_command).to be_failure
+ expect(err).to include("Could not find gem 'example' in locally installed gems.")
+ end
+
+ it "fails immediately with a helpful error when a non retriable network error happens while resolving sources" do
+ gemfile <<-G
+ source "https://gem.repo1"
+
+ source "https://gem.repo4" do
+ gem "example"
+ end
+ G
+
+ bundle "install", artifice: nil, raise_on_error: false
expect(last_command).to be_failure
expect(err).to include("Could not reach host gem.repo4. Check your network connection and try again.")
end
- context "when an indirect dependency is available from multiple ambiguous sources", :bundler => "< 3" do
+ context "when an indirect dependency is available from multiple ambiguous sources", bundler: "< 3" do
it "succeeds but warns, suggesting a source block" do
build_repo4 do
build_gem "depends_on_rack" do |s|
@@ -1309,7 +1592,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "rack"
end
- install_gemfile <<-G, :artifice => "compact_index", :raise_on_error => false
+ install_gemfile <<-G, artifice: "compact_index", raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
source "https://gem.repo4" do
@@ -1320,10 +1603,10 @@ RSpec.describe "bundle install with gems on multiple sources" do
gem "thin"
end
G
- expect(err).to eq strip_whitespace(<<-EOS).strip
+ expect(err).to eq <<~EOS.strip
Warning: The gem 'rack' was found in multiple relevant sources.
- * rubygems repository https://gem.repo1/ or installed locally
- * rubygems repository https://gem.repo4/ or installed locally
+ * rubygems repository https://gem.repo1/
+ * rubygems repository https://gem.repo4/
You should add this gem to the source block for the source you wish it to be installed from.
EOS
expect(last_command).to be_success
@@ -1331,7 +1614,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
end
- context "when an indirect dependency is available from multiple ambiguous sources", :bundler => "3" do
+ context "when an indirect dependency is available from multiple ambiguous sources", bundler: "3" do
it "raises, suggesting a source block" do
build_repo4 do
build_gem "depends_on_rack" do |s|
@@ -1340,7 +1623,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "rack"
end
- install_gemfile <<-G, :artifice => "compact_index", :raise_on_error => false
+ install_gemfile <<-G, artifice: "compact_index", raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
source "https://gem.repo4" do
gem "depends_on_rack"
@@ -1350,10 +1633,10 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
G
expect(last_command).to be_failure
- expect(err).to eq strip_whitespace(<<-EOS).strip
+ expect(err).to eq <<~EOS.strip
The gem 'rack' was found in multiple relevant sources.
- * rubygems repository https://gem.repo1/ or installed locally
- * rubygems repository https://gem.repo4/ or installed locally
+ * rubygems repository https://gem.repo1/
+ * rubygems repository https://gem.repo4/
You must add this gem to the source block for the source you wish it to be installed from.
EOS
expect(the_bundle).not_to be_locked
@@ -1394,16 +1677,23 @@ RSpec.describe "bundle install with gems on multiple sources" do
mime-types (3.3.1)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
capybara (~> 2.5.0)
mime-types (~> 3.0)!
+
+ CHECKSUMS
L
end
it "upgrades the lockfile correctly" do
- bundle "lock --update", :artifice => "compact_index"
+ bundle "lock --update", artifice: "compact_index"
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo2, "capybara", "2.5.0"
+ c.checksum gem_repo4, "mime-types", "3.0.0"
+ end
expect(lockfile).to eq <<~L
GEM
@@ -1418,15 +1708,215 @@ RSpec.describe "bundle install with gems on multiple sources" do
mime-types (3.0.0)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
capybara (~> 2.5.0)
mime-types (~> 3.0)!
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ context "when default source includes old gems with nil required_ruby_version" do
+ before do
+ build_repo2 do
+ build_gem "ruport", "1.7.0.3" do |s|
+ s.add_dependency "pdf-writer", "1.1.8"
+ end
+ end
+
+ build_repo gem_repo4 do
+ build_gem "pdf-writer", "1.1.8"
+ end
+
+ path = "#{gem_repo4}/#{Gem::MARSHAL_SPEC_DIR}/pdf-writer-1.1.8.gemspec.rz"
+ spec = Marshal.load(Bundler.rubygems.inflate(File.binread(path)))
+ spec.instance_variable_set(:@required_ruby_version, nil)
+ File.open(path, "wb") do |f|
+ f.write Gem.deflate(Marshal.dump(spec))
+ end
+
+ gemfile <<~G
+ source "https://localgemserver.test"
+
+ gem "ruport", "= 1.7.0.3", :source => "https://localgemserver.test/extra"
+ G
+ end
+
+ it "handles that fine" do
+ bundle "install", artifice: "compact_index_extra", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "pdf-writer", "1.1.8"
+ c.checksum gem_repo2, "ruport", "1.7.0.3"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: https://localgemserver.test/
+ specs:
+ pdf-writer (1.1.8)
+
+ GEM
+ remote: https://localgemserver.test/extra/
+ specs:
+ ruport (1.7.0.3)
+ pdf-writer (= 1.1.8)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ruport (= 1.7.0.3)!
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ context "when default source includes old gems with nil required_rubygems_version" do
+ before do
+ build_repo2 do
+ build_gem "ruport", "1.7.0.3" do |s|
+ s.add_dependency "pdf-writer", "1.1.8"
+ end
+ end
+
+ build_repo gem_repo4 do
+ build_gem "pdf-writer", "1.1.8"
+ end
+
+ path = "#{gem_repo4}/#{Gem::MARSHAL_SPEC_DIR}/pdf-writer-1.1.8.gemspec.rz"
+ spec = Marshal.load(Bundler.rubygems.inflate(File.binread(path)))
+ spec.instance_variable_set(:@required_rubygems_version, nil)
+ File.open(path, "wb") do |f|
+ f.write Gem.deflate(Marshal.dump(spec))
+ end
+
+ gemfile <<~G
+ source "https://localgemserver.test"
+
+ gem "ruport", "= 1.7.0.3", :source => "https://localgemserver.test/extra"
+ G
+ end
+ it "handles that fine" do
+ bundle "install", artifice: "compact_index_extra", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "pdf-writer", "1.1.8"
+ c.checksum gem_repo2, "ruport", "1.7.0.3"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: https://localgemserver.test/
+ specs:
+ pdf-writer (1.1.8)
+
+ GEM
+ remote: https://localgemserver.test/extra/
+ specs:
+ ruport (1.7.0.3)
+ pdf-writer (= 1.1.8)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ruport (= 1.7.0.3)!
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ context "when default source uses the old API and includes old gems with nil required_rubygems_version" do
+ before do
+ build_repo4 do
+ build_gem "pdf-writer", "1.1.8"
+ end
+
+ path = "#{gem_repo4}/#{Gem::MARSHAL_SPEC_DIR}/pdf-writer-1.1.8.gemspec.rz"
+ spec = Marshal.load(Bundler.rubygems.inflate(File.binread(path)))
+ spec.instance_variable_set(:@required_rubygems_version, nil)
+ File.open(path, "wb") do |f|
+ f.write Gem.deflate(Marshal.dump(spec))
+ end
+
+ gemfile <<~G
+ source "https://localgemserver.test"
+
+ gem "pdf-writer", "= 1.1.8"
+ G
+ end
+
+ it "handles that fine" do
+ bundle "install --verbose", artifice: "endpoint", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "pdf-writer", "1.1.8"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: https://localgemserver.test/
+ specs:
+ pdf-writer (1.1.8)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ pdf-writer (= 1.1.8)
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
end
end
+
+ context "when mistakenly adding a top level gem already depended on and cached under the wrong source" do
+ before do
+ build_repo4 do
+ build_gem "some_private_gem", "0.1.0" do |s|
+ s.add_dependency "example", "~> 1.0"
+ end
+ end
+
+ build_repo2 do
+ build_gem "example", "1.0.0"
+ end
+
+ install_gemfile <<~G, artifice: "compact_index"
+ source "https://gem.repo2"
+
+ source "https://gem.repo4" do
+ gem "some_private_gem"
+ end
+ G
+
+ gemfile <<~G
+ source "https://gem.repo2"
+
+ source "https://gem.repo4" do
+ gem "some_private_gem"
+ gem "example" # MISTAKE, example is not available at gem.repo4
+ end
+ G
+ end
+
+ it "shows a proper error message and does not generate a corrupted lockfile" do
+ expect do
+ bundle :install, artifice: "compact_index", raise_on_error: false, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ end.not_to change { lockfile }
+
+ expect(err).to include("Could not find gem 'example' in rubygems repository https://gem.repo4/")
+ end
+ end
end
diff --git a/spec/bundler/install/gemfile/specific_platform_spec.rb b/spec/bundler/install/gemfile/specific_platform_spec.rb
index 4c24f09368..5f1b034bfc 100644
--- a/spec/bundler/install/gemfile/specific_platform_spec.rb
+++ b/spec/bundler/install/gemfile/specific_platform_spec.rb
@@ -6,29 +6,29 @@ RSpec.describe "bundle install with specific platforms" do
gem "google-protobuf"
G
- context "when on a darwin machine" do
- before { simulate_platform "x86_64-darwin-15" }
-
- it "locks to the specific darwin platform" do
+ it "locks to the specific darwin platform" do
+ simulate_platform "x86_64-darwin-15" do
setup_multiplatform_gem
install_gemfile(google_protobuf)
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- expect(the_bundle.locked_gems.platforms).to eq([pl("x86_64-darwin-15")])
+ expect(the_bundle.locked_gems.platforms).to include(pl("x86_64-darwin-15"))
expect(the_bundle).to include_gem("google-protobuf 3.0.0.alpha.5.0.5.1 universal-darwin")
- expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[
- google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin
- ])
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to include(
+ "google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin"
+ )
end
+ end
- it "understands that a non-plaform specific gem in a old lockfile doesn't necessarily mean installing the non-specific variant" do
+ it "understands that a non-platform specific gem in a old lockfile doesn't necessarily mean installing the non-specific variant" do
+ simulate_platform "x86_64-darwin-15" do
setup_multiplatform_gem
system_gems "bundler-2.1.4"
# Consistent location to install and look for gems
- bundle "config set --local path vendor/bundle", :env => { "BUNDLER_VERSION" => "2.1.4" }
+ bundle "config set --local path vendor/bundle", env: { "BUNDLER_VERSION" => "2.1.4" }
- install_gemfile(google_protobuf, :env => { "BUNDLER_VERSION" => "2.1.4" })
+ install_gemfile(google_protobuf, env: { "BUNDLER_VERSION" => "2.1.4" })
# simulate lockfile created with old bundler, which only locks for ruby platform
lockfile <<-L
@@ -48,22 +48,28 @@ RSpec.describe "bundle install with specific platforms" do
L
# force strict usage of the lock file by setting frozen mode
- bundle "config set --local frozen true", :env => { "BUNDLER_VERSION" => "2.1.4" }
+ bundle "config set --local frozen true", env: { "BUNDLER_VERSION" => "2.1.4" }
# make sure the platform that got actually installed with the old bundler is used
expect(the_bundle).to include_gem("google-protobuf 3.0.0.alpha.5.0.5.1 universal-darwin")
end
+ end
- it "understands that a non-plaform specific gem in a new lockfile locked only to RUBY doesn't necessarily mean installing the non-specific variant" do
+ it "understands that a non-platform specific gem in a new lockfile locked only to RUBY doesn't necessarily mean installing the non-specific variant" do
+ simulate_platform "x86_64-darwin-15" do
setup_multiplatform_gem
system_gems "bundler-2.1.4"
# Consistent location to install and look for gems
- bundle "config set --local path vendor/bundle", :env => { "BUNDLER_VERSION" => "2.1.4" }
+ bundle "config set --local path vendor/bundle", env: { "BUNDLER_VERSION" => "2.1.4" }
gemfile google_protobuf
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo2, "google-protobuf", "3.0.0.alpha.4.0"
+ end
+
# simulate lockfile created with old bundler, which only locks for ruby platform
lockfile <<-L
GEM
@@ -76,18 +82,20 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
google-protobuf
-
+ #{checksums}
BUNDLED WITH
2.1.4
L
- bundle "update", :env => { "BUNDLER_VERSION" => Bundler::VERSION }
+ bundle "update", env: { "BUNDLER_VERSION" => Bundler::VERSION }
+
+ checksums.checksum gem_repo2, "google-protobuf", "3.0.0.alpha.5.0.5.1"
# make sure the platform that the platform specific dependency is used, since we're only locked to ruby
expect(the_bundle).to include_gem("google-protobuf 3.0.0.alpha.5.0.5.1 universal-darwin")
# make sure we're still only locked to ruby
- lockfile_should_be <<-L
+ expect(lockfile).to eq <<~L
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -98,13 +106,61 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
google-protobuf
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ context "when running on a legacy lockfile locked only to RUBY" do
+ around do |example|
+ build_repo4 do
+ build_gem "nokogiri", "1.3.10"
+ build_gem "nokogiri", "1.3.10" do |s|
+ s.platform = "arm64-darwin"
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "nokogiri"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ nokogiri (1.3.10)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ nokogiri
BUNDLED WITH
#{Bundler::VERSION}
L
+
+ simulate_platform "arm64-darwin-22", &example
end
- it "doesn't discard previously installed platform specific gem and fall back to ruby on subsequent bundles" do
+ it "still installs the generic RUBY variant if necessary" do
+ bundle "install --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ expect(out).to include("Installing nokogiri 1.3.10")
+ end
+
+ it "still installs the generic RUBY variant if necessary, even in frozen mode" do
+ bundle "install --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s, "BUNDLE_FROZEN" => "true" }
+ expect(out).to include("Installing nokogiri 1.3.10")
+ end
+ end
+
+ it "doesn't discard previously installed platform specific gem and fall back to ruby on subsequent bundles" do
+ simulate_platform "x86_64-darwin-15" do
build_repo2 do
build_gem("libv8", "8.4.255.0")
build_gem("libv8", "8.4.255.0") {|s| s.platform = "universal-darwin" }
@@ -117,7 +173,7 @@ RSpec.describe "bundle install with specific platforms" do
system_gems "bundler-2.1.4"
# Consistent location to install and look for gems
- bundle "config set --local path vendor/bundle", :env => { "BUNDLER_VERSION" => "2.1.4" }
+ bundle "config set --local path vendor/bundle", env: { "BUNDLER_VERSION" => "2.1.4" }
gemfile <<-G
source "https://localgemserver.test"
@@ -141,14 +197,50 @@ RSpec.describe "bundle install with specific platforms" do
2.1.4
L
- bundle "install --verbose", :artifice => "compact_index", :env => { "BUNDLER_VERSION" => "2.1.4", "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ bundle "install --verbose", artifice: "compact_index", env: { "BUNDLER_VERSION" => "2.1.4", "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(out).to include("Installing libv8 8.4.255.0 (universal-darwin)")
- bundle "add mini_racer --verbose", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ bundle "add mini_racer --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(out).to include("Using libv8 8.4.255.0 (universal-darwin)")
end
+ end
- it "caches the universal-darwin gem when --all-platforms is passed and properly picks it up on further bundler invocations" do
+ it "chooses platform specific gems even when resolving upon materialization and the API returns more specific platforms first" do
+ simulate_platform "x86_64-darwin-15" do
+ build_repo4 do
+ build_gem("grpc", "1.50.0")
+ build_gem("grpc", "1.50.0") {|s| s.platform = "universal-darwin" }
+ end
+
+ gemfile <<-G
+ source "https://localgemserver.test"
+ gem "grpc"
+ G
+
+ # simulate lockfile created with old bundler, which only locks for ruby platform
+ lockfile <<-L
+ GEM
+ remote: https://localgemserver.test/
+ specs:
+ grpc (1.50.0)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ grpc
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install --verbose", artifice: "compact_index_precompiled_before", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ expect(out).to include("Installing grpc 1.50.0 (universal-darwin)")
+ end
+ end
+
+ it "caches the universal-darwin gem when --all-platforms is passed and properly picks it up on further bundler invocations" do
+ simulate_platform "x86_64-darwin-15" do
setup_multiplatform_gem
gemfile(google_protobuf)
bundle "cache --all-platforms"
@@ -157,8 +249,10 @@ RSpec.describe "bundle install with specific platforms" do
bundle "install --verbose"
expect(err).to be_empty
end
+ end
- it "caches the universal-darwin gem when cache_all_platforms is configured and properly picks it up on further bundler invocations" do
+ it "caches the universal-darwin gem when cache_all_platforms is configured and properly picks it up on further bundler invocations" do
+ simulate_platform "x86_64-darwin-15" do
setup_multiplatform_gem
gemfile(google_protobuf)
bundle "config set --local cache_all_platforms true"
@@ -168,44 +262,46 @@ RSpec.describe "bundle install with specific platforms" do
bundle "install --verbose"
expect(err).to be_empty
end
+ end
- it "caches multiplatform git gems with a single gemspec when --all-platforms is passed" do
- git = build_git "pg_array_parser", "1.0"
+ it "caches multiplatform git gems with a single gemspec when --all-platforms is passed" do
+ git = build_git "pg_array_parser", "1.0"
- gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "pg_array_parser", :git => "#{lib_path("pg_array_parser-1.0")}"
- G
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "pg_array_parser", :git => "#{lib_path("pg_array_parser-1.0")}"
+ G
- lockfile <<-L
- GIT
- remote: #{lib_path("pg_array_parser-1.0")}
- revision: #{git.ref_for("master")}
- specs:
- pg_array_parser (1.0-java)
- pg_array_parser (1.0)
+ lockfile <<-L
+ GIT
+ remote: #{lib_path("pg_array_parser-1.0")}
+ revision: #{git.ref_for("main")}
+ specs:
+ pg_array_parser (1.0-java)
+ pg_array_parser (1.0)
- GEM
- specs:
+ GEM
+ specs:
- PLATFORMS
- java
- #{lockfile_platforms}
+ PLATFORMS
+ java
+ #{lockfile_platforms}
- DEPENDENCIES
- pg_array_parser!
+ DEPENDENCIES
+ pg_array_parser!
- BUNDLED WITH
- #{Bundler::VERSION}
- L
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
- bundle "config set --local cache_all true"
- bundle "cache --all-platforms"
+ bundle "config set --local cache_all true"
+ bundle "cache --all-platforms"
- expect(err).to be_empty
- end
+ expect(err).to be_empty
+ end
- it "uses the platform-specific gem with extra dependencies" do
+ it "uses the platform-specific gem with extra dependencies" do
+ simulate_platform "x86_64-darwin-15" do
setup_multiplatform_gem_with_different_dependencies_per_platform
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
@@ -213,47 +309,52 @@ RSpec.describe "bundle install with specific platforms" do
G
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- expect(the_bundle.locked_gems.platforms).to eq([pl("x86_64-darwin-15")])
+ expect(the_bundle.locked_gems.platforms).to include(pl("x86_64-darwin-15"))
expect(the_bundle).to include_gems("facter 2.4.6 universal-darwin", "CFPropertyList 1.0")
- expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(["CFPropertyList-1.0",
- "facter-2.4.6-universal-darwin"])
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to include("CFPropertyList-1.0",
+ "facter-2.4.6-universal-darwin")
end
+ end
- context "when adding a platform via lock --add_platform" do
- before do
- allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- end
+ context "when adding a platform via lock --add_platform" do
+ before do
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
+ end
- it "adds the foreign platform" do
+ it "adds the foreign platform" do
+ simulate_platform "x86_64-darwin-15" do
setup_multiplatform_gem
install_gemfile(google_protobuf)
- bundle "lock --add-platform=#{x64_mingw}"
+ bundle "lock --add-platform=#{x64_mingw32}"
- expect(the_bundle.locked_gems.platforms).to eq([x64_mingw, pl("x86_64-darwin-15")])
- expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[
+ expect(the_bundle.locked_gems.platforms).to include(x64_mingw32, pl("x86_64-darwin-15"))
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to include(*%w[
google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin
google-protobuf-3.0.0.alpha.5.0.5.1-x64-mingw32
])
end
+ end
- it "falls back on plain ruby when that version doesnt have a platform-specific gem" do
+ it "falls back on plain ruby when that version doesn't have a platform-specific gem" do
+ simulate_platform "x86_64-darwin-15" do
setup_multiplatform_gem
install_gemfile(google_protobuf)
bundle "lock --add-platform=#{java}"
- expect(the_bundle.locked_gems.platforms).to eq([java, pl("x86_64-darwin-15")])
- expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[
- google-protobuf-3.0.0.alpha.5.0.5.1
- google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin
- ])
+ expect(the_bundle.locked_gems.platforms).to include(java, pl("x86_64-darwin-15"))
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to include(
+ "google-protobuf-3.0.0.alpha.5.0.5.1",
+ "google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin"
+ )
end
end
end
- it "installs sorbet-static, which does not provide a pure ruby variant, just fine on truffleruby", :truffleruby do
+ it "installs sorbet-static, which does not provide a pure ruby variant, just fine", :truffleruby do
+ skip "does not apply to Windows" if Gem.win_platform?
+
build_repo2 do
- build_gem("sorbet-static", "0.5.6403") {|s| s.platform = "x86_64-linux" }
- build_gem("sorbet-static", "0.5.6403") {|s| s.platform = "universal-darwin-20" }
+ build_gem("sorbet-static", "0.5.6403") {|s| s.platform = Bundler.local_platform }
end
gemfile <<~G
@@ -266,8 +367,7 @@ RSpec.describe "bundle install with specific platforms" do
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
- sorbet-static (0.5.6403-universal-darwin-20)
- sorbet-static (0.5.6403-x86_64-linux)
+ sorbet-static (0.5.6403-#{Bundler.local_platform})
PLATFORMS
ruby
@@ -282,6 +382,1004 @@ RSpec.describe "bundle install with specific platforms" do
bundle "install --verbose"
end
+ it "does not resolve if the current platform does not match any of available platform specific variants for a top level dependency" do
+ build_repo4 do
+ build_gem("sorbet-static", "0.5.6433") {|s| s.platform = "x86_64-linux" }
+ build_gem("sorbet-static", "0.5.6433") {|s| s.platform = "universal-darwin-20" }
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "sorbet-static", "0.5.6433"
+ G
+
+ error_message = <<~ERROR.strip
+ Could not find gem 'sorbet-static (= 0.5.6433)' with platform 'arm64-darwin-21' in rubygems repository #{file_uri_for(gem_repo4)}/, cached gems or installed locally.
+
+ The source contains the following gems matching 'sorbet-static (= 0.5.6433)':
+ * sorbet-static-0.5.6433-universal-darwin-20
+ * sorbet-static-0.5.6433-x86_64-linux
+ ERROR
+
+ simulate_platform "arm64-darwin-21" do
+ bundle "lock", raise_on_error: false
+ end
+
+ expect(err).to include(error_message).once
+
+ # Make sure it doesn't print error twice in verbose mode
+
+ simulate_platform "arm64-darwin-21" do
+ bundle "lock --verbose", raise_on_error: false
+ end
+
+ expect(err).to include(error_message).once
+ end
+
+ it "does not resolve if the current platform does not match any of available platform specific variants for a transitive dependency" do
+ build_repo4 do
+ build_gem("sorbet", "0.5.6433") {|s| s.add_dependency "sorbet-static", "= 0.5.6433" }
+ build_gem("sorbet-static", "0.5.6433") {|s| s.platform = "x86_64-linux" }
+ build_gem("sorbet-static", "0.5.6433") {|s| s.platform = "universal-darwin-20" }
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "sorbet", "0.5.6433"
+ G
+
+ error_message = <<~ERROR.strip
+ Could not find compatible versions
+
+ Because every version of sorbet depends on sorbet-static = 0.5.6433
+ and sorbet-static = 0.5.6433 could not be found in rubygems repository #{file_uri_for(gem_repo4)}/, cached gems or installed locally for any resolution platforms (arm64-darwin-21),
+ sorbet cannot be used.
+ So, because Gemfile depends on sorbet = 0.5.6433,
+ version solving has failed.
+
+ The source contains the following gems matching 'sorbet-static (= 0.5.6433)':
+ * sorbet-static-0.5.6433-universal-darwin-20
+ * sorbet-static-0.5.6433-x86_64-linux
+ ERROR
+
+ simulate_platform "arm64-darwin-21" do
+ bundle "lock", raise_on_error: false
+ end
+
+ expect(err).to include(error_message).once
+
+ # Make sure it doesn't print error twice in verbose mode
+
+ simulate_platform "arm64-darwin-21" do
+ bundle "lock --verbose", raise_on_error: false
+ end
+
+ expect(err).to include(error_message).once
+ end
+
+ it "does not generate a lockfile if RUBY platform is forced and some gem has no RUBY variant available" do
+ build_repo4 do
+ build_gem("sorbet-static", "0.5.9889") {|s| s.platform = Gem::Platform.local }
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "sorbet-static", "0.5.9889"
+ G
+
+ bundle "lock", raise_on_error: false, env: { "BUNDLE_FORCE_RUBY_PLATFORM" => "true" }
+
+ expect(err).to include <<~ERROR.rstrip
+ Could not find gem 'sorbet-static (= 0.5.9889)' with platform 'ruby' in rubygems repository #{file_uri_for(gem_repo4)}/, cached gems or installed locally.
+
+ The source contains the following gems matching 'sorbet-static (= 0.5.9889)':
+ * sorbet-static-0.5.9889-#{Gem::Platform.local}
+ ERROR
+ end
+
+ it "automatically fixes the lockfile if RUBY platform is locked and some gem has no RUBY variant available" do
+ build_repo4 do
+ build_gem("sorbet-static-and-runtime", "0.5.10160") do |s|
+ s.add_runtime_dependency "sorbet", "= 0.5.10160"
+ s.add_runtime_dependency "sorbet-runtime", "= 0.5.10160"
+ end
+
+ build_gem("sorbet", "0.5.10160") do |s|
+ s.add_runtime_dependency "sorbet-static", "= 0.5.10160"
+ end
+
+ build_gem("sorbet-runtime", "0.5.10160")
+
+ build_gem("sorbet-static", "0.5.10160") do |s|
+ s.platform = Gem::Platform.local
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "sorbet-static-and-runtime"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ sorbet (0.5.10160)
+ sorbet-static (= 0.5.10160)
+ sorbet-runtime (0.5.10160)
+ sorbet-static (0.5.10160-#{Gem::Platform.local})
+ sorbet-static-and-runtime (0.5.10160)
+ sorbet (= 0.5.10160)
+ sorbet-runtime (= 0.5.10160)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ sorbet-static-and-runtime
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "update"
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "sorbet", "0.5.10160"
+ c.checksum gem_repo4, "sorbet-runtime", "0.5.10160"
+ c.checksum gem_repo4, "sorbet-static", "0.5.10160", Gem::Platform.local
+ c.checksum gem_repo4, "sorbet-static-and-runtime", "0.5.10160"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ sorbet (0.5.10160)
+ sorbet-static (= 0.5.10160)
+ sorbet-runtime (0.5.10160)
+ sorbet-static (0.5.10160-#{Gem::Platform.local})
+ sorbet-static-and-runtime (0.5.10160)
+ sorbet (= 0.5.10160)
+ sorbet-runtime (= 0.5.10160)
+
+ PLATFORMS
+ #{local_platform}
+
+ DEPENDENCIES
+ sorbet-static-and-runtime
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "automatically fixes the lockfile if both RUBY platform and a more specific platform are locked, and some gem has no RUBY variant available" do
+ build_repo4 do
+ build_gem "nokogiri", "1.12.0"
+ build_gem "nokogiri", "1.12.0" do |s|
+ s.platform = "x86_64-darwin"
+ end
+
+ build_gem "nokogiri", "1.13.0"
+ build_gem "nokogiri", "1.13.0" do |s|
+ s.platform = "x86_64-darwin"
+ end
+
+ build_gem("sorbet-static", "0.5.10601") do |s|
+ s.platform = "x86_64-darwin"
+ end
+ end
+
+ simulate_platform "x86_64-darwin-22" do
+ install_gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "nokogiri"
+ gem "sorbet-static"
+ G
+ end
+
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "nokogiri", "1.13.0", "x86_64-darwin"
+ c.no_checksum "sorbet-static", "0.5.10601", "x86_64-darwin"
+ end
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ nokogiri (1.12.0)
+ nokogiri (1.12.0-x86_64-darwin)
+ sorbet-static (0.5.10601-x86_64-darwin)
+
+ PLATFORMS
+ ruby
+ x86_64-darwin
+
+ DEPENDENCIES
+ nokogiri
+ sorbet-static
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ simulate_platform "x86_64-darwin-22" do
+ bundle "update --conservative nokogiri"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ nokogiri (1.13.0-x86_64-darwin)
+ sorbet-static (0.5.10601-x86_64-darwin)
+
+ PLATFORMS
+ x86_64-darwin
+
+ DEPENDENCIES
+ nokogiri
+ sorbet-static
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "automatically fixes the lockfile if only RUBY platform is locked and some gem has no RUBY variant available" do
+ build_repo4 do
+ build_gem("sorbet-static-and-runtime", "0.5.10160") do |s|
+ s.add_runtime_dependency "sorbet", "= 0.5.10160"
+ s.add_runtime_dependency "sorbet-runtime", "= 0.5.10160"
+ end
+
+ build_gem("sorbet", "0.5.10160") do |s|
+ s.add_runtime_dependency "sorbet-static", "= 0.5.10160"
+ end
+
+ build_gem("sorbet-runtime", "0.5.10160")
+
+ build_gem("sorbet-static", "0.5.10160") do |s|
+ s.platform = Gem::Platform.local
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "sorbet-static-and-runtime"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ sorbet (0.5.10160)
+ sorbet-static (= 0.5.10160)
+ sorbet-runtime (0.5.10160)
+ sorbet-static (0.5.10160-#{Gem::Platform.local})
+ sorbet-static-and-runtime (0.5.10160)
+ sorbet (= 0.5.10160)
+ sorbet-runtime (= 0.5.10160)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ sorbet-static-and-runtime
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "update"
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "sorbet", "0.5.10160"
+ c.checksum gem_repo4, "sorbet-runtime", "0.5.10160"
+ c.checksum gem_repo4, "sorbet-static", "0.5.10160", Gem::Platform.local
+ c.checksum gem_repo4, "sorbet-static-and-runtime", "0.5.10160"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ sorbet (0.5.10160)
+ sorbet-static (= 0.5.10160)
+ sorbet-runtime (0.5.10160)
+ sorbet-static (0.5.10160-#{Gem::Platform.local})
+ sorbet-static-and-runtime (0.5.10160)
+ sorbet (= 0.5.10160)
+ sorbet-runtime (= 0.5.10160)
+
+ PLATFORMS
+ #{local_platform}
+
+ DEPENDENCIES
+ sorbet-static-and-runtime
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "automatically fixes the lockfile if multiple platforms locked, but no valid versions of direct dependencies for all of them" do
+ simulate_platform "x86_64-linux" do
+ build_repo4 do
+ build_gem "nokogiri", "1.14.0" do |s|
+ s.platform = "x86_64-linux"
+ end
+ build_gem "nokogiri", "1.14.0" do |s|
+ s.platform = "arm-linux"
+ end
+
+ build_gem "sorbet-static", "0.5.10696" do |s|
+ s.platform = "x86_64-linux"
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "nokogiri"
+ gem "sorbet-static"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ nokogiri (1.14.0-arm-linux)
+ nokogiri (1.14.0-x86_64-linux)
+ sorbet-static (0.5.10696-x86_64-linux)
+
+ PLATFORMS
+ aarch64-linux
+ arm-linux
+ x86_64-linux
+
+ DEPENDENCIES
+ nokogiri
+ sorbet-static
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "update"
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "nokogiri", "1.14.0", "x86_64-linux"
+ c.checksum gem_repo4, "sorbet-static", "0.5.10696", "x86_64-linux"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ nokogiri (1.14.0-x86_64-linux)
+ sorbet-static (0.5.10696-x86_64-linux)
+
+ PLATFORMS
+ x86_64-linux
+
+ DEPENDENCIES
+ nokogiri
+ sorbet-static
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ it "automatically fixes the lockfile without removing other variants if it's missing platform gems, but they are installed locally" do
+ simulate_platform "x86_64-darwin-21" do
+ build_repo4 do
+ build_gem("sorbet-static", "0.5.10549") do |s|
+ s.platform = "universal-darwin-20"
+ end
+
+ build_gem("sorbet-static", "0.5.10549") do |s|
+ s.platform = "universal-darwin-21"
+ end
+ end
+
+ # Make sure sorbet-static-0.5.10549-universal-darwin-21 is installed
+ install_gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "sorbet-static", "= 0.5.10549"
+ G
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "sorbet-static", "0.5.10549", "universal-darwin-20"
+ c.checksum gem_repo4, "sorbet-static", "0.5.10549", "universal-darwin-21"
+ end
+
+ # Make sure the lockfile is missing sorbet-static-0.5.10549-universal-darwin-21
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ sorbet-static (0.5.10549-universal-darwin-20)
+
+ PLATFORMS
+ x86_64-darwin
+
+ DEPENDENCIES
+ sorbet-static (= 0.5.10549)
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install"
+
+ checksums.no_checksum "sorbet-static", "0.5.10549", "universal-darwin-21"
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ sorbet-static (0.5.10549-universal-darwin-20)
+ sorbet-static (0.5.10549-universal-darwin-21)
+
+ PLATFORMS
+ x86_64-darwin
+
+ DEPENDENCIES
+ sorbet-static (= 0.5.10549)
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ it "does not remove ruby if gems for other platforms, and not present in the lockfile, exist in the Gemfile" do
+ build_repo4 do
+ build_gem "nokogiri", "1.13.8"
+ build_gem "nokogiri", "1.13.8" do |s|
+ s.platform = Gem::Platform.local
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "nokogiri"
+
+ gem "tzinfo", "~> 1.2", platform: :#{not_local_tag}
+ G
+
+ original_lockfile = <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ nokogiri (1.13.8)
+ nokogiri (1.13.8-#{Gem::Platform.local})
+
+ PLATFORMS
+ #{lockfile_platforms("ruby")}
+
+ DEPENDENCIES
+ nokogiri
+ tzinfo (~> 1.2)
+
+ CHECKSUMS
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ lockfile original_lockfile
+
+ bundle "lock --update"
+
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "nokogiri", "1.13.8"
+ c.no_checksum "nokogiri", "1.13.8", Gem::Platform.local
+ end
+
+ updated_lockfile = <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ nokogiri (1.13.8)
+ nokogiri (1.13.8-#{Gem::Platform.local})
+
+ PLATFORMS
+ #{lockfile_platforms("ruby")}
+
+ DEPENDENCIES
+ nokogiri
+ tzinfo (~> 1.2)
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ expect(lockfile).to eq(updated_lockfile)
+ end
+
+ it "does not remove ruby when adding a new gem to the Gemfile" do
+ build_repo4 do
+ build_gem "concurrent-ruby", "1.2.2"
+ build_gem "rack", "3.0.7"
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "concurrent-ruby"
+ gem "rack"
+ G
+
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "concurrent-ruby", "1.2.2"
+ c.no_checksum "rack", "3.0.7"
+ end
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ concurrent-ruby (1.2.2)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ concurrent-ruby
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "lock"
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ concurrent-ruby (1.2.2)
+ rack (3.0.7)
+
+ PLATFORMS
+ #{lockfile_platforms("ruby", generic_local_platform, defaults: [])}
+
+ DEPENDENCIES
+ concurrent-ruby
+ rack
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "can fallback to a source gem when platform gems are incompatible with current ruby version" do
+ setup_multiplatform_gem_with_source_gem
+
+ source = file_uri_for(gem_repo2)
+
+ gemfile <<~G
+ source "#{source}"
+
+ gem "my-precompiled-gem"
+ G
+
+ # simulate lockfile which includes both a precompiled gem with:
+ # - Gem the current platform (with incompatible ruby version)
+ # - A source gem with compatible ruby version
+ lockfile <<-L
+ GEM
+ remote: #{source}/
+ specs:
+ my-precompiled-gem (3.0.0)
+ my-precompiled-gem (3.0.0-#{Bundler.local_platform})
+
+ PLATFORMS
+ ruby
+ #{Bundler.local_platform}
+
+ DEPENDENCIES
+ my-precompiled-gem
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle :install
+ end
+
+ it "automatically fixes the lockfile if the specific platform is locked and we move to a newer ruby version for which a native package is not available" do
+ #
+ # Given an existing application using native gems (e.g., nokogiri)
+ # And a lockfile generated with a stable ruby version
+ # When want test the application against ruby-head and `bundle install`
+ # Then bundler should fall back to the generic ruby platform gem
+ #
+ simulate_platform "x86_64-linux" do
+ build_repo4 do
+ build_gem "nokogiri", "1.14.0"
+ build_gem "nokogiri", "1.14.0" do |s|
+ s.platform = "x86_64-linux"
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "nokogiri", "1.14.0"
+ G
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "nokogiri", "1.14.0", "x86_64-linux"
+ end
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ nokogiri (1.14.0-x86_64-linux)
+
+ PLATFORMS
+ x86_64-linux
+
+ DEPENDENCIES
+ nokogiri (= 1.14.0)
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle :install
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "nokogiri", "1.14.0"
+ end
+
+ expect(lockfile).to eq(<<~L)
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ nokogiri (1.14.0)
+
+ PLATFORMS
+ x86_64-linux
+
+ DEPENDENCIES
+ nokogiri (= 1.14.0)
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ it "locks specific platforms automatically" do
+ simulate_platform "x86_64-linux" do
+ build_repo4 do
+ build_gem "nokogiri", "1.14.0"
+ build_gem "nokogiri", "1.14.0" do |s|
+ s.platform = "x86_64-linux"
+ end
+ build_gem "nokogiri", "1.14.0" do |s|
+ s.platform = "arm-linux"
+ end
+ build_gem "nokogiri", "1.14.0" do |s|
+ s.platform = "x64-mingw32"
+ end
+ build_gem "nokogiri", "1.14.0" do |s|
+ s.platform = "java"
+ end
+
+ build_gem "sorbet-static", "0.5.10696" do |s|
+ s.platform = "x86_64-linux"
+ end
+ build_gem "sorbet-static", "0.5.10696" do |s|
+ s.platform = "universal-darwin-22"
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "nokogiri"
+ G
+
+ bundle "lock"
+
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "nokogiri", "1.14.0"
+ c.no_checksum "nokogiri", "1.14.0", "arm-linux"
+ c.no_checksum "nokogiri", "1.14.0", "x86_64-linux"
+ end
+
+ # locks all compatible platforms, excluding Java and Windows
+ expect(lockfile).to eq(<<~L)
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ nokogiri (1.14.0)
+ nokogiri (1.14.0-arm-linux)
+ nokogiri (1.14.0-x86_64-linux)
+
+ PLATFORMS
+ arm-linux
+ ruby
+ x86_64-linux
+
+ DEPENDENCIES
+ nokogiri
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "nokogiri"
+ gem "sorbet-static"
+ G
+
+ FileUtils.rm bundled_app_lock
+
+ bundle "lock"
+
+ checksums.delete "nokogiri", "arm-linux"
+ checksums.no_checksum "sorbet-static", "0.5.10696", "universal-darwin-22"
+ checksums.no_checksum "sorbet-static", "0.5.10696", "x86_64-linux"
+
+ # locks only platforms compatible with all gems in the bundle
+ expect(lockfile).to eq(<<~L)
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ nokogiri (1.14.0)
+ nokogiri (1.14.0-x86_64-linux)
+ sorbet-static (0.5.10696-universal-darwin-22)
+ sorbet-static (0.5.10696-x86_64-linux)
+
+ PLATFORMS
+ universal-darwin-22
+ x86_64-linux
+
+ DEPENDENCIES
+ nokogiri
+ sorbet-static
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ it "does not fail when a platform variant is incompatible with the current ruby and another equivalent platform specific variant is part of the resolution", rubygems: ">= 3.3.21" do
+ build_repo4 do
+ build_gem "nokogiri", "1.15.5"
+
+ build_gem "nokogiri", "1.15.5" do |s|
+ s.platform = "x86_64-linux"
+ s.required_ruby_version = "< #{current_ruby_minor}.dev"
+ end
+
+ build_gem "sass-embedded", "1.69.5"
+
+ build_gem "sass-embedded", "1.69.5" do |s|
+ s.platform = "x86_64-linux-gnu"
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "nokogiri"
+ gem "sass-embedded"
+ G
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "nokogiri", "1.15.5"
+ c.no_checksum "sass-embedded", "1.69.5"
+ c.checksum gem_repo4, "sass-embedded", "1.69.5", "x86_64-linux-gnu"
+ end
+
+ simulate_platform "x86_64-linux" do
+ bundle "install --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+
+ # locks all compatible platforms, excluding Java and Windows
+ expect(lockfile).to eq(<<~L)
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ nokogiri (1.15.5)
+ sass-embedded (1.69.5)
+ sass-embedded (1.69.5-x86_64-linux-gnu)
+
+ PLATFORMS
+ ruby
+ x86_64-linux
+
+ DEPENDENCIES
+ nokogiri
+ sass-embedded
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ it "does not add ruby platform gem if it brings extra dependencies not resolved originally" do
+ build_repo4 do
+ build_gem "nokogiri", "1.15.5" do |s|
+ s.add_dependency "mini_portile2", "~> 2.8.2"
+ end
+
+ build_gem "nokogiri", "1.15.5" do |s|
+ s.platform = "x86_64-linux"
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "nokogiri"
+ G
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "nokogiri", "1.15.5", "x86_64-linux"
+ end
+
+ simulate_platform "x86_64-linux" do
+ bundle "install --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+
+ expect(lockfile).to eq(<<~L)
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ nokogiri (1.15.5-x86_64-linux)
+
+ PLATFORMS
+ x86_64-linux
+
+ DEPENDENCIES
+ nokogiri
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ ["x86_64-linux", "x86_64-linux-musl"].each do |host_platform|
+ describe "on host platform #{host_platform}" do
+ it "adds current musl platform" do
+ build_repo4 do
+ build_gem "rcee_precompiled", "0.5.0" do |s|
+ s.platform = "x86_64-linux"
+ end
+
+ build_gem "rcee_precompiled", "0.5.0" do |s|
+ s.platform = "x86_64-linux-musl"
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "rcee_precompiled", "0.5.0"
+ G
+
+ simulate_platform host_platform do
+ bundle "lock", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+
+ expect(lockfile).to eq(<<~L)
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ rcee_precompiled (0.5.0-x86_64-linux)
+ rcee_precompiled (0.5.0-x86_64-linux-musl)
+
+ PLATFORMS
+ x86_64-linux
+ x86_64-linux-musl
+
+ DEPENDENCIES
+ rcee_precompiled (= 0.5.0)
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+ end
+ end
+
+ it "adds current musl platform, when there are also gnu variants", rubygems: ">= 3.3.21" do
+ build_repo4 do
+ build_gem "rcee_precompiled", "0.5.0" do |s|
+ s.platform = "x86_64-linux-gnu"
+ end
+
+ build_gem "rcee_precompiled", "0.5.0" do |s|
+ s.platform = "x86_64-linux-musl"
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "rcee_precompiled", "0.5.0"
+ G
+
+ simulate_platform "x86_64-linux-musl" do
+ bundle "lock", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+
+ expect(lockfile).to eq(<<~L)
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ rcee_precompiled (0.5.0-x86_64-linux-gnu)
+ rcee_precompiled (0.5.0-x86_64-linux-musl)
+
+ PLATFORMS
+ x86_64-linux-gnu
+ x86_64-linux-musl
+
+ DEPENDENCIES
+ rcee_precompiled (= 0.5.0)
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ it "does not add current platform if there's an equivalent less specific platform among the ones resolved" do
+ build_repo4 do
+ build_gem "rcee_precompiled", "0.5.0" do |s|
+ s.platform = "universal-darwin"
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "rcee_precompiled", "0.5.0"
+ G
+
+ simulate_platform "x86_64-darwin-15" do
+ bundle "lock", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+
+ expect(lockfile).to eq(<<~L)
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ rcee_precompiled (0.5.0-universal-darwin)
+
+ PLATFORMS
+ universal-darwin
+
+ DEPENDENCIES
+ rcee_precompiled (= 0.5.0)
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
private
def setup_multiplatform_gem
@@ -312,4 +1410,16 @@ RSpec.describe "bundle install with specific platforms" do
build_gem("CFPropertyList")
end
end
+
+ def setup_multiplatform_gem_with_source_gem
+ build_repo2 do
+ build_gem("my-precompiled-gem", "3.0.0")
+ build_gem("my-precompiled-gem", "3.0.0") do |s|
+ s.platform = Bundler.local_platform
+
+ # purposely unresolvable
+ s.required_ruby_version = ">= 1000.0.0"
+ end
+ end
+ end
end
diff --git a/spec/bundler/install/gemfile_spec.rb b/spec/bundler/install/gemfile_spec.rb
index 0f8f1ecfa8..158645d3eb 100644
--- a/spec/bundler/install/gemfile_spec.rb
+++ b/spec/bundler/install/gemfile_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe "bundle install" do
context "with duplicated gems" do
it "will display a warning" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem 'rails', '~> 4.0.0'
@@ -20,7 +20,7 @@ RSpec.describe "bundle install" do
gem 'rack'
G
- bundle :install, :gemfile => bundled_app("NotGemfile")
+ bundle :install, gemfile: bundled_app("NotGemfile")
# Specify BUNDLE_GEMFILE for `the_bundle`
# to retrieve the proper Gemfile
@@ -46,8 +46,8 @@ RSpec.describe "bundle install" do
end
it "uses the gemfile while in a subdirectory" do
bundled_app("subdir").mkpath
- bundle "install", :dir => bundled_app("subdir")
- bundle "list", :dir => bundled_app("subdir")
+ bundle "install", dir: bundled_app("subdir")
+ bundle "list", dir: bundled_app("subdir")
expect(out).to include("rack (1.0.0)")
end
@@ -61,12 +61,12 @@ RSpec.describe "bundle install" do
gem "rack", :lib => "rack"
G
- bundle :install, :raise_on_error => false
+ bundle :install, raise_on_error: false
expect(err).to match(/You passed :lib as an option for gem 'rack', but it is invalid/)
end
end
- context "with engine specified in symbol", :jruby do
+ context "with engine specified in symbol", :jruby_only do
it "does not raise any error parsing Gemfile" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
diff --git a/spec/bundler/install/gems/compact_index_spec.rb b/spec/bundler/install/gems/compact_index_spec.rb
index 0cee69f702..50add8743b 100644
--- a/spec/bundler/install/gems/compact_index_spec.rb
+++ b/spec/bundler/install/gems/compact_index_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe "compact index api" do
gem "rack"
G
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(out).to include("Fetching gem metadata from #{source_uri}")
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -21,7 +21,7 @@ RSpec.describe "compact index api" do
gem " sinatra"
G
- bundle :install, :artifice => "compact_index", :raise_on_error => false
+ bundle :install, artifice: "compact_index", raise_on_error: false
expect(err).to include("' sinatra' is not a valid gem name because it contains whitespace.")
end
@@ -31,7 +31,7 @@ RSpec.describe "compact index api" do
gem "rails"
G
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(out).to include("Fetching gem metadata from #{source_uri}")
expect(the_bundle).to include_gems(
"rails 2.3.2",
@@ -44,14 +44,14 @@ RSpec.describe "compact index api" do
end
it "should handle case sensitivity conflicts" do
- build_repo4 do
+ build_repo4(build_compact_index: false) do
build_gem "rack", "1.0" do |s|
s.add_runtime_dependency("Rack", "0.1")
end
build_gem "Rack", "0.1"
end
- install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
source "#{source_uri}"
gem "rack", "1.0"
gem "Rack", "0.1"
@@ -69,7 +69,7 @@ RSpec.describe "compact index api" do
gem "net-sftp"
G
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(the_bundle).to include_gems "net-sftp 1.1.1"
end
@@ -78,11 +78,11 @@ RSpec.describe "compact index api" do
source "#{source_uri}"
gem "rack"
G
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
bundle "config set --local deployment true"
bundle "config set --local path vendor/bundle"
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(out).to include("Fetching gem metadata from #{source_uri}")
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -100,7 +100,7 @@ RSpec.describe "compact index api" do
end
G
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(the_bundle).to include_gems("rails 2.3.2")
end
@@ -116,10 +116,10 @@ RSpec.describe "compact index api" do
gem 'foo', :git => "#{file_uri_for(lib_path("foo-1.0"))}"
G
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
bundle "config set --local deployment true"
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(the_bundle).to include_gems("rails 2.3.2")
end
@@ -131,9 +131,9 @@ RSpec.describe "compact index api" do
gem 'foo', :git => "#{file_uri_for(lib_path("foo-1.0"))}"
G
- bundle "install", :artifice => "compact_index"
+ bundle "install", artifice: "compact_index"
bundle "config set --local deployment true"
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(the_bundle).to include_gems("foo 1.0")
end
@@ -144,7 +144,7 @@ RSpec.describe "compact index api" do
gem "rack"
G
- bundle :install, :verbose => true, :artifice => "compact_index_forbidden"
+ bundle :install, verbose: true, artifice: "compact_index_forbidden"
expect(out).to include("Fetching gem metadata from #{source_uri}")
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -155,14 +155,34 @@ RSpec.describe "compact index api" do
gem "rack"
G
- bundle :install, :verbose => true, :artifice => "compact_index_checksum_mismatch"
+ bundle :install, verbose: true, artifice: "compact_index_checksum_mismatch"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(out).to include <<-'WARN'
-The checksum of /versions does not match the checksum provided by the server! Something is wrong (local checksum is "\"d41d8cd98f00b204e9800998ecf8427e\"", was expecting "\"123\"").
- WARN
+ expect(out).to include("The checksum of /versions does not match the checksum provided by the server!")
+ expect(out).to include('Calculated checksums {"sha-256"=>"8KfZiM/fszVkqhP/m5s9lvE6M9xKu4I1bU4Izddp5Ms="} did not match expected {"sha-256"=>"ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0="}')
expect(the_bundle).to include_gems "rack 1.0.0"
end
+ it "shows proper path when permission errors happen", :permissions do
+ gemfile <<-G
+ source "#{source_uri}"
+ gem "rack"
+ G
+
+ versions = Pathname.new(Bundler.rubygems.user_home).join(
+ ".bundle", "cache", "compact_index",
+ "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions"
+ )
+ versions.dirname.mkpath
+ versions.write("created_at")
+ FileUtils.chmod("-r", versions)
+
+ bundle :install, artifice: "compact_index", raise_on_error: false
+
+ expect(err).to include(
+ "There was an error while trying to read from `#{versions}`. It is likely that you need to grant read permissions for that path."
+ )
+ end
+
it "falls back when the user's home directory does not exist or is not writable" do
ENV["HOME"] = tmp("missing_home").to_s
@@ -171,7 +191,7 @@ The checksum of /versions does not match the checksum provided by the server! So
gem "rack"
G
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(out).to include("Fetching gem metadata from #{source_uri}")
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -182,11 +202,11 @@ The checksum of /versions does not match the checksum provided by the server! So
gem "rack"
G
- bundle :install, :artifice => "compact_index_host_redirect"
+ bundle :install, artifice: "compact_index_host_redirect"
expect(the_bundle).to include_gems "rack 1.0.0"
end
- it "handles host redirects without Net::HTTP::Persistent" do
+ it "handles host redirects without Gem::Net::HTTP::Persistent" do
gemfile <<-G
source "#{source_uri}"
gem "rack"
@@ -205,7 +225,7 @@ The checksum of /versions does not match the checksum provided by the server! So
H
end
- bundle :install, :artifice => "compact_index_host_redirect", :requires => [lib_path("disable_net_http_persistent.rb")]
+ bundle :install, artifice: "compact_index_host_redirect", requires: [lib_path("disable_net_http_persistent.rb")]
expect(out).to_not match(/Too many redirects/)
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -216,7 +236,7 @@ The checksum of /versions does not match the checksum provided by the server! So
gem "rack"
G
- bundle :install, :artifice => "compact_index_redirects", :raise_on_error => false
+ bundle :install, artifice: "compact_index_redirects", raise_on_error: false
expect(err).to match(/Too many redirects/)
end
@@ -227,7 +247,7 @@ The checksum of /versions does not match the checksum provided by the server! So
gem "rack"
G
- bundle "install --full-index", :artifice => "compact_index"
+ bundle "install --full-index", artifice: "compact_index"
expect(out).to include("Fetching source index from #{source_uri}")
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -238,7 +258,7 @@ The checksum of /versions does not match the checksum provided by the server! So
gem "rack"
G
- bundle "update --full-index", :artifice => "compact_index", :all => true
+ bundle "update --full-index", artifice: "compact_index", all: true
expect(out).to include("Fetching source index from #{source_uri}")
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -258,7 +278,7 @@ The checksum of /versions does not match the checksum provided by the server! So
s.extensions << "Rakefile"
s.write "Rakefile", <<-RUBY
task :default do
- path = File.expand_path("../lib", __FILE__)
+ path = File.expand_path("lib", __dir__)
FileUtils.mkdir_p(path)
File.open("\#{path}/net_build_extensions.rb", "w") do |f|
f.puts "NET_BUILD_EXTENSIONS = 'YES'"
@@ -268,14 +288,14 @@ The checksum of /versions does not match the checksum provided by the server! So
end
end
- system_gems %w[rack-1.0.0 thin-1.0 net_a-1.0], :gem_repo => gem_repo2
+ system_gems %w[rack-1.0.0 thin-1.0 net_a-1.0], gem_repo: gem_repo2
bundle "config set --local path.system true"
- ENV["BUNDLER_SPEC_ALL_REQUESTS"] = strip_whitespace(<<-EOS).strip
+ ENV["BUNDLER_SPEC_ALL_REQUESTS"] = <<~EOS.strip
#{source_uri}/versions
#{source_uri}/info/rack
EOS
- install_gemfile <<-G, :artifice => "compact_index", :verbose => true, :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ install_gemfile <<-G, artifice: "compact_index", verbose: true, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
source "#{source_uri}"
gem "rack"
G
@@ -283,7 +303,7 @@ The checksum of /versions does not match the checksum provided by the server! So
expect(last_command.stdboth).not_to include "Double checking"
end
- it "fetches again when more dependencies are found in subsequent sources", :bundler => "< 3" do
+ it "fetches again when more dependencies are found in subsequent sources", bundler: "< 3" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -297,7 +317,7 @@ The checksum of /versions does not match the checksum provided by the server! So
gem "back_deps"
G
- bundle :install, :artifice => "compact_index_extra"
+ bundle :install, artifice: "compact_index_extra"
expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0"
end
@@ -309,7 +329,7 @@ The checksum of /versions does not match the checksum provided by the server! So
FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")]
end
- install_gemfile <<-G, :artifice => "compact_index_extra", :verbose => true
+ install_gemfile <<-G, artifice: "compact_index_extra", verbose: true
source "#{source_uri}"
source "#{source_uri}/extra" do
gem "back_deps"
@@ -324,7 +344,7 @@ The checksum of /versions does not match the checksum provided by the server! So
source "#{source_uri}"
gem "rack", "1.0.0"
G
- bundle :install, :artifice => "compact_index_extra_api"
+ bundle :install, artifice: "compact_index_extra_api"
expect(the_bundle).to include_gems "rack 1.0.0"
build_repo4 do
@@ -338,11 +358,11 @@ The checksum of /versions does not match the checksum provided by the server! So
source "#{source_uri}/extra"
gem "rack", "1.2"
G
- bundle :install, :artifice => "compact_index_extra_api"
+ bundle :install, artifice: "compact_index_extra_api"
expect(the_bundle).to include_gems "rack 1.2"
end
- it "considers all possible versions of dependencies from all api gem sources", :bundler => "< 3" do
+ it "considers all possible versions of dependencies from all api gem sources", bundler: "< 3" do
# In this scenario, the gem "somegem" only exists in repo4. It depends on specific version of activesupport that
# exists only in repo1. There happens also be a version of activesupport in repo4, but not the one that version 1.0.0
# of somegem wants. This test makes sure that bundler actually finds version 1.2.3 of active support in the other
@@ -360,7 +380,7 @@ The checksum of /versions does not match the checksum provided by the server! So
gem 'somegem', '1.0.0'
G
- bundle :install, :artifice => "compact_index_extra_api"
+ bundle :install, artifice: "compact_index_extra_api"
expect(the_bundle).to include_gems "somegem 1.0.0"
expect(the_bundle).to include_gems "activesupport 1.2.3"
@@ -381,13 +401,13 @@ The checksum of /versions does not match the checksum provided by the server! So
end
G
- bundle :install, :artifice => "compact_index_extra"
+ bundle :install, artifice: "compact_index_extra"
expect(out).to include("Fetching gem metadata from http://localgemserver.test/")
expect(out).to include("Fetching source index from http://localgemserver.test/extra")
end
- it "does not fetch every spec if the index of gems is large when doing back deps" do
+ it "does not fetch every spec when doing back deps" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -397,9 +417,7 @@ The checksum of /versions does not match the checksum provided by the server! So
FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")]
end
- api_request_limit = low_api_request_limit_for(gem_repo2)
-
- install_gemfile <<-G, :artifice => "compact_index_extra_missing", :requires => [api_request_limit_hack_file], :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation)
+ install_gemfile <<-G, artifice: "compact_index_extra_missing"
source "#{source_uri}"
source "#{source_uri}/extra" do
gem "back_deps"
@@ -409,7 +427,7 @@ The checksum of /versions does not match the checksum provided by the server! So
expect(the_bundle).to include_gems "back_deps 1.0"
end
- it "does not fetch every spec if the index of gems is large when doing back deps & everything is the compact index" do
+ it "does not fetch every spec when doing back deps & everything is the compact index" do
build_repo4 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -419,9 +437,7 @@ The checksum of /versions does not match the checksum provided by the server! So
FileUtils.rm_rf Dir[gem_repo4("gems/foo-*.gem")]
end
- api_request_limit = low_api_request_limit_for(gem_repo4)
-
- install_gemfile <<-G, :artifice => "compact_index_extra_api_missing", :requires => [api_request_limit_hack_file], :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation)
+ install_gemfile <<-G, artifice: "compact_index_extra_api_missing"
source "#{source_uri}"
source "#{source_uri}/extra" do
gem "back_deps"
@@ -438,11 +454,11 @@ The checksum of /versions does not match the checksum provided by the server! So
gem 'foo'
G
- bundle :install, :artifice => "compact_index_api_missing"
+ bundle :install, artifice: "compact_index_api_missing"
expect(the_bundle).to include_gems "foo 1.0"
end
- it "fetches again when more dependencies are found in subsequent sources using deployment mode", :bundler => "< 3" do
+ it "fetches again when more dependencies are found in subsequent sources using deployment mode", bundler: "< 3" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -456,9 +472,9 @@ The checksum of /versions does not match the checksum provided by the server! So
gem "back_deps"
G
- bundle :install, :artifice => "compact_index_extra"
+ bundle :install, artifice: "compact_index_extra"
bundle "config --set local deployment true"
- bundle :install, :artifice => "compact_index_extra"
+ bundle :install, artifice: "compact_index_extra"
expect(the_bundle).to include_gems "back_deps 1.0"
end
@@ -477,9 +493,9 @@ The checksum of /versions does not match the checksum provided by the server! So
end
G
- bundle :install, :artifice => "compact_index_extra"
+ bundle :install, artifice: "compact_index_extra"
bundle "config set --local deployment true"
- bundle :install, :artifice => "compact_index_extra"
+ bundle :install, artifice: "compact_index_extra"
expect(the_bundle).to include_gems "back_deps 1.0"
end
@@ -496,52 +512,40 @@ The checksum of /versions does not match the checksum provided by the server! So
gem "bundler_dep"
G
- bundle :install, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ bundle :install, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(out).to include("Fetching gem metadata from #{source_uri}")
end
- it "should install when EndpointSpecification has a bin dir owned by root", :sudo => true do
- sudo "mkdir -p #{system_gem_path("bin")}"
- sudo "chown -R root #{system_gem_path("bin")}"
-
- gemfile <<-G
- source "#{source_uri}"
- gem "rails"
- G
- bundle :install, :artifice => "compact_index"
- expect(the_bundle).to include_gems "rails 2.3.2"
- end
-
- it "installs the binstubs", :bundler => "< 3" do
+ it "installs the binstubs", bundler: "< 3" do
gemfile <<-G
source "#{source_uri}"
gem "rack"
G
- bundle "install --binstubs", :artifice => "compact_index"
+ bundle "install --binstubs", artifice: "compact_index"
gembin "rackup"
expect(out).to eq("1.0.0")
end
- it "installs the bins when using --path and uses autoclean", :bundler => "< 3" do
+ it "installs the bins when using --path and uses autoclean", bundler: "< 3" do
gemfile <<-G
source "#{source_uri}"
gem "rack"
G
- bundle "install --path vendor/bundle", :artifice => "compact_index"
+ bundle "install --path vendor/bundle", artifice: "compact_index"
expect(vendored_gems("bin/rackup")).to exist
end
- it "installs the bins when using --path and uses bundle clean", :bundler => "< 3" do
+ it "installs the bins when using --path and uses bundle clean", bundler: "< 3" do
gemfile <<-G
source "#{source_uri}"
gem "rack"
G
- bundle "install --path vendor/bundle --no-clean", :artifice => "compact_index"
+ bundle "install --path vendor/bundle --no-clean", artifice: "compact_index"
expect(vendored_gems("bin/rackup")).to exist
end
@@ -552,7 +556,7 @@ The checksum of /versions does not match the checksum provided by the server! So
gem 'rack-obama'
G
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(out).to include("Post-install message from rack:")
end
@@ -562,7 +566,7 @@ The checksum of /versions does not match the checksum provided by the server! So
gem 'rack_middleware'
G
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(out).to include("Post-install message from rack:")
expect(out).to include("Rack's post install message")
end
@@ -571,7 +575,7 @@ The checksum of /versions does not match the checksum provided by the server! So
let(:user) { "user" }
let(:password) { "pass" }
let(:basic_auth_source_uri) do
- uri = Bundler::URI.parse(source_uri)
+ uri = Gem::URI.parse(source_uri)
uri.user = user
uri.password = password
@@ -584,7 +588,7 @@ The checksum of /versions does not match the checksum provided by the server! So
gem "rack"
G
- bundle :install, :artifice => "compact_index_basic_authentication"
+ bundle :install, artifice: "compact_index_basic_authentication"
expect(out).not_to include("#{user}:#{password}")
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -595,19 +599,19 @@ The checksum of /versions does not match the checksum provided by the server! So
gem "rack"
G
- bundle :install, :verbose => true, :artifice => "compact_index_basic_authentication"
+ 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
+ it "strips http basic auth creds when warning about ambiguous sources", bundler: "< 3" do
gemfile <<-G
source "#{basic_auth_source_uri}"
source "#{file_uri_for(gem_repo1)}"
gem "rack"
G
- bundle :install, :artifice => "compact_index_basic_authentication"
+ bundle :install, artifice: "compact_index_basic_authentication"
expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
expect(err).not_to include("#{user}:#{password}")
expect(the_bundle).to include_gems "rack 1.0.0"
@@ -619,7 +623,7 @@ The checksum of /versions does not match the checksum provided by the server! So
gem "rack"
G
- bundle :install, :artifice => "compact_index_creds_diff_host"
+ bundle :install, artifice: "compact_index_creds_diff_host"
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -634,7 +638,7 @@ The checksum of /versions does not match the checksum provided by the server! So
it "reads authentication details by host name from bundle config" do
bundle "config set #{source_hostname} #{user}:#{password}"
- bundle :install, :artifice => "compact_index_strict_basic_authentication"
+ bundle :install, artifice: "compact_index_strict_basic_authentication"
expect(out).to include("Fetching gem metadata from #{source_uri}")
expect(the_bundle).to include_gems "rack 1.0.0"
@@ -644,7 +648,7 @@ The checksum of /versions does not match the checksum provided by the server! So
# The trailing slash is necessary here; Fetcher canonicalizes the URI.
bundle "config set #{source_uri}/ #{user}:#{password}"
- bundle :install, :artifice => "compact_index_strict_basic_authentication"
+ bundle :install, artifice: "compact_index_strict_basic_authentication"
expect(out).to include("Fetching gem metadata from #{source_uri}")
expect(the_bundle).to include_gems "rack 1.0.0"
@@ -652,7 +656,7 @@ The checksum of /versions does not match the checksum provided by the server! So
it "should use the API" do
bundle "config set #{source_hostname} #{user}:#{password}"
- bundle :install, :artifice => "compact_index_strict_basic_authentication"
+ bundle :install, artifice: "compact_index_strict_basic_authentication"
expect(out).to include("Fetching gem metadata from #{source_uri}")
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -665,20 +669,29 @@ The checksum of /versions does not match the checksum provided by the server! So
bundle "config set #{source_hostname} otheruser:wrong"
- bundle :install, :artifice => "compact_index_strict_basic_authentication"
+ bundle :install, artifice: "compact_index_strict_basic_authentication"
expect(the_bundle).to include_gems "rack 1.0.0"
end
it "shows instructions if auth is not provided for the source" do
- bundle :install, :artifice => "compact_index_strict_basic_authentication", :raise_on_error => false
+ bundle :install, artifice: "compact_index_strict_basic_authentication", raise_on_error: false
expect(err).to include("bundle config set --global #{source_hostname} username:password")
end
it "fails if authentication has already been provided, but failed" do
bundle "config set #{source_hostname} #{user}:wrong"
- bundle :install, :artifice => "compact_index_strict_basic_authentication", :raise_on_error => false
+ bundle :install, artifice: "compact_index_strict_basic_authentication", raise_on_error: false
+ expect(err).to include("Bad username or password")
+ end
+
+ it "does not fallback to old dependency API if bad authentication is provided" do
+ bundle "config set #{source_hostname} #{user}:wrong"
+
+ bundle :install, artifice: "compact_index_strict_basic_authentication", raise_on_error: false, verbose: true
expect(err).to include("Bad username or password")
+ expect(out).to include("HTTP 401 Unauthorized http://user@localgemserver.test/versions")
+ expect(out).not_to include("HTTP 401 Unauthorized http://user@localgemserver.test/api/v1/dependencies")
end
end
@@ -691,7 +704,7 @@ The checksum of /versions does not match the checksum provided by the server! So
gem "rack"
G
- bundle :install, :artifice => "compact_index_basic_authentication"
+ bundle :install, artifice: "compact_index_basic_authentication"
expect(the_bundle).to include_gems "rack 1.0.0"
end
end
@@ -716,7 +729,7 @@ The checksum of /versions does not match the checksum provided by the server! So
gem "rack"
G
- bundle :install, :env => { "RUBYOPT" => opt_add("-I#{bundled_app("broken_ssl")}", ENV["RUBYOPT"]) }, :raise_on_error => false
+ bundle :install, env: { "RUBYOPT" => opt_add("-I#{bundled_app("broken_ssl")}", ENV["RUBYOPT"]) }, raise_on_error: false
expect(err).to include("OpenSSL")
end
end
@@ -726,7 +739,7 @@ The checksum of /versions does not match the checksum provided by the server! So
# Install a monkeypatch that reproduces the effects of openssl raising
# a certificate validation error when RubyGems tries to connect.
gemfile <<-G
- class Net::HTTP
+ class Gem::Net::HTTP
def start
raise OpenSSL::SSL::SSLError, "certificate verify failed"
end
@@ -736,7 +749,7 @@ The checksum of /versions does not match the checksum provided by the server! So
gem "rack"
G
- bundle :install, :raise_on_error => false
+ bundle :install, raise_on_error: false
expect(err).to match(/could not verify the SSL certificate/i)
end
end
@@ -744,7 +757,7 @@ The checksum of /versions does not match the checksum provided by the server! So
context ".gemrc with sources is present" do
it "uses other sources declared in the Gemfile" do
File.open(home(".gemrc"), "w") do |file|
- file.puts({ :sources => ["https://rubygems.org"] }.to_yaml)
+ file.puts({ sources: ["https://rubygems.org"] }.to_yaml)
end
begin
@@ -753,23 +766,30 @@ The checksum of /versions does not match the checksum provided by the server! So
gem 'rack'
G
- bundle :install, :artifice => "compact_index_forbidden"
+ bundle :install, artifice: "compact_index_forbidden"
ensure
home(".gemrc").rmtree
end
end
end
- it "performs partial update with a non-empty range" do
- skip "HTTP_RANGE not set" if Gem.win_platform?
+ it "performs update with etag not-modified" do
+ versions_etag = Pathname.new(Bundler.rubygems.user_home).join(
+ ".bundle", "cache", "compact_index",
+ "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions.etag"
+ )
+ expect(versions_etag.file?).to eq(false)
gemfile <<-G
source "#{source_uri}"
gem 'rack', '0.9.1'
G
- # Initial install creates the cached versions file
- bundle :install, :artifice => "compact_index"
+ # Initial install creates the cached versions file and etag file
+ bundle :install, artifice: "compact_index"
+
+ expect(versions_etag.file?).to eq(true)
+ previous_content = versions_etag.binread
# Update the Gemfile so we can check subsequent install was successful
gemfile <<-G
@@ -777,8 +797,59 @@ The checksum of /versions does not match the checksum provided by the server! So
gem 'rack', '1.0.0'
G
- # Second install should make only a partial request to /versions
- bundle :install, :artifice => "compact_index_partial_update"
+ # Second install should match etag
+ bundle :install, artifice: "compact_index_etag_match"
+
+ expect(versions_etag.binread).to eq(previous_content)
+ expect(the_bundle).to include_gems "rack 1.0.0"
+ end
+
+ it "performs full update when range is ignored" do
+ gemfile <<-G
+ source "#{source_uri}"
+ gem 'rack', '0.9.1'
+ G
+
+ # Initial install creates the cached versions file and etag file
+ bundle :install, artifice: "compact_index"
+
+ gemfile <<-G
+ source "#{source_uri}"
+ gem 'rack', '1.0.0'
+ G
+
+ versions = Pathname.new(Bundler.rubygems.user_home).join(
+ ".bundle", "cache", "compact_index",
+ "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions"
+ )
+ # Modify the cached file. The ranged request will be based on this but,
+ # in this test, the range is ignored so this gets overwritten, allowing install.
+ versions.write "ruining this file"
+
+ bundle :install, artifice: "compact_index_range_ignored"
+
+ expect(the_bundle).to include_gems "rack 1.0.0"
+ end
+
+ it "performs partial update with a non-empty range" do
+ build_repo4 do
+ build_gem "rack", "0.9.1"
+ end
+
+ # Initial install creates the cached versions file
+ 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", 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
@@ -789,24 +860,26 @@ The checksum of /versions does not match the checksum provided by the server! So
gem 'rack'
G
- # Create an empty file to trigger a partial download
- versions = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index",
- "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions")
- FileUtils.mkdir_p(File.dirname(versions))
- FileUtils.touch(versions)
+ # Create a partial cache versions file
+ versions = Pathname.new(Bundler.rubygems.user_home).join(
+ ".bundle", "cache", "compact_index",
+ "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions"
+ )
+ versions.dirname.mkpath
+ versions.write("created_at")
- bundle :install, :artifice => "compact_index_concurrent_download"
+ bundle :install, artifice: "compact_index_concurrent_download"
- expect(File.read(versions)).to start_with("created_at")
+ expect(versions.read).to start_with("created_at")
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
+ it "performs a partial update that fails digest check, then a full update" 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 }
+ install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
source "#{source_uri}"
gem 'rack', '0.9.1'
G
@@ -815,7 +888,29 @@ The checksum of /versions does not match the checksum provided by the server! So
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 }
+ install_gemfile <<-G, artifice: "compact_index_partial_update_bad_digest", 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 if server endpoints serve partial content responses but don't have incremental content and provide no digest" 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_digest_not_incremental", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
source "#{source_uri}"
gem 'rack', '1.0.0'
G
@@ -829,15 +924,19 @@ The checksum of /versions does not match the checksum provided by the server! So
gem 'rack', '0.9.1'
G
- rake_info_path = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index",
- "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "info", "rack")
+ bundle :install, artifice: "compact_index"
- bundle :install, :artifice => "compact_index"
+ # We must remove the etag so that we don't ignore the range and get a 304 Not Modified.
+ rake_info_etag_path = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index",
+ "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "info-etags", "rack-11690b09f16021ff06a6857d784a1870")
+ File.unlink(rake_info_etag_path) if File.exist?(rake_info_etag_path)
+ rake_info_path = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index",
+ "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "info", "rack")
expected_rack_info_content = File.read(rake_info_path)
- # Modify the cache files. We expect them to be reset to the normal ones when we re-run :install
- File.open(rake_info_path, "w") {|f| f << (expected_rack_info_content + "this is different") }
+ # Modify the cache files to make the range not satisfiable
+ File.open(rake_info_path, "a") {|f| f << "0.9.2 |checksum:c55b525b421fd833a93171ad3d7f04528ca8e87d99ac273f8933038942a5888c" }
# Update the Gemfile so the next install does its normal things
gemfile <<-G
@@ -847,7 +946,7 @@ The checksum of /versions does not match the checksum provided by the server! So
# The cache files now being longer means the requested range is going to be not satisfiable
# Bundler must end up requesting the whole file to fix things up.
- bundle :install, :artifice => "compact_index_range_not_satisfiable"
+ bundle :install, artifice: "compact_index_range_not_satisfiable"
resulting_rack_info_content = File.read(rake_info_path)
@@ -855,7 +954,7 @@ The checksum of /versions does not match the checksum provided by the server! So
end
it "fails gracefully when the source URI has an invalid scheme" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "htps://rubygems.org"
gem "rack"
G
@@ -866,38 +965,76 @@ The checksum of /versions does not match the checksum provided by the server! So
end
describe "checksum validation" do
+ before do
+ lockfile <<-L
+ GEM
+ remote: #{source_uri}
+ specs:
+ rack (1.0.0)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ #{checksums_section}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "handles checksums from the server in base64" do
+ api_checksum = checksum_digest(gem_repo1, "rack", "1.0.0")
+ rack_checksum = [[api_checksum].pack("H*")].pack("m0")
+ install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_RACK_CHECKSUM" => rack_checksum }
+ source "#{source_uri}"
+ gem "rack"
+ G
+
+ expect(out).to include("Fetching gem metadata from #{source_uri}")
+ expect(the_bundle).to include_gems("rack 1.0.0")
+ end
+
it "raises when the checksum does not match" do
- install_gemfile <<-G, :artifice => "compact_index_wrong_gem_checksum", :raise_on_error => false
+ install_gemfile <<-G, artifice: "compact_index_wrong_gem_checksum", raise_on_error: false
source "#{source_uri}"
gem "rack"
G
- expect(exitstatus).to eq(19)
- expect(err).
- to include("Bundler cannot continue installing rack (1.0.0).").
- and include("The checksum for the downloaded `rack-1.0.0.gem` does not match the checksum given by the server.").
- and include("This means the contents of the downloaded gem is different from what was uploaded to the server, and could be a potential security issue.").
- and include("To resolve this issue:").
- and include("1. delete the downloaded gem located at: `#{default_bundle_path}/gems/rack-1.0.0/rack-1.0.0.gem`").
- and include("2. run `bundle install`").
- and include("If you wish to continue installing the downloaded gem, and are certain it does not pose a security issue despite the mismatching checksum, do the following:").
- and include("1. run `bundle config set --local disable_checksum_validation true` to turn off checksum verification").
- and include("2. run `bundle install`").
- and match(/\(More info: The expected SHA256 checksum was "#{"ab" * 22}", but the checksum for the downloaded gem was ".+?"\.\)/)
+ gem_path = if Bundler.feature_flag.global_gem_cache?
+ default_cache_path.dirname.join("cache", "gems", "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "rack-1.0.0.gem")
+ else
+ default_cache_path.dirname.join("rack-1.0.0.gem")
+ end
+
+ expect(exitstatus).to eq(37)
+ expect(err).to eq <<~E.strip
+ Bundler found mismatched checksums. This is a potential security risk.
+ rack (1.0.0) sha256=2222222222222222222222222222222222222222222222222222222222222222
+ from the API at http://localgemserver.test/
+ #{checksum_to_lock(gem_repo1, "rack", "1.0.0")}
+ from the gem at #{gem_path}
+
+ If you trust the API at http://localgemserver.test/, to resolve this issue you can:
+ 1. remove the gem at #{gem_path}
+ 2. run `bundle install`
+
+ To ignore checksum security warnings, disable checksum validation with
+ `bundle config set --local disable_checksum_validation true`
+ E
end
it "raises when the checksum is the wrong length" do
- install_gemfile <<-G, :artifice => "compact_index_wrong_gem_checksum", :env => { "BUNDLER_SPEC_RACK_CHECKSUM" => "checksum!", "DEBUG" => "1" }, :verbose => true, :raise_on_error => false
+ install_gemfile <<-G, artifice: "compact_index_wrong_gem_checksum", env: { "BUNDLER_SPEC_RACK_CHECKSUM" => "checksum!", "DEBUG" => "1" }, verbose: true, raise_on_error: false
source "#{source_uri}"
gem "rack"
G
- expect(exitstatus).to eq(5)
- expect(err).to include("The given checksum for rack-1.0.0 (\"checksum!\") is not a valid SHA256 hexdigest nor base64digest")
+ expect(exitstatus).to eq(14)
+ expect(err).to include('Invalid checksum for rack-0.9.1: "checksum!" is not a valid SHA256 hex or base64 digest')
end
it "does not raise when disable_checksum_validation is set" do
bundle "config set disable_checksum_validation true"
- install_gemfile <<-G, :artifice => "compact_index_wrong_gem_checksum"
+ install_gemfile <<-G, artifice: "compact_index_wrong_gem_checksum"
source "#{source_uri}"
gem "rack"
G
@@ -905,7 +1042,7 @@ The checksum of /versions does not match the checksum provided by the server! So
end
it "works when cache dir is world-writable" do
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
File.umask(0000)
source "#{source_uri}"
gem "rack"
@@ -913,23 +1050,24 @@ The checksum of /versions does not match the checksum provided by the server! So
end
it "doesn't explode when the API dependencies are wrong" do
- install_gemfile <<-G, :artifice => "compact_index_wrong_dependencies", :env => { "DEBUG" => "true" }, :raise_on_error => false
+ install_gemfile <<-G, artifice: "compact_index_wrong_dependencies", env: { "DEBUG" => "true" }, raise_on_error: false
source "#{source_uri}"
gem "rails"
G
- deps = [Gem::Dependency.new("rake", "= 13.0.1"),
+ deps = [Gem::Dependency.new("rake", "= #{rake_version}"),
Gem::Dependency.new("actionpack", "= 2.3.2"),
Gem::Dependency.new("activerecord", "= 2.3.2"),
Gem::Dependency.new("actionmailer", "= 2.3.2"),
Gem::Dependency.new("activeresource", "= 2.3.2")]
- expect(out).to include(<<-E.strip).and include("rails-2.3.2 from rubygems remote at #{source_uri}/ has either corrupted API or lockfile dependencies")
+ expect(out).to include("rails-2.3.2 from rubygems remote at #{source_uri}/ has either corrupted API or lockfile dependencies")
+ expect(err).to include(<<-E.strip)
Bundler::APIResponseMismatchError: Downloading rails-2.3.2 revealed dependencies not in the API or the lockfile (#{deps.map(&:to_s).join(", ")}).
-Either installing with `--full-index` or running `bundle update rails` should fix the problem.
+Running `bundle update rails` should fix the problem.
E
end
it "does not duplicate specs in the lockfile when updating and a dependency is not installed" do
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "#{file_uri_for(gem_repo1)}"
source "#{source_uri}" do
gem "rails"
@@ -937,7 +1075,8 @@ Either installing with `--full-index` or running `bundle update rails` should fi
end
G
gem_command "uninstall activemerchant"
- bundle "update rails", :artifice => "compact_index"
- expect(lockfile.scan(/activemerchant \(/).size).to eq(1)
+ bundle "update rails", artifice: "compact_index"
+ count = lockfile.match?("CHECKSUMS") ? 2 : 1 # Once in the specs, and once in CHECKSUMS
+ expect(lockfile.scan(/activemerchant \(/).size).to eq(count)
end
end
diff --git a/spec/bundler/install/gems/dependency_api_spec.rb b/spec/bundler/install/gems/dependency_api_spec.rb
index 9738a75474..35468b3a1c 100644
--- a/spec/bundler/install/gems/dependency_api_spec.rb
+++ b/spec/bundler/install/gems/dependency_api_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "rack"
G
- bundle :install, :artifice => "endpoint"
+ bundle :install, artifice: "endpoint"
expect(out).to include("Fetching gem metadata from #{source_uri}")
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -21,7 +21,7 @@ RSpec.describe "gemcutter's dependency API" do
gem " sinatra"
G
- bundle :install, :artifice => "endpoint", :raise_on_error => false
+ bundle :install, artifice: "endpoint", raise_on_error: false
expect(err).to include("' sinatra' is not a valid gem name because it contains whitespace.")
end
@@ -31,7 +31,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "rails"
G
- bundle :install, :artifice => "endpoint"
+ bundle :install, artifice: "endpoint"
expect(out).to include("Fetching gem metadata from #{source_uri}/...")
expect(the_bundle).to include_gems(
"rails 2.3.2",
@@ -49,7 +49,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "net-sftp"
G
- bundle :install, :artifice => "endpoint"
+ bundle :install, artifice: "endpoint"
expect(the_bundle).to include_gems "net-sftp 1.1.1"
end
@@ -58,11 +58,11 @@ RSpec.describe "gemcutter's dependency API" do
source "#{source_uri}"
gem "rack"
G
- bundle :install, :artifice => "endpoint"
+ bundle :install, artifice: "endpoint"
bundle "config set --local deployment true"
bundle "config set --local path vendor/bundle"
- bundle :install, :artifice => "endpoint"
+ bundle :install, artifice: "endpoint"
expect(out).to include("Fetching gem metadata from #{source_uri}")
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -80,7 +80,7 @@ RSpec.describe "gemcutter's dependency API" do
end
G
- bundle :install, :artifice => "endpoint"
+ bundle :install, artifice: "endpoint"
expect(the_bundle).to include_gems("rails 2.3.2")
end
@@ -96,10 +96,10 @@ RSpec.describe "gemcutter's dependency API" do
gem 'foo', :git => "#{file_uri_for(lib_path("foo-1.0"))}"
G
- bundle :install, :artifice => "endpoint"
+ bundle :install, artifice: "endpoint"
bundle "config set --local deployment true"
- bundle :install, :artifice => "endpoint"
+ bundle :install, artifice: "endpoint"
expect(the_bundle).to include_gems("rails 2.3.2")
end
@@ -111,15 +111,15 @@ RSpec.describe "gemcutter's dependency API" do
gem 'foo', :git => "#{file_uri_for(lib_path("foo-1.0"))}"
G
- bundle "install", :artifice => "endpoint"
+ bundle "install", artifice: "endpoint"
bundle "config set --local deployment true"
- bundle :install, :artifice => "endpoint"
+ bundle :install, artifice: "endpoint"
expect(the_bundle).to include_gems("foo 1.0")
end
it "falls back when the API errors out" do
- simulate_platform mswin
+ simulate_platform x86_mswin32
build_repo2 do
# The rcov gem is platform mswin32, but has no arch
@@ -134,7 +134,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "rcov"
G
- bundle :install, :artifice => "windows", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ bundle :install, artifice: "windows", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(out).to include("Fetching source index from #{source_uri}")
expect(the_bundle).to include_gems "rcov 1.0.0"
end
@@ -150,7 +150,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "rack"
gem "rails"
G
- bundle :install, :artifice => "endpoint_fallback"
+ bundle :install, artifice: "endpoint_fallback"
expect(out).to include("Fetching source index from #{source_uri}")
expect(the_bundle).to include_gems(
@@ -171,7 +171,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "rack"
G
- bundle :install, :verbose => true, :artifice => "endpoint_marshal_fail"
+ bundle :install, verbose: true, artifice: "endpoint_marshal_fail"
expect(out).to include("could not fetch from the dependency API, trying the full index")
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -182,7 +182,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "rack"
G
- bundle :install, :verbose => true, :artifice => "endpoint_api_forbidden"
+ bundle :install, verbose: true, artifice: "endpoint_api_forbidden"
expect(out).to include("Fetching source index from #{source_uri}")
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -193,11 +193,11 @@ RSpec.describe "gemcutter's dependency API" do
gem "rack"
G
- bundle :install, :artifice => "endpoint_host_redirect"
+ bundle :install, artifice: "endpoint_host_redirect"
expect(the_bundle).to include_gems "rack 1.0.0"
end
- it "handles host redirects without Net::HTTP::Persistent" do
+ it "handles host redirects without Gem::Net::HTTP::Persistent" do
gemfile <<-G
source "#{source_uri}"
gem "rack"
@@ -216,7 +216,7 @@ RSpec.describe "gemcutter's dependency API" do
H
end
- bundle :install, :artifice => "endpoint_host_redirect", :requires => [lib_path("disable_net_http_persistent.rb")]
+ bundle :install, artifice: "endpoint_host_redirect", requires: [lib_path("disable_net_http_persistent.rb")]
expect(out).to_not match(/Too many redirects/)
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -227,7 +227,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "rack"
G
- bundle :install, :artifice => "endpoint_redirect", :raise_on_error => false
+ bundle :install, artifice: "endpoint_redirect", raise_on_error: false
expect(err).to match(/Too many redirects/)
end
@@ -238,7 +238,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "rack"
G
- bundle "install --full-index", :artifice => "endpoint"
+ bundle "install --full-index", artifice: "endpoint"
expect(out).to include("Fetching source index from #{source_uri}")
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -249,13 +249,13 @@ RSpec.describe "gemcutter's dependency API" do
gem "rack"
G
- bundle "update --full-index", :artifice => "endpoint", :all => true
+ bundle "update --full-index", artifice: "endpoint", all: true
expect(out).to include("Fetching source index from #{source_uri}")
expect(the_bundle).to include_gems "rack 1.0.0"
end
end
- it "fetches again when more dependencies are found in subsequent sources", :bundler => "< 3" do
+ it "fetches again when more dependencies are found in subsequent sources", bundler: "< 3" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -269,7 +269,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "back_deps"
G
- bundle :install, :artifice => "endpoint_extra"
+ bundle :install, artifice: "endpoint_extra"
expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0"
end
@@ -288,7 +288,7 @@ RSpec.describe "gemcutter's dependency API" do
end
G
- bundle :install, :artifice => "endpoint_extra"
+ bundle :install, artifice: "endpoint_extra"
expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0"
end
@@ -297,7 +297,7 @@ RSpec.describe "gemcutter's dependency API" do
source "#{source_uri}"
gem "rack", "1.0.0"
G
- bundle :install, :artifice => "endpoint_extra_api"
+ bundle :install, artifice: "endpoint_extra_api"
build_repo4 do
build_gem "rack", "1.2" do |s|
@@ -310,11 +310,11 @@ RSpec.describe "gemcutter's dependency API" do
source "#{source_uri}/extra"
gem "rack", "1.2"
G
- bundle :install, :artifice => "endpoint_extra_api"
+ bundle :install, artifice: "endpoint_extra_api"
expect(the_bundle).to include_gems "rack 1.2"
end
- it "considers all possible versions of dependencies from all api gem sources", :bundler => "< 3" do
+ it "considers all possible versions of dependencies from all api gem sources", bundler: "< 3" do
# In this scenario, the gem "somegem" only exists in repo4. It depends on specific version of activesupport that
# exists only in repo1. There happens also be a version of activesupport in repo4, but not the one that version 1.0.0
# of somegem wants. This test makes sure that bundler actually finds version 1.2.3 of active support in the other
@@ -332,7 +332,7 @@ RSpec.describe "gemcutter's dependency API" do
gem 'somegem', '1.0.0'
G
- bundle :install, :artifice => "endpoint_extra_api"
+ bundle :install, artifice: "endpoint_extra_api"
expect(the_bundle).to include_gems "somegem 1.0.0"
expect(the_bundle).to include_gems "activesupport 1.2.3"
@@ -353,13 +353,13 @@ RSpec.describe "gemcutter's dependency API" do
end
G
- bundle :install, :artifice => "endpoint_extra"
+ bundle :install, artifice: "endpoint_extra"
expect(out).to include("Fetching gem metadata from http://localgemserver.test/.")
expect(out).to include("Fetching source index from http://localgemserver.test/extra")
end
- it "does not fetch every spec if the index of gems is large when doing back deps", :bundler => "< 3" do
+ it "does not fetch every spec when doing back deps", bundler: "< 3" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -369,9 +369,7 @@ RSpec.describe "gemcutter's dependency API" do
FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")]
end
- api_request_limit = low_api_request_limit_for(gem_repo2)
-
- install_gemfile <<-G, :artifice => "endpoint_extra_missing", :requires => [api_request_limit_hack_file], :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation)
+ install_gemfile <<-G, artifice: "endpoint_extra_missing"
source "#{source_uri}"
source "#{source_uri}/extra"
gem "back_deps"
@@ -380,7 +378,7 @@ RSpec.describe "gemcutter's dependency API" do
expect(the_bundle).to include_gems "back_deps 1.0"
end
- it "does not fetch every spec if the index of gems is large when doing back deps using blocks" do
+ it "does not fetch every spec when doing back deps using blocks" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -390,9 +388,7 @@ RSpec.describe "gemcutter's dependency API" do
FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")]
end
- api_request_limit = low_api_request_limit_for(gem_repo2)
-
- install_gemfile <<-G, :artifice => "endpoint_extra_missing", :requires => [api_request_limit_hack_file], :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation)
+ install_gemfile <<-G, artifice: "endpoint_extra_missing"
source "#{source_uri}"
source "#{source_uri}/extra" do
gem "back_deps"
@@ -402,18 +398,7 @@ RSpec.describe "gemcutter's dependency API" do
expect(the_bundle).to include_gems "back_deps 1.0"
end
- it "uses the endpoint if all sources support it" do
- gemfile <<-G
- source "#{source_uri}"
-
- gem 'foo'
- G
-
- bundle :install, :artifice => "endpoint_api_missing"
- expect(the_bundle).to include_gems "foo 1.0"
- end
-
- it "fetches again when more dependencies are found in subsequent sources using deployment mode", :bundler => "< 3" do
+ it "fetches again when more dependencies are found in subsequent sources using deployment mode", bundler: "< 3" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -427,9 +412,9 @@ RSpec.describe "gemcutter's dependency API" do
gem "back_deps"
G
- bundle :install, :artifice => "endpoint_extra"
+ bundle :install, artifice: "endpoint_extra"
bundle "config set --local deployment true"
- bundle :install, :artifice => "endpoint_extra"
+ bundle :install, artifice: "endpoint_extra"
expect(the_bundle).to include_gems "back_deps 1.0"
end
@@ -448,12 +433,28 @@ RSpec.describe "gemcutter's dependency API" do
end
G
- bundle :install, :artifice => "endpoint_extra"
+ bundle :install, artifice: "endpoint_extra"
bundle "config set --local deployment true"
- bundle "install", :artifice => "endpoint_extra"
+ bundle "install", artifice: "endpoint_extra"
expect(the_bundle).to include_gems "back_deps 1.0"
end
+ it "does not fetch all marshaled specs" do
+ build_repo2 do
+ build_gem "foo", "1.0"
+ build_gem "foo", "2.0"
+ end
+
+ install_gemfile <<-G, artifice: "endpoint", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, verbose: true
+ source "#{source_uri}"
+
+ gem "foo"
+ G
+
+ expect(out).to include("foo-2.0.gemspec.rz")
+ expect(out).not_to include("foo-1.0.gemspec.rz")
+ end
+
it "does not refetch if the only unmet dependency is bundler" do
build_repo2 do
build_gem "bundler_dep" do |s|
@@ -467,52 +468,40 @@ RSpec.describe "gemcutter's dependency API" do
gem "bundler_dep"
G
- bundle :install, :artifice => "endpoint", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ bundle :install, artifice: "endpoint", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(out).to include("Fetching gem metadata from #{source_uri}")
end
- it "should install when EndpointSpecification has a bin dir owned by root", :sudo => true do
- sudo "mkdir -p #{system_gem_path("bin")}"
- sudo "chown -R root #{system_gem_path("bin")}"
-
- gemfile <<-G
- source "#{source_uri}"
- gem "rails"
- G
- bundle :install, :artifice => "endpoint"
- expect(the_bundle).to include_gems "rails 2.3.2"
- end
-
- it "installs the binstubs", :bundler => "< 3" do
+ it "installs the binstubs", bundler: "< 3" do
gemfile <<-G
source "#{source_uri}"
gem "rack"
G
- bundle "install --binstubs", :artifice => "endpoint"
+ bundle "install --binstubs", artifice: "endpoint"
gembin "rackup"
expect(out).to eq("1.0.0")
end
- it "installs the bins when using --path and uses autoclean", :bundler => "< 3" do
+ it "installs the bins when using --path and uses autoclean", bundler: "< 3" do
gemfile <<-G
source "#{source_uri}"
gem "rack"
G
- bundle "install --path vendor/bundle", :artifice => "endpoint"
+ bundle "install --path vendor/bundle", artifice: "endpoint"
expect(vendored_gems("bin/rackup")).to exist
end
- it "installs the bins when using --path and uses bundle clean", :bundler => "< 3" do
+ it "installs the bins when using --path and uses bundle clean", bundler: "< 3" do
gemfile <<-G
source "#{source_uri}"
gem "rack"
G
- bundle "install --path vendor/bundle --no-clean", :artifice => "endpoint"
+ bundle "install --path vendor/bundle --no-clean", artifice: "endpoint"
expect(vendored_gems("bin/rackup")).to exist
end
@@ -523,7 +512,7 @@ RSpec.describe "gemcutter's dependency API" do
gem 'rack-obama'
G
- bundle :install, :artifice => "endpoint"
+ bundle :install, artifice: "endpoint"
expect(out).to include("Post-install message from rack:")
end
@@ -533,7 +522,7 @@ RSpec.describe "gemcutter's dependency API" do
gem 'rack_middleware'
G
- bundle :install, :artifice => "endpoint"
+ bundle :install, artifice: "endpoint"
expect(out).to include("Post-install message from rack:")
expect(out).to include("Rack's post install message")
end
@@ -542,7 +531,7 @@ RSpec.describe "gemcutter's dependency API" do
let(:user) { "user" }
let(:password) { "pass" }
let(:basic_auth_source_uri) do
- uri = Bundler::URI.parse(source_uri)
+ uri = Gem::URI.parse(source_uri)
uri.user = user
uri.password = password
@@ -555,7 +544,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "rack"
G
- bundle :install, :artifice => "endpoint_basic_authentication"
+ bundle :install, artifice: "endpoint_basic_authentication"
expect(out).not_to include("#{user}:#{password}")
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -566,7 +555,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "rack"
G
- bundle :install, :verbose => true, :artifice => "endpoint_basic_authentication"
+ 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
@@ -577,7 +566,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "rack"
G
- bundle :install, :artifice => "endpoint_marshal_fail_basic_authentication"
+ bundle :install, artifice: "endpoint_marshal_fail_basic_authentication"
expect(out).not_to include("#{user}:#{password}")
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -588,18 +577,18 @@ RSpec.describe "gemcutter's dependency API" do
gem "rack"
G
- bundle :install, :artifice => "endpoint_500", :raise_on_error => false
+ bundle :install, artifice: "endpoint_500", raise_on_error: false
expect(out).not_to include("#{user}:#{password}")
end
- it "strips http basic auth creds when warning about ambiguous sources", :bundler => "< 3" do
+ it "strips http basic auth creds when warning about ambiguous sources", bundler: "< 3" do
gemfile <<-G
source "#{basic_auth_source_uri}"
source "#{file_uri_for(gem_repo1)}"
gem "rack"
G
- bundle :install, :artifice => "endpoint_basic_authentication"
+ bundle :install, artifice: "endpoint_basic_authentication"
expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
expect(err).not_to include("#{user}:#{password}")
expect(the_bundle).to include_gems "rack 1.0.0"
@@ -611,7 +600,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "rack"
G
- bundle :install, :artifice => "endpoint_creds_diff_host"
+ bundle :install, artifice: "endpoint_creds_diff_host"
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -624,7 +613,7 @@ RSpec.describe "gemcutter's dependency API" do
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}" }
+ 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"
@@ -642,7 +631,7 @@ RSpec.describe "gemcutter's dependency API" do
it "reads authentication details by host name from bundle config" do
bundle "config set #{source_hostname} #{user}:#{password}"
- bundle :install, :artifice => "endpoint_strict_basic_authentication"
+ bundle :install, artifice: "endpoint_strict_basic_authentication"
expect(out).to include("Fetching gem metadata from #{source_uri}")
expect(the_bundle).to include_gems "rack 1.0.0"
@@ -652,7 +641,7 @@ RSpec.describe "gemcutter's dependency API" do
# The trailing slash is necessary here; Fetcher canonicalizes the URI.
bundle "config set #{source_uri}/ #{user}:#{password}"
- bundle :install, :artifice => "endpoint_strict_basic_authentication"
+ bundle :install, artifice: "endpoint_strict_basic_authentication"
expect(out).to include("Fetching gem metadata from #{source_uri}")
expect(the_bundle).to include_gems "rack 1.0.0"
@@ -660,7 +649,7 @@ RSpec.describe "gemcutter's dependency API" do
it "should use the API" do
bundle "config set #{source_hostname} #{user}:#{password}"
- bundle :install, :artifice => "endpoint_strict_basic_authentication"
+ bundle :install, artifice: "endpoint_strict_basic_authentication"
expect(out).to include("Fetching gem metadata from #{source_uri}")
expect(the_bundle).to include_gems "rack 1.0.0"
end
@@ -673,19 +662,19 @@ RSpec.describe "gemcutter's dependency API" do
bundle "config set #{source_hostname} otheruser:wrong"
- bundle :install, :artifice => "endpoint_strict_basic_authentication"
+ bundle :install, artifice: "endpoint_strict_basic_authentication"
expect(the_bundle).to include_gems "rack 1.0.0"
end
it "shows instructions if auth is not provided for the source" do
- bundle :install, :artifice => "endpoint_strict_basic_authentication", :raise_on_error => false
+ bundle :install, artifice: "endpoint_strict_basic_authentication", raise_on_error: false
expect(err).to include("bundle config set --global #{source_hostname} username:password")
end
it "fails if authentication has already been provided, but failed" do
bundle "config set #{source_hostname} #{user}:wrong"
- bundle :install, :artifice => "endpoint_strict_basic_authentication", :raise_on_error => false
+ bundle :install, artifice: "endpoint_strict_basic_authentication", raise_on_error: false
expect(err).to include("Bad username or password")
end
end
@@ -699,7 +688,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "rack"
G
- bundle :install, :artifice => "endpoint_basic_authentication"
+ bundle :install, artifice: "endpoint_basic_authentication"
expect(the_bundle).to include_gems "rack 1.0.0"
end
end
@@ -724,7 +713,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "rack"
G
- bundle :install, :env => { "RUBYOPT" => opt_add("-I#{bundled_app("broken_ssl")}", ENV["RUBYOPT"]) }, :raise_on_error => false
+ bundle :install, env: { "RUBYOPT" => opt_add("-I#{bundled_app("broken_ssl")}", ENV["RUBYOPT"]) }, raise_on_error: false
expect(err).to include("OpenSSL")
end
end
@@ -734,7 +723,7 @@ RSpec.describe "gemcutter's dependency API" do
# Install a monkeypatch that reproduces the effects of openssl raising
# a certificate validation error when RubyGems tries to connect.
gemfile <<-G
- class Net::HTTP
+ class Gem::Net::HTTP
def start
raise OpenSSL::SSL::SSLError, "certificate verify failed"
end
@@ -744,7 +733,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "rack"
G
- bundle :install, :raise_on_error => false
+ bundle :install, raise_on_error: false
expect(err).to match(/could not verify the SSL certificate/i)
end
end
@@ -752,7 +741,7 @@ RSpec.describe "gemcutter's dependency API" do
context ".gemrc with sources is present" do
it "uses other sources declared in the Gemfile" do
File.open(home(".gemrc"), "w") do |file|
- file.puts({ :sources => ["https://rubygems.org"] }.to_yaml)
+ file.puts({ sources: ["https://rubygems.org"] }.to_yaml)
end
begin
@@ -761,7 +750,7 @@ RSpec.describe "gemcutter's dependency API" do
gem 'rack'
G
- bundle "install", :artifice => "endpoint_marshal_fail"
+ bundle "install", artifice: "endpoint_marshal_fail"
ensure
home(".gemrc").rmtree
end
diff --git a/spec/bundler/install/gems/flex_spec.rb b/spec/bundler/install/gems/flex_spec.rb
index 326ec51214..8ef3984975 100644
--- a/spec/bundler/install/gems/flex_spec.rb
+++ b/spec/bundler/install/gems/flex_spec.rb
@@ -156,7 +156,7 @@ RSpec.describe "bundle flex_install" do
end
end
- describe "when Gemfile conflicts with lockfile" do
+ describe "when running bundle install and Gemfile conflicts with lockfile" do
before(:each) do
build_repo2
install_gemfile <<-G
@@ -183,34 +183,70 @@ RSpec.describe "bundle flex_install" do
end
it "does not install gems whose dependencies are not met" do
- bundle :install, :raise_on_error => false
- ruby <<-RUBY, :raise_on_error => false
+ bundle :install, raise_on_error: false
+ ruby <<-RUBY, raise_on_error: false
require 'bundler/setup'
RUBY
expect(err).to match(/could not find gem 'rack-obama/i)
end
- it "suggests bundle update when the Gemfile requires different versions than the lock" do
+ it "discards the locked gems when the Gemfile requires different versions than the lock" do
bundle "config set force_ruby_platform true"
- nice_error = <<-E.strip.gsub(/^ {8}/, "")
- Bundler could not find compatible versions for gem "rack":
- In snapshot (Gemfile.lock):
- rack (= 0.9.1)
+ nice_error = <<~E.strip
+ Could not find compatible versions
- In Gemfile:
- rack-obama (= 2.0) was resolved to 2.0, which depends on
- rack (= 1.2)
+ Because rack-obama >= 2.0 depends on rack = 1.2
+ and rack = 1.2 could not be found in rubygems repository #{file_uri_for(gem_repo2)}/, cached gems or installed locally,
+ rack-obama >= 2.0 cannot be used.
+ So, because Gemfile depends on rack-obama = 2.0,
+ version solving has failed.
+ E
+
+ bundle :install, retry: 0, raise_on_error: false
+ expect(err).to end_with(nice_error)
+ end
- rack_middleware was resolved to 1.0, which depends on
- rack (= 0.9.1)
+ it "does not include conflicts with a single requirement tree, because that can't possibly be a conflict" do
+ bundle "config set force_ruby_platform true"
- Running `bundle update` will rebuild your snapshot from scratch, using only
- the gems in your Gemfile, which may resolve the conflict.
+ bad_error = <<~E.strip
+ Bundler could not find compatible versions for gem "rack-obama":
+ In Gemfile:
+ rack-obama (= 2.0)
E
- bundle :install, :retry => 0, :raise_on_error => false
- expect(err).to end_with(nice_error)
+ bundle "update rack_middleware", retry: 0, raise_on_error: false
+ expect(err).not_to end_with(bad_error)
+ end
+ end
+
+ describe "when running bundle update and Gemfile conflicts with lockfile" do
+ before(:each) do
+ build_repo4 do
+ build_gem "jekyll-feed", "0.16.0"
+ build_gem "jekyll-feed", "0.15.1"
+
+ build_gem "github-pages", "226" do |s|
+ s.add_dependency "jekyll-feed", "0.15.1"
+ end
+ end
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "jekyll-feed", "~> 0.12"
+ G
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "github-pages", "~> 226"
+ gem "jekyll-feed", "~> 0.12"
+ G
+ end
+
+ it "discards the conflicting lockfile information and resolves properly" do
+ bundle :update, raise_on_error: false, all: true
+ expect(err).to be_empty
end
end
@@ -229,14 +265,32 @@ RSpec.describe "bundle flex_install" do
G
end
- it "does something" do
- expect do
- bundle "install", :raise_on_error => false
- end.not_to change { File.read(bundled_app_lock) }
+ it "should work when you install" do
+ bundle "install"
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo1, "rack", "0.9.1"
+ c.checksum gem_repo1, "rack-obama", "1.0"
+ end
- expect(err).to include("rack = 0.9.1")
- expect(err).to include("locked at 1.0.0")
- expect(err).to include("bundle update rack")
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+ rack (0.9.1)
+ rack-obama (1.0)
+ rack
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ rack (= 0.9.1)
+ rack-obama
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
end
it "should work when you update" do
@@ -259,24 +313,28 @@ RSpec.describe "bundle flex_install" do
gem "rack"
G
- lockfile_should_be <<-L
- GEM
- remote: #{file_uri_for(gem_repo1)}/
- specs:
- rack (1.0.0)
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo1, "rack", "1.0.0"
+ end
- GEM
- remote: #{file_uri_for(gem_repo2)}/
- specs:
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+ rack (1.0.0)
- PLATFORMS
- #{lockfile_platforms}
+ GEM
+ remote: #{file_uri_for(gem_repo2)}/
+ specs:
- DEPENDENCIES
- rack
+ PLATFORMS
+ #{lockfile_platforms}
- BUNDLED WITH
- #{Bundler::VERSION}
+ DEPENDENCIES
+ rack
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
L
end
end
@@ -301,7 +359,7 @@ RSpec.describe "bundle flex_install" do
end
end
- it "prints the correct error message" do
+ it "resolves them" do
# install Rails 3.0.0.rc
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
@@ -310,13 +368,12 @@ RSpec.describe "bundle flex_install" do
G
# upgrade Rails to 3.0.0 and then install again
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0.0"
gem "capybara", "0.3.9"
G
-
- expect(err).to include("Gemfile.lock")
+ expect(err).to be_empty
end
end
end
diff --git a/spec/bundler/install/gems/fund_spec.rb b/spec/bundler/install/gems/fund_spec.rb
index f521b0296f..9aadc9ed25 100644
--- a/spec/bundler/install/gems/fund_spec.rb
+++ b/spec/bundler/install/gems/fund_spec.rb
@@ -6,20 +6,20 @@ RSpec.describe "bundle install" do
build_repo2 do
build_gem "has_funding_and_other_metadata" do |s|
s.metadata = {
- "bug_tracker_uri" => "https://example.com/user/bestgemever/issues",
- "changelog_uri" => "https://example.com/user/bestgemever/CHANGELOG.md",
+ "bug_tracker_uri" => "https://example.com/user/bestgemever/issues",
+ "changelog_uri" => "https://example.com/user/bestgemever/CHANGELOG.md",
"documentation_uri" => "https://www.example.info/gems/bestgemever/0.0.1",
- "homepage_uri" => "https://bestgemever.example.io",
- "mailing_list_uri" => "https://groups.example.com/bestgemever",
- "funding_uri" => "https://example.com/has_funding_and_other_metadata/funding",
- "source_code_uri" => "https://example.com/user/bestgemever",
- "wiki_uri" => "https://example.com/user/bestgemever/wiki",
+ "homepage_uri" => "https://bestgemever.example.io",
+ "mailing_list_uri" => "https://groups.example.com/bestgemever",
+ "funding_uri" => "https://example.com/has_funding_and_other_metadata/funding",
+ "source_code_uri" => "https://example.com/user/bestgemever",
+ "wiki_uri" => "https://example.com/user/bestgemever/wiki",
}
end
build_gem "has_funding", "1.2.3" do |s|
s.metadata = {
- "funding_uri" => "https://example.com/has_funding/funding",
+ "funding_uri" => "https://example.com/has_funding/funding",
}
end
@@ -52,6 +52,33 @@ RSpec.describe "bundle install" do
end
end
+ context "when gems include a fund URI but `ignore_funding_requests` is configured" do
+ before do
+ bundle "config set ignore_funding_requests true"
+ end
+
+ it "does not display the plural fund message after installing" do
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'has_funding_and_other_metadata'
+ gem 'has_funding'
+ gem 'rack-obama'
+ G
+
+ expect(out).not_to include("2 installed gems you directly depend on are looking for funding.")
+ end
+
+ it "does not display the singular fund message after installing" do
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'has_funding'
+ gem 'rack-obama'
+ G
+
+ expect(out).not_to include("1 installed gem you directly depend on is looking for funding.")
+ end
+ end
+
context "when gems do not include fund messages" do
it "does not display any fund messages" do
install_gemfile <<-G
diff --git a/spec/bundler/install/gems/native_extensions_spec.rb b/spec/bundler/install/gems/native_extensions_spec.rb
index d5cafcfc2c..907778a384 100644
--- a/spec/bundler/install/gems/native_extensions_spec.rb
+++ b/spec/bundler/install/gems/native_extensions_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe "installing a gem with native extensions", :ruby_repo do
+RSpec.describe "installing a gem with native extensions" do
it "installs" do
build_repo2 do
build_gem "c_extension" do |s|
@@ -91,7 +91,7 @@ RSpec.describe "installing a gem with native extensions", :ruby_repo do
it "installs correctly from git when multiple gems with extensions share one repository" do
build_repo2 do
["one", "two"].each do |n|
- build_lib "c_extension_#{n}", "1.0", :path => lib_path("gems/c_extension_#{n}") do |s|
+ build_lib "c_extension_#{n}", "1.0", path: lib_path("gems/c_extension_#{n}") do |s|
s.extensions = ["ext/extconf.rb"]
s.write "ext/extconf.rb", <<-E
require "mkmf"
@@ -119,7 +119,7 @@ RSpec.describe "installing a gem with native extensions", :ruby_repo do
C
end
end
- build_git "gems", :path => lib_path("gems"), :gemspec => false
+ build_git "gems", path: lib_path("gems"), gemspec: false
end
bundle "config set build.c_extension_one --with-c_extension_one=one"
diff --git a/spec/bundler/install/gems/resolving_spec.rb b/spec/bundler/install/gems/resolving_spec.rb
index 94fac0052c..c5f9c4a3d3 100644
--- a/spec/bundler/install/gems/resolving_spec.rb
+++ b/spec/bundler/install/gems/resolving_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe "bundle install with install-time dependencies" do
s.extensions << "Rakefile"
s.write "Rakefile", <<-RUBY
task :default do
- path = File.expand_path("../lib", __FILE__)
+ path = File.expand_path("lib", __dir__)
FileUtils.mkdir_p(path)
File.open("\#{path}/implicit_rake_dep.rb", "w") do |f|
f.puts "IMPLICIT_RAKE_DEP = 'YES'"
@@ -20,7 +20,7 @@ RSpec.describe "bundle install with install-time dependencies" do
s.extensions << "Rakefile"
s.write "Rakefile", <<-RUBY
task :default do
- path = File.expand_path("../lib", __FILE__)
+ path = File.expand_path("lib", __dir__)
FileUtils.mkdir_p(path)
File.open("\#{path}/another_implicit_rake_dep.rb", "w") do |f|
f.puts "ANOTHER_IMPLICIT_RAKE_DEP = 'YES'"
@@ -42,7 +42,7 @@ RSpec.describe "bundle install with install-time dependencies" do
s.extensions << "Rakefile"
s.write "Rakefile", <<-RUBY
task :default do
- path = File.expand_path("../lib", __FILE__)
+ path = File.expand_path("lib", __dir__)
FileUtils.mkdir_p(path)
File.open("\#{path}/net_build_extensions.rb", "w") do |f|
f.puts "NET_BUILD_EXTENSIONS = 'YES'"
@@ -101,16 +101,14 @@ RSpec.describe "bundle install with install-time dependencies" do
end
it "installs gems with a dependency with no type" do
- skip "incorrect data check error" if Gem.win_platform?
-
build_repo2
path = "#{gem_repo2}/#{Gem::MARSHAL_SPEC_DIR}/actionpack-2.3.2.gemspec.rz"
spec = Marshal.load(Bundler.rubygems.inflate(File.binread(path)))
spec.dependencies.each do |d|
- d.instance_variable_set(:@type, :fail)
+ d.instance_variable_set(:@type, "fail")
end
- File.open(path, "w") do |f|
+ File.open(path, "wb") do |f|
f.write Gem.deflate(Marshal.dump(spec))
end
@@ -133,7 +131,7 @@ RSpec.describe "bundle install with install-time dependencies" do
end
it "installs plugins depended on by other plugins" do
- install_gemfile <<-G, :env => { "DEBUG" => "1" }
+ install_gemfile <<-G, env: { "DEBUG" => "1" }
source "#{file_uri_for(gem_repo2)}"
gem "net_a"
G
@@ -142,7 +140,7 @@ RSpec.describe "bundle install with install-time dependencies" do
end
it "installs multiple levels of dependencies" do
- install_gemfile <<-G, :env => { "DEBUG" => "1" }
+ install_gemfile <<-G, env: { "DEBUG" => "1" }
source "#{file_uri_for(gem_repo2)}"
gem "net_c"
gem "net_e"
@@ -159,9 +157,9 @@ RSpec.describe "bundle install with install-time dependencies" do
gem "net_e"
G
- bundle :install, :env => { "BUNDLER_DEBUG_RESOLVER" => "1", "DEBUG" => "1" }
+ bundle :install, env: { "BUNDLER_DEBUG_RESOLVER" => "1", "DEBUG" => "1" }
- expect(out).to include("BUNDLER: Starting resolution")
+ expect(out).to include("Resolving dependencies...")
end
end
@@ -173,9 +171,9 @@ RSpec.describe "bundle install with install-time dependencies" do
gem "net_e"
G
- bundle :install, :env => { "DEBUG_RESOLVER" => "1", "DEBUG" => "1" }
+ bundle :install, env: { "DEBUG_RESOLVER" => "1", "DEBUG" => "1" }
- expect(out).to include("BUNDLER: Starting resolution")
+ expect(out).to include("Resolving dependencies...")
end
end
@@ -187,18 +185,12 @@ RSpec.describe "bundle install with install-time dependencies" do
gem "net_e"
G
- bundle :install, :env => { "DEBUG_RESOLVER_TREE" => "1", "DEBUG" => "1" }
-
- activated_groups = if local_platforms.any?
- "net_b (1.0) (ruby), net_b (1.0) (#{local_platforms.join(", ")})"
- else
- "net_b (1.0) (ruby)"
- end
+ bundle :install, env: { "DEBUG_RESOLVER_TREE" => "1", "DEBUG" => "1" }
expect(out).to include(" net_b").
- and include("BUNDLER: Starting resolution").
- and include("BUNDLER: Finished resolution").
- and include("Attempting to activate [#{activated_groups}]")
+ and include("Resolving dependencies...").
+ and include("Solution found after 1 attempts:").
+ and include("selected net_b 1.0")
end
end
end
@@ -216,16 +208,327 @@ RSpec.describe "bundle install with install-time dependencies" do
end
end
- install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
- ruby "#{RUBY_VERSION}"
+ install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ ruby "#{Gem.ruby_version}"
source "http://localgemserver.test/"
gem 'rack'
G
- expect(out).to_not include("rack-9001.0.0 requires ruby version > 9000")
+ expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000")
expect(the_bundle).to include_gems("rack 1.2")
end
+ it "installs the older version when using servers not implementing the compact index API" do
+ build_repo2 do
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
+ end
+
+ build_gem "rack", "9001.0.0" do |s|
+ s.required_ruby_version = "> 9000"
+ end
+ end
+
+ install_gemfile <<-G, artifice: "endpoint", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ ruby "#{Gem.ruby_version}"
+ source "http://localgemserver.test/"
+ gem 'rack'
+ G
+
+ expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000")
+ expect(the_bundle).to include_gems("rack 1.2")
+ end
+
+ context "when there is a lockfile using the newer incompatible version" do
+ before do
+ build_repo2 do
+ build_gem "parallel_tests", "3.7.0" do |s|
+ s.required_ruby_version = ">= #{current_ruby_minor}"
+ end
+
+ build_gem "parallel_tests", "3.8.0" do |s|
+ s.required_ruby_version = ">= #{next_ruby_minor}"
+ end
+ end
+
+ gemfile <<-G
+ source "http://localgemserver.test/"
+ gem 'parallel_tests'
+ G
+
+ checksums = checksums_section do |c|
+ c.checksum gem_repo2, "parallel_tests", "3.8.0"
+ end
+
+ lockfile <<~L
+ GEM
+ remote: http://localgemserver.test/
+ specs:
+ parallel_tests (3.8.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ parallel_tests
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "automatically updates lockfile to use the older version" do
+ bundle "install --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo2, "parallel_tests", "3.7.0"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: http://localgemserver.test/
+ specs:
+ parallel_tests (3.7.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ parallel_tests
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "gives a meaningful error if we're in frozen mode" do
+ expect do
+ bundle "install --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s, "BUNDLE_FROZEN" => "true" }, raise_on_error: false
+ end.not_to change { lockfile }
+
+ expect(err).to include("parallel_tests-3.8.0 requires ruby version >= #{next_ruby_minor}")
+ expect(err).not_to include("That means the author of parallel_tests (3.8.0) has removed it.")
+ end
+ end
+
+ context "with transitive dependencies in a lockfile" do
+ before do
+ build_repo2 do
+ build_gem "rubocop", "1.28.2" do |s|
+ s.required_ruby_version = ">= #{current_ruby_minor}"
+
+ s.add_dependency "rubocop-ast", ">= 1.17.0", "< 2.0"
+ end
+
+ build_gem "rubocop", "1.35.0" do |s|
+ s.required_ruby_version = ">= #{next_ruby_minor}"
+
+ s.add_dependency "rubocop-ast", ">= 1.20.1", "< 2.0"
+ end
+
+ build_gem "rubocop-ast", "1.17.0" do |s|
+ s.required_ruby_version = ">= #{current_ruby_minor}"
+ end
+
+ build_gem "rubocop-ast", "1.21.0" do |s|
+ s.required_ruby_version = ">= #{next_ruby_minor}"
+ end
+ end
+
+ gemfile <<-G
+ source "http://localgemserver.test/"
+ gem 'rubocop'
+ G
+
+ checksums = checksums_section do |c|
+ c.checksum gem_repo2, "rubocop", "1.35.0"
+ c.checksum gem_repo2, "rubocop-ast", "1.21.0"
+ end
+
+ lockfile <<~L
+ GEM
+ remote: http://localgemserver.test/
+ specs:
+ rubocop (1.35.0)
+ rubocop-ast (>= 1.20.1, < 2.0)
+ rubocop-ast (1.21.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ parallel_tests
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "automatically updates lockfile to use the older compatible versions" do
+ bundle "install --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo2, "rubocop", "1.28.2"
+ c.checksum gem_repo2, "rubocop-ast", "1.17.0"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: http://localgemserver.test/
+ specs:
+ rubocop (1.28.2)
+ rubocop-ast (>= 1.17.0, < 2.0)
+ rubocop-ast (1.17.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ rubocop
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ context "with a Gemfile and lock file that don't resolve under the current platform" do
+ before do
+ build_repo4 do
+ build_gem "sorbet", "0.5.10554" do |s|
+ s.add_dependency "sorbet-static", "0.5.10554"
+ end
+
+ build_gem "sorbet-static", "0.5.10554" do |s|
+ s.platform = "universal-darwin-21"
+ end
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+ gem 'sorbet', '= 0.5.10554'
+ G
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ sorbet (0.5.10554)
+ sorbet-static (= 0.5.10554)
+ sorbet-static (0.5.10554-universal-darwin-21)
+
+ PLATFORMS
+ arm64-darwin-21
+
+ DEPENDENCIES
+ sorbet (= 0.5.10554)
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ it "raises a proper error" do
+ simulate_platform "aarch64-linux" do
+ bundle "install", raise_on_error: false
+ end
+
+ nice_error = <<~E.strip
+ Could not find gems matching 'sorbet-static (= 0.5.10554)' valid for all resolution platforms (arm64-darwin-21, aarch64-linux) in rubygems repository #{file_uri_for(gem_repo4)}/, cached gems or installed locally.
+
+ The source contains the following gems matching 'sorbet-static (= 0.5.10554)':
+ * sorbet-static-0.5.10554-universal-darwin-21
+ E
+ expect(err).to end_with(nice_error)
+ end
+ end
+
+ context "when adding a new gem that does not resolve under all locked platforms" do
+ before do
+ simulate_platform "x86_64-linux" do
+ build_repo4 do
+ build_gem "nokogiri", "1.14.0" do |s|
+ s.platform = "x86_64-linux"
+ end
+ build_gem "nokogiri", "1.14.0" do |s|
+ s.platform = "arm-linux"
+ end
+
+ build_gem "sorbet-static", "0.5.10696" do |s|
+ s.platform = "x86_64-linux"
+ end
+ end
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ nokogiri (1.14.0-arm-linux)
+ nokogiri (1.14.0-x86_64-linux)
+
+ PLATFORMS
+ arm-linux
+ x86_64-linux
+
+ DEPENDENCIES
+ nokogiri
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "nokogiri"
+ gem "sorbet-static"
+ G
+
+ bundle "lock", raise_on_error: false
+ end
+ end
+
+ it "raises a proper error" do
+ nice_error = <<~E.strip
+ Could not find gems matching 'sorbet-static' valid for all resolution platforms (arm-linux, x86_64-linux) in rubygems repository #{file_uri_for(gem_repo4)}/, cached gems or installed locally.
+
+ The source contains the following gems matching 'sorbet-static':
+ * sorbet-static-0.5.10696-x86_64-linux
+ E
+ expect(err).to end_with(nice_error)
+ end
+ end
+
+ it "gives a meaningful error on ruby version mismatches between dependencies" do
+ build_repo4 do
+ build_gem "requires-old-ruby" do |s|
+ s.required_ruby_version = "< #{Gem.ruby_version}"
+ end
+ end
+
+ build_lib("foo", path: bundled_app) do |s|
+ s.required_ruby_version = ">= #{Gem.ruby_version}"
+
+ s.add_dependency "requires-old-ruby"
+ end
+
+ install_gemfile <<-G, raise_on_error: false
+ source "#{file_uri_for(gem_repo4)}"
+ gemspec
+ G
+
+ expect(err).to end_with <<~E.strip
+ Could not find compatible versions
+
+ Because every version of foo depends on requires-old-ruby >= 0
+ and every version of requires-old-ruby depends on Ruby < #{Gem.ruby_version},
+ every version of foo requires Ruby < #{Gem.ruby_version}.
+ So, because Gemfile depends on foo >= 0
+ and current Ruby version is = #{Gem.ruby_version},
+ version solving has failed.
+ E
+ end
+
it "installs the older version under rate limiting conditions" do
build_repo4 do
build_gem "rack", "9001.0.0" do |s|
@@ -235,14 +538,14 @@ RSpec.describe "bundle install with install-time dependencies" do
build_gem "foo1", "1.0"
end
- install_gemfile <<-G, :artifice => "compact_index_rate_limited", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
- ruby "#{RUBY_VERSION}"
+ install_gemfile <<-G, artifice: "compact_index_rate_limited", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ ruby "#{Gem.ruby_version}"
source "http://localgemserver.test/"
gem 'rack'
gem 'foo1'
G
- expect(out).to_not include("rack-9001.0.0 requires ruby version > 9000")
+ expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000")
expect(the_bundle).to include_gems("rack 1.2")
end
@@ -252,22 +555,22 @@ RSpec.describe "bundle install with install-time dependencies" do
s.required_ruby_version = "> 9000"
end
build_gem "rack", "1.2" do |s|
- s.platform = mingw
+ s.platform = x86_mingw32
s.required_ruby_version = "> 9000"
end
build_gem "rack", "1.2"
end
- simulate_platform mingw do
- install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
- ruby "#{RUBY_VERSION}"
+ simulate_platform x86_mingw32 do
+ install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ ruby "#{Gem.ruby_version}"
source "http://localgemserver.test/"
gem 'rack'
G
end
- expect(out).to_not include("rack-9001.0.0 requires ruby version > 9000")
- expect(out).to_not include("rack-1.2-#{Bundler.local_platform} requires ruby version > 9000")
+ expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000")
+ expect(err).to_not include("rack-1.2-#{Bundler.local_platform} requires ruby version > 9000")
expect(the_bundle).to include_gems("rack 1.2")
end
end
@@ -281,14 +584,32 @@ RSpec.describe "bundle install with install-time dependencies" do
end
end
- let(:ruby_requirement) { %("#{RUBY_VERSION}") }
- let(:error_message_requirement) { "~> #{RUBY_VERSION}.0" }
+ let(:ruby_requirement) { %("#{Gem.ruby_version}") }
+ let(:error_message_requirement) { "= #{Gem.ruby_version}" }
+
+ it "raises a proper error that mentions the current Ruby version during resolution" do
+ install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, raise_on_error: false
+ source "http://localgemserver.test/"
+ gem 'require_ruby'
+ G
+
+ expect(out).to_not include("Gem::InstallError: require_ruby requires Ruby version > 9000")
+
+ nice_error = <<~E.strip
+ Could not find compatible versions
+
+ Because every version of require_ruby depends on Ruby > 9000
+ and Gemfile depends on require_ruby >= 0,
+ Ruby > 9000 is required.
+ So, because current Ruby version is #{error_message_requirement},
+ version solving has failed.
+ E
+ expect(err).to end_with(nice_error)
+ end
shared_examples_for "ruby version conflicts" do
it "raises an error during resolution" do
- skip "ruby requirement includes platform and it shouldn't" if Gem.win_platform?
-
- install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, :raise_on_error => false
+ install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, raise_on_error: false
source "http://localgemserver.test/"
ruby #{ruby_requirement}
gem 'require_ruby'
@@ -296,15 +617,14 @@ RSpec.describe "bundle install with install-time dependencies" do
expect(out).to_not include("Gem::InstallError: require_ruby requires Ruby version > 9000")
- nice_error = strip_whitespace(<<-E).strip
- Bundler found conflicting requirements for the Ruby\0 version:
- In Gemfile:
- Ruby\0 (#{error_message_requirement})
-
- require_ruby was resolved to 1.0, which depends on
- Ruby\0 (> 9000)
+ nice_error = <<~E.strip
+ Could not find compatible versions
- Ruby\0 (> 9000), which is required by gem 'require_ruby', is not available in the local ruby installation
+ Because every version of require_ruby depends on Ruby > 9000
+ and Gemfile depends on require_ruby >= 0,
+ Ruby > 9000 is required.
+ So, because current Ruby version is #{error_message_requirement},
+ version solving has failed.
E
expect(err).to end_with(nice_error)
end
@@ -314,7 +634,6 @@ RSpec.describe "bundle install with install-time dependencies" do
describe "with a < requirement" do
let(:ruby_requirement) { %("< 5000") }
- let(:error_message_requirement) { "< 5000" }
it_behaves_like "ruby version conflicts"
end
@@ -322,7 +641,6 @@ RSpec.describe "bundle install with install-time dependencies" do
describe "with a compound requirement" do
let(:reqs) { ["> 0.1", "< 5000"] }
let(:ruby_requirement) { reqs.map(&:dump).join(", ") }
- let(:error_message_requirement) { Gem::Requirement.new(reqs).to_s }
it_behaves_like "ruby version conflicts"
end
@@ -337,13 +655,20 @@ RSpec.describe "bundle install with install-time dependencies" do
end
end
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo2)}"
gem 'require_rubygems'
G
expect(err).to_not include("Gem::InstallError: require_rubygems requires RubyGems version > 9000")
- expect(err).to include("require_rubygems-1.0 requires rubygems version > 9000, which is incompatible with the current version, #{Gem::VERSION}")
+ nice_error = <<~E.strip
+ Because every version of require_rubygems depends on RubyGems > 9000
+ and Gemfile depends on require_rubygems >= 0,
+ RubyGems > 9000 is required.
+ So, because current RubyGems version is = #{Gem::VERSION},
+ version solving has failed.
+ E
+ expect(err).to end_with(nice_error)
end
end
end
diff --git a/spec/bundler/install/gems/standalone_spec.rb b/spec/bundler/install/gems/standalone_spec.rb
index b3b9d4d46b..46cab2dfeb 100644
--- a/spec/bundler/install/gems/standalone_spec.rb
+++ b/spec/bundler/install/gems/standalone_spec.rb
@@ -32,6 +32,21 @@ RSpec.shared_examples "bundle install --standalone" do
expect(out).to eq(expected_gems.values.join("\n"))
end
+ it "makes the gems available without bundler nor rubygems" do
+ testrb = String.new <<-RUBY
+ $:.unshift File.expand_path("bundle")
+ require "bundler/setup"
+
+ RUBY
+ expected_gems.each do |k, _|
+ testrb << "\nrequire \"#{k}\""
+ testrb << "\nputs #{k.upcase}"
+ end
+ sys_exec %(#{Gem.ruby} --disable-gems -w -e #{testrb.shellescape})
+
+ expect(out).to eq(expected_gems.values.join("\n"))
+ end
+
it "makes the gems available without bundler via Kernel.require" do
testrb = String.new <<-RUBY
$:.unshift File.expand_path("bundle")
@@ -82,7 +97,23 @@ RSpec.shared_examples "bundle install --standalone" do
testrb << "\nrequire \"#{k}\""
testrb << "\nputs #{k.upcase}"
end
- ruby testrb, :dir => "#{bundled_app}2"
+ ruby testrb, dir: "#{bundled_app}2"
+
+ expect(out).to eq(expected_gems.values.join("\n"))
+ end
+
+ it "skips activating gems" do
+ testrb = String.new <<-RUBY
+ $:.unshift File.expand_path("bundle")
+ require "bundler/setup"
+
+ gem "do_not_activate_me"
+ RUBY
+ expected_gems.each do |k, _|
+ testrb << "\nrequire \"#{k}\""
+ testrb << "\nputs #{k.upcase}"
+ end
+ sys_exec %(#{Gem.ruby} -w -e #{testrb.shellescape})
expect(out).to eq(expected_gems.values.join("\n"))
end
@@ -95,7 +126,7 @@ RSpec.shared_examples "bundle install --standalone" do
gem "rails"
G
bundle "config set --local path #{bundled_app("bundle")}"
- bundle :install, :standalone => true, :dir => cwd
+ bundle :install, standalone: true, dir: cwd
end
let(:expected_gems) do
@@ -108,10 +139,113 @@ RSpec.shared_examples "bundle install --standalone" do
include_examples "common functionality"
end
- describe "with gems with native extension", :ruby_repo do
+ describe "with default gems and a lockfile", :ruby_repo do
before do
+ realworld_system_gems "tsort --version 0.1.0"
+
+ necessary_system_gems = ["optparse --version 0.1.1", "psych --version 3.3.2", "logger --version 1.4.3", "etc --version 1.2.0", "stringio --version 3.1.0"]
+ necessary_system_gems += ["shellwords --version 0.1.0", "base64 --version 0.1.0", "resolv --version 0.2.1"] if Gem.rubygems_version < Gem::Version.new("3.3.a")
+ necessary_system_gems += ["yaml --version 0.1.1"] if Gem.rubygems_version < Gem::Version.new("3.4.a")
+ realworld_system_gems(*necessary_system_gems, path: scoped_gem_path(bundled_app("bundle")))
+
+ build_gem "foo", "1.0.0", to_system: true, default: true do |s|
+ s.add_dependency "bar"
+ end
+
+ build_gem "bar", "1.0.0", to_system: true, default: true
+
+ build_repo4 do
+ build_gem "foo", "1.0.0" do |s|
+ s.add_dependency "bar"
+ end
+
+ build_gem "bar", "1.0.0"
+ end
+
+ gemfile <<-G
+ source "https://gem.repo4"
+ gem "foo"
+ G
+
+ bundle "lock", dir: cwd, artifice: "compact_index"
+ end
+
+ it "works and points to the vendored copies, not to the default copies", :realworld do
bundle "config set --local path #{bundled_app("bundle")}"
- install_gemfile <<-G, :standalone => true, :dir => cwd
+ bundle :install, standalone: true, dir: cwd, artifice: "compact_index", env: { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }
+
+ load_path_lines = bundled_app("bundle/bundler/setup.rb").read.split("\n").select {|line| line.start_with?("$:.unshift") }
+
+ expect(load_path_lines).to eq [
+ '$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/bar-1.0.0/lib")',
+ '$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/foo-1.0.0/lib")',
+ ]
+ end
+ end
+
+ describe "with Gemfiles using absolute path sources and resulting bundle moved to a folder hierarchy with different nesting" do
+ before do
+ build_lib "minitest", "1.0.0", path: lib_path("minitest")
+
+ Dir.mkdir bundled_app("app")
+
+ gemfile bundled_app("app/Gemfile"), <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "minitest", :path => "#{lib_path("minitest")}"
+ G
+
+ bundle "install", standalone: true, dir: bundled_app("app")
+
+ Dir.mkdir tmp("one_more_level")
+ FileUtils.mv bundled_app, tmp("one_more_level")
+ end
+
+ it "also works" do
+ ruby <<-RUBY, dir: tmp("one_more_level/bundled_app/app")
+ require "./bundle/bundler/setup"
+
+ require "minitest"
+ puts MINITEST
+ RUBY
+
+ expect(out).to eq("1.0.0")
+ expect(err).to be_empty
+ end
+ end
+
+ describe "with Gemfiles using relative path sources and app moved to a different root" do
+ before do
+ FileUtils.mkdir_p bundled_app("app/vendor")
+
+ build_lib "minitest", "1.0.0", path: bundled_app("app/vendor/minitest")
+
+ gemfile bundled_app("app/Gemfile"), <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "minitest", :path => "vendor/minitest"
+ G
+
+ bundle "install", standalone: true, dir: bundled_app("app")
+
+ FileUtils.mv(bundled_app("app"), bundled_app2("app"))
+ end
+
+ it "also works" do
+ ruby <<-RUBY, dir: bundled_app2("app")
+ require "./bundle/bundler/setup"
+
+ require "minitest"
+ puts MINITEST
+ RUBY
+
+ expect(out).to eq("1.0.0")
+ expect(err).to be_empty
+ end
+ end
+
+ describe "with gems with native extension" do
+ before do
+ bundle "config set --local path #{bundled_app("bundle")}"
+ install_gemfile <<-G, standalone: true, dir: cwd
source "#{file_uri_for(gem_repo1)}"
gem "very_simple_binary"
G
@@ -119,18 +253,22 @@ RSpec.shared_examples "bundle install --standalone" do
it "generates a bundle/bundler/setup.rb with the proper paths" do
expected_path = bundled_app("bundle/bundler/setup.rb")
- extension_line = File.read(expected_path).each_line.find {|line| line.include? "/extensions/" }.strip
- expect(extension_line).to start_with '$:.unshift File.expand_path("#{path}/../#{ruby_engine}/#{ruby_version}/extensions/'
- expect(extension_line).to end_with '/very_simple_binary-1.0")'
+ script_content = File.read(expected_path)
+ expect(script_content).to include("def self.ruby_api_version")
+ expect(script_content).to include("def self.extension_api_version")
+ extension_line = script_content.each_line.find {|line| line.include? "/extensions/" }.strip
+ platform = Gem::Platform.local
+ expect(extension_line).to start_with '$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/'
+ expect(extension_line).to end_with platform.to_s + '/#{Gem.extension_api_version}/very_simple_binary-1.0")'
end
end
describe "with gem that has an invalid gemspec" do
before do
- build_git "bar", :gemspec => false do |s|
+ build_git "bar", gemspec: false do |s|
s.write "lib/bar/version.rb", %(BAR_VERSION = '1.0')
s.write "bar.gemspec", <<-G
- lib = File.expand_path('../lib/', __FILE__)
+ lib = File.expand_path('lib/', __dir__)
$:.unshift lib unless $:.include?(lib)
require 'bar/version'
@@ -145,7 +283,7 @@ RSpec.shared_examples "bundle install --standalone" do
G
end
bundle "config set --local path #{bundled_app("bundle")}"
- install_gemfile <<-G, :standalone => true, :dir => cwd, :raise_on_error => false
+ install_gemfile <<-G, standalone: true, dir: cwd, raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
gem "bar", :git => "#{lib_path("bar-1.0")}"
G
@@ -167,7 +305,7 @@ RSpec.shared_examples "bundle install --standalone" do
gem "devise", :git => "#{lib_path("devise-1.0")}"
G
bundle "config set --local path #{bundled_app("bundle")}"
- bundle :install, :standalone => true, :dir => cwd
+ bundle :install, standalone: true, dir: cwd
end
let(:expected_gems) do
@@ -195,7 +333,7 @@ RSpec.shared_examples "bundle install --standalone" do
end
G
bundle "config set --local path #{bundled_app("bundle")}"
- bundle :install, :standalone => true, :dir => cwd
+ bundle :install, standalone: true, dir: cwd
end
let(:expected_gems) do
@@ -209,7 +347,7 @@ RSpec.shared_examples "bundle install --standalone" do
it "allows creating a standalone file with limited groups" do
bundle "config set --local path #{bundled_app("bundle")}"
- bundle :install, :standalone => "default", :dir => cwd
+ bundle :install, standalone: "default", dir: cwd
load_error_ruby <<-RUBY, "spec"
$:.unshift File.expand_path("bundle")
@@ -227,7 +365,7 @@ RSpec.shared_examples "bundle install --standalone" do
it "allows `without` configuration to limit the groups used in a standalone" do
bundle "config set --local path #{bundled_app("bundle")}"
bundle "config set --local without test"
- bundle :install, :standalone => true, :dir => cwd
+ bundle :install, standalone: true, dir: cwd
load_error_ruby <<-RUBY, "spec"
$:.unshift File.expand_path("bundle")
@@ -244,7 +382,7 @@ RSpec.shared_examples "bundle install --standalone" do
it "allows `path` configuration to change the location of the standalone bundle" do
bundle "config set --local path path/to/bundle"
- bundle "install", :standalone => true, :dir => cwd
+ bundle "install", standalone: true, dir: cwd
ruby <<-RUBY
$:.unshift File.expand_path("path/to/bundle")
@@ -259,9 +397,9 @@ RSpec.shared_examples "bundle install --standalone" do
it "allows `without` to limit the groups used in a standalone" do
bundle "config set --local without test"
- bundle :install, :dir => cwd
+ bundle :install, dir: cwd
bundle "config set --local path #{bundled_app("bundle")}"
- bundle :install, :standalone => true, :dir => cwd
+ bundle :install, standalone: true, dir: cwd
load_error_ruby <<-RUBY, "spec"
$:.unshift File.expand_path("bundle")
@@ -287,7 +425,7 @@ RSpec.shared_examples "bundle install --standalone" do
gem "rails"
G
bundle "config set --local path #{bundled_app("bundle")}"
- bundle :install, :standalone => true, :artifice => "endpoint", :dir => cwd
+ bundle :install, standalone: true, artifice: "endpoint", dir: cwd
end
let(:expected_gems) do
@@ -301,14 +439,14 @@ RSpec.shared_examples "bundle install --standalone" do
end
end
- describe "with --binstubs", :bundler => "< 3" do
+ describe "with --binstubs", bundler: "< 3" do
before do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
bundle "config set --local path #{bundled_app("bundle")}"
- bundle :install, :standalone => true, :binstubs => true, :dir => cwd
+ bundle :install, standalone: true, binstubs: true, dir: cwd
end
let(:expected_gems) do
@@ -326,7 +464,7 @@ RSpec.shared_examples "bundle install --standalone" do
it "creates stubs that can be executed from anywhere" do
require "tmpdir"
- sys_exec(%(#{bundled_app("bin/rails")} -v), :dir => Dir.tmpdir)
+ sys_exec(%(#{bundled_app("bin/rails")} -v), dir: Dir.tmpdir)
expect(out).to eq("2.3.2")
end
@@ -344,7 +482,7 @@ RSpec.shared_examples "bundle install --standalone" do
it "creates stubs with the correct load path" do
extension_line = File.read(bundled_app("bin/rails")).each_line.find {|line| line.include? "$:.unshift" }.strip
- expect(extension_line).to eq %($:.unshift File.expand_path "../../bundle", path.realpath)
+ expect(extension_line).to eq %($:.unshift File.expand_path "../bundle", __dir__)
end
end
end
@@ -360,3 +498,31 @@ RSpec.describe "bundle install --standalone run in a subdirectory" do
include_examples("bundle install --standalone")
end
+
+RSpec.describe "bundle install --standalone --local" do
+ before do
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ G
+
+ system_gems "rack-1.0.0", path: default_bundle_path
+ end
+
+ it "generates script pointing to system gems" do
+ bundle "install --standalone --local --verbose"
+
+ expect(out).to include("Using rack 1.0.0")
+
+ load_error_ruby <<-RUBY, "spec"
+ require "./bundler/setup"
+
+ require "rack"
+ puts RACK
+ require "spec"
+ RUBY
+
+ expect(out).to eq("1.0.0")
+ expect(err).to eq("ZOMG LOAD ERROR")
+ end
+end
diff --git a/spec/bundler/install/gems/sudo_spec.rb b/spec/bundler/install/gems/sudo_spec.rb
deleted file mode 100644
index 3e5d38ea4c..0000000000
--- a/spec/bundler/install/gems/sudo_spec.rb
+++ /dev/null
@@ -1,205 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe "when using sudo", :sudo => true do
- describe "and BUNDLE_PATH is writable" do
- context "but BUNDLE_PATH/build_info is not writable" do
- let(:subdir) do
- system_gem_path("cache")
- end
-
- before do
- bundle "config set path.system true"
- subdir.mkpath
- sudo "chmod u-w #{subdir}"
- end
-
- after do
- sudo "chmod u+w #{subdir}"
- end
-
- it "installs" do
- install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
- G
-
- expect(out).to_not match(/an error occurred/i)
- expect(system_gem_path("cache/rack-1.0.0.gem")).to exist
- expect(the_bundle).to include_gems "rack 1.0"
- end
- end
- end
-
- describe "and GEM_HOME is owned by root" do
- before :each do
- bundle "config set path.system true"
- chown_system_gems_to_root
- end
-
- it "installs" do
- install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack", '1.0'
- gem "thin"
- G
-
- expect(system_gem_path("gems/rack-1.0.0")).to exist
- expect(system_gem_path("gems/rack-1.0.0").stat.uid).to eq(0)
- expect(the_bundle).to include_gems "rack 1.0"
- end
-
- it "installs rake and a gem dependent on rake in the same session" do
- build_repo2 do
- build_gem "another_implicit_rake_dep" do |s|
- s.extensions << "Rakefile"
- s.write "Rakefile", <<-RUBY
- task :default do
- path = File.expand_path("../lib", __FILE__)
- FileUtils.mkdir_p(path)
- File.open("\#{path}/another_implicit_rake_dep.rb", "w") do |f|
- f.puts "ANOTHER_IMPLICIT_RAKE_DEP = 'YES'"
- end
- end
- RUBY
- end
- end
-
- gemfile <<-G
- source "#{file_uri_for(gem_repo2)}"
- gem "rake"
- gem "another_implicit_rake_dep"
- G
- bundle "install"
- expect(system_gem_path("gems/another_implicit_rake_dep-1.0")).to exist
- end
-
- it "installs when BUNDLE_PATH is owned by root" do
- bundle_path = tmp("owned_by_root")
- FileUtils.mkdir_p bundle_path
- sudo "chown -R root #{bundle_path}"
-
- ENV["BUNDLE_PATH"] = bundle_path.to_s
- install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack", '1.0'
- G
-
- expect(bundle_path.join(Bundler.ruby_scope, "gems/rack-1.0.0")).to exist
- expect(bundle_path.join(Bundler.ruby_scope, "gems/rack-1.0.0").stat.uid).to eq(0)
- expect(the_bundle).to include_gems "rack 1.0"
- end
-
- it "installs when BUNDLE_PATH does not exist" do
- root_path = tmp("owned_by_root")
- FileUtils.mkdir_p root_path
- sudo "chown -R root #{root_path}"
- bundle_path = root_path.join("does_not_exist")
-
- ENV["BUNDLE_PATH"] = bundle_path.to_s
- install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack", '1.0'
- G
-
- expect(bundle_path.join(Bundler.ruby_scope, "gems/rack-1.0.0")).to exist
- expect(bundle_path.join(Bundler.ruby_scope, "gems/rack-1.0.0").stat.uid).to eq(0)
- expect(the_bundle).to include_gems "rack 1.0"
- end
-
- it "installs extensions/" do
- install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "very_simple_binary"
- G
-
- expect(system_gem_path("gems/very_simple_binary-1.0")).to exist
- binary_glob = system_gem_path("extensions/*/*/very_simple_binary-1.0")
- expect(Dir.glob(binary_glob).first).to be
- end
- end
-
- describe "and BUNDLE_PATH is not writable" do
- before do
- bundle "config set --local path .bundle"
- sudo "chmod ugo-w .bundle"
- end
-
- after do
- sudo "chmod ugo+w .bundle"
- end
-
- it "installs" do
- install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack", '1.0'
- G
-
- expect(local_gem_path("gems/rack-1.0.0")).to exist
- expect(the_bundle).to include_gems "rack 1.0"
- end
-
- it "cleans up the tmpdirs generated" do
- require "tmpdir"
- Dir.glob("#{Dir.tmpdir}/bundler*").each do |tmpdir|
- FileUtils.remove_entry_secure(tmpdir)
- end
-
- install_gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack"
- G
- tmpdirs = Dir.glob("#{Dir.tmpdir}/bundler*")
-
- expect(tmpdirs).to be_empty
- end
- end
-
- describe "and GEM_HOME is not writable" do
- it "installs" do
- bundle "config set path.system true"
- gem_home = tmp("sudo_gem_home")
- sudo "mkdir -p #{gem_home}"
- sudo "chmod ugo-w #{gem_home}"
-
- system_gems :bundler, :path => gem_home
-
- gemfile <<-G
- source "#{file_uri_for(gem_repo1)}"
- gem "rack", '1.0'
- G
-
- bundle :install, :env => { "GEM_HOME" => gem_home.to_s, "GEM_PATH" => nil }
- expect(gem_home.join("bin/rackup")).to exist
- expect(the_bundle).to include_gems "rack 1.0", :env => { "GEM_HOME" => gem_home.to_s, "GEM_PATH" => nil }
-
- sudo "rm -rf #{tmp("sudo_gem_home")}"
- end
- end
-
- describe "and root runs install" do
- let(:warning) { "Don't run Bundler as root." }
-
- before do
- gemfile %(source "#{file_uri_for(gem_repo1)}")
- end
-
- it "warns against that" do
- bundle :install, :sudo => :preserve_env
- expect(err).to include(warning)
- end
-
- context "when ENV['BUNDLE_SILENCE_ROOT_WARNING'] is set" do
- it "skips the warning" do
- bundle :install, :sudo => :preserve_env, :env => { "BUNDLE_SILENCE_ROOT_WARNING" => "true" }
- expect(err).to_not include(warning)
- end
- end
-
- context "when silence_root_warning = false" do
- it "warns against that" do
- bundle :install, :sudo => :preserve_env, :env => { "BUNDLE_SILENCE_ROOT_WARNING" => "false" }
- expect(err).to include(warning)
- end
- end
- end
-end
diff --git a/spec/bundler/install/gemspecs_spec.rb b/spec/bundler/install/gemspecs_spec.rb
index 0c4518fe2b..51aa0ed14f 100644
--- a/spec/bundler/install/gemspecs_spec.rb
+++ b/spec/bundler/install/gemspecs_spec.rb
@@ -4,7 +4,7 @@ RSpec.describe "bundle install" do
describe "when a gem has a YAML gemspec" do
before :each do
build_repo2 do
- build_gem "yaml_spec", :gemspec => :yaml
+ build_gem "yaml_spec", gemspec: :yaml
end
end
@@ -18,7 +18,7 @@ RSpec.describe "bundle install" do
end
it "still installs correctly when using path" do
- build_lib "yaml_spec", :gemspec => :yaml
+ build_lib "yaml_spec", gemspec: :yaml
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -34,6 +34,8 @@ RSpec.describe "bundle install" do
gem 'rack'
G
+ system_gems "rack-1.0.0", path: default_bundle_path
+
FileUtils.mkdir_p "#{default_bundle_path}/specifications"
File.open("#{default_bundle_path}/specifications/rack-1.0.0.gemspec", "w+") do |f|
spec = Gem::Specification.new do |s|
@@ -43,8 +45,8 @@ RSpec.describe "bundle install" do
end
f.write spec.to_ruby
end
- bundle :install, :artifice => "endpoint_marshal_fail" # force gemspec load
- expect(the_bundle).to include_gems "activesupport 2.3.2"
+ bundle :install, artifice: "endpoint_marshal_fail" # force gemspec load
+ expect(the_bundle).to include_gems "rack 1.0.0", "activesupport 2.3.2"
end
it "does not hang when gemspec has incompatible encoding" do
@@ -57,7 +59,7 @@ RSpec.describe "bundle install" do
end
G
- install_gemfile <<-G, :env => { "LANG" => "C" }
+ install_gemfile <<-G, env: { "LANG" => "C" }
source "#{file_uri_for(gem_repo1)}"
gemspec
G
@@ -92,8 +94,9 @@ RSpec.describe "bundle install" do
end
context "when ruby version is specified in gemspec and gemfile" do
- it "installs when patch level is not specified and the version matches" do
- build_lib("foo", :path => bundled_app) do |s|
+ it "installs when patch level is not specified and the version matches",
+ if: RUBY_PATCHLEVEL >= 0 do
+ build_lib("foo", path: bundled_app) do |s|
s.required_ruby_version = "~> #{RUBY_VERSION}.0"
end
@@ -106,12 +109,12 @@ RSpec.describe "bundle install" do
end
it "installs when patch level is specified and the version still matches the current version",
- :if => RUBY_PATCHLEVEL >= 0 do
- build_lib("foo", :path => bundled_app) do |s|
+ if: RUBY_PATCHLEVEL >= 0 do
+ build_lib("foo", path: bundled_app) do |s|
s.required_ruby_version = "#{RUBY_VERSION}.#{RUBY_PATCHLEVEL}"
end
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
ruby '#{RUBY_VERSION}', :engine_version => '#{RUBY_VERSION}', :engine => 'ruby', :patchlevel => '#{RUBY_PATCHLEVEL}'
source "#{file_uri_for(gem_repo1)}"
gemspec
@@ -120,13 +123,13 @@ RSpec.describe "bundle install" do
end
it "fails and complains about patchlevel on patchlevel mismatch",
- :if => RUBY_PATCHLEVEL >= 0 do
+ if: RUBY_PATCHLEVEL >= 0 do
patchlevel = RUBY_PATCHLEVEL.to_i + 1
- build_lib("foo", :path => bundled_app) do |s|
+ build_lib("foo", path: bundled_app) do |s|
s.required_ruby_version = "#{RUBY_VERSION}.#{patchlevel}"
end
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
ruby '#{RUBY_VERSION}', :engine_version => '#{RUBY_VERSION}', :engine => 'ruby', :patchlevel => '#{patchlevel}'
source "#{file_uri_for(gem_repo1)}"
gemspec
@@ -140,11 +143,11 @@ RSpec.describe "bundle install" do
it "fails and complains about version on version mismatch" do
version = Gem::Requirement.create(RUBY_VERSION).requirements.first.last.bump.version
- build_lib("foo", :path => bundled_app) do |s|
+ build_lib("foo", path: bundled_app) do |s|
s.required_ruby_version = version
end
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
ruby '#{version}', :engine_version => '#{version}', :engine => 'ruby'
source "#{file_uri_for(gem_repo1)}"
gemspec
diff --git a/spec/bundler/install/git_spec.rb b/spec/bundler/install/git_spec.rb
index d43aacee7e..c8d574baf3 100644
--- a/spec/bundler/install/git_spec.rb
+++ b/spec/bundler/install/git_spec.rb
@@ -3,51 +3,51 @@
RSpec.describe "bundle install" do
context "git sources" do
it "displays the revision hash of the gem repository" do
- build_git "foo", "1.0", :path => lib_path("foo")
+ build_git "foo", "1.0", path: lib_path("foo")
- install_gemfile <<-G, :verbose => true
+ install_gemfile <<-G, verbose: true
source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{file_uri_for(lib_path("foo"))}"
G
- expect(out).to include("Using foo 1.0 from #{file_uri_for(lib_path("foo"))} (at master@#{revision_for(lib_path("foo"))[0..6]})")
- expect(the_bundle).to include_gems "foo 1.0", :source => "git@#{lib_path("foo")}"
+ expect(out).to include("Using foo 1.0 from #{file_uri_for(lib_path("foo"))} (at main@#{revision_for(lib_path("foo"))[0..6]})")
+ expect(the_bundle).to include_gems "foo 1.0", source: "git@#{lib_path("foo")}"
end
- it "displays the correct default branch", :git => ">= 2.28.0" do
- build_git "foo", "1.0", :path => lib_path("foo"), :default_branch => "main"
+ it "displays the correct default branch", git: ">= 2.28.0" do
+ build_git "foo", "1.0", path: lib_path("foo"), default_branch: "main"
- install_gemfile <<-G, :verbose => true
+ install_gemfile <<-G, verbose: true
source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{file_uri_for(lib_path("foo"))}"
G
expect(out).to include("Using foo 1.0 from #{file_uri_for(lib_path("foo"))} (at main@#{revision_for(lib_path("foo"))[0..6]})")
- expect(the_bundle).to include_gems "foo 1.0", :source => "git@#{lib_path("foo")}"
+ expect(the_bundle).to include_gems "foo 1.0", source: "git@#{lib_path("foo")}"
end
it "displays the ref of the gem repository when using branch~num as a ref" do
skip "maybe branch~num notation doesn't work on Windows' git" if Gem.win_platform?
- build_git "foo", "1.0", :path => lib_path("foo")
+ build_git "foo", "1.0", path: lib_path("foo")
rev = revision_for(lib_path("foo"))[0..6]
- update_git "foo", "2.0", :path => lib_path("foo"), :gemspec => true
+ update_git "foo", "2.0", path: lib_path("foo"), gemspec: true
rev2 = revision_for(lib_path("foo"))[0..6]
- update_git "foo", "3.0", :path => lib_path("foo"), :gemspec => true
+ update_git "foo", "3.0", path: lib_path("foo"), gemspec: true
- install_gemfile <<-G, :verbose => true
+ install_gemfile <<-G, verbose: true
source "#{file_uri_for(gem_repo1)}"
- gem "foo", :git => "#{file_uri_for(lib_path("foo"))}", :ref => "master~2"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo"))}", :ref => "main~2"
G
- expect(out).to include("Using foo 1.0 from #{file_uri_for(lib_path("foo"))} (at master~2@#{rev})")
- expect(the_bundle).to include_gems "foo 1.0", :source => "git@#{lib_path("foo")}"
+ expect(out).to include("Using foo 1.0 from #{file_uri_for(lib_path("foo"))} (at main~2@#{rev})")
+ expect(the_bundle).to include_gems "foo 1.0", source: "git@#{lib_path("foo")}"
- update_git "foo", "4.0", :path => lib_path("foo"), :gemspec => true
+ update_git "foo", "4.0", path: lib_path("foo"), gemspec: true
- bundle :update, :all => true, :verbose => true
- expect(out).to include("Using foo 2.0 (was 1.0) from #{file_uri_for(lib_path("foo"))} (at master~2@#{rev2})")
- expect(the_bundle).to include_gems "foo 2.0", :source => "git@#{lib_path("foo")}"
+ bundle :update, all: true, verbose: true
+ expect(out).to include("Using foo 2.0 (was 1.0) from #{file_uri_for(lib_path("foo"))} (at main~2@#{rev2})")
+ expect(the_bundle).to include_gems "foo 2.0", source: "git@#{lib_path("foo")}"
end
it "should allows git repos that are missing but not being installed" do
@@ -81,9 +81,9 @@ RSpec.describe "bundle install" do
it "allows multiple gems from the same git source" do
build_repo2 do
- build_lib "foo", "1.0", :path => lib_path("gems/foo")
- build_lib "zebra", "2.0", :path => lib_path("gems/zebra")
- build_git "gems", :path => lib_path("gems"), :gemspec => false
+ build_lib "foo", "1.0", path: lib_path("gems/foo")
+ build_lib "zebra", "2.0", path: lib_path("gems/zebra")
+ build_git "gems", path: lib_path("gems"), gemspec: false
end
install_gemfile <<-G
@@ -98,5 +98,108 @@ RSpec.describe "bundle install" do
bundle "info zebra"
expect(out).to include("* zebra (2.0 #{revision_for(lib_path("gems"))[0..6]})")
end
+
+ it "should always sort dependencies in the same order" do
+ # This Gemfile + lockfile had a problem where the first
+ # `bundle install` would change the order, but the second would
+ # change it back.
+
+ # NOTE: both gems MUST have the same path! It has to be two gems in one repo.
+
+ test = build_git "test", "1.0.0", path: lib_path("test-and-other")
+ other = build_git "other", "1.0.0", path: lib_path("test-and-other")
+ test_ref = test.ref_for("HEAD")
+ other_ref = other.ref_for("HEAD")
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+
+ gem "test", git: #{test.path.to_s.inspect}
+ gem "other", ref: #{other_ref.inspect}, git: #{other.path.to_s.inspect}
+ G
+
+ lockfile <<-L
+ GIT
+ remote: #{test.path}
+ revision: #{test_ref}
+ specs:
+ test (1.0.0)
+
+ GIT
+ remote: #{other.path}
+ revision: #{other_ref}
+ ref: #{other_ref}
+ specs:
+ other (1.0.0)
+
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ other!
+ test!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ # If GH#6743 is present, the first `bundle install` will change the
+ # lockfile, by flipping the order (`other` would be moved to the top).
+ #
+ # The second `bundle install` would then change the lockfile back
+ # to the original.
+ #
+ # The fix makes it so it may change it once, but it will not change
+ # it a second time.
+ #
+ # So, we run `bundle install` once, and store the value of the
+ # modified lockfile.
+ bundle :install
+ modified_lockfile = lockfile
+
+ # If GH#6743 is present, the second `bundle install` would change the
+ # lockfile back to what it was originally.
+ #
+ # This `expect` makes sure it doesn't change a second time.
+ bundle :install
+ expect(lockfile).to eq(modified_lockfile)
+
+ expect(out).to include("Bundle complete!")
+ end
+
+ it "allows older revisions of git source when clean true" do
+ build_git "foo", "1.0", path: lib_path("foo")
+ rev = revision_for(lib_path("foo"))
+
+ bundle "config set path vendor/bundle"
+ bundle "config set clean true"
+ install_gemfile <<-G, verbose: true
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo"))}"
+ G
+
+ expect(out).to include("Using foo 1.0 from #{file_uri_for(lib_path("foo"))} (at main@#{rev[0..6]})")
+ expect(the_bundle).to include_gems "foo 1.0", source: "git@#{lib_path("foo")}"
+
+ old_lockfile = lockfile
+
+ update_git "foo", "2.0", path: lib_path("foo"), gemspec: true
+ rev2 = revision_for(lib_path("foo"))
+
+ bundle :update, all: true, verbose: true
+ expect(out).to include("Using foo 2.0 (was 1.0) from #{file_uri_for(lib_path("foo"))} (at main@#{rev2[0..6]})")
+ expect(out).to include("Removing foo (#{rev[0..11]})")
+ expect(the_bundle).to include_gems "foo 2.0", source: "git@#{lib_path("foo")}"
+
+ lockfile(old_lockfile)
+
+ bundle :install, verbose: true
+ expect(out).to include("Using foo 1.0 from #{file_uri_for(lib_path("foo"))} (at main@#{rev[0..6]})")
+ expect(the_bundle).to include_gems "foo 1.0", source: "git@#{lib_path("foo")}"
+ end
end
end
diff --git a/spec/bundler/install/global_cache_spec.rb b/spec/bundler/install/global_cache_spec.rb
index 9bc243e7cf..0da4de05b2 100644
--- a/spec/bundler/install/global_cache_spec.rb
+++ b/spec/bundler/install/global_cache_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe "global gem caching" do
end
it "caches gems into the global cache on download" do
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "#{source}"
gem "rack"
G
@@ -29,7 +29,7 @@ RSpec.describe "global gem caching" do
source_global_cache.mkpath
FileUtils.cp(gem_repo1("gems/rack-1.0.0.gem"), source_global_cache("rack-1.0.0.gem"))
- install_gemfile <<-G, :artifice => "compact_index_no_gem"
+ install_gemfile <<-G, artifice: "compact_index_no_gem"
source "#{source}"
gem "rack"
G
@@ -37,9 +37,21 @@ RSpec.describe "global gem caching" do
expect(the_bundle).to include_gems "rack 1.0.0"
end
+ it "shows a proper error message if a cached gem is corrupted" do
+ source_global_cache.mkpath
+ FileUtils.touch(source_global_cache("rack-1.0.0.gem"))
+
+ install_gemfile <<-G, artifice: "compact_index_no_gem", raise_on_error: false
+ source "#{source}"
+ gem "rack"
+ G
+
+ expect(err).to include("Gem::Package::FormatError: package metadata is missing in #{source_global_cache("rack-1.0.0.gem")}")
+ end
+
describe "when the same gem from different sources is installed" do
it "should use the appropriate one from the global cache" do
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "#{source}"
gem "rack"
G
@@ -49,7 +61,7 @@ RSpec.describe "global gem caching" do
expect(source_global_cache("rack-1.0.0.gem")).to exist
# rack 1.0.0 is not installed and it is in the global cache
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "#{source2}"
gem "rack", "0.9.1"
G
@@ -64,7 +76,7 @@ RSpec.describe "global gem caching" do
gem "rack", "1.0.0"
G
- bundle :install, :artifice => "compact_index_no_gem"
+ bundle :install, artifice: "compact_index_no_gem"
# rack 1.0.0 is installed and rack 0.9.1 is not
expect(the_bundle).to include_gems "rack 1.0.0"
expect(the_bundle).not_to include_gems "rack 0.9.1"
@@ -75,7 +87,7 @@ RSpec.describe "global gem caching" do
gem "rack", "0.9.1"
G
- bundle :install, :artifice => "compact_index_no_gem"
+ bundle :install, artifice: "compact_index_no_gem"
# rack 0.9.1 is installed and rack 1.0.0 is not
expect(the_bundle).to include_gems "rack 0.9.1"
expect(the_bundle).not_to include_gems "rack 1.0.0"
@@ -87,7 +99,7 @@ RSpec.describe "global gem caching" do
gem "rack"
G
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
simulate_new_machine
expect(the_bundle).not_to include_gems "rack 1.0.0"
expect(source_global_cache("rack-1.0.0.gem")).to exist
@@ -98,7 +110,7 @@ RSpec.describe "global gem caching" do
gem "rack", "0.9.1"
G
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
simulate_new_machine
expect(the_bundle).not_to include_gems "rack 0.9.1"
expect(source2_global_cache("rack-0.9.1.gem")).to exist
@@ -111,9 +123,9 @@ RSpec.describe "global gem caching" do
expect(source_global_cache("rack-1.0.0.gem")).to exist
expect(source2_global_cache("rack-0.9.1.gem")).to exist
- bundle :install, :artifice => "compact_index_no_gem", :raise_on_error => false
+ bundle :install, artifice: "compact_index_no_gem", raise_on_error: false
expect(err).to include("Internal Server Error 500")
- expect(err).not_to include("please copy and paste the report template above into a new issue")
+ expect(err).not_to include("ERROR REPORT TEMPLATE")
# rack 1.0.0 is not installed and rack 0.9.1 is not
expect(the_bundle).not_to include_gems "rack 1.0.0"
@@ -126,9 +138,9 @@ RSpec.describe "global gem caching" do
expect(source_global_cache("rack-1.0.0.gem")).to exist
expect(source2_global_cache("rack-0.9.1.gem")).to exist
- bundle :install, :artifice => "compact_index_no_gem", :raise_on_error => false
+ bundle :install, artifice: "compact_index_no_gem", raise_on_error: false
expect(err).to include("Internal Server Error 500")
- expect(err).not_to include("please copy and paste the report template above into a new issue")
+ expect(err).not_to include("ERROR REPORT TEMPLATE")
# rack 0.9.1 is not installed and rack 1.0.0 is not
expect(the_bundle).not_to include_gems "rack 0.9.1"
@@ -138,7 +150,7 @@ RSpec.describe "global gem caching" do
describe "when installing gems from a different directory" do
it "uses the global cache as a source" do
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "#{source}"
gem "rack"
gem "activesupport"
@@ -154,7 +166,7 @@ RSpec.describe "global gem caching" do
expect(the_bundle).not_to include_gems "rack 1.0.0"
expect(the_bundle).not_to include_gems "activesupport 2.3.5"
- install_gemfile <<-G, :artifice => "compact_index_no_gem"
+ install_gemfile <<-G, artifice: "compact_index_no_gem"
source "#{source}"
gem "rack"
G
@@ -171,20 +183,18 @@ RSpec.describe "global gem caching" do
G
# Neither gem is installed and both are in the global cache
- expect(the_bundle).not_to include_gems "rack 1.0.0", :dir => bundled_app2
- expect(the_bundle).not_to include_gems "activesupport 2.3.5", :dir => bundled_app2
+ expect(the_bundle).not_to include_gems "rack 1.0.0", dir: bundled_app2
+ expect(the_bundle).not_to include_gems "activesupport 2.3.5", dir: bundled_app2
expect(source_global_cache("rack-1.0.0.gem")).to exist
expect(source_global_cache("activesupport-2.3.5.gem")).to exist
# Install using the global cache instead of by downloading the .gem
# from the server
- bundle :install, :artifice => "compact_index_no_gem", :dir => bundled_app2
+ bundle :install, artifice: "compact_index_no_gem", dir: bundled_app2
# activesupport is installed and both are in the global cache
- simulate_bundler_version_when_missing_prerelease_default_gem_activation do
- expect(the_bundle).not_to include_gems "rack 1.0.0", :dir => bundled_app2
- expect(the_bundle).to include_gems "activesupport 2.3.5", :dir => bundled_app2
- end
+ expect(the_bundle).not_to include_gems "rack 1.0.0", dir: bundled_app2
+ expect(the_bundle).to include_gems "activesupport 2.3.5", dir: bundled_app2
expect(source_global_cache("rack-1.0.0.gem")).to exist
expect(source_global_cache("activesupport-2.3.5.gem")).to exist
@@ -193,7 +203,7 @@ RSpec.describe "global gem caching" do
end
describe "extension caching" do
- it "works", :ruby_repo do
+ it "works" do
skip "gets incorrect ref in path" if Gem.win_platform?
build_git "very_simple_git_binary", &:add_c_extension
@@ -208,9 +218,9 @@ RSpec.describe "global gem caching" do
gem "very_simple_path_binary", :path => "#{lib_path("very_simple_path_binary-1.0")}"
G
- gem_binary_cache = home(".bundle", "cache", "extensions", specific_local_platform.to_s, Bundler.ruby_scope,
+ gem_binary_cache = home(".bundle", "cache", "extensions", local_platform.to_s, Bundler.ruby_scope,
Digest(:MD5).hexdigest("#{gem_repo1}/"), "very_simple_binary-1.0")
- git_binary_cache = home(".bundle", "cache", "extensions", specific_local_platform.to_s, Bundler.ruby_scope,
+ git_binary_cache = home(".bundle", "cache", "extensions", local_platform.to_s, Bundler.ruby_scope,
"very_simple_git_binary-1.0-#{revision}", "very_simple_git_binary-1.0")
cached_extensions = Pathname.glob(home(".bundle", "cache", "extensions", "*", "*", "*", "*", "*")).sort
@@ -222,7 +232,7 @@ RSpec.describe "global gem caching" do
R
expect(out).to eq "VERY_SIMPLE_BINARY_IN_C\nVERY_SIMPLE_GIT_BINARY_IN_C"
- FileUtils.rm Dir[home(".bundle", "cache", "extensions", "**", "*binary_c*")]
+ FileUtils.rm_rf Dir[home(".bundle", "cache", "extensions", "**", "*binary_c*")]
gem_binary_cache.join("very_simple_binary_c.rb").open("w") {|f| f << "puts File.basename(__FILE__)" }
git_binary_cache.join("very_simple_git_binary_c.rb").open("w") {|f| f << "puts File.basename(__FILE__)" }
diff --git a/spec/bundler/install/path_spec.rb b/spec/bundler/install/path_spec.rb
index b0392c4ed2..0a30e402b7 100644
--- a/spec/bundler/install/path_spec.rb
+++ b/spec/bundler/install/path_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe "bundle install" do
describe "with path configured" do
before :each do
- build_gem "rack", "1.0.0", :to_system => true do |s|
+ build_gem "rack", "1.0.0", to_system: true do |s|
s.write "lib/rack.rb", "puts 'FAIL'"
end
@@ -23,7 +23,7 @@ RSpec.describe "bundle install" do
bundle "config set --local path.system true"
bundle "config set --global path vendor/bundle"
bundle :install
- run "require 'rack'", :raise_on_error => false
+ run "require 'rack'", raise_on_error: false
expect(out).to include("FAIL")
end
@@ -32,7 +32,7 @@ RSpec.describe "bundle install" do
dir.mkpath
bundle "config set --local path #{dir.join("vendor/bundle")}"
- bundle :install, :dir => dir
+ bundle :install, dir: dir
expect(out).to include("installed into `./vendor/bundle`")
dir.rmtree
@@ -44,13 +44,13 @@ RSpec.describe "bundle install" do
expect(out).to include("gems are installed into `./vendor/bundle`")
end
- it "disallows --path vendor/bundle --system", :bundler => "< 3" do
- bundle "install --path vendor/bundle --system", :raise_on_error => false
+ it "disallows --path vendor/bundle --system", bundler: "< 3" do
+ bundle "install --path vendor/bundle --system", raise_on_error: false
expect(err).to include("Please choose only one option.")
expect(exitstatus).to eq(15)
end
- it "remembers to disable system gems after the first time with bundle --path vendor/bundle", :bundler => "< 3" do
+ it "remembers to disable system gems after the first time with bundle --path vendor/bundle", bundler: "< 3" do
bundle "install --path vendor/bundle"
FileUtils.rm_rf bundled_app("vendor")
bundle "install"
@@ -62,22 +62,22 @@ RSpec.describe "bundle install" do
context "with path_relative_to_cwd set to true" do
before { bundle "config set path_relative_to_cwd true" }
- it "installs the bundle relatively to current working directory", :bundler => "< 3" do
- bundle "install --gemfile='#{bundled_app}/Gemfile' --path vendor/bundle", :dir => bundled_app.parent
+ it "installs the bundle relatively to current working directory", bundler: "< 3" do
+ bundle "install --gemfile='#{bundled_app}/Gemfile' --path vendor/bundle", dir: bundled_app.parent
expect(out).to include("installed into `./vendor/bundle`")
expect(bundled_app("../vendor/bundle")).to be_directory
expect(the_bundle).to include_gems "rack 1.0.0"
end
it "installs the standalone bundle relative to the cwd" do
- bundle :install, :gemfile => bundled_app_gemfile, :standalone => true, :dir => bundled_app.parent
+ bundle :install, gemfile: bundled_app_gemfile, standalone: true, dir: bundled_app.parent
expect(out).to include("installed into `./bundled_app/bundle`")
expect(bundled_app("bundle")).to be_directory
expect(bundled_app("bundle/ruby")).to be_directory
bundle "config unset path"
- bundle :install, :gemfile => bundled_app_gemfile, :standalone => true, :dir => bundled_app("subdir").tap(&:mkpath)
+ bundle :install, gemfile: bundled_app_gemfile, standalone: true, dir: bundled_app("subdir").tap(&:mkpath)
expect(out).to include("installed into `../bundle`")
expect(bundled_app("bundle")).to be_directory
expect(bundled_app("bundle/ruby")).to be_directory
@@ -87,7 +87,7 @@ RSpec.describe "bundle install" do
describe "when BUNDLE_PATH or the global path config is set" do
before :each do
- build_lib "rack", "1.0.0", :to_system => true do |s|
+ build_lib "rack", "1.0.0", to_system: true do |s|
s.write "lib/rack.rb", "raise 'FAIL'"
end
@@ -141,7 +141,7 @@ RSpec.describe "bundle install" do
set_bundle_path(type, "vendor")
FileUtils.mkdir_p bundled_app("lol")
- bundle :install, :dir => bundled_app("lol")
+ bundle :install, dir: bundled_app("lol")
expect(bundled_app("vendor", Bundler.ruby_scope, "gems/rack-1.0.0")).to be_directory
expect(the_bundle).to include_gems "rack 1.0.0"
@@ -168,7 +168,7 @@ RSpec.describe "bundle install" do
it "disables system gems when passing a path to install" do
# This is so that vendored gems can be distributed to others
- build_gem "rack", "1.1.0", :to_system => true
+ build_gem "rack", "1.1.0", to_system: true
bundle "config set --local path ./vendor/bundle"
bundle :install
@@ -176,8 +176,8 @@ RSpec.describe "bundle install" do
expect(the_bundle).to include_gems "rack 1.0.0"
end
- it "re-installs gems whose extensions have been deleted", :ruby_repo do
- build_lib "very_simple_binary", "1.0.0", :to_system => true do |s|
+ it "re-installs gems whose extensions have been deleted" do
+ build_lib "very_simple_binary", "1.0.0", to_system: true do |s|
s.write "lib/very_simple_binary.rb", "raise 'FAIL'"
end
@@ -191,11 +191,11 @@ RSpec.describe "bundle install" do
expect(vendored_gems("gems/very_simple_binary-1.0")).to be_directory
expect(vendored_gems("extensions")).to be_directory
- expect(the_bundle).to include_gems "very_simple_binary 1.0", :source => "remote1"
+ expect(the_bundle).to include_gems "very_simple_binary 1.0", source: "remote1"
vendored_gems("extensions").rmtree
- run "require 'very_simple_binary_c'", :raise_on_error => false
+ run "require 'very_simple_binary_c'", raise_on_error: false
expect(err).to include("Bundler::GemNotFound")
bundle "config set --local path ./vendor/bundle"
@@ -203,7 +203,7 @@ RSpec.describe "bundle install" do
expect(vendored_gems("gems/very_simple_binary-1.0")).to be_directory
expect(vendored_gems("extensions")).to be_directory
- expect(the_bundle).to include_gems "very_simple_binary 1.0", :source => "remote1"
+ expect(the_bundle).to include_gems "very_simple_binary 1.0", source: "remote1"
end
end
@@ -219,7 +219,7 @@ RSpec.describe "bundle install" do
G
bundle "config set --local path bundle"
- bundle :install, :raise_on_error => false
+ bundle :install, raise_on_error: false
expect(err).to include("file already exists")
end
end
diff --git a/spec/bundler/install/process_lock_spec.rb b/spec/bundler/install/process_lock_spec.rb
index dac0d34bc4..1f8c62f26e 100644
--- a/spec/bundler/install/process_lock_spec.rb
+++ b/spec/bundler/install/process_lock_spec.rb
@@ -31,5 +31,27 @@ RSpec.describe "process lock spec" do
expect(processed).to eq true
end
end
+
+ context "when creating a lock raises Errno::EPERM" do
+ before { allow(File).to receive(:open).and_raise(Errno::EPERM) }
+
+ it "skips creating the lock file and yields" do
+ processed = false
+ Bundler::ProcessLock.lock(default_bundle_path) { processed = true }
+
+ expect(processed).to eq true
+ end
+ end
+
+ context "when creating a lock raises Errno::EROFS" do
+ before { allow(File).to receive(:open).and_raise(Errno::EROFS) }
+
+ it "skips creating the lock file and yields" do
+ processed = false
+ Bundler::ProcessLock.lock(default_bundle_path) { processed = true }
+
+ expect(processed).to eq true
+ end
+ end
end
end
diff --git a/spec/bundler/install/redownload_spec.rb b/spec/bundler/install/redownload_spec.rb
index a936b2b536..3a72c356d9 100644
--- a/spec/bundler/install/redownload_spec.rb
+++ b/spec/bundler/install/redownload_spec.rb
@@ -57,7 +57,7 @@ RSpec.describe "bundle install" do
end
end
- describe "with --force", :bundler => 2 do
+ describe "with --force", bundler: 2 do
it_behaves_like "an option to force redownloading gems" do
let(:flag) { "force" }
end
diff --git a/spec/bundler/install/security_policy_spec.rb b/spec/bundler/install/security_policy_spec.rb
index 43c3069c4e..befeb81da5 100644
--- a/spec/bundler/install/security_policy_spec.rb
+++ b/spec/bundler/install/security_policy_spec.rb
@@ -16,23 +16,23 @@ RSpec.describe "policies with unsigned gems" do
end
it "will work after you try to deploy without a lock" do
- bundle "install --deployment", :raise_on_error => false
+ bundle "install --deployment", raise_on_error: false
bundle :install
expect(the_bundle).to include_gems "rack 1.0", "signed_gem 1.0"
end
it "will fail when given invalid security policy" do
- bundle "install --trust-policy=InvalidPolicyName", :raise_on_error => false
+ bundle "install --trust-policy=InvalidPolicyName", raise_on_error: false
expect(err).to include("RubyGems doesn't know about trust policy")
end
it "will fail with High Security setting due to presence of unsigned gem" do
- bundle "install --trust-policy=HighSecurity", :raise_on_error => false
+ bundle "install --trust-policy=HighSecurity", raise_on_error: false
expect(err).to include("security policy didn't allow")
end
it "will fail with Medium Security setting due to presence of unsigned gem" do
- bundle "install --trust-policy=MediumSecurity", :raise_on_error => false
+ bundle "install --trust-policy=MediumSecurity", raise_on_error: false
expect(err).to include("security policy didn't allow")
end
@@ -51,12 +51,12 @@ RSpec.describe "policies with signed gems and no CA" do
end
it "will fail with High Security setting, gem is self-signed" do
- bundle "install --trust-policy=HighSecurity", :raise_on_error => false
+ bundle "install --trust-policy=HighSecurity", raise_on_error: false
expect(err).to include("security policy didn't allow")
end
it "will fail with Medium Security setting, gem is self-signed" do
- bundle "install --trust-policy=MediumSecurity", :raise_on_error => false
+ bundle "install --trust-policy=MediumSecurity", raise_on_error: false
expect(err).to include("security policy didn't allow")
end
diff --git a/spec/bundler/install/yanked_spec.rb b/spec/bundler/install/yanked_spec.rb
index 6d3065a836..7408c24327 100644
--- a/spec/bundler/install/yanked_spec.rb
+++ b/spec/bundler/install/yanked_spec.rb
@@ -15,14 +15,14 @@ RSpec.context "when installing a bundle that includes yanked gems" do
foo (10.0.0)
PLATFORMS
- ruby
+ #{lockfile_platforms}
DEPENDENCIES
foo (= 10.0.0)
L
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo4)}"
gem "foo", "10.0.0"
G
@@ -30,10 +30,76 @@ RSpec.context "when installing a bundle that includes yanked gems" do
expect(err).to include("Your bundle is locked to foo (10.0.0)")
end
+ context "when a re-resolve is necessary, and a yanked version is considered by the resolver" do
+ before do
+ skip "Materialization on Windows is not yet strict, so the example does not detect the gem has been yanked" if Gem.win_platform?
+
+ build_repo4 do
+ build_gem "foo", "1.0.0", "1.0.1"
+ build_gem "actiontext", "6.1.7" do |s|
+ s.add_dependency "nokogiri", ">= 1.8"
+ end
+ build_gem "actiontext", "6.1.6" do |s|
+ s.add_dependency "nokogiri", ">= 1.8"
+ end
+ build_gem "actiontext", "6.1.7" do |s|
+ s.add_dependency "nokogiri", ">= 1.8"
+ end
+ build_gem "nokogiri", "1.13.8"
+ end
+
+ gemfile <<~G
+ source "#{source_uri}"
+ gem "foo", "1.0.1"
+ gem "actiontext", "6.1.6"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: #{source_uri}/
+ specs:
+ actiontext (6.1.6)
+ nokogiri (>= 1.8)
+ foo (1.0.0)
+ nokogiri (1.13.8-#{Bundler.local_platform})
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ actiontext (= 6.1.6)
+ foo (= 1.0.0)
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
+ context "and the old index is used" do
+ let(:source_uri) { file_uri_for(gem_repo4) }
+
+ it "reports the yanked gem properly" do
+ bundle "install", raise_on_error: false
+
+ expect(err).to include("Your bundle is locked to nokogiri (1.13.8-#{Bundler.local_platform})")
+ end
+ end
+
+ context "and the compact index API is used" do
+ let(:source_uri) { "https://gem.repo4" }
+
+ it "reports the yanked gem properly" do
+ bundle "install", artifice: "compact_index", raise_on_error: false
+
+ expect(err).to include("Your bundle is locked to nokogiri (1.13.8-#{Bundler.local_platform})")
+ end
+ end
+ end
+
it "throws the original error when only the Gemfile specifies a gem version that doesn't exist" do
bundle "config set force_ruby_platform true"
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo4)}"
gem "foo", "10.0.0"
G
@@ -43,6 +109,63 @@ RSpec.context "when installing a bundle that includes yanked gems" do
end
end
+RSpec.context "when resolving a bundle that includes yanked gems, but unlocking an unrelated gem" do
+ before(:each) do
+ build_repo4 do
+ build_gem "foo", "10.0.0"
+
+ build_gem "bar", "1.0.0"
+ build_gem "bar", "2.0.0"
+ end
+
+ lockfile <<-L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}
+ specs:
+ foo (9.0.0)
+ bar (1.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ foo
+ bar
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "foo"
+ gem "bar"
+ G
+ end
+
+ it "does not update the yanked gem" do
+ bundle "lock --update bar"
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ bar (2.0.0)
+ foo (9.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ bar
+ foo
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+end
+
RSpec.context "when using gem before installing" do
it "does not suggest the author has yanked the gem" do
gemfile <<-G
@@ -57,16 +180,53 @@ RSpec.context "when using gem before installing" do
rack (0.9.1)
PLATFORMS
- ruby
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ rack (= 0.9.1)
+ L
+
+ bundle :list, raise_on_error: false
+
+ expect(err).to include("Could not find rack-0.9.1 in cached gems or installed locally")
+ expect(err).to_not include("Your bundle is locked to rack (0.9.1) from")
+ expect(err).to_not include("If you haven't changed sources, that means the author of rack (0.9.1) has removed it.")
+ expect(err).to_not include("You'll need to update your bundle to a different version of rack (0.9.1) that hasn't been removed in order to install.")
+
+ # Check error message is still correct when multiple platforms are locked
+ lockfile lockfile.gsub(/PLATFORMS\n #{lockfile_platforms}/m, "PLATFORMS\n #{lockfile_platforms("ruby")}")
+
+ bundle :list, raise_on_error: false
+ expect(err).to include("Could not find rack-0.9.1 in cached gems or installed locally")
+ end
+
+ it "does not suggest the author has yanked the gem when using more than one gem, but shows all gems that couldn't be found in the source" do
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
+ gem "rack_middleware", "1.0"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: #{file_uri_for(gem_repo1)}
+ specs:
+ rack (0.9.1)
+ rack_middleware (1.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
DEPENDENCIES
rack (= 0.9.1)
+ rack_middleware (1.0)
L
- bundle :list, :raise_on_error => false
+ bundle :list, raise_on_error: false
- expect(err).to include("Could not find rack-0.9.1 in any of the sources")
- expect(err).to_not include("Your bundle is locked to rack (0.9.1), but that version could not be found in any of the sources listed in your Gemfile.")
+ expect(err).to include("Could not find rack-0.9.1, rack_middleware-1.0 in cached gems or installed locally")
+ expect(err).to include("Install missing gems with `bundle install`.")
+ expect(err).to_not include("Your bundle is locked to rack (0.9.1) from")
expect(err).to_not include("If you haven't changed sources, that means the author of rack (0.9.1) has removed it.")
expect(err).to_not include("You'll need to update your bundle to a different version of rack (0.9.1) that hasn't been removed in order to install.")
end
diff --git a/spec/bundler/lock/git_spec.rb b/spec/bundler/lock/git_spec.rb
index 56db5d8305..ad13e8ffc6 100644
--- a/spec/bundler/lock/git_spec.rb
+++ b/spec/bundler/lock/git_spec.rb
@@ -14,6 +14,52 @@ RSpec.describe "bundle lock with git gems" do
expect(the_bundle).to include_gems "foo 1.0.0"
end
+ it "doesn't print errors even if running lock after removing the cache" do
+ FileUtils.rm_rf(Dir[default_cache_path("git/foo-1.0-*")].first)
+
+ bundle "lock --verbose"
+
+ expect(err).to be_empty
+ end
+
+ it "prints a proper error when changing a locked Gemfile to point to a bad branch" do
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'foo', :git => "#{lib_path("foo-1.0")}", :branch => "bad"
+ G
+
+ bundle "lock --update foo", env: { "LANG" => "en" }, raise_on_error: false
+
+ expect(err).to include("Revision bad does not exist in the repository")
+ end
+
+ it "prints a proper error when installing a Gemfile with a locked ref that does not exist" do
+ lockfile <<~L
+ GIT
+ remote: #{lib_path("foo-1.0")}
+ revision: #{"a" * 40}
+ specs:
+ foo (1.0)
+
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ foo!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install", raise_on_error: false
+
+ expect(err).to include("Revision #{"a" * 40} does not exist in the repository")
+ end
+
it "locks a git source to the current ref" do
update_git "foo"
bundle :install
@@ -26,6 +72,87 @@ RSpec.describe "bundle lock with git gems" do
expect(out).to eq("WIN")
end
+ it "properly clones a git source locked to an out of date ref" do
+ update_git "foo"
+
+ bundle :install, env: { "BUNDLE_PATH" => "foo" }
+ expect(err).to be_empty
+ end
+
+ it "properly fetches a git source locked to an unreachable ref" do
+ # Create a commit and make it unreachable
+ git "checkout -b foo ", lib_path("foo-1.0")
+ unreachable_sha = update_git("foo").ref_for("HEAD")
+ git "checkout main ", lib_path("foo-1.0")
+ git "branch -D foo ", lib_path("foo-1.0")
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'foo', :git => "#{lib_path("foo-1.0")}"
+ G
+
+ lockfile <<-L
+ GIT
+ remote: #{lib_path("foo-1.0")}
+ revision: #{unreachable_sha}
+ specs:
+ foo (1.0)
+
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ foo!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install"
+
+ expect(err).to be_empty
+ end
+
+ it "properly fetches a git source locked to an annotated tag" do
+ # Create an annotated tag
+ git("tag -a v1.0 -m 'Annotated v1.0'", lib_path("foo-1.0"))
+ annotated_tag = git("rev-parse v1.0", lib_path("foo-1.0"))
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'foo', :git => "#{lib_path("foo-1.0")}"
+ G
+
+ lockfile <<-L
+ GIT
+ remote: #{lib_path("foo-1.0")}
+ revision: #{annotated_tag}
+ specs:
+ foo (1.0)
+
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ foo!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install"
+
+ expect(err).to be_empty
+ end
+
it "provides correct #full_gem_path" do
run <<-RUBY
puts Bundler.rubygems.find_name('foo').first.full_gem_path
diff --git a/spec/bundler/lock/lockfile_spec.rb b/spec/bundler/lock/lockfile_spec.rb
index 0e2a3a3cd8..4fd081e7d0 100644
--- a/spec/bundler/lock/lockfile_spec.rb
+++ b/spec/bundler/lock/lockfile_spec.rb
@@ -1,28 +1,22 @@
# frozen_string_literal: true
RSpec.describe "the lockfile format" do
- include Bundler::GemHelpers
-
before do
- build_repo2 do
- # Capistrano did this (at least until version 2.5.10)
- # RubyGems 2.2 doesn't allow the specifying of a dependency twice
- # See https://github.com/rubygems/rubygems/commit/03dbac93a3396a80db258d9bc63500333c25bd2f
- build_gem "double_deps", "1.0", :skip_validation => true do |s|
- s.add_dependency "net-ssh", ">= 1.0.0"
- s.add_dependency "net-ssh"
- end
- end
+ build_repo2
end
it "generates a simple lockfile for a single source, gem" do
+ checksums = checksums_section_when_existing do |c|
+ c.checksum(gem_repo2, "rack", "1.0.0")
+ end
+
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
gem "rack"
G
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -33,13 +27,13 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
- it "updates the lockfile's bundler version if current ver. is newer" do
+ it "updates the lockfile's bundler version if current ver. is newer, and version was forced through BUNDLER_VERSION" do
system_gems "bundler-1.8.2"
lockfile <<-L
@@ -64,13 +58,16 @@ RSpec.describe "the lockfile format" do
1.8.2
L
- install_gemfile <<-G, :env => { "BUNDLER_VERSION" => Bundler::VERSION }
+ install_gemfile <<-G, verbose: true, env: { "BUNDLER_VERSION" => Bundler::VERSION }
source "#{file_uri_for(gem_repo2)}"
gem "rack"
G
- lockfile_should_be <<-G
+ expect(out).not_to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with 1.8.2.")
+ expect(out).to include("Using bundler #{Bundler::VERSION}")
+
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -87,8 +84,8 @@ RSpec.describe "the lockfile format" do
G
end
- it "does not update the lockfile's bundler version if nothing changed during bundle install" do
- version = "#{Bundler::VERSION.split(".").first}.0.0.a"
+ it "does not update the lockfile's bundler version if nothing changed during bundle install, but uses the locked version", rubygems: ">= 3.3.0.a", realworld: true do
+ version = "2.3.0"
lockfile <<-L
GEM
@@ -106,13 +103,16 @@ RSpec.describe "the lockfile format" do
#{version}
L
- install_gemfile <<-G
+ install_gemfile <<-G, verbose: true, artifice: "vcr"
source "#{file_uri_for(gem_repo2)}"
gem "rack"
G
- lockfile_should_be <<-G
+ expect(out).to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{version}.")
+ expect(out).to include("Using bundler #{version}")
+
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -129,7 +129,13 @@ RSpec.describe "the lockfile format" do
G
end
- it "updates the lockfile's bundler version if not present" do
+ it "does not update the lockfile's bundler version if nothing changed during bundle install, and uses the latest version", rubygems: "< 3.3.0.a" do
+ version = "#{Bundler::VERSION.split(".").first}.0.0.a"
+
+ checksums = checksums_section do |c|
+ c.checksum(gem_repo2, "rack", "1.0.0")
+ end
+
lockfile <<-L
GEM
remote: #{file_uri_for(gem_repo2)}/
@@ -141,15 +147,21 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack
+ #{checksums}
+ BUNDLED WITH
+ #{version}
L
- install_gemfile <<-G
+ install_gemfile <<-G, verbose: true
source "#{file_uri_for(gem_repo2)}"
- gem "rack", "> 0"
+ gem "rack"
G
- lockfile_should_be <<-G
+ expect(out).not_to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{version}.")
+ expect(out).to include("Using bundler #{Bundler::VERSION}")
+
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -159,17 +171,14 @@ RSpec.describe "the lockfile format" do
#{lockfile_platforms}
DEPENDENCIES
- rack (> 0)
-
+ rack
+ #{checksums}
BUNDLED WITH
- #{Bundler::VERSION}
+ #{version}
G
end
- it "warns if the current is older than lockfile's bundler version" do
- current_version = Bundler::VERSION
- newer_minor = bump_minor(current_version)
-
+ it "adds the BUNDLED WITH section if not present" do
lockfile <<-L
GEM
remote: #{file_uri_for(gem_repo2)}/
@@ -181,25 +190,15 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack
-
- BUNDLED WITH
- #{newer_minor}
L
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
- gem "rack"
+ gem "rack", "> 0"
G
- pre_flag = prerelease?(newer_minor) ? " --pre" : ""
- warning_message = "the running version of Bundler (#{current_version}) is older " \
- "than the version that created the lockfile (#{newer_minor}). " \
- "We suggest you to upgrade to the version that created the " \
- "lockfile by running `gem install bundler:#{newer_minor}#{pre_flag}`."
- expect(err).to include warning_message
-
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -209,14 +208,14 @@ RSpec.describe "the lockfile format" do
#{lockfile_platforms}
DEPENDENCIES
- rack
+ rack (> 0)
BUNDLED WITH
- #{newer_minor}
+ #{Bundler::VERSION}
G
end
- it "warns when updating bundler major version" do
+ it "update the bundler major version just fine" do
current_version = Bundler::VERSION
older_major = previous_major(current_version)
@@ -238,18 +237,15 @@ RSpec.describe "the lockfile format" do
#{older_major}
L
- install_gemfile <<-G, :env => { "BUNDLER_VERSION" => Bundler::VERSION }
+ install_gemfile <<-G, env: { "BUNDLER_VERSION" => Bundler::VERSION }
source "#{file_uri_for(gem_repo2)}/"
gem "rack"
G
- expect(err).to include(
- "Warning: the lockfile is being updated to Bundler " \
- "#{current_version.split(".").first}, after which you will be unable to return to Bundler #{older_major.split(".").first}."
- )
+ expect(err).to be_empty
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -273,7 +269,12 @@ RSpec.describe "the lockfile format" do
gem "rack-obama"
G
- lockfile_should_be <<-G
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo2, "rack", "1.0.0"
+ c.checksum gem_repo2, "rack-obama", "1.0"
+ end
+
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -286,7 +287,7 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack-obama
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -299,7 +300,12 @@ RSpec.describe "the lockfile format" do
gem "rack-obama", ">= 1.0"
G
- lockfile_should_be <<-G
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo2, "rack", "1.0.0"
+ c.checksum gem_repo2, "rack-obama", "1.0"
+ end
+
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -312,16 +318,16 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack-obama (>= 1.0)
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
- it "generates a lockfile without credentials for a configured source" do
+ it "generates a lockfile without credentials" do
bundle "config set http://localgemserver.test/ user:pass"
- install_gemfile(<<-G, :artifice => "endpoint_strict_basic_authentication", :quiet => true)
+ install_gemfile(<<-G, artifice: "endpoint_strict_basic_authentication", quiet: true)
source "#{file_uri_for(gem_repo1)}"
source "http://localgemserver.test/" do
@@ -333,7 +339,12 @@ RSpec.describe "the lockfile format" do
end
G
- lockfile_should_be <<-G
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo2, "rack", "1.0.0"
+ c.checksum gem_repo2, "rack-obama", "1.0"
+ end
+
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
@@ -343,7 +354,7 @@ RSpec.describe "the lockfile format" do
specs:
GEM
- remote: http://user:pass@othergemserver.test/
+ remote: http://othergemserver.test/
specs:
rack (1.0.0)
rack-obama (1.0)
@@ -354,7 +365,7 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack-obama (>= 1.0)!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -366,7 +377,12 @@ RSpec.describe "the lockfile format" do
gem "net-sftp"
G
- lockfile_should_be <<-G
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo2, "net-sftp", "1.1.1"
+ c.checksum gem_repo2, "net-ssh", "1.0"
+ end
+
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -379,7 +395,7 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
net-sftp
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -395,10 +411,14 @@ RSpec.describe "the lockfile format" do
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
- lockfile_should_be <<-G
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ end
+
+ expect(lockfile).to eq <<~G
GIT
remote: #{lib_path("foo-1.0")}
- revision: #{git.ref_for("master")}
+ revision: #{git.ref_for("main")}
specs:
foo (1.0)
@@ -411,14 +431,14 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "does not asplode when a platform specific dependency is present and the Gemfile has not been resolved on that platform" do
- build_lib "omg", :path => lib_path("omg")
+ build_lib "omg", path: lib_path("omg")
gemfile <<-G
source "#{file_uri_for(gem_repo2)}/"
@@ -459,6 +479,10 @@ RSpec.describe "the lockfile format" do
it "serializes global git sources" do
git = build_git "foo"
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ end
+
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
@@ -466,10 +490,10 @@ RSpec.describe "the lockfile format" do
end
G
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GIT
remote: #{lib_path("foo-1.0")}
- revision: #{git.ref_for("master")}
+ revision: #{git.ref_for("main")}
specs:
foo (1.0)
@@ -482,7 +506,7 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -490,14 +514,18 @@ RSpec.describe "the lockfile format" do
it "generates a lockfile with a ref for a single pinned source, git gem with a branch requirement" do
git = build_git "foo"
- update_git "foo", :branch => "omg"
+ update_git "foo", branch: "omg"
+
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ end
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}", :branch => "omg"
G
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GIT
remote: #{lib_path("foo-1.0")}
revision: #{git.ref_for("omg")}
@@ -514,7 +542,7 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -522,14 +550,18 @@ RSpec.describe "the lockfile format" do
it "generates a lockfile with a ref for a single pinned source, git gem with a tag requirement" do
git = build_git "foo"
- update_git "foo", :tag => "omg"
+ update_git "foo", tag: "omg"
+
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ end
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}", :tag => "omg"
G
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GIT
remote: #{lib_path("foo-1.0")}
revision: #{git.ref_for("omg")}
@@ -546,21 +578,111 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
+ it "is conservative with dependencies of git gems" do
+ build_repo4 do
+ build_gem "orm_adapter", "0.4.1"
+ build_gem "orm_adapter", "0.5.0"
+ end
+
+ FileUtils.mkdir_p lib_path("ckeditor/lib")
+
+ @remote = build_git("ckeditor_remote", bare: true)
+
+ build_git "ckeditor", path: lib_path("ckeditor") do |s|
+ s.write "lib/ckeditor.rb", "CKEDITOR = '4.0.7'"
+ s.version = "4.0.7"
+ s.add_dependency "orm_adapter"
+ end
+
+ update_git "ckeditor", path: lib_path("ckeditor"), remote: file_uri_for(@remote.path)
+ update_git "ckeditor", path: lib_path("ckeditor"), tag: "v4.0.7"
+ old_git = update_git "ckeditor", path: lib_path("ckeditor"), push: "v4.0.7"
+
+ update_git "ckeditor", path: lib_path("ckeditor"), gemspec: true do |s|
+ s.write "lib/ckeditor.rb", "CKEDITOR = '4.0.8'"
+ s.version = "4.0.8"
+ s.add_dependency "orm_adapter"
+ end
+ update_git "ckeditor", path: lib_path("ckeditor"), tag: "v4.0.8"
+
+ new_git = update_git "ckeditor", path: lib_path("ckeditor"), push: "v4.0.8"
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "ckeditor", :git => "#{@remote.path}", :tag => "v4.0.8"
+ G
+
+ lockfile <<~L
+ GIT
+ remote: #{@remote.path}
+ revision: #{old_git.ref_for("v4.0.7")}
+ tag: v4.0.7
+ specs:
+ ckeditor (4.0.7)
+ orm_adapter
+
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ orm_adapter (0.4.1)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ckeditor!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "lock"
+
+ # Bumps the git gem, but keeps its dependency locked
+ expect(lockfile).to eq <<~L
+ GIT
+ remote: #{@remote.path}
+ revision: #{new_git.ref_for("v4.0.8")}
+ tag: v4.0.8
+ specs:
+ ckeditor (4.0.8)
+ orm_adapter
+
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ orm_adapter (0.4.1)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ckeditor!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+
it "serializes pinned path sources to the lockfile" do
build_lib "foo"
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ end
+
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo-1.0")}"
G
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
PATH
remote: #{lib_path("foo-1.0")}
specs:
@@ -575,7 +697,7 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -584,6 +706,10 @@ RSpec.describe "the lockfile format" do
it "serializes pinned path sources to the lockfile even when packaging" do
build_lib "foo"
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ end
+
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo-1.0")}"
@@ -591,9 +717,9 @@ RSpec.describe "the lockfile format" do
bundle "config set cache_all true"
bundle :cache
- bundle :install, :local => true
+ bundle :install, local: true
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
PATH
remote: #{lib_path("foo-1.0")}
specs:
@@ -608,7 +734,7 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -618,6 +744,12 @@ RSpec.describe "the lockfile format" do
build_lib "foo"
bar = build_git "bar"
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ c.no_checksum "bar", "1.0"
+ c.checksum gem_repo2, "rack", "1.0.0"
+ end
+
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}/"
@@ -626,10 +758,10 @@ RSpec.describe "the lockfile format" do
gem "bar", :git => "#{lib_path("bar-1.0")}"
G
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GIT
remote: #{lib_path("bar-1.0")}
- revision: #{bar.ref_for("master")}
+ revision: #{bar.ref_for("main")}
specs:
bar (1.0)
@@ -650,7 +782,7 @@ RSpec.describe "the lockfile format" do
bar!
foo!
rack
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -663,7 +795,11 @@ RSpec.describe "the lockfile format" do
gem "rack", :source => "#{file_uri_for(gem_repo2)}/"
G
- lockfile_should_be <<-G
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo2, "rack", "1.0.0"
+ end
+
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -674,7 +810,7 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -689,7 +825,15 @@ RSpec.describe "the lockfile format" do
gem "rack-obama"
G
- lockfile_should_be <<-G
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo2, "actionpack", "2.3.2"
+ c.checksum gem_repo2, "activesupport", "2.3.2"
+ c.checksum gem_repo2, "rack", "1.0.0"
+ c.checksum gem_repo2, "rack-obama", "1.0"
+ c.checksum gem_repo2, "thin", "1.0"
+ end
+
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -709,7 +853,7 @@ RSpec.describe "the lockfile format" do
actionpack
rack-obama
thin
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -722,7 +866,17 @@ RSpec.describe "the lockfile format" do
gem "rails"
G
- lockfile_should_be <<-G
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo2, "actionmailer", "2.3.2"
+ c.checksum gem_repo2, "actionpack", "2.3.2"
+ c.checksum gem_repo2, "activerecord", "2.3.2"
+ c.checksum gem_repo2, "activeresource", "2.3.2"
+ c.checksum gem_repo2, "activesupport", "2.3.2"
+ c.checksum gem_repo2, "rails", "2.3.2"
+ c.checksum gem_repo2, "rake", rake_version
+ end
+
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -740,27 +894,42 @@ RSpec.describe "the lockfile format" do
actionpack (= 2.3.2)
activerecord (= 2.3.2)
activeresource (= 2.3.2)
- rake (= 13.0.1)
- rake (13.0.1)
+ rake (= #{rake_version})
+ rake (#{rake_version})
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
rails
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "orders dependencies by version" do
+ update_repo2 do
+ # Capistrano did this (at least until version 2.5.10)
+ # RubyGems 2.2 doesn't allow the specifying of a dependency twice
+ # See https://github.com/rubygems/rubygems/commit/03dbac93a3396a80db258d9bc63500333c25bd2f
+ build_gem "double_deps", "1.0", skip_validation: true do |s|
+ s.add_dependency "net-ssh", ">= 1.0.0"
+ s.add_dependency "net-ssh"
+ end
+ end
+
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}/"
gem 'double_deps'
G
- lockfile_should_be <<-G
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo2, "double_deps", "1.0"
+ c.checksum gem_repo2, "net-ssh", "1.0"
+ end
+
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -774,7 +943,7 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
double_deps
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -787,7 +956,12 @@ RSpec.describe "the lockfile format" do
gem "rack-obama", ">= 1.0", :require => "rack/obama"
G
- lockfile_should_be <<-G
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo2, "rack", "1.0.0"
+ c.checksum gem_repo2, "rack-obama", "1.0"
+ end
+
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -800,7 +974,7 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack-obama (>= 1.0)
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -813,7 +987,12 @@ RSpec.describe "the lockfile format" do
gem "rack-obama", ">= 1.0", :group => :test
G
- lockfile_should_be <<-G
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo2, "rack", "1.0.0"
+ c.checksum gem_repo2, "rack-obama", "1.0"
+ end
+
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -826,14 +1005,18 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack-obama (>= 1.0)
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "stores relative paths when the path is provided in a relative fashion and in Gemfile dir" do
- build_lib "foo", :path => bundled_app("foo")
+ build_lib "foo", path: bundled_app("foo")
+
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ end
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -842,7 +1025,7 @@ RSpec.describe "the lockfile format" do
end
G
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
PATH
remote: foo
specs:
@@ -857,14 +1040,18 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "stores relative paths when the path is provided in a relative fashion and is above Gemfile dir" do
- build_lib "foo", :path => bundled_app(File.join("..", "foo"))
+ build_lib "foo", path: bundled_app(File.join("..", "foo"))
+
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ end
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -873,7 +1060,7 @@ RSpec.describe "the lockfile format" do
end
G
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
PATH
remote: ../foo
specs:
@@ -888,23 +1075,27 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "stores relative paths when the path is provided in an absolute fashion but is relative" do
- build_lib "foo", :path => bundled_app("foo")
+ build_lib "foo", path: bundled_app("foo")
+
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ end
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- path File.expand_path("../foo", __FILE__) do
+ path File.expand_path("foo", __dir__) do
gem "foo"
end
G
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
PATH
remote: foo
specs:
@@ -919,21 +1110,25 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "stores relative paths when the path is provided for gemspec" do
- build_lib("foo", :path => tmp.join("foo"))
+ build_lib("foo", path: tmp.join("foo"))
+
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "1.0"
+ end
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gemspec :path => "../foo"
G
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
PATH
remote: ../foo
specs:
@@ -948,13 +1143,17 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "keeps existing platforms in the lockfile" do
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "rack", "1.0.0"
+ end
+
lockfile <<-G
GEM
remote: #{file_uri_for(gem_repo2)}/
@@ -966,7 +1165,7 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -977,24 +1176,65 @@ RSpec.describe "the lockfile format" do
gem "rack"
G
- lockfile_should_be <<-G
+ checksums.checksum(gem_repo2, "rack", "1.0.0")
+
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
rack (1.0.0)
PLATFORMS
- java
- #{lockfile_platforms}
+ #{lockfile_platforms("java", local_platform, defaults: [])}
DEPENDENCIES
rack
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
+ it "adds compatible platform specific variants to the lockfile, even if resolution fallback to RUBY due to some other incompatible platform specific variant" do
+ simulate_platform "arm64-darwin-23" do
+ build_repo4 do
+ build_gem "google-protobuf", "3.25.1"
+ build_gem "google-protobuf", "3.25.1" do |s|
+ s.platform = "arm64-darwin-23"
+ end
+ build_gem "google-protobuf", "3.25.1" do |s|
+ s.platform = "x64-mingw-ucrt"
+ s.required_ruby_version = "> #{Gem.ruby_version}"
+ end
+ end
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "google-protobuf"
+ G
+ bundle "lock --add-platform x64-mingw-ucrt"
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ google-protobuf (3.25.1)
+ google-protobuf (3.25.1-arm64-darwin-23)
+
+ PLATFORMS
+ arm64-darwin-23
+ ruby
+ x64-mingw-ucrt
+
+ DEPENDENCIES
+ google-protobuf
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
it "persists the spec's specific platform to the lockfile" do
build_repo2 do
build_gem "platform_specific", "1.0" do |s|
@@ -1009,7 +1249,11 @@ RSpec.describe "the lockfile format" do
gem "platform_specific"
G
- lockfile_should_be <<-G
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo2, "platform_specific", "1.0", "universal-java-16"
+ end
+
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -1020,13 +1264,18 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
platform_specific
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "does not add duplicate gems" do
+ checksums = checksums_section_when_existing do |c|
+ c.checksum(gem_repo2, "activesupport", "2.3.5")
+ c.checksum(gem_repo2, "rack", "1.0.0")
+ end
+
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}/"
gem "rack"
@@ -1038,7 +1287,7 @@ RSpec.describe "the lockfile format" do
gem "activesupport"
G
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -1051,20 +1300,24 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
activesupport
rack
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "does not add duplicate dependencies" do
+ checksums = checksums_section_when_existing do |c|
+ c.checksum(gem_repo2, "rack", "1.0.0")
+ end
+
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}/"
gem "rack"
gem "rack"
G
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -1075,20 +1328,24 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "does not add duplicate dependencies with versions" do
+ checksums = checksums_section_when_existing do |c|
+ c.checksum(gem_repo2, "rack", "1.0.0")
+ end
+
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}/"
gem "rack", "1.0"
gem "rack", "1.0"
G
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -1099,20 +1356,24 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack (= 1.0)
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "does not add duplicate dependencies in different groups" do
+ checksums = checksums_section_when_existing do |c|
+ c.checksum(gem_repo2, "rack", "1.0.0")
+ end
+
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}/"
gem "rack", "1.0", :group => :one
gem "rack", "1.0", :group => :two
G
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -1123,14 +1384,14 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack (= 1.0)
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "raises if two different versions are used" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo2)}/"
gem "rack", "1.0"
gem "rack", "1.1"
@@ -1141,7 +1402,7 @@ RSpec.describe "the lockfile format" do
end
it "raises if two different sources are used" do
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo2)}/"
gem "rack"
gem "rack", :git => "git://hubz.com"
@@ -1152,12 +1413,16 @@ RSpec.describe "the lockfile format" do
end
it "works correctly with multiple version dependencies" do
+ checksums = checksums_section_when_existing do |c|
+ c.checksum(gem_repo2, "rack", "0.9.1")
+ end
+
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}/"
gem "rack", "> 0.9", "< 1.0"
G
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -1168,20 +1433,24 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack (> 0.9, < 1.0)
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "captures the Ruby version in the lockfile" do
+ checksums = checksums_section_when_existing do |c|
+ c.checksum(gem_repo2, "rack", "0.9.1")
+ end
+
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}/"
- ruby '#{RUBY_VERSION}'
+ ruby '#{Gem.ruby_version}'
gem "rack", "> 0.9", "< 1.0"
G
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
@@ -1192,9 +1461,9 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
rack (> 0.9, < 1.0)
-
+ #{checksums}
RUBY VERSION
- ruby #{RUBY_VERSION}p#{RUBY_PATCHLEVEL}
+ #{Bundler::RubyVersion.system}
BUNDLED WITH
#{Bundler::VERSION}
@@ -1215,13 +1484,184 @@ RSpec.describe "the lockfile format" do
rack_middleware
L
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo2)}"
gem "rack_middleware"
G
expect(err).to include("Downloading rack_middleware-1.0 revealed dependencies not in the API or the lockfile (#{Gem::Dependency.new("rack", "= 0.9.1")}).").
- and include("Either installing with `--full-index` or running `bundle update rack_middleware` should fix the problem.")
+ and include("Running `bundle update rack_middleware` should fix the problem.")
+ end
+
+ it "regenerates a lockfile with no specs" do
+ build_repo4 do
+ build_gem "indirect_dependency", "1.2.3" do |s|
+ s.metadata["funding_uri"] = "https://example.com/donate"
+ end
+
+ build_gem "direct_dependency", "4.5.6" do |s|
+ s.add_dependency "indirect_dependency", ">= 0"
+ end
+ end
+
+ lockfile <<-G
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ direct_dependency
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ G
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "direct_dependency"
+ G
+
+ expect(lockfile).to eq <<~G
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ direct_dependency (4.5.6)
+ indirect_dependency
+ indirect_dependency (1.2.3)
+
+ PLATFORMS
+ #{lockfile_platforms("ruby", generic_local_platform, defaults: [])}
+
+ DEPENDENCIES
+ direct_dependency
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ G
+ end
+
+ shared_examples_for "a lockfile missing dependent specs" do
+ it "auto-heals" do
+ build_repo4 do
+ build_gem "minitest-bisect", "1.6.0" do |s|
+ s.add_dependency "path_expander", "~> 1.1"
+ end
+
+ build_gem "path_expander", "1.1.1"
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "minitest-bisect"
+ G
+
+ # Corrupt lockfile (completely missing path_expander)
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ minitest-bisect (1.6.0)
+
+ PLATFORMS
+ #{platforms}
+
+ DEPENDENCIES
+ minitest-bisect
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ cache_gems "minitest-bisect-1.6.0", "path_expander-1.1.1", gem_repo: gem_repo4
+ bundle :install
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ minitest-bisect (1.6.0)
+ path_expander (~> 1.1)
+ path_expander (1.1.1)
+
+ PLATFORMS
+ #{platforms}
+
+ DEPENDENCIES
+ minitest-bisect
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ context "with just specific platform" do
+ let(:platforms) { lockfile_platforms }
+
+ it_behaves_like "a lockfile missing dependent specs"
+ end
+
+ context "with both ruby and specific platform" do
+ let(:platforms) { lockfile_platforms("ruby") }
+
+ it_behaves_like "a lockfile missing dependent specs"
+ end
+
+ it "auto-heals when the lockfile is missing specs" do
+ build_repo4 do
+ build_gem "minitest-bisect", "1.6.0" do |s|
+ s.add_dependency "path_expander", "~> 1.1"
+ end
+
+ build_gem "path_expander", "1.1.1"
+ end
+
+ gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "minitest-bisect"
+ G
+
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ minitest-bisect (1.6.0)
+ path_expander (~> 1.1)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ minitest-bisect
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install --verbose"
+ expect(out).to include("re-resolving dependencies because your lock file includes \"minitest-bisect\" but not some of its dependencies")
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ minitest-bisect (1.6.0)
+ path_expander (~> 1.1)
+ path_expander (1.1.1)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ minitest-bisect
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
end
describe "a line ending" do
@@ -1252,7 +1692,7 @@ RSpec.describe "the lockfile format" do
end
end
- expect { bundle "update", :all => true }.to change { File.mtime(bundled_app_lock) }
+ expect { bundle "update", all: true }.to change { File.mtime(bundled_app_lock) }
expect(File.read(bundled_app_lock)).not_to match("\r\n")
expect(the_bundle).to include_gems "rack 1.2"
end
@@ -1270,12 +1710,10 @@ RSpec.describe "the lockfile format" do
File.open(bundled_app_lock, "wb") {|f| f.puts(win_lock) }
set_lockfile_mtime_to_known_value
- expect { bundle "update", :all => true }.to change { File.mtime(bundled_app_lock) }
+ expect { bundle "update", all: true }.to change { File.mtime(bundled_app_lock) }
expect(File.read(bundled_app_lock)).to match("\r\n")
- simulate_bundler_version_when_missing_prerelease_default_gem_activation do
- expect(the_bundle).to include_gems "rack 1.2"
- end
+ expect(the_bundle).to include_gems "rack 1.2"
end
end
@@ -1296,7 +1734,7 @@ RSpec.describe "the lockfile format" do
expect do
ruby <<-RUBY
- require '#{entrypoint}'
+ require 'bundler'
Bundler.setup
RUBY
end.not_to change { File.mtime(bundled_app_lock) }
@@ -1325,7 +1763,7 @@ RSpec.describe "the lockfile format" do
#{Bundler::VERSION}
L
- install_gemfile <<-G, :raise_on_error => false
+ install_gemfile <<-G, raise_on_error: false
source "#{file_uri_for(gem_repo2)}/"
gem "rack"
G
diff --git a/spec/bundler/other/cli_dispatch_spec.rb b/spec/bundler/other/cli_dispatch_spec.rb
index 2d6080296f..48b285045a 100644
--- a/spec/bundler/other/cli_dispatch_spec.rb
+++ b/spec/bundler/other/cli_dispatch_spec.rb
@@ -2,19 +2,19 @@
RSpec.describe "bundle command names" do
it "work when given fully" do
- bundle "install", :raise_on_error => false
+ bundle "install", raise_on_error: false
expect(err).to eq("Could not locate Gemfile")
expect(last_command.stdboth).not_to include("Ambiguous command")
end
it "work when not ambiguous" do
- bundle "ins", :raise_on_error => false
+ bundle "ins", raise_on_error: false
expect(err).to eq("Could not locate Gemfile")
expect(last_command.stdboth).not_to include("Ambiguous command")
end
it "print a friendly error when ambiguous" do
- bundle "in", :raise_on_error => false
+ bundle "in", raise_on_error: false
expect(err).to eq("Ambiguous command in matches [info, init, inject, install]")
end
end
diff --git a/spec/bundler/other/ext_spec.rb b/spec/bundler/other/ext_spec.rb
index e13f62a856..4d954b474f 100644
--- a/spec/bundler/other/ext_spec.rb
+++ b/spec/bundler/other/ext_spec.rb
@@ -44,6 +44,10 @@ RSpec.describe "Bundler::GemHelpers#generic" do
expect(generic(pl("x64-mingw32"))).to eq(pl("x64-mingw32"))
expect(generic(pl("x86_64-mingw32"))).to eq(pl("x64-mingw32"))
end
+
+ it "converts 64-bit mingw UCRT platform variants into x64-mingw-ucrt" do
+ expect(generic(pl("x64-mingw-ucrt"))).to eq(pl("x64-mingw-ucrt"))
+ end
end
RSpec.describe "Gem::SourceIndex#refresh!" do
@@ -55,7 +59,27 @@ RSpec.describe "Gem::SourceIndex#refresh!" do
end
it "does not explode when called" do
- run "Gem.source_index.refresh!", :raise_on_error => false
- run "Gem::SourceIndex.new([]).refresh!", :raise_on_error => false
+ run "Gem.source_index.refresh!", raise_on_error: false
+ run "Gem::SourceIndex.new([]).refresh!", raise_on_error: false
+ end
+end
+
+RSpec.describe "Gem::NameTuple" do
+ describe "#initialize" do
+ it "creates a Gem::NameTuple with equality regardless of platform type" do
+ gem_platform = Gem::NameTuple.new "a", v("1"), pl("x86_64-linux")
+ str_platform = Gem::NameTuple.new "a", v("1"), "x86_64-linux"
+ expect(gem_platform).to eq(str_platform)
+ expect(gem_platform.hash).to eq(str_platform.hash)
+ expect(gem_platform.to_a).to eq(str_platform.to_a)
+ end
+ end
+
+ describe "#lock_name" do
+ it "returns the lock name" do
+ expect(Gem::NameTuple.new("a", v("1.0.0"), pl("x86_64-linux")).lock_name).to eq("a (1.0.0-x86_64-linux)")
+ expect(Gem::NameTuple.new("a", v("1.0.0"), "ruby").lock_name).to eq("a (1.0.0)")
+ expect(Gem::NameTuple.new("a", v("1.0.0")).lock_name).to eq("a (1.0.0)")
+ end
end
end
diff --git a/spec/bundler/other/major_deprecation_spec.rb b/spec/bundler/other/major_deprecation_spec.rb
index 688efbcec8..939b68a0bb 100644
--- a/spec/bundler/other/major_deprecation_spec.rb
+++ b/spec/bundler/other/major_deprecation_spec.rb
@@ -17,14 +17,14 @@ RSpec.describe "major deprecations" do
bundle "exec ruby -e #{source.dump}"
end
- it "is deprecated in favor of .unbundled_env", :bundler => "< 3" do
+ it "is deprecated in favor of .unbundled_env", bundler: "< 3" do
expect(deprecations).to include \
"`Bundler.clean_env` has been deprecated in favor of `Bundler.unbundled_env`. " \
"If you instead want the environment before bundler was originally loaded, use `Bundler.original_env` " \
"(called at -e:1)"
end
- pending "is removed and shows a helpful error message about it", :bundler => "3"
+ pending "is removed and shows a helpful error message about it", bundler: "3"
end
describe ".with_clean_env" do
@@ -33,7 +33,7 @@ RSpec.describe "major deprecations" do
bundle "exec ruby -e #{source.dump}"
end
- it "is deprecated in favor of .unbundled_env", :bundler => "< 3" do
+ it "is deprecated in favor of .unbundled_env", bundler: "< 3" do
expect(deprecations).to include(
"`Bundler.with_clean_env` has been deprecated in favor of `Bundler.with_unbundled_env`. " \
"If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env` " \
@@ -41,7 +41,7 @@ RSpec.describe "major deprecations" do
)
end
- pending "is removed and shows a helpful error message about it", :bundler => "3"
+ pending "is removed and shows a helpful error message about it", bundler: "3"
end
describe ".clean_system" do
@@ -50,7 +50,7 @@ RSpec.describe "major deprecations" do
bundle "exec ruby -e #{source.dump}"
end
- it "is deprecated in favor of .unbundled_system", :bundler => "< 3" do
+ it "is deprecated in favor of .unbundled_system", bundler: "< 3" do
expect(deprecations).to include(
"`Bundler.clean_system` has been deprecated in favor of `Bundler.unbundled_system`. " \
"If you instead want to run the command in the environment before bundler was originally loaded, use `Bundler.original_system` " \
@@ -58,7 +58,7 @@ RSpec.describe "major deprecations" do
)
end
- pending "is removed and shows a helpful error message about it", :bundler => "3"
+ pending "is removed and shows a helpful error message about it", bundler: "3"
end
describe ".clean_exec" do
@@ -67,7 +67,7 @@ RSpec.describe "major deprecations" do
bundle "exec ruby -e #{source.dump}"
end
- it "is deprecated in favor of .unbundled_exec", :bundler => "< 3" do
+ it "is deprecated in favor of .unbundled_exec", bundler: "< 3" do
expect(deprecations).to include(
"`Bundler.clean_exec` has been deprecated in favor of `Bundler.unbundled_exec`. " \
"If you instead want to exec to a command in the environment before bundler was originally loaded, use `Bundler.original_exec` " \
@@ -75,7 +75,7 @@ RSpec.describe "major deprecations" do
)
end
- pending "is removed and shows a helpful error message about it", :bundler => "3"
+ pending "is removed and shows a helpful error message about it", bundler: "3"
end
describe ".environment" do
@@ -84,17 +84,29 @@ RSpec.describe "major deprecations" do
bundle "exec ruby -e #{source.dump}"
end
- it "is deprecated in favor of .load", :bundler => "< 3" do
+ it "is deprecated in favor of .load", bundler: "< 3" do
expect(deprecations).to include "Bundler.environment has been removed in favor of Bundler.load (called at -e:1)"
end
- pending "is removed and shows a helpful error message about it", :bundler => "3"
+ pending "is removed and shows a helpful error message about it", bundler: "3"
end
end
+ describe "bundle exec --no-keep-file-descriptors" do
+ before do
+ bundle "exec --no-keep-file-descriptors -e 1", raise_on_error: false
+ end
+
+ it "is deprecated", bundler: "< 3" do
+ expect(deprecations).to include "The `--no-keep-file-descriptors` has been deprecated. `bundle exec` no longer mess with your file descriptors. Close them in the exec'd script if you need to"
+ end
+
+ pending "is removed and shows a helpful error message about it", bundler: "3"
+ end
+
describe "bundle update --quiet" do
it "does not print any deprecations" do
- bundle :update, :quiet => true, :raise_on_error => false
+ bundle :update, quiet: true, raise_on_error: false
expect(deprecations).to be_empty
end
end
@@ -106,19 +118,19 @@ RSpec.describe "major deprecations" do
gem "rack"
G
- bundle "check --path vendor/bundle", :raise_on_error => false
+ bundle "check --path vendor/bundle", raise_on_error: false
end
- it "should print a deprecation warning", :bundler => "< 3" do
+ it "should print a deprecation warning", bundler: "< 3" do
expect(deprecations).to include(
"The `--path` flag is deprecated because it relies on being " \
"remembered across bundler invocations, which bundler will no " \
- "longer do in future versions. Instead please use `bundle config set --local " \
+ "longer do in future versions. Instead please use `bundle config set " \
"path 'vendor/bundle'`, and stop using this flag"
)
end
- pending "fails with a helpful error", :bundler => "3"
+ pending "fails with a helpful error", bundler: "3"
end
context "bundle check --path=" do
@@ -128,19 +140,19 @@ RSpec.describe "major deprecations" do
gem "rack"
G
- bundle "check --path=vendor/bundle", :raise_on_error => false
+ bundle "check --path=vendor/bundle", raise_on_error: false
end
- it "should print a deprecation warning", :bundler => "< 3" do
+ it "should print a deprecation warning", bundler: "< 3" do
expect(deprecations).to include(
"The `--path` flag is deprecated because it relies on being " \
"remembered across bundler invocations, which bundler will no " \
- "longer do in future versions. Instead please use `bundle config set --local " \
+ "longer do in future versions. Instead please use `bundle config set " \
"path 'vendor/bundle'`, and stop using this flag"
)
end
- pending "fails with a helpful error", :bundler => "3"
+ pending "fails with a helpful error", bundler: "3"
end
context "bundle cache --all" do
@@ -150,10 +162,10 @@ RSpec.describe "major deprecations" do
gem "rack"
G
- bundle "cache --all", :raise_on_error => false
+ bundle "cache --all", raise_on_error: false
end
- it "should print a deprecation warning", :bundler => "< 3" do
+ it "should print a deprecation warning", bundler: "< 3" do
expect(deprecations).to include(
"The `--all` flag is deprecated because it relies on being " \
"remembered across bundler invocations, which bundler will no " \
@@ -162,7 +174,7 @@ RSpec.describe "major deprecations" do
)
end
- pending "fails with a helpful error", :bundler => "3"
+ pending "fails with a helpful error", bundler: "3"
end
context "bundle cache --path" do
@@ -172,10 +184,10 @@ RSpec.describe "major deprecations" do
gem "rack"
G
- bundle "cache --path foo", :raise_on_error => false
+ bundle "cache --path foo", raise_on_error: false
end
- it "should print a deprecation warning", :bundler => "< 3" do
+ it "should print a deprecation warning", bundler: "< 3" do
expect(deprecations).to include(
"The `--path` flag is deprecated because its semantics are unclear. " \
"Use `bundle config cache_path` to configure the path of your cache of gems, " \
@@ -184,7 +196,7 @@ RSpec.describe "major deprecations" do
)
end
- pending "fails with a helpful error", :bundler => "3"
+ pending "fails with a helpful error", bundler: "3"
end
describe "bundle config" do
@@ -193,11 +205,11 @@ RSpec.describe "major deprecations" do
bundle "config"
end
- it "warns", :bundler => "3" do
+ it "warns", bundler: "3" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config list` instead.")
end
- pending "fails with a helpful error", :bundler => "3"
+ pending "fails with a helpful error", bundler: "3"
end
describe "old get interface" do
@@ -205,11 +217,11 @@ RSpec.describe "major deprecations" do
bundle "config waka"
end
- it "warns", :bundler => "3" do
+ it "warns", bundler: "3" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config get waka` instead.")
end
- pending "fails with a helpful error", :bundler => "3"
+ pending "fails with a helpful error", bundler: "3"
end
describe "old set interface" do
@@ -217,11 +229,11 @@ RSpec.describe "major deprecations" do
bundle "config waka wakapun"
end
- it "warns", :bundler => "3" do
+ it "warns", bundler: "3" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config set waka wakapun` instead.")
end
- pending "fails with a helpful error", :bundler => "3"
+ pending "fails with a helpful error", bundler: "3"
end
describe "old set interface with --local" do
@@ -229,11 +241,11 @@ RSpec.describe "major deprecations" do
bundle "config --local waka wakapun"
end
- it "warns", :bundler => "3" do
+ it "warns", bundler: "3" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config set --local waka wakapun` instead.")
end
- pending "fails with a helpful error", :bundler => "3"
+ pending "fails with a helpful error", bundler: "3"
end
describe "old set interface with --global" do
@@ -241,11 +253,11 @@ RSpec.describe "major deprecations" do
bundle "config --global waka wakapun"
end
- it "warns", :bundler => "3" do
+ it "warns", bundler: "3" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config set --global waka wakapun` instead.")
end
- pending "fails with a helpful error", :bundler => "3"
+ pending "fails with a helpful error", bundler: "3"
end
describe "old unset interface" do
@@ -253,11 +265,11 @@ RSpec.describe "major deprecations" do
bundle "config --delete waka"
end
- it "warns", :bundler => "3" do
+ it "warns", bundler: "3" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config unset waka` instead.")
end
- pending "fails with a helpful error", :bundler => "3"
+ pending "fails with a helpful error", bundler: "3"
end
describe "old unset interface with --local" do
@@ -265,11 +277,11 @@ RSpec.describe "major deprecations" do
bundle "config --delete --local waka"
end
- it "warns", :bundler => "3" do
+ it "warns", bundler: "3" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config unset --local waka` instead.")
end
- pending "fails with a helpful error", :bundler => "3"
+ pending "fails with a helpful error", bundler: "3"
end
describe "old unset interface with --global" do
@@ -277,11 +289,11 @@ RSpec.describe "major deprecations" do
bundle "config --delete --global waka"
end
- it "warns", :bundler => "3" do
+ it "warns", bundler: "3" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config unset --global waka` instead.")
end
- pending "fails with a helpful error", :bundler => "3"
+ pending "fails with a helpful error", bundler: "3"
end
end
@@ -293,12 +305,12 @@ RSpec.describe "major deprecations" do
G
end
- it "warns when no options are given", :bundler => "3" do
+ it "warns when no options are given", bundler: "3" do
bundle "update"
expect(deprecations).to include("Pass --all to `bundle update` to update everything")
end
- pending "fails with a helpful error when no options are given", :bundler => "3"
+ pending "fails with a helpful error when no options are given", bundler: "3"
it "does not warn when --all is passed" do
bundle "update --all"
@@ -308,17 +320,17 @@ RSpec.describe "major deprecations" do
describe "bundle install --binstubs" do
before do
- install_gemfile <<-G, :binstubs => true
+ install_gemfile <<-G, binstubs: true
source "#{file_uri_for(gem_repo1)}"
gem "rack"
G
end
- it "should output a deprecation warning", :bundler => "< 3" do
+ it "should output a deprecation warning", bundler: "< 3" do
expect(deprecations).to include("The --binstubs option will be removed in favor of `bundle binstubs --all`")
end
- pending "fails with a helpful error", :bundler => "3"
+ pending "fails with a helpful error", bundler: "3"
end
context "bundle install with both gems.rb and Gemfile present" do
@@ -340,7 +352,7 @@ RSpec.describe "major deprecations" do
G
expect(warnings).to include(
- "Multiple gemfiles (gems.rb and Gemfile) detected. Make sure you remove Gemfile and Gemfile.lock since bundler is ignoring them in favor of gems.rb and gems.rb.locked."
+ "Multiple gemfiles (gems.rb and Gemfile) detected. Make sure you remove Gemfile and Gemfile.lock since bundler is ignoring them in favor of gems.rb and gems.locked."
)
expect(the_bundle).not_to include_gem "rack 1.0"
@@ -358,16 +370,16 @@ RSpec.describe "major deprecations" do
end
{
- "clean" => ["clean", true],
- "deployment" => ["deployment", true],
- "frozen" => ["frozen", true],
- "no-deployment" => ["deployment", false],
- "no-prune" => ["no_prune", true],
- "path" => ["path", "vendor/bundle"],
- "shebang" => ["shebang", "ruby27"],
- "system" => ["system", true],
- "without" => ["without", "development"],
- "with" => ["with", "development"],
+ "clean" => ["clean", "true"],
+ "deployment" => ["deployment", "true"],
+ "frozen" => ["frozen", "true"],
+ "no-deployment" => ["deployment", "false"],
+ "no-prune" => ["no_prune", "true"],
+ "path" => ["path", "'vendor/bundle'"],
+ "shebang" => ["shebang", "'ruby27'"],
+ "system" => ["path.system", "true"],
+ "without" => ["without", "'development'"],
+ "with" => ["with", "'development'"],
}.each do |name, expectations|
option_name, value = *expectations
flag_name = "--#{name}"
@@ -378,16 +390,16 @@ RSpec.describe "major deprecations" do
bundle "install #{flag_name} #{value}"
end
- it "should print a deprecation warning", :bundler => "< 3" do
+ it "should print a deprecation warning", bundler: "< 3" do
expect(deprecations).to include(
"The `#{flag_name}` flag is deprecated because it relies on " \
"being remembered across bundler invocations, which bundler " \
"will no longer do in future versions. Instead please use " \
- "`bundle config set --local #{option_name} '#{value}'`, and stop using this flag"
+ "`bundle config set #{option_name} #{value}`, and stop using this flag"
)
end
- pending "fails with a helpful error", :bundler => "3"
+ pending "fails with a helpful error", bundler: "3"
end
end
end
@@ -400,20 +412,20 @@ RSpec.describe "major deprecations" do
G
end
- it "shows a deprecation", :bundler => "< 3" do
+ it "shows a deprecation", bundler: "< 3" do
expect(deprecations).to include(
- "Your Gemfile contains multiple primary sources. " \
+ "Your Gemfile contains multiple global sources. " \
"Using `source` more than once without a block is a security risk, and " \
"may result in installing unexpected gems. To resolve this warning, use " \
"a block to indicate which gems should come from the secondary source."
)
end
- it "doesn't show lockfile deprecations if there's a lockfile", :bundler => "< 3" do
+ it "doesn't show lockfile deprecations if there's a lockfile", bundler: "< 3" do
bundle "install"
expect(deprecations).to include(
- "Your Gemfile contains multiple primary sources. " \
+ "Your Gemfile contains multiple global sources. " \
"Using `source` more than once without a block is a security risk, and " \
"may result in installing unexpected gems. To resolve this warning, use " \
"a block to indicate which gems should come from the secondary source."
@@ -426,7 +438,7 @@ RSpec.describe "major deprecations" do
bundle "install"
expect(deprecations).to include(
- "Your Gemfile contains multiple primary sources. " \
+ "Your Gemfile contains multiple global sources. " \
"Using `source` more than once without a block is a security risk, and " \
"may result in installing unexpected gems. To resolve this warning, use " \
"a block to indicate which gems should come from the secondary source."
@@ -437,7 +449,7 @@ RSpec.describe "major deprecations" do
)
end
- pending "fails with a helpful error", :bundler => "3"
+ pending "fails with a helpful error", bundler: "3"
end
context "bundle install in frozen mode with a lockfile with a single rubygems section with multiple remotes" do
@@ -473,13 +485,13 @@ RSpec.describe "major deprecations" do
bundle "config set --local frozen true"
end
- it "shows a deprecation", :bundler => "< 3" do
+ it "shows a deprecation", bundler: "< 3" do
bundle "install"
expect(deprecations).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure.")
end
- pending "fails with a helpful error", :bundler => "3"
+ pending "fails with a helpful error", bundler: "3"
end
context "when Bundler.setup is run in a ruby script" do
@@ -491,7 +503,7 @@ RSpec.describe "major deprecations" do
G
ruby <<-RUBY
- require '#{entrypoint}'
+ require 'bundler'
Bundler.setup
Bundler.setup
@@ -500,153 +512,119 @@ RSpec.describe "major deprecations" do
it "should print a single deprecation warning" do
expect(warnings).to include(
- "Multiple gemfiles (gems.rb and Gemfile) detected. Make sure you remove Gemfile and Gemfile.lock since bundler is ignoring them in favor of gems.rb and gems.rb.locked."
+ "Multiple gemfiles (gems.rb and Gemfile) detected. Make sure you remove Gemfile and Gemfile.lock since bundler is ignoring them in favor of gems.rb and gems.locked."
)
end
end
context "when `bundler/deployment` is required in a ruby script" do
before do
- ruby(<<-RUBY, :env => env_for_missing_prerelease_default_gem_activation)
+ ruby <<-RUBY
require 'bundler/deployment'
RUBY
end
- it "should print a capistrano deprecation warning", :bundler => "< 3" do
+ it "should print a capistrano deprecation warning", bundler: "< 3" do
expect(deprecations).to include("Bundler no longer integrates " \
"with Capistrano, but Capistrano provides " \
"its own integration with Bundler via the " \
"capistrano-bundler gem. Use it instead.")
end
- pending "fails with a helpful error", :bundler => "3"
+ pending "fails with a helpful error", bundler: "3"
end
- describe Bundler::Dsl do
+ context "bundle show" do
before do
- @rubygems = double("rubygems")
- allow(Bundler::Source::Rubygems).to receive(:new) { @rubygems }
- end
-
- context "with github gems" do
- it "does not warn about removal", :bundler => "< 3" do
- expect(Bundler.ui).not_to receive(:warn)
- subject.gem("sparks", :github => "indirect/sparks")
- github_uri = "https://github.com/indirect/sparks.git"
- expect(subject.dependencies.first.source.uri).to eq(github_uri)
- end
-
- it "warns about removal", :bundler => "3" do
- msg = <<-EOS
-The :github git source is deprecated, and will be removed in the future. Change any "reponame" :github sources to "username/reponame". Add this code to the top of your Gemfile to ensure it continues to work:
-
- git_source(:github) {|repo_name| "https://github.com/\#{repo_name}.git" }
-
- EOS
- expect(Bundler.ui).to receive(:warn).with("[DEPRECATED] #{msg}")
- subject.gem("sparks", :github => "indirect/sparks")
- github_uri = "https://github.com/indirect/sparks.git"
- expect(subject.dependencies.first.source.uri).to eq(github_uri)
- end
- end
-
- context "with bitbucket gems" do
- it "does not warn about removal", :bundler => "< 3" do
- expect(Bundler.ui).not_to receive(:warn)
- subject.gem("not-really-a-gem", :bitbucket => "mcorp/flatlab-rails")
- end
-
- it "warns about removal", :bundler => "3" do
- msg = <<-EOS
-The :bitbucket git source is deprecated, and will be removed in the future. Add this code to the top of your Gemfile to ensure it continues to work:
-
- git_source(:bitbucket) do |repo_name|
- user_name, repo_name = repo_name.split("/")
- repo_name ||= user_name
- "https://\#{user_name}@bitbucket.org/\#{user_name}/\#{repo_name}.git"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ G
end
- EOS
- expect(Bundler.ui).to receive(:warn).with("[DEPRECATED] #{msg}")
- subject.gem("not-really-a-gem", :bitbucket => "mcorp/flatlab-rails")
+ context "with --outdated flag" do
+ before do
+ bundle "show --outdated"
end
- end
- context "with gist gems" do
- it "does not warn about removal", :bundler => "< 3" do
- expect(Bundler.ui).not_to receive(:warn)
- subject.gem("not-really-a-gem", :gist => "1234")
+ it "prints a deprecation warning informing about its removal", bundler: "< 3" do
+ expect(deprecations).to include("the `--outdated` flag to `bundle show` was undocumented and will be removed without replacement")
end
- it "warns about removal", :bundler => "3" do
- msg = <<-EOS
-The :gist git source is deprecated, and will be removed in the future. Add this code to the top of your Gemfile to ensure it continues to work:
-
- git_source(:gist) {|repo_name| "https://gist.github.com/\#{repo_name}.git" }
-
- EOS
- expect(Bundler.ui).to receive(:warn).with("[DEPRECATED] #{msg}")
- subject.gem("not-really-a-gem", :gist => "1234")
- end
+ pending "fails with a helpful message", bundler: "3"
end
end
- context "bundle show" do
+ context "bundle remove" do
before do
- install_gemfile <<-G
+ gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
G
end
- context "with --outdated flag" do
- before do
- bundle "show --outdated"
- end
+ context "with --install" do
+ it "shows a deprecation warning", bundler: "< 3" do
+ bundle "remove rack --install"
- it "prints a deprecation warning informing about its removal", :bundler => "< 3" do
- expect(deprecations).to include("the `--outdated` flag to `bundle show` was undocumented and will be removed without replacement")
+ expect(err).to include "[DEPRECATED] The `--install` flag has been deprecated. `bundle install` is triggered by default."
end
- pending "fails with a helpful message", :bundler => "3"
+ pending "fails with a helpful message", bundler: "3"
end
end
context "bundle console" do
before do
- bundle "console", :raise_on_error => false
+ bundle "console", raise_on_error: false
end
- it "prints a deprecation warning", :bundler => "< 3" do
+ it "prints a deprecation warning", bundler: "< 3" do
expect(deprecations).to include \
"bundle console will be replaced by `bin/console` generated by `bundle gem <name>`"
end
- pending "fails with a helpful message", :bundler => "3"
+ pending "fails with a helpful message", bundler: "3"
end
- context "bundle viz" do
+ context "bundle viz", :realworld do
before do
- graphviz_version = RUBY_VERSION >= "2.4" ? "1.2.5" : "1.2.4"
- realworld_system_gems "ruby-graphviz --version #{graphviz_version}"
+ realworld_system_gems "ruby-graphviz --version 1.2.5"
create_file "gems.rb", "source \"#{file_uri_for(gem_repo1)}\""
bundle "viz"
end
- it "prints a deprecation warning", :bundler => "< 3" do
- expect(deprecations).to include "The `viz` command has been moved to the `bundle-viz` gem, see https://github.com/bundler/bundler-viz"
+ it "prints a deprecation warning", bundler: "< 3" do
+ expect(deprecations).to include "The `viz` command has been renamed to `graph` and moved to a plugin. See https://github.com/rubygems/bundler-graph"
+ end
+
+ pending "fails with a helpful message", bundler: "3"
+ end
+
+ context "bundle plugin install --local_git" do
+ before do
+ build_git "foo" do |s|
+ s.write "plugins.rb"
+ end
+ end
+
+ it "prints a deprecation warning", bundler: "< 3" do
+ bundle "plugin install foo --local_git #{lib_path("foo-1.0")}"
+
+ expect(out).to include("Installed plugin foo")
+ expect(deprecations).to include "--local_git is deprecated, use --git"
end
- pending "fails with a helpful message", :bundler => "3"
+ pending "fails with a helpful message", bundler: "3"
end
describe "deprecating rubocop", :readline do
context "bundle gem --rubocop" do
before do
- bundle "gem my_new_gem --rubocop", :raise_on_error => false
+ bundle "gem my_new_gem --rubocop", raise_on_error: false
end
- it "prints a deprecation warning", :bundler => "< 3" do
+ it "prints a deprecation warning", bundler: "< 3" do
expect(deprecations).to include \
"--rubocop is deprecated, use --linter=rubocop"
end
@@ -654,10 +632,10 @@ The :gist git source is deprecated, and will be removed in the future. Add this
context "bundle gem --no-rubocop" do
before do
- bundle "gem my_new_gem --no-rubocop", :raise_on_error => false
+ bundle "gem my_new_gem --no-rubocop", raise_on_error: false
end
- it "prints a deprecation warning", :bundler => "< 3" do
+ it "prints a deprecation warning", bundler: "< 3" do
expect(deprecations).to include \
"--no-rubocop is deprecated, use --linter"
end
@@ -665,10 +643,10 @@ The :gist git source is deprecated, and will be removed in the future. Add this
context "bundle gem with gem.rubocop set to true" do
before do
- bundle "gem my_new_gem", :env => { "BUNDLE_GEM__RUBOCOP" => "true" }, :raise_on_error => false
+ bundle "gem my_new_gem", env: { "BUNDLE_GEM__RUBOCOP" => "true" }, raise_on_error: false
end
- it "prints a deprecation warning", :bundler => "< 3" do
+ it "prints a deprecation warning", bundler: "< 3" do
expect(deprecations).to include \
"config gem.rubocop is deprecated; we've updated your config to use gem.linter instead"
end
@@ -676,10 +654,10 @@ The :gist git source is deprecated, and will be removed in the future. Add this
context "bundle gem with gem.rubocop set to false" do
before do
- bundle "gem my_new_gem", :env => { "BUNDLE_GEM__RUBOCOP" => "false" }, :raise_on_error => false
+ bundle "gem my_new_gem", env: { "BUNDLE_GEM__RUBOCOP" => "false" }, raise_on_error: false
end
- it "prints a deprecation warning", :bundler => "< 3" do
+ it "prints a deprecation warning", bundler: "< 3" do
expect(deprecations).to include \
"config gem.rubocop is deprecated; we've updated your config to use gem.linter instead"
end
diff --git a/spec/bundler/plugins/command_spec.rb b/spec/bundler/plugins/command_spec.rb
index 4567a39081..af132d6550 100644
--- a/spec/bundler/plugins/command_spec.rb
+++ b/spec/bundler/plugins/command_spec.rb
@@ -69,12 +69,10 @@ RSpec.describe "command plugins" do
end
end
- bundle "plugin install copycat --source #{file_uri_for(gem_repo2)}"
+ bundle "plugin install copycat --source #{file_uri_for(gem_repo2)}", raise_on_error: false
expect(out).not_to include("Installed plugin copycat")
- expect(err).to include("Failed to install the following plugins: `copycat`")
-
- expect(err).to include("Command(s) `mahcommand` declared by copycat are already registered.")
+ expect(err).to include("Failed to install plugin `copycat`, due to Bundler::Plugin::Index::CommandConflict (Command(s) `mahcommand` declared by copycat are already registered.)")
end
end
diff --git a/spec/bundler/plugins/hook_spec.rb b/spec/bundler/plugins/hook_spec.rb
index 72feb14d84..f6ee0ba210 100644
--- a/spec/bundler/plugins/hook_spec.rb
+++ b/spec/bundler/plugins/hook_spec.rb
@@ -106,4 +106,103 @@ RSpec.describe "hook plugins" do
expect(out).to include "installed gem rack : installed"
end
end
+
+ context "before-require-all hook" do
+ before do
+ build_repo2 do
+ build_plugin "before-require-all-plugin" do |s|
+ s.write "plugins.rb", <<-RUBY
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_BEFORE_REQUIRE_ALL do |deps|
+ puts "gems to be required \#{deps.map(&:name).join(", ")}"
+ end
+ RUBY
+ end
+ end
+
+ bundle "plugin install before-require-all-plugin --source #{file_uri_for(gem_repo2)}"
+ end
+
+ it "runs before all rubygems are required" do
+ install_gemfile_and_bundler_require
+ expect(out).to include "gems to be required rake, rack"
+ end
+ end
+
+ context "before-require hook" do
+ before do
+ build_repo2 do
+ build_plugin "before-require-plugin" do |s|
+ s.write "plugins.rb", <<-RUBY
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_BEFORE_REQUIRE do |dep|
+ puts "requiring gem \#{dep.name}"
+ end
+ RUBY
+ end
+ end
+
+ bundle "plugin install before-require-plugin --source #{file_uri_for(gem_repo2)}"
+ end
+
+ it "runs before each rubygem is required" do
+ install_gemfile_and_bundler_require
+ expect(out).to include "requiring gem rake"
+ expect(out).to include "requiring gem rack"
+ end
+ end
+
+ context "after-require-all hook" do
+ before do
+ build_repo2 do
+ build_plugin "after-require-all-plugin" do |s|
+ s.write "plugins.rb", <<-RUBY
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_AFTER_REQUIRE_ALL do |deps|
+ puts "required gems \#{deps.map(&:name).join(", ")}"
+ end
+ RUBY
+ end
+ end
+
+ bundle "plugin install after-require-all-plugin --source #{file_uri_for(gem_repo2)}"
+ end
+
+ it "runs after all rubygems are required" do
+ install_gemfile_and_bundler_require
+ expect(out).to include "required gems rake, rack"
+ end
+ end
+
+ context "after-require hook" do
+ before do
+ build_repo2 do
+ build_plugin "after-require-plugin" do |s|
+ s.write "plugins.rb", <<-RUBY
+ Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_AFTER_REQUIRE do |dep|
+ puts "required gem \#{dep.name}"
+ end
+ RUBY
+ end
+ end
+
+ bundle "plugin install after-require-plugin --source #{file_uri_for(gem_repo2)}"
+ end
+
+ it "runs after each rubygem is required" do
+ install_gemfile_and_bundler_require
+ expect(out).to include "required gem rake"
+ expect(out).to include "required gem rack"
+ end
+ end
+
+ def install_gemfile_and_bundler_require
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rake"
+ gem "rack"
+ G
+
+ ruby <<-RUBY
+ require "bundler"
+ Bundler.require
+ RUBY
+ end
end
diff --git a/spec/bundler/plugins/install_spec.rb b/spec/bundler/plugins/install_spec.rb
index c719e8533e..20c2f1fd26 100644
--- a/spec/bundler/plugins/install_spec.rb
+++ b/spec/bundler/plugins/install_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe "bundler plugin install" do
end
it "shows proper message when gem in not found in the source" do
- bundle "plugin install no-foo --source #{file_uri_for(gem_repo1)}", :raise_on_error => false
+ bundle "plugin install no-foo --source #{file_uri_for(gem_repo1)}", raise_on_error: false
expect(err).to include("Could not find")
plugin_should_not_be_installed("no-foo")
@@ -22,8 +22,15 @@ RSpec.describe "bundler plugin install" do
plugin_should_be_installed("foo")
end
+ it "installs from rubygems source in frozen mode" do
+ bundle "plugin install foo --source #{file_uri_for(gem_repo2)}", env: { "BUNDLE_DEPLOYMENT" => "true" }
+
+ expect(out).to include("Installed plugin foo")
+ plugin_should_be_installed("foo")
+ end
+
it "installs from sources configured as Gem.sources without any flags" do
- bundle "plugin install foo", :env => { "BUNDLER_SPEC_GEM_SOURCES" => file_uri_for(gem_repo2).to_s }
+ bundle "plugin install foo", env: { "BUNDLER_SPEC_GEM_SOURCES" => file_uri_for(gem_repo2).to_s }
expect(out).to include("Installed plugin foo")
plugin_should_be_installed("foo")
@@ -32,7 +39,8 @@ RSpec.describe "bundler plugin install" do
it "shows help when --help flag is given" do
bundle "plugin install --help"
- expect(out).to include("bundle plugin install PLUGINS # Install the plugin from the source")
+ # The help message defined in ../../lib/bundler/man/bundle-plugin.1.ronn will be output.
+ expect(out).to include("You can install, uninstall, and list plugin(s)")
end
context "plugin is already installed" do
@@ -69,6 +77,43 @@ RSpec.describe "bundler plugin install" do
plugin_should_be_installed("foo", "kung-foo")
end
+ it "installs the latest version if not installed" do
+ update_repo2 do
+ build_plugin "foo", "1.1"
+ end
+
+ bundle "plugin install foo --version 1.0 --source #{file_uri_for(gem_repo2)} --verbose"
+ expect(out).to include("Installing foo 1.0")
+
+ bundle "plugin install foo --source #{file_uri_for(gem_repo2)} --verbose"
+ expect(out).to include("Installing foo 1.1")
+
+ bundle "plugin install foo --source #{file_uri_for(gem_repo2)} --verbose"
+ expect(out).to include("Using foo 1.1")
+ end
+
+ it "raises an error when when --branch specified" do
+ bundle "plugin install foo --branch main --source #{file_uri_for(gem_repo2)}", raise_on_error: false
+
+ expect(out).not_to include("Installed plugin foo")
+
+ expect(err).to include("--branch can only be used with git sources")
+ end
+
+ it "raises an error when --ref specified" do
+ bundle "plugin install foo --ref v1.2.3 --source #{file_uri_for(gem_repo2)}", raise_on_error: false
+
+ expect(err).to include("--ref can only be used with git sources")
+ end
+
+ it "raises error when both --branch and --ref options are specified" do
+ bundle "plugin install foo --source #{file_uri_for(gem_repo2)} --branch main --ref v1.2.3", raise_on_error: false
+
+ expect(out).not_to include("Installed plugin foo")
+
+ expect(err).to include("You cannot specify `--branch` and `--ref` at the same time.")
+ end
+
it "works with different load paths" do
build_repo2 do
build_plugin "testing" do |s|
@@ -109,9 +154,9 @@ RSpec.describe "bundler plugin install" do
build_gem "charlie"
end
- bundle "plugin install charlie --source #{file_uri_for(gem_repo2)}"
+ bundle "plugin install charlie --source #{file_uri_for(gem_repo2)}", raise_on_error: false
- expect(err).to include("Failed to install the following plugins: `charlie`. The underlying error was: plugins.rb was not found")
+ expect(err).to include("Failed to install plugin `charlie`, due to Bundler::Plugin::MalformattedPlugin (plugins.rb was not found in the plugin.)")
expect(global_plugin_gem("charlie-1.0")).not_to be_directory
@@ -128,7 +173,7 @@ RSpec.describe "bundler plugin install" do
end
end
- bundle "plugin install chaplin --source #{file_uri_for(gem_repo2)}"
+ bundle "plugin install chaplin --source #{file_uri_for(gem_repo2)}", raise_on_error: false
expect(global_plugin_gem("chaplin-1.0")).not_to be_directory
@@ -153,20 +198,58 @@ RSpec.describe "bundler plugin install" do
s.write "plugins.rb"
end
- bundle "plugin install foo --local_git #{lib_path("foo-1.0")}"
+ bundle "plugin install foo --git #{lib_path("foo-1.0")}"
expect(out).to include("Installed plugin foo")
plugin_should_be_installed("foo")
end
- it "raises an error when both git and local git sources are specified" do
- bundle "plugin install foo --local_git /phony/path/project --git git@gitphony.com:/repo/project", :raise_on_error => false
+ it "raises an error when both git and local git sources are specified", bundler: "< 3" do
+ bundle "plugin install foo --git /phony/path/project --local_git git@gitphony.com:/repo/project", raise_on_error: false
expect(exitstatus).not_to eq(0)
expect(err).to eq("Remote and local plugin git sources can't be both specified")
end
end
+ context "path plugins" do
+ it "installs from a path source" do
+ build_lib "path_plugin" do |s|
+ s.write "plugins.rb"
+ end
+ bundle "plugin install path_plugin --path #{lib_path("path_plugin-1.0")}"
+
+ expect(out).to include("Installed plugin path_plugin")
+ plugin_should_be_installed("path_plugin")
+ end
+
+ it "installs from a relative path source" do
+ build_lib "path_plugin" do |s|
+ s.write "plugins.rb"
+ end
+ path = lib_path("path_plugin-1.0").relative_path_from(bundled_app)
+ bundle "plugin install path_plugin --path #{path}"
+
+ expect(out).to include("Installed plugin path_plugin")
+ plugin_should_be_installed("path_plugin")
+ end
+
+ it "installs from a relative path source when inside an app" do
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
+ gemfile ""
+
+ build_lib "ga-plugin" do |s|
+ s.write "plugins.rb"
+ end
+
+ path = lib_path("ga-plugin-1.0").relative_path_from(bundled_app)
+ bundle "plugin install ga-plugin --path #{path}"
+
+ plugin_should_be_installed("ga-plugin")
+ expect(local_plugin_gem("foo-1.0")).not_to be_directory
+ end
+ end
+
context "Gemfile eval" do
before do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
@@ -236,6 +319,21 @@ RSpec.describe "bundler plugin install" do
plugin_should_be_installed("ga-plugin")
end
+ it "accepts relative path sources" do
+ build_lib "ga-plugin" do |s|
+ s.write "plugins.rb"
+ end
+
+ path = lib_path("ga-plugin-1.0").relative_path_from(bundled_app)
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ plugin 'ga-plugin', :path => "#{path}"
+ G
+
+ expect(out).to include("Installed plugin ga-plugin")
+ plugin_should_be_installed("ga-plugin")
+ end
+
context "in deployment mode" do
it "installs plugins" do
install_gemfile <<-G
@@ -271,7 +369,7 @@ RSpec.describe "bundler plugin install" do
end
RUBY
- ruby code, :env => { "BUNDLER_VERSION" => Bundler::VERSION }
+ ruby code, env: { "BUNDLER_VERSION" => Bundler::VERSION }
expect(local_plugin_gem("foo-1.0", "plugins.rb")).to exist
end
end
@@ -321,7 +419,7 @@ RSpec.describe "bundler plugin install" do
end
# outside the app
- bundle "plugin install fubar --source #{file_uri_for(gem_repo2)}", :dir => tmp
+ bundle "plugin install fubar --source #{file_uri_for(gem_repo2)}", dir: tmp
end
it "inside the app takes precedence over global plugin" do
@@ -330,7 +428,7 @@ RSpec.describe "bundler plugin install" do
end
it "outside the app global plugin is used" do
- bundle "shout", :dir => tmp
+ bundle "shout", dir: tmp
expect(out).to eq("global_one")
end
end
diff --git a/spec/bundler/plugins/source/example_spec.rb b/spec/bundler/plugins/source/example_spec.rb
index e2bab9c199..e569f3e415 100644
--- a/spec/bundler/plugins/source/example_spec.rb
+++ b/spec/bundler/plugins/source/example_spec.rb
@@ -70,7 +70,11 @@ RSpec.describe "real source plugins" do
it "writes to lock file" do
bundle "install"
- lockfile_should_be <<-G
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "a-path-gem", "1.0"
+ end
+
+ expect(lockfile).to eq <<~G
PLUGIN SOURCE
remote: #{lib_path("a-path-gem-1.0")}
type: mpath
@@ -86,7 +90,7 @@ RSpec.describe "real source plugins" do
DEPENDENCIES
a-path-gem!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -203,7 +207,7 @@ RSpec.describe "real source plugins" do
def initialize(opts)
super
- @ref = options["ref"] || options["branch"] || options["tag"] || "master"
+ @ref = options["ref"] || options["branch"] || options["tag"] || "main"
@unlocked = false
end
@@ -247,7 +251,7 @@ RSpec.describe "real source plugins" do
def options_to_lock
opts = {"revision" => revision}
- opts["ref"] = ref if ref != "master"
+ opts["ref"] = ref if ref != "main"
opts
end
@@ -304,13 +308,7 @@ RSpec.describe "real source plugins" do
@install_path ||= begin
git_scope = "\#{base_name}-\#{shortref_for_path(revision)}"
- path = gem_install_dir.join(git_scope)
-
- if !path.exist? && requires_sudo?
- user_bundle_path.join(ruby_scope).join(git_scope)
- else
- path
- end
+ gem_install_dir.join(git_scope)
end
end
@@ -342,7 +340,11 @@ RSpec.describe "real source plugins" do
revision = revision_for(lib_path("ma-gitp-gem-1.0"))
bundle "install"
- lockfile_should_be <<-G
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "ma-gitp-gem", "1.0"
+ end
+
+ expect(lockfile).to eq <<~G
PLUGIN SOURCE
remote: #{file_uri_for(lib_path("ma-gitp-gem-1.0"))}
type: gitp
@@ -359,7 +361,7 @@ RSpec.describe "real source plugins" do
DEPENDENCIES
ma-gitp-gem!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -419,7 +421,7 @@ RSpec.describe "real source plugins" do
end
it "updates the deps on change in gemfile" do
- update_git "ma-gitp-gem", "1.1", :path => lib_path("ma-gitp-gem-1.0"), :gemspec => true
+ update_git "ma-gitp-gem", "1.1", path: lib_path("ma-gitp-gem-1.0"), gemspec: true
gemfile <<-G
source "#{file_uri_for(gem_repo2)}" # plugin source
source "#{file_uri_for(lib_path("ma-gitp-gem-1.0"))}", :type => :gitp do
@@ -435,7 +437,7 @@ RSpec.describe "real source plugins" do
describe "bundle cache with gitp" do
it "copies repository to vendor cache and uses it" do
git = build_git "foo"
- ref = git.ref_for("master", 11)
+ ref = git.ref_for("main", 11)
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}" # plugin source
diff --git a/spec/bundler/plugins/uninstall_spec.rb b/spec/bundler/plugins/uninstall_spec.rb
index 8180241911..555c6a7002 100644
--- a/spec/bundler/plugins/uninstall_spec.rb
+++ b/spec/bundler/plugins/uninstall_spec.rb
@@ -30,6 +30,31 @@ RSpec.describe "bundler plugin uninstall" do
plugin_should_not_be_installed("foo")
end
+ it "doesn't wipe out path plugins" do
+ build_lib "path_plugin" do |s|
+ s.write "plugins.rb"
+ end
+ path = lib_path("path_plugin-1.0")
+ expect(path).to be_a_directory
+
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
+
+ install_gemfile <<-G
+ source '#{file_uri_for(gem_repo2)}'
+ plugin 'path_plugin', :path => "#{path}"
+ gem 'rack', '1.0.0'
+ G
+
+ plugin_should_be_installed("path_plugin")
+ expect(Bundler::Plugin.index.plugin_path("path_plugin")).to eq path
+
+ bundle "plugin uninstall path_plugin"
+ expect(out).to include("Uninstalled plugin path_plugin")
+ plugin_should_not_be_installed("path_plugin")
+ # the actual gem still exists though
+ expect(path).to be_a_directory
+ end
+
describe "with --all" do
it "uninstalls all installed plugins" do
bundle "plugin install foo kung-foo --source #{file_uri_for(gem_repo2)}"
diff --git a/spec/bundler/quality_es_spec.rb b/spec/bundler/quality_es_spec.rb
index 90968e6270..0dbd77e451 100644
--- a/spec/bundler/quality_es_spec.rb
+++ b/spec/bundler/quality_es_spec.rb
@@ -41,7 +41,7 @@ RSpec.describe "La biblioteca si misma" do
included = /ronn/
error_messages = []
man_tracked_files.each do |filename|
- next unless filename =~ included
+ next unless filename&.match?(included)
error_messages << check_for_expendable_words(filename)
error_messages << check_for_specific_pronouns(filename)
end
@@ -52,7 +52,7 @@ RSpec.describe "La biblioteca si misma" do
error_messages = []
exempt = /vendor/
lib_tracked_files.each do |filename|
- next if filename =~ exempt
+ next if filename&.match?(exempt)
error_messages << check_for_expendable_words(filename)
error_messages << check_for_specific_pronouns(filename)
end
diff --git a/spec/bundler/quality_spec.rb b/spec/bundler/quality_spec.rb
index 08ec8bed5c..7cdb993017 100644
--- a/spec/bundler/quality_spec.rb
+++ b/spec/bundler/quality_spec.rb
@@ -3,25 +3,6 @@
require "set"
RSpec.describe "The library itself" do
- def check_for_debugging_mechanisms(filename)
- debugging_mechanisms_regex = /
- (binding\.pry)|
- (debugger)|
- (sleep\s*\(?\d+)|
- (fit\s*\(?("|\w))
- /x
-
- failing_lines = []
- each_line(filename) do |line, number|
- if line =~ debugging_mechanisms_regex && !line.end_with?("# ignore quality_spec\n")
- failing_lines << number + 1
- end
- end
-
- return if failing_lines.empty?
- "#{filename} has debugging mechanisms (like binding.pry, sleep, debugger, rspec focusing, etc.) on lines #{failing_lines.join(", ")}"
- end
-
def check_for_git_merge_conflicts(filename)
merge_conflicts_regex = /
<<<<<<<|
@@ -31,7 +12,7 @@ RSpec.describe "The library itself" do
failing_lines = []
each_line(filename) do |line, number|
- failing_lines << number + 1 if line =~ merge_conflicts_regex
+ failing_lines << number + 1 if line&.match?(merge_conflicts_regex)
end
return if failing_lines.empty?
@@ -41,7 +22,7 @@ RSpec.describe "The library itself" do
def check_for_tab_characters(filename)
failing_lines = []
each_line(filename) do |line, number|
- failing_lines << number + 1 if line =~ /\t/
+ failing_lines << number + 1 if line.include?("\t")
end
return if failing_lines.empty?
@@ -51,24 +32,22 @@ RSpec.describe "The library itself" do
def check_for_extra_spaces(filename)
failing_lines = []
each_line(filename) do |line, number|
- next if line =~ /^\s+#.*\s+\n$/
- failing_lines << number + 1 if line =~ /\s+\n$/
+ next if /^\s+#.*\s+\n$/.match?(line)
+ failing_lines << number + 1 if /\s+\n$/.match?(line)
end
return if failing_lines.empty?
"#{filename} has spaces on the EOL on lines #{failing_lines.join(", ")}"
end
- def check_for_straneous_quotes(filename)
- return if File.expand_path(filename) == __FILE__
-
+ def check_for_extraneous_quotes(filename)
failing_lines = []
each_line(filename) do |line, number|
- failing_lines << number + 1 if line =~ /’/
+ failing_lines << number + 1 if /\u{2019}/.match?(line)
end
return if failing_lines.empty?
- "#{filename} has an straneous quote on lines #{failing_lines.join(", ")}"
+ "#{filename} has an extraneous quote on lines #{failing_lines.join(", ")}"
end
def check_for_expendable_words(filename)
@@ -108,29 +87,19 @@ RSpec.describe "The library itself" do
exempt = /\.gitmodules|fixtures|vendor|LICENSE|vcr_cassettes|rbreadline\.diff|index\.txt$/
error_messages = []
tracked_files.each do |filename|
- next if filename =~ exempt
+ next if filename&.match?(exempt)
error_messages << check_for_tab_characters(filename)
error_messages << check_for_extra_spaces(filename)
end
expect(error_messages.compact).to be_well_formed
end
- it "has no estraneous quotes" do
+ it "has no extraneous quotes" do
exempt = /vendor|vcr_cassettes|LICENSE|rbreadline\.diff/
error_messages = []
tracked_files.each do |filename|
- next if filename =~ exempt
- error_messages << check_for_straneous_quotes(filename)
- end
- expect(error_messages.compact).to be_well_formed
- end
-
- it "does not include any leftover debugging or development mechanisms" do
- exempt = %r{quality_spec.rb|support/helpers|vcr_cassettes|\.md|\.ronn|index\.txt|\.5|\.1}
- error_messages = []
- tracked_files.each do |filename|
- next if filename =~ exempt
- error_messages << check_for_debugging_mechanisms(filename)
+ next if filename&.match?(exempt)
+ error_messages << check_for_extraneous_quotes(filename)
end
expect(error_messages.compact).to be_well_formed
end
@@ -139,7 +108,7 @@ RSpec.describe "The library itself" do
error_messages = []
exempt = %r{lock/lockfile_spec|quality_spec|vcr_cassettes|\.ronn|lockfile_parser\.rb}
tracked_files.each do |filename|
- next if filename =~ exempt
+ next if filename&.match?(exempt)
error_messages << check_for_git_merge_conflicts(filename)
end
expect(error_messages.compact).to be_well_formed
@@ -149,7 +118,7 @@ RSpec.describe "The library itself" do
included = /ronn/
error_messages = []
man_tracked_files.each do |filename|
- next unless filename =~ included
+ next unless filename&.match?(included)
error_messages << check_for_expendable_words(filename)
error_messages << check_for_specific_pronouns(filename)
end
@@ -160,7 +129,7 @@ RSpec.describe "The library itself" do
error_messages = []
exempt = /vendor|vcr_cassettes|CODE_OF_CONDUCT/
lib_tracked_files.each do |filename|
- next if filename =~ exempt
+ next if filename&.match?(exempt)
error_messages << check_for_expendable_words(filename)
error_messages << check_for_specific_pronouns(filename)
end
@@ -180,7 +149,6 @@ RSpec.describe "The library itself" do
git.allow_insecure
inline
trust-policy
- use_gem_version_promoter_for_major_updates
]
all_settings = Hash.new {|h, k| h[k] = [] }
@@ -223,11 +191,12 @@ 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 libexec/bundle*" : "lib exe CHANGELOG.md LICENSE.md README.md bundler.gemspec")
+ git_list = tracked_files.reject {|f| f.start_with?("spec/") }
gem_list = loaded_gemspec.files
+ gem_list.map! {|f| f.sub(%r{\Aexe/}, "libexec/") } if ruby_core?
- expect(git_list.sort).to eq(gem_list.sort)
+ expect(git_list).to match_array(gem_list)
end
it "does not contain any warnings" do
@@ -236,7 +205,6 @@ RSpec.describe "The library itself" do
lib/bundler/deployment.rb
lib/bundler/gem_tasks.rb
lib/bundler/vlad.rb
- lib/bundler/templates/gems.rb
]
files_to_require = lib_tracked_files.grep(/\.rb$/) - exclusions
files_to_require.reject! {|f| f.start_with?("lib/bundler/vendor") }
@@ -259,7 +227,7 @@ RSpec.describe "The library itself" do
exempt = %r{templates/|\.5|\.1|vendor/}
all_bad_requires = []
lib_tracked_files.each do |filename|
- next if filename =~ exempt
+ next if filename&.match?(exempt)
each_line(filename) do |line, number|
line.scan(/^ *require "bundler/).each { all_bad_requires << "#{filename}:#{number.succ}" }
end
@@ -271,6 +239,6 @@ RSpec.describe "The library itself" do
private
def each_line(filename, &block)
- File.readlines(filename, :encoding => "UTF-8").each_with_index(&block)
+ File.readlines(filename, encoding: "UTF-8").each_with_index(&block)
end
end
diff --git a/spec/bundler/realworld/dependency_api_spec.rb b/spec/bundler/realworld/dependency_api_spec.rb
index 08c6acf190..ee5c0e3d0a 100644
--- a/spec/bundler/realworld/dependency_api_spec.rb
+++ b/spec/bundler/realworld/dependency_api_spec.rb
@@ -2,7 +2,7 @@
require_relative "../support/silent_logger"
-RSpec.describe "gemcutter's dependency API", :realworld => true do
+RSpec.describe "gemcutter's dependency API", realworld: true do
context "when Gemcutter API takes too long to respond" do
before do
require_rack
@@ -13,12 +13,12 @@ RSpec.describe "gemcutter's dependency API", :realworld => true do
require_relative "../support/artifice/endpoint_timeout"
@t = Thread.new do
- server = Rack::Server.start(:app => EndpointTimeout,
- :Host => "0.0.0.0",
- :Port => port,
- :server => "webrick",
- :AccessLog => [],
- :Logger => Spec::SilentLogger.new)
+ server = Rack::Server.start(app: EndpointTimeout,
+ Host: "0.0.0.0",
+ Port: port,
+ server: "webrick",
+ AccessLog: [],
+ Logger: Spec::SilentLogger.new)
server.start
end
@t.run
@@ -34,7 +34,7 @@ RSpec.describe "gemcutter's dependency API", :realworld => true do
end
it "times out and falls back on the modern index" do
- install_gemfile <<-G, :artifice => nil
+ install_gemfile <<-G, artifice: nil
source "#{@server_uri}"
gem "rack"
G
diff --git a/spec/bundler/realworld/double_check_spec.rb b/spec/bundler/realworld/double_check_spec.rb
index d7f28d10bb..0741560395 100644
--- a/spec/bundler/realworld/double_check_spec.rb
+++ b/spec/bundler/realworld/double_check_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe "double checking sources", :realworld => true do
+RSpec.describe "double checking sources", realworld: true do
it "finds already-installed gems" do
create_file("rails.gemspec", <<-RUBY)
Gem::Specification.new do |s|
@@ -25,9 +25,9 @@ RSpec.describe "double checking sources", :realworld => true do
RUBY
cmd = <<-RUBY
- require "#{entrypoint}"
+ require "bundler"
require "#{spec_dir}/support/artifice/vcr"
- require "#{entrypoint}/inline"
+ require "bundler/inline"
gemfile(true) do
source "https://rubygems.org"
gem "rails", path: "."
diff --git a/spec/bundler/realworld/edgecases_spec.rb b/spec/bundler/realworld/edgecases_spec.rb
index f031e2f354..94ca3554b1 100644
--- a/spec/bundler/realworld/edgecases_spec.rb
+++ b/spec/bundler/realworld/edgecases_spec.rb
@@ -1,17 +1,19 @@
# frozen_string_literal: true
-RSpec.describe "real world edgecases", :realworld => true do
+RSpec.describe "real world edgecases", realworld: true do
def rubygems_version(name, requirement)
ruby <<-RUBY
require "#{spec_dir}/support/artifice/vcr"
- require "#{entrypoint}"
- require "#{entrypoint}/source/rubygems/remote"
- require "#{entrypoint}/fetcher"
+ require "bundler"
+ require "bundler/source/rubygems/remote"
+ require "bundler/fetcher"
rubygem = Bundler.ui.silence do
- source = Bundler::Source::Rubygems::Remote.new(Bundler::URI("https://rubygems.org"))
- fetcher = Bundler::Fetcher.new(source)
- index = fetcher.specs([#{name.dump}], nil)
- index.search(Gem::Dependency.new(#{name.dump}, #{requirement.dump})).last
+ remote = Bundler::Source::Rubygems::Remote.new(Gem::URI("https://rubygems.org"))
+ source = Bundler::Source::Rubygems.new
+ fetcher = Bundler::Fetcher.new(remote)
+ index = fetcher.specs([#{name.dump}], source)
+ requirement = Gem::Requirement.create(#{requirement.dump})
+ index.search(#{name.dump}).select {|spec| requirement.satisfied_by?(spec.version) }.last
end
if rubygem.nil?
raise "Could not find #{name} (#{requirement}) on rubygems.org!\n" \
@@ -64,7 +66,7 @@ RSpec.describe "real world edgecases", :realworld => true do
it "is able to update a top-level dependency when there is a conflict on a shared transitive child" do
# from https://github.com/rubygems/bundler/issues/5031
- system_gems "bundler-2.99.0"
+ pristine_system_gems "bundler-1.99.0"
gemfile <<-G
source "https://rubygems.org"
@@ -154,7 +156,7 @@ RSpec.describe "real world edgecases", :realworld => true do
activemodel (= 4.2.7.1)
activerecord (= 4.2.7.1)
activesupport (= 4.2.7.1)
- bundler (>= 1.3.0, < 3.0)
+ bundler (>= 1.3.0, < 2.0)
railties (= 4.2.7.1)
sprockets-rails
rails-deprecated_sanitizer (1.0.3)
@@ -191,336 +193,191 @@ RSpec.describe "real world edgecases", :realworld => true do
rails (~> 4.2.7.1)
L
- bundle "lock --update paperclip", :env => { "BUNDLER_VERSION" => "2.99.0" }
+ bundle "lock --update paperclip", env: { "BUNDLER_VERSION" => "1.99.0" }
expect(lockfile).to include(rubygems_version("paperclip", "~> 5.1.0"))
end
- it "outputs a helpful error message when gems have invalid gemspecs" do
- install_gemfile <<-G, :standalone => true, :raise_on_error => false
+ it "outputs a helpful error message when gems have invalid gemspecs", rubygems: "< 3.3.16" do
+ install_gemfile <<-G, standalone: true, raise_on_error: false, env: { "BUNDLE_FORCE_RUBY_PLATFORM" => "1" }
source 'https://rubygems.org'
gem "resque-scheduler", "2.2.0"
gem "redis-namespace", "1.6.0" # for a consistent resolution including ruby 2.3.0
+ gem "ruby2_keywords", "0.0.5"
G
expect(err).to include("You have one or more invalid gemspecs that need to be fixed.")
expect(err).to include("resque-scheduler 2.2.0 has an invalid gemspec")
end
- it "doesn't hang on big gemfile" do
- skip "Only for ruby 2.7.3" if RUBY_VERSION != "2.7.3" || RUBY_PLATFORM =~ /darwin/
-
- gemfile <<~G
- # frozen_string_literal: true
-
- source "https://rubygems.org"
-
- ruby "2.7.3"
-
- gem "rails"
- gem "pg", ">= 0.18", "< 2.0"
- gem "goldiloader"
- gem "awesome_nested_set"
- gem "circuitbox"
- gem "passenger"
- gem "globalid"
- gem "rack-cors"
- gem "rails-pg-extras"
- gem "linear_regression_trend"
- gem "rack-protection"
- gem "pundit"
- gem "remote_ip_proxy_scrubber"
- gem "bcrypt"
- gem "searchkick"
- gem "excon"
- gem "faraday_middleware-aws-sigv4"
- gem "typhoeus"
- gem "sidekiq"
- gem "sidekiq-undertaker"
- gem "sidekiq-cron"
- gem "storext"
- gem "appsignal"
- gem "fcm"
- gem "business_time"
- gem "tzinfo"
- gem "holidays"
- gem "bigdecimal"
- gem "progress_bar"
- gem "redis"
- gem "hiredis"
- gem "state_machines"
- gem "state_machines-audit_trail"
- gem "state_machines-activerecord"
- gem "interactor"
- gem "ar_transaction_changes"
- gem "redis-rails"
- gem "seed_migration"
- gem "lograge"
- gem "graphiql-rails", group: :development
- gem "graphql"
- gem "pusher"
- gem "rbnacl"
- gem "jwt"
- gem "json-schema"
- gem "discard"
- gem "money"
- gem "strip_attributes"
- gem "validates_email_format_of"
- gem "audited"
- gem "concurrent-ruby"
- gem "with_advisory_lock"
-
- group :test do
- gem "rspec-sidekiq"
- gem "simplecov", require: false
- end
-
- group :development, :test do
- gem "byebug", platform: :mri
- gem "guard"
- gem "guard-bundler"
- gem "guard-rspec"
- gem "rb-fsevent"
- gem "rspec_junit_formatter"
- gem "rspec-collection_matchers"
- gem "rspec-rails"
- gem "rspec-retry"
- gem "state_machines-rspec"
- gem "dotenv-rails"
- gem "database_cleaner-active_record"
- gem "database_cleaner-redis"
- gem "timecop"
- end
-
- gem "factory_bot_rails"
- gem "faker"
-
- group :development do
- gem "listen"
- gem "sql_queries_count"
- gem "rubocop"
- gem "rubocop-performance"
- gem "rubocop-rspec"
- gem "rubocop-rails"
- gem "brakeman"
- gem "bundler-audit"
- gem "solargraph"
- gem "annotate"
- end
- G
-
- if Bundler.feature_flag.bundler_3_mode?
- # Conflicts on bundler version, so fails earlier
- bundle :lock, :env => { "DEBUG_RESOLVER" => "1" }, :raise_on_error => false
- expect(out).to display_total_steps_of(435)
- else
- bundle :lock, :env => { "DEBUG_RESOLVER" => "1" }
- expect(out).to display_total_steps_of(1025)
- end
- end
-
- it "doesn't hang on tricky gemfile" do
- skip "Only for ruby 2.7.3" if RUBY_VERSION != "2.7.3" || RUBY_PLATFORM =~ /darwin/
-
- gemfile <<~G
+ it "outputs a helpful warning when gems have a gemspec with invalid `require_paths`", rubygems: ">= 3.3.16" do
+ install_gemfile <<-G, standalone: true, env: { "BUNDLE_FORCE_RUBY_PLATFORM" => "1" }
source 'https://rubygems.org'
-
- group :development do
- gem "puppet-module-posix-default-r2.7", '~> 0.3'
- gem "puppet-module-posix-dev-r2.7", '~> 0.3'
- gem "beaker-rspec"
- gem "beaker-puppet"
- gem "beaker-docker"
- gem "beaker-puppet_install_helper"
- gem "beaker-module_install_helper"
- end
+ gem "resque-scheduler", "2.2.0"
+ gem "redis-namespace", "1.6.0" # for a consistent resolution including ruby 2.3.0
+ gem "ruby2_keywords", "0.0.5"
G
-
- bundle :lock, :env => { "DEBUG_RESOLVER" => "1" }
-
- if Bundler.feature_flag.bundler_3_mode?
- expect(out).to display_total_steps_of(890)
- else
- expect(out).to display_total_steps_of(891)
- end
+ expect(err).to include("resque-scheduler 2.2.0 includes a gemspec with `require_paths` set to an array of arrays. Newer versions of this gem might've already fixed this").once
end
it "doesn't hang on nix gemfile" do
- skip "Only for ruby 3.0.1" if RUBY_VERSION != "3.0.1" || RUBY_PLATFORM =~ /darwin/
+ skip "Only for ruby 3.0" unless RUBY_VERSION.start_with?("3.0")
gemfile <<~G
- source "https://rubygems.org" do
- gem "addressable"
- gem "atk"
- gem "awesome_print"
- gem "bacon"
- gem "byebug"
- gem "cairo"
- gem "cairo-gobject"
- gem "camping"
- gem "charlock_holmes"
- gem "cld3"
- gem "cocoapods"
- gem "cocoapods-acknowledgements"
- gem "cocoapods-art"
- gem "cocoapods-bin"
- gem "cocoapods-browser"
- gem "cocoapods-bugsnag"
- gem "cocoapods-check"
- gem "cocoapods-clean"
- gem "cocoapods-clean_build_phases_scripts"
- gem "cocoapods-core"
- gem "cocoapods-coverage"
- gem "cocoapods-deintegrate"
- gem "cocoapods-dependencies"
- gem "cocoapods-deploy"
- gem "cocoapods-downloader"
- gem "cocoapods-expert-difficulty"
- gem "cocoapods-fix-react-native"
- gem "cocoapods-generate"
- gem "cocoapods-git_url_rewriter"
- gem "cocoapods-keys"
- gem "cocoapods-no-dev-schemes"
- gem "cocoapods-open"
- gem "cocoapods-packager"
- gem "cocoapods-playgrounds"
- gem "cocoapods-plugins"
- gem "cocoapods-prune-localizations"
- gem "cocoapods-rome"
- gem "cocoapods-search"
- gem "cocoapods-sorted-search"
- gem "cocoapods-static-swift-framework"
- gem "cocoapods-stats"
- gem "cocoapods-tdfire-binary"
- gem "cocoapods-testing"
- gem "cocoapods-trunk"
- gem "cocoapods-try"
- gem "cocoapods-try-release-fix"
- gem "cocoapods-update-if-you-dare"
- gem "cocoapods-whitelist"
- gem "cocoapods-wholemodule"
- gem "coderay"
- gem "concurrent-ruby"
- gem "curb"
- gem "curses"
- gem "daemons"
- gem "dep-selector-libgecode"
- gem "digest-sha3"
- gem "domain_name"
- gem "do_sqlite3"
- gem "ethon"
- gem "eventmachine"
- gem "excon"
- gem "faraday"
- gem "ffi"
- gem "ffi-rzmq-core"
- gem "fog-dnsimple"
- gem "gdk_pixbuf2"
- gem "gio2"
- gem "gitlab-markup"
- gem "glib2"
- gem "gpgme"
- gem "gtk2"
- gem "hashie"
- gem "highline"
- gem "hike"
- gem "hitimes"
- gem "hpricot"
- gem "httpclient"
- gem "http-cookie"
- gem "iconv"
- gem "idn-ruby"
- gem "jbuilder"
- gem "jekyll"
- gem "jmespath"
- gem "jwt"
- gem "libv8"
- gem "libxml-ruby"
- gem "magic"
- gem "markaby"
- gem "method_source"
- gem "mini_magick"
- gem "msgpack"
- gem "mysql2"
- gem "ncursesw"
- gem "netrc"
- gem "net-scp"
- gem "net-ssh"
- gem "nokogiri"
- gem "opus-ruby"
- gem "ovirt-engine-sdk"
- gem "pango"
- gem "patron"
- gem "pcaprub"
- gem "pg"
- gem "pry"
- gem "pry-byebug"
- gem "pry-doc"
- gem "public_suffix"
- gem "puma"
- gem "rails"
- gem "rainbow"
- gem "rbnacl"
- gem "rb-readline"
- gem "re2"
- gem "redis"
- gem "redis-rack"
- gem "rest-client"
- gem "rmagick"
- gem "rpam2"
- gem "rspec"
- gem "rubocop"
- gem "rubocop-performance"
- gem "ruby-libvirt"
- gem "ruby-lxc"
- gem "ruby-progressbar"
- gem "ruby-terminfo"
- gem "ruby-vips"
- gem "rubyzip"
- gem "rugged"
- gem "sassc"
- gem "scrypt"
- gem "semian"
- gem "sequel"
- gem "sequel_pg"
- gem "simplecov"
- gem "sinatra"
- gem "slop"
- gem "snappy"
- gem "sqlite3"
- gem "taglib-ruby"
- gem "thrift"
- gem "tilt"
- gem "tiny_tds"
- gem "treetop"
- gem "typhoeus"
- gem "tzinfo"
- gem "unf_ext"
- gem "uuid4r"
- gem "whois"
- gem "zookeeper"
- end
- G
-
- bundle :lock, :env => { "DEBUG_RESOLVER" => "1" }
-
- if Bundler.feature_flag.bundler_3_mode?
- expect(out).to display_total_steps_of(1874)
- else
- expect(out).to display_total_steps_of(1922)
- end
- end
-
- private
+ source "https://rubygems.org"
- RSpec::Matchers.define :display_total_steps_of do |expected_steps|
- match do |out|
- out.include?("BUNDLER: Finished resolution (#{expected_steps} steps)")
- end
+ gem "addressable"
+ gem "atk"
+ gem "awesome_print"
+ gem "bacon"
+ gem "byebug"
+ gem "cairo"
+ gem "cairo-gobject"
+ gem "camping"
+ gem "charlock_holmes"
+ gem "cld3"
+ gem "cocoapods"
+ gem "cocoapods-acknowledgements"
+ gem "cocoapods-art"
+ gem "cocoapods-bin"
+ gem "cocoapods-browser"
+ gem "cocoapods-bugsnag"
+ gem "cocoapods-check"
+ gem "cocoapods-clean"
+ gem "cocoapods-clean_build_phases_scripts"
+ gem "cocoapods-core"
+ gem "cocoapods-coverage"
+ gem "cocoapods-deintegrate"
+ gem "cocoapods-dependencies"
+ gem "cocoapods-deploy"
+ gem "cocoapods-downloader"
+ gem "cocoapods-expert-difficulty"
+ gem "cocoapods-fix-react-native"
+ gem "cocoapods-generate"
+ gem "cocoapods-git_url_rewriter"
+ gem "cocoapods-keys"
+ gem "cocoapods-no-dev-schemes"
+ gem "cocoapods-open"
+ gem "cocoapods-packager"
+ gem "cocoapods-playgrounds"
+ gem "cocoapods-plugins"
+ gem "cocoapods-prune-localizations"
+ gem "cocoapods-rome"
+ gem "cocoapods-search"
+ gem "cocoapods-sorted-search"
+ gem "cocoapods-static-swift-framework"
+ gem "cocoapods-stats"
+ gem "cocoapods-tdfire-binary"
+ gem "cocoapods-testing"
+ gem "cocoapods-trunk"
+ gem "cocoapods-try"
+ gem "cocoapods-try-release-fix"
+ gem "cocoapods-update-if-you-dare"
+ gem "cocoapods-whitelist"
+ gem "cocoapods-wholemodule"
+ gem "coderay"
+ gem "concurrent-ruby"
+ gem "curb"
+ gem "curses"
+ gem "daemons"
+ gem "dep-selector-libgecode"
+ gem "digest-sha3"
+ gem "domain_name"
+ gem "do_sqlite3"
+ gem "ethon"
+ gem "eventmachine"
+ gem "excon"
+ gem "faraday"
+ gem "ffi"
+ gem "ffi-rzmq-core"
+ gem "fog-dnsimple"
+ gem "gdk_pixbuf2"
+ gem "gio2"
+ gem "gitlab-markup"
+ gem "glib2"
+ gem "gpgme"
+ gem "gtk2"
+ gem "hashie"
+ gem "highline"
+ gem "hike"
+ gem "hitimes"
+ gem "hpricot"
+ gem "httpclient"
+ gem "http-cookie"
+ gem "iconv"
+ gem "idn-ruby"
+ gem "jbuilder"
+ gem "jekyll"
+ gem "jmespath"
+ gem "jwt"
+ gem "libv8"
+ gem "libxml-ruby"
+ gem "magic"
+ gem "markaby"
+ gem "method_source"
+ gem "mini_magick"
+ gem "msgpack"
+ gem "mysql2"
+ gem "ncursesw"
+ gem "netrc"
+ gem "net-scp"
+ gem "net-ssh"
+ gem "nokogiri"
+ gem "opus-ruby"
+ gem "ovirt-engine-sdk"
+ gem "pango"
+ gem "patron"
+ gem "pcaprub"
+ gem "pg"
+ gem "pry"
+ gem "pry-byebug"
+ gem "pry-doc"
+ gem "public_suffix"
+ gem "puma"
+ gem "rails"
+ gem "rainbow"
+ gem "rbnacl"
+ gem "rb-readline"
+ gem "re2"
+ gem "redis"
+ gem "redis-rack"
+ gem "rest-client"
+ gem "rmagick"
+ gem "rpam2"
+ gem "rspec"
+ gem "rubocop"
+ gem "rubocop-performance"
+ gem "ruby-libvirt"
+ gem "ruby-lxc"
+ gem "ruby-progressbar"
+ gem "ruby-terminfo"
+ gem "ruby-vips"
+ gem "rubyzip"
+ gem "rugged"
+ gem "sassc"
+ gem "scrypt"
+ gem "semian"
+ gem "sequel"
+ gem "sequel_pg"
+ gem "simplecov"
+ gem "sinatra"
+ gem "slop"
+ gem "snappy"
+ gem "sqlite3"
+ gem "taglib-ruby"
+ gem "thrift"
+ gem "tilt"
+ gem "tiny_tds"
+ gem "treetop"
+ gem "typhoeus"
+ gem "tzinfo"
+ gem "unf_ext"
+ gem "uuid4r"
+ gem "whois"
+ gem "zookeeper"
+ G
- failure_message do |out|
- actual_steps = out.scan(/BUNDLER: Finished resolution \((\d+) steps\)/).first.first
+ bundle :lock, env: { "DEBUG_RESOLVER" => "1" }
- "Expected resolution to finish in #{expected_steps} steps, but took #{actual_steps}"
- end
+ expect(out).to include("Solution found after 4 attempts")
end
end
diff --git a/spec/bundler/realworld/ffi_spec.rb b/spec/bundler/realworld/ffi_spec.rb
new file mode 100644
index 0000000000..5f40b43a0f
--- /dev/null
+++ b/spec/bundler/realworld/ffi_spec.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+RSpec.describe "loading dynamically linked library on a bundle exec context", realworld: true do
+ it "passes ENV right after argv in memory" do
+ create_file "foo.rb", <<~RUBY
+ require 'ffi'
+
+ module FOO
+ extend FFI::Library
+ ffi_lib './libfoo.so'
+
+ attach_function :Hello, [], :void
+ end
+
+ FOO.Hello()
+ RUBY
+
+ create_file "libfoo.c", <<~'C'
+ #include <stdio.h>
+
+ static int foo_init(int argc, char** argv, char** envp) {
+ if (argv[argc+1] == NULL) {
+ printf("FAIL\n");
+ } else {
+ printf("OK\n");
+ }
+
+ return 0;
+ }
+
+ #if defined(__APPLE__) && defined(__MACH__)
+ __attribute__((section("__DATA,__mod_init_func"), used, aligned(sizeof(void*))))
+ #else
+ __attribute__((section(".init_array")))
+ #endif
+ static void *ctr = &foo_init;
+
+ extern char** environ;
+
+ void Hello() {
+ return;
+ }
+ C
+
+ sys_exec "gcc -g -o libfoo.so -shared -fpic libfoo.c"
+
+ install_gemfile <<-G
+ source "https://rubygems.org"
+
+ gem 'ffi'
+ G
+
+ bundle "exec ruby foo.rb"
+
+ expect(out).to eq("OK")
+ end
+end
diff --git a/spec/bundler/realworld/fixtures/warbler/Gemfile b/spec/bundler/realworld/fixtures/warbler/Gemfile
index 4fbf2d05a7..a8dbb4911c 100644
--- a/spec/bundler/realworld/fixtures/warbler/Gemfile
+++ b/spec/bundler/realworld/fixtures/warbler/Gemfile
@@ -2,6 +2,6 @@
source "https://rubygems.org"
-gem "demo", :path => "./demo"
+gem "demo", path: "./demo"
gem "jruby-jars", "~> 9.2"
gem "warbler", "~> 2.0"
diff --git a/spec/bundler/realworld/fixtures/warbler/Gemfile.lock b/spec/bundler/realworld/fixtures/warbler/Gemfile.lock
index 05bcb877db..5b476f8df2 100644
--- a/spec/bundler/realworld/fixtures/warbler/Gemfile.lock
+++ b/spec/bundler/realworld/fixtures/warbler/Gemfile.lock
@@ -27,4 +27,4 @@ DEPENDENCIES
warbler (~> 2.0)
BUNDLED WITH
- 2.3.0.dev
+ 2.5.0.dev
diff --git a/spec/bundler/realworld/gemfile_source_header_spec.rb b/spec/bundler/realworld/gemfile_source_header_spec.rb
index ada2fc92ee..45f5d0fd22 100644
--- a/spec/bundler/realworld/gemfile_source_header_spec.rb
+++ b/spec/bundler/realworld/gemfile_source_header_spec.rb
@@ -2,7 +2,7 @@
require_relative "../support/silent_logger"
-RSpec.describe "fetching dependencies with a mirrored source", :realworld => true do
+RSpec.describe "fetching dependencies with a mirrored source", realworld: true do
let(:mirror) { "https://server.example.org" }
let(:original) { "http://127.0.0.1:#{@port}" }
@@ -17,13 +17,13 @@ RSpec.describe "fetching dependencies with a mirrored source", :realworld => tru
@t.join
end
- it "sets the 'X-Gemfile-Source' header and bundles successfully" do
+ it "sets the 'X-Gemfile-Source' and 'User-Agent' headers and bundles successfully" do
gemfile <<-G
source "#{mirror}"
gem 'weakling'
G
- bundle :install, :artifice => nil
+ bundle :install, artifice: nil
expect(out).to include("Installing weakling")
expect(out).to include("Bundle complete")
@@ -40,12 +40,12 @@ RSpec.describe "fetching dependencies with a mirrored source", :realworld => tru
require_relative "../support/artifice/endpoint_mirror_source"
@t = Thread.new do
- Rack::Server.start(:app => EndpointMirrorSource,
- :Host => "0.0.0.0",
- :Port => @port,
- :server => "webrick",
- :AccessLog => [],
- :Logger => Spec::SilentLogger.new)
+ Rack::Server.start(app: EndpointMirrorSource,
+ Host: "0.0.0.0",
+ Port: @port,
+ server: "webrick",
+ AccessLog: [],
+ Logger: Spec::SilentLogger.new)
end.run
wait_for_server("127.0.0.1", @port)
diff --git a/spec/bundler/realworld/git_spec.rb b/spec/bundler/realworld/git_spec.rb
new file mode 100644
index 0000000000..9eff74f1c9
--- /dev/null
+++ b/spec/bundler/realworld/git_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+RSpec.describe "github source", realworld: true do
+ it "properly fetches PRs" do
+ install_gemfile <<-G
+ source "https://rubygems.org"
+
+ gem "reline", github: "https://github.com/ruby/reline/pull/488"
+ G
+ end
+end
diff --git a/spec/bundler/realworld/mirror_probe_spec.rb b/spec/bundler/realworld/mirror_probe_spec.rb
index a2b5c89150..fc97f92375 100644
--- a/spec/bundler/realworld/mirror_probe_spec.rb
+++ b/spec/bundler/realworld/mirror_probe_spec.rb
@@ -2,7 +2,7 @@
require_relative "../support/silent_logger"
-RSpec.describe "fetching dependencies with a not available mirror", :realworld => true do
+RSpec.describe "fetching dependencies with a not available mirror", realworld: true do
let(:mirror) { @mirror_uri }
let(:original) { @server_uri }
let(:server_port) { @server_port }
@@ -32,7 +32,7 @@ RSpec.describe "fetching dependencies with a not available mirror", :realworld =
gem 'weakling'
G
- bundle :install, :artifice => nil
+ bundle :install, artifice: nil
expect(out).to include("Installing weakling")
expect(out).to include("Bundle complete")
@@ -52,7 +52,7 @@ RSpec.describe "fetching dependencies with a not available mirror", :realworld =
gem 'weakling'
G
- bundle :install, :artifice => nil
+ bundle :install, artifice: nil
expect(out).to include("Installing weakling")
expect(out).to include("Bundle complete")
@@ -71,30 +71,15 @@ RSpec.describe "fetching dependencies with a not available mirror", :realworld =
gem 'weakling'
G
- bundle :install, :artifice => nil, :raise_on_error => false
+ bundle :install, artifice: nil, raise_on_error: false
expect(out).to include("Fetching source index from #{mirror}")
- expect(err).to include("Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>")
- expect(err).to include("Retrying fetcher due to error (3/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>")
- expect(err).to include("Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>")
- expect(err).to include("Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>")
- end
-
- it "prints each error and warning on a new line" do
- gemfile <<-G
- source "#{original}"
- gem 'weakling'
- G
- bundle :install, :artifice => nil, :raise_on_error => false
-
- expect(out).to include "Fetching source index from #{mirror}/"
- expect(err).to include <<-EOS.strip
-Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>
-Retrying fetcher due to error (3/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>
-Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>
-Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>
- EOS
+ err_lines = err.split("\n")
+ expect(err_lines).to include(%r{\ARetrying fetcher due to error \(2/4\): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <})
+ expect(err_lines).to include(%r{\ARetrying fetcher due to error \(3/4\): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <})
+ expect(err_lines).to include(%r{\ARetrying fetcher due to error \(4/4\): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <})
+ expect(err_lines).to include(%r{\ACould not fetch specs from #{mirror}/ due to underlying error <})
end
end
@@ -109,13 +94,15 @@ Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUS
gem 'weakling'
G
- bundle :install, :artifice => nil, :raise_on_error => false
+ bundle :install, artifice: nil, raise_on_error: false
expect(out).to include("Fetching source index from #{mirror}")
- expect(err).to include("Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>")
- expect(err).to include("Retrying fetcher due to error (3/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>")
- expect(err).to include("Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>")
- expect(err).to include("Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUSED: Failed to open TCP connection to #{host}:#{@mirror_port} (Connection refused - connect(2) for \"#{host}\" port #{@mirror_port}) (#{mirror}/specs.4.8.gz)>")
+
+ err_lines = err.split("\n")
+ expect(err_lines).to include(%r{\ARetrying fetcher due to error \(2/4\): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <})
+ expect(err_lines).to include(%r{\ARetrying fetcher due to error \(3/4\): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <})
+ expect(err_lines).to include(%r{\ARetrying fetcher due to error \(4/4\): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error <})
+ expect(err_lines).to include(%r{\ACould not fetch specs from #{mirror}/ due to underlying error <})
end
end
@@ -126,12 +113,12 @@ Could not fetch specs from #{mirror}/ due to underlying error <Errno::ECONNREFUS
require_relative "../support/artifice/endpoint"
@server_thread = Thread.new do
- Rack::Server.start(:app => Endpoint,
- :Host => host,
- :Port => @server_port,
- :server => "webrick",
- :AccessLog => [],
- :Logger => Spec::SilentLogger.new)
+ Rack::Server.start(app: Endpoint,
+ Host: host,
+ Port: @server_port,
+ server: "webrick",
+ AccessLog: [],
+ Logger: Spec::SilentLogger.new)
end.run
wait_for_server(host, @server_port)
diff --git a/spec/bundler/realworld/parallel_spec.rb b/spec/bundler/realworld/parallel_spec.rb
index 97c0e0cab4..b57fdfd0ee 100644
--- a/spec/bundler/realworld/parallel_spec.rb
+++ b/spec/bundler/realworld/parallel_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe "parallel", :realworld => true do
+RSpec.describe "parallel", realworld: true do
it "installs" do
gemfile <<-G
source "https://rubygems.org"
@@ -9,7 +9,7 @@ RSpec.describe "parallel", :realworld => true do
gem 'i18n', '~> 0.6.0' # Because 0.7+ requires Ruby 1.9.3+
G
- bundle :install, :jobs => 4, :env => { "DEBUG" => "1" }
+ bundle :install, jobs: 4, env: { "DEBUG" => "1" }
expect(out).to match(/[1-3]: /)
@@ -34,7 +34,7 @@ RSpec.describe "parallel", :realworld => true do
gem 'i18n', '~> 0.6.0' # Because 0.7+ requires Ruby 1.9.3+
G
- bundle :update, :jobs => 4, :env => { "DEBUG" => "1" }, :all => true
+ bundle :update, jobs: 4, env: { "DEBUG" => "1" }, all: true
expect(out).to match(/[1-3]: /)
@@ -46,12 +46,12 @@ RSpec.describe "parallel", :realworld => true do
end
it "works with --standalone" do
- gemfile <<-G, :standalone => true
+ gemfile <<-G
source "https://rubygems.org"
gem "diff-lcs"
G
- bundle :install, :standalone => true, :jobs => 4
+ bundle :install, standalone: true, jobs: 4
ruby <<-RUBY
$:.unshift File.expand_path("bundle")
diff --git a/spec/bundler/realworld/slow_perf_spec.rb b/spec/bundler/realworld/slow_perf_spec.rb
index aced5a1641..32e266ff1b 100644
--- a/spec/bundler/realworld/slow_perf_spec.rb
+++ b/spec/bundler/realworld/slow_perf_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe "bundle install with complex dependencies", :realworld => true do
+RSpec.describe "bundle install with complex dependencies", realworld: true do
it "resolves quickly" do
gemfile <<-G
source 'https://rubygems.org'
@@ -11,12 +11,134 @@ RSpec.describe "bundle install with complex dependencies", :realworld => true do
gem "mongoid", ">= 0.10.2"
G
- start_time = Time.now
+ bundle "lock", env: { "DEBUG_RESOLVER" => "1" }
+ expect(out).to include("Solution found after 1 attempts")
+ end
+
+ it "resolves quickly (case 2)" do
+ gemfile <<-G
+ source "https://rubygems.org"
+
+ gem 'metasploit-erd'
+ gem 'rails-erd'
+ gem 'yard'
+
+ gem 'coveralls'
+ gem 'rails'
+ gem 'simplecov'
+ gem 'rspec-rails'
+ G
+
+ bundle "lock", env: { "DEBUG_RESOLVER" => "1" }
+ expect(out).to include("Solution found after 1 attempts")
+ end
+
+ it "resolves big gemfile quickly" do
+ gemfile <<~G
+ # frozen_string_literal: true
+
+ source "https://rubygems.org"
+
+ gem "rails"
+ gem "pg", ">= 0.18", "< 2.0"
+ gem "goldiloader"
+ gem "awesome_nested_set"
+ gem "circuitbox"
+ gem "passenger"
+ gem "globalid"
+ gem "rack-cors"
+ gem "rails-pg-extras"
+ gem "linear_regression_trend"
+ gem "rack-protection"
+ gem "pundit"
+ gem "remote_ip_proxy_scrubber"
+ gem "bcrypt"
+ gem "searchkick"
+ gem "excon"
+ gem "faraday_middleware-aws-sigv4"
+ gem "typhoeus"
+ gem "sidekiq"
+ gem "sidekiq-undertaker"
+ gem "sidekiq-cron"
+ gem "storext"
+ gem "appsignal"
+ gem "fcm"
+ gem "business_time"
+ gem "tzinfo"
+ gem "holidays"
+ gem "bigdecimal"
+ gem "progress_bar"
+ gem "redis"
+ gem "hiredis"
+ gem "state_machines"
+ gem "state_machines-audit_trail"
+ gem "state_machines-activerecord"
+ gem "interactor"
+ gem "ar_transaction_changes"
+ gem "redis-rails"
+ gem "seed_migration"
+ gem "lograge"
+ gem "graphiql-rails", group: :development
+ gem "graphql"
+ gem "pusher"
+ gem "rbnacl"
+ gem "jwt"
+ gem "json-schema"
+ gem "discard"
+ gem "money"
+ gem "strip_attributes"
+ gem "validates_email_format_of"
+ gem "audited"
+ gem "concurrent-ruby"
+ gem "with_advisory_lock"
+
+ group :test do
+ gem "rspec-sidekiq"
+ gem "simplecov", require: false
+ end
+
+ group :development, :test do
+ gem "byebug", platform: :mri
+ gem "guard"
+ gem "guard-bundler"
+ gem "guard-rspec"
+ gem "rb-fsevent"
+ gem "rspec_junit_formatter"
+ gem "rspec-collection_matchers"
+ gem "rspec-rails"
+ gem "rspec-retry"
+ gem "state_machines-rspec"
+ gem "dotenv-rails"
+ gem "database_cleaner-active_record"
+ gem "database_cleaner-redis"
+ gem "timecop"
+ end
+
+ gem "factory_bot_rails"
+ gem "faker"
+
+ group :development do
+ gem "listen"
+ gem "sql_queries_count"
+ gem "rubocop"
+ gem "rubocop-performance"
+ gem "rubocop-rspec"
+ gem "rubocop-rails"
+ gem "brakeman"
+ gem "bundler-audit"
+ gem "solargraph"
+ gem "annotate"
+ end
+ G
- bundle "lock"
+ if Bundler.feature_flag.bundler_3_mode?
+ bundle "lock", env: { "DEBUG_RESOLVER" => "1" }, raise_on_error: false
- duration = Time.now - start_time
+ expect(out).to include("backtracking").exactly(26).times
+ else
+ bundle "lock", env: { "DEBUG_RESOLVER" => "1" }
- expect(duration.to_f).to be < 12 # seconds
+ expect(out).to include("Solution found after 10 attempts")
+ end
end
end
diff --git a/spec/bundler/resolver/basic_spec.rb b/spec/bundler/resolver/basic_spec.rb
index ee62dc3577..4a0dd37bf9 100644
--- a/spec/bundler/resolver/basic_spec.rb
+++ b/spec/bundler/resolver/basic_spec.rb
@@ -100,11 +100,20 @@ RSpec.describe "Resolving" do
end
it "raises an exception if a child dependency is not resolved" do
- @index = a_unresovable_child_index
+ @index = a_unresolvable_child_index
dep "chef_app_error"
expect do
resolve
- end.to raise_error(Bundler::VersionConflict)
+ end.to raise_error(Bundler::SolveFailure)
+ end
+
+ it "does not try to re-resolve including prereleases if gems involved don't have prereleases" do
+ @index = a_unresolvable_child_index
+ dep "chef_app_error"
+ expect(Bundler.ui).not_to receive(:debug).with("Retrying resolution...", any_args)
+ expect do
+ resolve
+ end.to raise_error(Bundler::SolveFailure)
end
it "raises an exception with the minimal set of conflicting dependencies" do
@@ -118,14 +127,15 @@ RSpec.describe "Resolving" do
dep "c"
expect do
resolve
- end.to raise_error(Bundler::VersionConflict, <<-E.strip)
-Bundler could not find compatible versions for gem "a":
- In Gemfile:
- b was resolved to 1.0, which depends on
- a (>= 2)
-
- c was resolved to 1.0, which depends on
- a (< 1)
+ end.to raise_error(Bundler::SolveFailure, <<~E.strip)
+ Could not find compatible versions
+
+ Because every version of c depends on a < 1
+ and every version of b depends on a >= 2,
+ every version of c is incompatible with b >= 0.
+ So, because Gemfile depends on b >= 0
+ and Gemfile depends on c >= 0,
+ version solving has failed.
E
end
@@ -134,7 +144,7 @@ Bundler could not find compatible versions for gem "a":
dep "circular_app"
expect do
- resolve
+ Bundler::SpecSet.new(resolve).sort
end.to raise_error(Bundler::CyclicDependencyError, /please remove either gem 'bar' or gem 'foo'/i)
end
@@ -174,12 +184,7 @@ Bundler could not find compatible versions for gem "a":
dep "foo"
dep "Ruby\0", "1.8.7"
- deps = []
- @deps.each do |d|
- deps << Bundler::DepProxy.get_proxy(d, "ruby")
- end
-
- should_resolve_and_include %w[foo-1.0.0 bar-1.0.0], [[]]
+ should_resolve_and_include %w[foo-1.0.0 bar-1.0.0]
end
context "conservative" do
@@ -305,4 +310,73 @@ Bundler could not find compatible versions for gem "a":
end
end
end
+
+ it "handles versions that redundantly depend on themselves" do
+ @index = build_index do
+ gem "rack", "3.0.0"
+
+ gem "standalone_migrations", "7.1.0" do
+ dep "rack", "~> 2.0"
+ end
+
+ gem "standalone_migrations", "2.0.4" do
+ dep "standalone_migrations", ">= 0"
+ end
+
+ gem "standalone_migrations", "1.0.13" do
+ dep "rack", ">= 0"
+ end
+ end
+
+ dep "rack", "~> 3.0"
+ dep "standalone_migrations"
+
+ should_resolve_as %w[rack-3.0.0 standalone_migrations-2.0.4]
+ end
+
+ it "ignores versions that incorrectly depend on themselves" do
+ @index = build_index do
+ gem "rack", "3.0.0"
+
+ gem "standalone_migrations", "7.1.0" do
+ dep "rack", "~> 2.0"
+ end
+
+ gem "standalone_migrations", "2.0.4" do
+ dep "standalone_migrations", ">= 2.0.5"
+ end
+
+ gem "standalone_migrations", "1.0.13" do
+ dep "rack", ">= 0"
+ end
+ end
+
+ dep "rack", "~> 3.0"
+ dep "standalone_migrations"
+
+ should_resolve_as %w[rack-3.0.0 standalone_migrations-1.0.13]
+ end
+
+ it "does not ignore versions that incorrectly depend on themselves when dependency_api is not available" do
+ @index = build_index do
+ gem "rack", "3.0.0"
+
+ gem "standalone_migrations", "7.1.0" do
+ dep "rack", "~> 2.0"
+ end
+
+ gem "standalone_migrations", "2.0.4" do
+ dep "standalone_migrations", ">= 2.0.5"
+ end
+
+ gem "standalone_migrations", "1.0.13" do
+ dep "rack", ">= 0"
+ end
+ end
+
+ dep "rack", "~> 3.0"
+ dep "standalone_migrations"
+
+ should_resolve_without_dependency_api %w[rack-3.0.0 standalone_migrations-2.0.4]
+ end
end
diff --git a/spec/bundler/resolver/platform_spec.rb b/spec/bundler/resolver/platform_spec.rb
index bc4081f8b5..3e959aeb89 100644
--- a/spec/bundler/resolver/platform_spec.rb
+++ b/spec/bundler/resolver/platform_spec.rb
@@ -82,21 +82,105 @@ RSpec.describe "Resolving platform craziness" do
should_resolve_as %w[foo-1.0.0-x64-mingw32]
end
- it "takes the latest ruby gem if the platform specific gem doesn't match the required_ruby_version" do
- @index = build_index do
- gem "foo", "1.0.0"
- gem "foo", "1.0.0", "x64-mingw32"
- gem "foo", "1.1.0"
- gem "foo", "1.1.0", "x64-mingw32" do |s|
- s.required_ruby_version = [">= 2.0", "< 2.4"]
+ describe "on a linux platform" do
+ # Ruby's platform is *-linux => platform's libc is glibc, so not musl
+ # Ruby's platform is *-linux-musl => platform's libc is musl, so not glibc
+ # Gem's platform is *-linux => gem is glibc + maybe musl compatible
+ # Gem's platform is *-linux-musl => gem is musl compatible but not glibc
+
+ it "favors the platform version-specific gem on a version-specifying linux platform" do
+ @index = build_index do
+ gem "foo", "1.0.0"
+ gem "foo", "1.0.0", "x86_64-linux"
+ gem "foo", "1.0.0", "x86_64-linux-musl"
end
- gem "Ruby\0", "2.5.1"
+ dep "foo"
+ platforms "x86_64-linux-musl"
+
+ should_resolve_as %w[foo-1.0.0-x86_64-linux-musl]
end
- dep "foo"
- dep "Ruby\0", "2.5.1"
- platforms "x64-mingw32"
- should_resolve_as %w[foo-1.1.0]
+ it "favors the version-less gem over the version-specific gem on a gnu linux platform" do
+ @index = build_index do
+ gem "foo", "1.0.0"
+ gem "foo", "1.0.0", "x86_64-linux"
+ gem "foo", "1.0.0", "x86_64-linux-musl"
+ end
+ dep "foo"
+ platforms "x86_64-linux"
+
+ should_resolve_as %w[foo-1.0.0-x86_64-linux]
+ end
+
+ it "ignores the platform version-specific gem on a gnu linux platform" do
+ @index = build_index do
+ gem "foo", "1.0.0", "x86_64-linux-musl"
+ end
+ dep "foo"
+ platforms "x86_64-linux"
+
+ should_not_resolve
+ end
+
+ it "falls back to the platform version-less gem on a linux platform with a version" do
+ @index = build_index do
+ gem "foo", "1.0.0"
+ gem "foo", "1.0.0", "x86_64-linux"
+ end
+ dep "foo"
+ platforms "x86_64-linux-musl"
+
+ should_resolve_as %w[foo-1.0.0-x86_64-linux]
+ end
+
+ it "falls back to the ruby platform gem on a gnu linux platform when only a version-specifying gem is available" do
+ @index = build_index do
+ gem "foo", "1.0.0"
+ gem "foo", "1.0.0", "x86_64-linux-musl"
+ end
+ dep "foo"
+ platforms "x86_64-linux"
+
+ should_resolve_as %w[foo-1.0.0]
+ end
+
+ it "falls back to the platform version-less gem on a version-specifying linux platform and no ruby platform gem is available" do
+ @index = build_index do
+ gem "foo", "1.0.0", "x86_64-linux"
+ end
+ dep "foo"
+ platforms "x86_64-linux-musl"
+
+ should_resolve_as %w[foo-1.0.0-x86_64-linux]
+ end
+ end
+
+ context "when the platform specific gem doesn't match the required_ruby_version" do
+ before do
+ @index = build_index do
+ gem "foo", "1.0.0"
+ gem "foo", "1.0.0", "x64-mingw32"
+ gem "foo", "1.1.0"
+ gem "foo", "1.1.0", "x64-mingw32" do |s|
+ s.required_ruby_version = [">= 2.0", "< 2.4"]
+ end
+ gem "Ruby\0", "2.5.1"
+ end
+ dep "Ruby\0", "2.5.1"
+ platforms "x64-mingw32"
+ end
+
+ it "takes the latest ruby gem" do
+ dep "foo"
+
+ should_resolve_as %w[foo-1.1.0]
+ end
+
+ it "takes the latest ruby gem, even if requirement does not match previous versions with the same ruby requirement" do
+ dep "foo", "1.1.0"
+
+ should_resolve_as %w[foo-1.1.0]
+ end
end
it "takes the latest ruby gem with required_ruby_version if the platform specific gem doesn't match the required_ruby_version" do
@@ -137,39 +221,6 @@ RSpec.describe "Resolving platform craziness" do
should_resolve_as %w[foo-1.1.0]
end
- it "doesn't include gems not needed for none of the platforms" do
- @index = build_index do
- gem "empyrean", "0.1.0"
- gem "coderay", "1.1.2"
- gem "method_source", "0.9.0"
-
- gem "spoon", "0.0.6" do
- dep "ffi", ">= 0"
- end
-
- gem "pry", "0.11.3", "java" do
- dep "coderay", "~> 1.1.0"
- dep "method_source", "~> 0.9.0"
- dep "spoon", "~> 0.0"
- end
-
- gem "pry", "0.11.3" do
- dep "coderay", "~> 1.1.0"
- dep "method_source", "~> 0.9.0"
- end
-
- gem "ffi", "1.9.23", "java"
- gem "ffi", "1.9.23"
- end
-
- dep "empyrean", "0.1.0"
- dep "pry"
-
- platforms "ruby", "java"
-
- should_resolve_as %w[coderay-1.1.2 empyrean-0.1.0 ffi-1.9.23-java method_source-0.9.0 pry-0.11.3 pry-0.11.3-java spoon-0.0.6]
- end
-
it "includes gems needed for at least one platform" do
@index = build_index do
gem "empyrean", "0.1.0"
@@ -291,7 +342,7 @@ RSpec.describe "Resolving platform craziness" do
describe "with mingw32" do
before :each do
@index = build_index do
- platforms "mingw32 mswin32 x64-mingw32" do |platform|
+ platforms "mingw32 mswin32 x64-mingw32 x64-mingw-ucrt" do |platform|
gem "thin", "1.2.7", platform
end
gem "win32-api", "1.5.1", "universal-mingw32"
@@ -312,7 +363,7 @@ RSpec.describe "Resolving platform craziness" do
should_resolve_as %w[thin-1.2.7-mingw32]
end
- it "finds x64-mingw gems" do
+ it "finds x64-mingw32 gems" do
platforms "x64-mingw32"
dep "thin"
should_resolve_as %w[thin-1.2.7-x64-mingw32]
@@ -329,6 +380,22 @@ RSpec.describe "Resolving platform craziness" do
dep "win32-api"
should_resolve_as %w[win32-api-1.5.1-universal-mingw32]
end
+
+ if Gem.rubygems_version >= Gem::Version.new("3.2.28")
+ it "finds x64-mingw-ucrt gems" do
+ platforms "x64-mingw-ucrt"
+ dep "thin"
+ should_resolve_as %w[thin-1.2.7-x64-mingw-ucrt]
+ end
+ end
+
+ if Gem.rubygems_version >= Gem::Version.new("3.3.18")
+ it "finds universal-mingw gems on x64-mingw-ucrt" do
+ platform "x64-mingw-ucrt"
+ dep "win32-api"
+ should_resolve_as %w[win32-api-1.5.1-universal-mingw32]
+ end
+ end
end
describe "with conflicting cases" do
diff --git a/spec/bundler/runtime/executable_spec.rb b/spec/bundler/runtime/executable_spec.rb
index a11f547648..36ce6dcf67 100644
--- a/spec/bundler/runtime/executable_spec.rb
+++ b/spec/bundler/runtime/executable_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe "Running bin/* commands" do
it "runs the bundled command when in the bundle" do
bundle "binstubs rack"
- build_gem "rack", "2.0", :to_system => true do |s|
+ build_gem "rack", "2.0", to_system: true do |s|
s.executables = "rackup"
end
@@ -20,7 +20,7 @@ RSpec.describe "Running bin/* commands" do
end
it "allows the location of the gem stubs to be specified" do
- bundle "binstubs rack", :path => "gbin"
+ bundle "binstubs rack", path: "gbin"
expect(bundled_app("bin")).not_to exist
expect(bundled_app("gbin/rackup")).to exist
@@ -30,7 +30,7 @@ RSpec.describe "Running bin/* commands" do
end
it "allows absolute paths as a specification of where to install bin stubs" do
- bundle "binstubs rack", :path => tmp("bin")
+ bundle "binstubs rack", path: tmp("bin")
gembin tmp("bin/rackup")
expect(out).to eq("1.0.0")
@@ -42,23 +42,23 @@ RSpec.describe "Running bin/* commands" do
end
it "allows the name of the shebang executable to be specified" do
- bundle "binstubs rack", :shebang => "ruby-foo"
+ bundle "binstubs rack", shebang: "ruby-foo"
expect(File.readlines(bundled_app("bin/rackup")).first).to eq("#!/usr/bin/env ruby-foo\n")
end
it "runs the bundled command when out of the bundle" do
bundle "binstubs rack"
- build_gem "rack", "2.0", :to_system => true do |s|
+ build_gem "rack", "2.0", to_system: true do |s|
s.executables = "rackup"
end
- gembin "rackup", :dir => tmp
+ gembin "rackup", dir: tmp
expect(out).to eq("1.0.0")
end
it "works with gems in path" do
- build_lib "rack", :path => lib_path("rack") do |s|
+ build_lib "rack", path: lib_path("rack") do |s|
s.executables = "rackup"
end
@@ -69,7 +69,7 @@ RSpec.describe "Running bin/* commands" do
bundle "binstubs rack"
- build_gem "rack", "2.0", :to_system => true do |s|
+ build_gem "rack", "2.0", to_system: true do |s|
s.executables = "rackup"
end
@@ -94,7 +94,7 @@ RSpec.describe "Running bin/* commands" do
expect(bundled_app("bin/rackup")).not_to exist
end
- it "allows you to stop installing binstubs", :bundler => "< 3" do
+ it "allows you to stop installing binstubs", bundler: "< 3" do
skip "delete permission error" if Gem.win_platform?
bundle "install --binstubs bin/"
@@ -107,13 +107,13 @@ RSpec.describe "Running bin/* commands" do
expect(out).to include("You have not configured a value for `bin`")
end
- it "remembers that the option was specified", :bundler => "< 3" do
+ it "remembers that the option was specified", bundler: "< 3" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
G
- bundle :install, :binstubs => "bin"
+ bundle :install, binstubs: "bin"
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
diff --git a/spec/bundler/runtime/gem_tasks_spec.rb b/spec/bundler/runtime/gem_tasks_spec.rb
index b0ef0cc144..f7afc0eb92 100644
--- a/spec/bundler/runtime/gem_tasks_spec.rb
+++ b/spec/bundler/runtime/gem_tasks_spec.rb
@@ -27,8 +27,8 @@ RSpec.describe "require 'bundler/gem_tasks'" do
end
it "includes the relevant tasks" do
- with_gem_path_as(base_system_gems.to_s) do
- sys_exec "#{rake} -T", :env => { "GEM_HOME" => system_gem_path.to_s }
+ with_gem_path_as(base_system_gem_path.to_s) do
+ sys_exec "#{rake} -T", env: { "GEM_HOME" => system_gem_path.to_s }
end
expect(err).to be_empty
@@ -44,8 +44,8 @@ RSpec.describe "require 'bundler/gem_tasks'" do
end
it "defines a working `rake install` task", :ruby_repo do
- with_gem_path_as(base_system_gems.to_s) do
- sys_exec "#{rake} install", :env => { "GEM_HOME" => system_gem_path.to_s }
+ with_gem_path_as(base_system_gem_path.to_s) do
+ sys_exec "#{rake} install", env: { "GEM_HOME" => system_gem_path.to_s }
end
expect(err).to be_empty
@@ -59,7 +59,7 @@ RSpec.describe "require 'bundler/gem_tasks'" do
before do
spaced_bundled_app = tmp.join("bundled app")
FileUtils.cp_r bundled_app, spaced_bundled_app
- bundle "exec rake build", :dir => spaced_bundled_app
+ bundle "exec rake build", dir: spaced_bundled_app
end
it "still runs successfully" do
@@ -71,7 +71,7 @@ RSpec.describe "require 'bundler/gem_tasks'" do
before do
bracketed_bundled_app = tmp.join("bundled[app")
FileUtils.cp_r bundled_app, bracketed_bundled_app
- bundle "exec rake build", :dir => bracketed_bundled_app
+ bundle "exec rake build", dir: bracketed_bundled_app
end
it "still runs successfully" do
@@ -98,8 +98,8 @@ RSpec.describe "require 'bundler/gem_tasks'" do
end
it "adds 'pkg' to rake/clean's CLOBBER" do
- with_gem_path_as(base_system_gems.to_s) do
- sys_exec %(#{rake} -e 'load "Rakefile"; puts CLOBBER.inspect'), :env => { "GEM_HOME" => system_gem_path.to_s }
+ with_gem_path_as(base_system_gem_path.to_s) do
+ sys_exec %(#{rake} -e 'load "Rakefile"; puts CLOBBER.inspect'), env: { "GEM_HOME" => system_gem_path.to_s }
end
expect(out).to eq '["pkg"]'
end
diff --git a/spec/bundler/runtime/inline_spec.rb b/spec/bundler/runtime/inline_spec.rb
index 4f39c552e8..50a5258dc7 100644
--- a/spec/bundler/runtime/inline_spec.rb
+++ b/spec/bundler/runtime/inline_spec.rb
@@ -2,7 +2,7 @@
RSpec.describe "bundler/inline#gemfile" do
def script(code, options = {})
- requires = ["#{entrypoint}/inline"]
+ requires = ["bundler/inline"]
requires.unshift "#{spec_dir}/support/artifice/" + options.delete(:artifice) if options.key?(:artifice)
requires = requires.map {|r| "require '#{r}'" }.join("\n")
ruby("#{requires}\n\n" + code, options)
@@ -28,7 +28,7 @@ RSpec.describe "bundler/inline#gemfile" do
s.write "lib/four.rb", "puts 'four'"
end
- build_lib "five", "1.0.0", :no_default => true do |s|
+ build_lib "five", "1.0.0", no_default: true do |s|
s.write "lib/mofive.rb", "puts 'five'"
end
@@ -57,7 +57,7 @@ RSpec.describe "bundler/inline#gemfile" do
expect(out).to eq("two")
- script <<-RUBY, :raise_on_error => false
+ script <<-RUBY, raise_on_error: false
gemfile do
source "#{file_uri_for(gem_repo1)}"
path "#{lib_path}" do
@@ -80,7 +80,7 @@ RSpec.describe "bundler/inline#gemfile" do
expect(out).to include("Rack's post install message")
- script <<-RUBY, :artifice => "endpoint"
+ script <<-RUBY, artifice: "endpoint"
gemfile(true) do
source "https://notaserver.com"
gem "activesupport", :require => true
@@ -89,19 +89,21 @@ RSpec.describe "bundler/inline#gemfile" do
expect(out).to include("Installing activesupport")
err_lines = err.split("\n")
- err_lines.reject!{|line| line =~ /\.rb:\d+: warning: / } unless RUBY_VERSION < "2.7"
+ err_lines.reject! {|line| line =~ /\.rb:\d+: warning: / }
expect(err_lines).to be_empty
end
it "lets me use my own ui object" do
- script <<-RUBY, :artifice => "endpoint"
- require '#{entrypoint}'
- class MyBundlerUI < Bundler::UI::Silent
+ script <<-RUBY, artifice: "endpoint"
+ require 'bundler'
+ class MyBundlerUI < Bundler::UI::Shell
def confirm(msg, newline = nil)
puts "CONFIRMED!"
end
end
- gemfile(true, :ui => MyBundlerUI.new) do
+ my_ui = MyBundlerUI.new
+ my_ui.level = "confirm"
+ gemfile(true, :ui => my_ui) do
source "https://notaserver.com"
gem "activesupport", :require => true
end
@@ -111,8 +113,8 @@ RSpec.describe "bundler/inline#gemfile" do
end
it "has an option for quiet installation" do
- script <<-RUBY, :artifice => "endpoint"
- require '#{entrypoint}/inline'
+ script <<-RUBY, artifice: "endpoint"
+ require 'bundler/inline'
gemfile(true, :quiet => true) do
source "https://notaserver.com"
@@ -124,7 +126,7 @@ RSpec.describe "bundler/inline#gemfile" do
end
it "raises an exception if passed unknown arguments" do
- script <<-RUBY, :raise_on_error => false
+ script <<-RUBY, raise_on_error: false
gemfile(true, :arglebargle => true) do
path "#{lib_path}"
gem "two"
@@ -138,7 +140,7 @@ RSpec.describe "bundler/inline#gemfile" do
it "does not mutate the option argument" do
script <<-RUBY
- require '#{entrypoint}'
+ require 'bundler'
options = { :ui => Bundler::UI::Shell.new }
gemfile(false, options) do
source "#{file_uri_for(gem_repo1)}"
@@ -166,6 +168,54 @@ RSpec.describe "bundler/inline#gemfile" do
expect(err).to be_empty
end
+ it "installs subdependencies quietly if necessary when the install option is not set" do
+ build_repo4 do
+ build_gem "rack" do |s|
+ s.add_dependency "rackdep"
+ end
+
+ build_gem "rackdep", "1.0.0"
+ end
+
+ script <<-RUBY
+ gemfile do
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
+ end
+
+ require "rackdep"
+ puts RACKDEP
+ RUBY
+
+ expect(out).to eq("1.0.0")
+ expect(err).to be_empty
+ end
+
+ it "installs subdependencies quietly if necessary when the install option is not set, and multiple sources used" do
+ build_repo4 do
+ build_gem "rack" do |s|
+ s.add_dependency "rackdep"
+ end
+
+ build_gem "rackdep", "1.0.0"
+ end
+
+ script <<-RUBY
+ gemfile do
+ source "#{file_uri_for(gem_repo1)}"
+ source "#{file_uri_for(gem_repo4)}" do
+ gem "rack"
+ end
+ end
+
+ require "rackdep"
+ puts RACKDEP
+ RUBY
+
+ expect(out).to eq("1.0.0")
+ expect(err).to be_empty
+ end
+
it "installs quietly from git if necessary when the install option is not set" do
build_git "foo", "1.0.0"
baz_ref = build_git("baz", "2.0.0").ref_for("HEAD")
@@ -205,6 +255,113 @@ RSpec.describe "bundler/inline#gemfile" do
expect(err).to be_empty
end
+ it "doesn't reinstall already installed gems" do
+ system_gems "rack-1.0.0"
+
+ script <<-RUBY
+ require 'bundler'
+ ui = Bundler::UI::Shell.new
+ ui.level = "confirm"
+
+ gemfile(true, ui: ui) do
+ source "#{file_uri_for(gem_repo1)}"
+ gem "activesupport"
+ gem "rack"
+ end
+ RUBY
+
+ expect(out).to include("Installing activesupport")
+ expect(out).not_to include("Installing rack")
+ expect(err).to be_empty
+ end
+
+ it "installs gems in later gemfile calls" do
+ system_gems "rack-1.0.0"
+
+ script <<-RUBY
+ require 'bundler'
+ ui = Bundler::UI::Shell.new
+ ui.level = "confirm"
+ gemfile(true, ui: ui) do
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ end
+
+ gemfile(true, ui: ui) do
+ source "#{file_uri_for(gem_repo1)}"
+ gem "activesupport"
+ end
+ RUBY
+
+ expect(out).to include("Installing activesupport")
+ expect(out).not_to include("Installing rack")
+ expect(err).to be_empty
+ end
+
+ it "doesn't reinstall already installed gems in later gemfile calls" do
+ system_gems "rack-1.0.0"
+
+ script <<-RUBY
+ require 'bundler'
+ ui = Bundler::UI::Shell.new
+ ui.level = "confirm"
+ gemfile(true, ui: ui) do
+ source "#{file_uri_for(gem_repo1)}"
+ gem "activesupport"
+ end
+
+ gemfile(true, ui: ui) do
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ end
+ RUBY
+
+ expect(out).to include("Installing activesupport")
+ expect(out).not_to include("Installing rack")
+ expect(err).to be_empty
+ end
+
+ it "installs gems with native extensions in later gemfile calls" do
+ system_gems "rack-1.0.0"
+
+ build_git "foo" do |s|
+ s.add_dependency "rake"
+ s.extensions << "Rakefile"
+ s.write "Rakefile", <<-RUBY
+ task :default do
+ path = File.expand_path("lib", __dir__)
+ FileUtils.mkdir_p(path)
+ File.open("\#{path}/foo.rb", "w") do |f|
+ f.puts "FOO = 'YES'"
+ end
+ end
+ RUBY
+ end
+
+ script <<-RUBY
+ require 'bundler'
+ ui = Bundler::UI::Shell.new
+ ui.level = "confirm"
+ gemfile(true, ui: ui) do
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ end
+
+ gemfile(true, ui: ui) do
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => "#{lib_path("foo-1.0")}"
+ end
+
+ require 'foo'
+ puts FOO
+ puts $:.grep(/ext/)
+ RUBY
+
+ expect(out).to include("YES")
+ expect(out).to include(Pathname.glob(default_bundle_path("bundler/gems/extensions/**/foo-1.0-*")).first.to_s)
+ expect(err).to be_empty
+ end
+
it "installs inline gems when a Gemfile.lock is present" do
gemfile <<-G
source "https://notaserver.com"
@@ -239,8 +396,42 @@ RSpec.describe "bundler/inline#gemfile" do
expect(err).to be_empty
end
+ it "does not leak Gemfile.lock versions to the installation output" do
+ gemfile <<-G
+ source "https://notaserver.com"
+ gem "rake"
+ G
+
+ lockfile <<-G
+ GEM
+ remote: https://rubygems.org/
+ specs:
+ rake (11.3.0)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ rake
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ G
+
+ script <<-RUBY
+ gemfile(true) do
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rake", "#{rake_version}"
+ end
+ RUBY
+
+ expect(out).to include("Installing rake #{rake_version}")
+ expect(out).not_to include("was 11.3.0")
+ expect(err).to be_empty
+ end
+
it "installs inline gems when frozen is set" do
- script <<-RUBY, :env => { "BUNDLE_FROZEN" => "true" }
+ script <<-RUBY, env: { "BUNDLE_FROZEN" => "true" }
gemfile do
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -253,7 +444,7 @@ RSpec.describe "bundler/inline#gemfile" do
end
it "installs inline gems when deployment is set" do
- script <<-RUBY, :env => { "BUNDLE_DEPLOYMENT" => "true" }
+ script <<-RUBY, env: { "BUNDLE_DEPLOYMENT" => "true" }
gemfile do
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -297,7 +488,7 @@ RSpec.describe "bundler/inline#gemfile" do
context "when BUNDLE_PATH is set" do
it "installs inline gems to the system path regardless" do
- script <<-RUBY, :env => { "BUNDLE_PATH" => "./vendor/inline" }
+ script <<-RUBY, env: { "BUNDLE_PATH" => "./vendor/inline" }
gemfile(true) do
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -309,7 +500,7 @@ RSpec.describe "bundler/inline#gemfile" do
end
it "skips platform warnings" do
- simulate_platform "ruby"
+ bundle "config set --local force_ruby_platform true"
script <<-RUBY
gemfile(true) do
@@ -321,6 +512,20 @@ RSpec.describe "bundler/inline#gemfile" do
expect(err).to be_empty
end
+ it "still installs if the application has `bundle package` no_install config set" do
+ bundle "config set --local no_install true"
+
+ script <<-RUBY
+ gemfile do
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ end
+ RUBY
+
+ expect(last_command).to be_success
+ expect(system_gem_path("gems/rack-1.0.0")).to exist
+ end
+
it "preserves previous BUNDLE_GEMFILE value" do
ENV["BUNDLE_GEMFILE"] = ""
script <<-RUBY
@@ -371,7 +576,7 @@ RSpec.describe "bundler/inline#gemfile" do
s.write "lib/foo.rb", foo_code
end
- script <<-RUBY, :dir => tmp("path_without_gemfile")
+ script <<-RUBY, dir: tmp("path_without_gemfile")
gemfile do
source "#{file_uri_for(gem_repo2)}"
path "#{lib_path}" do
@@ -386,24 +591,17 @@ RSpec.describe "bundler/inline#gemfile" do
expect(err).to be_empty
end
- it "when requiring fileutils after does not show redefinition warnings" do
- dependency_installer_loads_fileutils = ruby "require 'rubygems/dependency_installer'; puts $LOADED_FEATURES.grep(/fileutils/)", :raise_on_error => false
- skip "does not work if rubygems/dependency_installer loads fileutils, which happens until rubygems 3.2.0" unless dependency_installer_loads_fileutils.empty?
-
- skip "does not work on ruby 3.0 because it changes the path to look for default gems, tsort is a default gem there, and we can't install it either like we do with fiddle because it doesn't yet exist" unless RUBY_VERSION < "3.0.0"
-
+ it "when requiring fileutils after does not show redefinition warnings", :realworld do
Dir.mkdir tmp("path_without_gemfile")
- default_fileutils_version = ruby "gem 'fileutils', '< 999999'; require 'fileutils'; puts FileUtils::VERSION", :raise_on_error => false
+ default_fileutils_version = ruby "gem 'fileutils', '< 999999'; require 'fileutils'; puts FileUtils::VERSION", raise_on_error: false
skip "fileutils isn't a default gem" if default_fileutils_version.empty?
realworld_system_gems "fileutils --version 1.4.1"
- realworld_system_gems "fiddle" # not sure why, but this is needed on Windows to boot rubygems successfully
+ realworld_system_gems "pathname --version 0.2.0"
- realworld_system_gems "timeout uri" # this spec uses net/http which requires these default gems
-
- script <<-RUBY, :dir => tmp("path_without_gemfile"), :env => { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }
+ script <<-RUBY, dir: tmp("path_without_gemfile"), env: { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }
require "bundler/inline"
gemfile(true) do
@@ -415,4 +613,47 @@ RSpec.describe "bundler/inline#gemfile" do
expect(err).to eq("The Gemfile specifies no dependencies")
end
+
+ it "does not load default timeout" do
+ default_timeout_version = ruby "gem 'timeout', '< 999999'; require 'timeout'; puts Timeout::VERSION", raise_on_error: false
+ skip "timeout isn't a default gem" if default_timeout_version.empty?
+
+ # This only works on RubyGems 3.5.0 or higher
+ ruby "require 'rubygems/timeout'", raise_on_error: false
+ skip "rubygems under test does not yet vendor timeout" unless last_command.success?
+
+ build_repo4 do
+ build_gem "timeout", "999"
+ end
+
+ script <<-RUBY
+ require "bundler/inline"
+
+ gemfile(true) do
+ source "#{file_uri_for(gem_repo4)}"
+
+ gem "timeout"
+ end
+ RUBY
+
+ expect(out).to include("Installing timeout 999")
+ end
+
+ it "does not upcase ENV" do
+ script <<-RUBY
+ require 'bundler/inline'
+
+ ENV['Test_Variable'] = 'value string'
+ puts("before: \#{ENV.each_key.select { |key| key.match?(/test_variable/i) }}")
+
+ gemfile do
+ source "#{file_uri_for(gem_repo1)}"
+ end
+
+ puts("after: \#{ENV.each_key.select { |key| key.match?(/test_variable/i) }}")
+ RUBY
+
+ expect(out).to include("before: [\"Test_Variable\"]")
+ expect(out).to include("after: [\"Test_Variable\"]")
+ end
end
diff --git a/spec/bundler/runtime/load_spec.rb b/spec/bundler/runtime/load_spec.rb
index 96a22a46cc..f28ffd9460 100644
--- a/spec/bundler/runtime/load_spec.rb
+++ b/spec/bundler/runtime/load_spec.rb
@@ -82,7 +82,7 @@ RSpec.describe "Bundler.load" do
G
ruby <<-RUBY
- require "#{entrypoint}"
+ require "bundler"
Bundler.setup :default
Bundler.require :default
puts RACK
diff --git a/spec/bundler/runtime/platform_spec.rb b/spec/bundler/runtime/platform_spec.rb
index d81bccbdf8..1925e9bf2e 100644
--- a/spec/bundler/runtime/platform_spec.rb
+++ b/spec/bundler/runtime/platform_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
ruby <<-R
begin
- require '#{entrypoint}'
+ require 'bundler'
Bundler.ui.silence { Bundler.setup }
rescue Bundler::GemNotFound => e
puts "WIN"
@@ -61,16 +61,23 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
build_repo4 do
build_gem "nokogiri", "1.11.1" do |s|
s.add_dependency "mini_portile2", "~> 2.5.0"
- s.add_dependency "racc", "~> 1.4"
+ s.add_dependency "racca", "~> 1.5.2"
end
build_gem "nokogiri", "1.11.1" do |s|
s.platform = Bundler.local_platform
- s.add_dependency "racc", "~> 1.4"
+ s.add_dependency "racca", "~> 1.4"
end
build_gem "mini_portile2", "2.5.0"
- build_gem "racc", "1.5.2"
+ build_gem "racca", "1.5.2"
+ end
+
+ checksums = checksums_section do |c|
+ c.checksum gem_repo4, "mini_portile2", "2.5.0"
+ c.checksum gem_repo4, "nokogiri", "1.11.1"
+ c.checksum gem_repo4, "nokogiri", "1.11.1", Bundler.local_platform
+ c.checksum gem_repo4, "racca", "1.5.2"
end
good_lockfile = <<~L
@@ -80,18 +87,17 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
mini_portile2 (2.5.0)
nokogiri (1.11.1)
mini_portile2 (~> 2.5.0)
- racc (~> 1.4)
+ racca (~> 1.5.2)
nokogiri (1.11.1-#{Bundler.local_platform})
- racc (~> 1.4)
- racc (1.5.2)
+ racca (~> 1.4)
+ racca (1.5.2)
PLATFORMS
- ruby
- #{Bundler.local_platform}
+ #{lockfile_platforms("ruby")}
DEPENDENCIES
nokogiri (~> 1.11)
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -139,14 +145,14 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
#{Bundler::VERSION}
L
- bundle "install", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ bundle "install", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
expect(out).to include("Fetching nokogiri 1.11.1")
expect(the_bundle).to include_gems "nokogiri 1.11.1"
expect(the_bundle).not_to include_gems "nokogiri 1.11.1 #{Bundler.local_platform}"
end
- it "will use the java platform if both generic java and generic ruby platforms are locked", :jruby do
+ it "will use the java platform if both generic java and generic ruby platforms are locked", :jruby_only do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "nokogiri"
@@ -169,7 +175,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
nokogiri
BUNDLED WITH
- 2.1.4
+ #{Bundler::VERSION}
G
bundle "install"
@@ -205,7 +211,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 x86-darwin-100"
end
- it "allows specifying only-ruby-platform on jruby", :jruby do
+ it "allows specifying only-ruby-platform on jruby", :jruby_only do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "nokogiri"
@@ -233,7 +239,21 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 RUBY"
end
- it "doesn't pull platform specific gems on truffleruby", :truffleruby do
+ it "allows specifying only-ruby-platform even if the lockfile is locked to a specific compatible platform" do
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "nokogiri"
+ gem "platform_specific"
+ G
+
+ bundle "config set force_ruby_platform true"
+
+ bundle "install"
+
+ expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 RUBY"
+ end
+
+ it "doesn't pull platform specific gems on truffleruby", :truffleruby_only do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "platform_specific"
@@ -242,11 +262,117 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
expect(the_bundle).to include_gems "platform_specific 1.0 RUBY"
end
+ it "doesn't pull platform specific gems on truffleruby (except when whitelisted) even if lockfile was generated with an older version that declared RUBY as platform", :truffleruby_only do
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "platform_specific"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+ platform_specific (1.0)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ platform_specific
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install"
+
+ expect(the_bundle).to include_gems "platform_specific 1.0 RUBY"
+
+ simulate_platform "x86_64-linux" do
+ build_repo4 do
+ build_gem "libv8"
+
+ build_gem "libv8" do |s|
+ s.platform = "x86_64-linux"
+ end
+ end
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "libv8"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ libv8 (1.0)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ libv8
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install"
+
+ expect(the_bundle).to include_gems "libv8 1.0 x86_64-linux"
+ end
+ end
+
+ it "doesn't pull platform specific gems on truffleruby, even if lockfile only includes those", :truffleruby_only do
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "platform_specific"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+ platform_specific (1.0-x86-darwin-100)
+
+ PLATFORMS
+ x86-darwin-100
+
+ DEPENDENCIES
+ platform_specific
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install"
+
+ expect(the_bundle).to include_gems "platform_specific 1.0 RUBY"
+ end
+
+ it "pulls platform specific gems correctly on musl" do
+ build_repo4 do
+ build_gem "nokogiri", "1.13.8" do |s|
+ s.platform = "aarch64-linux"
+ end
+ end
+
+ simulate_platform "aarch64-linux-musl" do
+ install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }, verbose: true
+ source "https://gems.repo4"
+ gem "nokogiri"
+ G
+ end
+
+ expect(out).to include("Fetching nokogiri 1.13.8 (aarch64-linux)")
+ end
+
it "allows specifying only-ruby-platform on windows with dependency platforms" do
simulate_windows do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "nokogiri", :platforms => [:mingw, :mswin, :x64_mingw, :jruby]
+ gem "nokogiri", :platforms => [:windows, :mswin, :mswin64, :mingw, :x64_mingw, :jruby]
gem "platform_specific"
G
@@ -260,7 +386,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
end
it "allows specifying only-ruby-platform on windows with gemspec dependency" do
- build_lib("foo", "1.0", :path => bundled_app) do |s|
+ build_lib("foo", "1.0", path: bundled_app) do |s|
s.add_dependency "rack"
end
@@ -284,7 +410,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
s.add_dependency "platform_specific"
end
end
- simulate_windows x64_mingw do
+ simulate_windows x64_mingw32 do
lockfile <<-L
GEM
remote: #{file_uri_for(gem_repo2)}/
@@ -301,12 +427,45 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
requires_platform_specific
L
- install_gemfile <<-G, :verbose => true
+ install_gemfile <<-G, verbose: true
source "#{file_uri_for(gem_repo2)}"
gem "requires_platform_specific"
G
+ expect(out).to include("lockfile does not have all gems needed for the current platform")
expect(the_bundle).to include_gem "platform_specific 1.0 x64-mingw32"
end
end
+
+ %w[x86-mswin32 x64-mswin64 x86-mingw32 x64-mingw32 x64-mingw-ucrt].each do |arch|
+ it "allows specifying platform windows on #{arch} arch" do
+ platform = send(arch.tr("-", "_"))
+
+ simulate_windows platform do
+ lockfile <<-L
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+ platform_specific (1.0-#{platform})
+ requires_platform_specific (1.0)
+ platform_specific
+
+ PLATFORMS
+ #{platform}
+
+ DEPENDENCIES
+ requires_platform_specific
+ L
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "platform_specific", :platforms => [:windows]
+ G
+
+ bundle "install"
+
+ expect(the_bundle).to include_gems "platform_specific 1.0 #{platform}"
+ end
+ end
+ end
end
diff --git a/spec/bundler/runtime/require_spec.rb b/spec/bundler/runtime/require_spec.rb
index d91b5f8666..76271a5593 100644
--- a/spec/bundler/runtime/require_spec.rb
+++ b/spec/bundler/runtime/require_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe "Bundler.require" do
s.write "lib/four.rb", "puts 'four'"
end
- build_lib "five", "1.0.0", :no_default => true do |s|
+ build_lib "five", "1.0.0", no_default: true do |s|
s.write "lib/mofive.rb", "puts 'five'"
end
@@ -138,7 +138,7 @@ RSpec.describe "Bundler.require" do
end
G
- run "Bundler.require", :raise_on_error => false
+ run "Bundler.require", raise_on_error: false
expect(err).to match("error while trying to load the gem 'faulty'")
expect(err).to match("Gem Internal Error Message")
end
@@ -187,7 +187,7 @@ RSpec.describe "Bundler.require" do
end
it "silently passes if the require fails" do
- build_lib "bcrypt-ruby", "1.0.0", :no_default => true do |s|
+ build_lib "bcrypt-ruby", "1.0.0", no_default: true do |s|
s.write "lib/brcrypt.rb", "BCrypt = '1.0.0'"
end
gemfile <<-G
@@ -199,7 +199,7 @@ RSpec.describe "Bundler.require" do
G
cmd = <<-RUBY
- require '#{entrypoint}'
+ require 'bundler'
Bundler.require
RUBY
ruby(cmd)
@@ -323,7 +323,7 @@ RSpec.describe "Bundler.require" do
describe "a gem with different requires for different envs" do
before(:each) do
- build_gem "multi_gem", :to_bundle => true do |s|
+ build_gem "multi_gem", to_bundle: true do |s|
s.write "lib/one.rb", "puts 'ONE'"
s.write "lib/two.rb", "puts 'TWO'"
end
@@ -366,7 +366,7 @@ RSpec.describe "Bundler.require" do
describe "with busted gems" do
it "should be busted" do
- build_gem "busted_require", :to_bundle => true do |s|
+ build_gem "busted_require", to_bundle: true do |s|
s.write "lib/busted_require.rb", "require 'no_such_file_omg'"
end
@@ -449,8 +449,6 @@ RSpec.describe "Bundler.require with platform specific dependencies" do
end
it "requires gems pinned to multiple platforms, including the current one" do
- skip "platform issues" if Gem.win_platform?
-
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
diff --git a/spec/bundler/runtime/requiring_spec.rb b/spec/bundler/runtime/requiring_spec.rb
new file mode 100644
index 0000000000..1f32269622
--- /dev/null
+++ b/spec/bundler/runtime/requiring_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+RSpec.describe "Requiring bundler" do
+ it "takes care of requiring rubygems when entrypoint is bundler/setup" do
+ sys_exec("#{Gem.ruby} -I#{lib_dir} -rbundler/setup -e'puts true'", env: { "RUBYOPT" => opt_add("--disable=gems", ENV["RUBYOPT"]) })
+
+ expect(last_command.stdboth).to eq("true")
+ end
+
+ it "takes care of requiring rubygems when requiring just bundler" do
+ sys_exec("#{Gem.ruby} -I#{lib_dir} -rbundler -e'puts true'", env: { "RUBYOPT" => opt_add("--disable=gems", ENV["RUBYOPT"]) })
+
+ expect(last_command.stdboth).to eq("true")
+ end
+end
diff --git a/spec/bundler/runtime/self_management_spec.rb b/spec/bundler/runtime/self_management_spec.rb
new file mode 100644
index 0000000000..d15ca3189e
--- /dev/null
+++ b/spec/bundler/runtime/self_management_spec.rb
@@ -0,0 +1,159 @@
+# frozen_string_literal: true
+
+RSpec.describe "Self management", rubygems: ">= 3.3.0.dev", realworld: true do
+ describe "auto switching" do
+ let(:previous_minor) do
+ "2.3.0"
+ end
+
+ let(:current_version) do
+ "2.4.0"
+ end
+
+ before do
+ build_repo2
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
+
+ gem "rack"
+ G
+ end
+
+ it "installs locked version when using system path and uses it" do
+ lockfile_bundled_with(previous_minor)
+
+ bundle "config set --local path.system true"
+ bundle "install", artifice: "vcr"
+ expect(out).to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+
+ # It uninstalls the older system bundler
+ bundle "clean --force", artifice: nil
+ expect(out).to eq("Removing bundler (#{Bundler::VERSION})")
+
+ # App now uses locked version
+ bundle "-v", artifice: nil
+ expect(out).to end_with(previous_minor[0] == "2" ? "Bundler version #{previous_minor}" : previous_minor)
+
+ # Subsequent installs use the locked version without reinstalling
+ bundle "install --verbose", artifice: nil
+ expect(out).to include("Using bundler #{previous_minor}")
+ expect(out).not_to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+ end
+
+ it "installs locked version when using local path and uses it" do
+ lockfile_bundled_with(previous_minor)
+
+ bundle "config set --local path vendor/bundle"
+ bundle "install", artifice: "vcr"
+ expect(out).to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+ expect(vendored_gems("gems/bundler-#{previous_minor}")).to exist
+
+ # It does not uninstall the locked bundler
+ bundle "clean"
+ expect(out).to be_empty
+
+ # App now uses locked version
+ bundle "-v"
+ expect(out).to end_with(previous_minor[0] == "2" ? "Bundler version #{previous_minor}" : previous_minor)
+
+ # Subsequent installs use the locked version without reinstalling
+ bundle "install --verbose"
+ expect(out).to include("Using bundler #{previous_minor}")
+ expect(out).not_to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+ end
+
+ it "installs locked version when using deployment option and uses it" do
+ lockfile_bundled_with(previous_minor)
+
+ bundle "config set --local deployment true"
+ bundle "install", artifice: "vcr"
+ expect(out).to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+ expect(vendored_gems("gems/bundler-#{previous_minor}")).to exist
+
+ # It does not uninstall the locked bundler
+ bundle "clean"
+ expect(out).to be_empty
+
+ # App now uses locked version
+ bundle "-v"
+ expect(out).to end_with(previous_minor[0] == "2" ? "Bundler version #{previous_minor}" : previous_minor)
+
+ # Subsequent installs use the locked version without reinstalling
+ bundle "install --verbose"
+ expect(out).to include("Using bundler #{previous_minor}")
+ expect(out).not_to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+ end
+
+ it "does not try to install a development version" do
+ lockfile_bundled_with("#{previous_minor}.dev")
+
+ bundle "install --verbose"
+ expect(out).not_to match(/restarting using that version/)
+
+ bundle "-v"
+ expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION)
+ end
+
+ it "shows a discrete message if locked bundler does not exist" do
+ missing_minor = "#{Bundler::VERSION[0]}.999.999"
+
+ lockfile_bundled_with(missing_minor)
+
+ bundle "install", artifice: "vcr"
+ expect(err).to eq("Your lockfile is locked to a version of bundler (#{missing_minor}) that doesn't exist at https://rubygems.org/. Going on using #{Bundler::VERSION}")
+
+ bundle "-v"
+ expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION)
+ end
+
+ it "installs BUNDLE_VERSION version when using bundle config version x.y.z" do
+ lockfile_bundled_with(current_version)
+
+ bundle "config set --local version #{previous_minor}"
+ bundle "install", artifice: "vcr"
+ expect(out).to include("Bundler #{Bundler::VERSION} is running, but your configuration was #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
+
+ bundle "-v"
+ expect(out).to eq(previous_minor[0] == "2" ? "Bundler version #{previous_minor}" : previous_minor)
+ end
+
+ it "does not try to install when using bundle config version global" do
+ lockfile_bundled_with(previous_minor)
+
+ bundle "config set version system"
+ bundle "install", artifice: "vcr"
+ expect(out).not_to match(/restarting using that version/)
+
+ bundle "-v"
+ expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION)
+ end
+
+ it "ignores malformed lockfile version" do
+ lockfile_bundled_with("2.3.")
+
+ bundle "install --verbose"
+ expect(out).to include("Using bundler #{Bundler::VERSION}")
+ end
+
+ private
+
+ def lockfile_bundled_with(version)
+ lockfile <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo2)}/
+ specs:
+ rack (1.0.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ rack
+
+ BUNDLED WITH
+ #{version}
+ L
+ end
+ end
+end
diff --git a/spec/bundler/runtime/setup_spec.rb b/spec/bundler/runtime/setup_spec.rb
index 42bbacea0e..0344d24223 100644
--- a/spec/bundler/runtime/setup_spec.rb
+++ b/spec/bundler/runtime/setup_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
require "tmpdir"
-require "tempfile"
RSpec.describe "Bundler.setup" do
describe "with no arguments" do
@@ -90,7 +89,7 @@ RSpec.describe "Bundler.setup" do
end
it "handles multiple non-additive invocations" do
- ruby <<-RUBY, :raise_on_error => false
+ ruby <<-RUBY, raise_on_error: false
require 'bundler'
Bundler.setup(:default, :test)
Bundler.setup(:default)
@@ -145,6 +144,7 @@ RSpec.describe "Bundler.setup" do
ruby <<-RUBY
require 'bundler'
+ gem "bundler", "#{Bundler::VERSION}" if #{ruby_core?}
Bundler.setup
puts $LOAD_PATH
RUBY
@@ -158,7 +158,7 @@ RSpec.describe "Bundler.setup" do
"/gems/actionpack-2.3.2/lib",
"/gems/actionmailer-2.3.2/lib",
"/gems/activesupport-2.3.2/lib",
- "/gems/rake-13.0.1/lib"
+ "/gems/rake-#{rake_version}/lib"
)
end
@@ -194,7 +194,7 @@ RSpec.describe "Bundler.setup" do
G
ruby <<-R
- require '#{entrypoint}'
+ require 'bundler'
begin
Bundler.setup
@@ -213,7 +213,7 @@ RSpec.describe "Bundler.setup" do
gem "rack"
G
- ruby <<-R, :raise_on_error => false
+ ruby <<-R, raise_on_error: false
require 'bundler'
Bundler.setup
@@ -236,7 +236,7 @@ RSpec.describe "Bundler.setup" do
gem "nosuchgem", "10.0"
G
- ruby <<-R, :raise_on_error => false
+ ruby <<-R, raise_on_error: false
require 'bundler'
Bundler.setup
@@ -312,7 +312,7 @@ RSpec.describe "Bundler.setup" do
gem "rack", "1.0.0"
G
- build_gem "rack", "1.0", :to_system => true do |s|
+ build_gem "rack", "1.0", to_system: true do |s|
s.write "lib/rack.rb", "RACK = 'FAIL'"
end
@@ -341,19 +341,6 @@ RSpec.describe "Bundler.setup" do
expect(out).to eq("WIN")
end
- it "version_requirement is now deprecated in rubygems 1.4.0+ when gem is missing" do
- run <<-R
- begin
- gem "activesupport"
- puts "FAIL"
- rescue LoadError
- puts "WIN"
- end
- R
-
- expect(err).to be_empty
- end
-
it "replaces #gem but raises when the version is wrong" do
run <<-R
begin
@@ -366,19 +353,6 @@ RSpec.describe "Bundler.setup" do
expect(out).to eq("WIN")
end
-
- it "version_requirement is now deprecated in rubygems 1.4.0+ when the version is wrong" do
- run <<-R
- begin
- gem "rack", "1.0.0"
- puts "FAIL"
- rescue LoadError
- puts "WIN"
- end
- R
-
- expect(err).to be_empty
- end
end
describe "by hiding system gems" do
@@ -397,8 +371,8 @@ RSpec.describe "Bundler.setup" do
context "when the ruby stdlib is a substring of Gem.path" do
it "does not reject the stdlib from $LOAD_PATH" do
- substring = "/" + $LOAD_PATH.find {|p| p =~ /vendor_ruby/ }.split("/")[2]
- run "puts 'worked!'", :env => { "GEM_PATH" => substring }
+ substring = "/" + $LOAD_PATH.find {|p| p.include?("vendor_ruby") }.split("/")[2]
+ run "puts 'worked!'", env: { "GEM_PATH" => substring }
expect(out).to eq("worked!")
end
end
@@ -436,8 +410,8 @@ RSpec.describe "Bundler.setup" do
end
it "provides a useful exception when the git repo is not checked out yet" do
- run "1", :raise_on_error => false
- expect(err).to match(/the git source #{lib_path('rack-1.0.0')} is not yet checked out. Please run `bundle install`/i)
+ run "1", raise_on_error: false
+ expect(err).to match(/the git source #{lib_path("rack-1.0.0")} is not yet checked out. Please run `bundle install`/i)
end
it "does not hit the git binary if the lockfile is available and up to date" do
@@ -467,7 +441,7 @@ RSpec.describe "Bundler.setup" do
break_git!
ruby <<-R
- require "#{entrypoint}"
+ require "bundler"
begin
Bundler.setup
@@ -477,7 +451,7 @@ RSpec.describe "Bundler.setup" do
end
R
- run "puts 'FAIL'", :raise_on_error => false
+ run "puts 'FAIL'", raise_on_error: false
expect(err).not_to include "This is not the git you are looking for"
end
@@ -516,15 +490,15 @@ RSpec.describe "Bundler.setup" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
bundle %(config set local.rack #{lib_path("local-rack")})
bundle :install
FileUtils.rm_rf(lib_path("local-rack"))
- run "require 'rack'", :raise_on_error => false
- expect(err).to match(/Cannot use local override for rack-0.8 because #{Regexp.escape(lib_path('local-rack').to_s)} does not exist/)
+ run "require 'rack'", raise_on_error: false
+ expect(err).to match(/Cannot use local override for rack-0.8 because #{Regexp.escape(lib_path("local-rack").to_s)} does not exist/)
end
it "explodes if branch is not given on runtime" do
@@ -534,7 +508,7 @@ RSpec.describe "Bundler.setup" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
bundle %(config set local.rack #{lib_path("local-rack")})
@@ -545,7 +519,7 @@ RSpec.describe "Bundler.setup" do
gem "rack", :git => "#{lib_path("rack-0.8")}"
G
- run "require 'rack'", :raise_on_error => false
+ run "require 'rack'", raise_on_error: false
expect(err).to match(/because :branch is not specified in Gemfile/)
end
@@ -556,7 +530,7 @@ RSpec.describe "Bundler.setup" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
bundle %(config set local.rack #{lib_path("local-rack")})
@@ -567,8 +541,8 @@ RSpec.describe "Bundler.setup" do
gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "changed"
G
- run "require 'rack'", :raise_on_error => false
- expect(err).to match(/is using branch master but Gemfile specifies changed/)
+ run "require 'rack'", raise_on_error: false
+ expect(err).to match(/is using branch main but Gemfile specifies changed/)
end
it "explodes on refs with different branches on runtime" do
@@ -578,17 +552,17 @@ RSpec.describe "Bundler.setup" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :ref => "master", :branch => "master"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :ref => "main", :branch => "main"
G
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{lib_path("rack-0.8")}", :ref => "master", :branch => "nonexistant"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :ref => "main", :branch => "nonexistent"
G
bundle %(config set local.rack #{lib_path("local-rack")})
- run "require 'rack'", :raise_on_error => false
- expect(err).to match(/is using branch master but Gemfile specifies nonexistant/)
+ run "require 'rack'", raise_on_error: false
+ expect(err).to match(/is using branch main but Gemfile specifies nonexistent/)
end
end
@@ -606,7 +580,7 @@ RSpec.describe "Bundler.setup" do
system_gems "activesupport-2.3.5"
- expect(the_bundle).to include_gems "activesupport 2.3.2", :groups => :default
+ expect(the_bundle).to include_gems "activesupport 2.3.2", groups: :default
end
it "remembers --without and does not bail on bare Bundler.setup" do
@@ -629,7 +603,7 @@ RSpec.describe "Bundler.setup" do
bundle "config set --local without development"
path = bundled_app(File.join("vendor", "foo"))
- build_lib "foo", :path => path
+ build_lib "foo", path: path
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -639,7 +613,7 @@ RSpec.describe "Bundler.setup" do
FileUtils.rm_rf(path)
- ruby "require 'bundler'; Bundler.setup", :env => { "DEBUG" => "1" }
+ ruby "require 'bundler'; Bundler.setup", env: { "DEBUG" => "1" }
expect(out).to include("Assuming that source at `vendor/foo` has not changed since fetching its specs errored")
expect(out).to include("Found no changes, using resolution from the lockfile")
expect(err).to be_empty
@@ -659,8 +633,35 @@ RSpec.describe "Bundler.setup" do
gem "depends_on_bundler"
G
- ruby "require '#{system_gem_path("gems/bundler-9.99.9.beta1/lib/bundler.rb")}'; Bundler.setup", :env => { "DEBUG" => "1" }
+ ruby "require '#{system_gem_path("gems/bundler-9.99.9.beta1/lib/bundler.rb")}'; Bundler.setup", env: { "DEBUG" => "1" }
expect(out).to include("Found no changes, using resolution from the lockfile")
+ expect(out).not_to include("lockfile does not have all gems needed for the current platform")
+ expect(err).to be_empty
+ end
+
+ it "doesn't fail in frozen mode when bundler is a Gemfile dependency" do
+ install_gemfile <<~G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "bundler"
+ G
+
+ bundle "install --verbose", env: { "BUNDLE_FROZEN" => "true" }
+ expect(err).to be_empty
+ end
+
+ it "doesn't re-resolve when deleting dependencies" do
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "actionpack"
+ G
+
+ install_gemfile <<-G, verbose: true
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ G
+
+ expect(out).to include("Some dependencies were deleted, using a subset of the resolution from the lockfile")
expect(err).to be_empty
end
@@ -679,15 +680,15 @@ RSpec.describe "Bundler.setup" do
end
G
- expect(the_bundle).not_to include_gems "activesupport 2.3.2", :groups => :rack
- expect(the_bundle).to include_gems "rack 1.0.0", :groups => :rack
+ expect(the_bundle).not_to include_gems "activesupport 2.3.2", groups: :rack
+ expect(the_bundle).to include_gems "rack 1.0.0", groups: :rack
end
end
# RubyGems returns loaded_from as a string
it "has loaded_from as a string on all specs" do
build_git "foo"
- build_git "no-gemspec", :gemspec => false
+ build_git "no-gemspec", gemspec: false
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -727,6 +728,27 @@ end
R
run <<-R
+ File.open(File.join(Gem.dir, "specifications", "broken-ext.gemspec"), "w") do |f|
+ f.write <<-RUBY
+# -*- encoding: utf-8 -*-
+# stub: broken-ext 1.0.0 ruby lib
+# stub: a.ext\\0b.ext
+
+Gem::Specification.new do |s|
+ s.name = "broken-ext"
+ s.version = "1.0.0"
+ raise "BROKEN GEMSPEC EXT"
+end
+ RUBY
+ end
+ # Need to write the gem.build_complete file,
+ # otherwise the full spec is loaded to check the installed_by_version
+ extensions_dir = Gem.default_ext_dir_for(Gem.dir) || File.join(Gem.dir, "extensions", Gem::Platform.local.to_s, Gem.extension_api_version)
+ Bundler::FileUtils.mkdir_p(File.join(extensions_dir, "broken-ext-1.0.0"))
+ File.open(File.join(extensions_dir, "broken-ext-1.0.0", "gem.build_complete"), "w") {}
+ R
+
+ run <<-R
puts "WIN"
R
@@ -745,41 +767,68 @@ end
expect(err).to be_empty
end
- describe "$MANPATH" do
- before do
+ context "when the user has `MANPATH` set", :man do
+ before { ENV["MANPATH"] = "/foo#{File::PATH_SEPARATOR}" }
+
+ it "adds the gem's man dir to the MANPATH" do
build_repo4 do
build_gem "with_man" do |s|
s.write("man/man1/page.1", "MANPAGE")
end
end
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "with_man"
+ G
+
+ run "puts ENV['MANPATH']"
+ expect(out).to eq("#{default_bundle_path("gems/with_man-1.0/man")}#{File::PATH_SEPARATOR}/foo")
end
+ end
- context "when the user has one set" do
- before { ENV["MANPATH"] = "/foo#{File::PATH_SEPARATOR}" }
+ context "when the user does not have `MANPATH` set", :man do
+ before { ENV.delete("MANPATH") }
- it "adds the gem's man dir to the MANPATH" do
- install_gemfile <<-G
- source "#{file_uri_for(gem_repo4)}"
- gem "with_man"
- G
+ it "adds the gem's man dir to the MANPATH, leaving : in the end so that system man pages still work" do
+ build_repo4 do
+ build_gem "with_man" do |s|
+ s.write("man/man1/page.1", "MANPAGE")
+ end
- run "puts ENV['MANPATH']"
- expect(out).to eq("#{default_bundle_path("gems/with_man-1.0/man")}#{File::PATH_SEPARATOR}/foo")
+ build_gem "with_man_overriding_system_man" do |s|
+ s.write("man/man1/ls.1", "LS MANPAGE")
+ end
end
- end
- context "when the user does not have one set" do
- before { ENV.delete("MANPATH") }
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "with_man"
+ G
- it "adds the gem's man dir to the MANPATH" do
- install_gemfile <<-G
- source "#{file_uri_for(gem_repo4)}"
- gem "with_man"
- G
+ run <<~RUBY
+ puts ENV['MANPATH']
+ require "open3"
+ puts Open3.capture2e("man", "ls")[1].success?
+ RUBY
- run "puts ENV['MANPATH']"
- expect(out).to eq(default_bundle_path("gems/with_man-1.0/man").to_s)
- end
+ expect(out).to eq("#{default_bundle_path("gems/with_man-1.0/man")}#{File::PATH_SEPARATOR}\ntrue")
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "with_man_overriding_system_man"
+ G
+
+ run <<~RUBY
+ puts ENV['MANPATH']
+ require "open3"
+ puts Open3.capture2e({ "LC_ALL" => "C" }, "man", "ls")[0]
+ RUBY
+
+ lines = out.split("\n")
+
+ expect(lines).to include("#{default_bundle_path("gems/with_man_overriding_system_man-1.0/man")}#{File::PATH_SEPARATOR}")
+ expect(lines).to include("LS MANPAGE")
end
end
@@ -801,7 +850,7 @@ end
expect(out).to eq("yay")
end
- it "should clean $LOAD_PATH properly", :ruby_repo do
+ it "should clean $LOAD_PATH properly" do
gem_name = "very_simple_binary"
full_gem_name = gem_name + "-1.0"
ext_dir = File.join(tmp("extensions", full_gem_name))
@@ -834,23 +883,21 @@ end
context "with bundler is located in symlinked GEM_HOME" do
let(:gem_home) { Dir.mktmpdir }
- let(:symlinked_gem_home) { Tempfile.new("gem_home").path }
+ let(:symlinked_gem_home) { tmp("gem_home-symlink").to_s }
let(:full_name) { "bundler-#{Bundler::VERSION}" }
before do
- skip "symlink destination exists" if Gem.win_platform?
-
- FileUtils.ln_sf(gem_home, symlinked_gem_home)
+ File.symlink(gem_home, symlinked_gem_home)
gems_dir = File.join(gem_home, "gems")
specifications_dir = File.join(gem_home, "specifications")
Dir.mkdir(gems_dir)
Dir.mkdir(specifications_dir)
- FileUtils.ln_s(source_root, File.join(gems_dir, full_name))
+ File.symlink(source_root, File.join(gems_dir, full_name))
gemspec_content = File.binread(gemspec).
sub("Bundler::VERSION", %("#{Bundler::VERSION}")).
- lines.reject {|line| line =~ %r{lib/bundler/version} }.join
+ lines.reject {|line| line.include?("lib/bundler/version") }.join
File.open(File.join(specifications_dir, "#{full_name}.gemspec"), "wb") do |f|
f.write(gemspec_content)
@@ -860,7 +907,7 @@ end
it "should not remove itself from the LOAD_PATH and require a different copy of 'bundler/setup'" do
install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
- ruby <<-R, :env => { "GEM_PATH" => symlinked_gem_home }
+ ruby <<-R, env: { "GEM_PATH" => symlinked_gem_home }
TracePoint.trace(:class) do |tp|
if tp.path.include?("bundler") && !tp.path.start_with?("#{source_root}")
puts "OMG. Defining a class from another bundler at \#{tp.path}:\#{tp.lineno}"
@@ -900,7 +947,7 @@ end
it "should resolve paths relative to the Gemfile" do
path = bundled_app(File.join("vendor", "foo"))
- build_lib "foo", :path => path
+ build_lib "foo", path: path
# If the .gemspec exists, then Bundler handles the path differently.
# See Source::Path.load_spec_files for details.
@@ -911,7 +958,7 @@ end
gem 'foo', '1.2.3', :path => 'vendor/foo'
G
- run <<-R, :env => { "BUNDLE_GEMFILE" => bundled_app_gemfile.to_s }, :dir => bundled_app.parent
+ run <<-R, env: { "BUNDLE_GEMFILE" => bundled_app_gemfile.to_s }, dir: bundled_app.parent
require 'foo'
R
expect(err).to be_empty
@@ -921,7 +968,7 @@ end
relative_path = File.join("vendor", Dir.pwd.gsub(/^#{filesystem_root}/, ""))
absolute_path = bundled_app(relative_path)
FileUtils.mkdir_p(absolute_path)
- build_lib "foo", :path => absolute_path
+ build_lib "foo", path: absolute_path
# If the .gemspec exists, then Bundler handles the path differently.
# See Source::Path.load_spec_files for details.
@@ -934,7 +981,7 @@ end
bundle :install
- run <<-R, :env => { "BUNDLE_GEMFILE" => bundled_app_gemfile.to_s }, :dir => bundled_app.parent
+ run <<-R, env: { "BUNDLE_GEMFILE" => bundled_app_gemfile.to_s }, dir: bundled_app.parent
require 'foo'
R
@@ -944,7 +991,7 @@ end
describe "with git gems that don't have gemspecs" do
before :each do
- build_git "no_gemspec", :gemspec => false
+ build_git "no_gemspec", gemspec: false
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -1034,7 +1081,7 @@ end
describe "with a gemspec that requires other files" do
before :each do
- build_git "bar", :gemspec => false do |s|
+ build_git "bar", gemspec: false do |s|
s.write "lib/bar/version.rb", %(BAR_VERSION = '1.0')
s.write "bar.gemspec", <<-G
require_relative 'lib/bar/version'
@@ -1064,10 +1111,10 @@ end
it "error intelligently if the gemspec has a LoadError" do
skip "whitespace issue?" if Gem.win_platform?
- ref = update_git "bar", :gemspec => false do |s|
+ ref = update_git "bar", gemspec: false do |s|
s.write "bar.gemspec", "require 'foobarbaz'"
end.ref_for("HEAD")
- bundle :install, :raise_on_error => false
+ bundle :install, raise_on_error: false
expect(err.lines.map(&:chomp)).to include(
a_string_starting_with("[!] There was an error while loading `bar.gemspec`:"),
@@ -1108,7 +1155,7 @@ end
describe "when BUNDLED WITH" do
def lock_with(bundler_version = nil)
- lock = <<-L
+ lock = <<~L
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
@@ -1122,7 +1169,7 @@ end
L
if bundler_version
- lock += "\n BUNDLED WITH\n #{bundler_version}\n"
+ lock += "\nBUNDLED WITH\n #{bundler_version}\n"
end
lock
@@ -1140,8 +1187,8 @@ end
context "is not present" do
it "does not change the lock" do
lockfile lock_with(nil)
- ruby "require '#{entrypoint}/setup'"
- lockfile_should_be lock_with(nil)
+ ruby "require 'bundler/setup'"
+ expect(lockfile).to eq lock_with(nil)
end
end
@@ -1151,7 +1198,7 @@ end
ruby "require 'bundler/setup'"
expect(out).to be_empty
expect(err).to be_empty
- lockfile_should_be lock_with(Bundler::VERSION.succ)
+ expect(lockfile).to eq lock_with(Bundler::VERSION.succ)
end
end
@@ -1159,8 +1206,8 @@ end
it "does not change the lock" do
system_gems "bundler-1.10.1"
lockfile lock_with("1.10.1")
- ruby "require '#{entrypoint}/setup'"
- lockfile_should_be lock_with("1.10.1")
+ ruby "require 'bundler/setup'"
+ expect(lockfile).to eq lock_with("1.10.1")
end
end
end
@@ -1169,7 +1216,11 @@ end
let(:ruby_version) { nil }
def lock_with(ruby_version = nil)
- lock = <<-L
+ checksums = checksums_section do |c|
+ c.checksum gem_repo1, "rack", "1.0.0"
+ end
+
+ lock = <<~L
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
@@ -1180,13 +1231,14 @@ end
DEPENDENCIES
rack
+ #{checksums}
L
if ruby_version
- lock += "\n RUBY VERSION\n ruby #{ruby_version}\n"
+ lock += "\nRUBY VERSION\n ruby #{ruby_version}\n"
end
- lock += <<-L
+ lock += <<~L
BUNDLED WITH
#{Bundler::VERSION}
@@ -1228,10 +1280,43 @@ end
end
describe "with gemified standard libraries" do
+ it "does not load Digest", :ruby_repo do
+ build_git "bar", gemspec: false do |s|
+ s.write "lib/bar/version.rb", %(BAR_VERSION = '1.0')
+ s.write "bar.gemspec", <<-G
+ require_relative 'lib/bar/version'
+
+ Gem::Specification.new do |s|
+ s.name = 'bar'
+ s.version = BAR_VERSION
+ s.summary = 'Bar'
+ s.files = Dir["lib/**/*.rb"]
+ s.author = 'no one'
+
+ s.add_runtime_dependency 'digest'
+ end
+ G
+ end
+
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "bar", :git => "#{lib_path("bar-1.0")}"
+ G
+
+ bundle :install
+
+ ruby <<-RUBY
+ require 'bundler/setup'
+ puts defined?(::Digest) ? "Digest defined" : "Digest undefined"
+ require 'digest'
+ RUBY
+ expect(out).to eq("Digest undefined")
+ end
+
it "does not load Psych" do
gemfile "source \"#{file_uri_for(gem_repo1)}\""
ruby <<-RUBY
- require '#{entrypoint}/setup'
+ require 'bundler/setup'
puts defined?(Psych::VERSION) ? Psych::VERSION : "undefined"
require 'psych'
puts Psych::VERSION
@@ -1252,22 +1337,46 @@ end
expect(out).to eq("undefined\nconstant")
end
+ it "does not load uri while reading gemspecs", rubygems: ">= 3.6.0.dev" do
+ Dir.mkdir bundled_app("test")
+
+ create_file(bundled_app("test/test.gemspec"), <<-G)
+ Gem::Specification.new do |s|
+ s.name = "test"
+ s.version = "1.0.0"
+ s.summary = "test"
+ s.authors = ['John Doe']
+ s.homepage = 'https://example.com'
+ end
+ G
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "test", path: "#{bundled_app("test")}"
+ G
+
+ ruby <<-RUBY
+ require "bundler/setup"
+ puts defined?(URI) || "undefined"
+ require "uri"
+ puts defined?(URI) || "undefined"
+ RUBY
+ expect(out).to eq("undefined\nconstant")
+ end
+
describe "default gem activation" do
let(:exemptions) do
- exempts = if Gem.rubygems_version >= Gem::Version.new("2.7")
- %w[did_you_mean]
- else
- %w[io-console openssl]
- end << "bundler"
- exempts << "fiddle" if Gem.win_platform? && Gem.rubygems_version >= Gem::Version.new("2.7")
- exempts << "uri" if Gem.ruby_version >= Gem::Version.new("2.7")
- exempts << "pathname" if Gem.ruby_version >= Gem::Version.new("3.0")
+ exempts = %w[did_you_mean bundler uri pathname]
+ exempts << "etc" if Gem.ruby_version < Gem::Version.new("3.2") && Gem.win_platform?
exempts << "set" unless Gem.rubygems_version >= Gem::Version.new("3.2.6")
- exempts << "tsort" if Gem.ruby_version >= Gem::Version.new("3.0")
+ exempts << "tsort" unless Gem.rubygems_version >= Gem::Version.new("3.2.31")
+ exempts << "error_highlight" # added in Ruby 3.1 as a default gem
+ exempts << "ruby2_keywords" # added in Ruby 3.1 as a default gem
+ exempts << "syntax_suggest" # added in Ruby 3.2 as a default gem
exempts
end
- let(:activation_warning_hack) { strip_whitespace(<<-RUBY) }
+ let(:activation_warning_hack) { <<~RUBY }
require #{spec_dir.join("support/hax").to_s.dump}
Gem::Specification.send(:alias_method, :bundler_spec_activate, :activate)
@@ -1287,7 +1396,7 @@ end
"-r#{bundled_app("activation_warning_hack.rb")} #{ENV["RUBYOPT"]}"
end
- let(:code) { strip_whitespace(<<-RUBY) }
+ let(:code) { <<~RUBY }
require "pp"
loaded_specs = Gem.loaded_specs.dup
#{exemptions.inspect}.each {|s| loaded_specs.delete(s) }
@@ -1302,14 +1411,14 @@ end
it "activates no gems with -rbundler/setup" do
install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
- ruby code, :env => { "RUBYOPT" => activation_warning_hack_rubyopt + " -rbundler/setup" }
+ ruby code, env: { "RUBYOPT" => activation_warning_hack_rubyopt + " -rbundler/setup" }
expect(out).to eq("{}")
end
it "activates no gems with bundle exec" do
install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
create_file("script.rb", code)
- bundle "exec ruby ./script.rb", :env => { "RUBYOPT" => activation_warning_hack_rubyopt }
+ bundle "exec ruby ./script.rb", env: { "RUBYOPT" => activation_warning_hack_rubyopt }
expect(out).to eq("{}")
end
@@ -1319,7 +1428,7 @@ end
install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
create_file("script.rb", "#!/usr/bin/env ruby\n\n#{code}")
FileUtils.chmod(0o777, bundled_app("script.rb"))
- bundle "exec ./script.rb", :artifice => nil, :env => { "RUBYOPT" => activation_warning_hack_rubyopt }
+ bundle "exec ./script.rb", artifice: nil, env: { "RUBYOPT" => activation_warning_hack_rubyopt }
expect(out).to eq("{}")
end
@@ -1328,7 +1437,7 @@ end
build_gem "net-http-pipeline", "1.0.1"
end
- system_gems "net-http-pipeline-1.0.1", :gem_repo => gem_repo4
+ system_gems "net-http-pipeline-1.0.1", gem_repo: gem_repo4
gemfile <<-G
source "#{file_uri_for(gem_repo4)}"
@@ -1357,7 +1466,7 @@ end
gem "#{g}", "999999"
G
- expect(the_bundle).to include_gem("#{g} 999999", :env => { "RUBYOPT" => activation_warning_hack_rubyopt })
+ expect(the_bundle).to include_gem("#{g} 999999", env: { "RUBYOPT" => activation_warning_hack_rubyopt })
end
it "activates older versions of #{g}", :ruby_repo do
@@ -1372,14 +1481,14 @@ end
gem "#{g}", "0.0.0.a"
G
- expect(the_bundle).to include_gem("#{g} 0.0.0.a", :env => { "RUBYOPT" => activation_warning_hack_rubyopt })
+ expect(the_bundle).to include_gem("#{g} 0.0.0.a", env: { "RUBYOPT" => activation_warning_hack_rubyopt })
end
end
end
end
describe "after setup" do
- it "allows calling #gem on random objects", :bundler => "< 3" do
+ it "allows calling #gem on random objects", bundler: "< 3" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
@@ -1394,13 +1503,13 @@ end
expect(out).to eq("rack-1.0.0")
end
- it "keeps Kernel#gem private", :bundler => "3" do
+ it "keeps Kernel#gem private", bundler: "3" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
G
- ruby <<-RUBY, :raise_on_error => false
+ ruby <<-RUBY, raise_on_error: false
require "bundler/setup"
Object.new.gem "rack"
puts "FAIL"
@@ -1416,20 +1525,93 @@ end
gem "rack"
G
- ruby <<-RUBY, :raise_on_error => false
+ ruby <<-RUBY, raise_on_error: false
require "bundler/setup"
Object.new.require "rack"
puts "FAIL"
RUBY
expect(last_command.stdboth).not_to include "FAIL"
- expect(err).to include "private method `require'"
+ expect(err).to match(/private method [`']require'/)
end
- it "takes care of requiring rubygems" do
- sys_exec("#{Gem.ruby} -I#{lib_dir} -rbundler/setup -e'puts true'", :env => { "RUBYOPT" => opt_add("--disable=gems", ENV["RUBYOPT"]) })
+ it "memoizes initial set of specs when requiring bundler/setup, so that even if further code mutates dependencies, Bundler.definition.specs is not affected" do
+ install_gemfile <<~G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "yard"
+ gem "rack", :group => :test
+ G
+
+ ruby <<-RUBY, raise_on_error: false
+ require "bundler/setup"
+ Bundler.require(:test).select! {|d| (d.groups & [:test]).any? }
+ puts Bundler.definition.specs.map(&:name).join(", ")
+ RUBY
- expect(last_command.stdboth).to eq("true")
+ expect(out).to include("rack, yard")
end
+
+ it "does not cause double loads when higher versions of default gems are activated before bundler" do
+ build_repo2 do
+ build_gem "json", "999.999.999" do |s|
+ s.write "lib/json.rb", <<~RUBY
+ module JSON
+ VERSION = "999.999.999"
+ end
+ RUBY
+ end
+ end
+
+ system_gems "json-999.999.999", gem_repo: gem_repo2
+
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
+ ruby <<-RUBY
+ require "json"
+ require "bundler/setup"
+ require "json"
+ RUBY
+
+ expect(err).to be_empty
+ end
+ end
+
+ it "does not undo the Kernel.require decorations", rubygems: ">= 3.4.6" do
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
+ script = bundled_app("bin/script")
+ create_file(script, <<~RUBY)
+ module Kernel
+ module_function
+
+ alias_method :require_before_extra_monkeypatches, :require
+
+ def require(path)
+ puts "requiring \#{path} used the monkeypatch"
+
+ require_before_extra_monkeypatches(path)
+ end
+ end
+
+ require "bundler/setup"
+
+ require "foo"
+ RUBY
+
+ sys_exec "#{Gem.ruby} #{script}", raise_on_error: false
+ expect(out).to include("requiring foo used the monkeypatch")
+ end
+
+ it "performs an automatic bundle install" do
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :group => :test
+ G
+
+ bundle "config set auto_install 1"
+
+ ruby <<-RUBY
+ require 'bundler/setup'
+ RUBY
+ expect(err).to be_empty
+ expect(out).to include("Installing rack 1.0.0")
end
end
diff --git a/spec/bundler/runtime/with_unbundled_env_spec.rb b/spec/bundler/runtime/with_unbundled_env_spec.rb
index 731a9921a2..135c71b0af 100644
--- a/spec/bundler/runtime/with_unbundled_env_spec.rb
+++ b/spec/bundler/runtime/with_unbundled_env_spec.rb
@@ -90,9 +90,7 @@ RSpec.describe "Bundler.with_env helpers" do
RUBY
setup_require = "-r#{lib_dir}/bundler/setup"
ENV["BUNDLER_ORIG_RUBYOPT"] = "-W2 #{setup_require} #{ENV["RUBYOPT"]}"
- simulate_bundler_version_when_missing_prerelease_default_gem_activation do
- bundle_exec_ruby bundled_app("source.rb")
- end
+ bundle_exec_ruby bundled_app("source.rb")
expect(last_command.stdboth).not_to include(setup_require)
end
@@ -101,9 +99,7 @@ RSpec.describe "Bundler.with_env helpers" do
print #{modified_env}['RUBYOPT']
RUBY
ENV["BUNDLER_ORIG_RUBYOPT"] = "-W2 -rbundler/setup #{ENV["RUBYOPT"]}"
- simulate_bundler_version_when_missing_prerelease_default_gem_activation do
- bundle_exec_ruby bundled_app("source.rb")
- end
+ bundle_exec_ruby bundled_app("source.rb")
expect(last_command.stdboth).not_to include("-rbundler/setup")
end
@@ -134,7 +130,7 @@ RSpec.describe "Bundler.with_env helpers" do
it_behaves_like "an unbundling helper"
end
- describe "Bundler.clean_env", :bundler => 2 do
+ describe "Bundler.clean_env", bundler: 2 do
let(:modified_env) { "Bundler.clean_env" }
it_behaves_like "an unbundling helper"
@@ -143,7 +139,7 @@ RSpec.describe "Bundler.with_env helpers" do
describe "Bundler.with_original_env" do
it "should set ENV to original_env in the block" do
expected = Bundler.original_env
- actual = Bundler.with_original_env { Bundler::EnvironmentPreserver.env_to_hash(ENV) }
+ actual = Bundler.with_original_env { ENV.to_hash }
expect(actual).to eq(expected)
end
@@ -156,12 +152,12 @@ RSpec.describe "Bundler.with_env helpers" do
end
end
- describe "Bundler.with_clean_env", :bundler => 2 do
+ describe "Bundler.with_clean_env", bundler: 2 do
it "should set ENV to unbundled_env in the block" do
expected = Bundler.unbundled_env
actual = Bundler.ui.silence do
- Bundler.with_clean_env { Bundler::EnvironmentPreserver.env_to_hash(ENV) }
+ Bundler.with_clean_env { ENV.to_hash }
end
expect(actual).to eq(expected)
@@ -179,7 +175,7 @@ RSpec.describe "Bundler.with_env helpers" do
describe "Bundler.with_unbundled_env" do
it "should set ENV to unbundled_env in the block" do
expected = Bundler.unbundled_env
- actual = Bundler.with_unbundled_env { Bundler::EnvironmentPreserver.env_to_hash(ENV) }
+ actual = Bundler.with_unbundled_env { ENV.to_hash }
expect(actual).to eq(expected)
end
@@ -207,7 +203,7 @@ RSpec.describe "Bundler.with_env helpers" do
end
end
- describe "Bundler.clean_system", :bundler => 2 do
+ describe "Bundler.clean_system", bundler: 2 do
before do
create_file("source.rb", <<-'RUBY')
Bundler.ui.silence { Bundler.clean_system("ruby", "-e", "exit(42) unless ENV['BUNDLE_FOO'] == 'bar'") }
@@ -258,7 +254,7 @@ RSpec.describe "Bundler.with_env helpers" do
end
end
- describe "Bundler.clean_exec", :bundler => 2 do
+ describe "Bundler.clean_exec", bundler: 2 do
before do
create_file("source.rb", <<-'RUBY')
Process.fork do
diff --git a/spec/bundler/spec_helper.rb b/spec/bundler/spec_helper.rb
index 80b0ccff4d..66bdcfa028 100644
--- a/spec/bundler/spec_helper.rb
+++ b/spec/bundler/spec_helper.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require "bundler/psyched_yaml"
+require "psych"
require "bundler/vendored_fileutils"
require "bundler/vendored_uri"
require "digest"
@@ -17,13 +17,13 @@ require "rspec/support/differ"
require_relative "support/builders"
require_relative "support/build_metadata"
+require_relative "support/checksums"
require_relative "support/filters"
require_relative "support/helpers"
require_relative "support/indexes"
require_relative "support/matchers"
require_relative "support/permissions"
require_relative "support/platforms"
-require_relative "support/sudo"
$debug = false
@@ -35,12 +35,12 @@ end
RSpec.configure do |config|
config.include Spec::Builders
+ config.include Spec::Checksums
config.include Spec::Helpers
config.include Spec::Indexes
config.include Spec::Matchers
config.include Spec::Path
config.include Spec::Platforms
- config.include Spec::Sudo
config.include Spec::Permissions
# Enable flags like --only-failures and --next-failure
@@ -48,6 +48,9 @@ RSpec.configure do |config|
config.silence_filter_announcements = !ENV["TEST_ENV_NUMBER"].nil?
+ config.backtrace_exclusion_patterns <<
+ %r{./spec/(spec_helper\.rb|support/.+)}
+
config.disable_monkey_patching!
# Since failures cause us to keep a bunch of long strings in memory, stop
@@ -60,6 +63,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|
@@ -71,8 +76,11 @@ RSpec.configure do |config|
require_relative "support/rubygems_ext"
Spec::Rubygems.test_setup
- ENV["BUNDLE_SPEC_RUN"] = "true"
+ ENV["BUNDLER_SPEC_RUN"] = "true"
ENV["BUNDLE_USER_CONFIG"] = ENV["BUNDLE_USER_CACHE"] = ENV["BUNDLE_USER_PLUGIN"] = nil
+ ENV["BUNDLE_APP_CONFIG"] = nil
+ ENV["BUNDLE_SILENCE_ROOT_WARNING"] = nil
+ ENV["RUBYGEMS_GEMDEPS"] = nil
ENV["XDG_CONFIG_HOME"] = nil
ENV["GEMRC"] = nil
@@ -80,7 +88,7 @@ RSpec.configure do |config|
ENV["THOR_COLUMNS"] = "10000"
extend(Spec::Helpers)
- system_gems :bundler, :path => pristine_system_gem_path
+ system_gems :bundler, path: pristine_system_gem_path
end
config.before :all do
@@ -92,26 +100,24 @@ RSpec.configure do |config|
end
config.around :each do |example|
- begin
- FileUtils.cp_r pristine_system_gem_path, system_gem_path
-
- with_gem_path_as(system_gem_path) do
- Bundler.ui.silence { example.run }
-
- all_output = all_commands_output
- if example.exception && !all_output.empty?
- message = all_output + "\n" + example.exception.message
- (class << example.exception; self; end).send(:define_method, :message) do
- message
- end
+ FileUtils.cp_r pristine_system_gem_path, system_gem_path
+
+ with_gem_path_as(system_gem_path) do
+ Bundler.ui.silence { example.run }
+
+ all_output = all_commands_output
+ if example.exception && !all_output.empty?
+ message = all_output + "\n" + example.exception.message
+ (class << example.exception; self; end).send(:define_method, :message) do
+ message
end
end
- ensure
- reset!
end
+ ensure
+ reset!
end
config.after :suite do
- FileUtils.rm_r Spec::Path.pristine_system_gem_path
+ FileUtils.rm_rf Spec::Path.pristine_system_gem_path
end
end
diff --git a/spec/bundler/support/activate.rb b/spec/bundler/support/activate.rb
new file mode 100644
index 0000000000..143b77833d
--- /dev/null
+++ b/spec/bundler/support/activate.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require "rubygems"
+Gem.instance_variable_set(:@ruby, ENV["RUBY"]) if ENV["RUBY"]
+
+require_relative "path"
+bundler_gemspec = Spec::Path.loaded_gemspec
+bundler_gemspec.instance_variable_set(:@full_gem_path, Spec::Path.source_root.to_s)
+bundler_gemspec.activate if bundler_gemspec.respond_to?(:activate)
diff --git a/spec/bundler/support/api_request_limit_hax.rb b/spec/bundler/support/api_request_limit_hax.rb
deleted file mode 100644
index 37ff0203b3..0000000000
--- a/spec/bundler/support/api_request_limit_hax.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-if ENV["BUNDLER_SPEC_API_REQUEST_LIMIT"]
- require_relative "path"
- require "bundler/source"
- require "bundler/source/rubygems"
-
- module Bundler
- class Source
- class Rubygems < Source
- remove_const :API_REQUEST_LIMIT
- API_REQUEST_LIMIT = ENV["BUNDLER_SPEC_API_REQUEST_LIMIT"].to_i
- end
- end
- end
-end
diff --git a/spec/bundler/support/artifice/compact_index.rb b/spec/bundler/support/artifice/compact_index.rb
index 1b314e89ef..ebc4d0ae5b 100644
--- a/spec/bundler/support/artifice/compact_index.rb
+++ b/spec/bundler/support/artifice/compact_index.rb
@@ -1,120 +1,6 @@
# frozen_string_literal: true
-require_relative "endpoint"
-
-$LOAD_PATH.unshift Dir[Spec::Path.base_system_gems.join("gems/compact_index*/lib")].first.to_s
-require "compact_index"
-
-class CompactIndexAPI < Endpoint
- helpers do
- include Spec::Path
-
- def load_spec(name, version, platform, gem_repo)
- full_name = "#{name}-#{version}"
- full_name += "-#{platform}" if platform != "ruby"
- Marshal.load(Bundler.rubygems.inflate(File.binread(gem_repo.join("quick/Marshal.4.8/#{full_name}.gemspec.rz"))))
- end
-
- def etag_response
- response_body = yield
- checksum = Digest(:MD5).hexdigest(response_body)
- return if not_modified?(checksum)
- headers "ETag" => quote(checksum)
- headers "Surrogate-Control" => "max-age=2592000, stale-while-revalidate=60"
- content_type "text/plain"
- requested_range_for(response_body)
- rescue StandardError => e
- puts e
- puts e.backtrace
- raise
- end
-
- def not_modified?(checksum)
- etags = parse_etags(request.env["HTTP_IF_NONE_MATCH"])
-
- return unless etags.include?(checksum)
- headers "ETag" => quote(checksum)
- status 304
- body ""
- end
-
- def requested_range_for(response_body)
- ranges = Rack::Utils.byte_ranges(env, response_body.bytesize)
-
- if ranges
- status 206
- body ranges.map! {|range| slice_body(response_body, range) }.join
- else
- status 200
- body response_body
- end
- end
-
- def quote(string)
- %("#{string}")
- end
-
- def parse_etags(value)
- value ? value.split(/, ?/).select {|s| s.sub!(/"(.*)"/, '\1') } : []
- end
-
- def slice_body(body, range)
- body.byteslice(range)
- end
-
- def gems(gem_repo = default_gem_repo)
- @gems ||= {}
- @gems[gem_repo] ||= begin
- specs = Bundler::Deprecate.skip_during do
- %w[specs.4.8 prerelease_specs.4.8].map do |filename|
- Marshal.load(File.open(gem_repo.join(filename)).read).map do |name, version, platform|
- load_spec(name, version, platform, gem_repo)
- end
- end.flatten
- end
-
- specs.group_by(&:name).map do |name, versions|
- gem_versions = versions.map do |spec|
- deps = spec.dependencies.select {|d| d.type == :runtime }.map do |d|
- reqs = d.requirement.requirements.map {|r| r.join(" ") }.join(", ")
- CompactIndex::Dependency.new(d.name, reqs)
- end
- checksum = begin
- Digest(:SHA256).file("#{gem_repo}/gems/#{spec.original_name}.gem").base64digest
- rescue StandardError
- nil
- end
- CompactIndex::GemVersion.new(spec.version.version, spec.platform.to_s, checksum, nil,
- deps, spec.required_ruby_version.to_s, spec.required_rubygems_version.to_s)
- end
- CompactIndex::Gem.new(name, gem_versions)
- end
- end
- end
- end
-
- get "/names" do
- etag_response do
- CompactIndex.names(gems.map(&:name))
- end
- end
-
- get "/versions" do
- etag_response do
- file = tmp("versions.list")
- FileUtils.rm_f(file)
- file = CompactIndex::VersionsFile.new(file.to_s)
- file.create(gems)
- file.contents
- end
- end
-
- get "/info/:name" do
- etag_response do
- gem = gems.find {|g| g.name == params[:name] }
- CompactIndex.info(gem ? gem.versions : [])
- end
- end
-end
+require_relative "helpers/compact_index"
+require_relative "helpers/artifice"
Artifice.activate_with(CompactIndexAPI)
diff --git a/spec/bundler/support/artifice/compact_index_api_missing.rb b/spec/bundler/support/artifice/compact_index_api_missing.rb
index 6514fde01e..f771f7d1f0 100644
--- a/spec/bundler/support/artifice/compact_index_api_missing.rb
+++ b/spec/bundler/support/artifice/compact_index_api_missing.rb
@@ -1,18 +1,13 @@
# frozen_string_literal: true
-require_relative "compact_index"
-
-Artifice.deactivate
+require_relative "helpers/compact_index"
class CompactIndexApiMissing < CompactIndexAPI
get "/fetch/actual/gem/:id" do
- warn params[:id]
- if params[:id] == "rack-1.0.gemspec.rz"
- halt 404
- else
- File.binread("#{gem_repo2}/quick/Marshal.4.8/#{params[:id]}")
- end
+ halt 404
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(CompactIndexApiMissing)
diff --git a/spec/bundler/support/artifice/compact_index_basic_authentication.rb b/spec/bundler/support/artifice/compact_index_basic_authentication.rb
index 775f1a3977..b9115cdd86 100644
--- a/spec/bundler/support/artifice/compact_index_basic_authentication.rb
+++ b/spec/bundler/support/artifice/compact_index_basic_authentication.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "compact_index"
-
-Artifice.deactivate
+require_relative "helpers/compact_index"
class CompactIndexBasicAuthentication < CompactIndexAPI
before do
@@ -12,4 +10,6 @@ class CompactIndexBasicAuthentication < CompactIndexAPI
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(CompactIndexBasicAuthentication)
diff --git a/spec/bundler/support/artifice/compact_index_checksum_mismatch.rb b/spec/bundler/support/artifice/compact_index_checksum_mismatch.rb
index 1abe64236c..83b147d2ae 100644
--- a/spec/bundler/support/artifice/compact_index_checksum_mismatch.rb
+++ b/spec/bundler/support/artifice/compact_index_checksum_mismatch.rb
@@ -1,16 +1,16 @@
# frozen_string_literal: true
-require_relative "compact_index"
-
-Artifice.deactivate
+require_relative "helpers/compact_index"
class CompactIndexChecksumMismatch < CompactIndexAPI
get "/versions" do
- headers "ETag" => quote("123")
+ headers "Repr-Digest" => "sha-256=:ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=:"
headers "Surrogate-Control" => "max-age=2592000, stale-while-revalidate=60"
content_type "text/plain"
- body ""
+ body "content does not match the checksum"
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(CompactIndexChecksumMismatch)
diff --git a/spec/bundler/support/artifice/compact_index_concurrent_download.rb b/spec/bundler/support/artifice/compact_index_concurrent_download.rb
index 14c31f35a4..5d55b8a72b 100644
--- a/spec/bundler/support/artifice/compact_index_concurrent_download.rb
+++ b/spec/bundler/support/artifice/compact_index_concurrent_download.rb
@@ -1,19 +1,18 @@
# frozen_string_literal: true
-require_relative "compact_index"
-
-Artifice.deactivate
+require_relative "helpers/compact_index"
class CompactIndexConcurrentDownload < CompactIndexAPI
get "/versions" do
versions = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index",
"localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions")
- # Verify the original (empty) content hasn't been deleted, e.g. on a retry
- File.binread(versions) == "" || raise("Original file should be present and empty")
+ # Verify the original content hasn't been deleted, e.g. on a retry
+ data = File.binread(versions)
+ data == "created_at" || raise("Original file should be present with expected content")
# Verify this is only requested once for a partial download
- env["HTTP_RANGE"] || raise("Missing Range header for expected partial download")
+ env["HTTP_RANGE"] == "bytes=#{data.bytesize - 1}-" || raise("Missing Range header for expected partial download")
# Overwrite the file in parallel, which should be then overwritten
# after a successful download to prevent corruption
@@ -29,4 +28,6 @@ class CompactIndexConcurrentDownload < CompactIndexAPI
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(CompactIndexConcurrentDownload)
diff --git a/spec/bundler/support/artifice/compact_index_creds_diff_host.rb b/spec/bundler/support/artifice/compact_index_creds_diff_host.rb
index cfe22c7f51..401e8a98d8 100644
--- a/spec/bundler/support/artifice/compact_index_creds_diff_host.rb
+++ b/spec/bundler/support/artifice/compact_index_creds_diff_host.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "compact_index"
-
-Artifice.deactivate
+require_relative "helpers/compact_index"
class CompactIndexCredsDiffHost < CompactIndexAPI
helpers do
@@ -36,4 +34,6 @@ class CompactIndexCredsDiffHost < CompactIndexAPI
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(CompactIndexCredsDiffHost)
diff --git a/spec/bundler/support/artifice/compact_index_etag_match.rb b/spec/bundler/support/artifice/compact_index_etag_match.rb
new file mode 100644
index 0000000000..08d7b5ec53
--- /dev/null
+++ b/spec/bundler/support/artifice/compact_index_etag_match.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require_relative "helpers/compact_index"
+
+class CompactIndexEtagMatch < CompactIndexAPI
+ get "/versions" do
+ raise "ETag header should be present" unless env["HTTP_IF_NONE_MATCH"]
+ headers "ETag" => env["HTTP_IF_NONE_MATCH"]
+ status 304
+ body ""
+ end
+end
+
+require_relative "helpers/artifice"
+
+Artifice.activate_with(CompactIndexEtagMatch)
diff --git a/spec/bundler/support/artifice/compact_index_extra.rb b/spec/bundler/support/artifice/compact_index_extra.rb
index cec368276a..cd41b3ecca 100644
--- a/spec/bundler/support/artifice/compact_index_extra.rb
+++ b/spec/bundler/support/artifice/compact_index_extra.rb
@@ -1,37 +1,6 @@
# frozen_string_literal: true
-require_relative "compact_index"
-
-Artifice.deactivate
-
-class CompactIndexExtra < CompactIndexAPI
- get "/extra/versions" do
- halt 404
- end
-
- get "/extra/api/v1/dependencies" do
- halt 404
- end
-
- get "/extra/specs.4.8.gz" do
- File.binread("#{gem_repo2}/specs.4.8.gz")
- end
-
- get "/extra/prerelease_specs.4.8.gz" do
- File.binread("#{gem_repo2}/prerelease_specs.4.8.gz")
- end
-
- get "/extra/quick/Marshal.4.8/:id" do
- redirect "/extra/fetch/actual/gem/#{params[:id]}"
- end
-
- get "/extra/fetch/actual/gem/:id" do
- File.binread("#{gem_repo2}/quick/Marshal.4.8/#{params[:id]}")
- end
-
- get "/extra/gems/:id" do
- File.binread("#{gem_repo2}/gems/#{params[:id]}")
- end
-end
+require_relative "helpers/compact_index_extra"
+require_relative "helpers/artifice"
Artifice.activate_with(CompactIndexExtra)
diff --git a/spec/bundler/support/artifice/compact_index_extra_api.rb b/spec/bundler/support/artifice/compact_index_extra_api.rb
index 5cc13421a8..8b9d304ab4 100644
--- a/spec/bundler/support/artifice/compact_index_extra_api.rb
+++ b/spec/bundler/support/artifice/compact_index_extra_api.rb
@@ -1,52 +1,6 @@
# frozen_string_literal: true
-require_relative "compact_index"
-
-Artifice.deactivate
-
-class CompactIndexExtraApi < CompactIndexAPI
- get "/extra/names" do
- etag_response do
- CompactIndex.names(gems(gem_repo4).map(&:name))
- end
- end
-
- get "/extra/versions" do
- etag_response do
- file = tmp("versions.list")
- FileUtils.rm_f(file)
- file = CompactIndex::VersionsFile.new(file.to_s)
- file.create(gems(gem_repo4))
- file.contents
- end
- end
-
- get "/extra/info/:name" do
- etag_response do
- gem = gems(gem_repo4).find {|g| g.name == params[:name] }
- CompactIndex.info(gem ? gem.versions : [])
- end
- end
-
- get "/extra/specs.4.8.gz" do
- File.binread("#{gem_repo4}/specs.4.8.gz")
- end
-
- get "/extra/prerelease_specs.4.8.gz" do
- File.binread("#{gem_repo4}/prerelease_specs.4.8.gz")
- end
-
- get "/extra/quick/Marshal.4.8/:id" do
- redirect "/extra/fetch/actual/gem/#{params[:id]}"
- end
-
- get "/extra/fetch/actual/gem/:id" do
- File.binread("#{gem_repo4}/quick/Marshal.4.8/#{params[:id]}")
- end
-
- get "/extra/gems/:id" do
- File.binread("#{gem_repo4}/gems/#{params[:id]}")
- end
-end
+require_relative "helpers/compact_index_extra_api"
+require_relative "helpers/artifice"
Artifice.activate_with(CompactIndexExtraApi)
diff --git a/spec/bundler/support/artifice/compact_index_extra_api_missing.rb b/spec/bundler/support/artifice/compact_index_extra_api_missing.rb
index b9d757c266..df6ede584c 100644
--- a/spec/bundler/support/artifice/compact_index_extra_api_missing.rb
+++ b/spec/bundler/support/artifice/compact_index_extra_api_missing.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "compact_index_extra_api"
-
-Artifice.deactivate
+require_relative "helpers/compact_index_extra_api"
class CompactIndexExtraAPIMissing < CompactIndexExtraApi
get "/extra/fetch/actual/gem/:id" do
@@ -14,4 +12,6 @@ class CompactIndexExtraAPIMissing < CompactIndexExtraApi
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(CompactIndexExtraAPIMissing)
diff --git a/spec/bundler/support/artifice/compact_index_extra_missing.rb b/spec/bundler/support/artifice/compact_index_extra_missing.rb
index ff1e47a1bb..255c89afdb 100644
--- a/spec/bundler/support/artifice/compact_index_extra_missing.rb
+++ b/spec/bundler/support/artifice/compact_index_extra_missing.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "compact_index_extra"
-
-Artifice.deactivate
+require_relative "helpers/compact_index_extra"
class CompactIndexExtraMissing < CompactIndexExtra
get "/extra/fetch/actual/gem/:id" do
@@ -14,4 +12,6 @@ class CompactIndexExtraMissing < CompactIndexExtra
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(CompactIndexExtraMissing)
diff --git a/spec/bundler/support/artifice/compact_index_forbidden.rb b/spec/bundler/support/artifice/compact_index_forbidden.rb
index 3eebe0fbd8..18c30ed9a2 100644
--- a/spec/bundler/support/artifice/compact_index_forbidden.rb
+++ b/spec/bundler/support/artifice/compact_index_forbidden.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "compact_index"
-
-Artifice.deactivate
+require_relative "helpers/compact_index"
class CompactIndexForbidden < CompactIndexAPI
get "/versions" do
@@ -10,4 +8,6 @@ class CompactIndexForbidden < CompactIndexAPI
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(CompactIndexForbidden)
diff --git a/spec/bundler/support/artifice/compact_index_host_redirect.rb b/spec/bundler/support/artifice/compact_index_host_redirect.rb
index 304c897d68..4f82bf3812 100644
--- a/spec/bundler/support/artifice/compact_index_host_redirect.rb
+++ b/spec/bundler/support/artifice/compact_index_host_redirect.rb
@@ -1,11 +1,9 @@
# frozen_string_literal: true
-require_relative "compact_index"
-
-Artifice.deactivate
+require_relative "helpers/compact_index"
class CompactIndexHostRedirect < CompactIndexAPI
- get "/fetch/actual/gem/:id", :host_name => "localgemserver.test" do
+ get "/fetch/actual/gem/:id", host_name: "localgemserver.test" do
redirect "http://bundler.localgemserver.test#{request.path_info}"
end
@@ -18,4 +16,6 @@ class CompactIndexHostRedirect < CompactIndexAPI
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(CompactIndexHostRedirect)
diff --git a/spec/bundler/support/artifice/compact_index_no_gem.rb b/spec/bundler/support/artifice/compact_index_no_gem.rb
index 0a4be08a46..71f6629688 100644
--- a/spec/bundler/support/artifice/compact_index_no_gem.rb
+++ b/spec/bundler/support/artifice/compact_index_no_gem.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "compact_index"
-
-Artifice.deactivate
+require_relative "helpers/compact_index"
class CompactIndexNoGem < CompactIndexAPI
get "/gems/:id" do
@@ -10,4 +8,6 @@ class CompactIndexNoGem < CompactIndexAPI
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(CompactIndexNoGem)
diff --git a/spec/bundler/support/artifice/compact_index_partial_update.rb b/spec/bundler/support/artifice/compact_index_partial_update.rb
index cb1c7b9481..f111d91ef9 100644
--- a/spec/bundler/support/artifice/compact_index_partial_update.rb
+++ b/spec/bundler/support/artifice/compact_index_partial_update.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "compact_index"
-
-Artifice.deactivate
+require_relative "helpers/compact_index"
class CompactIndexPartialUpdate < CompactIndexAPI
# Stub the server to never return 304s. This simulates the behaviour of
@@ -25,7 +23,7 @@ class CompactIndexPartialUpdate < CompactIndexAPI
# Verify that a partial request is made, starting from the index of the
# final byte of the cached file.
unless env["HTTP_RANGE"] == "bytes=#{File.binread(cached_versions_path).bytesize - 1}-"
- raise("Range header should be present, and start from the index of the final byte of the cache.")
+ raise("Range header should be present, and start from the index of the final byte of the cache. #{env["HTTP_RANGE"].inspect}")
end
etag_response do
@@ -35,4 +33,6 @@ class CompactIndexPartialUpdate < CompactIndexAPI
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(CompactIndexPartialUpdate)
diff --git a/spec/bundler/support/artifice/compact_index_partial_update_bad_digest.rb b/spec/bundler/support/artifice/compact_index_partial_update_bad_digest.rb
new file mode 100644
index 0000000000..ac04336636
--- /dev/null
+++ b/spec/bundler/support/artifice/compact_index_partial_update_bad_digest.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require_relative "helpers/compact_index"
+
+# The purpose of this Artifice is to test that an incremental response is invalidated
+# and a second request is issued for the full content.
+class CompactIndexPartialUpdateBadDigest < CompactIndexAPI
+ def partial_update_bad_digest
+ response_body = yield
+ if request.env["HTTP_RANGE"]
+ headers "Repr-Digest" => "sha-256=:#{Digest::SHA256.base64digest("wrong digest on ranged request")}:"
+ else
+ headers "Repr-Digest" => "sha-256=:#{Digest::SHA256.base64digest(response_body)}:"
+ end
+ 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_bad_digest do
+ file = tmp("versions.list")
+ FileUtils.rm_f(file)
+ file = CompactIndex::VersionsFile.new(file.to_s)
+ file.create(gems)
+ file.contents([], calculate_info_checksums: true)
+ end
+ end
+
+ get "/info/:name" do
+ partial_update_bad_digest do
+ gem = gems.find {|g| g.name == params[:name] }
+ CompactIndex.info(gem ? gem.versions : [])
+ end
+ end
+end
+
+require_relative "helpers/artifice"
+
+Artifice.activate_with(CompactIndexPartialUpdateBadDigest)
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_digest_not_incremental.rb
index acf76dfbf0..99bae039f0 100644
--- a/spec/bundler/support/artifice/compact_index_partial_update_no_etag_not_incremental.rb
+++ b/spec/bundler/support/artifice/compact_index_partial_update_no_digest_not_incremental.rb
@@ -1,11 +1,11 @@
# frozen_string_literal: true
-require_relative "compact_index"
+require_relative "helpers/compact_index"
-Artifice.deactivate
-
-class CompactIndexPartialUpdateNoEtagNotIncremental < CompactIndexAPI
- def partial_update_no_etag
+# The purpose of this Artifice is to test that an incremental response is ignored
+# when the digest is not present to verify that the partial response is valid.
+class CompactIndexPartialUpdateNoDigestNotIncremental < CompactIndexAPI
+ def partial_update_no_digest
response_body = yield
headers "Surrogate-Control" => "max-age=2592000, stale-while-revalidate=60"
content_type "text/plain"
@@ -13,12 +13,12 @@ class CompactIndexPartialUpdateNoEtagNotIncremental < CompactIndexAPI
end
get "/versions" do
- partial_update_no_etag do
+ partial_update_no_digest 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")
+ 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
@@ -27,7 +27,7 @@ class CompactIndexPartialUpdateNoEtagNotIncremental < CompactIndexAPI
end
get "/info/:name" do
- partial_update_no_etag do
+ partial_update_no_digest do
gem = gems.find {|g| g.name == params[:name] }
lines = CompactIndex.info(gem ? gem.versions : []).split("\n")
@@ -37,4 +37,6 @@ class CompactIndexPartialUpdateNoEtagNotIncremental < CompactIndexAPI
end
end
-Artifice.activate_with(CompactIndexPartialUpdateNoEtagNotIncremental)
+require_relative "helpers/artifice"
+
+Artifice.activate_with(CompactIndexPartialUpdateNoDigestNotIncremental)
diff --git a/spec/bundler/support/artifice/compact_index_precompiled_before.rb b/spec/bundler/support/artifice/compact_index_precompiled_before.rb
new file mode 100644
index 0000000000..b5f72f546a
--- /dev/null
+++ b/spec/bundler/support/artifice/compact_index_precompiled_before.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require_relative "helpers/compact_index"
+
+class CompactIndexPrecompiledBefore < CompactIndexAPI
+ get "/info/:name" do
+ etag_response do
+ gem = gems.find {|g| g.name == params[:name] }
+ move_ruby_variant_to_the_end(CompactIndex.info(gem ? gem.versions : []))
+ end
+ end
+
+ private
+
+ def move_ruby_variant_to_the_end(response)
+ lines = response.split("\n")
+ ruby = lines.find {|line| /\A\d+\.\d+\.\d* \|/.match(line) }
+ lines.delete(ruby)
+ lines.push(ruby).join("\n")
+ end
+end
+
+require_relative "helpers/artifice"
+
+Artifice.activate_with(CompactIndexPrecompiledBefore)
diff --git a/spec/bundler/support/artifice/compact_index_range_ignored.rb b/spec/bundler/support/artifice/compact_index_range_ignored.rb
new file mode 100644
index 0000000000..2303682c1f
--- /dev/null
+++ b/spec/bundler/support/artifice/compact_index_range_ignored.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require_relative "helpers/compact_index"
+
+class CompactIndexRangeIgnored < CompactIndexAPI
+ # Stub the server to not return 304 so that we don't bypass all the logic
+ def not_modified?(_checksum)
+ false
+ end
+
+ get "/versions" do
+ cached_versions_path = File.join(
+ Bundler.rubygems.user_home, ".bundle", "cache", "compact_index",
+ "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions"
+ )
+
+ # Verify a cached copy of the versions file exists
+ unless File.binread(cached_versions_path).size > 0
+ raise("Cached versions file should be present and have content")
+ end
+
+ # Verify that a partial request is made, starting from the index of the
+ # final byte of the cached file.
+ unless env.delete("HTTP_RANGE")
+ raise("Expected client to write the full response on the first try")
+ end
+
+ etag_response do
+ file = tmp("versions.list")
+ FileUtils.rm_f(file)
+ file = CompactIndex::VersionsFile.new(file.to_s)
+ file.create(gems)
+ file.contents
+ end
+ end
+end
+
+require_relative "helpers/artifice"
+
+Artifice.activate_with(CompactIndexRangeIgnored)
diff --git a/spec/bundler/support/artifice/compact_index_range_not_satisfiable.rb b/spec/bundler/support/artifice/compact_index_range_not_satisfiable.rb
index bb616125bb..8a7c4b79b0 100644
--- a/spec/bundler/support/artifice/compact_index_range_not_satisfiable.rb
+++ b/spec/bundler/support/artifice/compact_index_range_not_satisfiable.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "compact_index"
-
-Artifice.deactivate
+require_relative "helpers/compact_index"
class CompactIndexRangeNotSatisfiable < CompactIndexAPI
get "/versions" do
@@ -31,4 +29,6 @@ class CompactIndexRangeNotSatisfiable < CompactIndexAPI
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(CompactIndexRangeNotSatisfiable)
diff --git a/spec/bundler/support/artifice/compact_index_rate_limited.rb b/spec/bundler/support/artifice/compact_index_rate_limited.rb
index 570105e2a0..4495491635 100644
--- a/spec/bundler/support/artifice/compact_index_rate_limited.rb
+++ b/spec/bundler/support/artifice/compact_index_rate_limited.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "compact_index"
-
-Artifice.deactivate
+require_relative "helpers/compact_index"
class CompactIndexRateLimited < CompactIndexAPI
class RequestCounter
@@ -45,4 +43,6 @@ class CompactIndexRateLimited < CompactIndexAPI
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(CompactIndexRateLimited)
diff --git a/spec/bundler/support/artifice/compact_index_redirects.rb b/spec/bundler/support/artifice/compact_index_redirects.rb
index 99adc797bf..f7ba393239 100644
--- a/spec/bundler/support/artifice/compact_index_redirects.rb
+++ b/spec/bundler/support/artifice/compact_index_redirects.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "compact_index"
-
-Artifice.deactivate
+require_relative "helpers/compact_index"
class CompactIndexRedirect < CompactIndexAPI
get "/fetch/actual/gem/:id" do
@@ -18,4 +16,6 @@ class CompactIndexRedirect < CompactIndexAPI
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(CompactIndexRedirect)
diff --git a/spec/bundler/support/artifice/compact_index_strict_basic_authentication.rb b/spec/bundler/support/artifice/compact_index_strict_basic_authentication.rb
index 7d427b5382..96259385e7 100644
--- a/spec/bundler/support/artifice/compact_index_strict_basic_authentication.rb
+++ b/spec/bundler/support/artifice/compact_index_strict_basic_authentication.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "compact_index"
-
-Artifice.deactivate
+require_relative "helpers/compact_index"
class CompactIndexStrictBasicAuthentication < CompactIndexAPI
before do
@@ -12,9 +10,11 @@ class CompactIndexStrictBasicAuthentication < CompactIndexAPI
# Only accepts password == "password"
unless env["HTTP_AUTHORIZATION"] == "Basic dXNlcjpwYXNz"
- halt 403, "Authentication failed"
+ halt 401, "Authentication failed"
end
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(CompactIndexStrictBasicAuthentication)
diff --git a/spec/bundler/support/artifice/compact_index_wrong_dependencies.rb b/spec/bundler/support/artifice/compact_index_wrong_dependencies.rb
index 036fac70b3..15850599b6 100644
--- a/spec/bundler/support/artifice/compact_index_wrong_dependencies.rb
+++ b/spec/bundler/support/artifice/compact_index_wrong_dependencies.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "compact_index"
-
-Artifice.deactivate
+require_relative "helpers/compact_index"
class CompactIndexWrongDependencies < CompactIndexAPI
get "/info/:name" do
@@ -14,4 +12,6 @@ class CompactIndexWrongDependencies < CompactIndexAPI
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(CompactIndexWrongDependencies)
diff --git a/spec/bundler/support/artifice/compact_index_wrong_gem_checksum.rb b/spec/bundler/support/artifice/compact_index_wrong_gem_checksum.rb
index 8add32b88f..9bd2ca0a9d 100644
--- a/spec/bundler/support/artifice/compact_index_wrong_gem_checksum.rb
+++ b/spec/bundler/support/artifice/compact_index_wrong_gem_checksum.rb
@@ -1,15 +1,14 @@
# frozen_string_literal: true
-require_relative "compact_index"
-
-Artifice.deactivate
+require_relative "helpers/compact_index"
class CompactIndexWrongGemChecksum < CompactIndexAPI
get "/info/:name" do
etag_response do
name = params[:name]
gem = gems.find {|g| g.name == name }
- checksum = ENV.fetch("BUNDLER_SPEC_#{name.upcase}_CHECKSUM") { "ab" * 22 }
+ # This generates the hexdigest "2222222222222222222222222222222222222222222222222222222222222222"
+ checksum = ENV.fetch("BUNDLER_SPEC_#{name.upcase}_CHECKSUM") { "IiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiI=" }
versions = gem ? gem.versions : []
versions.each {|v| v.checksum = checksum }
CompactIndex.info(versions)
@@ -17,4 +16,6 @@ class CompactIndexWrongGemChecksum < CompactIndexAPI
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(CompactIndexWrongGemChecksum)
diff --git a/spec/bundler/support/artifice/endpoint.rb b/spec/bundler/support/artifice/endpoint.rb
index 4a820e5a3f..15242a7942 100644
--- a/spec/bundler/support/artifice/endpoint.rb
+++ b/spec/bundler/support/artifice/endpoint.rb
@@ -1,115 +1,6 @@
# frozen_string_literal: true
-require_relative "../path"
-
-$LOAD_PATH.unshift(*Dir[Spec::Path.base_system_gems.join("gems/{artifice,mustermann,rack,tilt,sinatra,ruby2_keywords}-*/lib")].map(&:to_s))
-
-require "artifice"
-require "sinatra/base"
-
-ALL_REQUESTS = [] # rubocop:disable Style/MutableConstant
-ALL_REQUESTS_MUTEX = Thread::Mutex.new
-
-at_exit do
- if expected = ENV["BUNDLER_SPEC_ALL_REQUESTS"]
- expected = expected.split("\n").sort
- actual = ALL_REQUESTS.sort
-
- unless expected == actual
- raise "Unexpected requests!\nExpected:\n\t#{expected.join("\n\t")}\n\nActual:\n\t#{actual.join("\n\t")}"
- end
- end
-end
-
-class Endpoint < Sinatra::Base
- def self.all_requests
- @all_requests ||= []
- end
-
- set :raise_errors, true
- set :show_exceptions, false
-
- def call!(*)
- super.tap do
- ALL_REQUESTS_MUTEX.synchronize do
- ALL_REQUESTS << @request.url
- end
- end
- end
-
- helpers do
- include Spec::Path
-
- def default_gem_repo
- if ENV["BUNDLER_SPEC_GEM_REPO"]
- Pathname.new(ENV["BUNDLER_SPEC_GEM_REPO"])
- else
- case request.host
- when "gem.repo1"
- Spec::Path.gem_repo1
- when "gem.repo2"
- Spec::Path.gem_repo2
- when "gem.repo3"
- Spec::Path.gem_repo3
- when "gem.repo4"
- Spec::Path.gem_repo4
- 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|
- Marshal.load(File.open(gem_repo.join(filename)).read)
- end.inject(:+)
-
- all_specs.map do |name, version, platform|
- spec = load_spec(name, version, platform, gem_repo)
- next unless gem_names.include?(spec.name)
- {
- :name => spec.name,
- :number => spec.version.version,
- :platform => spec.platform.to_s,
- :dependencies => spec.dependencies.select {|dep| dep.type == :runtime }.map do |dep|
- [dep.name, dep.requirement.requirements.map {|a| a.join(" ") }.join(", ")]
- end,
- }
- end.compact
- end
-
- def load_spec(name, version, platform, gem_repo)
- full_name = "#{name}-#{version}"
- full_name += "-#{platform}" if platform != "ruby"
- Marshal.load(Bundler.rubygems.inflate(File.binread(gem_repo.join("quick/Marshal.4.8/#{full_name}.gemspec.rz"))))
- end
- end
-
- get "/quick/Marshal.4.8/:id" do
- redirect "/fetch/actual/gem/#{params[:id]}"
- end
-
- get "/fetch/actual/gem/:id" do
- File.binread("#{default_gem_repo}/quick/Marshal.4.8/#{params[:id]}")
- end
-
- get "/gems/:id" do
- File.binread("#{default_gem_repo}/gems/#{params[:id]}")
- end
-
- get "/api/v1/dependencies" do
- Marshal.dump(dependencies_for(params[:gems]))
- end
-
- get "/specs.4.8.gz" do
- File.binread("#{default_gem_repo}/specs.4.8.gz")
- end
-
- get "/prerelease_specs.4.8.gz" do
- File.binread("#{default_gem_repo}/prerelease_specs.4.8.gz")
- end
-end
+require_relative "helpers/endpoint"
+require_relative "helpers/artifice"
Artifice.activate_with(Endpoint)
diff --git a/spec/bundler/support/artifice/endpoint_500.rb b/spec/bundler/support/artifice/endpoint_500.rb
index 0ce8dfeaad..b1ed1964c8 100644
--- a/spec/bundler/support/artifice/endpoint_500.rb
+++ b/spec/bundler/support/artifice/endpoint_500.rb
@@ -2,17 +2,16 @@
require_relative "../path"
-$LOAD_PATH.unshift(*Dir[Spec::Path.base_system_gems.join("gems/{artifice,mustermann,rack,tilt,sinatra,ruby2_keywords}-*/lib")].map(&:to_s))
+$LOAD_PATH.unshift(*Dir[Spec::Path.base_system_gem_path.join("gems/{mustermann,rack,tilt,sinatra,ruby2_keywords,base64}-*/lib")].map(&:to_s))
-require "artifice"
require "sinatra/base"
-Artifice.deactivate
-
class Endpoint500 < Sinatra::Base
before do
halt 500
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(Endpoint500)
diff --git a/spec/bundler/support/artifice/endpoint_api_forbidden.rb b/spec/bundler/support/artifice/endpoint_api_forbidden.rb
index edc2463424..6bdc5896d6 100644
--- a/spec/bundler/support/artifice/endpoint_api_forbidden.rb
+++ b/spec/bundler/support/artifice/endpoint_api_forbidden.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "endpoint"
-
-Artifice.deactivate
+require_relative "helpers/endpoint"
class EndpointApiForbidden < Endpoint
get "/api/v1/dependencies" do
@@ -10,4 +8,6 @@ class EndpointApiForbidden < Endpoint
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(EndpointApiForbidden)
diff --git a/spec/bundler/support/artifice/endpoint_api_missing.rb b/spec/bundler/support/artifice/endpoint_api_missing.rb
deleted file mode 100644
index 755c42e836..0000000000
--- a/spec/bundler/support/artifice/endpoint_api_missing.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "endpoint"
-
-Artifice.deactivate
-
-class EndpointApiMissing < Endpoint
- get "/fetch/actual/gem/:id" do
- warn params[:id]
- if params[:id] == "rack-1.0.gemspec.rz"
- halt 404
- else
- File.binread("#{gem_repo2}/quick/Marshal.4.8/#{params[:id]}")
- end
- end
-end
-
-Artifice.activate_with(EndpointApiMissing)
diff --git a/spec/bundler/support/artifice/endpoint_basic_authentication.rb b/spec/bundler/support/artifice/endpoint_basic_authentication.rb
index ff3d1493d6..e8e3569e63 100644
--- a/spec/bundler/support/artifice/endpoint_basic_authentication.rb
+++ b/spec/bundler/support/artifice/endpoint_basic_authentication.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "endpoint"
-
-Artifice.deactivate
+require_relative "helpers/endpoint"
class EndpointBasicAuthentication < Endpoint
before do
@@ -12,4 +10,6 @@ class EndpointBasicAuthentication < Endpoint
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(EndpointBasicAuthentication)
diff --git a/spec/bundler/support/artifice/endpoint_creds_diff_host.rb b/spec/bundler/support/artifice/endpoint_creds_diff_host.rb
index 8b8972cedd..ce30de0a68 100644
--- a/spec/bundler/support/artifice/endpoint_creds_diff_host.rb
+++ b/spec/bundler/support/artifice/endpoint_creds_diff_host.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "endpoint"
-
-Artifice.deactivate
+require_relative "helpers/endpoint"
class EndpointCredsDiffHost < Endpoint
helpers do
@@ -36,4 +34,6 @@ class EndpointCredsDiffHost < Endpoint
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(EndpointCredsDiffHost)
diff --git a/spec/bundler/support/artifice/endpoint_extra.rb b/spec/bundler/support/artifice/endpoint_extra.rb
index 942c4352b7..021fd435fe 100644
--- a/spec/bundler/support/artifice/endpoint_extra.rb
+++ b/spec/bundler/support/artifice/endpoint_extra.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "endpoint"
-
-Artifice.deactivate
+require_relative "helpers/endpoint"
class EndpointExtra < Endpoint
get "/extra/api/v1/dependencies" do
@@ -30,4 +28,6 @@ class EndpointExtra < Endpoint
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(EndpointExtra)
diff --git a/spec/bundler/support/artifice/endpoint_extra_api.rb b/spec/bundler/support/artifice/endpoint_extra_api.rb
index 1cfef7a7fc..a965af6e73 100644
--- a/spec/bundler/support/artifice/endpoint_extra_api.rb
+++ b/spec/bundler/support/artifice/endpoint_extra_api.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "endpoint"
-
-Artifice.deactivate
+require_relative "helpers/endpoint"
class EndpointExtraApi < Endpoint
get "/extra/api/v1/dependencies" do
@@ -31,4 +29,6 @@ class EndpointExtraApi < Endpoint
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(EndpointExtraApi)
diff --git a/spec/bundler/support/artifice/endpoint_extra_missing.rb b/spec/bundler/support/artifice/endpoint_extra_missing.rb
index 5fd9238207..73e2defb32 100644
--- a/spec/bundler/support/artifice/endpoint_extra_missing.rb
+++ b/spec/bundler/support/artifice/endpoint_extra_missing.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "endpoint_extra"
-
-Artifice.deactivate
+require_relative "helpers/endpoint_extra"
class EndpointExtraMissing < EndpointExtra
get "/extra/fetch/actual/gem/:id" do
@@ -14,4 +12,6 @@ class EndpointExtraMissing < EndpointExtra
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(EndpointExtraMissing)
diff --git a/spec/bundler/support/artifice/endpoint_fallback.rb b/spec/bundler/support/artifice/endpoint_fallback.rb
index 08edf232e3..742e563f07 100644
--- a/spec/bundler/support/artifice/endpoint_fallback.rb
+++ b/spec/bundler/support/artifice/endpoint_fallback.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "endpoint"
-
-Artifice.deactivate
+require_relative "helpers/endpoint"
class EndpointFallback < Endpoint
DEPENDENCY_LIMIT = 60
@@ -16,4 +14,6 @@ class EndpointFallback < Endpoint
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(EndpointFallback)
diff --git a/spec/bundler/support/artifice/endpoint_host_redirect.rb b/spec/bundler/support/artifice/endpoint_host_redirect.rb
index 338cbcad00..6ce51bed93 100644
--- a/spec/bundler/support/artifice/endpoint_host_redirect.rb
+++ b/spec/bundler/support/artifice/endpoint_host_redirect.rb
@@ -1,11 +1,9 @@
# frozen_string_literal: true
-require_relative "endpoint"
-
-Artifice.deactivate
+require_relative "helpers/endpoint"
class EndpointHostRedirect < Endpoint
- get "/fetch/actual/gem/:id", :host_name => "localgemserver.test" do
+ get "/fetch/actual/gem/:id", host_name: "localgemserver.test" do
redirect "http://bundler.localgemserver.test#{request.path_info}"
end
@@ -14,4 +12,6 @@ class EndpointHostRedirect < Endpoint
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(EndpointHostRedirect)
diff --git a/spec/bundler/support/artifice/endpoint_marshal_fail.rb b/spec/bundler/support/artifice/endpoint_marshal_fail.rb
index 22c13e3e17..74ce321de6 100644
--- a/spec/bundler/support/artifice/endpoint_marshal_fail.rb
+++ b/spec/bundler/support/artifice/endpoint_marshal_fail.rb
@@ -1,13 +1,6 @@
# frozen_string_literal: true
-require_relative "endpoint_fallback"
-
-Artifice.deactivate
-
-class EndpointMarshalFail < EndpointFallback
- get "/api/v1/dependencies" do
- "f0283y01hasf"
- end
-end
+require_relative "helpers/endpoint_marshal_fail"
+require_relative "helpers/artifice"
Artifice.activate_with(EndpointMarshalFail)
diff --git a/spec/bundler/support/artifice/endpoint_marshal_fail_basic_authentication.rb b/spec/bundler/support/artifice/endpoint_marshal_fail_basic_authentication.rb
index c341c3993f..ea4cfbe965 100644
--- a/spec/bundler/support/artifice/endpoint_marshal_fail_basic_authentication.rb
+++ b/spec/bundler/support/artifice/endpoint_marshal_fail_basic_authentication.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "endpoint_marshal_fail"
-
-Artifice.deactivate
+require_relative "helpers/endpoint_marshal_fail"
class EndpointMarshalFailBasicAuthentication < EndpointMarshalFail
before do
@@ -12,4 +10,6 @@ class EndpointMarshalFailBasicAuthentication < EndpointMarshalFail
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(EndpointMarshalFailBasicAuthentication)
diff --git a/spec/bundler/support/artifice/endpoint_mirror_source.rb b/spec/bundler/support/artifice/endpoint_mirror_source.rb
index 788a9027f3..fed7a746b9 100644
--- a/spec/bundler/support/artifice/endpoint_mirror_source.rb
+++ b/spec/bundler/support/artifice/endpoint_mirror_source.rb
@@ -1,10 +1,10 @@
# frozen_string_literal: true
-require_relative "endpoint"
+require_relative "helpers/endpoint"
class EndpointMirrorSource < Endpoint
get "/gems/:id" do
- if request.env["HTTP_X_GEMFILE_SOURCE"] == "https://server.example.org/"
+ if request.env["HTTP_X_GEMFILE_SOURCE"] == "https://server.example.org/" && request.env["HTTP_USER_AGENT"].start_with?("bundler")
File.binread("#{gem_repo1}/gems/#{params[:id]}")
else
halt 500
@@ -12,4 +12,6 @@ class EndpointMirrorSource < Endpoint
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(EndpointMirrorSource)
diff --git a/spec/bundler/support/artifice/endpoint_redirect.rb b/spec/bundler/support/artifice/endpoint_redirect.rb
index ee97fccf64..84f546ba9d 100644
--- a/spec/bundler/support/artifice/endpoint_redirect.rb
+++ b/spec/bundler/support/artifice/endpoint_redirect.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "endpoint"
-
-Artifice.deactivate
+require_relative "helpers/endpoint"
class EndpointRedirect < Endpoint
get "/fetch/actual/gem/:id" do
@@ -14,4 +12,6 @@ class EndpointRedirect < Endpoint
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(EndpointRedirect)
diff --git a/spec/bundler/support/artifice/endpoint_strict_basic_authentication.rb b/spec/bundler/support/artifice/endpoint_strict_basic_authentication.rb
index 4d4da08770..dff360c5c5 100644
--- a/spec/bundler/support/artifice/endpoint_strict_basic_authentication.rb
+++ b/spec/bundler/support/artifice/endpoint_strict_basic_authentication.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "endpoint"
-
-Artifice.deactivate
+require_relative "helpers/endpoint"
class EndpointStrictBasicAuthentication < Endpoint
before do
@@ -12,9 +10,11 @@ class EndpointStrictBasicAuthentication < Endpoint
# Only accepts password == "password"
unless env["HTTP_AUTHORIZATION"] == "Basic dXNlcjpwYXNz"
- halt 403, "Authentication failed"
+ halt 401, "Authentication failed"
end
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(EndpointStrictBasicAuthentication)
diff --git a/spec/bundler/support/artifice/endpoint_timeout.rb b/spec/bundler/support/artifice/endpoint_timeout.rb
index c118da1893..86b793e499 100644
--- a/spec/bundler/support/artifice/endpoint_timeout.rb
+++ b/spec/bundler/support/artifice/endpoint_timeout.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
-require_relative "endpoint_fallback"
-
-Artifice.deactivate
+require_relative "helpers/endpoint_fallback"
class EndpointTimeout < EndpointFallback
SLEEP_TIMEOUT = 3
@@ -12,4 +10,6 @@ class EndpointTimeout < EndpointFallback
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(EndpointTimeout)
diff --git a/spec/bundler/support/artifice/fail.rb b/spec/bundler/support/artifice/fail.rb
index f69f2eccc6..8822e5b8e2 100644
--- a/spec/bundler/support/artifice/fail.rb
+++ b/spec/bundler/support/artifice/fail.rb
@@ -1,15 +1,11 @@
# frozen_string_literal: true
-require "net/http"
+require "bundler/vendored_net_http"
-# We can't use artifice here because it uses rack
-
-module Artifice; end # for < 2.0, Net::HTTP::Persistent::SSLReuse
-
-class Fail < Net::HTTP
- # Net::HTTP uses a @newimpl instance variable to decide whether
+class Fail < Gem::Net::HTTP
+ # Gem::Net::HTTP uses a @newimpl instance variable to decide whether
# to use a legacy implementation. Since we are subclassing
- # Net::HTTP, we must set it
+ # Gem::Net::HTTP, we must set it
@newimpl = true
def request(req, body = nil, &block)
@@ -21,14 +17,11 @@ class Fail < Net::HTTP
end
def exception(req)
- name = ENV.fetch("BUNDLER_SPEC_EXCEPTION") { "Errno::ENETUNREACH" }
- const = name.split("::").reduce(Object) {|mod, sym| mod.const_get(sym) }
- const.new("host down: Bundler spec artifice fail! #{req["PATH_INFO"]}")
+ Errno::ENETUNREACH.new("host down: Bundler spec artifice fail! #{req["PATH_INFO"]}")
end
end
-# Replace Net::HTTP with our failing subclass
-::Net.class_eval do
- remove_const(:HTTP)
- const_set(:HTTP, ::Fail)
-end
+require_relative "helpers/artifice"
+
+# Replace Gem::Net::HTTP with our failing subclass
+Artifice.replace_net_http(::Fail)
diff --git a/spec/bundler/support/artifice/helpers/artifice.rb b/spec/bundler/support/artifice/helpers/artifice.rb
new file mode 100644
index 0000000000..788268295c
--- /dev/null
+++ b/spec/bundler/support/artifice/helpers/artifice.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+# This module was initially borrowed from https://github.com/wycats/artifice
+module Artifice
+ # Activate Artifice with a particular Rack endpoint.
+ #
+ # Calling this method will replace the Gem::Net::HTTP system
+ # with a replacement that routes all requests to the
+ # Rack endpoint.
+ #
+ # @param [#call] endpoint A valid Rack endpoint
+ def self.activate_with(endpoint)
+ require_relative "rack_request"
+
+ Net::HTTP.endpoint = endpoint
+ replace_net_http(Artifice::Net::HTTP)
+ end
+
+ # Deactivate the Artifice replacement.
+ def self.deactivate
+ replace_net_http(::Gem::Net::HTTP)
+ end
+
+ def self.replace_net_http(value)
+ ::Gem::Net.class_eval do
+ remove_const(:HTTP)
+ const_set(:HTTP, value)
+ end
+ end
+end
diff --git a/spec/bundler/support/artifice/helpers/compact_index.rb b/spec/bundler/support/artifice/helpers/compact_index.rb
new file mode 100644
index 0000000000..a803a2d30a
--- /dev/null
+++ b/spec/bundler/support/artifice/helpers/compact_index.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+
+require_relative "endpoint"
+
+$LOAD_PATH.unshift Dir[Spec::Path.base_system_gem_path.join("gems/compact_index*/lib")].first.to_s
+require "compact_index"
+require "digest"
+
+class CompactIndexAPI < Endpoint
+ helpers do
+ include Spec::Path
+
+ def load_spec(name, version, platform, gem_repo)
+ full_name = "#{name}-#{version}"
+ full_name += "-#{platform}" if platform != "ruby"
+ Marshal.load(Bundler.rubygems.inflate(File.binread(gem_repo.join("quick/Marshal.4.8/#{full_name}.gemspec.rz"))))
+ end
+
+ def etag_response
+ response_body = yield
+ etag = Digest::MD5.hexdigest(response_body)
+ headers "ETag" => quote(etag)
+ return if not_modified?(etag)
+ headers "Repr-Digest" => "sha-256=:#{Digest::SHA256.base64digest(response_body)}:"
+ headers "Surrogate-Control" => "max-age=2592000, stale-while-revalidate=60"
+ content_type "text/plain"
+ requested_range_for(response_body)
+ rescue StandardError => e
+ puts e
+ puts e.backtrace
+ raise
+ end
+
+ def not_modified?(etag)
+ etags = parse_etags(request.env["HTTP_IF_NONE_MATCH"])
+
+ return unless etags.include?(etag)
+ status 304
+ body ""
+ end
+
+ def requested_range_for(response_body)
+ ranges = Rack::Utils.byte_ranges(env, response_body.bytesize)
+
+ if ranges
+ status 206
+ body ranges.map! {|range| slice_body(response_body, range) }.join
+ else
+ status 200
+ body response_body
+ end
+ end
+
+ def quote(string)
+ %("#{string}")
+ end
+
+ def parse_etags(value)
+ value ? value.split(/, ?/).select {|s| s.sub!(/"(.*)"/, '\1') } : []
+ end
+
+ def slice_body(body, range)
+ body.byteslice(range)
+ end
+
+ def gems(gem_repo = default_gem_repo)
+ @gems ||= {}
+ @gems[gem_repo] ||= begin
+ specs = Bundler::Deprecate.skip_during do
+ %w[specs.4.8 prerelease_specs.4.8].map do |filename|
+ Marshal.load(File.open(gem_repo.join(filename)).read).map do |name, version, platform|
+ load_spec(name, version, platform, gem_repo)
+ end
+ end.flatten
+ end
+
+ specs.group_by(&:name).map do |name, versions|
+ gem_versions = versions.map do |spec|
+ deps = spec.runtime_dependencies.map do |d|
+ reqs = d.requirement.requirements.map {|r| r.join(" ") }.join(", ")
+ CompactIndex::Dependency.new(d.name, reqs)
+ end
+ begin
+ checksum = ENV.fetch("BUNDLER_SPEC_#{name.upcase}_CHECKSUM") do
+ Digest(:SHA256).file("#{gem_repo}/gems/#{spec.original_name}.gem").hexdigest
+ end
+ rescue StandardError
+ checksum = nil
+ end
+ CompactIndex::GemVersion.new(spec.version.version, spec.platform.to_s, checksum, nil,
+ deps, spec.required_ruby_version.to_s, spec.required_rubygems_version.to_s)
+ end
+ CompactIndex::Gem.new(name, gem_versions)
+ end
+ end
+ end
+ end
+
+ get "/names" do
+ etag_response do
+ CompactIndex.names(gems.map(&:name))
+ end
+ end
+
+ get "/versions" do
+ etag_response do
+ file = tmp("versions.list")
+ FileUtils.rm_f(file)
+ file = CompactIndex::VersionsFile.new(file.to_s)
+ file.create(gems)
+ file.contents
+ end
+ end
+
+ get "/info/:name" do
+ etag_response do
+ gem = gems.find {|g| g.name == params[:name] }
+ CompactIndex.info(gem ? gem.versions : [])
+ end
+ end
+end
diff --git a/spec/bundler/support/artifice/helpers/compact_index_extra.rb b/spec/bundler/support/artifice/helpers/compact_index_extra.rb
new file mode 100644
index 0000000000..9e742630dd
--- /dev/null
+++ b/spec/bundler/support/artifice/helpers/compact_index_extra.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require_relative "compact_index"
+
+class CompactIndexExtra < CompactIndexAPI
+ get "/extra/versions" do
+ halt 404
+ end
+
+ get "/extra/api/v1/dependencies" do
+ halt 404
+ end
+
+ get "/extra/specs.4.8.gz" do
+ File.binread("#{gem_repo2}/specs.4.8.gz")
+ end
+
+ get "/extra/prerelease_specs.4.8.gz" do
+ File.binread("#{gem_repo2}/prerelease_specs.4.8.gz")
+ end
+
+ get "/extra/quick/Marshal.4.8/:id" do
+ redirect "/extra/fetch/actual/gem/#{params[:id]}"
+ end
+
+ get "/extra/fetch/actual/gem/:id" do
+ File.binread("#{gem_repo2}/quick/Marshal.4.8/#{params[:id]}")
+ end
+
+ get "/extra/gems/:id" do
+ File.binread("#{gem_repo2}/gems/#{params[:id]}")
+ end
+end
diff --git a/spec/bundler/support/artifice/helpers/compact_index_extra_api.rb b/spec/bundler/support/artifice/helpers/compact_index_extra_api.rb
new file mode 100644
index 0000000000..d9a7d83d23
--- /dev/null
+++ b/spec/bundler/support/artifice/helpers/compact_index_extra_api.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+require_relative "compact_index"
+
+class CompactIndexExtraApi < CompactIndexAPI
+ get "/extra/names" do
+ etag_response do
+ CompactIndex.names(gems(gem_repo4).map(&:name))
+ end
+ end
+
+ get "/extra/versions" do
+ etag_response do
+ file = tmp("versions.list")
+ FileUtils.rm_f(file)
+ file = CompactIndex::VersionsFile.new(file.to_s)
+ file.create(gems(gem_repo4))
+ file.contents
+ end
+ end
+
+ get "/extra/info/:name" do
+ etag_response do
+ gem = gems(gem_repo4).find {|g| g.name == params[:name] }
+ CompactIndex.info(gem ? gem.versions : [])
+ end
+ end
+
+ get "/extra/specs.4.8.gz" do
+ File.binread("#{gem_repo4}/specs.4.8.gz")
+ end
+
+ get "/extra/prerelease_specs.4.8.gz" do
+ File.binread("#{gem_repo4}/prerelease_specs.4.8.gz")
+ end
+
+ get "/extra/quick/Marshal.4.8/:id" do
+ redirect "/extra/fetch/actual/gem/#{params[:id]}"
+ end
+
+ get "/extra/fetch/actual/gem/:id" do
+ File.binread("#{gem_repo4}/quick/Marshal.4.8/#{params[:id]}")
+ end
+
+ get "/extra/gems/:id" do
+ File.binread("#{gem_repo4}/gems/#{params[:id]}")
+ end
+end
diff --git a/spec/bundler/support/artifice/helpers/endpoint.rb b/spec/bundler/support/artifice/helpers/endpoint.rb
new file mode 100644
index 0000000000..83ba1be0fc
--- /dev/null
+++ b/spec/bundler/support/artifice/helpers/endpoint.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: true
+
+require_relative "../../path"
+
+$LOAD_PATH.unshift(*Dir[Spec::Path.base_system_gem_path.join("gems/{mustermann,rack,tilt,sinatra,ruby2_keywords,base64}-*/lib")].map(&:to_s))
+
+require "sinatra/base"
+
+ALL_REQUESTS = [] # rubocop:disable Style/MutableConstant
+ALL_REQUESTS_MUTEX = Thread::Mutex.new
+
+at_exit do
+ if expected = ENV["BUNDLER_SPEC_ALL_REQUESTS"]
+ expected = expected.split("\n").sort
+ actual = ALL_REQUESTS.sort
+
+ unless expected == actual
+ raise "Unexpected requests!\nExpected:\n\t#{expected.join("\n\t")}\n\nActual:\n\t#{actual.join("\n\t")}"
+ end
+ end
+end
+
+class Endpoint < Sinatra::Base
+ def self.all_requests
+ @all_requests ||= []
+ end
+
+ set :raise_errors, true
+ set :show_exceptions, false
+
+ def call!(*)
+ super.tap do
+ ALL_REQUESTS_MUTEX.synchronize do
+ ALL_REQUESTS << @request.url
+ end
+ end
+ end
+
+ helpers do
+ include Spec::Path
+
+ def default_gem_repo
+ if ENV["BUNDLER_SPEC_GEM_REPO"]
+ Pathname.new(ENV["BUNDLER_SPEC_GEM_REPO"])
+ else
+ case request.host
+ when "gem.repo1"
+ Spec::Path.gem_repo1
+ when "gem.repo2"
+ Spec::Path.gem_repo2
+ when "gem.repo3"
+ Spec::Path.gem_repo3
+ when "gem.repo4"
+ Spec::Path.gem_repo4
+ 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|
+ Marshal.load(File.open(gem_repo.join(filename)).read)
+ end.inject(:+)
+
+ all_specs.map do |name, version, platform|
+ spec = load_spec(name, version, platform, gem_repo)
+ next unless gem_names.include?(spec.name)
+ {
+ name: spec.name,
+ number: spec.version.version,
+ platform: spec.platform.to_s,
+ dependencies: spec.runtime_dependencies.map do |dep|
+ [dep.name, dep.requirement.requirements.map {|a| a.join(" ") }.join(", ")]
+ end,
+ }
+ end.compact
+ end
+
+ def load_spec(name, version, platform, gem_repo)
+ full_name = "#{name}-#{version}"
+ full_name += "-#{platform}" if platform != "ruby"
+ Marshal.load(Bundler.rubygems.inflate(File.binread(gem_repo.join("quick/Marshal.4.8/#{full_name}.gemspec.rz"))))
+ end
+ end
+
+ get "/quick/Marshal.4.8/:id" do
+ redirect "/fetch/actual/gem/#{params[:id]}"
+ end
+
+ get "/fetch/actual/gem/:id" do
+ File.binread("#{default_gem_repo}/quick/Marshal.4.8/#{params[:id]}")
+ end
+
+ get "/gems/:id" do
+ File.binread("#{default_gem_repo}/gems/#{params[:id]}")
+ end
+
+ get "/api/v1/dependencies" do
+ Marshal.dump(dependencies_for(params[:gems]))
+ end
+
+ get "/specs.4.8.gz" do
+ File.binread("#{default_gem_repo}/specs.4.8.gz")
+ end
+
+ get "/prerelease_specs.4.8.gz" do
+ File.binread("#{default_gem_repo}/prerelease_specs.4.8.gz")
+ end
+end
diff --git a/spec/bundler/support/artifice/helpers/endpoint_extra.rb b/spec/bundler/support/artifice/helpers/endpoint_extra.rb
new file mode 100644
index 0000000000..ad08495b50
--- /dev/null
+++ b/spec/bundler/support/artifice/helpers/endpoint_extra.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require_relative "endpoint"
+
+class EndpointExtra < Endpoint
+ get "/extra/api/v1/dependencies" do
+ halt 404
+ end
+
+ get "/extra/specs.4.8.gz" do
+ File.binread("#{gem_repo2}/specs.4.8.gz")
+ end
+
+ get "/extra/prerelease_specs.4.8.gz" do
+ File.binread("#{gem_repo2}/prerelease_specs.4.8.gz")
+ end
+
+ get "/extra/quick/Marshal.4.8/:id" do
+ redirect "/extra/fetch/actual/gem/#{params[:id]}"
+ end
+
+ get "/extra/fetch/actual/gem/:id" do
+ File.binread("#{gem_repo2}/quick/Marshal.4.8/#{params[:id]}")
+ end
+
+ get "/extra/gems/:id" do
+ File.binread("#{gem_repo2}/gems/#{params[:id]}")
+ end
+end
diff --git a/spec/bundler/support/artifice/helpers/endpoint_fallback.rb b/spec/bundler/support/artifice/helpers/endpoint_fallback.rb
new file mode 100644
index 0000000000..a232930b67
--- /dev/null
+++ b/spec/bundler/support/artifice/helpers/endpoint_fallback.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require_relative "endpoint"
+
+class EndpointFallback < Endpoint
+ DEPENDENCY_LIMIT = 60
+
+ get "/api/v1/dependencies" do
+ if params[:gems] && params[:gems].size <= DEPENDENCY_LIMIT
+ Marshal.dump(dependencies_for(params[:gems]))
+ else
+ halt 413, "Too many gems to resolve, please request less than #{DEPENDENCY_LIMIT} gems"
+ end
+ end
+end
diff --git a/spec/bundler/support/artifice/helpers/endpoint_marshal_fail.rb b/spec/bundler/support/artifice/helpers/endpoint_marshal_fail.rb
new file mode 100644
index 0000000000..c409d39d99
--- /dev/null
+++ b/spec/bundler/support/artifice/helpers/endpoint_marshal_fail.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require_relative "endpoint_fallback"
+
+class EndpointMarshalFail < EndpointFallback
+ get "/api/v1/dependencies" do
+ "f0283y01hasf"
+ end
+end
diff --git a/spec/bundler/support/artifice/helpers/rack_request.rb b/spec/bundler/support/artifice/helpers/rack_request.rb
new file mode 100644
index 0000000000..f419bacb8c
--- /dev/null
+++ b/spec/bundler/support/artifice/helpers/rack_request.rb
@@ -0,0 +1,100 @@
+# frozen_string_literal: true
+
+require "rack/test"
+require "bundler/vendored_net_http"
+
+module Artifice
+ module Net
+ # This is an internal object that can receive Rack requests
+ # to the application using the Rack::Test API
+ class RackRequest
+ include Rack::Test::Methods
+ attr_reader :app
+
+ def initialize(app)
+ @app = app
+ end
+ end
+
+ class HTTP < ::Gem::Net::HTTP
+ class << self
+ attr_accessor :endpoint
+ end
+
+ # Gem::Net::HTTP uses a @newimpl instance variable to decide whether
+ # to use a legacy implementation. Since we are subclassing
+ # Gem::Net::HTTP, we must set it
+ @newimpl = true
+
+ # We don't need to connect, so blank out this method
+ def connect
+ end
+
+ # Replace the Gem::Net::HTTP request method with a method
+ # that converts the request into a Rack request and
+ # dispatches it to the Rack endpoint.
+ #
+ # @param [Net::HTTPRequest] req A Gem::Net::HTTPRequest
+ # object, or one if its subclasses
+ # @param [optional, String, #read] body This should
+ # be sent as "rack.input". If it's a String, it will
+ # be converted to a StringIO.
+ # @return [Net::HTTPResponse]
+ #
+ # @yield [Net::HTTPResponse] If a block is provided,
+ # this method will yield the Gem::Net::HTTPResponse to
+ # it after the body is read.
+ def request(req, body = nil, &block)
+ rack_request = RackRequest.new(self.class.endpoint)
+
+ req.each_header do |header, value|
+ rack_request.header(header, value)
+ end
+
+ scheme = use_ssl? ? "https" : "http"
+ prefix = "#{scheme}://#{addr_port}"
+ body_stream_contents = req.body_stream.read if req.body_stream
+
+ response = rack_request.request("#{prefix}#{req.path}",
+ { method: req.method, input: body || req.body || body_stream_contents })
+
+ make_net_http_response(response, &block)
+ end
+
+ private
+
+ # This method takes a Rack response and creates a Gem::Net::HTTPResponse
+ # Instead of trying to mock HTTPResponse directly, we just convert
+ # the Rack response into a String that looks like a normal HTTP
+ # response and call Gem::Net::HTTPResponse.read_new
+ #
+ # @param [Array(#to_i, Hash, #each)] response a Rack response
+ # @return [Net::HTTPResponse]
+ # @yield [Net::HTTPResponse] If a block is provided, yield the
+ # response to it after the body is read
+ def make_net_http_response(response)
+ status = response.status
+ headers = response.headers
+ body = response.body
+
+ response_string = []
+ response_string << "HTTP/1.1 #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]}"
+
+ headers.each do |header, value|
+ response_string << "#{header}: #{value}"
+ end
+
+ response_string << "" << body
+
+ response_io = ::Gem::Net::BufferedIO.new(StringIO.new(response_string.join("\n")))
+ res = ::Gem::Net::HTTPResponse.read_new(response_io)
+
+ res.reading_body(response_io, true) do
+ yield res if block_given?
+ end
+
+ res
+ end
+ end
+ end
+end
diff --git a/spec/bundler/support/artifice/vcr.rb b/spec/bundler/support/artifice/vcr.rb
index 0d51201bef..7b9a8bdeaf 100644
--- a/spec/bundler/support/artifice/vcr.rb
+++ b/spec/bundler/support/artifice/vcr.rb
@@ -1,12 +1,13 @@
# frozen_string_literal: true
-require "net/http"
+require "bundler/vendored_net_http"
require_relative "../path"
-CASSETTE_PATH = "#{Spec::Path.spec_dir}/support/artifice/vcr_cassettes"
+CASSETTE_PATH = "#{Spec::Path.spec_dir}/support/artifice/vcr_cassettes".freeze
+USED_CASSETTES_PATH = "#{Spec::Path.spec_dir}/support/artifice/used_cassettes.txt".freeze
CASSETTE_NAME = ENV.fetch("BUNDLER_SPEC_VCR_CASSETTE_NAME") { "realworld" }
-class BundlerVCRHTTP < Net::HTTP
+class BundlerVCRHTTP < Gem::Net::HTTP
class RequestHandler
attr_reader :http, :request, :body, :response_block
def initialize(http, request, body = nil, &response_block)
@@ -22,6 +23,10 @@ class BundlerVCRHTTP < Net::HTTP
@__vcr_request_handler = handler
end
+ File.open(USED_CASSETTES_PATH, "a+") do |f|
+ f.puts request_pair_paths.map {|path| Pathname.new(path).relative_path_from(Spec::Path.source_root).to_s }.join("\n")
+ end
+
if recorded_response?
recorded_response
else
@@ -36,13 +41,13 @@ class BundlerVCRHTTP < Net::HTTP
def recorded_response
File.open(request_pair_paths.last, "rb:ASCII-8BIT") do |response_file|
- response_io = ::Net::BufferedIO.new(response_file)
- ::Net::HTTPResponse.read_new(response_io).tap do |response|
+ response_io = ::Gem::Net::BufferedIO.new(response_file)
+ ::Gem::Net::HTTPResponse.read_new(response_io).tap do |response|
response.decode_content = request.decode_content if request.respond_to?(:decode_content)
response.uri = request.uri
response.reading_body(response_io, request.response_body_permitted?) do
- response_block.call(response) if response_block
+ response_block&.call(response)
end
end
end
@@ -69,30 +74,13 @@ class BundlerVCRHTTP < Net::HTTP
end
def file_name_for_key(key)
- key.join("/").gsub(/[\:*?"<>|]/, "-")
+ File.join(*key).gsub(/[\:*?"<>|]/, "-")
end
def request_pair_paths
%w[request response].map do |kind|
- File.join(CASSETTE_PATH, CASSETTE_NAME, file_name_for_key(key + [kind]))
- end
- end
-
- def read_stored_request(path)
- contents = File.binread(path)
- headers = {}
- method = nil
- path = nil
- contents.lines.grep(/^> /).each do |line|
- if line =~ /^> (GET|HEAD|POST|PATCH|PUT|DELETE) (.*)/
- method = $1
- path = $2.strip
- elsif line =~ /^> (.*?): (.*)/
- headers[$1] = $2
- end
+ File.join(CASSETTE_PATH, CASSETTE_NAME, file_name_for_key(key), kind)
end
- body = contents =~ /^([^>].*)/m && $1
- Net::HTTP.const_get(method.capitalize).new(path, headers).tap {|r| r.body = body if body }
end
def request_to_string(request)
@@ -158,8 +146,7 @@ class BundlerVCRHTTP < Net::HTTP
alias_method :request, :request_with_vcr
end
-# Replace Net::HTTP with our VCR subclass
-::Net.class_eval do
- remove_const(:HTTP)
- const_set(:HTTP, BundlerVCRHTTP)
-end
+require_relative "helpers/artifice"
+
+# Replace Gem::Net::HTTP with our VCR subclass
+Artifice.replace_net_http(BundlerVCRHTTP)
diff --git a/spec/bundler/support/artifice/windows.rb b/spec/bundler/support/artifice/windows.rb
index ddbbd62b96..fea991c071 100644
--- a/spec/bundler/support/artifice/windows.rb
+++ b/spec/bundler/support/artifice/windows.rb
@@ -2,13 +2,10 @@
require_relative "../path"
-$LOAD_PATH.unshift(*Dir[Spec::Path.base_system_gems.join("gems/{artifice,mustermann,rack,tilt,sinatra,ruby2_keywords}-*/lib")].map(&:to_s))
+$LOAD_PATH.unshift(*Dir[Spec::Path.base_system_gem_path.join("gems/{mustermann,rack,tilt,sinatra,ruby2_keywords,base64}-*/lib")].map(&:to_s))
-require "artifice"
require "sinatra/base"
-Artifice.deactivate
-
class Windows < Sinatra::Base
set :raise_errors, true
set :show_exceptions, false
@@ -43,4 +40,6 @@ class Windows < Sinatra::Base
end
end
+require_relative "helpers/artifice"
+
Artifice.activate_with(Windows)
diff --git a/spec/bundler/support/build_metadata.rb b/spec/bundler/support/build_metadata.rb
index 98d8ac23c8..5898e7f3bd 100644
--- a/spec/bundler/support/build_metadata.rb
+++ b/spec/bundler/support/build_metadata.rb
@@ -10,20 +10,20 @@ module Spec
def write_build_metadata(dir: source_root)
build_metadata = {
- :git_commit_sha => git_commit_sha,
- :built_at => loaded_gemspec.date.utc.strftime("%Y-%m-%d"),
- :release => true,
+ git_commit_sha: git_commit_sha,
+ built_at: loaded_gemspec.date.utc.strftime("%Y-%m-%d"),
+ release: true,
}
- replace_build_metadata(build_metadata, dir: dir) # rubocop:disable Style/HashSyntax
+ replace_build_metadata(build_metadata, dir: dir)
end
def reset_build_metadata(dir: source_root)
build_metadata = {
- :release => false,
+ release: false,
}
- replace_build_metadata(build_metadata, dir: dir) # rubocop:disable Style/HashSyntax
+ replace_build_metadata(build_metadata, dir: dir)
end
private
@@ -41,7 +41,7 @@ module Spec
end
def git_commit_sha
- ruby_core_tarball? ? "unknown" : sys_exec("git rev-parse --short HEAD", :dir => source_root).strip
+ ruby_core_tarball? ? "unknown" : sys_exec("git rev-parse --short HEAD", dir: source_root).strip
end
extend self
diff --git a/spec/bundler/support/builders.rb b/spec/bundler/support/builders.rb
index 25377d2ac2..ab2dafb0b9 100644
--- a/spec/bundler/support/builders.rb
+++ b/spec/bundler/support/builders.rb
@@ -17,16 +17,8 @@ module Spec
Gem::Platform.new(platform)
end
- # Returns a number smaller than the size of the index. Useful for specs that
- # need the API request limit to be reached for some reason.
- def low_api_request_limit_for(gem_repo)
- all_gems = Dir[gem_repo.join("gems/*.gem")]
-
- all_gem_names = all_gems.map do |file|
- File.basename(file, ".gem").match(/\A(?<gem_name>[^-]+)-.*\z/)[:gem_name]
- end.uniq
-
- (all_gem_names - ["bundler"]).size
+ def rake_version
+ "13.2.1"
end
def build_repo1
@@ -35,6 +27,11 @@ module Spec
build_repo gem_repo1 do
FileUtils.cp rake_path, "#{gem_repo1}/gems/"
+ build_gem "coffee-script-source"
+ build_gem "git"
+ build_gem "puma"
+ build_gem "minitest"
+
build_gem "rack", %w[0.9.1 1.0.0] do |s|
s.executables = "rackup"
s.post_install_message = "Rack's post install message"
@@ -56,7 +53,7 @@ module Spec
build_gem "rails", "2.3.2" do |s|
s.executables = "rails"
- s.add_dependency "rake", "13.0.1"
+ s.add_dependency "rake", rake_version
s.add_dependency "actionpack", "2.3.2"
s.add_dependency "activerecord", "2.3.2"
s.add_dependency "actionmailer", "2.3.2"
@@ -80,17 +77,17 @@ module Spec
s.add_dependency "activesupport", ">= 2.0.0"
end
- build_gem "rspec", "1.2.7", :no_default => true do |s|
+ build_gem "rspec", "1.2.7", no_default: true do |s|
s.write "lib/spec.rb", "SPEC = '1.2.7'"
end
- build_gem "rack-test", :no_default => true do |s|
+ build_gem "rack-test", no_default: true do |s|
s.write "lib/rack/test.rb", "RACK_TEST = '1.0'"
end
build_gem "platform_specific" do |s|
- s.platform = Bundler.local_platform
- s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 #{Bundler.local_platform}'"
+ s.platform = Gem::Platform.local
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 #{Gem::Platform.local}'"
end
build_gem "platform_specific" do |s|
@@ -105,15 +102,27 @@ module Spec
build_gem "platform_specific" do |s|
s.platform = "x86-mswin32"
- s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 MSWIN'"
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0 x86-mswin32'"
+ end
+
+ build_gem "platform_specific" do |s|
+ s.platform = "x64-mswin64"
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0 x64-mswin64'"
end
build_gem "platform_specific" do |s|
s.platform = "x86-mingw32"
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0 x86-mingw32'"
end
build_gem "platform_specific" do |s|
s.platform = "x64-mingw32"
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0 x64-mingw32'"
+ end
+
+ build_gem "platform_specific" do |s|
+ s.platform = "x64-mingw-ucrt"
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0 x64-mingw-ucrt'"
end
build_gem "platform_specific" do |s|
@@ -186,27 +195,25 @@ module Spec
end
end
- def build_repo2(&blk)
+ def build_repo2(**kwargs, &blk)
FileUtils.rm_rf gem_repo2
FileUtils.cp_r gem_repo1, gem_repo2
- update_repo2(&blk) if block_given?
+ update_repo2(**kwargs, &blk) if block_given?
end
# A repo that has no pre-installed gems included. (The caller completely
# determines the contents with the block.)
- def build_repo4(&blk)
+ def build_repo4(**kwargs, &blk)
FileUtils.rm_rf gem_repo4
- build_repo(gem_repo4, &blk)
+ build_repo(gem_repo4, **kwargs, &blk)
end
def update_repo4(&blk)
update_repo(gem_repo4, &blk)
end
- def update_repo2
- update_repo gem_repo2 do
- yield if block_given?
- end
+ def update_repo2(**kwargs, &blk)
+ update_repo(gem_repo2, **kwargs, &blk)
end
def build_security_repo
@@ -224,12 +231,12 @@ module Spec
end
end
- def build_repo(path, &blk)
+ def build_repo(path, **kwargs, &blk)
return if File.directory?(path)
FileUtils.mkdir_p("#{path}/gems")
- update_repo(path, &blk)
+ update_repo(path,**kwargs, &blk)
end
def check_test_gems!
@@ -246,7 +253,7 @@ module Spec
end
end
- def update_repo(path)
+ def update_repo(path, build_compact_index: true)
if path == gem_repo1 && caller.first.split(" ").last == "`build_repo`"
raise "Updating gem_repo1 is unsupported -- use gem_repo2 instead"
end
@@ -254,8 +261,13 @@ module Spec
@_build_path = "#{path}/gems"
@_build_repo = File.basename(path)
yield
- with_gem_path_as Path.base_system_gems do
- gem_command :generate_index, :dir => path
+ with_gem_path_as Path.base_system_gem_path do
+ Dir[Spec::Path.base_system_gem_path.join("gems/rubygems-generate_index*/lib")].first ||
+ raise("Could not find rubygems-generate_index lib directory in #{Spec::Path.base_system_gem_path}")
+
+ command = "generate_index"
+ command += " --no-compact" if !build_compact_index && gem_command(command + " --help").include?("--[no-]compact")
+ gem_command command, dir: path
end
ensure
@_build_path = nil
@@ -281,14 +293,14 @@ module Spec
end
end
- def build_dep(name, requirements = Gem::Requirement.default, type = :runtime)
- Bundler::Dependency.new(name, :version => requirements)
- end
-
def build_lib(name, *args, &blk)
build_with(LibBuilder, name, args, &blk)
end
+ def build_bundler(*args, &blk)
+ build_with(BundlerBuilder, "bundler", args, &blk)
+ end
+
def build_gem(name, *args, &blk)
build_with(GemBuilder, name, args, &blk)
end
@@ -394,6 +406,49 @@ module Spec
alias_method :dep, :runtime
end
+ class BundlerBuilder
+ attr_writer :required_ruby_version
+
+ def initialize(context, name, version)
+ raise "can only build bundler" unless name == "bundler"
+
+ @context = context
+ @version = version || Bundler::VERSION
+ end
+
+ def _build(options = {})
+ full_name = "bundler-#{@version}"
+ build_path = @context.tmp + full_name
+ bundler_path = build_path + "#{full_name}.gem"
+
+ FileUtils.mkdir_p build_path
+
+ @context.shipped_files.each do |shipped_file|
+ target_shipped_file = shipped_file
+ target_shipped_file = shipped_file.sub(/\Alibexec/, "exe") if @context.ruby_core?
+ target_shipped_file = build_path + target_shipped_file
+ target_shipped_dir = File.dirname(target_shipped_file)
+ FileUtils.mkdir_p target_shipped_dir unless File.directory?(target_shipped_dir)
+ FileUtils.cp shipped_file, target_shipped_file, preserve: true
+ end
+
+ @context.replace_version_file(@version, dir: build_path)
+ @context.replace_required_ruby_version(@required_ruby_version, dir: build_path) if @required_ruby_version
+
+ Spec::BuildMetadata.write_build_metadata(dir: build_path)
+
+ @context.gem_command "build #{@context.relative_gemspec}", dir: build_path
+
+ if block_given?
+ yield(bundler_path)
+ else
+ FileUtils.mv bundler_path, options[:path]
+ end
+ ensure
+ build_path.rmtree
+ end
+ end
+
class LibBuilder
def initialize(context, name, version)
@context = context
@@ -439,9 +494,6 @@ module Spec
write "ext/extconf.rb", <<-RUBY
require "mkmf"
-
- # exit 1 unless with_config("simple")
-
extension_name = "#{name}_c"
if extra_lib_dir = with_config("ext-lib")
# add extra libpath if --with-ext-lib is
@@ -479,7 +531,7 @@ module Spec
end
@spec.authors = ["no one"]
- @spec.files = @files.keys
+ @spec.files += @files.keys
case options[:gemspec]
when false
@@ -520,10 +572,10 @@ module Spec
class GitBuilder < LibBuilder
def _build(options)
- default_branch = options[:default_branch] || "master"
+ default_branch = options[:default_branch] || "main"
path = options[:path] || _default_path
source = options[:source] || "git@#{path}"
- super(options.merge(:path => path, :source => source))
+ super(options.merge(path: path, source: source))
@context.git("config --global init.defaultBranch #{default_branch}", path)
@context.git("init", path)
@context.git("add *", path)
@@ -537,7 +589,7 @@ module Spec
class GitBareBuilder < LibBuilder
def _build(options)
path = options[:path] || _default_path
- super(options.merge(:path => path))
+ super(options.merge(path: path))
@context.git("init --bare", path)
end
end
@@ -548,17 +600,8 @@ module Spec
update_gemspec = options[:gemspec] || false
source = options[:source] || "git@#{libpath}"
- @context.git "checkout master", libpath
-
if branch = options[:branch]
- raise "You can't specify `master` as the branch" if branch == "master"
- escaped_branch = Shellwords.shellescape(branch)
-
- if @context.git("branch -l #{escaped_branch}", libpath).empty?
- @context.git("branch #{escaped_branch}", libpath)
- end
-
- @context.git("checkout #{escaped_branch}", libpath)
+ @context.git("checkout -b #{Shellwords.shellescape(branch)}", libpath)
elsif tag = options[:tag]
@context.git("tag #{Shellwords.shellescape(tag)}", libpath)
elsif options[:remote]
@@ -571,9 +614,8 @@ module Spec
_default_files.keys.each do |path|
_default_files[path] += "\n#{Builders.constantize(name)}_PREV_REF = '#{current_ref}'"
end
- super(options.merge(:path => libpath, :gemspec => update_gemspec, :source => source))
- @context.git("add *", libpath)
- @context.git("commit -m BUMP", libpath, :raise_on_error => false)
+ super(options.merge(path: libpath, gemspec: update_gemspec, source: source))
+ @context.git("commit -am BUMP", libpath)
end
end
@@ -594,7 +636,8 @@ module Spec
class GemBuilder < LibBuilder
def _build(opts)
- lib_path = super(opts.merge(:path => @context.tmp(".tmp/#{@spec.full_name}"), :no_default => opts[:no_default]))
+ lib_path = opts[:lib_path] || @context.tmp(".tmp/#{@spec.full_name}")
+ lib_path = super(opts.merge(path: lib_path, no_default: opts[:no_default]))
destination = opts[:path] || _default_path
FileUtils.mkdir_p(lib_path.join(destination))
@@ -603,16 +646,16 @@ module Spec
Bundler.rubygems.build(@spec, opts[:skip_validation])
end
elsif opts[:skip_validation]
- @context.gem_command "build --force #{@spec.name}", :dir => lib_path
+ @context.gem_command "build --force #{@spec.name}", dir: lib_path
else
- @context.gem_command "build #{@spec.name}", :dir => lib_path
+ @context.gem_command "build #{@spec.name}", dir: lib_path
end
gem_path = File.expand_path("#{@spec.full_name}.gem", lib_path)
if opts[:to_system]
- @context.system_gems gem_path, :default => opts[:default]
+ @context.system_gems gem_path, default: opts[:default]
elsif opts[:to_bundle]
- @context.system_gems gem_path, :path => @context.default_bundle_path
+ @context.system_gems gem_path, path: @context.default_bundle_path
else
FileUtils.mv(gem_path, destination)
end
@@ -632,7 +675,7 @@ module Spec
end
end
- TEST_CERT = <<-CERT.gsub(/^\s*/, "")
+ TEST_CERT = <<~CERT
-----BEGIN CERTIFICATE-----
MIIDMjCCAhqgAwIBAgIBATANBgkqhkiG9w0BAQUFADAnMQwwCgYDVQQDDAN5b3Ux
FzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMB4XDTE1MDIwODAwMTIyM1oXDTQyMDYy
@@ -655,7 +698,7 @@ module Spec
-----END CERTIFICATE-----
CERT
- TEST_PKEY = <<-PKEY.gsub(/^\s*/, "")
+ TEST_PKEY = <<~PKEY
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA2W8V2k3jdzgMxL0mjTqbRruTdtDcdZDXKtiFkyLvsXUXvc2k
GSdgcjMOS1CkafqGz/hAUlPibjM0QEXjtQuMdTmdMrmuORLeeIZhSO+HdkTNV6j3
diff --git a/spec/bundler/support/bundle.rb b/spec/bundler/support/bundle.rb
index bb21526d35..5d6d658040 100644
--- a/spec/bundler/support/bundle.rb
+++ b/spec/bundler/support/bundle.rb
@@ -1,8 +1,5 @@
# frozen_string_literal: true
-require "rubygems"
-require_relative "path"
-bundler_gemspec = Spec::Path.loaded_gemspec
-bundler_gemspec.instance_variable_set(:@full_gem_path, Spec::Path.source_root)
-bundler_gemspec.activate if bundler_gemspec.respond_to?(:activate)
+require_relative "activate"
+
load File.expand_path("bundle", Spec::Path.bindir)
diff --git a/spec/bundler/support/checksums.rb b/spec/bundler/support/checksums.rb
new file mode 100644
index 0000000000..f758559b3b
--- /dev/null
+++ b/spec/bundler/support/checksums.rb
@@ -0,0 +1,114 @@
+# frozen_string_literal: true
+
+module Spec
+ module Checksums
+ class ChecksumsBuilder
+ def initialize(enabled = true, &block)
+ @enabled = enabled
+ @checksums = {}
+ yield self if block_given?
+ end
+
+ def initialize_copy(original)
+ super
+ @checksums = @checksums.dup
+ end
+
+ def checksum(repo, name, version, platform = Gem::Platform::RUBY)
+ name_tuple = Gem::NameTuple.new(name, version, platform)
+ gem_file = File.join(repo, "gems", "#{name_tuple.full_name}.gem")
+ File.open(gem_file, "rb") do |f|
+ register(name_tuple, Bundler::Checksum.from_gem(f, "#{gem_file} (via ChecksumsBuilder#checksum)"))
+ end
+ end
+
+ def no_checksum(name, version, platform = Gem::Platform::RUBY)
+ name_tuple = Gem::NameTuple.new(name, version, platform)
+ register(name_tuple, nil)
+ end
+
+ def delete(name, platform = nil)
+ @checksums.reject! {|k, _| k.name == name && (platform.nil? || k.platform == platform) }
+ end
+
+ def to_s
+ return "" unless @enabled
+
+ locked_checksums = @checksums.map do |name_tuple, checksum|
+ checksum &&= " #{checksum.to_lock}"
+ " #{name_tuple.lock_name}#{checksum}\n"
+ end
+
+ "\nCHECKSUMS\n#{locked_checksums.sort.join}"
+ end
+
+ private
+
+ def register(name_tuple, checksum)
+ delete(name_tuple.name, name_tuple.platform)
+ @checksums[name_tuple] = checksum
+ end
+ end
+
+ def checksums_section(enabled = true, &block)
+ ChecksumsBuilder.new(enabled, &block)
+ end
+
+ def checksums_section_when_existing(&block)
+ begin
+ enabled = lockfile.match?(/^CHECKSUMS$/)
+ rescue Errno::ENOENT
+ enabled = false
+ end
+ checksums_section(enabled, &block)
+ end
+
+ def checksum_to_lock(*args)
+ checksums_section do |c|
+ c.checksum(*args)
+ end.to_s.sub(/^CHECKSUMS\n/, "").strip
+ end
+
+ def checksum_digest(*args)
+ checksum_to_lock(*args).split(Bundler::Checksum::ALGO_SEPARATOR, 2).last
+ end
+
+ # if prefixes is given, removes all checksums where the line
+ # has any of the prefixes on the line before the checksum
+ # otherwise, removes all checksums from the lockfile
+ def remove_checksums_from_lockfile(lockfile, *prefixes)
+ head, remaining = lockfile.split(/^CHECKSUMS$/, 2)
+ return lockfile unless remaining
+ checksums, tail = remaining.split("\n\n", 2)
+
+ prefixes =
+ if prefixes.empty?
+ nil
+ else
+ /(#{prefixes.map {|p| Regexp.escape(p) }.join("|")})/
+ end
+
+ checksums = checksums.each_line.map do |line|
+ if prefixes.nil? || line.match?(prefixes)
+ line.gsub(/ sha256=[a-f0-9]{64}/i, "")
+ else
+ line
+ end
+ end
+
+ head.concat(
+ "CHECKSUMS",
+ checksums.join,
+ "\n\n",
+ tail
+ )
+ end
+
+ def remove_checksums_section_from_lockfile(lockfile)
+ head, remaining = lockfile.split(/^CHECKSUMS$/, 2)
+ return lockfile unless remaining
+ _checksums, tail = remaining.split("\n\n", 2)
+ head.concat(tail)
+ end
+ end
+end
diff --git a/spec/bundler/support/command_execution.rb b/spec/bundler/support/command_execution.rb
index 68e5c56c75..5639fda3b6 100644
--- a/spec/bundler/support/command_execution.rb
+++ b/spec/bundler/support/command_execution.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Spec
- CommandExecution = Struct.new(:command, :working_directory, :exitstatus, :stdout, :stderr) do
+ CommandExecution = Struct.new(:command, :working_directory, :exitstatus, :original_stdout, :original_stderr) do
def to_s
"$ #{command}"
end
@@ -11,6 +11,19 @@ module Spec
@stdboth ||= [stderr, stdout].join("\n").strip
end
+ def stdout
+ original_stdout
+ end
+
+ # Can be removed once/if https://github.com/oneclick/rubyinstaller2/pull/369 is resolved
+ def stderr
+ return original_stderr unless Gem.win_platform?
+
+ original_stderr.split("\n").reject do |l|
+ l.include?("operating_system_defaults")
+ end.join("\n")
+ end
+
def to_s_verbose
[
to_s,
diff --git a/spec/bundler/support/filters.rb b/spec/bundler/support/filters.rb
index 0c1f27e470..8e164af756 100644
--- a/spec/bundler/support/filters.rb
+++ b/spec/bundler/support/filters.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require_relative "sudo"
-
class RequirementChecker < Proc
def self.against(present)
provided = Gem::Version.new(present)
@@ -21,19 +19,20 @@ class RequirementChecker < Proc
end
RSpec.configure do |config|
- config.filter_run_excluding :sudo => true
- config.filter_run_excluding :realworld => true
-
- git_version = Bundler::Source::Git::GitProxy.new(nil, nil, nil).version
-
- config.filter_run_excluding :git => RequirementChecker.against(git_version)
- config.filter_run_excluding :bundler => RequirementChecker.against(Bundler::VERSION.split(".")[0])
- config.filter_run_excluding :ruby_repo => !ENV["GEM_COMMAND"].nil?
- config.filter_run_excluding :no_color_tty => Gem.win_platform? || !ENV["GITHUB_ACTION"].nil?
- config.filter_run_excluding :permissions => Gem.win_platform?
- config.filter_run_excluding :readline => Gem.win_platform?
- config.filter_run_excluding :jruby => RUBY_ENGINE != "jruby"
- config.filter_run_excluding :truffleruby => RUBY_ENGINE != "truffleruby"
+ config.filter_run_excluding realworld: true
+
+ git_version = Bundler::Source::Git::GitProxy.new(nil, nil).version
+
+ config.filter_run_excluding git: RequirementChecker.against(git_version)
+ config.filter_run_excluding bundler: RequirementChecker.against(Bundler::VERSION.split(".")[0])
+ config.filter_run_excluding rubygems: RequirementChecker.against(Gem::VERSION)
+ config.filter_run_excluding ruby_repo: !ENV["GEM_COMMAND"].nil?
+ config.filter_run_excluding no_color_tty: Gem.win_platform? || !ENV["GITHUB_ACTION"].nil?
+ config.filter_run_excluding permissions: Gem.win_platform?
+ config.filter_run_excluding readline: Gem.win_platform?
+ config.filter_run_excluding jruby_only: RUBY_ENGINE != "jruby"
+ config.filter_run_excluding truffleruby_only: RUBY_ENGINE != "truffleruby"
+ config.filter_run_excluding man: Gem.win_platform?
config.filter_run_when_matching :focus unless ENV["CI"]
end
diff --git a/spec/bundler/support/hax.rb b/spec/bundler/support/hax.rb
index aaf8c74894..c7fe3637cc 100644
--- a/spec/bundler/support/hax.rb
+++ b/spec/bundler/support/hax.rb
@@ -1,5 +1,10 @@
# frozen_string_literal: true
+if ENV["BUNDLER_SPEC_RUBY_PLATFORM"]
+ Object.send(:remove_const, :RUBY_PLATFORM)
+ RUBY_PLATFORM = ENV["BUNDLER_SPEC_RUBY_PLATFORM"]
+end
+
module Gem
def self.ruby=(ruby)
@ruby = ruby
@@ -9,33 +14,40 @@ module Gem
Gem.ruby = ENV["RUBY"]
end
- @default_dir = ENV["BUNDLER_GEM_DEFAULT_DIR"] if ENV["BUNDLER_GEM_DEFAULT_DIR"]
+ if ENV["BUNDLER_GEM_DEFAULT_DIR"]
+ @default_dir = ENV["BUNDLER_GEM_DEFAULT_DIR"]
+ @default_specifications_dir = nil
+ end
+
+ if ENV["BUNDLER_SPEC_WINDOWS"]
+ @@win_platform = true # rubocop:disable Style/ClassVars
+ end
if ENV["BUNDLER_SPEC_PLATFORM"]
+ previous_platforms = @platforms
+ previous_local = Platform.local
+
class Platform
@local = new(ENV["BUNDLER_SPEC_PLATFORM"])
end
- @platforms = [Gem::Platform::RUBY, Gem::Platform.local]
-
- if ENV["BUNDLER_SPEC_PLATFORM"] == "ruby"
- class << self
- remove_method :finish_resolve
-
- def finish_resolve
- []
- end
- end
- end
+ @platforms = previous_platforms.map {|platform| platform == previous_local ? Platform.local : platform }
end
if ENV["BUNDLER_SPEC_GEM_SOURCES"]
- @sources = [ENV["BUNDLER_SPEC_GEM_SOURCES"]]
+ self.sources = [ENV["BUNDLER_SPEC_GEM_SOURCES"]]
end
- # We only need this hack for rubygems versions without the BundlerVersionFinder
- if Gem.rubygems_version < Gem::Version.new("2.7.0")
- @path_to_default_spec_map.delete_if do |_path, spec|
- spec.name == "bundler"
+ if ENV["BUNDLER_IGNORE_DEFAULT_GEM"]
+ module RemoveDefaultBundlerStub
+ def default_stubs(pattern = "*")
+ super.delete_if {|stub| stub.name == "bundler" }
+ end
+ end
+
+ class Specification
+ class << self
+ prepend RemoveDefaultBundlerStub
+ end
end
end
end
diff --git a/spec/bundler/support/helpers.rb b/spec/bundler/support/helpers.rb
index 13fa36fbc2..1ad9cc78ca 100644
--- a/spec/bundler/support/helpers.rb
+++ b/spec/bundler/support/helpers.rb
@@ -43,7 +43,7 @@ module Spec
last_command.stderr
end
- MAJOR_DEPRECATION = /^\[DEPRECATED\]\s*/.freeze
+ MAJOR_DEPRECATION = /^\[DEPRECATED\]\s*/
def err_without_deprecations
err.gsub(/#{MAJOR_DEPRECATION}.+[\n]?/, "")
@@ -60,7 +60,7 @@ module Spec
def run(cmd, *args)
opts = args.last.is_a?(Hash) ? args.pop : {}
groups = args.map(&:inspect).join(", ")
- setup = "require '#{entrypoint}' ; Bundler.ui.silence { Bundler.setup(#{groups}) }"
+ setup = "require 'bundler' ; Bundler.ui.silence { Bundler.setup(#{groups}) }"
ruby([setup, cmd].join(" ; "), opts)
end
@@ -78,9 +78,6 @@ module Spec
end
def bundle(cmd, options = {}, &block)
- with_sudo = options.delete(:sudo)
- sudo = with_sudo == :preserve_env ? "sudo -E --preserve-env=RUBYOPT" : "sudo" if with_sudo
-
bundle_bin = options.delete(:bundle_bin)
bundle_bin ||= installed_bindir.join("bundle")
@@ -88,7 +85,6 @@ module Spec
requires = options.delete(:requires) || []
realworld = RSpec.current_example.metadata[:realworld]
- options[:verbose] = true if options[:verbose].nil? && realworld
artifice = options.delete(:artifice) do
if realworld
@@ -120,9 +116,9 @@ module Spec
end
end.join
- ruby_cmd = build_ruby_cmd({ :sudo => sudo, :load_path => load_path, :requires => requires })
+ ruby_cmd = build_ruby_cmd({ load_path: load_path, requires: requires, env: env })
cmd = "#{ruby_cmd} #{bundle_bin} #{cmd}#{args}"
- sys_exec(cmd, { :env => env, :dir => dir, :raise_on_error => raise_on_error }, &block)
+ sys_exec(cmd, { env: env, dir: dir, raise_on_error: raise_on_error }, &block)
end
def bundler(cmd, options = {})
@@ -147,16 +143,20 @@ module Spec
end
def build_ruby_cmd(options = {})
- sudo = options.delete(:sudo)
-
libs = options.delete(:load_path)
lib_option = libs ? "-I#{libs.join(File::PATH_SEPARATOR)}" : []
requires = options.delete(:requires) || []
- requires << "#{Path.spec_dir}/support/hax.rb"
+
+ hax_path = "#{Path.spec_dir}/support/hax.rb"
+
+ # For specs that need to ignore the default Bundler gem, load hax before
+ # anything else since other stuff may actually load bundler and not skip
+ # the default version
+ options[:env]&.include?("BUNDLER_IGNORE_DEFAULT_GEM") ? requires.prepend(hax_path) : requires.append(hax_path)
require_option = requires.map {|r| "-r#{r}" }
- [sudo, Gem.ruby, *lib_option, *require_option].compact.join(" ")
+ [Gem.ruby, *lib_option, *require_option].compact.join(" ")
end
def gembin(cmd, options = {})
@@ -166,7 +166,7 @@ module Spec
def gem_command(command, options = {})
env = options[:env] || {}
- env["RUBYOPT"] = opt_add("-r#{spec_dir}/support/hax.rb", env["RUBYOPT"] || ENV["RUBYOPT"])
+ env["RUBYOPT"] = opt_add(opt_add("-r#{spec_dir}/support/hax.rb", env["RUBYOPT"]), ENV["RUBYOPT"])
options[:env] = env
sys_exec("#{Path.gem_bin} #{command}", options)
end
@@ -176,31 +176,31 @@ module Spec
end
def git(cmd, path, options = {})
- sys_exec("git #{cmd}", options.merge(:dir => path))
+ sys_exec("git #{cmd}", options.merge(dir: path))
end
def sys_exec(cmd, options = {})
env = options[:env] || {}
- env["RUBYOPT"] = opt_add("-r#{spec_dir}/support/switch_rubygems.rb", env["RUBYOPT"] || ENV["RUBYOPT"])
+ env["RUBYOPT"] = opt_add(opt_add("-r#{spec_dir}/support/switch_rubygems.rb", env["RUBYOPT"]), ENV["RUBYOPT"])
dir = options[:dir] || bundled_app
command_execution = CommandExecution.new(cmd.to_s, dir)
require "open3"
require "shellwords"
- Open3.popen3(env, *cmd.shellsplit, :chdir => dir) do |stdin, stdout, stderr, wait_thr|
+ Open3.popen3(env, *cmd.shellsplit, chdir: dir) do |stdin, stdout, stderr, wait_thr|
yield stdin, stdout, wait_thr if block_given?
stdin.close
stdout_read_thread = Thread.new { stdout.read }
stderr_read_thread = Thread.new { stderr.read }
- command_execution.stdout = stdout_read_thread.value.strip
- command_execution.stderr = stderr_read_thread.value.strip
+ command_execution.original_stdout = stdout_read_thread.value.strip
+ command_execution.original_stderr = stderr_read_thread.value.strip
status = wait_thr.value
command_execution.exitstatus = if status.exited?
status.exitstatus
elsif status.signaled?
- 128 + status.termsig
+ exit_status_for_signal(status.termsig)
end
end
@@ -220,13 +220,13 @@ module Spec
end
def all_commands_output
- return [] if command_executions.empty?
+ return "" if command_executions.empty?
"\n\nCommands:\n#{command_executions.map(&:to_s_verbose).join("\n\n")}"
end
def config(config = nil, path = bundled_app(".bundle/config"))
- return YAML.load_file(path) unless config
+ return Psych.load_file(path) unless config
FileUtils.mkdir_p(File.dirname(path))
File.open(path, "w") do |f|
f.puts config.to_yaml
@@ -238,36 +238,46 @@ module Spec
config(config, home(".bundle/config"))
end
- def create_file(*args)
- path = bundled_app(args.shift)
- path = args.shift if args.first.is_a?(Pathname)
- str = args.shift || ""
+ def create_file(path, contents = "")
+ path = Pathname.new(path).expand_path(bundled_app) unless path.is_a?(Pathname)
path.dirname.mkpath
File.open(path.to_s, "w") do |f|
- f.puts strip_whitespace(str)
+ f.puts strip_whitespace(contents)
end
end
def gemfile(*args)
- contents = args.shift
+ contents = args.pop
if contents.nil?
- File.open(bundled_app_gemfile, "r", &:read)
+ read_gemfile
else
- create_file("Gemfile", contents, *args)
+ create_file(args.pop || "Gemfile", contents)
end
end
def lockfile(*args)
- contents = args.shift
+ contents = args.pop
if contents.nil?
- File.open(bundled_app_lock, "r", &:read)
+ read_lockfile
else
- create_file("Gemfile.lock", contents, *args)
+ create_file(args.pop || "Gemfile.lock", contents)
end
end
+ def read_gemfile(file = "Gemfile")
+ read_bundled_app_file(file)
+ end
+
+ def read_lockfile(file = "Gemfile.lock")
+ read_bundled_app_file(file)
+ end
+
+ def read_bundled_app_file(file)
+ bundled_app(file).read
+ end
+
def strip_whitespace(str)
# Trim the leading spaces
spaces = str[/\A\s+/, 0] || ""
@@ -275,8 +285,8 @@ module Spec
end
def install_gemfile(*args)
+ opts = args.last.is_a?(Hash) ? args.pop : {}
gemfile(*args)
- opts = args.last.is_a?(Hash) ? args.last : {}
bundle :install, opts
end
@@ -289,65 +299,42 @@ module Spec
def system_gems(*gems)
gems = gems.flatten
options = gems.last.is_a?(Hash) ? gems.pop : {}
- path = options.fetch(:path, system_gem_path)
+ install_dir = options.fetch(:path, system_gem_path)
default = options.fetch(:default, false)
- with_gem_path_as(path) do
+ with_gem_path_as(install_dir) do
gem_repo = options.fetch(:gem_repo, gem_repo1)
gems.each do |g|
gem_name = g.to_s
if gem_name.start_with?("bundler")
version = gem_name.match(/\Abundler-(?<version>.*)\z/)[:version] if gem_name != "bundler"
- with_built_bundler(version) {|gem_path| install_gem(gem_path, default) }
- elsif gem_name =~ %r{\A(?:[a-zA-Z]:)?/.*\.gem\z}
- install_gem(gem_name, default)
+ with_built_bundler(version) {|gem_path| install_gem(gem_path, install_dir, default) }
+ elsif %r{\A(?:[a-zA-Z]:)?/.*\.gem\z}.match?(gem_name)
+ install_gem(gem_name, install_dir, default)
else
- install_gem("#{gem_repo}/gems/#{gem_name}.gem", default)
+ install_gem("#{gem_repo}/gems/#{gem_name}.gem", install_dir, default)
end
end
end
end
- def install_gem(path, default = false)
+ def install_gem(path, install_dir, default = false)
raise "OMG `#{path}` does not exist!" unless File.exist?(path)
- args = "--no-document --ignore-dependencies"
- args += " --default --install-dir #{system_gem_path}" if default
+ args = "--no-document --ignore-dependencies --verbose --local --install-dir #{install_dir}"
+ args += " --default" if default
gem_command "install #{args} '#{path}'"
end
- def with_built_bundler(version = nil)
- version ||= Bundler::VERSION
- full_name = "bundler-#{version}"
- build_path = tmp + full_name
- bundler_path = build_path + "#{full_name}.gem"
-
- Dir.mkdir build_path
-
- begin
- shipped_files.each do |shipped_file|
- target_shipped_file = build_path + shipped_file
- target_shipped_dir = File.dirname(target_shipped_file)
- FileUtils.mkdir_p target_shipped_dir unless File.directory?(target_shipped_dir)
- FileUtils.cp shipped_file, target_shipped_file, :preserve => true
- end
-
- replace_version_file(version, dir: build_path) # rubocop:disable Style/HashSyntax
-
- Spec::BuildMetadata.write_build_metadata(dir: build_path) # rubocop:disable Style/HashSyntax
-
- gem_command "build #{relative_gemspec}", :dir => build_path
-
- yield(bundler_path)
- ensure
- build_path.rmtree
- end
+ def with_built_bundler(version = nil, &block)
+ Builders::BundlerBuilder.new(self, "bundler", version)._build(&block)
end
def with_gem_path_as(path)
without_env_side_effects do
ENV["GEM_HOME"] = path.to_s
ENV["GEM_PATH"] = path.to_s
+ ENV["BUNDLER_ORIG_GEM_HOME"] = nil
ENV["BUNDLER_ORIG_GEM_PATH"] = nil
yield
end
@@ -421,14 +408,14 @@ module Spec
end
end
- def cache_gems(*gems)
+ def cache_gems(*gems, gem_repo: gem_repo1)
gems = gems.flatten
FileUtils.rm_rf("#{bundled_app}/vendor/cache")
FileUtils.mkdir_p("#{bundled_app}/vendor/cache")
gems.each do |g|
- path = "#{gem_repo1}/gems/#{g}.gem"
+ path = "#{gem_repo}/gems/#{g}.gem"
raise "OMG `#{path}` does not exist!" unless File.exist?(path)
FileUtils.cp(path, "#{bundled_app}/vendor/cache")
end
@@ -439,6 +426,14 @@ module Spec
pristine_system_gems :bundler
end
+ def simulate_ruby_platform(ruby_platform)
+ old = ENV["BUNDLER_SPEC_RUBY_PLATFORM"]
+ ENV["BUNDLER_SPEC_RUBY_PLATFORM"] = ruby_platform.to_s
+ yield
+ ensure
+ ENV["BUNDLER_SPEC_RUBY_PLATFORM"] = old
+ end
+
def simulate_platform(platform)
old = ENV["BUNDLER_SPEC_PLATFORM"]
ENV["BUNDLER_SPEC_PLATFORM"] = platform.to_s
@@ -447,49 +442,36 @@ module Spec
ENV["BUNDLER_SPEC_PLATFORM"] = old if block_given?
end
- def simulate_ruby_version(version)
- return if version == RUBY_VERSION
- old = ENV["BUNDLER_SPEC_RUBY_VERSION"]
- ENV["BUNDLER_SPEC_RUBY_VERSION"] = version
- yield if block_given?
- ensure
- ENV["BUNDLER_SPEC_RUBY_VERSION"] = old if block_given?
- end
-
- def simulate_windows(platform = mswin)
+ def simulate_windows(platform = x86_mswin32)
+ old = ENV["BUNDLER_SPEC_WINDOWS"]
+ ENV["BUNDLER_SPEC_WINDOWS"] = "true"
simulate_platform platform do
- simulate_bundler_version_when_missing_prerelease_default_gem_activation do
- yield
- end
+ yield
end
+ ensure
+ ENV["BUNDLER_SPEC_WINDOWS"] = old
end
- def simulate_bundler_version_when_missing_prerelease_default_gem_activation
- return yield unless rubygems_version_failing_to_activate_bundler_prereleases
+ def current_ruby_minor
+ Gem.ruby_version.segments.tap {|s| s.delete_at(2) }.join(".")
+ end
- old = ENV["BUNDLER_VERSION"]
- ENV["BUNDLER_VERSION"] = Bundler::VERSION
- yield
- ensure
- ENV["BUNDLER_VERSION"] = old
+ def next_ruby_minor
+ ruby_major_minor.map.with_index {|s, i| i == 1 ? s + 1 : s }.join(".")
end
- def env_for_missing_prerelease_default_gem_activation
- if rubygems_version_failing_to_activate_bundler_prereleases
- { "BUNDLER_VERSION" => Bundler::VERSION }
- else
- {}
- end
+ def previous_ruby_minor
+ return "2.7" if ruby_major_minor == [3, 0]
+
+ ruby_major_minor.map.with_index {|s, i| i == 1 ? s - 1 : s }.join(".")
end
- # versions providing a bundler version finder but not including
- # https://github.com/rubygems/rubygems/commit/929e92d752baad3a08f3ac92eaec162cb96aedd1
- def rubygems_version_failing_to_activate_bundler_prereleases
- Gem.rubygems_version < Gem::Version.new("3.1.0.pre.1") && Gem.rubygems_version >= Gem::Version.new("2.7.0")
+ def ruby_major_minor
+ Gem.ruby_version.segments[0..1]
end
def revision_for(path)
- sys_exec("git rev-parse HEAD", :dir => path).strip
+ sys_exec("git rev-parse HEAD", dir: path).strip
end
def with_read_only(pattern)
@@ -544,7 +526,7 @@ module Spec
def require_rack
# need to hack, so we can require rack
old_gem_home = ENV["GEM_HOME"]
- ENV["GEM_HOME"] = Spec::Path.base_system_gems.to_s
+ ENV["GEM_HOME"] = Spec::Path.base_system_gem_path.to_s
require "rack"
ENV["GEM_HOME"] = old_gem_home
end
@@ -569,6 +551,11 @@ module Spec
port
end
+ def exit_status_for_signal(signal_number)
+ # For details see: https://en.wikipedia.org/wiki/Exit_status#Shell_and_scripts
+ 128 + signal_number
+ end
+
private
def git_root_dir?
diff --git a/spec/bundler/support/indexes.rb b/spec/bundler/support/indexes.rb
index bf4300edb2..086a311551 100644
--- a/spec/bundler/support/indexes.rb
+++ b/spec/bundler/support/indexes.rb
@@ -14,22 +14,25 @@ module Spec
alias_method :platforms, :platform
- def resolve(args = [])
+ def resolve(args = [], dependency_api_available: true)
@platforms ||= ["ruby"]
- deps = []
- default_source = instance_double("Bundler::Source::Rubygems", :specs => @index)
- source_requirements = { :default => default_source }
+ default_source = instance_double("Bundler::Source::Rubygems", specs: @index, to_s: "locally install gems", dependency_api_available?: dependency_api_available)
+ source_requirements = { default: default_source }
+ base = args[0] || Bundler::SpecSet.new([])
+ base.each {|ls| ls.source = default_source }
+ gem_version_promoter = args[1] || Bundler::GemVersionPromoter.new
+ originally_locked = args[2] || Bundler::SpecSet.new([])
+ unlock = args[3] || []
@deps.each do |d|
- source_requirements[d.name] = d.source = default_source
- @platforms.each do |p|
- deps << Bundler::DepProxy.get_proxy(d, p)
- end
+ name = d.name
+ source_requirements[name] = d.source = default_source
end
- args[0] ||= [] # base
- args[1] ||= Bundler::GemVersionPromoter.new # gem_version_promoter
- args[2] ||= [] # additional_base_requirements
- args[3] ||= @platforms # platforms
- Bundler::Resolver.resolve(deps, source_requirements, *args)
+ packages = Bundler::Resolver::Base.new(source_requirements, @deps, base, @platforms, locked_specs: originally_locked, unlock: unlock)
+ Bundler::Resolver.new(packages, gem_version_promoter).start
+ end
+
+ def should_not_resolve
+ expect { resolve }.to raise_error(Bundler::GemNotFound)
end
def should_resolve_as(specs)
@@ -38,6 +41,12 @@ module Spec
expect(got).to eq(specs.sort)
end
+ def should_resolve_without_dependency_api(specs)
+ got = resolve(dependency_api_available: false)
+ got = got.map(&:full_name).sort
+ expect(got).to eq(specs.sort)
+ end
+
def should_resolve_and_include(specs, args = [])
got = resolve(args)
got = got.map(&:full_name).sort
@@ -46,13 +55,6 @@ module Spec
end
end
- def should_conflict_on(names)
- got = resolve
- raise "The resolve succeeded with: #{got.map(&:full_name).sort.inspect}"
- rescue Bundler::VersionConflict => e
- expect(Array(names).sort).to eq(e.conflicts.sort)
- end
-
def gem(*args, &blk)
build_spec(*args, &blk).first
end
@@ -66,12 +68,11 @@ module Spec
def should_conservative_resolve_and_include(opts, unlock, specs)
# empty unlock means unlock all
opts = Array(opts)
- search = Bundler::GemVersionPromoter.new(@locked, unlock).tap do |s|
+ search = Bundler::GemVersionPromoter.new.tap do |s|
s.level = opts.first
s.strict = opts.include?(:strict)
- s.prerelease_specified = Hash[@deps.map {|d| [d.name, d.requirement.prerelease?] }]
end
- should_resolve_and_include specs, [@base, search]
+ should_resolve_and_include specs, [@base, search, @locked, unlock]
end
def an_awesome_index
@@ -126,7 +127,7 @@ module Spec
next if version == v("1.4.2.1") && platform != pl("x86-mswin32")
next if version == v("1.4.2") && platform == pl("x86-mswin32")
gem "nokogiri", version, platform do
- dep "weakling", ">= 0.0.3" if platform =~ pl("java")
+ dep "weakling", ">= 0.0.3" if platform =~ pl("java") # rubocop:disable Performance/RegexpMatch
end
end
end
@@ -303,7 +304,7 @@ module Spec
end
end
- def a_unresovable_child_index
+ def a_unresolvable_child_index
build_index do
gem "json", %w[1.8.0]
diff --git a/spec/bundler/support/matchers.rb b/spec/bundler/support/matchers.rb
index 180ad54c5b..0f027dcf04 100644
--- a/spec/bundler/support/matchers.rb
+++ b/spec/bundler/support/matchers.rb
@@ -150,7 +150,7 @@ module Spec
end
if exitstatus == 65
actual_platform = out.split("\n").last
- next "#{name} was expected to be of platform #{platform} but was #{actual_platform}"
+ next "#{name} was expected to be of platform #{platform || "ruby"} but was #{actual_platform || "ruby"}"
end
if exitstatus == 66
actual_source = out.split("\n").last
@@ -178,7 +178,7 @@ module Spec
begin
require '#{name}'
- name_constant = '#{Spec::Builders.constantize(name)}'
+ name_constant = #{Spec::Builders.constantize(name)}
if #{version.nil?} || name_constant == '#{version}'
exit 64
else
@@ -208,10 +208,6 @@ module Spec
RSpec::Matchers.define_negated_matcher :not_include_gems, :include_gems
RSpec::Matchers.alias_matcher :include_gem, :include_gems
- def have_lockfile(expected)
- read_as(strip_whitespace(expected))
- end
-
def plugin_should_be_installed(*names)
names.each do |name|
expect(Bundler::Plugin).to be_installed(name)
@@ -225,13 +221,5 @@ module Spec
expect(Bundler::Plugin).not_to be_installed(name)
end
end
-
- def lockfile_should_be(expected)
- expect(bundled_app_lock).to have_lockfile(expected)
- end
-
- def gemfile_should_be(expected)
- expect(bundled_app_gemfile).to read_as(strip_whitespace(expected))
- end
end
end
diff --git a/spec/bundler/support/path.rb b/spec/bundler/support/path.rb
index a98ef7c6cf..7352d5a353 100644
--- a/spec/bundler/support/path.rb
+++ b/spec/bundler/support/path.rb
@@ -30,7 +30,7 @@ module Spec
end
def test_gemfile
- @test_gemfile ||= source_root.join("tool/bundler/test_gems.rb")
+ @test_gemfile ||= tool_dir.join("test_gems.rb")
end
def rubocop_gemfile
@@ -42,7 +42,7 @@ module Spec
end
def dev_gemfile
- @dev_gemfile ||= git_root.join("dev_gems.rb")
+ @dev_gemfile ||= tool_dir.join("dev_gems.rb")
end
def bindir
@@ -71,10 +71,6 @@ module Spec
@spec_dir ||= source_root.join(ruby_core? ? "spec/bundler" : "spec")
end
- def api_request_limit_hack_file
- spec_dir.join("support/api_request_limit_hax.rb")
- end
-
def man_dir
@man_dir ||= lib_dir.join("bundler/man")
end
@@ -84,7 +80,13 @@ module Spec
end
def shipped_files
- @shipped_files ||= loaded_gemspec.files
+ @shipped_files ||= if ruby_core_tarball?
+ loaded_gemspec.files.map {|f| f.gsub(%r{^exe/}, "libexec/") }
+ elsif ruby_core?
+ tracked_files
+ else
+ loaded_gemspec.files
+ end
end
def lib_tracked_files
@@ -118,6 +120,14 @@ module Spec
end
end
+ def default_cache_path(*path)
+ if Bundler.feature_flag.global_gem_cache?
+ home(".bundle/cache", *path)
+ else
+ default_bundle_path("cache/bundler", *path)
+ end
+ end
+
def bundled_app(*path)
root = tmp.join("bundled_app")
FileUtils.mkdir_p(root)
@@ -146,6 +156,10 @@ module Spec
bundled_app("Gemfile.lock")
end
+ def base_system_gem_path
+ scoped_gem_path(base_system_gems)
+ end
+
def base_system_gems
tmp.join("gems/base")
end
@@ -217,13 +231,6 @@ module Spec
root.join("lib")
end
- # Sometimes rubygems version under test does not include
- # https://github.com/rubygems/rubygems/pull/2728 and will not always end up
- # activating the current bundler. In that case, require bundler absolutely.
- def entrypoint
- Gem.rubygems_version < Gem::Version.new("3.1.a") ? "#{lib_dir}/bundler" : "bundler"
- end
-
def global_plugin_gem(*args)
home ".bundle", "plugin", "gems", *args
end
@@ -243,6 +250,13 @@ module Spec
File.open(version_file, "w") {|f| f << contents }
end
+ def replace_required_ruby_version(version, dir:)
+ gemspec_file = File.expand_path("bundler.gemspec", dir)
+ contents = File.read(gemspec_file)
+ contents.sub!(/(^\s+s\.required_ruby_version\s*=\s*)"[^"]+"/, %(\\1"#{version}"))
+ File.open(gemspec_file, "w") {|f| f << contents }
+ end
+
def ruby_core?
# avoid to warnings
@ruby_core ||= nil
@@ -254,16 +268,20 @@ module Spec
end
end
+ def git_root
+ ruby_core? ? source_root : source_root.parent
+ end
+
private
def git_ls_files(glob)
skip "Not running on a git context, since running tests from a tarball" if ruby_core_tarball?
- sys_exec("git ls-files -z -- #{glob}", :dir => source_root).split("\x0")
+ sys_exec("git ls-files -z -- #{glob}", dir: source_root).split("\x0")
end
def tracked_files_glob
- ruby_core? ? "lib/bundler lib/bundler.rb spec/bundler man/bundle*" : ""
+ ruby_core? ? "libexec/bundle* lib/bundler lib/bundler.rb spec/bundler man/bundle*" : "lib exe spec CHANGELOG.md LICENSE.md README.md bundler.gemspec"
end
def lib_tracked_files_glob
@@ -274,20 +292,24 @@ module Spec
ruby_core? ? "man/bundle* man/gemfile*" : "lib/bundler/man/bundle*.1 lib/bundler/man/gemfile*.5"
end
- def git_root
- ruby_core? ? source_root : source_root.parent
- end
-
def ruby_core_tarball?
!git_root.join(".git").directory?
end
def rubocop_gemfile_basename
- source_root.join("tool/bundler/#{RUBY_VERSION.start_with?("2.3") ? "rubocop23_gems.rb" : "rubocop_gems.rb"}")
+ tool_dir.join("rubocop_gems.rb")
end
def standard_gemfile_basename
- source_root.join("tool/bundler/#{RUBY_VERSION.start_with?("2.3") ? "standard23_gems.rb" : "standard_gems.rb"}")
+ tool_dir.join("standard_gems.rb")
+ end
+
+ def tool_dir
+ ruby_core? ? source_root.join("tool/bundler") : source_root.join("../tool/bundler")
+ end
+
+ def templates_dir
+ lib_dir.join("bundler", "templates")
end
extend self
diff --git a/spec/bundler/support/platforms.rb b/spec/bundler/support/platforms.rb
index 0cb7f7cd29..526e1c09a9 100644
--- a/spec/bundler/support/platforms.rb
+++ b/spec/bundler/support/platforms.rb
@@ -21,31 +21,35 @@ module Spec
end
def linux
- Gem::Platform.new(["x86", "linux", nil])
+ Gem::Platform.new("x86_64-linux")
end
- def mswin
+ def x86_mswin32
Gem::Platform.new(["x86", "mswin32", nil])
end
- def mingw
+ def x64_mswin64
+ Gem::Platform.new(["x64", "mswin64", nil])
+ end
+
+ def x86_mingw32
Gem::Platform.new(["x86", "mingw32", nil])
end
- def x64_mingw
+ def x64_mingw32
Gem::Platform.new(["x64", "mingw32", nil])
end
- def all_platforms
- [rb, java, linux, mswin, mingw, x64_mingw]
+ def x64_mingw_ucrt
+ Gem::Platform.new(["x64", "mingw", "ucrt"])
end
- def local
- generic_local_platform
+ def windows_platforms
+ [x86_mswin32, x64_mswin64, x86_mingw32, x64_mingw32, x64_mingw_ucrt]
end
- def specific_local_platform
- Bundler.local_platform
+ def all_platforms
+ [rb, java, linux, windows_platforms].flatten
end
def not_local
@@ -55,13 +59,15 @@ module Spec
def local_tag
if RUBY_PLATFORM == "java"
:jruby
+ elsif ["x64-mingw32", "x64-mingw-ucrt"].include?(RUBY_PLATFORM)
+ :windows
else
:ruby
end
end
def not_local_tag
- [:ruby, :jruby].find {|tag| tag != local_tag }
+ [:jruby, :windows, :ruby].find {|tag| tag != local_tag }
end
def local_ruby_engine
@@ -69,12 +75,12 @@ module Spec
end
def local_engine_version
- RUBY_ENGINE_VERSION
+ RUBY_ENGINE == "ruby" ? Gem.ruby_version : RUBY_ENGINE_VERSION
end
def not_local_engine_version
case not_local_tag
- when :ruby
+ when :ruby, :windows
not_local_ruby_version
when :jruby
"1.6.1"
@@ -89,12 +95,17 @@ module Spec
9999
end
- def lockfile_platforms
- local_platforms.map(&:to_s).sort.join("\n ")
+ def default_platform_list(*extra, defaults: default_locked_platforms)
+ defaults.concat(extra).uniq
+ end
+
+ def lockfile_platforms(*extra, defaults: default_locked_platforms)
+ platforms = default_platform_list(*extra, defaults: defaults)
+ platforms.map(&:to_s).sort.join("\n ")
end
- def local_platforms
- [specific_local_platform]
+ def default_locked_platforms
+ [local_platform, generic_local_platform]
end
end
end
diff --git a/spec/bundler/support/rubygems_ext.rb b/spec/bundler/support/rubygems_ext.rb
index 9389543a0f..889ebc90c3 100644
--- a/spec/bundler/support/rubygems_ext.rb
+++ b/spec/bundler/support/rubygems_ext.rb
@@ -18,9 +18,15 @@ module Spec
gem_load_and_activate(gem_name, bin_container)
end
- def gem_require(gem_name)
+ def gem_load_and_possibly_install(gem_name, bin_container)
+ require_relative "switch_rubygems"
+
+ gem_load_activate_and_possibly_install(gem_name, bin_container)
+ end
+
+ def gem_require(gem_name, entrypoint)
gem_activate(gem_name)
- require gem_name
+ require entrypoint
end
def test_setup
@@ -32,6 +38,10 @@ module Spec
FileUtils.mkdir_p(Path.tmpdir)
ENV["HOME"] = Path.home.to_s
+ # Remove "RUBY_CODESIGN", which is used by mkmf-generated Makefile to
+ # sign extension bundles on macOS, to avoid trying to find the specified key
+ # from the fake $HOME/Library/Keychains directory.
+ ENV.delete "RUBY_CODESIGN"
ENV["TMPDIR"] = Path.tmpdir.to_s
require "rubygems/user_interaction"
@@ -59,15 +69,13 @@ module Spec
Gem.clear_paths
ENV["BUNDLE_PATH"] = nil
- ENV["GEM_HOME"] = ENV["GEM_PATH"] = Path.base_system_gems.to_s
+ ENV["GEM_HOME"] = ENV["GEM_PATH"] = Path.base_system_gem_path.to_s
ENV["PATH"] = [Path.system_gem_path.join("bin"), ENV["PATH"]].join(File::PATH_SEPARATOR)
ENV["PATH"] = [Path.bindir, ENV["PATH"]].join(File::PATH_SEPARATOR) if Path.ruby_core?
end
def install_test_deps
- setup_test_paths
-
- install_gems(test_gemfile)
+ install_gems(test_gemfile, Path.base_system_gems.to_s)
install_gems(rubocop_gemfile, Path.rubocop_gems.to_s)
install_gems(standard_gemfile, Path.standard_gems.to_s)
end
@@ -82,7 +90,7 @@ module Spec
puts success_message
puts
else
- system("git status --porcelain")
+ system("git diff")
puts
puts error_message
@@ -101,15 +109,30 @@ module Spec
abort "We couldn't activate #{gem_name} (#{e.requirement}). Run `gem install #{gem_name}:'#{e.requirement}'`"
end
+ def gem_load_activate_and_possibly_install(gem_name, bin_container)
+ gem_activate_and_possibly_install(gem_name)
+ load Gem.bin_path(gem_name, bin_container)
+ end
+
+ def gem_activate_and_possibly_install(gem_name)
+ gem_activate(gem_name)
+ rescue Gem::LoadError => e
+ Gem.install(gem_name, e.requirement)
+ retry
+ end
+
def gem_activate(gem_name)
+ require_relative "activate"
require "bundler"
- gem_requirement = Bundler::LockfileParser.new(File.read(dev_lockfile)).dependencies[gem_name]&.requirement
+ gem_requirement = Bundler::LockfileParser.new(File.read(dev_lockfile)).specs.find {|spec| spec.name == gem_name }.version
gem gem_name, gem_requirement
end
def install_gems(gemfile, path = nil)
old_gemfile = ENV["BUNDLE_GEMFILE"]
+ old_orig_gemfile = ENV["BUNDLER_ORIG_BUNDLE_GEMFILE"]
ENV["BUNDLE_GEMFILE"] = gemfile.to_s
+ ENV["BUNDLER_ORIG_BUNDLE_GEMFILE"] = nil
if path
old_path = ENV["BUNDLE_PATH"]
@@ -119,8 +142,8 @@ module Spec
ENV["BUNDLE_PATH__SYSTEM"] = "true"
end
- output = `#{Gem.ruby} #{File.expand_path("support/bundle.rb", Path.spec_dir)} install`
- raise "Error when installing gems in #{gemfile}: #{output}" unless $?.success?
+ puts `#{Gem.ruby} #{File.expand_path("support/bundle.rb", Path.spec_dir)} install --verbose`
+ raise unless $?.success?
ensure
if path
ENV["BUNDLE_PATH"] = old_path
@@ -128,6 +151,7 @@ module Spec
ENV["BUNDLE_PATH__SYSTEM"] = old_path__system
end
+ ENV["BUNDLER_ORIG_BUNDLE_GEMFILE"] = old_orig_gemfile
ENV["BUNDLE_GEMFILE"] = old_gemfile
end
diff --git a/spec/bundler/support/rubygems_version_manager.rb b/spec/bundler/support/rubygems_version_manager.rb
index c2e5a5f484..88da14b67e 100644
--- a/spec/bundler/support/rubygems_version_manager.rb
+++ b/spec/bundler/support/rubygems_version_manager.rb
@@ -24,30 +24,23 @@ class RubygemsVersionManager
def assert_system_features_not_loaded!
at_exit do
- errors = if $?.nil?
- ""
- else
- all_commands_output
- end
-
rubylibdir = RbConfig::CONFIG["rubylibdir"]
rubygems_path = rubylibdir + "/rubygems"
rubygems_default_path = rubygems_path + "/defaults"
bundler_path = rubylibdir + "/bundler"
- bundler_exemptions = Gem.rubygems_version < Gem::Version.new("3.2.0") ? [bundler_path + "/errors.rb"] : []
bad_loaded_features = $LOADED_FEATURES.select do |loaded_feature|
(loaded_feature.start_with?(rubygems_path) && !loaded_feature.start_with?(rubygems_default_path)) ||
- (loaded_feature.start_with?(bundler_path) && !bundler_exemptions.any? {|bundler_exemption| loaded_feature.start_with?(bundler_exemption) })
+ loaded_feature.start_with?(bundler_path)
end
- if bad_loaded_features.any?
- errors += "the following features were incorrectly loaded:\n#{bad_loaded_features.join("\n")}"
+ errors = if bad_loaded_features.any?
+ all_commands_output + "the following features were incorrectly loaded:\n#{bad_loaded_features.join("\n")}"
end
- raise errors unless errors.empty?
+ raise errors if errors
end
end
@@ -72,7 +65,7 @@ class RubygemsVersionManager
def switch_local_copy_if_needed
return unless local_copy_switch_needed?
- sys_exec("git checkout #{target_tag}", :dir => local_copy_path)
+ sys_exec("git checkout #{target_tag}", dir: local_copy_path)
ENV["RGV"] = local_copy_path.to_s
end
@@ -91,7 +84,7 @@ class RubygemsVersionManager
end
def local_copy_tag
- sys_exec("git rev-parse --abbrev-ref HEAD", :dir => local_copy_path)
+ sys_exec("git rev-parse --abbrev-ref HEAD", dir: local_copy_path)
end
def local_copy_path
@@ -104,7 +97,7 @@ class RubygemsVersionManager
rubygems_path = source_root.join("tmp/rubygems")
unless rubygems_path.directory?
- sys_exec("git clone .. #{rubygems_path}", :dir => source_root)
+ sys_exec("git clone .. #{rubygems_path}", dir: source_root)
end
rubygems_path
@@ -119,7 +112,7 @@ class RubygemsVersionManager
end
def resolve_target_tag
- return "v#{@source}" if @source.match(/^\d/)
+ return "v#{@source}" if @source.match?(/^\d/)
@source
end
diff --git a/spec/bundler/support/sudo.rb b/spec/bundler/support/sudo.rb
deleted file mode 100644
index 04e9443945..0000000000
--- a/spec/bundler/support/sudo.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module Spec
- module Sudo
- def self.present?
- @which_sudo ||= Bundler.which("sudo")
- end
-
- def sudo(cmd)
- raise "sudo not present" unless Sudo.present?
- sys_exec("sudo #{cmd}")
- end
-
- def chown_system_gems_to_root
- sudo "chown -R root #{system_gem_path}"
- end
- end
-end
diff --git a/spec/bundler/update/gemfile_spec.rb b/spec/bundler/update/gemfile_spec.rb
index 1c5294101e..d32a7945b0 100644
--- a/spec/bundler/update/gemfile_spec.rb
+++ b/spec/bundler/update/gemfile_spec.rb
@@ -8,8 +8,8 @@ RSpec.describe "bundle update" do
gem 'rack'
G
- bundle :install, :gemfile => bundled_app("NotGemfile")
- bundle :update, :gemfile => bundled_app("NotGemfile"), :all => true
+ bundle :install, gemfile: bundled_app("NotGemfile")
+ bundle :update, gemfile: bundled_app("NotGemfile"), all: true
# Specify BUNDLE_GEMFILE for `the_bundle`
# to retrieve the proper Gemfile
@@ -30,7 +30,7 @@ RSpec.describe "bundle update" do
end
it "uses the gemfile to update" do
- bundle "update", :all => true
+ bundle "update", all: true
bundle "list"
expect(out).to include("rack (1.0.0)")
@@ -38,8 +38,8 @@ RSpec.describe "bundle update" do
it "uses the gemfile while in a subdirectory" do
bundled_app("subdir").mkpath
- bundle "update", :all => true, :dir => bundled_app("subdir")
- bundle "list", :dir => bundled_app("subdir")
+ bundle "update", all: true, dir: bundled_app("subdir")
+ bundle "list", dir: bundled_app("subdir")
expect(out).to include("rack (1.0.0)")
end
diff --git a/spec/bundler/update/gems/fund_spec.rb b/spec/bundler/update/gems/fund_spec.rb
index 0dfe63d36d..4a87c16bf7 100644
--- a/spec/bundler/update/gems/fund_spec.rb
+++ b/spec/bundler/update/gems/fund_spec.rb
@@ -5,20 +5,20 @@ RSpec.describe "bundle update" do
build_repo2 do
build_gem "has_funding_and_other_metadata" do |s|
s.metadata = {
- "bug_tracker_uri" => "https://example.com/user/bestgemever/issues",
- "changelog_uri" => "https://example.com/user/bestgemever/CHANGELOG.md",
+ "bug_tracker_uri" => "https://example.com/user/bestgemever/issues",
+ "changelog_uri" => "https://example.com/user/bestgemever/CHANGELOG.md",
"documentation_uri" => "https://www.example.info/gems/bestgemever/0.0.1",
- "homepage_uri" => "https://bestgemever.example.io",
- "mailing_list_uri" => "https://groups.example.com/bestgemever",
- "funding_uri" => "https://example.com/has_funding_and_other_metadata/funding",
- "source_code_uri" => "https://example.com/user/bestgemever",
- "wiki_uri" => "https://example.com/user/bestgemever/wiki",
+ "homepage_uri" => "https://bestgemever.example.io",
+ "mailing_list_uri" => "https://groups.example.com/bestgemever",
+ "funding_uri" => "https://example.com/has_funding_and_other_metadata/funding",
+ "source_code_uri" => "https://example.com/user/bestgemever",
+ "wiki_uri" => "https://example.com/user/bestgemever/wiki",
}
end
build_gem "has_funding", "1.2.3" do |s|
s.metadata = {
- "funding_uri" => "https://example.com/has_funding/funding",
+ "funding_uri" => "https://example.com/has_funding/funding",
}
end
end
@@ -40,7 +40,7 @@ RSpec.describe "bundle update" do
gem 'has_funding'
G
- bundle :update, :all => true
+ bundle :update, all: true
end
it "displays fund message" do
diff --git a/spec/bundler/update/gems/post_install_spec.rb b/spec/bundler/update/gems/post_install_spec.rb
index 3aaa659d57..e3593387d4 100644
--- a/spec/bundler/update/gems/post_install_spec.rb
+++ b/spec/bundler/update/gems/post_install_spec.rb
@@ -52,7 +52,7 @@ RSpec.describe "bundle update" do
gem 'thin'
G
- bundle :update, :all => true
+ bundle :update, all: true
end
it_behaves_like "a post-install message outputter"
@@ -67,7 +67,7 @@ RSpec.describe "bundle update" do
gem 'thin'
G
- bundle :update, :all => true
+ bundle :update, all: true
end
it_behaves_like "a post-install message outputter"
diff --git a/spec/bundler/update/git_spec.rb b/spec/bundler/update/git_spec.rb
index 26ad1b45d3..3b7bbfd979 100644
--- a/spec/bundler/update/git_spec.rb
+++ b/spec/bundler/update/git_spec.rb
@@ -4,7 +4,7 @@ RSpec.describe "bundle update" do
describe "git sources" do
it "floats on a branch when :branch is used" do
build_git "foo", "1.0"
- update_git "foo", :branch => "omg"
+ update_git "foo", branch: "omg"
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -13,18 +13,18 @@ RSpec.describe "bundle update" do
end
G
- update_git "foo", :branch => "omg" do |s|
+ update_git "foo" do |s|
s.write "lib/foo.rb", "FOO = '1.1'"
end
- bundle "update", :all => true
+ bundle "update", all: true
expect(the_bundle).to include_gems "foo 1.1"
end
it "updates correctly when you have like craziness" do
- build_lib "activesupport", "3.0", :path => lib_path("rails/activesupport")
- build_git "rails", "3.0", :path => lib_path("rails") do |s|
+ build_lib "activesupport", "3.0", path: lib_path("rails/activesupport")
+ build_git "rails", "3.0", path: lib_path("rails") do |s|
s.add_dependency "activesupport", "= 3.0"
end
@@ -38,8 +38,8 @@ RSpec.describe "bundle update" do
end
it "floats on a branch when :branch is used and the source is specified in the update" do
- build_git "foo", "1.0", :path => lib_path("foo")
- update_git "foo", :branch => "omg", :path => lib_path("foo")
+ build_git "foo", "1.0", path: lib_path("foo")
+ update_git "foo", branch: "omg", path: lib_path("foo")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -48,7 +48,7 @@ RSpec.describe "bundle update" do
end
G
- update_git "foo", :branch => "omg", :path => lib_path("foo") do |s|
+ update_git "foo", path: lib_path("foo") do |s|
s.write "lib/foo.rb", "FOO = '1.1'"
end
@@ -57,9 +57,9 @@ RSpec.describe "bundle update" do
expect(the_bundle).to include_gems "foo 1.1"
end
- it "floats on master when updating all gems that are pinned to the source even if you have child dependencies" do
- build_git "foo", :path => lib_path("foo")
- build_gem "bar", :to_bundle => true do |s|
+ it "floats on main when updating all gems that are pinned to the source even if you have child dependencies" do
+ build_git "foo", path: lib_path("foo")
+ build_gem "bar", to_bundle: true do |s|
s.add_dependency "foo"
end
@@ -69,7 +69,7 @@ RSpec.describe "bundle update" do
gem "bar"
G
- update_git "foo", :path => lib_path("foo") do |s|
+ update_git "foo", path: lib_path("foo") do |s|
s.write "lib/foo.rb", "FOO = '1.1'"
end
@@ -79,8 +79,8 @@ RSpec.describe "bundle update" do
end
it "notices when you change the repo url in the Gemfile" do
- build_git "foo", :path => lib_path("foo_one")
- build_git "foo", :path => lib_path("foo_two")
+ build_git "foo", path: lib_path("foo_one")
+ build_git "foo", path: lib_path("foo_two")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -101,9 +101,9 @@ RSpec.describe "bundle update" do
it "fetches tags from the remote" do
build_git "foo"
- @remote = build_git("bar", :bare => true)
- update_git "foo", :remote => file_uri_for(@remote.path)
- update_git "foo", :push => "master"
+ @remote = build_git("bar", bare: true)
+ update_git "foo", remote: file_uri_for(@remote.path)
+ update_git "foo", push: "main"
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
@@ -111,19 +111,23 @@ RSpec.describe "bundle update" do
G
# Create a new tag on the remote that needs fetching
- update_git "foo", :tag => "fubar"
- update_git "foo", :push => "fubar"
+ update_git "foo", tag: "fubar"
+ update_git "foo", push: "fubar"
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => "#{@remote.path}", :tag => "fubar"
G
- bundle "update", :all => true
+ bundle "update", all: true
+ expect(err).to be_empty
end
describe "with submodules" do
before :each do
+ # CVE-2022-39253: https://lore.kernel.org/lkml/xmqq4jw1uku5.fsf@gitster.g/
+ system(*%W[git config --global protocol.file.allow always])
+
build_repo4 do
build_gem "submodule" do |s|
s.write "lib/submodule.rb", "puts 'GEM'"
@@ -138,8 +142,8 @@ RSpec.describe "bundle update" do
s.add_dependency "submodule"
end
- sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0")
- sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0")
+ sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", dir: lib_path("has_submodule-1.0")
+ sys_exec "git commit -m \"submodulator\"", dir: lib_path("has_submodule-1.0")
end
it "it unlocks the source when submodules are added to a git source" do
@@ -164,7 +168,7 @@ RSpec.describe "bundle update" do
expect(out).to eq("GIT")
end
- it "unlocks the source when submodules are removed from git source", :git => ">= 2.9.0" do
+ it "unlocks the source when submodules are removed from git source", git: ">= 2.9.0" do
install_gemfile <<-G
source "#{file_uri_for(gem_repo4)}"
git "#{lib_path("has_submodule-1.0")}", :submodules => true do
@@ -197,7 +201,7 @@ RSpec.describe "bundle update" do
lib_path("foo-1.0").join(".git").rmtree
- bundle :update, :all => true, :raise_on_error => false
+ bundle :update, all: true, raise_on_error: false
expect(err).to include(lib_path("foo-1.0").to_s).
and match(/Git error: command `git fetch.+has failed/)
end
@@ -205,13 +209,13 @@ RSpec.describe "bundle update" do
it "should not explode on invalid revision on update of gem by name" do
build_git "rack", "0.8"
- build_git "rack", "0.8", :path => lib_path("local-rack") do |s|
+ build_git "rack", "0.8", path: lib_path("local-rack") do |s|
s.write "lib/rack.rb", "puts :LOCAL"
end
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
- gem "rack", :git => "#{file_uri_for(lib_path("rack-0.8"))}", :branch => "master"
+ gem "rack", :git => "#{file_uri_for(lib_path("rack-0.8"))}", :branch => "main"
G
bundle %(config set local.rack #{lib_path("local-rack")})
@@ -220,24 +224,24 @@ RSpec.describe "bundle update" do
end
it "shows the previous version of the gem" do
- build_git "rails", "2.3.2", :path => lib_path("rails")
+ build_git "rails", "2.3.2", path: lib_path("rails")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rails", :git => "#{file_uri_for(lib_path("rails"))}"
G
- update_git "rails", "3.0", :path => lib_path("rails"), :gemspec => true
+ update_git "rails", "3.0", path: lib_path("rails"), gemspec: true
- bundle "update", :all => true
- expect(out).to include("Using rails 3.0 (was 2.3.2) from #{file_uri_for(lib_path("rails"))} (at master@#{revision_for(lib_path("rails"))[0..6]})")
+ bundle "update", all: true
+ expect(out).to include("Using rails 3.0 (was 2.3.2) from #{file_uri_for(lib_path("rails"))} (at main@#{revision_for(lib_path("rails"))[0..6]})")
end
end
describe "with --source flag" do
before :each do
build_repo2
- @git = build_git "foo", :path => lib_path("foo") do |s|
+ @git = build_git "foo", path: lib_path("foo") do |s|
s.executables = "foobar"
end
@@ -251,7 +255,7 @@ RSpec.describe "bundle update" do
end
it "updates the source" do
- update_git "foo", :path => @git.path
+ update_git "foo", path: @git.path
bundle "update --source foo"
@@ -264,7 +268,7 @@ RSpec.describe "bundle update" do
end
it "unlocks gems that were originally pulled in by the source" do
- update_git "foo", "2.0", :path => @git.path
+ update_git "foo", "2.0", path: @git.path
bundle "update --source foo"
expect(the_bundle).to include_gems "foo 2.0"
@@ -272,7 +276,7 @@ RSpec.describe "bundle update" do
it "leaves all other gems frozen" do
update_repo2
- update_git "foo", :path => @git.path
+ update_git "foo", path: @git.path
bundle "update --source foo"
expect(the_bundle).to include_gems "rack 1.0"
@@ -282,7 +286,7 @@ RSpec.describe "bundle update" do
context "when the gem and the repository have different names" do
before :each do
build_repo2
- @git = build_git "foo", :path => lib_path("bar")
+ @git = build_git "foo", path: lib_path("bar")
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
@@ -293,55 +297,24 @@ RSpec.describe "bundle update" do
G
end
- it "the --source flag updates version of gems that were originally pulled in by the source", :bundler => "< 3" do
+ it "the --source flag updates version of gems that were originally pulled in by the source" do
spec_lines = lib_path("bar/foo.gemspec").read.split("\n")
spec_lines[5] = "s.version = '2.0'"
- update_git "foo", "2.0", :path => @git.path do |s|
+ update_git "foo", "2.0", path: @git.path do |s|
s.write "foo.gemspec", spec_lines.join("\n")
end
- ref = @git.ref_for "master"
+ ref = @git.ref_for "main"
bundle "update --source bar"
- lockfile_should_be <<-G
- GIT
- remote: #{@git.path}
- revision: #{ref}
- specs:
- foo (2.0)
-
- GEM
- remote: #{file_uri_for(gem_repo2)}/
- specs:
- rack (1.0.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- foo!
- rack
-
- BUNDLED WITH
- #{Bundler::VERSION}
- G
- end
-
- it "the --source flag updates version of gems that were originally pulled in by the source", :bundler => "3" do
- spec_lines = lib_path("bar/foo.gemspec").read.split("\n")
- spec_lines[5] = "s.version = '2.0'"
-
- update_git "foo", "2.0", :path => @git.path do |s|
- s.write "foo.gemspec", spec_lines.join("\n")
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "foo", "2.0"
+ c.checksum gem_repo2, "rack", "1.0.0"
end
- ref = @git.ref_for "master"
-
- bundle "update --source bar"
-
- lockfile_should_be <<-G
+ expect(lockfile).to eq <<~G
GIT
remote: #{@git.path}
revision: #{ref}
@@ -359,7 +332,7 @@ RSpec.describe "bundle update" do
DEPENDENCIES
foo!
rack
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
diff --git a/spec/bundler/update/path_spec.rb b/spec/bundler/update/path_spec.rb
index 756770313b..1f8992b33f 100644
--- a/spec/bundler/update/path_spec.rb
+++ b/spec/bundler/update/path_spec.rb
@@ -3,14 +3,14 @@
RSpec.describe "path sources" do
describe "bundle update --source" do
it "shows the previous version of the gem when updated from path source" do
- build_lib "activesupport", "2.3.5", :path => lib_path("rails/activesupport")
+ build_lib "activesupport", "2.3.5", path: lib_path("rails/activesupport")
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "activesupport", :path => "#{lib_path("rails/activesupport")}"
G
- build_lib "activesupport", "3.0", :path => lib_path("rails/activesupport")
+ build_lib "activesupport", "3.0", path: lib_path("rails/activesupport")
bundle "update --source activesupport"
expect(out).to include("Using activesupport 3.0 (was 2.3.5) from source at `#{lib_path("rails/activesupport")}`")
diff --git a/spec/bundler/update/redownload_spec.rb b/spec/bundler/update/redownload_spec.rb
index 147be823f5..4a8c711bfa 100644
--- a/spec/bundler/update/redownload_spec.rb
+++ b/spec/bundler/update/redownload_spec.rb
@@ -9,12 +9,12 @@ RSpec.describe "bundle update" do
end
describe "with --force" do
- it "shows a deprecation when single flag passed", :bundler => 2 do
+ it "shows a deprecation when single flag passed", bundler: 2 do
bundle "update rack --force"
expect(err).to include "[DEPRECATED] The `--force` option has been renamed to `--redownload`"
end
- it "shows a deprecation when multiple flags passed", :bundler => 2 do
+ it "shows a deprecation when multiple flags passed", bundler: 2 do
bundle "update rack --no-color --force"
expect(err).to include "[DEPRECATED] The `--force` option has been renamed to `--redownload`"
end
@@ -30,5 +30,15 @@ RSpec.describe "bundle update" do
bundle "update rack --no-color --redownload"
expect(err).not_to include "[DEPRECATED] The `--force` option has been renamed to `--redownload`"
end
+
+ it "re-installs installed gems" do
+ rack_lib = default_bundle_path("gems/rack-1.0.0/lib/rack.rb")
+ rack_lib.open("w") {|f| f.write("blah blah blah") }
+ bundle :update, redownload: true
+
+ expect(out).to include "Installing rack 1.0.0"
+ expect(rack_lib.open(&:read)).to eq("RACK = '1.0.0'\n")
+ expect(the_bundle).to include_gems "rack 1.0.0"
+ end
end
end