diff options
Diffstat (limited to 'spec')
35 files changed, 1424 insertions, 423 deletions
diff --git a/spec/bundler/bundler/dep_proxy_spec.rb b/spec/bundler/bundler/dep_proxy_spec.rb index 84243d2ee2..8d02a33725 100644 --- a/spec/bundler/bundler/dep_proxy_spec.rb +++ b/spec/bundler/bundler/dep_proxy_spec.rb @@ -22,7 +22,7 @@ RSpec.describe Bundler::DepProxy do end describe "frozen" do - if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.5.0") + if Gem.ruby_version >= Gem::Version.new("2.5.0") error = Object.const_get("FrozenError") else error = RuntimeError diff --git a/spec/bundler/bundler/gem_helper_spec.rb b/spec/bundler/bundler/gem_helper_spec.rb index d718615ad2..6c3ac3e035 100644 --- a/spec/bundler/bundler/gem_helper_spec.rb +++ b/spec/bundler/bundler/gem_helper_spec.rb @@ -9,7 +9,7 @@ RSpec.describe Bundler::GemHelper do let(:app_gemspec_path) { app_path.join("#{app_name}.gemspec") } before(:each) do - global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__RUBOCOP" => "false", + 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" bundle "gem #{app_name}" prepare_gemspec(app_gemspec_path) @@ -61,10 +61,16 @@ RSpec.describe Bundler::GemHelper do mock_confirm_message message end + def mock_checksum_message(name, version) + message = "#{name} #{version} checksum written to checksums/#{name}-#{version}.gem.sha512." + mock_confirm_message message + end + subject! { Bundler::GemHelper.new(app_path) } let(:app_version) { "0.1.0" } let(:app_gem_dir) { app_path.join("pkg") } let(:app_gem_path) { app_gem_dir.join("#{app_name}-#{app_version}.gem") } + let(:app_sha_path) { app_path.join("checksums", "#{app_name}-#{app_version}.gem.sha512") } let(:app_gemspec_content) { File.read(app_gemspec_path) } before(:each) do @@ -162,6 +168,37 @@ RSpec.describe Bundler::GemHelper do end end + describe "#build_checksum" do + 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 + end + end + context "when building in the current working directory" do + it "creates a .sha512 file" do + mock_build_message app_name, app_version + mock_checksum_message app_name, app_version + Dir.chdir app_path do + Bundler::GemHelper.new.build_checksum + end + expect(app_sha_path).to exist + end + end + context "when building in a location relative to the current working directory" do + it "creates a .sha512 file" do + mock_build_message app_name, app_version + mock_checksum_message app_name, app_version + Dir.chdir File.dirname(app_path) do + Bundler::GemHelper.new(File.basename(app_path)).build_checksum + end + expect(app_sha_path).to exist + end + end + end + describe "#install_gem" do context "when installation was successful" do it "gem is installed" do diff --git a/spec/bundler/bundler/installer/parallel_installer_spec.rb b/spec/bundler/bundler/installer/parallel_installer_spec.rb index ace5c1a23a..e680633862 100644 --- a/spec/bundler/bundler/installer/parallel_installer_spec.rb +++ b/spec/bundler/bundler/installer/parallel_installer_spec.rb @@ -44,4 +44,37 @@ The missing gems are: 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 a9cf09a372..e63ef26cb3 100644 --- a/spec/bundler/bundler/installer/spec_installation_spec.rb +++ b/spec/bundler/bundler/installer/spec_installation_spec.rb @@ -8,6 +8,10 @@ RSpec.describe Bundler::ParallelInstaller::SpecInstallation do def a_spec.name "I like tests" end + + def a_spec.full_name + "I really like tests" + end a_spec end diff --git a/spec/bundler/bundler/source_list_spec.rb b/spec/bundler/bundler/source_list_spec.rb index 3a0691b959..0c40ba8a77 100644 --- a/spec/bundler/bundler/source_list_spec.rb +++ b/spec/bundler/bundler/source_list_spec.rb @@ -372,26 +372,7 @@ RSpec.describe Bundler::SourceList do source_list.add_git_source("uri" => "git://first-git.org/path.git") end - it "combines the rubygems sources into a single instance, removing duplicate remotes from the end", :bundler => "< 3" do - expect(source_list.lock_sources).to eq [ - Bundler::Source::Git.new("uri" => "git://first-git.org/path.git"), - Bundler::Source::Git.new("uri" => "git://second-git.org/path.git"), - Bundler::Source::Git.new("uri" => "git://third-git.org/path.git"), - ASourcePlugin.new("uri" => "https://second-plugin.org/random"), - ASourcePlugin.new("uri" => "https://third-bar.org/foo"), - Bundler::Source::Path.new("path" => "/first/path/to/gem"), - Bundler::Source::Path.new("path" => "/second/path/to/gem"), - Bundler::Source::Path.new("path" => "/third/path/to/gem"), - Bundler::Source::Rubygems.new("remotes" => [ - "https://duplicate-rubygems.org", - "https://first-rubygems.org", - "https://second-rubygems.org", - "https://third-rubygems.org", - ]), - ] - end - - it "returns all sources, without combining rubygems sources", :bundler => "3" do + it "returns all sources, without combining rubygems sources" do expect(source_list.lock_sources).to eq [ Bundler::Source::Git.new("uri" => "git://first-git.org/path.git"), Bundler::Source::Git.new("uri" => "git://second-git.org/path.git"), diff --git a/spec/bundler/commands/info_spec.rb b/spec/bundler/commands/info_spec.rb index 7702959306..daed4587d5 100644 --- a/spec/bundler/commands/info_spec.rb +++ b/spec/bundler/commands/info_spec.rb @@ -182,4 +182,18 @@ RSpec.describe "bundle info" do expect(err).to include("Could not find gem '#{invalid_regexp}'.") end end + + context "with without configured" do + it "does not find the gem, but gives a helpful error" do + bundle "config without test" + + install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + gem "rails", group: :test + G + + 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 end diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb index 7724170a63..264af30f6c 100644 --- a/spec/bundler/commands/lock_spec.rb +++ b/spec/bundler/commands/lock_spec.rb @@ -86,7 +86,7 @@ RSpec.describe "bundle lock" do it "does not fetch remote specs when using the --local option" do bundle "lock --update --local", :raise_on_error => false - expect(err).to match(/sources listed in your Gemfile|installed locally/) + expect(err).to match(/installed locally/) end it "works with --gemfile flag" do diff --git a/spec/bundler/commands/newgem_spec.rb b/spec/bundler/commands/newgem_spec.rb index c1d5e1814d..00bd009c5a 100644 --- a/spec/bundler/commands/newgem_spec.rb +++ b/spec/bundler/commands/newgem_spec.rb @@ -12,15 +12,16 @@ RSpec.describe "bundle gem" do def bundle_exec_rubocop prepare_gemspec(bundled_app(gem_name, "#{gem_name}.gemspec")) - rubocop_version = RUBY_VERSION > "2.4" ? "1.7.0" : "0.81.0" - gems = ["minitest", "rake", "rake-compiler", "rspec", "rubocop -v #{rubocop_version}", "test-unit"] - gems.unshift "parallel -v 1.19.2" if RUBY_VERSION < "2.5" - gems += ["rubocop-ast -v 1.4.0"] if rubocop_version == "1.7.0" - path = Bundler.feature_flag.default_install_uses_path? ? local_gem_path(:base => bundled_app(gem_name)) : system_gem_path - realworld_system_gems gems, :path => path + 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) + end + let(:generated_gemspec) { Bundler.load_gemspec_uncached(bundled_app(gem_name).join("#{gem_name}.gemspec")) } let(:gem_name) { "mygem" } @@ -102,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" 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" @@ -147,8 +148,68 @@ RSpec.describe "bundle gem" do end shared_examples_for "--rubocop flag" do + context "is deprecated", :bundler => "< 3" do + before do + bundle "gem #{gem_name} --rubocop" + end + + it "generates a gem skeleton with rubocop" do + gem_skeleton_assertions + expect(bundled_app("test-gem/Rakefile")).to read_as( + include("# frozen_string_literal: true"). + and(include('require "rubocop/rake_task"'). + and(include("RuboCop::RakeTask.new"). + and(match(/default:.+:rubocop/)))) + ) + end + + it "includes rubocop in generated Gemfile" do + allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) + builder = Bundler::Dsl.new + builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile")) + builder.dependencies + rubocop_dep = builder.dependencies.find {|d| d.name == "rubocop" } + expect(rubocop_dep).not_to be_nil + end + + it "generates a default .rubocop.yml" do + expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist + end + end + end + + shared_examples_for "--no-rubocop flag" do + context "is deprecated", :bundler => "< 3" do + define_negated_matcher :exclude, :include + + before do + bundle "gem #{gem_name} --no-rubocop" + end + + it "generates a gem skeleton without rubocop" do + gem_skeleton_assertions + expect(bundled_app("test-gem/Rakefile")).to read_as(exclude("rubocop")) + expect(bundled_app("test-gem/#{gem_name}.gemspec")).to read_as(exclude("rubocop")) + end + + it "does not include rubocop in generated Gemfile" do + allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) + builder = Bundler::Dsl.new + builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile")) + builder.dependencies + rubocop_dep = builder.dependencies.find {|d| d.name == "rubocop" } + expect(rubocop_dep).to be_nil + end + + it "doesn't generate a default .rubocop.yml" do + expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist + end + end + end + + shared_examples_for "--linter=rubocop flag" do before do - bundle "gem #{gem_name} --rubocop" + bundle "gem #{gem_name} --linter=rubocop" end it "generates a gem skeleton with rubocop" do @@ -175,11 +236,38 @@ RSpec.describe "bundle gem" do end end - shared_examples_for "--no-rubocop flag" do + shared_examples_for "--linter=standard flag" do + before do + bundle "gem #{gem_name} --linter=standard" + end + + it "generates a gem skeleton with standard" do + gem_skeleton_assertions + expect(bundled_app("test-gem/Rakefile")).to read_as( + include('require "standard/rake"'). + and(match(/default:.+:standard/)) + ) + end + + it "includes standard in generated Gemfile" do + allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) + builder = Bundler::Dsl.new + builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile")) + builder.dependencies + standard_dep = builder.dependencies.find {|d| d.name == "standard" } + expect(standard_dep).not_to be_nil + end + + it "generates a default .standard.yml" do + expect(bundled_app("#{gem_name}/.standard.yml")).to exist + end + end + + shared_examples_for "--linter=none flag" do define_negated_matcher :exclude, :include before do - bundle "gem #{gem_name} --no-rubocop" + bundle "gem #{gem_name} --linter=none" end it "generates a gem skeleton without rubocop" do @@ -197,46 +285,66 @@ RSpec.describe "bundle gem" do expect(rubocop_dep).to be_nil end + it "does not include standard in generated Gemfile" do + allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) + builder = Bundler::Dsl.new + builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile")) + builder.dependencies + standard_dep = builder.dependencies.find {|d| d.name == "standard" } + expect(standard_dep).to be_nil + end + it "doesn't generate a default .rubocop.yml" do expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist end + + it "doesn't generate a default .standard.yml" do + expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist + end end - it "has no rubocop offenses when using --rubocop flag", :readline do + it "has no rubocop offenses when using --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} --rubocop" + bundle "gem #{gem_name} --linter=rubocop" bundle_exec_rubocop expect(err).to be_empty end - it "has no rubocop offenses when using --ext and --rubocop flag", :readline do + it "has no rubocop offenses when using --ext 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 --rubocop" + bundle "gem #{gem_name} --ext --linter=rubocop" bundle_exec_rubocop expect(err).to be_empty end - it "has no rubocop offenses when using --ext, --test=minitest, and --rubocop flag", :readline do + it "has no rubocop offenses when using --ext, --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 --rubocop" + bundle "gem #{gem_name} --ext --test=minitest --linter=rubocop" bundle_exec_rubocop expect(err).to be_empty end - it "has no rubocop offenses when using --ext, --test=rspec, and --rubocop flag", :readline do + it "has no rubocop offenses when using --ext, --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 --rubocop" + bundle "gem #{gem_name} --ext --test=rspec --linter=rubocop" bundle_exec_rubocop expect(err).to be_empty end - it "has no rubocop offenses when using --ext, --ext=test-unit, and --rubocop flag", :readline do + it "has no rubocop offenses when using --ext, --ext=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 --rubocop" + bundle "gem #{gem_name} --ext --test=test-unit --linter=rubocop" bundle_exec_rubocop expect(err).to be_empty end + it "has no standard offenses when using --linter=standard 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} --linter=standard" + bundle_exec_standardrb + expect(err).to be_empty + 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 @@ -351,6 +459,55 @@ RSpec.describe "bundle gem" do end end + shared_examples_for "--github-username option" do |github_username| + before do + bundle "gem #{gem_name} --github-username=#{github_username}" + end + + it "generates a gem skeleton" do + gem_skeleton_assertions + end + + it "contribute URL set to given github username" do + expect(bundled_app("#{gem_name}/README.md").read).not_to include("[USERNAME]") + expect(bundled_app("#{gem_name}/README.md").read).to include("github.com/#{github_username}") + end + end + + shared_examples_for "github_username configuration" do + context "with github_username setting set to some value" do + before do + global_config "BUNDLE_GEM__GITHUB_USERNAME" => "different_username" + bundle "gem #{gem_name}" + end + + it "generates a gem skeleton" do + gem_skeleton_assertions + end + + it "contribute URL set to bundle config setting" do + expect(bundled_app("#{gem_name}/README.md").read).not_to include("[USERNAME]") + expect(bundled_app("#{gem_name}/README.md").read).to include("github.com/different_username") + end + end + + context "with github_username setting set to false" do + before do + global_config "BUNDLE_GEM__GITHUB_USERNAME" => "false" + bundle "gem #{gem_name}" + end + + it "generates a gem skeleton" do + gem_skeleton_assertions + end + + it "contribute URL set to [USERNAME]" do + expect(bundled_app("#{gem_name}/README.md").read).to include("[USERNAME]") + expect(bundled_app("#{gem_name}/README.md").read).not_to include("github.com/bundleuser") + end + end + end + shared_examples_for "generating a gem" do it "generates a gem skeleton" do bundle "gem #{gem_name}" @@ -841,6 +998,127 @@ RSpec.describe "bundle gem" do end end + context "--linter with no argument" do + it "does not generate any linter config" do + bundle "gem #{gem_name}" + + expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist + expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist + end + end + + context "--linter set to rubocop" do + it "generates a RuboCop config" do + bundle "gem #{gem_name} --linter=rubocop" + + expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist + expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist + end + end + + context "--linter set to standard" do + it "generates a Standard config" do + bundle "gem #{gem_name} --linter=standard" + + expect(bundled_app("#{gem_name}/.standard.yml")).to exist + expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist + end + end + + context "gem.linter setting set to none" do + it "doesn't generate any linter config" do + bundle "gem #{gem_name}" + + expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist + expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist + end + end + + context "gem.linter setting set to rubocop" do + it "generates a RuboCop config file" do + bundle "config set gem.linter rubocop" + bundle "gem #{gem_name}" + + expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist + end + end + + context "gem.linter setting set to standard" do + it "generates a Standard config file" do + bundle "config set gem.linter standard" + bundle "gem #{gem_name}" + + expect(bundled_app("#{gem_name}/.standard.yml")).to exist + end + end + + context "gem.rubocop setting set to true", :bundler => "< 3" do + before do + bundle "config set gem.rubocop true" + bundle "gem #{gem_name}" + end + + it "generates rubocop config" do + expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist + end + + it "unsets gem.rubocop" do + bundle "config gem.rubocop" + expect(out).to include("You have not configured a value for `gem.rubocop`") + end + + it "sets gem.linter=rubocop instead" do + bundle "config gem.linter" + expect(out).to match(/Set for the current user .*: "rubocop"/) + end + end + + context "gem.linter set to rubocop and --linter with no arguments", :hint_text do + before do + bundle "config set gem.linter rubocop" + bundle "gem #{gem_name} --linter" + end + + it "generates a RuboCop config file" do + expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist + end + + it "hints that --linter is already configured" do + expect(out).to match("rubocop is already configured, ignoring --linter flag.") + end + end + + context "gem.linter setting set to false and --linter with no arguments", :hint_text do + before do + bundle "config set gem.linter false" + bundle "gem #{gem_name} --linter" + end + + it "asks to setup a linter" do + expect(out).to match("Do you want to add a code linter and formatter to your gem?") + end + + it "hints that the choice will only be applied to the current gem" do + expect(out).to match("Your choice will only be applied to this gem.") + end + end + + context "gem.linter setting not set and --linter with no arguments", :hint_text do + before do + bundle "gem #{gem_name} --linter" + end + + it "asks to setup a linter" do + expect(out).to match("Do you want to add a code linter and formatter to your gem?") + end + + it "hints that the choice will be applied to future bundle gem calls" do + hint = "Future `bundle gem` calls will use your choice. " \ + "This setting can be changed anytime with `bundle config gem.linter`." + expect(out).to match(hint) + end + end + context "--edit option" do it "opens the generated gemspec in the user's text editor" do output = bundle "gem #{gem_name} --edit=echo" @@ -891,6 +1169,9 @@ RSpec.describe "bundle gem" do before do global_config "BUNDLE_GEM__RUBOCOP" => "true" end + it_behaves_like "--linter=rubocop flag" + it_behaves_like "--linter=standard flag" + it_behaves_like "--linter=none flag" it_behaves_like "--rubocop flag" it_behaves_like "--no-rubocop flag" end @@ -899,10 +1180,40 @@ RSpec.describe "bundle gem" do before do global_config "BUNDLE_GEM__RUBOCOP" => "false" end + it_behaves_like "--linter=rubocop flag" + it_behaves_like "--linter=standard flag" + it_behaves_like "--linter=none flag" it_behaves_like "--rubocop flag" it_behaves_like "--no-rubocop flag" end + context "with linter option in bundle config settings set to rubocop" do + before do + global_config "BUNDLE_GEM__LINTER" => "rubocop" + end + it_behaves_like "--linter=rubocop flag" + it_behaves_like "--linter=standard flag" + it_behaves_like "--linter=none flag" + end + + context "with linter option in bundle config settings set to standard" do + before do + global_config "BUNDLE_GEM__LINTER" => "standard" + end + it_behaves_like "--linter=rubocop flag" + it_behaves_like "--linter=standard flag" + it_behaves_like "--linter=none flag" + end + + context "with linter option in bundle config settings set to false" do + before do + global_config "BUNDLE_GEM__LINTER" => "false" + end + it_behaves_like "--linter=rubocop flag" + it_behaves_like "--linter=standard flag" + it_behaves_like "--linter=none flag" + end + context "with changelog option in bundle config settings set to true" do before do global_config "BUNDLE_GEM__CHANGELOG" => "true" @@ -920,6 +1231,57 @@ RSpec.describe "bundle gem" do end end + context "testing --github-username option against git and bundle config settings", :readline do + context "without git config set" do + before do + sys_exec("git config --global --unset github.user") + end + context "with github-username option in bundle config settings set to some value" do + before do + global_config "BUNDLE_GEM__GITHUB_USERNAME" => "different_username" + end + it_behaves_like "--github-username option", "gh_user" + end + + context "with github-username option in bundle config settings set to false" do + before do + global_config "BUNDLE_GEM__GITHUB_USERNAME" => "false" + end + it_behaves_like "--github-username option", "gh_user" + end + end + + context "with git config set" do + context "with github-username option in bundle config settings set to some value" do + before do + global_config "BUNDLE_GEM__GITHUB_USERNAME" => "different_username" + end + it_behaves_like "--github-username option", "gh_user" + end + + context "with github-username option in bundle config settings set to false" do + before do + global_config "BUNDLE_GEM__GITHUB_USERNAME" => "false" + end + it_behaves_like "--github-username option", "gh_user" + end + end + end + + context "testing github_username bundle config against git config settings", :readline do + context "without git config set" do + before do + sys_exec("git config --global --unset github.user") + end + + it_behaves_like "github_username configuration" + end + + context "with git config set" do + it_behaves_like "github_username configuration" + end + end + context "gem naming with underscore", :readline do let(:gem_name) { "test_gem" } @@ -1073,7 +1435,7 @@ Usage: "bundle gem NAME [OPTIONS]" end it "asks about CI service" do - global_config "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__RUBOCOP" => "false" + global_config "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__LINTER" => "false" bundle "gem foobar" do |input, _, _| input.puts "github" @@ -1083,7 +1445,7 @@ Usage: "bundle gem NAME [OPTIONS]" end it "asks about MIT license" do - global_config "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__RUBOCOP" => "false" + global_config "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__LINTER" => "false" bundle "config list" @@ -1095,7 +1457,7 @@ Usage: "bundle gem NAME [OPTIONS]" end it "asks about CoC" do - global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__RUBOCOP" => "false" + global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__LINTER" => "false" bundle "gem foobar" do |input, _, _| input.puts "yes" @@ -1105,7 +1467,7 @@ Usage: "bundle gem NAME [OPTIONS]" end it "asks about CHANGELOG" do - global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__RUBOCOP" => "false", + global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__LINTER" => "false", "BUNDLE_GEM__COC" => "false" bundle "gem foobar" do |input, _, _| diff --git a/spec/bundler/commands/outdated_spec.rb b/spec/bundler/commands/outdated_spec.rb index 0ee8bd425a..7c4005824c 100644 --- a/spec/bundler/commands/outdated_spec.rb +++ b/spec/bundler/commands/outdated_spec.rb @@ -929,4 +929,54 @@ RSpec.describe "bundle outdated" do expect(out).to end_with(expected_output) end end + + describe "with a multiplatform lockfile" do + before do + build_repo4 do + build_gem "nokogiri", "1.11.1" + build_gem "nokogiri", "1.11.1" do |s| + s.platform = Bundler.local_platform + end + + build_gem "nokogiri", "1.11.2" + build_gem "nokogiri", "1.11.2" do |s| + s.platform = Bundler.local_platform + end + end + + lockfile <<~L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + nokogiri (1.11.1) + nokogiri (1.11.1-#{Bundler.local_platform}) + + PLATFORMS + ruby + #{Bundler.local_platform} + + DEPENDENCIES + nokogiri + + BUNDLED WITH + #{Bundler::VERSION} + L + + gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem "nokogiri" + G + end + + it "reports a single entry per gem" do + bundle "outdated", :raise_on_error => false + + expected_output = <<~TABLE.strip + Gem Current Latest Requested Groups + nokogiri 1.11.1 1.11.2 >= 0 default + TABLE + + expect(out).to end_with(expected_output) + end + end end diff --git a/spec/bundler/commands/post_bundle_message_spec.rb b/spec/bundler/commands/post_bundle_message_spec.rb index 104221efbe..72f8020b44 100644 --- a/spec/bundler/commands/post_bundle_message_spec.rb +++ b/spec/bundler/commands/post_bundle_message_spec.rb @@ -32,21 +32,21 @@ RSpec.describe "post bundle message" do bundle "config set --local without emo" bundle :install expect(out).to include(bundle_show_message) - expect(out).to include("Gems in the group emo were not installed") + expect(out).to include("Gems in the group 'emo' were not installed") expect(out).to include(bundle_complete_message) expect(out).to include(installed_gems_stats) bundle "config set --local without emo test" bundle :install expect(out).to include(bundle_show_message) - expect(out).to include("Gems in the groups emo and test were not installed") + expect(out).to include("Gems in the groups 'emo' and 'test' were not installed") expect(out).to include(bundle_complete_message) expect(out).to include("4 Gemfile dependencies, 3 gems now installed.") bundle "config set --local without emo obama test" bundle :install expect(out).to include(bundle_show_message) - expect(out).to include("Gems in the groups emo, obama and test were not installed") + expect(out).to include("Gems in the groups 'emo', 'obama' and 'test' were not installed") expect(out).to include(bundle_complete_message) expect(out).to include("4 Gemfile dependencies, 2 gems now installed.") end @@ -65,21 +65,21 @@ RSpec.describe "post bundle message" do bundle "config set --local without emo" bundle :install expect(out).to include(bundle_show_path_message) - expect(out).to include("Gems in the group emo were not installed") + expect(out).to include("Gems in the group 'emo' were not installed") expect(out).to include(bundle_complete_message) bundle "config set --local path vendor" bundle "config set --local without emo test" bundle :install expect(out).to include(bundle_show_path_message) - expect(out).to include("Gems in the groups emo and test were not installed") + expect(out).to include("Gems in the groups 'emo' and 'test' were not installed") expect(out).to include(bundle_complete_message) bundle "config set --local path vendor" bundle "config set --local without emo obama test" bundle :install expect(out).to include(bundle_show_path_message) - expect(out).to include("Gems in the groups emo, obama and test were not installed") + expect(out).to include("Gems in the groups 'emo', 'obama' and 'test' were not installed") expect(out).to include(bundle_complete_message) end end @@ -156,7 +156,7 @@ The source does not contain any versions of 'not-a-gem' bundle "install --without emo" bundle :install expect(out).to include(bundle_show_message) - expect(out).to include("Gems in the group emo were not installed") + expect(out).to include("Gems in the group 'emo' were not installed") expect(out).to include(bundle_complete_message) expect(out).to include(installed_gems_stats) end @@ -165,7 +165,7 @@ The source does not contain any versions of 'not-a-gem' bundle "install --without emo test" bundle :install expect(out).to include(bundle_show_message) - expect(out).to include("Gems in the groups emo and test were not installed") + expect(out).to include("Gems in the groups 'emo' and 'test' were not installed") expect(out).to include(bundle_complete_message) end @@ -173,7 +173,7 @@ The source does not contain any versions of 'not-a-gem' bundle "install --without emo obama test" bundle :install expect(out).to include(bundle_show_message) - expect(out).to include("Gems in the groups emo, obama and test were not installed") + expect(out).to include("Gems in the groups 'emo', 'obama' and 'test' were not installed") expect(out).to include(bundle_complete_message) end end @@ -187,19 +187,19 @@ The source does not contain any versions of 'not-a-gem' bundle "config set --local without emo" bundle :install bundle :update, :all => true - expect(out).to include("Gems in the group emo were not updated") + 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 - expect(out).to include("Gems in the groups emo and test were not updated") + 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 - expect(out).to include("Gems in the groups emo, obama and test were not updated") + expect(out).to include("Gems in the groups 'emo', 'obama' and 'test' were not updated") expect(out).to include(bundle_updated_message) end end diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb index 521c175711..0f17d931a3 100644 --- a/spec/bundler/commands/update_spec.rb +++ b/spec/bundler/commands/update_spec.rb @@ -148,72 +148,66 @@ RSpec.describe "bundle update" do end describe "when a possible resolve requires an older version of a locked gem" do - context "and only_update_to_newer_versions is set" do - before do - bundle "config set only_update_to_newer_versions true" - end - - it "does not go to an older version" do - build_repo4 do - build_gem "tilt", "2.0.8" - build_gem "slim", "3.0.9" do |s| - s.add_dependency "tilt", [">= 1.3.3", "< 2.1"] - end - build_gem "slim_lint", "0.16.1" do |s| - s.add_dependency "slim", [">= 3.0", "< 5.0"] - end - build_gem "slim-rails", "0.2.1" do |s| - s.add_dependency "slim", ">= 0.9.2" - end - build_gem "slim-rails", "3.1.3" do |s| - s.add_dependency "slim", "~> 3.0" - end + it "does not go to an older version" do + build_repo4 do + build_gem "tilt", "2.0.8" + build_gem "slim", "3.0.9" do |s| + s.add_dependency "tilt", [">= 1.3.3", "< 2.1"] + end + build_gem "slim_lint", "0.16.1" do |s| + s.add_dependency "slim", [">= 3.0", "< 5.0"] + end + build_gem "slim-rails", "0.2.1" do |s| + s.add_dependency "slim", ">= 0.9.2" + end + build_gem "slim-rails", "3.1.3" do |s| + s.add_dependency "slim", "~> 3.0" end + end - install_gemfile <<-G - source "#{file_uri_for(gem_repo4)}" - gem "slim-rails" - gem "slim_lint" - G + install_gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem "slim-rails" + gem "slim_lint" + G - expect(the_bundle).to include_gems("slim 3.0.9", "slim-rails 3.1.3", "slim_lint 0.16.1") + expect(the_bundle).to include_gems("slim 3.0.9", "slim-rails 3.1.3", "slim_lint 0.16.1") - update_repo4 do - build_gem "slim", "4.0.0" do |s| - s.add_dependency "tilt", [">= 2.0.6", "< 2.1"] - end + update_repo4 do + build_gem "slim", "4.0.0" do |s| + s.add_dependency "tilt", [">= 2.0.6", "< 2.1"] 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 + expect(the_bundle).to include_gems("slim 3.0.9", "slim-rails 3.1.3", "slim_lint 0.16.1") + end - it "should still downgrade if forced by the Gemfile" do - build_repo4 do - build_gem "a" - build_gem "b", "1.0" - build_gem "b", "2.0" - end + it "should still downgrade if forced by the Gemfile" do + build_repo4 do + build_gem "a" + build_gem "b", "1.0" + build_gem "b", "2.0" + end - install_gemfile <<-G - source "#{file_uri_for(gem_repo4)}" - gem "a" - gem "b" - G + install_gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem "a" + gem "b" + G - expect(the_bundle).to include_gems("a 1.0", "b 2.0") + expect(the_bundle).to include_gems("a 1.0", "b 2.0") - gemfile <<-G - source "#{file_uri_for(gem_repo4)}" - gem "a" - gem "b", "1.0" - G + gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem "a" + gem "b", "1.0" + G - bundle "update b" + bundle "update b" - expect(the_bundle).to include_gems("a 1.0", "b 1.0") - end + expect(the_bundle).to include_gems("a 1.0", "b 1.0") end end diff --git a/spec/bundler/install/deploy_spec.rb b/spec/bundler/install/deploy_spec.rb index f3898c0a65..8f6298b301 100644 --- a/spec/bundler/install/deploy_spec.rb +++ b/spec/bundler/install/deploy_spec.rb @@ -126,21 +126,21 @@ RSpec.describe "install in deployment or frozen mode" do bundle "config set --local path vendor/bundle" bundle "install" gemfile <<-G - source "http://user_name:password@localgemserver.test/" - gem "rack" + source "http://user_name:password@localgemserver.test/" + gem "rack" G lockfile <<-G - GEM - remote: http://localgemserver.test/ - specs: - rack (1.0.0) + GEM + remote: http://localgemserver.test/ + specs: + rack (1.0.0) - PLATFORMS - #{local} + PLATFORMS + #{local} - DEPENDENCIES - rack + DEPENDENCIES + rack G bundle "config set --local deployment true" diff --git a/spec/bundler/install/gemfile/gemspec_spec.rb b/spec/bundler/install/gemfile/gemspec_spec.rb index a70b950e1b..ec6a1d4a4a 100644 --- a/spec/bundler/install/gemfile/gemspec_spec.rb +++ b/spec/bundler/install/gemfile/gemspec_spec.rb @@ -259,7 +259,7 @@ RSpec.describe "bundle install from an existing gemspec" do expect(out).to eq("WIN") end - it "works with only_update_to_newer_versions" do + it "handles downgrades" do build_lib "omg", "2.0", :path => lib_path("omg") install_gemfile <<-G @@ -268,7 +268,7 @@ RSpec.describe "bundle install from an existing gemspec" do build_lib "omg", "1.0", :path => lib_path("omg") - bundle :install, :env => { "BUNDLE_BUNDLE_ONLY_UPDATE_TO_NEWER_VERSIONS" => "true" } + bundle :install expect(the_bundle).to include_gems "omg 1.0" end diff --git a/spec/bundler/install/gemfile/path_spec.rb b/spec/bundler/install/gemfile/path_spec.rb index 3463c5ec06..1c77b3a37e 100644 --- a/spec/bundler/install/gemfile/path_spec.rb +++ b/spec/bundler/install/gemfile/path_spec.rb @@ -173,7 +173,7 @@ RSpec.describe "bundle install with explicit source paths" do expect(the_bundle).to include_gems "foo 1.0" end - it "works with only_update_to_newer_versions" do + it "handles downgrades" do build_lib "omg", "2.0", :path => lib_path("omg") install_gemfile <<-G @@ -182,7 +182,7 @@ RSpec.describe "bundle install with explicit source paths" do build_lib "omg", "1.0", :path => lib_path("omg") - bundle :install, :env => { "BUNDLE_BUNDLE_ONLY_UPDATE_TO_NEWER_VERSIONS" => "true" } + bundle :install expect(the_bundle).to include_gems "omg 1.0" end @@ -328,11 +328,12 @@ RSpec.describe "bundle install with explicit source paths" do s.executables = "foobar" end - install_gemfile <<-G + install_gemfile <<-G, :verbose => true path "#{lib_path("foo-1.0")}" do gem 'foo' end G + expect(out).to include("Using foo 1.0 from source at `#{lib_path("foo-1.0")}` and installing its executables") expect(the_bundle).to include_gems "foo 1.0" bundle "exec foobar" diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb index b388b17881..d86bc18311 100644 --- a/spec/bundler/install/gemfile/sources_spec.rb +++ b/spec/bundler/install/gemfile/sources_spec.rb @@ -141,156 +141,159 @@ RSpec.describe "bundle install with gems on multiple sources" do end end - context "when a pinned gem has an indirect dependency" do + context "when a pinned gem has an indirect dependency in the pinned source" do before do build_repo gem_repo3 do build_gem "depends_on_rack", "1.0.1" do |s| s.add_dependency "rack" end end - end - context "when the indirect dependency is in the pinned source" do - before do - # we need a working rack gem in repo3 - update_repo gem_repo3 do - build_gem "rack", "1.0.0" - end - - gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - source "#{file_uri_for(gem_repo3)}" do - gem "depends_on_rack" - end - G + # we need a working rack gem in repo3 + update_repo gem_repo3 do + build_gem "rack", "1.0.0" end - context "and not in any other sources" do - before do - build_repo(gem_repo2) {} + gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + source "#{file_uri_for(gem_repo3)}" do + gem "depends_on_rack" end + G + end - it "installs from the same source without any warning" do - bundle :install - expect(err).not_to include("Warning") - expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3") - end + context "and not in any other sources" do + before do + build_repo(gem_repo2) {} end - context "and in another source" do - before do - # need this to be broken to check for correct source ordering - build_repo gem_repo2 do - build_gem "rack", "1.0.0" do |s| - s.write "lib/rack.rb", "RACK = 'FAIL'" - end + it "installs from the same source without any warning" do + bundle :install + expect(err).not_to include("Warning") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3") + end + end + + context "and in another source" do + before do + # need this to be broken to check for correct source ordering + build_repo gem_repo2 do + build_gem "rack", "1.0.0" do |s| + s.write "lib/rack.rb", "RACK = 'FAIL'" end end + end - it "installs from the same source without any warning" do - bundle :install + it "installs from the same source without any warning" do + bundle :install - 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(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") - # 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 + # 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 - 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") - end + 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") end end + end - context "when the indirect dependency is in a different source" do - before do - # In these tests, we need a working rack gem in repo2 and not repo3 - build_repo gem_repo2 do - build_gem "rack", "1.0.0" + context "when a pinned gem has an indirect dependency in a different source" do + before do + # In these tests, we need a working rack gem in repo2 and not repo3 + + build_repo gem_repo3 do + build_gem "depends_on_rack", "1.0.1" do |s| + s.add_dependency "rack" end end - context "and not in any other sources" do - before do - install_gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - source "#{file_uri_for(gem_repo3)}" do - gem "depends_on_rack" - end - G - end + build_repo gem_repo2 do + build_gem "rack", "1.0.0" + end + end - it "installs from the other source without any warning" do - expect(err).not_to include("Warning") - expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") - end + context "and not in any other sources" do + before do + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + source "#{file_uri_for(gem_repo3)}" do + gem "depends_on_rack" + end + G end - context "and in yet another source" do - before do - gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - source "#{file_uri_for(gem_repo2)}" - source "#{file_uri_for(gem_repo3)}" do - gem "depends_on_rack" - end - G - end + it "installs from the other source without any warning" do + expect(err).not_to include("Warning") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") + end + end - it "installs from the other source and warns about ambiguous gems", :bundler => "< 3" do - bundle :install - expect(err).to include("Warning: the gem 'rack' was found in multiple sources.") - expect(err).to include("Installed from: #{file_uri_for(gem_repo2)}") - expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") - end + context "and in yet another source" do + before do + gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" + source "#{file_uri_for(gem_repo3)}" do + gem "depends_on_rack" + end + G + end - it "fails", :bundler => "3" do - bundle :install, :raise_on_error => false - expect(err).to include("Each source after the first must include a block") - expect(exitstatus).to eq(4) - end + it "installs from the other source and warns about ambiguous gems", :bundler => "< 3" do + bundle :install + expect(err).to include("Warning: the gem 'rack' was found in multiple sources.") + expect(err).to include("Installed from: #{file_uri_for(gem_repo2)}") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") end - context "and only the dependency is pinned" do - before do - # need this to be broken to check for correct source ordering - build_repo gem_repo2 do - build_gem "rack", "1.0.0" do |s| - s.write "lib/rack.rb", "RACK = 'FAIL'" - end + it "fails", :bundler => "3" do + bundle :install, :raise_on_error => false + expect(err).to include("Each source after the first must include a block") + expect(exitstatus).to eq(4) + end + end + + context "and only the dependency is pinned" do + before do + # need this to be broken to check for correct source ordering + build_repo gem_repo2 do + build_gem "rack", "1.0.0" do |s| + s.write "lib/rack.rb", "RACK = 'FAIL'" end + end - gemfile <<-G - source "#{file_uri_for(gem_repo3)}" # contains depends_on_rack - source "#{file_uri_for(gem_repo2)}" # contains broken rack + gemfile <<-G + source "#{file_uri_for(gem_repo3)}" # contains depends_on_rack + source "#{file_uri_for(gem_repo2)}" # contains broken rack - gem "depends_on_rack" # installed from gem_repo3 - gem "rack", :source => "#{file_uri_for(gem_repo1)}" - G - end + gem "depends_on_rack" # installed from gem_repo3 + gem "rack", :source => "#{file_uri_for(gem_repo1)}" + G + end - it "installs the dependency from the pinned source without warning", :bundler => "< 3" do - bundle :install + it "installs the dependency from the pinned source without warning", :bundler => "< 3" do + bundle :install - 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") + 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") - # 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 + # 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 - 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 + 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, :raise_on_error => false - expect(err).to include("Each source after the first must include a block") - expect(exitstatus).to eq(4) - end + it "fails", :bundler => "3" do + bundle :install, :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 @@ -511,9 +514,149 @@ RSpec.describe "bundle install with gems on multiple sources" do L end - it "upgrades gems when running bundle update, without printing any warnings or errors" do + it "does not install newer versions or generate lockfile changes when running bundle install, and warns", :bundler => "< 3" do + initial_lockfile = lockfile + + bundle :install + + expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") + + expect(the_bundle).to include_gems("activesupport 6.0.3.4") + expect(the_bundle).not_to include_gems("activesupport 6.1.2.1") + expect(the_bundle).to include_gems("tzinfo 1.2.9") + expect(the_bundle).not_to include_gems("tzinfo 2.0.4") + expect(the_bundle).to include_gems("concurrent-ruby 1.1.8") + expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.9") + + expect(lockfile).to eq(initial_lockfile) + end + + it "fails when running bundle install", :bundler => "3" do + initial_lockfile = lockfile + + bundle :install, :raise_on_error => false + + expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") + + expect(lockfile).to eq(initial_lockfile) + end + + it "splits sections and upgrades gems when running bundle update, and doesn't warn" do bundle "update --all" 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") + expect(the_bundle).not_to include_gems("tzinfo 1.2.9") + expect(the_bundle).to include_gems("tzinfo 2.0.4") + expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8") + expect(the_bundle).to include_gems("concurrent-ruby 1.1.9") + + expect(lockfile).to eq <<~L + GEM + remote: #{file_uri_for(gem_repo2)}/ + specs: + activesupport (6.1.2.1) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) + concurrent-ruby (1.1.9) + connection_pool (2.2.3) + i18n (1.8.9) + concurrent-ruby (~> 1.0) + minitest (5.14.3) + rack (2.2.3) + redis (4.2.5) + sidekiq (6.1.3) + connection_pool (>= 2.2.2) + rack (~> 2.0) + redis (>= 4.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + zeitwerk (2.4.2) + + GEM + remote: #{file_uri_for(gem_repo3)}/ + specs: + sidekiq-pro (5.2.1) + connection_pool (>= 2.2.3) + sidekiq (>= 6.1.0) + + PLATFORMS + #{specific_local_platform} + + DEPENDENCIES + activesupport + sidekiq-pro! + + BUNDLED WITH + #{Bundler::VERSION} + L + end + + it "it keeps the currrent lockfile format and upgrades the requested gem when running bundle update with an argument, and warns", :bundler => "< 3" do + bundle "update concurrent-ruby" + expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") + + expect(the_bundle).to include_gems("activesupport 6.0.3.4") + expect(the_bundle).not_to include_gems("activesupport 6.1.2.1") + expect(the_bundle).to include_gems("tzinfo 1.2.9") + expect(the_bundle).not_to include_gems("tzinfo 2.0.4") + expect(the_bundle).to include_gems("concurrent-ruby 1.1.9") + expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8") + + expect(lockfile).to eq <<~L + GEM + remote: #{file_uri_for(gem_repo2)}/ + remote: #{file_uri_for(gem_repo3)}/ + specs: + activesupport (6.0.3.4) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) + minitest (~> 5.1) + tzinfo (~> 1.1) + zeitwerk (~> 2.2, >= 2.2.2) + concurrent-ruby (1.1.9) + connection_pool (2.2.3) + i18n (1.8.9) + concurrent-ruby (~> 1.0) + minitest (5.14.3) + rack (2.2.3) + redis (4.2.5) + sidekiq (6.1.3) + connection_pool (>= 2.2.2) + rack (~> 2.0) + redis (>= 4.2.0) + sidekiq-pro (5.2.1) + connection_pool (>= 2.2.3) + sidekiq (>= 6.1.0) + thread_safe (0.3.6) + tzinfo (1.2.9) + thread_safe (~> 0.1) + zeitwerk (2.4.2) + + PLATFORMS + #{specific_local_platform} + + DEPENDENCIES + activesupport + sidekiq-pro! + + BUNDLED WITH + #{Bundler::VERSION} + L + end + + it "fails when running bundle update with an argument", :bundler => "3" do + initial_lockfile = lockfile + + bundle "update concurrent-ruby", :raise_on_error => false + + expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") + + expect(lockfile).to eq(initial_lockfile) end end end @@ -551,7 +694,7 @@ RSpec.describe "bundle install with gems on multiple sources" do end end - context "when a pinned gem has an indirect dependency with more than one level of indirection in the default source ", :bundler => "< 3" do + context "when a pinned gem has an indirect dependency with more than one level of indirection in the default source " do before do build_repo gem_repo3 do build_gem "handsoap", "0.2.5.5" do |s| @@ -578,12 +721,38 @@ RSpec.describe "bundle install with gems on multiple sources" do G end - it "installs from the proper sources without any warnings or errors" do + it "installs from the default source without any warnings or errors and generates a proper lockfile" do + expected_lockfile = <<~L + GEM + remote: #{file_uri_for(gem_repo2)}/ + specs: + nokogiri (1.11.1) + racca (~> 1.4) + racca (1.5.2) + + GEM + remote: #{file_uri_for(gem_repo3)}/ + specs: + handsoap (0.2.5.5) + nokogiri (>= 1.2.3) + + PLATFORMS + #{specific_local_platform} + + DEPENDENCIES + handsoap! + nokogiri + + BUNDLED WITH + #{Bundler::VERSION} + L + bundle "install --verbose" 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(lockfile).to eq(expected_lockfile) # Even if the gems are already installed FileUtils.rm bundled_app_lock @@ -592,6 +761,7 @@ RSpec.describe "bundle install with gems on multiple sources" do 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(lockfile).to eq(expected_lockfile) end end @@ -619,6 +789,9 @@ RSpec.describe "bundle install with gems on multiple sources" do lockfile <<-L GEM remote: #{file_uri_for(gem_repo1)} + specs: + + GEM remote: #{file_uri_for(gem_repo3)} specs: rack (0.9.1) @@ -644,6 +817,84 @@ RSpec.describe "bundle install with gems on multiple sources" do end end + context "with a lockfile with aggregated rubygems sources" do + let(:aggregate_gem_section_lockfile) do + <<~L + GEM + remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo3)}/ + specs: + rack (0.9.1) + + PLATFORMS + #{specific_local_platform} + + DEPENDENCIES + rack! + + BUNDLED WITH + #{Bundler::VERSION} + L + end + + let(:split_gem_section_lockfile) do + <<~L + GEM + remote: #{file_uri_for(gem_repo1)}/ + specs: + + GEM + remote: #{file_uri_for(gem_repo3)}/ + specs: + rack (0.9.1) + + PLATFORMS + #{specific_local_platform} + + DEPENDENCIES + rack! + + BUNDLED WITH + #{Bundler::VERSION} + L + end + + before do + build_repo gem_repo3 do + build_gem "rack", "0.9.1" + end + + gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo3)}" do + gem 'rack' + end + G + + lockfile aggregate_gem_section_lockfile + end + + it "installs the existing lockfile but prints a warning", :bundler => "< 3" do + bundle "config set --local deployment true" + + bundle "install" + + 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") + end + + it "refuses to install the existing lockfile and prints an error", :bundler => "3" do + bundle "config set --local deployment true" + + bundle "install", :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.") + expect(out).to be_empty + end + end + context "with a path gem in the same Gemfile" do before do build_lib "foo" @@ -825,13 +1076,34 @@ RSpec.describe "bundle install with gems on multiple sources" do G end - it "keeps the old version", :bundler => "< 3" do - expect(the_bundle).to include_gems("rack 1.0.0") + it "installs the higher version in the new repo" do + expect(the_bundle).to include_gems("rack 1.2") + end + end + + it "doesn't update version when a gem uses a source block but a higher version from another source is already installed locally" do + build_repo2 do + build_gem "example", "0.1.0" end - it "installs the higher version in the new repo", :bundler => "3" do - expect(the_bundle).to include_gems("rack 1.2") + build_repo4 do + build_gem "example", "1.0.2" end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + + gem "example", :source => "#{file_uri_for(gem_repo2)}" + G + + 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 + + bundle "update example --verbose" + expect(out).not_to include("Using example 1.0.2") + expect(out).to include("Using example 0.1.0") end context "when a gem is available from multiple ambiguous sources", :bundler => "3" do diff --git a/spec/bundler/install/gemfile/specific_platform_spec.rb b/spec/bundler/install/gemfile/specific_platform_spec.rb index 9e30fc4fd4..a5b78443b9 100644 --- a/spec/bundler/install/gemfile/specific_platform_spec.rb +++ b/spec/bundler/install/gemfile/specific_platform_spec.rb @@ -104,6 +104,50 @@ RSpec.describe "bundle install with specific platforms" do L end + it "doesn't discard previously installed platform specific gem and fall back to ruby on subsequent bundles" do + build_repo2 do + build_gem("libv8", "8.4.255.0") + build_gem("libv8", "8.4.255.0") {|s| s.platform = "universal-darwin" } + + build_gem("mini_racer", "1.0.0") do |s| + s.add_runtime_dependency "libv8" + end + end + + 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" } + + gemfile <<-G + source "https://localgemserver.test" + gem "libv8" + G + + # simulate lockfile created with old bundler, which only locks for ruby platform + lockfile <<-L + GEM + remote: https://localgemserver.test/ + specs: + libv8 (8.4.255.0) + + PLATFORMS + ruby + + DEPENDENCIES + libv8 + + BUNDLED WITH + 2.1.4 + L + + 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 } + expect(out).to include("Using libv8 8.4.255.0 (universal-darwin)") + end + it "caches the universal-darwin gem when --all-platforms is passed and properly picks it up on further bundler invocations" do setup_multiplatform_gem gemfile(google_protobuf) diff --git a/spec/bundler/install/gems/flex_spec.rb b/spec/bundler/install/gems/flex_spec.rb index 7ab0ded26d..326ec51214 100644 --- a/spec/bundler/install/gems/flex_spec.rb +++ b/spec/bundler/install/gems/flex_spec.rb @@ -245,37 +245,7 @@ RSpec.describe "bundle flex_install" do end describe "when adding a new source" do - it "updates the lockfile", :bundler => "< 3" do - build_repo2 - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" - G - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - source "#{file_uri_for(gem_repo2)}" - gem "rack" - G - - lockfile_should_be <<-L - GEM - remote: #{file_uri_for(gem_repo1)}/ - remote: #{file_uri_for(gem_repo2)}/ - specs: - rack (1.0.0) - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - rack - - BUNDLED WITH - #{Bundler::VERSION} - L - end - - it "updates the lockfile", :bundler => "3" do + it "updates the lockfile" do build_repo2 install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" diff --git a/spec/bundler/install/gems/resolving_spec.rb b/spec/bundler/install/gems/resolving_spec.rb index 035ed9a7f3..94fac0052c 100644 --- a/spec/bundler/install/gems/resolving_spec.rb +++ b/spec/bundler/install/gems/resolving_spec.rb @@ -3,6 +3,32 @@ RSpec.describe "bundle install with install-time dependencies" do before do build_repo2 do + build_gem "with_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}/implicit_rake_dep.rb", "w") do |f| + f.puts "IMPLICIT_RAKE_DEP = 'YES'" + end + end + RUBY + end + + 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 + # Test complicated gem dependencies for install build_gem "net_a" do |s| s.add_dependency "net_b" @@ -55,6 +81,25 @@ RSpec.describe "bundle install with install-time dependencies" do expect(out).to eq("YES\nYES") end + it "installs gems with implicit rake dependencies without rake previously installed" do + with_path_as("") do + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "with_implicit_rake_dep" + gem "another_implicit_rake_dep" + gem "rake" + G + end + + run <<-R + require 'implicit_rake_dep' + require 'another_implicit_rake_dep' + puts IMPLICIT_RAKE_DEP + puts ANOTHER_IMPLICIT_RAKE_DEP + R + expect(out).to eq("YES\nYES") + end + it "installs gems with a dependency with no type" do skip "incorrect data check error" if Gem.win_platform? diff --git a/spec/bundler/install/gems/sudo_spec.rb b/spec/bundler/install/gems/sudo_spec.rb index ff73b4a1fa..3e5d38ea4c 100644 --- a/spec/bundler/install/gems/sudo_spec.rb +++ b/spec/bundler/install/gems/sudo_spec.rb @@ -49,8 +49,23 @@ RSpec.describe "when using sudo", :sudo => true do 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_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "rake" gem "another_implicit_rake_dep" G diff --git a/spec/bundler/install/git_spec.rb b/spec/bundler/install/git_spec.rb index 71771d3dc2..4a3827eafd 100644 --- a/spec/bundler/install/git_spec.rb +++ b/spec/bundler/install/git_spec.rb @@ -13,7 +13,7 @@ RSpec.describe "bundle install" do expect(the_bundle).to include_gems "foo 1.0", :source => "git@#{lib_path("foo")}" end - it "displays the correct default branch" do + 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 diff --git a/spec/bundler/lock/lockfile_spec.rb b/spec/bundler/lock/lockfile_spec.rb index 976db33b0e..d68410824e 100644 --- a/spec/bundler/lock/lockfile_spec.rb +++ b/spec/bundler/lock/lockfile_spec.rb @@ -318,40 +318,7 @@ RSpec.describe "the lockfile format" do G end - it "generates a lockfile without credentials for a configured source", :bundler => "< 3" do - bundle "config set http://localgemserver.test/ user:pass" - - install_gemfile(<<-G, :artifice => "endpoint_strict_basic_authentication", :quiet => true) - source "http://localgemserver.test/" do - - end - - source "http://user:pass@othergemserver.test/" do - gem "rack-obama", ">= 1.0" - end - G - - lockfile_should_be <<-G - GEM - remote: http://localgemserver.test/ - remote: http://user:pass@othergemserver.test/ - specs: - rack (1.0.0) - rack-obama (1.0) - rack - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - rack-obama (>= 1.0)! - - BUNDLED WITH - #{Bundler::VERSION} - G - end - - it "generates a lockfile without credentials for a configured source", :bundler => "3" do + it "generates a lockfile without credentials for a configured source" do bundle "config set http://localgemserver.test/ user:pass" install_gemfile(<<-G, :artifice => "endpoint_strict_basic_authentication", :quiet => true) @@ -674,6 +641,30 @@ RSpec.describe "the lockfile format" do G end + it "removes redundant sources" do + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}/" + + gem "rack", :source => "#{file_uri_for(gem_repo2)}/" + G + + lockfile_should_be <<-G + GEM + remote: #{file_uri_for(gem_repo2)}/ + specs: + rack (1.0.0) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + rack! + + BUNDLED WITH + #{Bundler::VERSION} + G + end + it "lists gems alphabetically" do install_gemfile <<-G source "#{file_uri_for(gem_repo2)}/" diff --git a/spec/bundler/other/major_deprecation_spec.rb b/spec/bundler/other/major_deprecation_spec.rb index 0758d29746..92b05d8b74 100644 --- a/spec/bundler/other/major_deprecation_spec.rb +++ b/spec/bundler/other/major_deprecation_spec.rb @@ -165,6 +165,28 @@ RSpec.describe "major deprecations" do pending "fails with a helpful error", :bundler => "3" end + context "bundle cache --path" do + before do + install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + gem "rack" + G + + bundle "cache --path foo", :raise_on_error => false + end + + 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, " \ + "and `bundle config path` to configure the path where your gems are installed, " \ + "and stop using this flag" + ) + end + + pending "fails with a helpful error", :bundler => "3" + end + describe "bundle config" do describe "old list interface" do before do @@ -383,15 +405,53 @@ RSpec.describe "major deprecations" do "Your Gemfile contains multiple primary 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. " \ - "To upgrade this warning to an error, run `bundle config set --local " \ - "disable_multisource true`." + "a block to indicate which gems should come from the secondary source." ) end pending "fails with a helpful error", :bundler => "3" end + context "bundle install with a lockfile with a single rubygems section with multiple remotes" do + before do + build_repo gem_repo3 do + build_gem "rack", "0.9.1" + end + + gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo3)}" do + gem 'rack' + end + G + + lockfile <<~L + GEM + remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo3)}/ + specs: + rack (0.9.1) + + PLATFORMS + ruby + + DEPENDENCIES + rack! + + BUNDLED WITH + #{Bundler::VERSION} + L + end + + 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. You should run `bundle update` or generate your lockfile from scratch.") + end + + pending "fails with a helpful error", :bundler => "3" + end + context "when Bundler.setup is run in a ruby script" do before do create_file "gems.rb" @@ -609,4 +669,50 @@ The :gist git source is deprecated, and will be removed in the future. Add this 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 + end + + it "prints a deprecation warning", :bundler => "< 3" do + expect(deprecations).to include \ + "--rubocop is deprecated, use --linter=rubocop" + end + end + + context "bundle gem --no-rubocop" do + before do + bundle "gem my_new_gem --no-rubocop", :raise_on_error => false + end + + it "prints a deprecation warning", :bundler => "< 3" do + expect(deprecations).to include \ + "--no-rubocop is deprecated, use --linter" + end + end + + 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 + end + + 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 + end + + 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 + end + + 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 + end + end end diff --git a/spec/bundler/quality_spec.rb b/spec/bundler/quality_spec.rb index 2b1e28fa30..dcdbf61f52 100644 --- a/spec/bundler/quality_spec.rb +++ b/spec/bundler/quality_spec.rb @@ -169,7 +169,6 @@ RSpec.describe "The library itself" do it "documents all used settings" do exemptions = %w[ - deployment_means_frozen forget_cli_options gem.coc gem.mit diff --git a/spec/bundler/realworld/fixtures/warbler/Gemfile.lock b/spec/bundler/realworld/fixtures/warbler/Gemfile.lock index 6945be3ed2..05bcb877db 100644 --- a/spec/bundler/realworld/fixtures/warbler/Gemfile.lock +++ b/spec/bundler/realworld/fixtures/warbler/Gemfile.lock @@ -6,7 +6,7 @@ PATH GEM remote: https://rubygems.org/ specs: - jruby-jars (9.2.14.0) + jruby-jars (9.2.16.0) jruby-rack (1.1.21) rake (13.0.1) rubyzip (1.3.0) @@ -19,6 +19,7 @@ GEM PLATFORMS java ruby + universal-java-11 DEPENDENCIES demo! @@ -26,4 +27,4 @@ DEPENDENCIES warbler (~> 2.0) BUNDLED WITH - 2.2.0.rc.2 + 2.3.0.dev diff --git a/spec/bundler/runtime/inline_spec.rb b/spec/bundler/runtime/inline_spec.rb index bd136ddcd7..bad1df93a9 100644 --- a/spec/bundler/runtime/inline_spec.rb +++ b/spec/bundler/runtime/inline_spec.rb @@ -246,6 +246,19 @@ RSpec.describe "bundler/inline#gemfile" do expect(last_command.stderr).to be_empty end + it "installs inline gems when deployment is set" do + script <<-RUBY, :env => { "BUNDLE_DEPLOYMENT" => "true" } + gemfile do + source "#{file_uri_for(gem_repo1)}" + gem "rack" + end + + puts RACK + RUBY + + expect(last_command.stderr).to be_empty + end + it "installs inline gems when BUNDLE_GEMFILE is set to an empty string" do ENV["BUNDLE_GEMFILE"] = "" diff --git a/spec/bundler/runtime/platform_spec.rb b/spec/bundler/runtime/platform_spec.rb index 154d967e12..bec42e0f70 100644 --- a/spec/bundler/runtime/platform_spec.rb +++ b/spec/bundler/runtime/platform_spec.rb @@ -108,6 +108,44 @@ RSpec.describe "Bundler.setup with multi platform stuff" do expect(lockfile).to eq(good_lockfile) end + it "will not try to install platform specific gems when they don't match the current ruby if locked only to ruby" do + build_repo4 do + build_gem "nokogiri", "1.11.1" + + build_gem "nokogiri", "1.11.1" do |s| + s.platform = Bundler.local_platform + s.required_ruby_version = "< #{Gem.ruby_version}" + end + end + + gemfile <<-G + source "https://gems.repo4" + gem "nokogiri" + G + + lockfile <<~L + GEM + remote: https://gems.repo4/ + specs: + nokogiri (1.11.1) + + PLATFORMS + ruby + + DEPENDENCIES + nokogiri + + BUNDLED WITH + #{Bundler::VERSION} + L + + 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 gemfile <<-G source "#{file_uri_for(gem_repo1)}" diff --git a/spec/bundler/runtime/setup_spec.rb b/spec/bundler/runtime/setup_spec.rb index a0036df39e..4d5e1c616e 100644 --- a/spec/bundler/runtime/setup_spec.rb +++ b/spec/bundler/runtime/setup_spec.rb @@ -1244,16 +1244,16 @@ end describe "default gem activation" do let(:exemptions) do - exempts = if Gem::Version.new(Gem::VERSION) >= Gem::Version.new("2.7") + 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::Version.new(Gem::VERSION) >= Gem::Version.new("2.7") - exempts << "uri" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7") - exempts << "pathname" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.0") - exempts << "set" unless Gem::Version.new(Gem::VERSION) >= Gem::Version.new("3.2.6") - exempts << "tsort" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.0") + 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 << "set" unless Gem.rubygems_version >= Gem::Version.new("3.2.6") + exempts << "tsort" if Gem.ruby_version >= Gem::Version.new("3.0") exempts end diff --git a/spec/bundler/spec_helper.rb b/spec/bundler/spec_helper.rb index a72a1f5255..db1055c295 100644 --- a/spec/bundler/spec_helper.rb +++ b/spec/bundler/spec_helper.rb @@ -66,16 +66,9 @@ RSpec.configure do |config| mocks.allow_message_expectations_on_nil = false end - config.around :each do |example| - if ENV["RUBY"] - orig_ruby = Gem.ruby - Gem.ruby = ENV["RUBY"] - end - example.run - Gem.ruby = orig_ruby if ENV["RUBY"] - end - config.before :suite do + Gem.ruby = ENV["RUBY"] if ENV["RUBY"] + require_relative "support/rubygems_ext" Spec::Rubygems.test_setup ENV["BUNDLE_SPEC_RUN"] = "true" @@ -90,6 +83,8 @@ RSpec.configure do |config| end config.before :all do + check_test_gems! + build_repo1 reset_paths! diff --git a/spec/bundler/support/builders.rb b/spec/bundler/support/builders.rb index c76c3f505e..d593ced27e 100644 --- a/spec/bundler/support/builders.rb +++ b/spec/bundler/support/builders.rb @@ -30,7 +30,11 @@ module Spec end def build_repo1 + rake_path = Dir["#{Path.base_system_gems}/**/rake*.gem"].first + build_repo gem_repo1 do + FileUtils.cp rake_path, "#{gem_repo1}/gems/" + build_gem "rack", %w[0.9.1 1.0.0] do |s| s.executables = "rackup" s.post_install_message = "Rack's post install message" @@ -150,32 +154,6 @@ module Spec build_gem "duradura", "7.0" - build_gem "with_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}/implicit_rake_dep.rb", "w") do |f| - f.puts "IMPLICIT_RAKE_DEP = 'YES'" - end - end - RUBY - end - - 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 - build_gem "very_simple_binary", &:add_c_extension build_gem "simple_binary", &:add_c_extension @@ -255,6 +233,13 @@ module Spec def build_repo(path, &blk) return if File.directory?(path) + + FileUtils.mkdir_p("#{path}/gems") + + update_repo(path, &blk) + end + + def check_test_gems! rake_path = Dir["#{Path.base_system_gems}/**/rake*.gem"].first if rake_path.nil? @@ -263,14 +248,9 @@ module Spec rake_path = Dir["#{Path.base_system_gems}/**/rake*.gem"].first end - if rake_path - FileUtils.mkdir_p("#{path}/gems") - FileUtils.cp rake_path, "#{path}/gems/" - else + if rake_path.nil? abort "Your test gems are missing! Run `rm -rf #{tmp}` and try again." end - - update_repo(path, &blk) end def update_repo(path) diff --git a/spec/bundler/support/bundle.rb b/spec/bundler/support/bundle.rb new file mode 100644 index 0000000000..bb21526d35 --- /dev/null +++ b/spec/bundler/support/bundle.rb @@ -0,0 +1,8 @@ +# 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) +load File.expand_path("bundle", Spec::Path.bindir) diff --git a/spec/bundler/support/hax.rb b/spec/bundler/support/hax.rb index fc8e0ad55d..8fd35890ae 100644 --- a/spec/bundler/support/hax.rb +++ b/spec/bundler/support/hax.rb @@ -29,7 +29,7 @@ module Gem end # We only need this hack for rubygems versions without the BundlerVersionFinder - if Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0") + if Gem.rubygems_version < Gem::Version.new("2.7.0") @path_to_default_spec_map.delete_if do |_path, spec| spec.name == "bundler" end diff --git a/spec/bundler/support/helpers.rb b/spec/bundler/support/helpers.rb index a7cc1ce810..d896b5276e 100644 --- a/spec/bundler/support/helpers.rb +++ b/spec/bundler/support/helpers.rb @@ -10,7 +10,7 @@ module Spec def reset! Dir.glob("#{tmp}/{gems/*,*}", File::FNM_DOTMATCH).each do |dir| - next if %w[base base_system remote1 gems rubygems . ..].include?(File.basename(dir)) + next if %w[base base_system remote1 rubocop standard gems rubygems . ..].include?(File.basename(dir)) FileUtils.rm_rf(dir) end FileUtils.mkdir_p(home) @@ -130,7 +130,7 @@ module Spec def ruby(ruby, options = {}) ruby_cmd = build_ruby_cmd - escaped_ruby = RUBY_PLATFORM == "java" ? ruby.shellescape.dump : ruby.shellescape + escaped_ruby = ruby.shellescape sys_exec(%(#{ruby_cmd} -w -e #{escaped_ruby}), options) end diff --git a/spec/bundler/support/matchers.rb b/spec/bundler/support/matchers.rb index 5d129ed849..1613662981 100644 --- a/spec/bundler/support/matchers.rb +++ b/spec/bundler/support/matchers.rb @@ -114,30 +114,49 @@ module Spec match do opts = names.last.is_a?(Hash) ? names.pop : {} source = opts.delete(:source) - groups = Array(opts[:groups]) + groups = Array(opts.delete(:groups)).map(&:inspect).join(", ") opts[:raise_on_error] = false - groups << opts - @errors = names.map do |name| - name, version, platform = name.split(/\s+/) + @errors = names.map do |full_name| + name, version, platform = full_name.split(/\s+/) require_path = name == "bundler" ? "#{lib_dir}/bundler" : name.tr("-", "/") version_const = name == "bundler" ? "Bundler::VERSION" : Spec::Builders.constantize(name) - code = [] - code << "require '#{require_path}.rb'" - code << "puts #{version_const}" - run code.join("; "), *groups - actual_version, actual_platform = out.strip.split(/\s+/, 2) - unless Gem::Version.new(actual_version) == Gem::Version.new(version) + source_const = "#{Spec::Builders.constantize(name)}_SOURCE" + ruby <<~R, opts + require '#{lib_dir}/bundler' + Bundler.setup(#{groups}) + + require '#{require_path}.rb' + actual_version, actual_platform = #{version_const}.split(/\s+/, 2) + unless Gem::Version.new(actual_version) == Gem::Version.new('#{version}') + puts actual_version + exit 64 + end + unless actual_platform.to_s == '#{platform}' + puts actual_platform + exit 65 + end + require '#{require_path}/source' + exit 0 if #{source.nil?} + actual_source = #{source_const} + unless actual_source == '#{source}' + puts actual_source + exit 66 + end + R + next if exitstatus == 0 + if exitstatus == 64 + actual_version = out.split("\n").last next "#{name} was expected to be at version #{version} but was #{actual_version}" end - unless actual_platform == platform + if exitstatus == 65 + actual_platform = out.split("\n").last next "#{name} was expected to be of platform #{platform} but was #{actual_platform}" end - next unless source - source_const = "#{Spec::Builders.constantize(name)}_SOURCE" - run "require '#{require_path}/source'; puts #{source_const}", *groups - unless out.strip == source - next "Expected #{name} (#{version}) to be installed from `#{source}`, was actually from `#{out}`" + if exitstatus == 66 + actual_source = out.split("\n").last + next "Expected #{name} (#{version}) to be installed from `#{source}`, was actually from `#{actual_source}`" end + next "Command to check forgem inclusion of gem #{full_name} failed" end.compact @errors.empty? diff --git a/spec/bundler/support/path.rb b/spec/bundler/support/path.rb index 62f136aa0b..a9e9704cf9 100644 --- a/spec/bundler/support/path.rb +++ b/spec/bundler/support/path.rb @@ -6,7 +6,7 @@ require "rbconfig" module Spec module Path def source_root - @source_root ||= Pathname.new(ruby_core? ? "../../../.." : "../../..").expand_path(__FILE__) + @source_root ||= Pathname.new(ruby_core? ? "../../.." : "../..").expand_path(__dir__) end def root @@ -30,7 +30,15 @@ module Spec end def test_gemfile - @test_gemfile ||= source_root.join(ruby_core? ? "tool/bundler/test_gems.rb" : "test_gems.rb") + @test_gemfile ||= source_root.join("tool/bundler/test_gems.rb") + end + + def rubocop_gemfile + @rubocop_gemfile ||= source_root.join(rubocop_gemfile_basename) + end + + def standard_gemfile + @standard_gemfile ||= source_root.join(standard_gemfile_basename) end def dev_gemfile @@ -119,7 +127,7 @@ module Spec end def vendored_gems(path = nil) - bundled_app(*["vendor/bundle", Gem.ruby_engine, RbConfig::CONFIG["ruby_version"], path].compact) + scoped_gem_path(bundled_app("vendor/bundle")).join(*[path].compact) end def cached_gem(path) @@ -138,6 +146,14 @@ module Spec tmp.join("gems/base") end + def rubocop_gems + tmp.join("gems/rubocop") + end + + def standard_gems + tmp.join("gems/standard") + end + def file_uri_for(path) protocol = "file://" root = Gem.win_platform? ? "/" : "" @@ -178,7 +194,11 @@ module Spec end def local_gem_path(*path, base: bundled_app) - base.join(*[".bundle", Gem.ruby_engine, RbConfig::CONFIG["ruby_version"], *path].compact) + scoped_gem_path(base.join(".bundle")).join(*path) + end + + def scoped_gem_path(base) + base.join(Gem.ruby_engine, RbConfig::CONFIG["ruby_version"]) end def lib_path(*args) @@ -193,10 +213,6 @@ module Spec root.join("lib") end - def xdg_config_home - home(".config") - end - def global_plugin_gem(*args) home ".bundle", "plugin", "gems", *args end @@ -255,6 +271,14 @@ module Spec !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"}") + end + + def standard_gemfile_basename + source_root.join("tool/bundler/#{RUBY_VERSION.start_with?("2.3") ? "standard23_gems.rb" : "standard_gems.rb"}") + end + extend self end end diff --git a/spec/bundler/support/rubygems_ext.rb b/spec/bundler/support/rubygems_ext.rb index 59429884d6..ea774429c9 100644 --- a/spec/bundler/support/rubygems_ext.rb +++ b/spec/bundler/support/rubygems_ext.rb @@ -9,7 +9,7 @@ module Spec extend self def dev_setup - install_gems(dev_gemfile, dev_lockfile) + install_gems(dev_gemfile) end def gem_load(gem_name, bin_container) @@ -33,25 +33,25 @@ module Spec ENV["HOME"] = Path.home.to_s ENV["TMPDIR"] = Path.tmpdir.to_s - ENV["XDG_CONFIG_HOME"] = Path.xdg_config_home.to_s require "rubygems/user_interaction" Gem::DefaultUserInteraction.ui = Gem::SilentUI.new end def install_parallel_test_deps + Gem.clear_paths + require "parallel" + require "fileutils" - prev_env_test_number = ENV["TEST_ENV_NUMBER"] + install_test_deps - begin - Parallel.processor_count.times do |n| - ENV["TEST_ENV_NUMBER"] = (n + 1).to_s + (2..Parallel.processor_count).each do |n| + source = Path.source_root.join("tmp", "1") + destination = Path.source_root.join("tmp", n.to_s) - install_test_deps - end - ensure - ENV["TEST_ENV_NUMBER"] = prev_env_test_number + FileUtils.rm_rf destination + FileUtils.cp_r source, destination end end @@ -67,9 +67,9 @@ module Spec def install_test_deps setup_test_paths - workaround_loaded_specs_issue - - install_gems(test_gemfile, test_lockfile) + install_gems(test_gemfile) + install_gems(rubocop_gemfile, Path.rubocop_gems.to_s) + install_gems(standard_gemfile, Path.standard_gems.to_s) end def check_source_control_changes(success_message:, error_message:) @@ -94,18 +94,6 @@ module Spec private - # Some rubygems versions include loaded specs when loading gemspec stubs - # from the file system. In this situation, that makes bundler incorrectly - # assume that `rake` is already installed at `tmp/` because it's installed - # globally, and makes it skip installing it to the proper location for our - # tests. To workaround, we remove `rake` from the loaded specs when running - # under those versions, so that `bundler` does the right thing. - def workaround_loaded_specs_issue - current_rubygems_version = Gem::Version.new(Gem::VERSION) - - Gem.loaded_specs.delete("rake") if current_rubygems_version >= Gem::Version.new("3.0.0.beta2") && current_rubygems_version < Gem::Version.new("3.2.0") - end - def gem_load_and_activate(gem_name, bin_container) gem_activate(gem_name) load Gem.bin_path(gem_name, bin_container) @@ -119,14 +107,27 @@ module Spec gem gem_name, gem_requirement end - def install_gems(gemfile, lockfile) + def install_gems(gemfile, path = nil) old_gemfile = ENV["BUNDLE_GEMFILE"] ENV["BUNDLE_GEMFILE"] = gemfile.to_s - require "bundler" - definition = Bundler::Definition.build(gemfile, lockfile, nil) - definition.validate_runtime! - Bundler::Installer.install(Path.source_root, definition, :path => ENV["GEM_HOME"]) + + if path + old_path = ENV["BUNDLE_PATH"] + ENV["BUNDLE_PATH"] = path + else + old_path__system = ENV["BUNDLE_PATH__SYSTEM"] + 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? ensure + if path + ENV["BUNDLE_PATH"] = old_path + else + ENV["BUNDLE_PATH__SYSTEM"] = old_path__system + end + ENV["BUNDLE_GEMFILE"] = old_gemfile end @@ -134,8 +135,12 @@ module Spec Path.test_gemfile end - def test_lockfile - lockfile_for(test_gemfile) + def rubocop_gemfile + Path.rubocop_gemfile + end + + def standard_gemfile + Path.standard_gemfile end def dev_gemfile |