diff options
author | Colby Swandale <colby@taplaboratories.com> | 2017-03-29 18:52:18 +1100 |
---|---|---|
committer | Colby Swandale <colby@taplaboratories.com> | 2017-03-29 18:52:18 +1100 |
commit | fe3046b0b422d0ff453149f4445026072648d6d6 (patch) | |
tree | 12a0923433fbe5d880abe23fd0c089c072031213 /spec | |
parent | 9f358b82190dee44567726c5352c24109f3550ad (diff) | |
parent | 22db10fe2c1ff89468de2b3b2ce85a21902bf576 (diff) | |
download | bundler-fe3046b0b422d0ff453149f4445026072648d6d6.tar.gz |
Merge remote-tracking branch 'upstream/master' into bundler-config-parseable-flag
* upstream/master: (522 commits)
add tests
fix EOL
Require socket in the file that needs it
use Gem::Version.correct? instead of catching exceptions
remove rails 2.3 from ISSUES guide
quote empty PATH
turns out linux needs env vars to be quoted (even when empty)
run specs without git in the env
add specs to test gem command when git is not installed (note: this won't actually work at the moment)
dont create .gitignore as well if git is not installed in the gem command
dont init new git repo unless git is installed on gem command
fix spacing between paragraphs in generated READMEs for new gems
Account for differing behavior in hash#select between 1.8.7 and 1.9.3+
.map -> .each, as we are not using return value
Only uninstall plugins that we attempted to install.
Documentation at the correct place
Double quotes and small documentation
--key parameter can be set via bundle config gem.push_key
Add a spec for nested bundle exec with a gem that shadows a default gem
Allow installing a gem from an arbitrary repo in the specs
...
Diffstat (limited to 'spec')
158 files changed, 3166 insertions, 507 deletions
diff --git a/spec/bundler/bundler_spec.rb b/spec/bundler/bundler_spec.rb index 2ff9920614..268c0d99ac 100644 --- a/spec/bundler/bundler_spec.rb +++ b/spec/bundler/bundler_spec.rb @@ -3,7 +3,7 @@ require "spec_helper" require "bundler" -describe Bundler do +RSpec.describe Bundler do describe "#load_gemspec_uncached" do let(:app_gemspec_path) { tmp("test.gemspec") } subject { Bundler.load_gemspec_uncached(app_gemspec_path) } @@ -143,12 +143,12 @@ describe Bundler do describe "configuration" do context "disable_shared_gems" do - it "should unset GEM_PATH with nil" do + it "should unset GEM_PATH with empty string" do env = {} settings = { :disable_shared_gems => true } Bundler.send(:configure_gem_path, env, settings) expect(env.keys).to include("GEM_PATH") - expect(env["GEM_PATH"]).to be_nil + expect(env["GEM_PATH"]).to eq "" end end end @@ -156,7 +156,7 @@ describe Bundler do describe "#rm_rf" do context "the directory is world writable" do let(:bundler_ui) { Bundler.ui } - it "should show a fridenly error" do + it "should raise a friendly error" do allow(File).to receive(:exist?).and_return(true) allow(FileUtils).to receive(:remove_entry_secure).and_raise(ArgumentError) allow(File).to receive(:world_writable?).and_return(true) @@ -170,4 +170,43 @@ EOF end end end + + describe "#user_home" do + context "home directory is set" do + it "should return the user home" do + path = "/home/oggy" + allow(Bundler.rubygems).to receive(:user_home).and_return(path) + allow(File).to receive(:directory?).with(path).and_return true + allow(File).to receive(:writable?).with(path).and_return true + expect(Bundler.user_home).to eq(Pathname(path)) + end + end + + context "home directory is not set" do + it "should issue warning and return a temporary user home" do + allow(Bundler.rubygems).to receive(:user_home).and_return(nil) + allow(Etc).to receive(:getlogin).and_return("USER") + allow(Dir).to receive(:tmpdir).and_return("/TMP") + allow(FileTest).to receive(:exist?).with("/TMP/bundler/home").and_return(true) + expect(FileUtils).to receive(:mkpath).with("/TMP/bundler/home/USER") + message = <<EOF +Your home directory is not set. +Bundler will use `/TMP/bundler/home/USER' as your home directory temporarily. +EOF + expect(Bundler.ui).to receive(:warn).with(message) + expect(Bundler.user_home).to eq(Pathname("/TMP/bundler/home/USER")) + end + end + end + + describe "#tmp_home_path" do + it "should create temporary user home" do + allow(Dir).to receive(:tmpdir).and_return("/TMP") + allow(FileTest).to receive(:exist?).with("/TMP/bundler/home").and_return(false) + expect(FileUtils).to receive(:mkpath).once.ordered.with("/TMP/bundler/home") + expect(FileUtils).to receive(:mkpath).once.ordered.with("/TMP/bundler/home/USER") + expect(File).to receive(:chmod).with(0o777, "/TMP/bundler/home") + expect(Bundler.tmp_home_path("USER", "")).to eq(Pathname("/TMP/bundler/home/USER")) + end + end end diff --git a/spec/bundler/cli_spec.rb b/spec/bundler/cli_spec.rb index ac704fb41d..ec1d384851 100644 --- a/spec/bundler/cli_spec.rb +++ b/spec/bundler/cli_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" require "bundler/cli" -describe "bundle executable" do +RSpec.describe "bundle executable" do it "returns non-zero exit status when passed unrecognized options" do bundle "--invalid_argument" expect(exitstatus).to_not be_zero if exitstatus @@ -61,9 +61,72 @@ describe "bundle executable" do expect(out).to start_with("Running `bundle config --verbose` with bundler #{Bundler::VERSION}") end end + + describe "printing the outdated warning" do + shared_examples_for "no warning" do + it "prints no warning" do + bundle "fail" + expect(err + out).to eq("Could not find command \"fail\".") + end + end + + let(:bundler_version) { "1.1" } + let(:latest_version) { nil } + before do + simulate_bundler_version(bundler_version) + if latest_version + info_path = home(".bundle/cache/compact_index/rubygems.org.443.29b0360b937aa4d161703e6160654e47/info/bundler") + info_path.parent.mkpath + info_path.open("w") {|f| f.write "#{latest_version}\n" } + end + end + + context "when there is no latest version" do + include_examples "no warning" + end + + context "when the latest version is equal to the current version" do + let(:latest_version) { bundler_version } + include_examples "no warning" + end + + context "when the latest version is less than the current version" do + let(:latest_version) { "0.9" } + include_examples "no warning" + end + + context "when the latest version is greater than the current version" do + let(:latest_version) { "2.0" } + it "prints the version warning" do + bundle "fail" + expect(err + out).to eq(<<-EOS.strip) +The latest bundler is #{latest_version}, but you are currently running #{bundler_version}. +To update, run `gem install bundler` +Could not find command "fail". + EOS + end + + context "and disable_version_check is set" do + before { bundle! "config disable_version_check true" } + include_examples "no warning" + end + + context "and is a pre-release" do + let(:latest_version) { "2.0.0.pre.4" } + it "prints the version warning" do + bundle "fail" + expect(err + out).to eq(<<-EOS.strip) +The latest bundler is #{latest_version}, but you are currently running #{bundler_version}. +To update, run `gem install bundler --pre` +Could not find command "fail". + EOS + end + end + end + end end -describe "bundler executable" do +RSpec.describe "bundler executable" do it "shows the bundler version just as the `bundle` executable does" do bundler "--version" expect(out).to eq("Bundler version #{Bundler::VERSION}") diff --git a/spec/bundler/compact_index_client/updater_spec.rb b/spec/bundler/compact_index_client/updater_spec.rb new file mode 100644 index 0000000000..c1cae31956 --- /dev/null +++ b/spec/bundler/compact_index_client/updater_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true +require "spec_helper" +require "net/http" +require "bundler/compact_index_client" +require "bundler/compact_index_client/updater" + +RSpec.describe Bundler::CompactIndexClient::Updater do + subject(:updater) { described_class.new(fetcher) } + + let(:fetcher) { double(:fetcher) } + + context "when the ETag header is missing" do + # Regression test for https://github.com/bundler/bundler/issues/5463 + + let(:response) { double(:response, :body => "") } + let(:local_path) { Pathname("/tmp/localpath") } + let(:remote_path) { double(:remote_path) } + + it "MisMatchedChecksumError is raised" do + # Twice: #update retries on failure + expect(response).to receive(:[]).with("Content-Encoding").twice { "" } + expect(response).to receive(:[]).with("ETag").twice { nil } + expect(fetcher).to receive(:call).twice { response } + + expect do + updater.update(local_path, remote_path) + end.to raise_error(Bundler::CompactIndexClient::Updater::MisMatchedChecksumError) + end + end +end diff --git a/spec/bundler/definition_spec.rb b/spec/bundler/definition_spec.rb index c72f50f0d1..73d44a93ab 100644 --- a/spec/bundler/definition_spec.rb +++ b/spec/bundler/definition_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" require "bundler/definition" -describe Bundler::Definition do +RSpec.describe Bundler::Definition do describe "#lock" do before do allow(Bundler).to receive(:settings) { Bundler::Settings.new(".") } @@ -137,7 +137,7 @@ describe Bundler::Definition do describe "initialize" do context "gem version promoter" do context "with lockfile" do - before :each do + before do install_gemfile <<-G source "file://#{gem_repo1}" gem "foo" @@ -159,25 +159,119 @@ describe Bundler::Definition do end end - def mock_source_list - Class.new do - def all_sources - [] - end + context "eager unlock" do + before do + gemfile <<-G + source "file://#{gem_repo4}" + gem 'isolated_owner' - def path_sources - [] - end + gem 'shared_owner_a' + gem 'shared_owner_b' + G + + lockfile <<-L + GEM + remote: file://#{gem_repo4} + specs: + isolated_dep (2.0.1) + isolated_owner (1.0.1) + isolated_dep (~> 2.0) + shared_dep (5.0.1) + shared_owner_a (3.0.1) + shared_dep (~> 5.0) + shared_owner_b (4.0.1) + shared_dep (~> 5.0) + + PLATFORMS + ruby + + DEPENDENCIES + shared_owner_a + shared_owner_b + isolated_owner + + BUNDLED WITH + 1.13.0 + L + end - def rubygems_remotes - [] - end + it "should not eagerly unlock shared dependency with bundle install conservative updating behavior" do + updated_deps_in_gemfile = [Bundler::Dependency.new("isolated_owner", ">= 0"), + Bundler::Dependency.new("shared_owner_a", "3.0.2"), + Bundler::Dependency.new("shared_owner_b", ">= 0")] + unlock_hash_for_bundle_install = {} + definition = Bundler::Definition.new( + bundled_app("Gemfile.lock"), + updated_deps_in_gemfile, + Bundler::SourceList.new, + unlock_hash_for_bundle_install + ) + locked = definition.send(:converge_locked_specs).map(&:name) + expect(locked.include?("shared_dep")).to be_truthy + end - def replace_sources!(arg) - nil - end - end.new + it "should not eagerly unlock shared dependency with bundle update conservative updating behavior" do + updated_deps_in_gemfile = [Bundler::Dependency.new("isolated_owner", ">= 0"), + Bundler::Dependency.new("shared_owner_a", ">= 0"), + Bundler::Dependency.new("shared_owner_b", ">= 0")] + definition = Bundler::Definition.new( + bundled_app("Gemfile.lock"), + updated_deps_in_gemfile, + Bundler::SourceList.new, + :gems => ["shared_owner_a"], :lock_shared_dependencies => true + ) + locked = definition.send(:converge_locked_specs).map(&:name) + expect(locked).to eq %w(isolated_dep isolated_owner shared_dep shared_owner_b) + expect(locked.include?("shared_dep")).to be_truthy + end end end end + + describe "find_resolved_spec" do + it "with no platform set in SpecSet" do + ss = Bundler::SpecSet.new([build_stub_spec("a", "1.0"), build_stub_spec("b", "1.0")]) + dfn = Bundler::Definition.new(nil, [], mock_source_list, true) + dfn.instance_variable_set("@specs", ss) + found = dfn.find_resolved_spec(build_spec("a", "0.9", "ruby").first) + expect(found.name).to eq "a" + expect(found.version.to_s).to eq "1.0" + end + end + + describe "find_indexed_specs" do + it "with no platform set in indexed specs" do + index = Bundler::Index.new + %w(1.0.0 1.0.1 1.1.0).each {|v| index << build_stub_spec("foo", v) } + + dfn = Bundler::Definition.new(nil, [], mock_source_list, true) + dfn.instance_variable_set("@index", index) + found = dfn.find_indexed_specs(build_spec("foo", "0.9", "ruby").first) + expect(found.length).to eq 3 + end + end + + def build_stub_spec(name, version) + Bundler::StubSpecification.new(name, version, nil, nil) + end + + def mock_source_list + Class.new do + def all_sources + [] + end + + def path_sources + [] + end + + def rubygems_remotes + [] + end + + def replace_sources!(arg) + nil + end + end.new + end end diff --git a/spec/bundler/dsl_spec.rb b/spec/bundler/dsl_spec.rb index 00d36dd55f..0561cb7ddc 100644 --- a/spec/bundler/dsl_spec.rb +++ b/spec/bundler/dsl_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::Dsl do +RSpec.describe Bundler::Dsl do before do @rubygems = double("rubygems") allow(Bundler::Source::Rubygems).to receive(:new) { @rubygems } @@ -93,8 +93,8 @@ describe Bundler::Dsl do end describe "#gem" do - [:ruby, :ruby_18, :ruby_19, :ruby_20, :ruby_21, :ruby_22, :ruby_23, :mri, :mri_18, :mri_19, - :mri_20, :mri_21, :mri_22, :mri_23, :jruby, :rbx].each do |platform| + [:ruby, :ruby_18, :ruby_19, :ruby_20, :ruby_21, :ruby_22, :ruby_23, :ruby_24, :ruby_25, :mri, :mri_18, :mri_19, + :mri_20, :mri_21, :mri_22, :mri_23, :mri_24, :mri_25, :jruby, :rbx].each do |platform| it "allows #{platform} as a valid platform" do subject.gem("foo", :platform => platform) end diff --git a/spec/bundler/endpoint_specification_spec.rb b/spec/bundler/endpoint_specification_spec.rb index 6718b24971..0b8da840d2 100644 --- a/spec/bundler/endpoint_specification_spec.rb +++ b/spec/bundler/endpoint_specification_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::EndpointSpecification do +RSpec.describe Bundler::EndpointSpecification do let(:name) { "foo" } let(:version) { "1.0.0" } let(:platform) { Gem::Platform::RUBY } @@ -50,4 +50,17 @@ describe Bundler::EndpointSpecification do end end end + + describe "#parse_metadata" do + context "when the metadata has malformed requirements" do + let(:metadata) { { "rubygems" => ">\n" } } + it "raises a helpful error message" do + expect { subject }.to raise_error( + Bundler::GemspecError, + a_string_including("There was an error parsing the metadata for the gem foo (1.0.0)"). + and(a_string_including('The metadata was {"rubygems"=>">\n"}')) + ) + end + end + end end diff --git a/spec/bundler/env_spec.rb b/spec/bundler/env_spec.rb index 1be6cf46bc..269c323ac6 100644 --- a/spec/bundler/env_spec.rb +++ b/spec/bundler/env_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" require "bundler/settings" -describe Bundler::Env do +RSpec.describe Bundler::Env do let(:env) { described_class.new } let(:git_proxy_stub) { Bundler::Source::Git::GitProxy.new(nil, nil, nil) } @@ -49,9 +49,17 @@ describe Bundler::Env do end end + context "when there no Gemfile and print_gemfile is true" do + let(:output) { env.report(:print_gemfile => true) } + + it "prints the environment" do + expect(output).to start_with("## Environment") + end + end + context "when Gemfile contains a gemspec and print_gemspecs is true" do let(:gemspec) do - <<-GEMSPEC.gsub(/^\s+/, "") + strip_whitespace(<<-GEMSPEC) Gem::Specification.new do |gem| gem.name = "foo" gem.author = "Fumofu" @@ -68,7 +76,7 @@ describe Bundler::Env do end it "prints the gemspec" do - output = env.report(:print_gemspecs => true).gsub(/^\s+/, "") + output = env.report(:print_gemspecs => true) expect(output).to include("foo.gemspec") expect(output).to include(gemspec) diff --git a/spec/bundler/environment_preserver_spec.rb b/spec/bundler/environment_preserver_spec.rb index 496646d654..41d2650055 100644 --- a/spec/bundler/environment_preserver_spec.rb +++ b/spec/bundler/environment_preserver_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::EnvironmentPreserver do +RSpec.describe Bundler::EnvironmentPreserver do let(:preserver) { described_class.new(env, ["foo"]) } describe "#backup" do diff --git a/spec/bundler/fetcher/base_spec.rb b/spec/bundler/fetcher/base_spec.rb index bd1c03660c..38b69429bc 100644 --- a/spec/bundler/fetcher/base_spec.rb +++ b/spec/bundler/fetcher/base_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::Fetcher::Base do +RSpec.describe Bundler::Fetcher::Base do let(:downloader) { double(:downloader) } let(:remote) { double(:remote) } let(:display_uri) { "http://sample_uri.com" } diff --git a/spec/bundler/fetcher/compact_index_spec.rb b/spec/bundler/fetcher/compact_index_spec.rb index f6c6ba2ee1..e653c1ea43 100644 --- a/spec/bundler/fetcher/compact_index_spec.rb +++ b/spec/bundler/fetcher/compact_index_spec.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::Fetcher::CompactIndex do +RSpec.describe Bundler::Fetcher::CompactIndex do let(:downloader) { double(:downloader) } - let(:remote) { double(:remote, :cache_slug => "lsjdf") } let(:display_uri) { URI("http://sampleuri.com") } + let(:remote) { double(:remote, :cache_slug => "lsjdf", :uri => display_uri) } let(:compact_index) { described_class.new(downloader, remote, display_uri) } before do @@ -15,7 +15,7 @@ describe Bundler::Fetcher::CompactIndex do it "has only one thread open at the end of the run" do compact_index.specs_for_names(["lskdjf"]) - thread_count = Thread.list.select {|thread| thread.status == "run" }.count + thread_count = Thread.list.count {|thread| thread.status == "run" } expect(thread_count).to eq 1 end @@ -25,6 +25,46 @@ describe Bundler::Fetcher::CompactIndex do compact_index.specs_for_names(["lskdjf"]) end + describe "#available?" do + before do + allow(compact_index).to receive(:compact_index_client). + and_return(double(:compact_index_client, :update_and_parse_checksums! => true)) + end + + it "returns true" do + expect(compact_index).to be_available + end + + context "when OpenSSL is not available" do + before do + allow(compact_index).to receive(:require).with("openssl").and_raise(LoadError) + end + + it "returns true" do + expect(compact_index).to be_available + end + end + + context "when OpenSSL is FIPS-enabled", :ruby => ">= 2.0.0" do + before { stub_const("OpenSSL::OPENSSL_FIPS", true) } + + context "when FIPS-mode is active" do + before do + allow(OpenSSL::Digest::MD5).to receive(:digest). + and_raise(OpenSSL::Digest::DigestError) + end + + it "returns false" do + expect(compact_index).to_not be_available + end + end + + it "returns true" do + expect(compact_index).to be_available + end + end + end + context "logging" do before { allow(compact_index).to receive(:log_specs).and_call_original } diff --git a/spec/bundler/fetcher/dependency_spec.rb b/spec/bundler/fetcher/dependency_spec.rb index bf7749d07a..134ca1bc57 100644 --- a/spec/bundler/fetcher/dependency_spec.rb +++ b/spec/bundler/fetcher/dependency_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::Fetcher::Dependency do +RSpec.describe Bundler::Fetcher::Dependency do let(:downloader) { double(:downloader) } let(:remote) { double(:remote, :uri => URI("http://localhost:5000")) } let(:display_uri) { "http://sample_uri.com" } @@ -262,13 +262,13 @@ describe Bundler::Fetcher::Dependency do let(:uri) { URI("http://gem-api.com") } context "with gem names" do - let(:gem_names) { [%w(foo bar), %w(bundler rubocop)] } + let(:gem_names) { %w(foo bar bundler rubocop) } before { allow(subject).to receive(:fetch_uri).and_return(uri) } it "should return an api calling uri with the gems in the query" do expect(subject.dependency_api_uri(gem_names).to_s).to eq( - "http://gem-api.com/api/v1/dependencies?gems=foo%2Cbar%2Cbundler%2Crubocop" + "http://gem-api.com/api/v1/dependencies?gems=bar%2Cbundler%2Cfoo%2Crubocop" ) end end diff --git a/spec/bundler/fetcher/downloader_spec.rb b/spec/bundler/fetcher/downloader_spec.rb index 8371bcfa6c..8b26b8e415 100644 --- a/spec/bundler/fetcher/downloader_spec.rb +++ b/spec/bundler/fetcher/downloader_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::Fetcher::Downloader do +RSpec.describe Bundler::Fetcher::Downloader do let(:connection) { double(:connection) } let(:redirect_limit) { 5 } let(:uri) { URI("http://www.uri-to-fetch.com/api/v2/endpoint") } diff --git a/spec/bundler/fetcher/index_spec.rb b/spec/bundler/fetcher/index_spec.rb index f81a655c24..b17e0d1727 100644 --- a/spec/bundler/fetcher/index_spec.rb +++ b/spec/bundler/fetcher/index_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::Fetcher::Index do +RSpec.describe Bundler::Fetcher::Index do let(:downloader) { nil } let(:remote) { nil } let(:display_uri) { "http://sample_uri.com" } diff --git a/spec/bundler/fetcher_spec.rb b/spec/bundler/fetcher_spec.rb index 015eb81fd9..5244fc2b18 100644 --- a/spec/bundler/fetcher_spec.rb +++ b/spec/bundler/fetcher_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" require "bundler/fetcher" -describe Bundler::Fetcher do +RSpec.describe Bundler::Fetcher do let(:uri) { URI("https://example.com") } let(:remote) { double("remote", :uri => uri, :original_uri => nil) } diff --git a/spec/bundler/friendly_errors_spec.rb b/spec/bundler/friendly_errors_spec.rb index 1d88403c0e..19799d5495 100644 --- a/spec/bundler/friendly_errors_spec.rb +++ b/spec/bundler/friendly_errors_spec.rb @@ -4,7 +4,7 @@ require "bundler" require "bundler/friendly_errors" require "cgi" -describe Bundler, "friendly errors" do +RSpec.describe Bundler, "friendly errors" do context "with invalid YAML in .gemrc" do before do File.open(Gem.configuration.config_file_name, "w") do |f| @@ -44,14 +44,194 @@ describe Bundler, "friendly errors" do end end - it "rescues Thor::AmbiguousTaskError and raises SystemExit" do + it "calls log_error in case of exception" do + exception = Exception.new + expect(Bundler::FriendlyErrors).to receive(:exit_status).with(exception).and_return(1) expect do Bundler.with_friendly_errors do - raise Thor::AmbiguousTaskError.new("") + raise exception end end.to raise_error(SystemExit) end + it "calls exit_status on exception" do + exception = Exception.new + expect(Bundler::FriendlyErrors).to receive(:log_error).with(exception) + expect do + Bundler.with_friendly_errors do + raise exception + end + end.to raise_error(SystemExit) + end + + describe "#log_error" do + shared_examples "Bundler.ui receive error" do |error, message| + it "" do + expect(Bundler.ui).to receive(:error).with(message || error.message) + Bundler::FriendlyErrors.log_error(error) + end + end + + shared_examples "Bundler.ui receive trace" do |error| + it "" do + expect(Bundler.ui).to receive(:trace).with(error) + Bundler::FriendlyErrors.log_error(error) + end + end + + context "YamlSyntaxError" do + it_behaves_like "Bundler.ui receive error", Bundler::YamlSyntaxError.new(StandardError.new, "sample_message") + + it "Bundler.ui receive trace" do + std_error = StandardError.new + exception = Bundler::YamlSyntaxError.new(std_error, "sample_message") + expect(Bundler.ui).to receive(:trace).with(std_error) + Bundler::FriendlyErrors.log_error(exception) + end + end + + context "Dsl::DSLError, GemspecError" do + it_behaves_like "Bundler.ui receive error", Bundler::Dsl::DSLError.new("description", "dsl_path", "backtrace") + it_behaves_like "Bundler.ui receive error", Bundler::GemspecError.new + end + + context "GemRequireError" do + let(:orig_error) { StandardError.new } + let(:error) { Bundler::GemRequireError.new(orig_error, "sample_message") } + + before do + allow(orig_error).to receive(:backtrace).and_return([]) + end + + it "Bundler.ui receive error" do + expect(Bundler.ui).to receive(:error).with(error.message) + Bundler::FriendlyErrors.log_error(error) + end + + it "writes to Bundler.ui.trace" do + expect(Bundler.ui).to receive(:trace).with(orig_error, nil, true) + Bundler::FriendlyErrors.log_error(error) + end + end + + context "BundlerError" do + it "Bundler.ui receive error" do + error = Bundler::BundlerError.new + 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") } + + it "Bundler.ui receive error" do + expect(Bundler.ui).to receive(:error).with("\nCould not load OpenSSL.") + Bundler::FriendlyErrors.log_error(error) + end + + it "Bundler.ui receive warn" do + expect(Bundler.ui).to receive(:warn).with(any_args, :wrap => true) + Bundler::FriendlyErrors.log_error(error) + end + + it "Bundler.ui receive trace" do + expect(Bundler.ui).to receive(:trace).with(error) + Bundler::FriendlyErrors.log_error(error) + end + end + + context "Interrupt" do + it "Bundler.ui receive error" do + expect(Bundler.ui).to receive(:error).with("\nQuitting...") + Bundler::FriendlyErrors.log_error(Interrupt.new) + end + it_behaves_like "Bundler.ui receive trace", Interrupt.new + end + + 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) + Bundler::FriendlyErrors.log_error(error) + end + end + + context "SystemExit" do + # Does nothing + end + + context "Java::JavaLang::OutOfMemoryError" do + module Java + module JavaLang + class OutOfMemoryError < StandardError; end + end + end + + it "Bundler.ui receive error" do + error = Java::JavaLang::OutOfMemoryError.new + expect(Bundler.ui).to receive(:error).with(/JVM has run out of memory/) + Bundler::FriendlyErrors.log_error(error) + end + end + + context "unexpected error" do + it "calls request_issue_report_for with error" do + error = StandardError.new + expect(Bundler::FriendlyErrors).to receive(:request_issue_report_for).with(error) + Bundler::FriendlyErrors.log_error(error) + end + end + end + + describe "#exit_status" do + it "calls status_code for BundlerError" do + error = Bundler::BundlerError.new + expect(error).to receive(:status_code).and_return("sample_status_code") + expect(Bundler::FriendlyErrors.exit_status(error)).to eq("sample_status_code") + end + + it "returns 15 for Thor::Error" do + error = Bundler::Thor::Error.new + expect(Bundler::FriendlyErrors.exit_status(error)).to eq(15) + end + + it "calls status for SystemExit" do + error = SystemExit.new + expect(error).to receive(:status).and_return("sample_status") + expect(Bundler::FriendlyErrors.exit_status(error)).to eq("sample_status") + end + + it "returns 1 in other cases" do + error = StandardError.new + expect(Bundler::FriendlyErrors.exit_status(error)).to eq(1) + end + end + + describe "#request_issue_report_for" do + it "calls relevant methods for Bundler.ui" do + expect(Bundler.ui).to receive(:info) + expect(Bundler.ui).to receive(:error) + expect(Bundler.ui).to receive(:warn) + Bundler::FriendlyErrors.request_issue_report_for(StandardError.new) + end + + it "includes error class, message and backlog" do + error = StandardError.new + allow(Bundler::FriendlyErrors).to receive(:issues_url).and_return("") + + expect(error).to receive(:class).at_least(:once) + expect(error).to receive(:message).at_least(:once) + expect(error).to receive(:backtrace).at_least(:once) + Bundler::FriendlyErrors.request_issue_report_for(error) + end + end + describe "#issues_url" do it "generates a search URL for the exception message" do exception = Exception.new("Exception message") diff --git a/spec/bundler/gem_helper_spec.rb b/spec/bundler/gem_helper_spec.rb index 4e1af32c11..498ed89447 100644 --- a/spec/bundler/gem_helper_spec.rb +++ b/spec/bundler/gem_helper_spec.rb @@ -3,7 +3,7 @@ require "spec_helper" require "rake" require "bundler/gem_helper" -describe Bundler::GemHelper do +RSpec.describe Bundler::GemHelper do let(:app_name) { "lorem__ipsum" } let(:app_path) { bundled_app app_name } let(:app_gemspec_path) { app_path.join("#{app_name}.gemspec") } @@ -160,9 +160,10 @@ describe Bundler::GemHelper do it "gem is installed" do mock_build_message app_name, app_version mock_confirm_message "#{app_name} (#{app_version}) installed." - subject.install_gem + subject.install_gem(nil, :local) expect(app_gem_path).to exist - expect(`gem list`).to include("#{app_name} (#{app_version})") + gem_command! :list + expect(out).to include("#{app_name} (#{app_version})") end end diff --git a/spec/bundler/gem_version_promoter_spec.rb b/spec/bundler/gem_version_promoter_spec.rb index 9e5a7bb581..c7620e2620 100644 --- a/spec/bundler/gem_version_promoter_spec.rb +++ b/spec/bundler/gem_version_promoter_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::GemVersionPromoter do +RSpec.describe Bundler::GemVersionPromoter do context "conservative resolver" do def versions(result) result.flatten.map(&:version).map(&:to_s) diff --git a/spec/bundler/index_spec.rb b/spec/bundler/index_spec.rb index da8e5731ca..09b09e08fa 100644 --- a/spec/bundler/index_spec.rb +++ b/spec/bundler/index_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::Index do +RSpec.describe Bundler::Index do let(:specs) { [] } subject { described_class.build {|i| i.use(specs) } } @@ -26,4 +26,12 @@ describe Bundler::Index do end end end + + context "with specs that include development dependencies" do + let(:specs) { [*build_spec("a", "1.0.0") {|s| s.development("b", "~> 1.0") }] } + + it "does not include b in #dependency_names" do + expect(subject.dependency_names).not_to include("b") + end + end end diff --git a/spec/bundler/installer/gem_installer_spec.rb b/spec/bundler/installer/gem_installer_spec.rb new file mode 100644 index 0000000000..de5189eecd --- /dev/null +++ b/spec/bundler/installer/gem_installer_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +require "spec_helper" +require "bundler/installer/gem_installer" + +RSpec.describe Bundler::GemInstaller do + let(:installer) { instance_double("Installer") } + let(:spec_source) { instance_double("SpecSource") } + 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", :rubygems => ">= 2" do + allow(spec_source).to receive(:install).with(spec, :force => false, :ensure_builtin_gems_cached => false, :build_args => []) + subject.install_from_spec + end + end + + context "spec_settings is build option" do + it "invokes install method with build_args", :rubygems => ">= 2" do + allow(Bundler.settings).to receive(:[]).with(:bin) + allow(Bundler.settings).to receive(:[]).with("build.dummy").and_return("--with-dummy-config=dummy") + allow(spec_source).to receive(:install).with(spec, :force => false, :ensure_builtin_gems_cached => false, :build_args => ["--with-dummy-config=dummy"]) + subject.install_from_spec + end + end +end diff --git a/spec/bundler/installer/parallel_installer_spec.rb b/spec/bundler/installer/parallel_installer_spec.rb new file mode 100644 index 0000000000..7d2c441399 --- /dev/null +++ b/spec/bundler/installer/parallel_installer_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true +require "spec_helper" +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 +end diff --git a/spec/install/parallel/spec_installation_spec.rb b/spec/bundler/installer/spec_installation_spec.rb index 7bbd2bd0e6..1e368ab7c5 100644 --- a/spec/install/parallel/spec_installation_spec.rb +++ b/spec/bundler/installer/spec_installation_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" require "bundler/installer/parallel_installer" -describe Bundler::ParallelInstaller::SpecInstallation do +RSpec.describe Bundler::ParallelInstaller::SpecInstallation do let!(:dep) do a_spec = Object.new def a_spec.name @@ -58,20 +58,5 @@ describe Bundler::ParallelInstaller::SpecInstallation do expect(spec.dependencies_installed?(all_specs)).to be_falsey end end - - context "when dependencies that are not on the overall installation list are the only ones not installed" do - it "raises an error" do - dependencies = [] - dependencies << instance_double("SpecInstallation", :spec => "alpha", :name => "alpha", :installed? => true, :all_dependencies => [], :type => :production) - all_specs = dependencies + [instance_double("SpecInstallation", :spec => "gamma", :name => "gamma", :installed? => false, :all_dependencies => [], :type => :production)] - # Add dependency which is not in all_specs - dependencies << instance_double("SpecInstallation", :spec => "beta", :name => "beta", :installed? => false, :all_dependencies => [], :type => :production) - dependencies << instance_double("SpecInstallation", :spec => "delta", :name => "delta", :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 raise_error(Bundler::LockfileError, /Your Gemfile.lock is corrupt\. The following.*'beta' 'delta'/) - end - end end end diff --git a/spec/bundler/lockfile_parser_spec.rb b/spec/bundler/lockfile_parser_spec.rb index 98d7b68c6e..17bb447194 100644 --- a/spec/bundler/lockfile_parser_spec.rb +++ b/spec/bundler/lockfile_parser_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" require "bundler/lockfile_parser" -describe Bundler::LockfileParser do +RSpec.describe Bundler::LockfileParser do let(:lockfile_contents) { strip_whitespace(<<-L) } GIT remote: https://github.com/alloy/peiji-san.git diff --git a/spec/bundler/mirror_spec.rb b/spec/bundler/mirror_spec.rb index eb0ccf0bdf..9051a80465 100644 --- a/spec/bundler/mirror_spec.rb +++ b/spec/bundler/mirror_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" require "bundler/mirror" -describe Bundler::Settings::Mirror do +RSpec.describe Bundler::Settings::Mirror do let(:mirror) { Bundler::Settings::Mirror.new } it "returns zero when fallback_timeout is not set" do @@ -131,10 +131,20 @@ describe Bundler::Settings::Mirror do end end end + + describe "#==" do + it "returns true if uri and fallback timeout are the same" do + uri = "https://ruby.taobao.org" + mirror = Bundler::Settings::Mirror.new(uri, 1) + another_mirror = Bundler::Settings::Mirror.new(uri, 1) + + expect(mirror == another_mirror).to be true + end + end end end -describe Bundler::Settings::Mirrors do +RSpec.describe Bundler::Settings::Mirrors do let(:localhost_uri) { URI("http://localhost:9292") } context "with a just created mirror" do @@ -283,7 +293,7 @@ describe Bundler::Settings::Mirrors do end end -describe Bundler::Settings::TCPSocketProbe do +RSpec.describe Bundler::Settings::TCPSocketProbe do let(:probe) { Bundler::Settings::TCPSocketProbe.new } context "with a listening TCP Server" do diff --git a/spec/bundler/plugin/api/source_spec.rb b/spec/bundler/plugin/api/source_spec.rb index d62127a604..4dbb993b89 100644 --- a/spec/bundler/plugin/api/source_spec.rb +++ b/spec/bundler/plugin/api/source_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::Plugin::API::Source do +RSpec.describe Bundler::Plugin::API::Source do let(:uri) { "uri://to/test" } let(:type) { "spec_type" } diff --git a/spec/bundler/plugin/api_spec.rb b/spec/bundler/plugin/api_spec.rb index 0eba52301a..e40b9adb0f 100644 --- a/spec/bundler/plugin/api_spec.rb +++ b/spec/bundler/plugin/api_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::Plugin::API do +RSpec.describe Bundler::Plugin::API do context "plugin declarations" do before do stub_const "UserPluginClass", Class.new(Bundler::Plugin::API) diff --git a/spec/bundler/plugin/dsl_spec.rb b/spec/bundler/plugin/dsl_spec.rb index 9a694833ff..cd15b6ea9d 100644 --- a/spec/bundler/plugin/dsl_spec.rb +++ b/spec/bundler/plugin/dsl_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::Plugin::DSL do +RSpec.describe Bundler::Plugin::DSL do DSL = Bundler::Plugin::DSL subject(:dsl) { Bundler::Plugin::DSL.new } diff --git a/spec/bundler/plugin/index_spec.rb b/spec/bundler/plugin/index_spec.rb index 5a754f355c..24b9a408ff 100644 --- a/spec/bundler/plugin/index_spec.rb +++ b/spec/bundler/plugin/index_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::Plugin::Index do +RSpec.describe Bundler::Plugin::Index do Index = Bundler::Plugin::Index before do @@ -31,7 +31,7 @@ describe Bundler::Plugin::Index do expect(new_index.plugin_path(plugin_name)).to eq(lib_path(plugin_name)) end - it "load_paths are persistant" do + it "load_paths are persistent" do new_index = Index.new expect(new_index.load_paths(plugin_name)).to eq([lib_path(plugin_name).join("lib").to_s]) end @@ -95,7 +95,7 @@ describe Bundler::Plugin::Index do allow(File).to receive(:open).and_yield(file) end - it "should not save it with next registed hook" do + it "should not save it with next registered hook" do expect(file).to receive(:puts) do |content| expect(content).not_to include("not-there") end diff --git a/spec/bundler/plugin/installer_spec.rb b/spec/bundler/plugin/installer_spec.rb index 9d6eb1c55b..2454ef00f9 100644 --- a/spec/bundler/plugin/installer_spec.rb +++ b/spec/bundler/plugin/installer_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::Plugin::Installer do +RSpec.describe Bundler::Plugin::Installer do subject(:installer) { Bundler::Plugin::Installer.new } describe "cli install" do diff --git a/spec/bundler/plugin/source_list_spec.rb b/spec/bundler/plugin/source_list_spec.rb index 774156b27c..86cc4ac4ed 100644 --- a/spec/bundler/plugin/source_list_spec.rb +++ b/spec/bundler/plugin/source_list_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::Plugin::SourceList do +RSpec.describe Bundler::Plugin::SourceList do SourceList = Bundler::Plugin::SourceList before do diff --git a/spec/bundler/plugin_spec.rb b/spec/bundler/plugin_spec.rb index 540278036c..5bbb7384c8 100644 --- a/spec/bundler/plugin_spec.rb +++ b/spec/bundler/plugin_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::Plugin do +RSpec.describe Bundler::Plugin do Plugin = Bundler::Plugin let(:installer) { double(:installer) } diff --git a/spec/bundler/psyched_yaml_spec.rb b/spec/bundler/psyched_yaml_spec.rb index 4b7715b482..18e40d6b5a 100644 --- a/spec/bundler/psyched_yaml_spec.rb +++ b/spec/bundler/psyched_yaml_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" require "bundler/psyched_yaml" -describe "Bundler::YamlLibrarySyntaxError" do +RSpec.describe "Bundler::YamlLibrarySyntaxError" do it "is raised on YAML parse errors" do expect { YAML.parse "{foo" }.to raise_error(Bundler::YamlLibrarySyntaxError) end diff --git a/spec/bundler/remote_specification_spec.rb b/spec/bundler/remote_specification_spec.rb index 28d78a82c7..69a2ab3d67 100644 --- a/spec/bundler/remote_specification_spec.rb +++ b/spec/bundler/remote_specification_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::RemoteSpecification do +RSpec.describe Bundler::RemoteSpecification do let(:name) { "foo" } let(:version) { Gem::Version.new("1.0.0") } let(:platform) { Gem::Platform::RUBY } @@ -128,8 +128,8 @@ describe Bundler::RemoteSpecification do end describe "#__swap__" do - let(:spec) { double(:spec) } - let(:new_spec) { double(:new_spec) } + let(:spec) { double(:spec, :dependencies => []) } + let(:new_spec) { double(:new_spec, :runtime_dependencies => []) } before { subject.instance_variable_set(:@_remote_specification, spec) } @@ -158,32 +158,30 @@ describe Bundler::RemoteSpecification do describe "method missing" do context "and is present in Gem::Specification" do - let(:remote_spec) { double(:remote_spec) } + let(:remote_spec) { double(:remote_spec, :authors => "abcd") } before do - allow_any_instance_of(Gem::Specification).to receive(:respond_to?).and_return(true) allow(subject).to receive(:_remote_specification).and_return(remote_spec) + expect(subject.methods.map(&:to_sym)).not_to include(:authors) end it "should send through to Gem::Specification" do - expect(remote_spec).to receive(:send).with(:missing_method_call).once - subject.missing_method_call + expect(subject.authors).to eq("abcd") end end end describe "respond to missing?" do context "and is present in Gem::Specification" do - let(:remote_spec) { double(:remote_spec) } + let(:remote_spec) { double(:remote_spec, :authors => "abcd") } before do - allow_any_instance_of(Gem::Specification).to receive(:respond_to?).and_return(false) allow(subject).to receive(:_remote_specification).and_return(remote_spec) + expect(subject.methods.map(&:to_sym)).not_to include(:authors) end it "should send through to Gem::Specification" do - expect(remote_spec).to receive(:respond_to?).with(:missing_method_call, false).once - subject.respond_to?(:missing_method_call) + expect(subject.respond_to?(:authors)).to be_truthy end end end diff --git a/spec/bundler/retry_spec.rb b/spec/bundler/retry_spec.rb index 665ba9f2df..525f05d327 100644 --- a/spec/bundler/retry_spec.rb +++ b/spec/bundler/retry_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::Retry do +RSpec.describe Bundler::Retry do it "return successful result if no errors" do attempts = 0 result = Bundler::Retry.new(nil, nil, 3).attempt do @@ -65,10 +65,10 @@ describe Bundler::Retry do end end - context "with debugging on" do + context "with debugging off" do it "print error message with newlines" do allow(Bundler.ui).to receive(:debug?).and_return(false) - expect(Bundler.ui).to receive(:info).with("") + expect(Bundler.ui).to receive(:info).with("").twice expect(Bundler.ui).to receive(:warn).with(failure_message, false) expect do diff --git a/spec/bundler/ruby_dsl_spec.rb b/spec/bundler/ruby_dsl_spec.rb index ac73747ac7..3e0ec9d7f0 100644 --- a/spec/bundler/ruby_dsl_spec.rb +++ b/spec/bundler/ruby_dsl_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" require "bundler/ruby_dsl" -describe Bundler::RubyDsl do +RSpec.describe Bundler::RubyDsl do class MockDSL include Bundler::RubyDsl diff --git a/spec/bundler/ruby_version_spec.rb b/spec/bundler/ruby_version_spec.rb index abcd0303d0..f77ec606fc 100644 --- a/spec/bundler/ruby_version_spec.rb +++ b/spec/bundler/ruby_version_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" require "bundler/ruby_version" -describe "Bundler::RubyVersion and its subclasses" do +RSpec.describe "Bundler::RubyVersion and its subclasses" do let(:version) { "2.0.0" } let(:patchlevel) { "645" } let(:engine) { "jruby" } @@ -35,6 +35,14 @@ describe "Bundler::RubyVersion and its subclasses" do end end + context "with engine in symbol" do + let(:engine) { :jruby } + + it "should coerce engine to string" do + expect(subject.engine).to eq("jruby") + end + end + context "is called with multiple requirements" do let(:version) { ["<= 2.0.0", "> 1.9.3"] } let(:engine_version) { nil } diff --git a/spec/bundler/rubygems_integration_spec.rb b/spec/bundler/rubygems_integration_spec.rb index fbc49c414c..37eb499e38 100644 --- a/spec/bundler/rubygems_integration_spec.rb +++ b/spec/bundler/rubygems_integration_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::RubygemsIntegration do +RSpec.describe Bundler::RubygemsIntegration do it "uses the same chdir lock as rubygems", :rubygems => "2.1" do expect(Bundler.rubygems.ext_lock).to eq(Gem::Ext::Builder::CHDIR_MONITOR) end diff --git a/spec/bundler/settings_spec.rb b/spec/bundler/settings_spec.rb index 0f7d2a0138..020897882c 100644 --- a/spec/bundler/settings_spec.rb +++ b/spec/bundler/settings_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" require "bundler/settings" -describe Bundler::Settings do +RSpec.describe Bundler::Settings do subject(:settings) { described_class.new(bundled_app) } describe "#set_local" do @@ -51,9 +51,41 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow end] expect(loaded).to eq(expected) end + + context "when BUNDLE_IGNORE_CONFIG is set" do + before { ENV["BUNDLE_IGNORE_CONFIG"] = "TRUE" } + + it "ignores the config" do + loaded = settings.send(:load_config, bundled_app("config")) + expect(loaded).to eq({}) + end + end + end + + describe "#global_config_file" do + context "when $HOME is not accessible" do + context "when $TMPDIR is not writable" do + it "does not raise" do + expect(Bundler.rubygems).to receive(:user_home).twice.and_return(nil) + expect(FileUtils).to receive(:mkpath).twice.with(File.join(Dir.tmpdir, "bundler", "home")).and_raise(Errno::EROFS, "Read-only file system @ dir_s_mkdir - /tmp/bundler") + + expect(subject.send(:global_config_file)).to be_nil + end + end + end end describe "#[]" do + context "when the local config file is not found" do + subject(:settings) { described_class.new } + + it "does not raise" do + expect do + subject["foo"] + end.not_to raise_error + end + end + context "when not set" do context "when default value present" do it "retrieves value" do @@ -96,6 +128,18 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow end end + describe "#temporary" do + it "reset after used" do + Bundler.settings[:no_install] = true + + Bundler.settings.temporary(:no_install => false) do + expect(Bundler.settings[:no_install]).to eq false + end + + expect(Bundler.settings[:no_install]).to eq true + end + end + describe "#set_global" do context "when it's not possible to write to the file" do it "raises an PermissionError with explanation" do diff --git a/spec/bundler/shared_helpers_spec.rb b/spec/bundler/shared_helpers_spec.rb index 4c0d61cf0a..8bd7215666 100644 --- a/spec/bundler/shared_helpers_spec.rb +++ b/spec/bundler/shared_helpers_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::SharedHelpers do +RSpec.describe Bundler::SharedHelpers do let(:ext_lock_double) { double(:ext_lock) } before do @@ -234,7 +234,9 @@ describe Bundler::SharedHelpers do shared_examples_for "ENV['RUBYLIB'] gets set correctly" do let(:ruby_lib_path) { "stubbed_ruby_lib_dir" } - before { allow(File).to receive(:expand_path).and_return(ruby_lib_path) } + before do + allow(Bundler::SharedHelpers).to receive(:bundler_ruby_lib).and_return(ruby_lib_path) + end it "ensures bundler's ruby version lib path is in ENV['RUBYLIB']" do subject.set_bundle_environment @@ -324,7 +326,6 @@ describe Bundler::SharedHelpers do let(:ruby_lib_path) { "stubbed_ruby_lib_dir" } before do - allow(File).to receive(:expand_path).and_return(ruby_lib_path) ENV["RUBYLIB"] = ruby_lib_path end @@ -387,6 +388,27 @@ describe Bundler::SharedHelpers do ) end end + + context "system throws Errno::ENOSPC" do + let(:file_op_block) { proc {|_path| raise Errno::ENOSPC } } + + it "raises a NoSpaceOnDeviceError" do + expect { subject.filesystem_access("/path", &file_op_block) }.to raise_error( + Bundler::NoSpaceOnDeviceError + ) + end + end + + context "system throws an unhandled SystemCallError" do + let(:error) { SystemCallError.new("Shields down", 1337) } + let(:file_op_block) { proc {|_path| raise error } } + + it "raises a GenericSystemCallError" do + expect { subject.filesystem_access("/path", &file_op_block) }.to raise_error( + Bundler::GenericSystemCallError, /error accessing.+underlying.+Shields down/m + ) + end + end end describe "#const_get_safely" do diff --git a/spec/bundler/source/git/git_proxy_spec.rb b/spec/bundler/source/git/git_proxy_spec.rb index ce6b79b2b2..34fe21e9fb 100644 --- a/spec/bundler/source/git/git_proxy_spec.rb +++ b/spec/bundler/source/git/git_proxy_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::Source::Git::GitProxy do +RSpec.describe Bundler::Source::Git::GitProxy do let(:uri) { "https://github.com/bundler/bundler.git" } subject { described_class.new(Pathname("path"), uri, "HEAD") } diff --git a/spec/bundler/source/rubygems/remote_spec.rb b/spec/bundler/source/rubygems/remote_spec.rb index a541bf1468..54394fc0ca 100644 --- a/spec/bundler/source/rubygems/remote_spec.rb +++ b/spec/bundler/source/rubygems/remote_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" require "bundler/source/rubygems/remote" -describe Bundler::Source::Rubygems::Remote do +RSpec.describe Bundler::Source::Rubygems::Remote do def remote(uri) Bundler::Source::Rubygems::Remote.new(uri) end diff --git a/spec/bundler/source/rubygems_spec.rb b/spec/bundler/source/rubygems_spec.rb index 9fb4bf0ad3..b8f9f09c20 100644 --- a/spec/bundler/source/rubygems_spec.rb +++ b/spec/bundler/source/rubygems_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::Source::Rubygems do +RSpec.describe Bundler::Source::Rubygems do before do allow(Bundler).to receive(:root) { Pathname.new("root") } end diff --git a/spec/bundler/source_list_spec.rb b/spec/bundler/source_list_spec.rb index 3657ac0927..6a23c8bcbf 100644 --- a/spec/bundler/source_list_spec.rb +++ b/spec/bundler/source_list_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::SourceList do +RSpec.describe Bundler::SourceList do before do allow(Bundler).to receive(:root) { Pathname.new "./tmp/bundled_app" } diff --git a/spec/bundler/source_spec.rb b/spec/bundler/source_spec.rb index 4e99411a17..08d1698fcd 100644 --- a/spec/bundler/source_spec.rb +++ b/spec/bundler/source_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::Source do +RSpec.describe Bundler::Source do class ExampleSource < Bundler::Source end @@ -61,7 +61,7 @@ describe Bundler::Source do before { Bundler.ui = Bundler::UI::Shell.new } 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[32mwas < 1.5\e[0m)") + expect(subject.version_message(spec)).to eq("nokogiri >= 1.6\e[32m (was < 1.5)\e[0m") end end @@ -71,6 +71,32 @@ describe Bundler::Source do 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") } + + context "with color" do + before { Bundler.ui = Bundler::UI::Shell.new } + + 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") + 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") } + + context "with color" do + before { Bundler.ui = Bundler::UI::Shell.new } + + 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") + end + end + end end context "that do not contain the relevant gem spec" do diff --git a/spec/bundler/spec_set_spec.rb b/spec/bundler/spec_set_spec.rb index 29d81cb30c..8f7c27f065 100644 --- a/spec/bundler/spec_set_spec.rb +++ b/spec/bundler/spec_set_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::SpecSet do +RSpec.describe Bundler::SpecSet do let(:specs) do [ build_spec("a", "1.0"), diff --git a/spec/bundler/ssl_certs/certificate_manager_spec.rb b/spec/bundler/ssl_certs/certificate_manager_spec.rb index cc8c8a49a1..51552f7234 100644 --- a/spec/bundler/ssl_certs/certificate_manager_spec.rb +++ b/spec/bundler/ssl_certs/certificate_manager_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" require "bundler/ssl_certs/certificate_manager" -describe Bundler::SSLCerts::CertificateManager do +RSpec.describe Bundler::SSLCerts::CertificateManager do let(:rubygems_path) { root } let(:stub_cert) { File.join(root.to_s, "lib", "rubygems", "ssl_certs", "rubygems.org", "ssl-cert.pem") } let(:rubygems_certs_dir) { File.join(root.to_s, "lib", "rubygems", "ssl_certs", "rubygems.org") } diff --git a/spec/bundler/ui_spec.rb b/spec/bundler/ui_spec.rb new file mode 100644 index 0000000000..41c037527b --- /dev/null +++ b/spec/bundler/ui_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +require "spec_helper" + +RSpec.describe Bundler::UI do + describe Bundler::UI::Silent do + it "has the same instance methods as Shell", :ruby => ">= 1.9" do + shell = Bundler::UI::Shell + methods = proc do |cls| + cls.instance_methods.map do |i| + m = shell.instance_method(i) + [i, m.parameters] + end.sort_by(&:first) + end + expect(methods.call(described_class)).to eq(methods.call(shell)) + end + + it "has the same instance class as Shell", :ruby => ">= 1.9" do + shell = Bundler::UI::Shell + methods = proc do |cls| + cls.methods.map do |i| + m = shell.method(i) + [i, m.parameters] + end.sort_by(&:first) + end + expect(methods.call(described_class)).to eq(methods.call(shell)) + end + end +end diff --git a/spec/bundler/uri_credentials_filter_spec.rb b/spec/bundler/uri_credentials_filter_spec.rb index 70f71cecac..1dd01b4be0 100644 --- a/spec/bundler/uri_credentials_filter_spec.rb +++ b/spec/bundler/uri_credentials_filter_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe Bundler::URICredentialsFilter do +RSpec.describe Bundler::URICredentialsFilter do subject { described_class } describe "#credential_filtered_uri" do diff --git a/spec/bundler/worker_spec.rb b/spec/bundler/worker_spec.rb new file mode 100644 index 0000000000..fbfe6ddab3 --- /dev/null +++ b/spec/bundler/worker_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +require "spec_helper" +require "bundler/worker" + +RSpec.describe Bundler::Worker do + let(:size) { 5 } + let(:name) { "Spec Worker" } + let(:function) { proc {|object, worker_number| [object, worker_number] } } + subject { described_class.new(size, name, function) } + + after { subject.stop } + + describe "#initialize" do + context "when Thread.start raises ThreadError" do + it "raises when no threads can be created" do + allow(Thread).to receive(:start).and_raise(ThreadError, "error creating thread") + + expect { subject.enq "a" }.to raise_error(Bundler::ThreadCreationError, "Failed to create threads for the Spec Worker worker: error creating thread") + end + end + end +end diff --git a/spec/bundler/yaml_serializer_spec.rb b/spec/bundler/yaml_serializer_spec.rb index bf86d2a076..361159e0da 100644 --- a/spec/bundler/yaml_serializer_spec.rb +++ b/spec/bundler/yaml_serializer_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" require "bundler/yaml_serializer" -describe Bundler::YAMLSerializer do +RSpec.describe Bundler::YAMLSerializer do subject(:serializer) { Bundler::YAMLSerializer } describe "#dump" do diff --git a/spec/cache/cache_path_spec.rb b/spec/cache/cache_path_spec.rb index 594162886a..ec6d6e312a 100644 --- a/spec/cache/cache_path_spec.rb +++ b/spec/cache/cache_path_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle package" do +RSpec.describe "bundle package" do before do gemfile <<-G source "file://#{gem_repo1}" diff --git a/spec/cache/gems_spec.rb b/spec/cache/gems_spec.rb index 474233a83c..7828c87fec 100644 --- a/spec/cache/gems_spec.rb +++ b/spec/cache/gems_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle cache" do +RSpec.describe "bundle cache" do describe "when there are only gemsources" do before :each do gemfile <<-G @@ -238,7 +238,7 @@ describe "bundle cache" do gem "platform_specific" G - expect(cached_gem("platform_specific-1.0-#{Gem::Platform.local}")).to exist + expect(cached_gem("platform_specific-1.0-#{Bundler.local_platform}")).to exist expect(cached_gem("platform_specific-1.0-java")).to exist end diff --git a/spec/cache/git_spec.rb b/spec/cache/git_spec.rb index c15ee26c25..b256c8d90f 100644 --- a/spec/cache/git_spec.rb +++ b/spec/cache/git_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "git base name" do +RSpec.describe "git base name" do it "base_name should strip private repo uris" do source = Bundler::Source::Git.new("uri" => "git@github.com:bundler.git") expect(source.send(:base_name)).to eq("bundler") @@ -14,7 +14,7 @@ describe "git base name" do end %w(cache package).each do |cmd| - describe "bundle #{cmd} with git" do + RSpec.describe "bundle #{cmd} with git" do it "copies repository to vendor cache and uses it" do git = build_git "foo" ref = git.ref_for("master", 11) diff --git a/spec/cache/path_spec.rb b/spec/cache/path_spec.rb index 4233b3e88b..bbce448759 100644 --- a/spec/cache/path_spec.rb +++ b/spec/cache/path_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" %w(cache package).each do |cmd| - describe "bundle #{cmd} with path" do + RSpec.describe "bundle #{cmd} with path" do it "is no-op when the path is within the bundle" do build_lib "foo", :path => bundled_app("lib/foo") diff --git a/spec/cache/platform_spec.rb b/spec/cache/platform_spec.rb index 259eff0e15..ed80c949aa 100644 --- a/spec/cache/platform_spec.rb +++ b/spec/cache/platform_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle cache with multiple platforms" do +RSpec.describe "bundle cache with multiple platforms" do before :each do gemfile <<-G source "file://#{gem_repo1}" diff --git a/spec/commands/binstubs_spec.rb b/spec/commands/binstubs_spec.rb index 0f8c5af391..cb0999348e 100644 --- a/spec/commands/binstubs_spec.rb +++ b/spec/commands/binstubs_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle binstubs <gem>" do +RSpec.describe "bundle binstubs <gem>" do context "when the gem exists in the lockfile" do it "sets up the binstub" do install_gemfile <<-G @@ -157,7 +157,7 @@ describe "bundle binstubs <gem>" do it "includes the standalone path" do bundle "binstubs rack --standalone" 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", path.realpath) end end diff --git a/spec/commands/check_spec.rb b/spec/commands/check_spec.rb index 42d6459760..532be07c3f 100644 --- a/spec/commands/check_spec.rb +++ b/spec/commands/check_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle check" do +RSpec.describe "bundle check" do it "returns success when the Gemfile is satisfied" do install_gemfile <<-G source "file://#{gem_repo1}" diff --git a/spec/commands/clean_spec.rb b/spec/commands/clean_spec.rb index 72d422c3a2..8fd4b6fbe8 100644 --- a/spec/commands/clean_spec.rb +++ b/spec/commands/clean_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle clean" do +RSpec.describe "bundle clean" do def should_have_gems(*gems) gems.each do |g| expect(vendored_gems("gems/#{g}")).to exist @@ -567,7 +567,7 @@ describe "bundle clean" do expect(exitstatus).to eq(0) if exitstatus end - it "doesn't remove gems in dry-run mode" do + it "doesn't remove gems in dry-run mode with path set" do gemfile <<-G source "file://#{gem_repo1}" @@ -595,6 +595,36 @@ describe "bundle clean" do expect(vendored_gems("bin/rackup")).to exist end + it "doesn't remove gems in dry-run mode with no path set" do + gemfile <<-G + source "file://#{gem_repo1}" + + gem "thin" + gem "foo" + G + + bundle "install --path vendor/bundle --no-clean" + + gemfile <<-G + source "file://#{gem_repo1}" + + gem "thin" + G + + bundle :install + + bundle "configuration --delete path" + + bundle "clean --dry-run" + + expect(out).not_to include("Removing foo (1.0)") + expect(out).to include("Would have removed foo (1.0)") + + should_have_gems "thin-1.0", "rack-1.0.0", "foo-1.0" + + expect(vendored_gems("bin/rackup")).to exist + end + it "doesn't store dry run as a config setting" do gemfile <<-G source "file://#{gem_repo1}" diff --git a/spec/commands/config_spec.rb b/spec/commands/config_spec.rb index 15c1c365c8..640ec06e17 100644 --- a/spec/commands/config_spec.rb +++ b/spec/commands/config_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe ".bundle/config" do +RSpec.describe ".bundle/config" do before :each do gemfile <<-G source "file://#{gem_repo1}" @@ -319,7 +319,7 @@ E end end -describe "setting gemfile via config" do +RSpec.describe "setting gemfile via config" do context "when only the non-default Gemfile exists" do it "persists the gemfile location to .bundle/config" do File.open(bundled_app("NotGemfile"), "w") do |f| diff --git a/spec/commands/console_spec.rb b/spec/commands/console_spec.rb index 131b47368b..de14b6db5f 100644 --- a/spec/commands/console_spec.rb +++ b/spec/commands/console_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle console" do +RSpec.describe "bundle console" do before :each do install_gemfile <<-G source "file://#{gem_repo1}" diff --git a/spec/commands/doctor_spec.rb b/spec/commands/doctor_spec.rb index 8debeb55e4..7c6e48ce19 100644 --- a/spec/commands/doctor_spec.rb +++ b/spec/commands/doctor_spec.rb @@ -4,7 +4,7 @@ require "stringio" require "bundler/cli" require "bundler/cli/doctor" -describe "bundle doctor" do +RSpec.describe "bundle doctor" do before(:each) do @stdout = StringIO.new diff --git a/spec/commands/exec_spec.rb b/spec/commands/exec_spec.rb index 42afbd24ba..3c5f2ca1dd 100644 --- a/spec/commands/exec_spec.rb +++ b/spec/commands/exec_spec.rb @@ -1,9 +1,10 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle exec" do +RSpec.describe "bundle exec" do + let(:system_gems_to_install) { %w(rack-1.0.0 rack-0.9.1) } before :each do - system_gems "rack-1.0.0", "rack-0.9.1" + system_gems(system_gems_to_install) end it "activates the correct gem" do @@ -271,35 +272,35 @@ describe "bundle exec" do with_fake_man do bundle "#{exec} --help cat" end - expect(out).to include(%(["#{root}/lib/bundler/man/bundle-exec"])) + expect(out).to include(%(["#{root}/man/bundle-exec.1"])) end it "shows bundle-exec's man page when --help is before exec" do with_fake_man do bundle "--help #{exec}" end - expect(out).to include(%(["#{root}/lib/bundler/man/bundle-exec"])) + expect(out).to include(%(["#{root}/man/bundle-exec.1"])) end it "shows bundle-exec's man page when -h is before exec" do with_fake_man do bundle "-h #{exec}" end - expect(out).to include(%(["#{root}/lib/bundler/man/bundle-exec"])) + expect(out).to include(%(["#{root}/man/bundle-exec.1"])) end it "shows bundle-exec's man page when --help is after exec" do with_fake_man do bundle "#{exec} --help" end - expect(out).to include(%(["#{root}/lib/bundler/man/bundle-exec"])) + expect(out).to include(%(["#{root}/man/bundle-exec.1"])) end it "shows bundle-exec's man page when -h is after exec" do with_fake_man do bundle "#{exec} -h" end - expect(out).to include(%(["#{root}/lib/bundler/man/bundle-exec"])) + expect(out).to include(%(["#{root}/man/bundle-exec.1"])) end end end @@ -513,6 +514,21 @@ describe "bundle exec" do end end + context "the executable is empty" do + let(:executable) { "" } + + let(:exit_code) { 0 } + let(:expected) { "#{path} is empty" } + let(:expected_err) { "" } + if LessThanProc.with(RUBY_VERSION).call("1.9") + # Kernel#exec in ruby < 1.9 will raise Errno::ENOEXEC if the command content is empty, + # even if the command is set as an executable. + pending "Kernel#exec is different" + else + it_behaves_like "it runs" + end + end + context "the executable raises" do let(:executable) { super() << "\nraise 'ERROR'" } let(:exit_code) { 1 } @@ -539,7 +555,7 @@ describe "bundle exec" do let(:exit_code) { Bundler::GemNotFound.new.status_code } let(:expected) { <<-EOS.strip } -\e[31mCould not find gem 'rack (= 2)' in any of the gem sources listed in your Gemfile or available on this machine.\e[0m +\e[31mCould not find gem 'rack (= 2)' in any of the gem sources listed in your Gemfile.\e[0m \e[33mRun `bundle install` to install missing gems.\e[0m EOS @@ -627,4 +643,68 @@ __FILE__: #{path.to_s.inspect} end end end + + context "nested bundle exec" do + let(:system_gems_to_install) { super() << :bundler } + + context "with shared gems disabled" do + before do + gemfile <<-G + source "file://#{gem_repo1}" + gem "rack" + G + bundle :install, :system_bundler => true, :path => "vendor/bundler" + end + + it "overrides disable_shared_gems so bundler can be found" do + file = bundled_app("file_that_bundle_execs.rb") + create_file(file, <<-RB) + #!#{Gem.ruby} + puts `bundle exec echo foo` + RB + file.chmod(0o777) + bundle! "exec #{file}", :system_bundler => true + expect(out).to eq("foo") + end + end + + context "with a system gem that shadows a default gem" do + let(:openssl_version) { "2.0.3" } + let(:expected) { ruby "gem 'openssl', '< 999999'; require 'openssl'; puts OpenSSL::VERSION", :artifice => nil } + + it "only leaves the default gem in the stdlib available" do + skip "openssl isn't a default gem" if expected.empty? + + install_gemfile! "" # must happen before installing the broken system gem + + build_repo4 do + build_gem "openssl", openssl_version do |s| + s.write("lib/openssl.rb", <<-RB) + raise "custom openssl should not be loaded, it's not in the gemfile!" + RB + end + end + + system_gems(:bundler, "openssl-#{openssl_version}", :gem_repo => gem_repo4) + + file = bundled_app("require_openssl.rb") + create_file(file, <<-RB) + #!/usr/bin/env ruby + require "openssl" + puts OpenSSL::VERSION + RB + file.chmod(0o777) + + aggregate_failures do + expect(bundle!("exec #{file}", :system_bundler => true, :artifice => nil)).to eq(expected) + expect(bundle!("exec bundle exec #{file}", :system_bundler => true, :artifice => nil)).to eq(expected) + expect(bundle!("exec ruby #{file}", :system_bundler => true, :artifice => nil)).to eq(expected) + end + + # sanity check that we get the newer, custom version without bundler + sys_exec(file.to_s) + expect(err).to include("custom openssl should not be loaded") + end + end + end end diff --git a/spec/commands/help_spec.rb b/spec/commands/help_spec.rb index d59346f615..790d26fda4 100644 --- a/spec/commands/help_spec.rb +++ b/spec/commands/help_spec.rb @@ -1,10 +1,9 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle help" do +RSpec.describe "bundle help" do # Rubygems 1.4+ no longer load gem plugins so this test is no longer needed - rubygems_under_14 = Gem::Requirement.new("< 1.4").satisfied_by?(Gem::Version.new(Gem::VERSION)) - it "complains if older versions of bundler are installed", :if => rubygems_under_14 do + it "complains if older versions of bundler are installed", :rubygems => "< 1.4" do system_gems "bundler-0.8.1" bundle "help" @@ -16,14 +15,14 @@ describe "bundle help" do with_fake_man do bundle "help gemfile" end - expect(out).to eq(%(["#{root}/lib/bundler/man/gemfile.5"])) + expect(out).to eq(%(["#{root}/man/gemfile.5"])) end it "prefixes bundle commands with bundle- when finding the groff files" do with_fake_man do bundle "help install" end - expect(out).to eq(%(["#{root}/lib/bundler/man/bundle-install"])) + expect(out).to eq(%(["#{root}/man/bundle-install.1"])) end it "simply outputs the txt file when there is no man on the path" do @@ -34,8 +33,8 @@ describe "bundle help" do end it "still outputs the old help for commands that do not have man pages yet" do - bundle "help check" - expect(out).to include("Check searches the local machine") + bundle "help version" + expect(out).to include("Prints the bundler's version information") end it "looks for a binary and executes it with --help option if it's named bundler-<task>" do @@ -55,28 +54,28 @@ describe "bundle help" do with_fake_man do bundle "install --help" end - expect(out).to eq(%(["#{root}/lib/bundler/man/bundle-install"])) + expect(out).to eq(%(["#{root}/man/bundle-install.1"])) end it "is called when the --help flag is used before the command" do with_fake_man do bundle "--help install" end - expect(out).to eq(%(["#{root}/lib/bundler/man/bundle-install"])) + expect(out).to eq(%(["#{root}/man/bundle-install.1"])) end it "is called when the -h flag is used before the command" do with_fake_man do bundle "-h install" end - expect(out).to eq(%(["#{root}/lib/bundler/man/bundle-install"])) + expect(out).to eq(%(["#{root}/man/bundle-install.1"])) end it "is called when the -h flag is used after the command" do with_fake_man do bundle "install -h" end - expect(out).to eq(%(["#{root}/lib/bundler/man/bundle-install"])) + expect(out).to eq(%(["#{root}/man/bundle-install.1"])) end it "has helpful output when using --help flag for a non-existent command" do @@ -90,11 +89,11 @@ describe "bundle help" do with_fake_man do bundle "--help" end - expect(out).to eq(%(["#{root}/lib/bundler/man/bundle"])) + expect(out).to eq(%(["#{root}/man/bundle.1"])) with_fake_man do bundle "-h" end - expect(out).to eq(%(["#{root}/lib/bundler/man/bundle"])) + expect(out).to eq(%(["#{root}/man/bundle.1"])) end end diff --git a/spec/commands/info_spec.rb b/spec/commands/info_spec.rb new file mode 100644 index 0000000000..b37de765e4 --- /dev/null +++ b/spec/commands/info_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true +require "spec_helper" + +RSpec.describe "bundle info" do + context "info from specific gem in gemfile" do + before do + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "rails" + G + end + + it "prints information about the current gem" do + bundle "info rails" + expect(out).to include "* rails (2.3.2) +\tSummary: This is just a fake gem for testing +\tHomepage: http://example.com" + expect(out).to match(%r{Path\: .*\/rails\-2\.3\.2}) + end + + context "given a gem that is not installed" do + it "prints missing gem error" do + bundle "info foo" + expect(out).to eq "Could not find gem 'foo'." + end + end + + context "given a default gem shippped in ruby" do + it "prints information about the default gem", :if => (RUBY_VERSION >= "2.0") do + bundle "info rdoc" + expect(out).to include("* rdoc") + expect(out).to include("Default Gem: yes") + end + end + + context "when gem does not have homepage" do + before do + build_repo1 do + build_gem "rails", "2.3.2" do |s| + s.executables = "rails" + s.summary = "Just another test gem" + end + end + end + + it "excludes the homepage field from the output" do + expect(out).to_not include("Homepage:") + end + end + + context "given --path option" do + it "prints the path to the gem" do + bundle "info rails" + expect(out).to match(%r{.*\/rails\-2\.3\.2}) + end + end + end +end diff --git a/spec/commands/init_spec.rb b/spec/commands/init_spec.rb index 70d1143055..03a46a8bfa 100644 --- a/spec/commands/init_spec.rb +++ b/spec/commands/init_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle init" do +RSpec.describe "bundle init" do it "generates a Gemfile" do bundle :init expect(bundled_app("Gemfile")).to exist diff --git a/spec/commands/inject_spec.rb b/spec/commands/inject_spec.rb index d0112915ca..dd5e22498b 100644 --- a/spec/commands/inject_spec.rb +++ b/spec/commands/inject_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle inject" do +RSpec.describe "bundle inject" do before :each do gemfile <<-G source "file://#{gem_repo1}" @@ -42,6 +42,16 @@ describe "bundle inject" do end end + context "incorrect arguments" do + it "fails when more than 2 arguments are passed" do + bundle "inject gem_name 1 v" + expect(out).to eq(<<-E.strip) +ERROR: "bundle inject" was called with arguments ["gem_name", "1", "v"] +Usage: "bundle inject GEM VERSION" + E + end + end + context "when frozen" do before do bundle "install" diff --git a/spec/commands/install_spec.rb b/spec/commands/install_spec.rb index eb78ced86e..49eee01910 100644 --- a/spec/commands/install_spec.rb +++ b/spec/commands/install_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install with gem sources" do +RSpec.describe "bundle install with gem sources" do describe "the simple case" do it "prints output and returns if no dependencies are specified" do gemfile <<-G @@ -216,7 +216,7 @@ describe "bundle install with gem sources" do G run "require 'platform_specific' ; puts PLATFORM_SPECIFIC" - expect(out).to eq("1.0.0 #{Gem::Platform.local}") + expect(out).to eq("1.0.0 #{Bundler.local_platform}") end it "falls back on plain ruby" do @@ -314,14 +314,14 @@ describe "bundle install with gem sources" do end it "gracefully handles error when rubygems server is unavailable" do - install_gemfile <<-G + install_gemfile <<-G, :artifice => nil source "file://#{gem_repo1}" source "http://localhost:9384" gem 'foo' G - bundle :install + bundle :install, :artifice => nil expect(out).to include("Could not fetch specs from http://localhost:9384/") expect(out).not_to include("file://") end diff --git a/spec/commands/licenses_spec.rb b/spec/commands/licenses_spec.rb index dd9f261eb3..0ee1a46945 100644 --- a/spec/commands/licenses_spec.rb +++ b/spec/commands/licenses_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle licenses" do +RSpec.describe "bundle licenses" do before :each do install_gemfile <<-G source "file://#{gem_repo1}" diff --git a/spec/commands/lock_spec.rb b/spec/commands/lock_spec.rb index fc605dc5a6..52c281a6ae 100644 --- a/spec/commands/lock_spec.rb +++ b/spec/commands/lock_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle lock" do +RSpec.describe "bundle lock" do def strip_lockfile(lockfile) strip_whitespace(lockfile).sub(/\n\Z/, "") end @@ -10,9 +10,11 @@ describe "bundle lock" do strip_lockfile bundled_app(file).read end + let(:repo) { gem_repo1 } + before :each do gemfile <<-G - source "file://#{gem_repo1}" + source "file://#{repo}" gem "rails" gem "with_license" gem "foo" @@ -20,7 +22,7 @@ describe "bundle lock" do @lockfile = strip_lockfile <<-L GEM - remote: file:#{gem_repo1}/ + remote: file:#{repo}/ specs: actionmailer (2.3.2) activesupport (= 2.3.2) @@ -77,7 +79,7 @@ describe "bundle lock" do it "writes a lockfile when there is an outdated lockfile using --update" do lockfile @lockfile.gsub("2.3.2", "2.3.1") - bundle "lock --update" + bundle! "lock --update" expect(read_lockfile).to eq(@lockfile) end @@ -85,7 +87,7 @@ describe "bundle lock" do it "does not fetch remote specs when using the --local option" do bundle "lock --update --local" - expect(out).to include("available on this machine.") + expect(out).to include("sources listed in your Gemfile") end it "writes to a custom location using --lockfile" do @@ -104,6 +106,54 @@ describe "bundle lock" do expect(read_lockfile).to eq(@lockfile) end + # see update_spec for more coverage on same options. logic is shared so it's not necessary + # to repeat coverage here. + context "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.0.1 1.1.0 2.0.0) + end + + # establish a lockfile set to 1.4.3 + install_gemfile <<-G + source "file://#{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://#{gem_repo4}" + gem 'foo' + gem 'qux' + G + end + + it "single gem updates dependent gem to minor" do + bundle "lock --update foo --patch" + + expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w(foo-1.4.5 bar-2.1.1 qux-1.0.0).sort) + end + + it "minor preferred with strict" do + bundle "lock --update --minor --strict" + + 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 + end + it "supports adding new platforms" do bundle! "lock --add-platform java x86-mingw32" @@ -111,6 +161,12 @@ describe "bundle lock" do expect(lockfile.platforms).to eq([java, local, mingw]) end + it "supports adding the `ruby` platform" do + bundle! "lock --add-platform ruby" + lockfile = Bundler::LockfileParser.new(read_lockfile) + expect(lockfile.platforms).to eq([local, "ruby"].uniq) + end + it "warns when adding an unknown platform" do bundle "lock --add-platform foobarbaz" expect(out).to include("The platform `foobarbaz` is unknown to RubyGems and adding it will likely lead to resolution errors") @@ -223,4 +279,28 @@ describe "bundle lock" do #{Bundler::VERSION} G end + + context "when an update is available" do + let(:repo) { gem_repo2 } + + before do + lockfile(@lockfile) + build_repo2 do + build_gem "foo", "2.0" + end + end + + it "does not implicitly update" do + bundle! "lock" + + expect(read_lockfile).to eq(@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)")) + end + end end diff --git a/spec/commands/newgem_spec.rb b/spec/commands/newgem_spec.rb index 6e80aa7a60..6ce19124f5 100644 --- a/spec/commands/newgem_spec.rb +++ b/spec/commands/newgem_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle gem" do +RSpec.describe "bundle gem" do def reset! super global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false" @@ -17,7 +17,7 @@ describe "bundle gem" do end def execute_bundle_gem(gem_name, flag = "", to_remove_push_guard = true) - bundle "gem #{gem_name} #{flag}" + bundle! "gem #{gem_name} #{flag}" remove_push_guard(gem_name) if to_remove_push_guard # reset gemspec cache for each test because of commit 3d4163a Bundler.clear_gemspec_cache @@ -25,6 +25,7 @@ describe "bundle gem" do def gem_skeleton_assertions(gem_name) expect(bundled_app("#{gem_name}/#{gem_name}.gemspec")).to exist + expect(bundled_app("#{gem_name}/README.md")).to exist expect(bundled_app("#{gem_name}/Gemfile")).to exist expect(bundled_app("#{gem_name}/Rakefile")).to exist expect(bundled_app("#{gem_name}/lib/test/gem.rb")).to exist @@ -36,6 +37,8 @@ describe "bundle gem" do [user] name = "Bundler User" email = user@example.com + [github] + user = bundleuser EOF @git_config_location = ENV["GIT_CONFIG"] path = "#{File.expand_path("../../tmp", File.dirname(__FILE__))}/test_git_config.txt" @@ -100,6 +103,13 @@ describe "bundle gem" do gem_skeleton_assertions(gem_name) expect(bundled_app("test-gem/CODE_OF_CONDUCT.md")).to exist end + + describe "README additions" do + it "generates the README with a section for the Code of Conduct" do + expect(bundled_app("test-gem/README.md").read).to include("## Code of Conduct") + expect(bundled_app("test-gem/README.md").read).to include("https://github.com/bundleuser/#{gem_name}/blob/master/CODE_OF_CONDUCT.md") + end + end end shared_examples_for "--no-coc flag" do @@ -110,25 +120,33 @@ describe "bundle gem" do gem_skeleton_assertions(gem_name) expect(bundled_app("test-gem/CODE_OF_CONDUCT.md")).to_not exist end + + describe "README additions" do + it "generates the README without a section for the Code of Conduct" do + expect(bundled_app("test-gem/README.md").read).not_to include("## Code of Conduct") + expect(bundled_app("test-gem/README.md").read).not_to include("https://github.com/bundleuser/#{gem_name}/blob/master/CODE_OF_CONDUCT.md") + end + end end context "README.md" do let(:gem_name) { "test_gem" } let(:generated_gem) { Bundler::GemHelper.new(bundled_app(gem_name).to_s) } - context "git config user.name present" do + context "git config github.user present" do before do execute_bundle_gem(gem_name) end it "contribute URL set to git username" do expect(bundled_app("test_gem/README.md").read).not_to include("[USERNAME]") + expect(bundled_app("test_gem/README.md").read).to include("github.com/bundleuser") end end - context "git config user.name is absent" do + context "git config github.user is absent" do before do - `git config --unset user.name` + sys_exec("git config --unset github.user") reset! in_app_root bundle "gem #{gem_name}" @@ -137,10 +155,42 @@ describe "bundle gem" do it "contribute URL set to [USERNAME]" do expect(bundled_app("test_gem/README.md").read).to include("[USERNAME]") + expect(bundled_app("test_gem/README.md").read).not_to include("github.com/bundleuser") end end end + it "creates a new git repository" do + in_app_root + bundle "gem test_gem" + expect(bundled_app("test_gem/.git")).to exist + end + + context "when git is not avaiable" do + let(:gem_name) { "test_gem" } + + # This spec cannot have `git` avaiable in the test env + before do + bundle_bin = File.expand_path("../../../exe/bundle", __FILE__) + load_paths = [lib, spec] + load_path_str = "-I#{load_paths.join(File::PATH_SEPARATOR)}" + + sys_exec "PATH=\"\" #{Gem.ruby} #{load_path_str} #{bundle_bin} gem #{gem_name}" + end + + it "creates the gem without the need for git" do + expect(bundled_app("#{gem_name}/README.md")).to exist + end + + it "doesn't create a git repo" do + expect(bundled_app("#{gem_name}/.git")).to_not exist + end + + it "doesn't create a .gitignore file" do + expect(bundled_app("#{gem_name}/.gitignore")).to_not exist + end + end + it "generates a valid gemspec" do system_gems ["rake-10.0.2"] @@ -407,11 +457,11 @@ describe "bundle gem" do end it "requires 'test-gem'" do - expect(bundled_app("test_gem/test/test_helper.rb").read).to include("require 'test_gem'") + expect(bundled_app("test_gem/test/test_helper.rb").read).to include(%(require "test_gem")) end it "requires 'minitest_helper'" do - expect(bundled_app("test_gem/test/test_gem_test.rb").read).to include("require 'test_helper'") + expect(bundled_app("test_gem/test/test_gem_test.rb").read).to include(%(require "test_helper")) end it "creates a default test which fails" do @@ -435,7 +485,7 @@ describe "bundle gem" do Rake::TestTask.new(:test) do |t| t.libs << "test" t.libs << "lib" - t.test_files = FileList['test/**/*_test.rb'] + t.test_files = FileList["test/**/*_test.rb"] end task :default => :test @@ -648,11 +698,11 @@ describe "bundle gem" do end it "requires 'test/gem'" do - expect(bundled_app("test-gem/test/test_helper.rb").read).to match(%r{require 'test/gem'}) + expect(bundled_app("test-gem/test/test_helper.rb").read).to match(%r{require "test/gem"}) end it "requires 'test_helper'" do - expect(bundled_app("test-gem/test/test/gem_test.rb").read).to match(/require 'test_helper'/) + expect(bundled_app("test-gem/test/test/gem_test.rb").read).to match(/require "test_helper"/) end it "creates a default test which fails" do @@ -667,7 +717,7 @@ describe "bundle gem" do Rake::TestTask.new(:test) do |t| t.libs << "test" t.libs << "lib" - t.test_files = FileList['test/**/*_test.rb'] + t.test_files = FileList["test/**/*_test.rb"] end task :default => :test @@ -733,6 +783,29 @@ describe "bundle gem" do expect(bundled_app("a--a/a--a.gemspec")).to exist end + + it "fails gracefully with a ." do + bundle "gem foo.gemspec" + expect(out).to end_with("Invalid gem name foo.gemspec -- `Foo.gemspec` is an invalid constant name") + end + + it "fails gracefully with a ^" do + bundle "gem ^" + expect(out).to end_with("Invalid gem name ^ -- `^` is an invalid constant name") + end + + it "fails gracefully with a space" do + bundle "gem 'foo bar'" + expect(out).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" + expect(out).to eq(<<-E.strip) +ERROR: "bundle gem" was called with arguments ["foo", "bar", "baz"] +Usage: "bundle gem GEM [OPTIONS]" + E + end end describe "#ensure_safe_gem_name" do @@ -812,4 +885,26 @@ describe "bundle gem" do expect(bundled_app("foobar/CODE_OF_CONDUCT.md")).to exist end end + + context "on conflicts with a previously created file" do + it "should fail gracefully" do + in_app_root do + FileUtils.touch("conflict-foobar") + end + output = bundle "gem conflict-foobar" + expect(output).to include("Errno::EEXIST") + expect(exitstatus).to eql(32) if exitstatus + end + end + + context "on conflicts with a previously created directory" do + it "should fail gracefully" do + in_app_root do + FileUtils.mkdir_p("conflict-foobar/Gemfile") + end + output = bundle "gem conflict-foobar" + expect(output).to include("Errno::EISDIR") + expect(exitstatus).to eql(32) if exitstatus + end + end end diff --git a/spec/commands/open_spec.rb b/spec/commands/open_spec.rb index 5507398382..6872e859d2 100644 --- a/spec/commands/open_spec.rb +++ b/spec/commands/open_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle open" do +RSpec.describe "bundle open" do before :each do install_gemfile <<-G source "file://#{gem_repo1}" @@ -67,6 +67,13 @@ describe "bundle open" do expect(out).to match(/bundler_editor #{default_bundle_path('gems', 'activerecord-2.3.2')}\z/) end + it "allows selecting exit from many match gems" do + env = { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" } + bundle! "open active", :env => env do |input, _, _| + input.puts "0" + end + end + it "performs an automatic bundle install" do gemfile <<-G source "file://#{gem_repo1}" diff --git a/spec/commands/outdated_spec.rb b/spec/commands/outdated_spec.rb index 6420c28ac7..b927a0be2b 100644 --- a/spec/commands/outdated_spec.rb +++ b/spec/commands/outdated_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle outdated" do +RSpec.describe "bundle outdated" do before :each do build_repo2 do build_git "foo", :path => lib_path("foo") @@ -72,7 +72,136 @@ describe "bundle outdated" do end end + describe "with --group option" do + def test_group_option(group = nil, gems_list_size = 1) + install_gemfile <<-G + source "file://#{gem_repo2}" + + gem "weakling", "~> 0.0.1" + gem "terranova", '8' + group :development, :test do + gem "duradura", '7.0' + gem 'activesupport', '2.3.5' + end + G + + update_repo2 do + build_gem "activesupport", "3.0" + build_gem "terranova", "9" + build_gem "duradura", "8.0" + end + + bundle "outdated --group #{group}" + + # Gem names are one per-line, between "*" and their parenthesized version. + gem_list = out.split("\n").map {|g| g[/\* (.*) \(/, 1] }.compact + expect(gem_list).to eq(gem_list.sort) + expect(gem_list.size).to eq gems_list_size + end + + it "not outdated gems" do + install_gemfile <<-G + source "file://#{gem_repo2}" + + gem "weakling", "~> 0.0.1" + gem "terranova", '8' + group :development, :test do + gem 'activesupport', '2.3.5' + gem "duradura", '7.0' + end + G + + bundle "outdated --group" + expect(out).to include("Bundle up to date!") + end + + it "returns a sorted list of outdated gems from one group => 'default'" do + test_group_option("default") + + expect(out).to include("===== Group default =====") + expect(out).to include("terranova (") + + expect(out).not_to include("===== Group development, test =====") + expect(out).not_to include("activesupport") + expect(out).not_to include("duradura") + end + + it "returns a sorted list of outdated gems from one group => 'development'" do + test_group_option("development", 2) + + expect(out).not_to include("===== Group default =====") + expect(out).not_to include("terranova (") + + expect(out).to include("===== Group development, test =====") + expect(out).to include("activesupport") + expect(out).to include("duradura") + end + end + + describe "with --groups option" do + it "not outdated gems" do + install_gemfile <<-G + source "file://#{gem_repo2}" + + gem "weakling", "~> 0.0.1" + gem "terranova", '8' + group :development, :test do + gem 'activesupport', '2.3.5' + gem "duradura", '7.0' + end + G + + bundle "outdated --groups" + expect(out).to include("Bundle up to date!") + end + + it "returns a sorted list of outdated gems by groups" do + install_gemfile <<-G + source "file://#{gem_repo2}" + + gem "weakling", "~> 0.0.1" + gem "terranova", '8' + group :development, :test do + gem 'activesupport', '2.3.5' + gem "duradura", '7.0' + end + G + + update_repo2 do + build_gem "activesupport", "3.0" + build_gem "terranova", "9" + build_gem "duradura", "8.0" + end + + bundle "outdated --groups" + expect(out).to include("===== Group default =====") + expect(out).to include("terranova (newest 9, installed 8, requested = 8)") + expect(out).to include("===== Group development, test =====") + expect(out).to include("activesupport (newest 3.0, installed 2.3.5, requested = 2.3.5)") + expect(out).to include("duradura (newest 8.0, installed 7.0, requested = 7.0)") + + expect(out).not_to include("weakling (") + + # TODO: check gems order inside the group + end + end + describe "with --local option" do + it "uses local cache to return a list of outdated gems" do + update_repo2 do + build_gem "activesupport", "2.3.4" + end + + install_gemfile <<-G + source "file://#{gem_repo2}" + gem "activesupport", "2.3.4" + G + + bundle "outdated --local" + + expect(out).to include("activesupport (newest 2.3.5, installed 2.3.4, requested = 2.3.4)") + end + it "doesn't hit repo2" do FileUtils.rm_rf(gem_repo2) @@ -195,6 +324,62 @@ describe "bundle outdated" do expect(out).to_not include("rack (1.2") end + + describe "and filter options" do + it "only reports gems that match requirement and patch filter level" do + install_gemfile <<-G + source "file://#{gem_repo2}" + gem "activesupport", "~> 2.3" + gem "weakling", ">= 0.0.1" + G + + update_repo2 do + build_gem "activesupport", %w(2.4.0 3.0.0) + build_gem "weakling", "0.0.5" + end + + bundle "outdated --strict --filter-patch" + + expect(out).to_not include("activesupport (newest") + expect(out).to include("(newest 0.0.5, installed 0.0.3") + end + + it "only reports gems that match requirement and minor filter level" do + install_gemfile <<-G + source "file://#{gem_repo2}" + gem "activesupport", "~> 2.3" + gem "weakling", ">= 0.0.1" + G + + update_repo2 do + build_gem "activesupport", %w(2.3.9) + build_gem "weakling", "0.1.5" + end + + bundle "outdated --strict --filter-minor" + + expect(out).to_not include("activesupport (newest") + expect(out).to include("(newest 0.1.5, installed 0.0.3") + end + + it "only reports gems that match requirement and major filter level" do + install_gemfile <<-G + source "file://#{gem_repo2}" + gem "activesupport", "~> 2.3" + gem "weakling", ">= 0.0.1" + G + + update_repo2 do + build_gem "activesupport", %w(2.4.0 2.5.0) + build_gem "weakling", "1.1.5" + end + + bundle "outdated --strict --filter-major" + + expect(out).to_not include("activesupport (newest") + expect(out).to include("(newest 1.1.5, installed 0.0.3") + end + end end describe "with invalid gem name" do @@ -257,6 +442,33 @@ describe "bundle outdated" do end end + context "update available for a gem on the same platform while multiple platforms used for gem" do + it "reports that updates are available if the Ruby platform is used" do + install_gemfile <<-G + source "file://#{gem_repo2}" + gem "laduradura", '= 5.15.2', :platforms => [:ruby, :jruby] + G + + bundle "outdated" + expect(out).to include("Bundle up to date!") + end + + it "reports that updates are available if the JRuby platform is used" do + simulate_ruby_engine "jruby", "1.6.7" do + simulate_platform "jruby" do + install_gemfile <<-G + source "file://#{gem_repo2}" + gem "laduradura", '= 5.15.2', :platforms => [:ruby, :jruby] + G + + bundle "outdated" + expect(out).to include("Outdated gems included in the bundle:") + expect(out).to include("laduradura (newest 5.15.3, installed 5.15.2, requested = 5.15.2)") + end + end + end + end + shared_examples_for "version update is detected" do it "reports that a gem has a newer version" do subject @@ -302,7 +514,7 @@ describe "bundle outdated" do shared_examples_for "no version updates are detected" do it "does not detect any version updates" do subject - expect(out).to include("Bundle up to date!") + expect(out).to include("updates to display.") expect(out).to_not include("ERROR REPORT TEMPLATE") expect(out).to_not include("activesupport (newest") expect(out).to_not include("weakling (newest") @@ -342,59 +554,163 @@ describe "bundle outdated" do it_behaves_like "no version updates are detected" end - describe "with --major option" do - subject { bundle "outdated --major" } + describe "with --filter-major option" do + subject { bundle "outdated --filter-major" } it_behaves_like "major version updates are detected" it_behaves_like "minor version is ignored" it_behaves_like "patch version is ignored" end - describe "with --minor option" do - subject { bundle "outdated --minor" } + describe "with --filter-minor option" do + subject { bundle "outdated --filter-minor" } it_behaves_like "minor version updates are detected" it_behaves_like "major version is ignored" it_behaves_like "patch version is ignored" end - describe "with --patch option" do - subject { bundle "outdated --patch" } + describe "with --filter-patch option" do + subject { bundle "outdated --filter-patch" } it_behaves_like "patch version updates are detected" it_behaves_like "major version is ignored" it_behaves_like "minor version is ignored" end - describe "with --minor --patch options" do - subject { bundle "outdated --minor --patch" } + describe "with --filter-minor --filter-patch options" do + subject { bundle "outdated --filter-minor --filter-patch" } it_behaves_like "minor version updates are detected" it_behaves_like "patch version updates are detected" it_behaves_like "major version is ignored" end - describe "with --major --minor options" do - subject { bundle "outdated --major --minor" } + describe "with --filter-major --filter-minor options" do + subject { bundle "outdated --filter-major --filter-minor" } it_behaves_like "major version updates are detected" it_behaves_like "minor version updates are detected" it_behaves_like "patch version is ignored" end - describe "with --major --patch options" do - subject { bundle "outdated --major --patch" } + describe "with --filter-major --filter-patch options" do + subject { bundle "outdated --filter-major --filter-patch" } it_behaves_like "major version updates are detected" it_behaves_like "patch version updates are detected" it_behaves_like "minor version is ignored" end - describe "with --major --minor --patch options" do - subject { bundle "outdated --major --minor --patch" } + describe "with --filter-major --filter-minor --filter-patch options" do + subject { bundle "outdated --filter-major --filter-minor --filter-patch" } it_behaves_like "major version updates are detected" it_behaves_like "minor version updates are detected" it_behaves_like "patch version updates are detected" 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 + + # establish a lockfile set to 1.0.0 + install_gemfile <<-G + source "file://#{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://#{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" + + expect(out).to include("No minor updates to display.") + expect(out).not_to include("patch (newest") + expect(out).not_to include("minor (newest") + expect(out).not_to include("major (newest") + end + + it "shows all gems when patching and filtering to patch" do + bundle "outdated --patch --filter-patch" + + expect(out).to include("patch (newest 1.0.1") + expect(out).to include("minor (newest 1.0.1") + expect(out).to include("major (newest 1.0.1") + end + + it "shows minor and major when updating to minor and filtering to patch and minor" do + bundle "outdated --minor --filter-minor" + + expect(out).not_to include("patch (newest") + expect(out).to include("minor (newest 1.1.0") + expect(out).to include("major (newest 1.1.0") + end + + it "shows minor when updating to major and filtering to minor with parseable" do + bundle "outdated --major --filter-minor --parseable" + + 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) + end + + # establish a lockfile set to 1.4.3 + install_gemfile <<-G + source "file://#{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://#{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" + + expect(out).to include("foo (newest 1.4.4") + expect(out).to include("bar (newest 2.0.5") + expect(out).not_to include("qux (newest") + end + end + end end diff --git a/spec/commands/package_spec.rb b/spec/commands/package_spec.rb index a72b94a0b9..86c09db3ca 100644 --- a/spec/commands/package_spec.rb +++ b/spec/commands/package_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle package" do +RSpec.describe "bundle package" do context "with --gemfile" do it "finds the gemfile" do gemfile bundled_app("NotGemfile"), <<-G @@ -222,7 +222,7 @@ describe "bundle package" do end end -describe "bundle install with gem sources" do +RSpec.describe "bundle install with gem sources" do describe "when cached and locked" do it "does not hit the remote at all" do build_repo2 diff --git a/spec/commands/show_spec.rb b/spec/commands/show_spec.rb index 84352c5427..45af035959 100644 --- a/spec/commands/show_spec.rb +++ b/spec/commands/show_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle show" do +RSpec.describe "bundle show" do context "with a standard Gemfile" do before :each do install_gemfile <<-G @@ -161,4 +161,31 @@ describe "bundle show" do expect(out).to include("Could not find gem '#{invalid_regexp}'.") end end + + context "--outdated option" do + # Regression test for https://github.com/bundler/bundler/issues/5375 + before do + build_repo2 + end + + it "doesn't update gems to newer versions" do + install_gemfile! <<-G + source "file://#{gem_repo2}" + gem "rails" + G + + expect(the_bundle).to include_gem("rails 2.3.2") + + update_repo2 do + build_gem "rails", "3.0.0" do |s| + s.executables = "rails" + end + end + + bundle! "show --outdated" + + bundle! "install" + expect(the_bundle).to include_gem("rails 2.3.2") + end + end end diff --git a/spec/commands/update_spec.rb b/spec/commands/update_spec.rb index 8a9867d1e9..4992e428da 100644 --- a/spec/commands/update_spec.rb +++ b/spec/commands/update_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle update" do +RSpec.describe "bundle update" do before :each do build_repo2 @@ -159,8 +159,16 @@ describe "bundle update" do bundle "update" expect(out).to match(/You are trying to install in deployment mode after changing.your Gemfile/m) + expect(out).to match(/freeze \nby running `bundle install --no-deployment`./m) expect(exitstatus).not_to eq(0) if exitstatus end + + it "should suggest different command when frozen is set globally" do + bundler "config --global frozen 1" + bundle "update" + expect(out).to match(/You are trying to install in deployment mode after changing.your Gemfile/m) + expect(out).to match(/freeze \nby running `bundle config --delete frozen`./m) + end end describe "with --source option" do @@ -254,7 +262,7 @@ describe "bundle update" do end end -describe "bundle update in more complicated situations" do +RSpec.describe "bundle update in more complicated situations" do before :each do build_repo2 end @@ -295,7 +303,7 @@ describe "bundle update in more complicated situations" do end end -describe "bundle update without a Gemfile.lock" do +RSpec.describe "bundle update without a Gemfile.lock" do it "should not explode" do build_repo2 @@ -311,7 +319,7 @@ describe "bundle update without a Gemfile.lock" do end end -describe "bundle update when a gem depends on a newer version of bundler" do +RSpec.describe "bundle update when a gem depends on a newer version of bundler" do before(:each) do build_repo2 do build_gem "rails", "3.0.1" do |s| @@ -338,7 +346,7 @@ describe "bundle update when a gem depends on a newer version of bundler" do end end -describe "bundle update" do +RSpec.describe "bundle update" do it "shows the previous version of the gem when updated from rubygems source" do build_repo2 @@ -370,7 +378,7 @@ describe "bundle update" do end end -describe "bundle update --ruby" do +RSpec.describe "bundle update --ruby" do before do install_gemfile <<-G ::RUBY_VERSION = '2.1.3' @@ -480,92 +488,170 @@ describe "bundle update --ruby" do end # these specs are slow and focus on integration and therefore are not exhaustive. unit specs elsewhere handle that. -describe "bundle update conservative" 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" +RSpec.describe "bundle update conservative" do + context "patch and minor options" 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.0.1 1.1.0 2.0.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.0.1 1.1.0 2.0.0) + + # establish a lockfile set to 1.4.3 + install_gemfile <<-G + source "file://#{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://#{gem_repo4}" + gem 'foo' + gem 'qux' + G end - # establish a lockfile set to 1.4.3 - install_gemfile <<-G - source "file://#{gem_repo4}" - gem 'foo', '1.4.3' - gem 'bar', '2.0.3' - gem 'qux', '1.0.0' - G + context "patch preferred" do + it "single gem updates dependent gem to minor" do + bundle "update --patch foo" - # remove 1.4.3 requirement and bar altogether - # to setup update specs below - gemfile <<-G - source "file://#{gem_repo4}" - gem 'foo' - gem 'qux' - G - end + expect(the_bundle).to include_gems "foo 1.4.5", "bar 2.1.1", "qux 1.0.0" + end - context "patch preferred" do - it "single gem updates dependent gem to minor" do - bundle "update --patch foo" + it "update all" do + bundle "update --patch" - expect(the_bundle).to include_gems "foo 1.4.5", "bar 2.1.1", "qux 1.0.0" + expect(the_bundle).to include_gems "foo 1.4.5", "bar 2.1.1", "qux 1.0.1" + end end - it "update all" do - bundle "update --patch" + context "minor preferred" do + it "single gem updates dependent gem to major" do + bundle "update --minor foo" - expect(the_bundle).to include_gems "foo 1.4.5", "bar 2.1.1", "qux 1.0.1" + expect(the_bundle).to include_gems "foo 1.5.1", "bar 3.0.0", "qux 1.0.0" + end end - it "warns on minor or major increment elsewhere" ## include in prior test + context "strict" do + it "patch preferred" do + bundle "update --patch foo bar --strict" + + expect(the_bundle).to include_gems "foo 1.4.4", "bar 2.0.5", "qux 1.0.0" + end + + it "minor preferred" do + bundle "update --minor --strict" + + expect(the_bundle).to include_gems "foo 1.5.0", "bar 2.1.1", "qux 1.1.0" + end + end end - context "minor preferred" do - it "single gem updates dependent gem to major" do - bundle "update --minor foo" + context "eager unlocking" do + before do + build_repo4 do + build_gem "isolated_owner", %w(1.0.1 1.0.2) do |s| + s.add_dependency "isolated_dep", "~> 2.0" + end + build_gem "isolated_dep", %w(2.0.1 2.0.2) + + build_gem "shared_owner_a", %w(3.0.1 3.0.2) do |s| + s.add_dependency "shared_dep", "~> 5.0" + end + build_gem "shared_owner_b", %w(4.0.1 4.0.2) do |s| + s.add_dependency "shared_dep", "~> 5.0" + end + build_gem "shared_dep", %w(5.0.1 5.0.2) + end + + gemfile <<-G + source "file://#{gem_repo4}" + gem 'isolated_owner' - expect(the_bundle).to include_gems "foo 1.5.1", "bar 3.0.0", "qux 1.0.0" + gem 'shared_owner_a' + gem 'shared_owner_b' + G + + lockfile <<-L + GEM + remote: file://#{gem_repo4} + specs: + isolated_dep (2.0.1) + isolated_owner (1.0.1) + isolated_dep (~> 2.0) + shared_dep (5.0.1) + shared_owner_a (3.0.1) + shared_dep (~> 5.0) + shared_owner_b (4.0.1) + shared_dep (~> 5.0) + + PLATFORMS + ruby + + DEPENDENCIES + shared_owner_a + shared_owner_b + isolated_owner + + BUNDLED WITH + 1.13.0 + L end - it "warns on major increment elsewhere" ## include in prior test + it "should eagerly unlock isolated dependency" do + bundle "update isolated_owner" - it "warns when something unlocked doesn't update at all" - end + expect(the_bundle).to include_gems "isolated_owner 1.0.2", "isolated_dep 2.0.2", "shared_dep 5.0.1", "shared_owner_a 3.0.1", "shared_owner_b 4.0.1" + end + + it "should eagerly unlock shared dependency" do + bundle "update shared_owner_a" + + expect(the_bundle).to include_gems "isolated_owner 1.0.1", "isolated_dep 2.0.1", "shared_dep 5.0.2", "shared_owner_a 3.0.2", "shared_owner_b 4.0.1" + end - context "strict" do - it "patch preferred" do - bundle "update --patch foo bar --strict" + it "should not eagerly unlock with --conservative" do + bundle "update --conservative shared_owner_a isolated_owner" - expect(the_bundle).to include_gems "foo 1.4.4", "bar 2.0.5", "qux 1.0.0" + expect(the_bundle).to include_gems "isolated_owner 1.0.2", "isolated_dep 2.0.2", "shared_dep 5.0.1", "shared_owner_a 3.0.2", "shared_owner_b 4.0.1" end - it "minor preferred" do - bundle "update --minor --strict" + it "should match bundle install conservative update behavior when not eagerly unlocking" do + gemfile <<-G + source "file://#{gem_repo4}" + gem 'isolated_owner', '1.0.2' + + gem 'shared_owner_a', '3.0.2' + gem 'shared_owner_b' + G + + bundle "install" - expect(the_bundle).to include_gems "foo 1.5.0", "bar 2.1.1", "qux 1.1.0" + expect(the_bundle).to include_gems "isolated_owner 1.0.2", "isolated_dep 2.0.2", "shared_dep 5.0.1", "shared_owner_a 3.0.2", "shared_owner_b 4.0.1" end end context "error handling" do + before do + gemfile "" + end + it "raises if too many flags are provided" do bundle "update --patch --minor" expect(out).to eq "Provide only one of the following options: minor, patch" end end - - context "other commands" do - it "Installer could support --dry-run flag for install and update" - - it "outdated should conform its flags to the resolver flags" - end end diff --git a/spec/commands/viz_spec.rb b/spec/commands/viz_spec.rb index f3fab9272c..123e7bef62 100644 --- a/spec/commands/viz_spec.rb +++ b/spec/commands/viz_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle viz", :ruby => "1.9.3", :if => Bundler.which("dot") do +RSpec.describe "bundle viz", :ruby => "1.9.3", :if => Bundler.which("dot") do let(:graphviz_lib) do graphviz_glob = base_system_gems.join("gems/ruby-graphviz*/lib") Dir[graphviz_glob].first diff --git a/spec/install/allow_offline_install_spec.rb b/spec/install/allow_offline_install_spec.rb index 44100ca97b..1bca055c9f 100644 --- a/spec/install/allow_offline_install_spec.rb +++ b/spec/install/allow_offline_install_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install with :allow_offline_install" do +RSpec.describe "bundle install with :allow_offline_install" do before do bundle "config allow_offline_install true" end diff --git a/spec/install/binstubs_spec.rb b/spec/install/binstubs_spec.rb index a7e0b847cc..a1a9ab167d 100644 --- a/spec/install/binstubs_spec.rb +++ b/spec/install/binstubs_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install" do +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 diff --git a/spec/install/bundler_spec.rb b/spec/install/bundler_spec.rb index 9f06a48086..c1ce57e60e 100644 --- a/spec/install/bundler_spec.rb +++ b/spec/install/bundler_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install" do +RSpec.describe "bundle install" do describe "with bundler dependencies" do before(:each) do build_repo2 do @@ -44,17 +44,14 @@ describe "bundle install" do In Gemfile: bundler (= 0.9.2) - rails (= 3.0) was resolved to 3.0, which depends on - bundler (>= 0.9.0.pre) - Current Bundler version: bundler (#{Bundler::VERSION}) This Gemfile requires a different version of Bundler. Perhaps you need to update Bundler by running `gem install bundler`? - Could not find gem 'bundler (= 0.9.2)', which is required by gem 'rails (= 3.0)', in any of the sources. + Could not find gem 'bundler (= 0.9.2)' in any of the sources E - expect(out).to include(nice_error) + expect(out).to eq(nice_error) end it "works for gems with multiple versions in its dependencies" do diff --git a/spec/install/deploy_spec.rb b/spec/install/deploy_spec.rb index c73cff5e80..4a4f6e912f 100644 --- a/spec/install/deploy_spec.rb +++ b/spec/install/deploy_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "install with --deployment or --frozen" do +RSpec.describe "install with --deployment or --frozen" do before do gemfile <<-G source "file://#{gem_repo1}" @@ -22,15 +22,15 @@ describe "install with --deployment or --frozen" do it "disallows --deployment --system" do bundle "install --deployment --system" expect(out).to include("You have specified both --deployment") - expect(out).to include("Please choose.") + expect(out).to include("Please choose only one option") expect(exitstatus).to eq(15) if exitstatus end it "disallows --deployment --path --system" do bundle "install --deployment --path . --system" - expect(out).to include("You have specified both a path to install your gems to") - expect(out).to include("You have specified both --deployment") - expect(out).to include("Please choose.") + expect(out).to include("You have specified both --path") + expect(out).to include("as well as --system") + expect(out).to include("Please choose only one option") expect(exitstatus).to eq(15) if exitstatus end @@ -77,10 +77,8 @@ describe "install with --deployment or --frozen" do gem "bar", :path => "#{lib_path("nested")}" G - bundle :install - bundle "install --deployment" - - expect(exitstatus).to eq(0) if exitstatus + bundle! :install + bundle! "install --deployment" end it "works when there are credentials in the source URL" do @@ -267,22 +265,21 @@ describe "install with --deployment or --frozen" do 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") - install_gemfile <<-G - gem "foo", :path => "#{lib_path("foo")}" + install_gemfile! <<-G + gem "foo", :path => "#{lib_path("foo")}" G - bundle :install + bundle! :install expect(the_bundle).to include_gems "foo 1.0" - bundle "package --all" + bundle! "package --all" expect(bundled_app("vendor/cache/foo")).to be_directory - bundle "install --local" + bundle! "install --local" expect(out).to include("Using foo 1.0 from source at") expect(out).to include("vendor/cache/foo") - expect(exitstatus).to eq(0) if exitstatus simulate_new_machine - bundle "install --deployment" + bundle! "install --deployment --verbose" expect(out).not_to include("You are trying to install in deployment mode after changing your Gemfile") expect(out).not_to include("You have added to the Gemfile") expect(out).not_to include("You have deleted from the Gemfile") diff --git a/spec/install/failure_spec.rb b/spec/install/failure_spec.rb new file mode 100644 index 0000000000..738b2cf1bd --- /dev/null +++ b/spec/install/failure_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true +require "spec_helper" + +RSpec.describe "bundle install" do + context "installing a gem fails" do + it "prints out why that gem was being installed" do + build_repo2 do + build_gem "activesupport", "2.3.2" do |s| + s.extensions << "Rakefile" + s.write "Rakefile", <<-RUBY + task :default do + abort "make installing activesupport-2.3.2 fail" + end + RUBY + end + end + + install_gemfile <<-G + source "file:#{gem_repo2}" + gem "rails" + G + expect(out).to end_with(<<-M.strip) +An error occurred while installing activesupport (2.3.2), and Bundler cannot continue. +Make sure that `gem install activesupport -v '2.3.2'` succeeds before bundling. + +In Gemfile: + rails was resolved to 2.3.2, which depends on + actionmailer was resolved to 2.3.2, which depends on + activesupport + M + end + end +end diff --git a/spec/install/force_spec.rb b/spec/install/force_spec.rb index 2027660cba..6d852b3bf1 100644 --- a/spec/install/force_spec.rb +++ b/spec/install/force_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install" do +RSpec.describe "bundle install" do describe "with --force" do before :each do gemfile <<-G diff --git a/spec/install/gemfile/eval_gemfile_spec.rb b/spec/install/gemfile/eval_gemfile_spec.rb index 2660ac98c2..4f5a109e32 100644 --- a/spec/install/gemfile/eval_gemfile_spec.rb +++ b/spec/install/gemfile/eval_gemfile_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install with gemfile that uses eval_gemfile" do +RSpec.describe "bundle install with gemfile that uses eval_gemfile" do before do build_lib("gunks", :path => bundled_app.join("gems/gunks")) do |s| s.name = "gunks" @@ -26,6 +26,24 @@ describe "bundle install with gemfile that uses eval_gemfile" do end end + context "eval-ed Gemfile has relative-path gems" do + before do + build_lib("a", :path => "gems/a") + create_file "nested/Gemfile-nested", <<-G + gem "a", :path => "../gems/a" + G + + gemfile <<-G + eval_gemfile "nested/Gemfile-nested" + G + end + + it "installs the path gem" do + bundle! :install + expect(the_bundle).to include_gem("a 1.0") + end + end + context "Gemfile uses gemspec paths after eval-ing a Gemfile" do before { create_file "other/Gemfile-other" } diff --git a/spec/install/gemfile/gemspec_spec.rb b/spec/install/gemfile/gemspec_spec.rb index 9a6bd5f1e8..e2534be1ad 100644 --- a/spec/install/gemfile/gemspec_spec.rb +++ b/spec/install/gemfile/gemspec_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install from an existing gemspec" do +RSpec.describe "bundle install from an existing gemspec" do before(:each) do build_gem "bar", :to_system => true build_gem "bar-dev", :to_system => true @@ -131,6 +131,55 @@ describe "bundle install from an existing gemspec" do end end + it "should match a lockfile without needing to re-resolve" do + build_lib("foo", :path => tmp.join("foo")) do |s| + s.add_dependency "rack" + end + + install_gemfile! <<-G + source "file://#{gem_repo1}" + gemspec :path => '#{tmp.join("foo")}' + G + + bundle! "install", :verbose => true + expect(out).to include("Found no changes, using resolution from the lockfile") + end + + 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| + s.add_dependency "rack" + s.add_development_dependency "thin" + end + + install_gemfile! <<-G + source "file://#{gem_repo1}" + gemspec :path => '#{tmp.join("foo")}' + G + + bundle! "install", :verbose => true + expect(out).to include("Found no changes, using resolution from the lockfile") + end + + it "should match a lockfile on non-ruby platforms with a transitive platform dependency" do + simulate_platform java + simulate_ruby_engine "jruby" + + build_lib("foo", :path => tmp.join("foo")) do |s| + s.add_dependency "platform_specific" + end + + install_gem "platform_specific-1.0-java" + + install_gemfile! <<-G + gemspec :path => '#{tmp.join("foo")}' + G + + bundle! "update --bundler", :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")) File.open(tmp.join("foo/foo.gemspec"), "w") do |s| @@ -143,6 +192,26 @@ describe "bundle install from an existing gemspec" do expect(@err).not_to match(/ahh/) end + it "allows the gemspec to activate other gems" do + # see https://github.com/bundler/bundler/issues/5409 + # + # issue was caused by rubygems having an unresolved gem during a require, + # so emulate that + system_gems %w(rack-1.0.0 rack-0.9.1 rack-obama-1.0) + + 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' }" + end + + install_gemfile! <<-G + gemspec + G + + expect(the_bundle).to include_gem "foo 1.0" + end + it "allows conflicts" do build_lib("foo", :path => tmp.join("foo")) do |s| s.version = "1.0.0" @@ -162,6 +231,31 @@ describe "bundle install from an existing gemspec" do expect(the_bundle).to include_gems "foo 1.0.0" end + 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| + s.add_dependency "activesupport", ">= 1" + end + + install_gemfile! <<-G + source "file://#{gem_repo1}" + gemspec + G + + expect(the_bundle).to include_gems("cocoapods 1.0", "activesupport 2.3.5") + + build_lib "cocoapods", :path => bundled_app do |s| + s.add_dependency "activesupport", ">= 1.0.1" + end + + bundle "install --deployment" + + expect(out).to include("changed") + end + end + end + 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 @@ -409,4 +503,37 @@ describe "bundle install from an existing gemspec" do end end end + + context "with multiple platforms" do + before do + 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 + end + end + + it "installs the ruby platform gemspec" do + simulate_platform "ruby" + + install_gemfile! <<-G + source "file://#{gem_repo1}" + gemspec :path => '#{tmp.join("foo")}', :name => 'foo' + G + + expect(the_bundle).to include_gems "foo 1.0.0", "rack 1.0.0" + end + + it "installs the ruby platform gemspec and skips dev deps with --without development" do + simulate_platform "ruby" + + install_gemfile! <<-G, :without => "development" + source "file://#{gem_repo1}" + gemspec :path => '#{tmp.join("foo")}', :name => 'foo' + G + + expect(the_bundle).to include_gem "foo 1.0.0" + expect(the_bundle).not_to include_gem "rack" + end + end end diff --git a/spec/install/gemfile/git_spec.rb b/spec/install/gemfile/git_spec.rb index f70ea5b43a..d2d46279aa 100644 --- a/spec/install/gemfile/git_spec.rb +++ b/spec/install/gemfile/git_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install with git sources" do +RSpec.describe "bundle install with git sources" do describe "when floating on master" do before :each do build_git "foo" do |s| @@ -209,6 +209,94 @@ describe "bundle install with git sources" do end end + describe "when specifying a branch" do + let(:branch) { "branch" } + let(:repo) { build_git("foo").path } + before(:each) do + update_git("foo", :path => repo, :branch => branch) + end + + it "works" do + install_gemfile <<-G + git "#{repo}", :branch => #{branch.dump} do + gem "foo" + end + G + + expect(the_bundle).to include_gems("foo 1.0") + end + + context "when the branch starts with a `#`" do + let(:branch) { "#149/redirect-url-fragment" } + it "works" do + install_gemfile <<-G + git "#{repo}", :branch => #{branch.dump} do + gem "foo" + end + G + + expect(the_bundle).to include_gems("foo 1.0") + end + end + + context "when the branch includes quotes" do + let(:branch) { %('") } + it "works" do + install_gemfile <<-G + git "#{repo}", :branch => #{branch.dump} do + gem "foo" + end + G + + expect(the_bundle).to include_gems("foo 1.0") + end + end + end + + describe "when specifying a tag" do + let(:tag) { "tag" } + let(:repo) { build_git("foo").path } + before(:each) do + update_git("foo", :path => repo, :tag => tag) + end + + it "works" do + install_gemfile <<-G + git "#{repo}", :tag => #{tag.dump} do + gem "foo" + end + G + + expect(the_bundle).to include_gems("foo 1.0") + end + + context "when the tag starts with a `#`" do + let(:tag) { "#149/redirect-url-fragment" } + it "works" do + install_gemfile <<-G + git "#{repo}", :tag => #{tag.dump} do + gem "foo" + end + G + + expect(the_bundle).to include_gems("foo 1.0") + end + end + + context "when the tag includes quotes" do + let(:tag) { %('") } + it "works" do + install_gemfile <<-G + git "#{repo}", :tag => #{tag.dump} do + gem "foo" + end + G + + expect(the_bundle).to include_gems("foo 1.0") + end + end + end + 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 @@ -997,7 +1085,12 @@ describe "bundle install with git sources" do gem "foo", :git => "#{lib_path("foo-1.0")}" G - expect(out).to include("An error occurred while installing foo (1.0)") + expect(out).to end_with(<<-M.strip) +An error occurred while installing foo (1.0), and Bundler cannot continue. + +In Gemfile: + foo + M expect(out).not_to include("gem install foo") end @@ -1022,20 +1115,20 @@ describe "bundle install with git sources" do gem "foo", :git => "#{lib_path("foo-1.0")}" G - run <<-R + run! <<-R require 'foo' puts FOO R installed_time = out - expect(installed_time).to match(/\d+\.\d+/) + expect(installed_time).to match(/\A\d+\.\d+\z/) install_gemfile <<-G source "file://#{gem_repo1}" gem "foo", :git => "#{lib_path("foo-1.0")}" G - run <<-R + run! <<-R require 'foo' puts FOO R diff --git a/spec/install/gemfile/groups_spec.rb b/spec/install/gemfile/groups_spec.rb index cb052b6c7a..a3a5eeefdf 100644 --- a/spec/install/gemfile/groups_spec.rb +++ b/spec/install/gemfile/groups_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install with groups" do +RSpec.describe "bundle install with groups" do describe "installing with no options" do before :each do install_gemfile <<-G diff --git a/spec/install/gemfile/path_spec.rb b/spec/install/gemfile/path_spec.rb index 0a73335225..a1c41aebbb 100644 --- a/spec/install/gemfile/path_spec.rb +++ b/spec/install/gemfile/path_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install with explicit source paths" do +RSpec.describe "bundle install with explicit source paths" do it "fetches gems" do build_lib "foo" diff --git a/spec/install/gemfile/platform_spec.rb b/spec/install/gemfile/platform_spec.rb index 58129bb313..c6eaec7ca6 100644 --- a/spec/install/gemfile/platform_spec.rb +++ b/spec/install/gemfile/platform_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install across platforms" do +RSpec.describe "bundle install across platforms" do it "maintains the same lockfile if all gems are compatible across platforms" do lockfile <<-G GEM @@ -88,6 +88,32 @@ describe "bundle install across platforms" do expect(the_bundle).to include_gems "nokogiri 1.4.2 JAVA", "weakling 0.0.3" end + it "works with gems that have extra platform-specific runtime dependencies" do + simulate_platform x64_mac + + update_repo2 do + build_gem "facter", "2.4.6" + build_gem "facter", "2.4.6" do |s| + s.platform = "universal-darwin" + s.add_runtime_dependency "CFPropertyList" + end + build_gem "CFPropertyList" + end + + install_gemfile! <<-G + source "file://#{gem_repo2}" + + gem "facter" + G + + expect(out).to include "Unable to use the platform-specific (universal-darwin) version of facter (2.4.6) " \ + "because it has different dependencies from the ruby version. " \ + "To use the platform-specific version of the gem, run `bundle config specific_platform true` and install again." + + expect(the_bundle).to include_gem "facter 2.4.6" + expect(the_bundle).not_to include_gem "CFPropertyList" + end + it "fetches gems again after changing the version of Ruby" do gemfile <<-G source "file://#{gem_repo1}" @@ -105,7 +131,7 @@ describe "bundle install across platforms" do end end -describe "bundle install with platform conditionals" do +RSpec.describe "bundle install with platform conditionals" do it "installs gems tagged w/ the current platforms" do install_gemfile <<-G source "file://#{gem_repo1}" @@ -184,7 +210,7 @@ describe "bundle install with platform conditionals" do gemfile <<-G source "file://#{gem_repo1}" - gem "some_gem", platform: :rbx + gem "some_gem", :platform => :rbx G bundle "install --local" @@ -204,9 +230,26 @@ describe "bundle install with platform conditionals" do bundle "install --local" expect(out).not_to match(/Could not find gem 'some_gem/) end + + it "prints a helpful warning when a dependency is unused on any platform" do + simulate_platform "ruby" + simulate_ruby_engine "ruby" + + gemfile <<-G + source "file://#{gem_repo1}" + + gem "rack", :platform => [:mingw, :mswin, :x64_mingw, :jruby] + G + + bundle! "install" + + expect(out).to include <<-O.strip +The dependency #{Gem::Dependency.new("rack", ">= 0")} will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`. + O + end end -describe "when a gem has no architecture" do +RSpec.describe "when a gem has no architecture" do it "still installs correctly" do simulate_platform mswin @@ -216,7 +259,7 @@ describe "when a gem has no architecture" do gem "rcov" G - bundle :install, :fakeweb => "windows" + bundle :install, :artifice => "windows" expect(the_bundle).to include_gems "rcov 1.0.0" end end diff --git a/spec/install/gemfile/ruby_spec.rb b/spec/install/gemfile/ruby_spec.rb index 1adbf10833..b9d9683758 100644 --- a/spec/install/gemfile/ruby_spec.rb +++ b/spec/install/gemfile/ruby_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "ruby requirement" do +RSpec.describe "ruby requirement" do def locked_ruby_version Bundler::RubyVersion.from_string(Bundler::LockfileParser.new(lockfile).ruby_version) end @@ -86,4 +86,24 @@ describe "ruby requirement" do expect(the_bundle).to include_gems "rack 1.0.0" expect(locked_ruby_version.versions).to eq(["5100"]) end + + it "allows requirements with trailing whitespace" do + install_gemfile! <<-G + source "file://#{gem_repo1}" + ruby "#{RUBY_VERSION}\\n \t\\n" + gem "rack" + G + + expect(the_bundle).to include_gems "rack 1.0.0" + end + + it "fails gracefully with malformed requirements" do + install_gemfile <<-G + source "file://#{gem_repo1}" + ruby ">= 0", "-.\\0" + gem "rack" + G + + expect(out).to include("There was an error parsing") # i.e. DSL error, not error template + end end diff --git a/spec/install/gemfile/sources_spec.rb b/spec/install/gemfile/sources_spec.rb index fd11c3feab..c5375b4abf 100644 --- a/spec/install/gemfile/sources_spec.rb +++ b/spec/install/gemfile/sources_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install with gems on multiple sources" do +RSpec.describe "bundle install with gems on multiple sources" do # repo1 is built automatically before all of the specs run # it contains rack-obama 1.0.0 and rack 0.9.1 & 1.0.0 amongst other gems @@ -449,4 +449,70 @@ describe "bundle install with gems on multiple sources" do end end end + + context "when a gem is installed to system gems" do + before do + install_gemfile! <<-G + source "file://#{gem_repo1}" + gem "rack" + G + end + + context "and the gemfile changes" do + it "is still able to find that gem from remote sources" do + source_uri = "file://#{gem_repo1}" + second_uri = "file://#{gem_repo4}" + + build_repo4 do + build_gem "rack", "2.0.1.1.forked" + build_gem "thor", "0.19.1.1.forked" + end + + # When this gemfile is installed... + gemfile <<-G + source "#{source_uri}" + + source "#{second_uri}" do + gem "rack", "2.0.1.1.forked" + gem "thor" + end + gem "rack-obama" + G + + # It creates this lockfile. + lockfile <<-L + GEM + remote: #{source_uri}/ + remote: #{second_uri}/ + specs: + rack (2.0.1.1.forked) + rack-obama (1.0) + rack + thor (0.19.1.1.forked) + + PLATFORMS + ruby + + DEPENDENCIES + rack (= 2.0.1.1.forked)! + rack-obama + thor! + L + + # Then we change the Gemfile by adding a version to thor + gemfile <<-G + source "#{source_uri}" + + source "#{second_uri}" do + gem "rack", "2.0.1.1.forked" + gem "thor", "0.19.1.1.forked" + end + gem "rack-obama" + G + + # But we should still be able to find rack 2.0.1.1.forked and install it + bundle! :install + end + end + end end diff --git a/spec/install/gemfile/specific_platform_spec.rb b/spec/install/gemfile/specific_platform_spec.rb index 3e12f94c86..cc6c82c0ff 100644 --- a/spec/install/gemfile/specific_platform_spec.rb +++ b/spec/install/gemfile/specific_platform_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install with specific_platform enabled" do +RSpec.describe "bundle install with specific_platform enabled" do before do bundle "config specific_platform true" @@ -39,6 +39,13 @@ describe "bundle install with specific_platform enabled" do build_gem("google-protobuf", "3.0.0.alpha.2.0") build_gem("google-protobuf", "3.0.0.alpha.1.1") build_gem("google-protobuf", "3.0.0.alpha.1.0") + + build_gem("facter", "2.4.6") + build_gem("facter", "2.4.6") do |s| + s.platform = "universal-darwin" + s.add_runtime_dependency "CFPropertyList" + end + build_gem("CFPropertyList") end end @@ -67,6 +74,19 @@ describe "bundle install with specific_platform enabled" do to all(exist) end + it "uses the platform-specific gem with extra dependencies" do + install_gemfile! <<-G + source "file:#{gem_repo2}" + gem "facter" + G + + expect(the_bundle.locked_gems.platforms).to eq([pl("ruby"), 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", + "facter-2.4.6-universal-darwin"]) + end + context "when adding a platform via lock --add_platform" do it "adds the foreign platform" do install_gemfile!(google_protobuf) diff --git a/spec/install/gemfile_spec.rb b/spec/install/gemfile_spec.rb index 98abc30c86..bc49053081 100644 --- a/spec/install/gemfile_spec.rb +++ b/spec/install/gemfile_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install" do +RSpec.describe "bundle install" do context "with duplicated gems" do it "will display a warning" do install_gemfile <<-G @@ -66,4 +66,33 @@ describe "bundle install" do expect(out).to match(/You passed :lib as an option for gem 'rack', but it is invalid/) end end + + context "with engine specified in symbol" do + it "does not raise any error parsing Gemfile" do + simulate_ruby_version "2.3.0" do + simulate_ruby_engine "jruby", "9.1.2.0" do + install_gemfile! <<-G + source "file://#{gem_repo1}" + ruby "2.3.0", :engine => :jruby, :engine_version => "9.1.2.0" + G + + expect(out).to match(/Bundle complete!/) + end + end + end + + it "installation succeeds" do + simulate_ruby_version "2.3.0" do + simulate_ruby_engine "jruby", "9.1.2.0" do + install_gemfile! <<-G + source "file://#{gem_repo1}" + ruby "2.3.0", :engine => :jruby, :engine_version => "9.1.2.0" + gem "rack" + G + + expect(the_bundle).to include_gems "rack 1.0.0" + end + end + end + end end diff --git a/spec/install/gems/compact_index_spec.rb b/spec/install/gems/compact_index_spec.rb index a800a6ad7b..3ba858ed08 100644 --- a/spec/install/gems/compact_index_spec.rb +++ b/spec/install/gems/compact_index_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "compact index api" do +RSpec.describe "compact index api" do let(:source_hostname) { "localgemserver.test" } let(:source_uri) { "http://#{source_hostname}" } @@ -144,7 +144,7 @@ describe "compact index api" do gem "rcov" G - bundle! :install, :fakeweb => "windows" + bundle! :install, :artifice => "windows" expect(out).to include("Fetching source index from #{source_uri}") expect(the_bundle).to include_gems "rcov 1.0.0" end @@ -696,18 +696,36 @@ The checksum of /versions does not match the checksum provided by the server! So expect(the_bundle).to include_gems "rack 1.0.0" end + it "fails gracefully when the source URI has an invalid scheme" do + install_gemfile <<-G + source "htps://rubygems.org" + gem "rack" + G + expect(exitstatus).to eq(15) if exitstatus + expect(out).to end_with(<<-E.strip) + The request uri `htps://index.rubygems.org/versions` has an invalid scheme (`htps`). Did you mean `http` or `https`? + E + end + describe "checksum validation", :rubygems => ">= 2.3.0" do it "raises when the checksum does not match" do install_gemfile <<-G, :artifice => "compact_index_wrong_gem_checksum" source "#{source_uri}" gem "rack" G + expect(exitstatus).to eq(19) if exitstatus expect(out). - to include("The checksum for the downloaded `rack-1.0.0.gem` did not match the checksum given by the API."). - and include("This means that the contents of the gem appear to be different from what was uploaded, and could be an indicator of a security issue."). - and match(/\(The expected SHA256 checksum was "#{"ab" * 22}", but the checksum for the downloaded gem was ".+?"\.\)/). - and include("Bundler cannot continue installing rack (1.0.0).") + 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: `#{system_gem_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 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 ".+?"\.\)/) end it "raises when the checksum is the wrong length" do @@ -727,4 +745,28 @@ The checksum of /versions does not match the checksum provided by the server! So G end end + + it "works when cache dir is world-writable" do + install_gemfile! <<-G, :artifice => "compact_index" + File.umask(0000) + source "#{source_uri}" + gem "rack" + G + end + + it "doesn't explode when the API dependencies are wrong" do + install_gemfile <<-G, :artifice => "compact_index_wrong_dependencies", :env => { "DEBUG" => "true" } + source "#{source_uri}" + gem "rails" + G + deps = [Gem::Dependency.new("rake", "= 10.0.2"), + 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 corrupted API dependencies") +Downloading rails-2.3.2 revealed dependencies not in the API (#{deps.join(", ")}). +Installing with `--full-index` should fix the problem. + E + end end diff --git a/spec/install/gems/dependency_api_spec.rb b/spec/install/gems/dependency_api_spec.rb index a7c1aedea3..d2de0d358b 100644 --- a/spec/install/gems/dependency_api_spec.rb +++ b/spec/install/gems/dependency_api_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "gemcutter's dependency API" do +RSpec.describe "gemcutter's dependency API" do let(:source_hostname) { "localgemserver.test" } let(:source_uri) { "http://#{source_hostname}" } @@ -124,7 +124,7 @@ describe "gemcutter's dependency API" do gem "rcov" G - bundle :install, :fakeweb => "windows" + bundle :install, :artifice => "windows" expect(out).to include("Fetching source index from #{source_uri}") expect(the_bundle).to include_gems "rcov 1.0.0" end diff --git a/spec/install/gems/env_spec.rb b/spec/install/gems/env_spec.rb index d7d3a3230e..9b1d8e5424 100644 --- a/spec/install/gems/env_spec.rb +++ b/spec/install/gems/env_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install with ENV conditionals" do +RSpec.describe "bundle install with ENV conditionals" do describe "when just setting an ENV key as a string" do before :each do gemfile <<-G diff --git a/spec/install/gems/flex_spec.rb b/spec/install/gems/flex_spec.rb index 2f900893cd..2c2d3c16a1 100644 --- a/spec/install/gems/flex_spec.rb +++ b/spec/install/gems/flex_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle flex_install" do +RSpec.describe "bundle flex_install" do it "installs the gems as expected" do install_gemfile <<-G source "file://#{gem_repo1}" diff --git a/spec/install/gems/mirror_spec.rb b/spec/install/gems/mirror_spec.rb index e7b4317f05..798156fb12 100644 --- a/spec/install/gems/mirror_spec.rb +++ b/spec/install/gems/mirror_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install with a mirror configured" do +RSpec.describe "bundle install with a mirror configured" do describe "when the mirror does not match the gem source" do before :each do gemfile <<-G diff --git a/spec/install/gems/native_extensions_spec.rb b/spec/install/gems/native_extensions_spec.rb index 6134663fcc..7531768b5f 100644 --- a/spec/install/gems/native_extensions_spec.rb +++ b/spec/install/gems/native_extensions_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "installing a gem with native extensions" do +RSpec.describe "installing a gem with native extensions" do it "installs" do build_repo2 do build_gem "c_extension" do |s| @@ -47,4 +47,46 @@ describe "installing a gem with native extensions" do run "Bundler.require; puts CExtension.new.its_true" expect(out).to eq("true") end + + it "installs from git" do + build_git "c_extension" do |s| + s.extensions = ["ext/extconf.rb"] + s.write "ext/extconf.rb", <<-E + require "mkmf" + name = "c_extension_bundle" + dir_config(name) + raise "OMG" unless with_config("c_extension") == "hello" + create_makefile(name) + E + + s.write "ext/c_extension.c", <<-C + #include "ruby.h" + + VALUE c_extension_true(VALUE self) { + return Qtrue; + } + + void Init_c_extension_bundle() { + VALUE c_Extension = rb_define_class("CExtension", rb_cObject); + rb_define_method(c_Extension, "its_true", c_extension_true, 0); + } + C + + s.write "lib/c_extension.rb", <<-C + require "c_extension_bundle" + C + end + + bundle! "config build.c_extension --with-c_extension=hello" + + install_gemfile! <<-G + gem "c_extension", :git => #{lib_path("c_extension-1.0").to_s.dump} + G + + expect(out).not_to include("extconf.rb failed") + expect(out).to include("Using c_extension 1.0") + + run! "Bundler.require; puts CExtension.new.its_true" + expect(out).to eq("true") + end end diff --git a/spec/install/gems/post_install_spec.rb b/spec/install/gems/post_install_spec.rb index 596fa6412f..c3ea3e7c51 100644 --- a/spec/install/gems/post_install_spec.rb +++ b/spec/install/gems/post_install_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install" do +RSpec.describe "bundle install" do context "with gem sources" do context "when gems include post install messages" do it "should display the post-install messages after installing" do diff --git a/spec/install/gems/resolving_spec.rb b/spec/install/gems/resolving_spec.rb index 0204a222f9..c227993448 100644 --- a/spec/install/gems/resolving_spec.rb +++ b/spec/install/gems/resolving_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install with install-time dependencies" do +RSpec.describe "bundle install with install-time dependencies" do it "installs gems with implicit rake dependencies" do install_gemfile <<-G source "file://#{gem_repo1}" diff --git a/spec/install/gems/standalone_spec.rb b/spec/install/gems/standalone_spec.rb index 7a6749dea9..496844ae14 100644 --- a/spec/install/gems/standalone_spec.rb +++ b/spec/install/gems/standalone_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -shared_examples "bundle install --standalone" do +RSpec.shared_examples "bundle install --standalone" do shared_examples "common functionality" do it "still makes the gems available to normal bundler" do args = expected_gems.map {|k, v| "#{k} #{v}" } @@ -298,16 +298,16 @@ 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", path.realpath) end end end -describe "bundle install --standalone" do +RSpec.describe "bundle install --standalone" do include_examples("bundle install --standalone") end -describe "bundle install --standalone run in a subdirectory" do +RSpec.describe "bundle install --standalone run in a subdirectory" do before do subdir = bundled_app("bob") FileUtils.mkdir_p(subdir) diff --git a/spec/install/gems/sudo_spec.rb b/spec/install/gems/sudo_spec.rb index 66b9901831..13abffc14e 100644 --- a/spec/install/gems/sudo_spec.rb +++ b/spec/install/gems/sudo_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "when using sudo", :sudo => true do +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 before do diff --git a/spec/install/gems/win32_spec.rb b/spec/install/gems/win32_spec.rb index 69ea035f5e..cdad9a8821 100644 --- a/spec/install/gems/win32_spec.rb +++ b/spec/install/gems/win32_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install with win32-generated lockfile" do +RSpec.describe "bundle install with win32-generated lockfile" do it "should read lockfile" do File.open(bundled_app("Gemfile.lock"), "wb") do |f| f << "GEM\r\n" diff --git a/spec/install/gemspecs_spec.rb b/spec/install/gemspecs_spec.rb index 8f719bf601..97eaf149c1 100644 --- a/spec/install/gemspecs_spec.rb +++ b/spec/install/gemspecs_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install" do +RSpec.describe "bundle install" do describe "when a gem has a YAML gemspec" do before :each do build_repo2 do diff --git a/spec/install/git_spec.rb b/spec/install/git_spec.rb index f35a543509..a555822012 100644 --- a/spec/install/git_spec.rb +++ b/spec/install/git_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install" do +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") diff --git a/spec/install/path_spec.rb b/spec/install/path_spec.rb index 03c42f008c..ad6071d29f 100644 --- a/spec/install/path_spec.rb +++ b/spec/install/path_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install" do +RSpec.describe "bundle install" do describe "with --path" do before :each do build_gem "rack", "1.0.0", :to_system => true do |s| @@ -38,7 +38,7 @@ describe "bundle install" do it "disallows --path vendor/bundle --system" do bundle "install --path vendor/bundle --system" - expect(out).to include("Please choose.") + expect(out).to include("Please choose only one option.") expect(exitstatus).to eq(15) if exitstatus end @@ -128,6 +128,34 @@ describe "bundle install" do expect(vendored_gems("gems/rack-1.0.0")).to be_directory expect(the_bundle).to include_gems "rack 1.0.0" end + + it "re-installs gems whose extensions have been deleted", :rubygems => ">= 2.3" do + build_lib "very_simple_binary", "1.0.0", :to_system => true do |s| + s.write "lib/very_simple_binary.rb", "raise 'FAIL'" + end + + gemfile <<-G + source "file://#{gem_repo1}" + gem "very_simple_binary" + G + + bundle "install --path ./vendor/bundle" + + 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" + + vendored_gems("extensions").rmtree + + run "require 'very_simple_binary_c'" + expect(err).to include("Bundler::GemNotFound") + + bundle "install --path ./vendor/bundle" + + 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" + end end describe "to a file" do diff --git a/spec/install/post_bundle_message_spec.rb b/spec/install/post_bundle_message_spec.rb index 10c71f0a51..4453e4190f 100644 --- a/spec/install/post_bundle_message_spec.rb +++ b/spec/install/post_bundle_message_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "post bundle message" do +RSpec.describe "post bundle message" do before :each do gemfile <<-G source "file://#{gem_repo1}" @@ -14,7 +14,7 @@ describe "post bundle message" do G end - let(:bundle_show_message) { "Use `bundle show [gemname]` to see where a bundled gem is installed." } + let(:bundle_show_message) { "Use `bundle info [gemname]` to see where a bundled gem is installed." } let(:bundle_deployment_message) { "Bundled gems are installed into ./vendor" } let(:bundle_complete_message) { "Bundle complete!" } let(:bundle_updated_message) { "Bundle updated!" } @@ -104,7 +104,22 @@ describe "post bundle message" do gem "rack" gem "not-a-gem", :group => :development G - expect(out).to include("Could not find gem 'not-a-gem' in any of the gem sources listed in your Gemfile or available on this machine.") + expect(out).to include("Could not find gem 'not-a-gem' in any of the gem sources listed in your Gemfile.") + end + + it "should report a helpful error message with reference to cache if available" do + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "rack" + G + bundle :cache + expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "rack" + gem "not-a-gem", :group => :development + G + expect(out).to include("Could not find gem 'not-a-gem' in any of the gem sources listed in your Gemfile or in gems cached in vendor/cache.") end end end diff --git a/spec/install/prereleases_spec.rb b/spec/install/prereleases_spec.rb index cbf99ca96f..6c32094d90 100644 --- a/spec/install/prereleases_spec.rb +++ b/spec/install/prereleases_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle install" do +RSpec.describe "bundle install" do describe "when prerelease gems are available" do it "finds prereleases" do install_gemfile <<-G diff --git a/spec/install/security_policy_spec.rb b/spec/install/security_policy_spec.rb index 7e2c320b80..ab531bdad6 100644 --- a/spec/install/security_policy_spec.rb +++ b/spec/install/security_policy_spec.rb @@ -5,7 +5,7 @@ require "rubygems/security" # unfortunately, testing signed gems with a provided CA is extremely difficult # as 'gem cert' is currently the only way to add CAs to the system. -describe "policies with unsigned gems" do +RSpec.describe "policies with unsigned gems" do before do build_security_repo gemfile <<-G @@ -44,7 +44,7 @@ describe "policies with unsigned gems" do end end -describe "policies with signed gems and no CA" do +RSpec.describe "policies with signed gems and no CA" do before do build_security_repo gemfile <<-G diff --git a/spec/install/yanked_spec.rb b/spec/install/yanked_spec.rb index ab96d4fcee..d42978ce4c 100644 --- a/spec/install/yanked_spec.rb +++ b/spec/install/yanked_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -context "when installing a bundle that includes yanked gems" do +RSpec.context "when installing a bundle that includes yanked gems" do before(:each) do build_repo4 do build_gem "foo", "9.0.0" @@ -41,3 +41,32 @@ context "when installing a bundle that includes yanked gems" do expect(out).to include("Could not find gem 'foo (= 10.0.0)' in any of the gem sources") end end + +RSpec.context "when using gem before installing" do + it "does not suggest the author has yanked the gem" do + gemfile <<-G + source "file://#{gem_repo1}" + gem "rack", "0.9.1" + G + + lockfile <<-L + GEM + remote: file://#{gem_repo1} + specs: + rack (0.9.1) + + PLATFORMS + ruby + + DEPENDENCIES + rack (= 0.9.1) + L + + bundle :list + + expect(out).to include("Could not find rack-0.9.1 in any of the sources") + expect(out).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(out).to_not include("If you haven't changed sources, that means the author of rack (0.9.1) has removed it.") + expect(out).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 +end diff --git a/spec/lock/git_spec.rb b/spec/lock/git_spec.rb index 93473db052..b36f61338d 100644 --- a/spec/lock/git_spec.rb +++ b/spec/lock/git_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle lock with git gems" do +RSpec.describe "bundle lock with git gems" do before :each do build_git "foo" diff --git a/spec/lock/lockfile_spec.rb b/spec/lock/lockfile_spec.rb index e6810b405f..7d768e337c 100644 --- a/spec/lock/lockfile_spec.rb +++ b/spec/lock/lockfile_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "the lockfile format" do +RSpec.describe "the lockfile format" do include Bundler::GemHelpers it "generates a simple lockfile for a single source, gem" do @@ -600,6 +600,36 @@ describe "the lockfile format" do G end + it "serializes pinned path sources to the lockfile even when packaging" do + build_lib "foo" + + install_gemfile! <<-G + gem "foo", :path => "#{lib_path("foo-1.0")}" + G + + bundle! "package --all" + bundle! "install --local" + + lockfile_should_be <<-G + PATH + remote: #{lib_path("foo-1.0")} + specs: + foo (1.0) + + GEM + specs: + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + foo! + + BUNDLED WITH + #{Bundler::VERSION} + G + end + it "sorts serialized sources by type" do build_lib "foo" bar = build_git "bar" diff --git a/spec/other/bundle_ruby_spec.rb b/spec/other/bundle_ruby_spec.rb index 4b2ebf4cfd..09fa2c223b 100644 --- a/spec/other/bundle_ruby_spec.rb +++ b/spec/other/bundle_ruby_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle_ruby" do +RSpec.describe "bundle_ruby" do context "without patchlevel" do it "returns the ruby version" do gemfile <<-G diff --git a/spec/other/cli_dispatch_spec.rb b/spec/other/cli_dispatch_spec.rb index 05dac51559..8b34a457ef 100644 --- a/spec/other/cli_dispatch_spec.rb +++ b/spec/other/cli_dispatch_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle command names" do +RSpec.describe "bundle command names" do it "work when given fully" do bundle "install" expect(err).to lack_errors diff --git a/spec/other/ext_spec.rb b/spec/other/ext_spec.rb index 7e2e712827..2d6ab941b8 100644 --- a/spec/other/ext_spec.rb +++ b/spec/other/ext_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "Gem::Specification#match_platform" do +RSpec.describe "Gem::Specification#match_platform" do it "does not match platforms other than the gem platform" do darwin = gem "lol", "1.0", "platform_specific-1.0-x86-darwin-10" expect(darwin.match_platform(pl("java"))).to eq(false) @@ -16,7 +16,7 @@ describe "Gem::Specification#match_platform" do end end -describe "Bundler::GemHelpers#generic" do +RSpec.describe "Bundler::GemHelpers#generic" do include Bundler::GemHelpers it "converts non-windows platforms into ruby" do @@ -47,9 +47,7 @@ describe "Bundler::GemHelpers#generic" do end end -describe "Gem::SourceIndex#refresh!" do - rubygems_1_7 = Gem::Version.new(Gem::VERSION) >= Gem::Version.new("1.7.0") - +RSpec.describe "Gem::SourceIndex#refresh!" do before do install_gemfile <<-G source "file://#{gem_repo1}" @@ -57,12 +55,12 @@ describe "Gem::SourceIndex#refresh!" do G end - it "does not explode when called", :if => rubygems_1_7 do + it "does not explode when called", :rubygems => "1.7" do run "Gem.source_index.refresh!" run "Gem::SourceIndex.new([]).refresh!" end - it "does not explode when called", :unless => rubygems_1_7 do + it "does not explode when called", :rubygems => "< 1.7" do run "Gem.source_index.refresh!" run "Gem::SourceIndex.from_gems_in([]).refresh!" end diff --git a/spec/other/major_deprecation_spec.rb b/spec/other/major_deprecation_spec.rb index 6505023d13..465d769538 100644 --- a/spec/other/major_deprecation_spec.rb +++ b/spec/other/major_deprecation_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "major deprecations" do +RSpec.describe "major deprecations" do let(:warnings) { out } # change to err in 2.0 context "in a .99 version" do @@ -97,7 +97,7 @@ describe "major deprecations" do G bundle :install, :binstubs => true - expect(warnings).to have_major_deprecation a_string_including("the --binstubs option will be removed") + expect(warnings).to have_major_deprecation a_string_including("The --binstubs option will be removed") end end end @@ -120,7 +120,7 @@ describe "major deprecations" do gem "rack" G - expect(warnings).to have_major_deprecation("gems.rb and gems.locked will be prefered to Gemfile and Gemfile.lock.") + expect(warnings).to have_major_deprecation("gems.rb and gems.locked will be preferred to Gemfile and Gemfile.lock.") end context "with flags" do @@ -154,7 +154,7 @@ describe "major deprecations" do Bundler.setup RUBY - expect(warnings).to have_major_deprecation("gems.rb and gems.locked will be prefered to Gemfile and Gemfile.lock.") + expect(warnings).to have_major_deprecation("gems.rb and gems.locked will be preferred to Gemfile and Gemfile.lock.") end end diff --git a/spec/other/platform_spec.rb b/spec/other/platform_spec.rb index 7aa0d0f8ea..6adbcef111 100644 --- a/spec/other/platform_spec.rb +++ b/spec/other/platform_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle platform" do +RSpec.describe "bundle platform" do context "without flags" do it "returns all the output" do gemfile <<-G diff --git a/spec/other/ssl_cert_spec.rb b/spec/other/ssl_cert_spec.rb index e1a134c919..2de4dfdd0c 100644 --- a/spec/other/ssl_cert_spec.rb +++ b/spec/other/ssl_cert_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" require "bundler/ssl_certs/certificate_manager" -describe "SSL Certificates", :rubygems_master do +RSpec.describe "SSL Certificates", :rubygems_master do hosts = %w( rubygems.org index.rubygems.org diff --git a/spec/other/trampoline_spec.rb b/spec/other/trampoline_spec.rb index 9a8e0a4a5d..39de7048c7 100644 --- a/spec/other/trampoline_spec.rb +++ b/spec/other/trampoline_spec.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true require "spec_helper" -describe "bundler version trampolining" do +RSpec.describe "bundler version trampolining" do before do - ENV["BUNDLE_DISABLE_POSTIT"] = nil - ENV["BUNDLE_ENABLE_TRAMPOLINE"] = "true" + ENV["BUNDLE_TRAMPOLINE_DISABLE"] = nil + ENV["BUNDLE_TRAMPOLINE_FORCE"] = "true" FileUtils.rm_rf(system_gem_path) FileUtils.cp_r(base_system_gems, system_gem_path) end @@ -59,8 +59,8 @@ describe "bundler version trampolining" do end end - context "without BUNDLE_ENABLE_TRAMPOLINE" do - before { ENV["BUNDLE_ENABLE_TRAMPOLINE"] = nil } + context "without BUNDLE_TRAMPOLINE_FORCE" do + before { ENV["BUNDLE_TRAMPOLINE_FORCE"] = nil } context "when the version is >= 2" do let(:version) { "2.7182818285" } diff --git a/spec/plugins/command_spec.rb b/spec/plugins/command_spec.rb index 71e87a5b01..6ad782b758 100644 --- a/spec/plugins/command_spec.rb +++ b/spec/plugins/command_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "command plugins" do +RSpec.describe "command plugins" do before do build_repo2 do build_plugin "command-mah" do |s| diff --git a/spec/plugins/hook_spec.rb b/spec/plugins/hook_spec.rb index bafe688d5e..9850d850ac 100644 --- a/spec/plugins/hook_spec.rb +++ b/spec/plugins/hook_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "hook plugins" do +RSpec.describe "hook plugins" do before do build_repo2 do build_plugin "before-install-plugin" do |s| diff --git a/spec/plugins/install_spec.rb b/spec/plugins/install_spec.rb index a24f318156..e2d351181c 100644 --- a/spec/plugins/install_spec.rb +++ b/spec/plugins/install_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundler plugin install" do +RSpec.describe "bundler plugin install" do before do build_repo2 do build_plugin "foo" @@ -70,6 +70,17 @@ describe "bundler plugin install" do context "malformatted plugin" do it "fails when plugins.rb is missing" do + update_repo2 do + build_plugin "foo", "1.1" + build_plugin "kung-foo", "1.1" + end + + bundle "plugin install foo kung-foo --version '1.0' --source file://#{gem_repo2}" + + expect(out).to include("Installing foo 1.0") + expect(out).to include("Installing kung-foo 1.0") + plugin_should_be_installed("foo", "kung-foo") + build_repo2 do build_gem "charlie" end @@ -80,6 +91,7 @@ describe "bundler plugin install" do expect(global_plugin_gem("charlie-1.0")).not_to be_directory + plugin_should_be_installed("foo", "kung-foo") plugin_should_not_be_installed("charlie") end diff --git a/spec/plugins/source/example_spec.rb b/spec/plugins/source/example_spec.rb index 520e1b9db4..2ae34caf73 100644 --- a/spec/plugins/source/example_spec.rb +++ b/spec/plugins/source/example_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "real source plugins" do +RSpec.describe "real source plugins" do context "with a minimal source plugin" do before do build_repo2 do diff --git a/spec/plugins/source_spec.rb b/spec/plugins/source_spec.rb index 92e948c190..0448bc409a 100644 --- a/spec/plugins/source_spec.rb +++ b/spec/plugins/source_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundler source plugin" do +RSpec.describe "bundler source plugin" do describe "plugins dsl eval for #source with :type option" do before do update_repo2 do diff --git a/spec/quality_spec.rb b/spec/quality_spec.rb index 5f73228b4a..c2a4ae536b 100644 --- a/spec/quality_spec.rb +++ b/spec/quality_spec.rb @@ -6,7 +6,7 @@ if defined?(Encoding) && Encoding.default_external.name != "UTF-8" Encoding.default_external = Encoding.find("UTF-8") end -describe "The library itself" do +RSpec.describe "The library itself" do def check_for_spec_defs_with_single_quotes(filename) failing_lines = [] @@ -191,6 +191,38 @@ describe "The library itself" do expect(error_messages.compact).to be_well_formed end + it "documents all used settings" do + exemptions = %w( + gem.coc + gem.mit + warned_version + ) + + all_settings = Hash.new {|h, k| h[k] = [] } + documented_settings = exemptions + + Bundler::Settings::BOOL_KEYS.each {|k| all_settings[k] << "in Bundler::Settings::BOOL_KEYS" } + Bundler::Settings::NUMBER_KEYS.each {|k| all_settings[k] << "in Bundler::Settings::NUMBER_KEYS" } + + Dir.chdir(File.expand_path("../../lib", __FILE__)) do + key_pattern = /([a-z\._-]+)/i + `git ls-files -z`.split("\x0").each do |filename| + File.readlines(filename).each_with_index do |line, number| + line.scan(/Bundler\.settings\[:#{key_pattern}\]/).flatten.each {|s| all_settings[s] << "referenced at `lib/#{filename}:#{number.succ}`" } + end + end + documented_settings = File.read("../man/bundle-config.ronn").scan(/^\* `#{key_pattern}`/).flatten + end + + documented_settings.each {|s| all_settings.delete(s) } + exemptions.each {|s| all_settings.delete(s) } + error_messages = all_settings.map do |setting, refs| + "The `#{setting}` setting is undocumented\n\t- #{refs.join("\n\t- ")}\n" + end + + expect(error_messages.sort).to be_well_formed + end + it "can still be built" do Dir.chdir(root) do begin diff --git a/spec/realworld/dependency_api_spec.rb b/spec/realworld/dependency_api_spec.rb index 9823cf8c76..468fa3644c 100644 --- a/spec/realworld/dependency_api_spec.rb +++ b/spec/realworld/dependency_api_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -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 @@ -26,6 +26,7 @@ describe "gemcutter's dependency API", :realworld => true do end after do + Artifice.deactivate @t.kill @t.join end diff --git a/spec/realworld/edgecases_spec.rb b/spec/realworld/edgecases_spec.rb index 7a78a114b4..302fd57cf0 100644 --- a/spec/realworld/edgecases_spec.rb +++ b/spec/realworld/edgecases_spec.rb @@ -1,7 +1,21 @@ # frozen_string_literal: true require "spec_helper" -describe "real world edgecases", :realworld => true, :sometimes => true do +RSpec.describe "real world edgecases", :realworld => true, :sometimes => true do + def rubygems_version(name, requirement) + require "bundler/source/rubygems/remote" + require "bundler/fetcher" + source = Bundler::Source::Rubygems::Remote.new(URI("https://rubygems.org")) + fetcher = Bundler::Fetcher.new(source) + index = fetcher.specs([name], nil) + rubygem = index.search(Gem::Dependency.new(name, requirement)).last + if rubygem.nil? + raise "Could not find #{name} (#{requirement}) on rubygems.org!\n" \ + "Found specs:\n#{index.send(:specs).inspect}" + end + "#{name} (#{rubygem.version})" + end + # there is no rbx-relative-require gem that will install on 1.9 it "ignores extra gems with bad platforms", :ruby => "~> 1.8.7" do gemfile <<-G @@ -15,7 +29,7 @@ describe "real world edgecases", :realworld => true, :sometimes => true do # https://github.com/bundler/bundler/issues/1202 it "bundle cache works with rubygems 1.3.7 and pre gems", - :ruby => "~> 1.8.7", "https://rubygems.org" => "~> 1.3.7" do + :ruby => "~> 1.8.7", :rubygems => "~> 1.3.7" do install_gemfile <<-G source "https://rubygems.org" gem "rack", "1.3.0.beta2" @@ -32,8 +46,8 @@ describe "real world edgecases", :realworld => true, :sometimes => true do source "https://rubygems.org" gem 'i18n', '~> 0.6.0' - gem 'activesupport', '~> 3.0' - gem 'activerecord', '~> 3.0' + gem 'activesupport', '~> 3.0.5' + gem 'activerecord', '~> 3.0.5' gem 'builder', '~> 2.1.2' G bundle :lock @@ -48,8 +62,8 @@ describe "real world edgecases", :realworld => true, :sometimes => true do gem 'capybara', '~> 2.2.0' gem 'rack-cache', '1.2.0' # last version that works on Ruby 1.9 G - bundle :lock - expect(lockfile).to include("rails (3.2.22.4)") + bundle! :lock + expect(lockfile).to include(rubygems_version("rails", "~> 3.0")) expect(lockfile).to include("capybara (2.2.1)") end @@ -76,8 +90,144 @@ describe "real world edgecases", :realworld => true, :sometimes => true do gem "builder", "~> 2.1.2" G bundle :lock - expect(lockfile).to include("i18n (0.6.11)") - expect(lockfile).to include("activesupport (3.0.5)") + expect(lockfile).to include(rubygems_version("i18n", "~> 0.6.0")) + expect(lockfile).to include(rubygems_version("activesupport", "~> 3.0")) + end + + it "is able to update a top-level dependency when there is a conflict on a shared transitive child", :ruby => "2.1" do + # from https://github.com/bundler/bundler/issues/5031 + + gemfile <<-G + source "https://rubygems.org" + gem 'rails', '~> 4.2.7.1' + gem 'paperclip', '~> 5.1.0' + G + + lockfile <<-L + GEM + remote: https://rubygems.org/ + specs: + actionmailer (4.2.7.1) + actionpack (= 4.2.7.1) + actionview (= 4.2.7.1) + activejob (= 4.2.7.1) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 1.0, >= 1.0.5) + actionpack (4.2.7.1) + actionview (= 4.2.7.1) + activesupport (= 4.2.7.1) + rack (~> 1.6) + rack-test (~> 0.6.2) + rails-dom-testing (~> 1.0, >= 1.0.5) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + actionview (4.2.7.1) + activesupport (= 4.2.7.1) + builder (~> 3.1) + erubis (~> 2.7.0) + rails-dom-testing (~> 1.0, >= 1.0.5) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + activejob (4.2.7.1) + activesupport (= 4.2.7.1) + globalid (>= 0.3.0) + activemodel (4.2.7.1) + activesupport (= 4.2.7.1) + builder (~> 3.1) + activerecord (4.2.7.1) + activemodel (= 4.2.7.1) + activesupport (= 4.2.7.1) + arel (~> 6.0) + activesupport (4.2.7.1) + i18n (~> 0.7) + json (~> 1.7, >= 1.7.7) + minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) + tzinfo (~> 1.1) + arel (6.0.3) + builder (3.2.2) + climate_control (0.0.3) + activesupport (>= 3.0) + cocaine (0.5.8) + climate_control (>= 0.0.3, < 1.0) + concurrent-ruby (1.0.2) + erubis (2.7.0) + globalid (0.3.7) + activesupport (>= 4.1.0) + i18n (0.7.0) + json (1.8.3) + loofah (2.0.3) + nokogiri (>= 1.5.9) + mail (2.6.4) + mime-types (>= 1.16, < 4) + mime-types (3.1) + mime-types-data (~> 3.2015) + mime-types-data (3.2016.0521) + mimemagic (0.3.2) + mini_portile2 (2.1.0) + minitest (5.9.1) + nokogiri (1.6.8) + mini_portile2 (~> 2.1.0) + pkg-config (~> 1.1.7) + paperclip (5.1.0) + activemodel (>= 4.2.0) + activesupport (>= 4.2.0) + cocaine (~> 0.5.5) + mime-types + mimemagic (~> 0.3.0) + pkg-config (1.1.7) + rack (1.6.4) + rack-test (0.6.3) + rack (>= 1.0) + rails (4.2.7.1) + actionmailer (= 4.2.7.1) + actionpack (= 4.2.7.1) + actionview (= 4.2.7.1) + activejob (= 4.2.7.1) + activemodel (= 4.2.7.1) + activerecord (= 4.2.7.1) + activesupport (= 4.2.7.1) + bundler (>= 1.3.0, < 2.0) + railties (= 4.2.7.1) + sprockets-rails + rails-deprecated_sanitizer (1.0.3) + activesupport (>= 4.2.0.alpha) + rails-dom-testing (1.0.7) + activesupport (>= 4.2.0.beta, < 5.0) + nokogiri (~> 1.6.0) + rails-deprecated_sanitizer (>= 1.0.1) + rails-html-sanitizer (1.0.3) + loofah (~> 2.0) + railties (4.2.7.1) + actionpack (= 4.2.7.1) + activesupport (= 4.2.7.1) + rake (>= 0.8.7) + thor (>= 0.18.1, < 2.0) + rake (11.3.0) + sprockets (3.7.0) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.2.0) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) + thor (0.19.1) + thread_safe (0.3.5) + tzinfo (1.2.2) + thread_safe (~> 0.1) + + PLATFORMS + ruby + + DEPENDENCIES + paperclip (~> 5.1.0) + rails (~> 4.2.7.1) + + BUNDLED WITH + 1.13.1 + L + + bundle! "lock --update paperclip" + + expect(lockfile).to include(rubygems_version("paperclip", "~> 5.1.0")) end # https://github.com/bundler/bundler/issues/1500 diff --git a/spec/realworld/gemfile_source_header_spec.rb b/spec/realworld/gemfile_source_header_spec.rb index 1c39fe97bb..ba888d43bd 100644 --- a/spec/realworld/gemfile_source_header_spec.rb +++ b/spec/realworld/gemfile_source_header_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" require "thread" -describe "fetching dependencies with a mirrored source", :realworld => true, :rubygems => ">= 2.0" do +RSpec.describe "fetching dependencies with a mirrored source", :realworld => true, :rubygems => ">= 2.0" do let(:mirror) { "https://server.example.org" } let(:original) { "http://127.0.0.1:#{@port}" } @@ -12,6 +12,7 @@ describe "fetching dependencies with a mirrored source", :realworld => true, :ru end after do + Artifice.deactivate @t.kill @t.join end diff --git a/spec/realworld/mirror_probe_spec.rb b/spec/realworld/mirror_probe_spec.rb index bb2be7f232..93dca0c173 100644 --- a/spec/realworld/mirror_probe_spec.rb +++ b/spec/realworld/mirror_probe_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" require "thread" -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 } @@ -15,6 +15,7 @@ describe "fetching dependencies with a not available mirror", :realworld => true end after do + Artifice.deactivate @server_thread.kill @server_thread.join end @@ -78,6 +79,22 @@ describe "fetching dependencies with a not available mirror", :realworld => true expect(out).to include("Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from #{mirror}") expect(out).to include("Could not fetch specs from #{mirror}") end + + it "prints each error and warning on a new line" do + gemfile <<-G + source "#{original}" + gem 'weakling' + G + + bundle :install + + expect(out).to eq "Fetching source index from #{mirror}/ + +Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ +Retrying fetcher due to error (3/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ +Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ +Could not fetch specs from #{mirror}/" + end end context "with a global mirror without a fallback timeout" do diff --git a/spec/realworld/parallel_spec.rb b/spec/realworld/parallel_spec.rb index 539b8ab287..6950bead19 100644 --- a/spec/realworld/parallel_spec.rb +++ b/spec/realworld/parallel_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "parallel", :realworld => true, :sometimes => true do +RSpec.describe "parallel", :realworld => true, :sometimes => true do it "installs" do gemfile <<-G source "https://rubygems.org" diff --git a/spec/resolver/basic_spec.rb b/spec/resolver/basic_spec.rb index 3e8883d1d4..69881d1019 100644 --- a/spec/resolver/basic_spec.rb +++ b/spec/resolver/basic_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "Resolving" do +RSpec.describe "Resolving" do before :each do @index = an_awesome_index end @@ -214,18 +214,22 @@ describe "Resolving" do should_conservative_resolve_and_include :patch, [], %w(foo-1.4.4 bar-2.1.1) end - it "will not revert to a previous version in strict mode level patch" do - pending "possible issue with molinillo - needs further research" - should_conservative_resolve_and_include [:patch, :strict], [], %w(foo-1.4.3 bar-2.1.1) + it "cannot revert to a previous version in strict mode level patch" do + # the strict option removes the version required to match, so a version conflict results + expect do + should_conservative_resolve_and_include [:patch, :strict], [], %w(foo-1.4.3 bar-2.1.1) + end.to raise_error Bundler::VersionConflict, /#{Regexp.escape("Could not find gem 'bar (~> 2.1.0)'")}/ end it "could revert to a previous version level minor" do should_conservative_resolve_and_include :minor, [], %w(foo-1.5.0 bar-2.0.5) end - it "will not revert to a previous version in strict mode level minor" do - pending "possible issue with molinillo - needs further research" - should_conservative_resolve_and_include [:minor, :strict], [], %w(foo-1.4.3 bar-2.1.1) + it "cannot revert to a previous version in strict mode level minor" do + # the strict option removes the version required to match, so a version conflict results + expect do + should_conservative_resolve_and_include [:minor, :strict], [], %w(foo-1.4.3 bar-2.1.1) + end.to raise_error Bundler::VersionConflict, /#{Regexp.escape("Could not find gem 'bar (~> 2.0.0)'")}/ end end end diff --git a/spec/resolver/platform_spec.rb b/spec/resolver/platform_spec.rb index fa91eab9c2..90d6f637ce 100644 --- a/spec/resolver/platform_spec.rb +++ b/spec/resolver/platform_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "Resolving platform craziness" do +RSpec.describe "Resolving platform craziness" do describe "with cross-platform gems" do before :each do @index = an_awesome_index diff --git a/spec/runtime/executable_spec.rb b/spec/runtime/executable_spec.rb index 1ce65bd598..ff27d0b415 100644 --- a/spec/runtime/executable_spec.rb +++ b/spec/runtime/executable_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "Running bin/* commands" do +RSpec.describe "Running bin/* commands" do before :each do gemfile <<-G source "file://#{gem_repo1}" diff --git a/spec/runtime/gem_tasks_spec.rb b/spec/runtime/gem_tasks_spec.rb index c187efd681..422ec45470 100644 --- a/spec/runtime/gem_tasks_spec.rb +++ b/spec/runtime/gem_tasks_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "require 'bundler/gem_tasks'" do +RSpec.describe "require 'bundler/gem_tasks'" do before :each do bundled_app("foo.gemspec").open("w") do |f| f.write <<-GEMSPEC diff --git a/spec/runtime/inline_spec.rb b/spec/runtime/inline_spec.rb index 3119045be4..022b123dc3 100644 --- a/spec/runtime/inline_spec.rb +++ b/spec/runtime/inline_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundler/inline#gemfile" do +RSpec.describe "bundler/inline#gemfile" do def script(code, options = {}) requires = ["bundler/inline"] requires.unshift File.expand_path("../../support/artifice/" + options.delete(:artifice) + ".rb", __FILE__) if options.key?(:artifice) @@ -85,12 +85,14 @@ describe "bundler/inline#gemfile" do script <<-RUBY, :artifice => "endpoint" gemfile(true) do - source "https://rubygems.org" + source "https://notaserver.com" gem "activesupport", :require => true end RUBY expect(out).to include("Installing activesupport") + err.gsub! %r{.*lib/sinatra/base\.rb:\d+: warning: constant ::Fixnum is deprecated$}, "" + err.strip! expect(err).to lack_errors expect(exitstatus).to be_zero if exitstatus end @@ -104,12 +106,12 @@ describe "bundler/inline#gemfile" do end end gemfile(true, :ui => MyBundlerUI.new) do - source "https://rubygems.org" + source "https://notaserver.com" gem "activesupport", :require => true end RUBY - expect(out).to eq("CONFIRMED!") + expect(out).to eq("CONFIRMED!\nCONFIRMED!") expect(exitstatus).to be_zero if exitstatus end @@ -173,4 +175,79 @@ describe "bundler/inline#gemfile" do expect(err).to be_empty expect(exitstatus).to be_zero if exitstatus end + + it "allows calling gemfile twice" do + script <<-RUBY + gemfile do + path "#{lib_path}" do + gem "two" + end + end + + gemfile do + path "#{lib_path}" do + gem "four" + end + end + RUBY + + expect(out).to eq("two\nfour") + expect(err).to be_empty + expect(exitstatus).to be_zero if exitstatus + end + + it "installs inline gems when a Gemfile.lock is present" 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 + 1.13.6 + G + + in_app_root do + script <<-RUBY + gemfile do + source "file://#{gem_repo1}" + gem "rack" + end + + puts RACK + RUBY + end + + expect(err).to be_empty + expect(exitstatus).to be_zero if exitstatus + end + + it "installs inline gems when BUNDLE_GEMFILE is set to an empty string" do + ENV["BUNDLE_GEMFILE"] = "" + + in_app_root do + script <<-RUBY + gemfile do + source "file://#{gem_repo1}" + gem "rack" + end + + puts RACK + RUBY + end + + expect(err).to be_empty + expect(exitstatus).to be_zero if exitstatus + end end diff --git a/spec/runtime/load_spec.rb b/spec/runtime/load_spec.rb index c010f8f8e9..d0e308ed3e 100644 --- a/spec/runtime/load_spec.rb +++ b/spec/runtime/load_spec.rb @@ -1,16 +1,9 @@ # frozen_string_literal: true require "spec_helper" -describe "Bundler.load" do +RSpec.describe "Bundler.load" do before :each do system_gems "rack-1.0.0" - # clear memoized method results - # TODO: Don't reset internal ivars - Bundler.instance_eval do - @load = nil - @runtime = nil - @definition = nil - end end describe "with a gemfile" do diff --git a/spec/runtime/platform_spec.rb b/spec/runtime/platform_spec.rb index 666864a88c..4df934e71f 100644 --- a/spec/runtime/platform_spec.rb +++ b/spec/runtime/platform_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "Bundler.setup with multi platform stuff" do +RSpec.describe "Bundler.setup with multi platform stuff" do it "raises a friendly error when gems are missing locally" do gemfile <<-G source "file://#{gem_repo1}" @@ -88,4 +88,36 @@ 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" do + simulate_platform "java" + + install_gemfile! <<-G + source "file://#{gem_repo1}" + gem "nokogiri" + gem "platform_specific" + G + + bundle! "config force_ruby_platform true" + + bundle! "install" + + expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 RUBY" + end + + it "allows specifying only-ruby-platform on windows with dependency platforms" do + simulate_windows do + install_gemfile! <<-G + source "file://#{gem_repo1}" + gem "nokogiri", :platforms => [:mingw, :mswin, :x64_mingw, :jruby] + gem "platform_specific" + G + + bundle! "config force_ruby_platform true" + + bundle! "install" + + expect(the_bundle).to include_gems "platform_specific 1.0 RUBY" + end + end end diff --git a/spec/runtime/require_spec.rb b/spec/runtime/require_spec.rb index ef88f91282..2d8935d2af 100644 --- a/spec/runtime/require_spec.rb +++ b/spec/runtime/require_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "Bundler.require" do +RSpec.describe "Bundler.require" do before :each do build_lib "one", "1.0.0" do |s| s.write "lib/baz.rb", "puts 'baz'" @@ -196,7 +196,7 @@ describe "Bundler.require" do expect(err).to lack_errors end - it "does not mangle explictly given requires" do + it "does not mangle explicitly given requires" do gemfile <<-G path "#{lib_path}" gem 'jquery-rails', :require => 'jquery-rails' @@ -362,7 +362,7 @@ describe "Bundler.require" do end end -describe "Bundler.require with platform specific dependencies" do +RSpec.describe "Bundler.require with platform specific dependencies" do it "does not require the gems that are pinned to other platforms" do install_gemfile <<-G source "file://#{gem_repo1}" diff --git a/spec/runtime/setup_spec.rb b/spec/runtime/setup_spec.rb index eab66e2ee2..be0c7a1593 100644 --- a/spec/runtime/setup_spec.rb +++ b/spec/runtime/setup_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "Bundler.setup" do +RSpec.describe "Bundler.setup" do describe "with no arguments" do it "makes all groups available" do install_gemfile <<-G @@ -673,6 +673,34 @@ describe "Bundler.setup" do expect(out).to be_empty end + it "does not load all gemspecs", :rubygems => ">= 2.3" do + install_gemfile! <<-G + source "file://#{gem_repo1}" + gem "rack" + G + + run! <<-R + File.open(File.join(Gem.dir, "specifications", "broken.gemspec"), "w") do |f| + f.write <<-RUBY +# -*- encoding: utf-8 -*- +# stub: broken 1.0.0 ruby lib + +Gem::Specification.new do |s| + s.name = "broken" + s.version = "1.0.0" + raise "BROKEN GEMSPEC" +end + RUBY + end + R + + run! <<-R + puts "WIN" + R + + expect(out).to eq("WIN") + end + it "ignores empty gem paths" do install_gemfile <<-G source "file://#{gem_repo1}" @@ -1080,8 +1108,8 @@ describe "Bundler.setup" do end end - describe "when Psych is not in the Gemfile", :ruby => "~> 2.2" do - it "does not load Psych" do + describe "with gemified standard libraries" do + it "does not load Psych", :ruby => "~> 2.2" do gemfile "" ruby <<-RUBY require 'bundler/setup' @@ -1093,5 +1121,31 @@ describe "Bundler.setup" do expect(pre_bundler).to eq("undefined") expect(post_bundler).to match(/\d+\.\d+\.\d+/) end + + it "does not load openssl" do + install_gemfile! "" + ruby! <<-RUBY + require "bundler/setup" + puts defined?(OpenSSL) || "undefined" + require "openssl" + puts defined?(OpenSSL) || "undefined" + RUBY + expect(out).to eq("undefined\nconstant") + end + end + + describe "after setup" do + it "allows calling #gem on random objects" do + install_gemfile <<-G + source "file:#{gem_repo1}" + gem "rack" + G + ruby! <<-RUBY + require "bundler/setup" + Object.new.gem "rack" + puts Gem.loaded_specs["rack"].full_name + RUBY + expect(out).to eq("rack-1.0.0") + end end end diff --git a/spec/runtime/with_clean_env_spec.rb b/spec/runtime/with_clean_env_spec.rb index 752754be39..b351e86c8b 100644 --- a/spec/runtime/with_clean_env_spec.rb +++ b/spec/runtime/with_clean_env_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "Bundler.with_env helpers" do +RSpec.describe "Bundler.with_env helpers" do describe "Bundler.original_env" do before do gemfile "" @@ -116,14 +116,14 @@ describe "Bundler.with_env helpers" do end end - describe "Bundler.clean_system" do + describe "Bundler.clean_system", :ruby => ">= 1.9" do it "runs system inside with_clean_env" do Bundler.clean_system(%(echo 'if [ "$BUNDLE_PATH" = "" ]; then exit 42; else exit 1; fi' | /bin/sh)) expect($?.exitstatus).to eq(42) end end - describe "Bundler.clean_exec" do + describe "Bundler.clean_exec", :ruby => ">= 1.9" do it "runs exec inside with_clean_env" do pid = Kernel.fork do Bundler.clean_exec(%(echo 'if [ "$BUNDLE_PATH" = "" ]; then exit 42; else exit 1; fi' | /bin/sh)) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a3251ea640..297d81f531 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -17,6 +17,10 @@ rescue LoadError abort "Run rake spec:deps to install development dependencies" end +if File.expand_path(__FILE__) =~ %r{([^\w/\.])} + abort "The bundler specs cannot be run from a path that contains special characters (particularly #{$1.inspect})" +end + require "bundler" # Require the correct version of popen for the current platform @@ -31,7 +35,7 @@ else end Dir["#{File.expand_path("../support", __FILE__)}/*.rb"].each do |file| - require file unless file =~ %r{fakeweb/.*\.rb} + require file unless file.end_with?("hax.rb") end $debug = false @@ -61,6 +65,14 @@ RSpec.configure do |config| # Enable flags like --only-failures and --next-failure config.example_status_persistence_file_path = ".rspec_status" + config.disable_monkey_patching! + + # Since failures cause us to keep a bunch of long strings in memory, stop + # once we have a large number of failures (indicative of core pieces of + # bundler being broken) so that running the full test suite doesn't take + # forever due to memory constraints + config.fail_fast ||= 25 + if ENV["BUNDLER_SUDO_TESTS"] && Spec::Sudo.present? config.filter_run :sudo => true else @@ -91,6 +103,14 @@ RSpec.configure do |config| config.before :all do build_repo1 + # HACK: necessary until rspec-mocks > 3.5.0 is used + # see https://github.com/bundler/bundler/pull/5363#issuecomment-278089256 + if RUBY_VERSION < "1.9" + FileUtils.module_eval do + alias_method :mkpath, :mkdir_p + module_function :mkpath + end + end end config.before :each do diff --git a/spec/support/artifice/compact_index.rb b/spec/support/artifice/compact_index.rb index f3ff2db4fa..9111ed8211 100644 --- a/spec/support/artifice/compact_index.rb +++ b/spec/support/artifice/compact_index.rb @@ -67,9 +67,11 @@ class CompactIndexAPI < Endpoint @gems ||= {} @gems[gem_repo] ||= begin specs = Bundler::Deprecate.skip_during do - Marshal.load(File.open(gem_repo.join("specs.4.8")).read).map do |name, version, platform| - load_spec(name, version, platform, gem_repo) - end + %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| @@ -103,8 +105,8 @@ class CompactIndexAPI < Endpoint file = tmp("versions.list") file.delete if file.file? file = CompactIndex::VersionsFile.new(file.to_s) - file.update_with(gems) - CompactIndex.versions(file, nil, {}) + file.create(gems) + file.contents end end diff --git a/spec/support/artifice/compact_index_concurrent_download.rb b/spec/support/artifice/compact_index_concurrent_download.rb index 30a2171a30..b788a852cf 100644 --- a/spec/support/artifice/compact_index_concurrent_download.rb +++ b/spec/support/artifice/compact_index_concurrent_download.rb @@ -22,8 +22,8 @@ class CompactIndexConcurrentDownload < CompactIndexAPI file = tmp("versions.list") file.delete if file.file? file = CompactIndex::VersionsFile.new(file.to_s) - file.update_with(gems) - CompactIndex.versions(file, nil, {}) + file.create(gems) + file.contents end end end diff --git a/spec/support/artifice/compact_index_extra_api.rb b/spec/support/artifice/compact_index_extra_api.rb index 063e5589d4..844a9ca9f2 100644 --- a/spec/support/artifice/compact_index_extra_api.rb +++ b/spec/support/artifice/compact_index_extra_api.rb @@ -15,8 +15,8 @@ class CompactIndexExtraApi < CompactIndexAPI file = tmp("versions.list") file.delete if file.file? file = CompactIndex::VersionsFile.new(file.to_s) - file.update_with(gems(gem_repo4)) - CompactIndex.versions(file, nil, {}) + file.create(gems(gem_repo4)) + file.contents end end diff --git a/spec/support/artifice/compact_index_wrong_dependencies.rb b/spec/support/artifice/compact_index_wrong_dependencies.rb new file mode 100644 index 0000000000..25935f5e5d --- /dev/null +++ b/spec/support/artifice/compact_index_wrong_dependencies.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +require File.expand_path("../compact_index", __FILE__) + +Artifice.deactivate + +class CompactIndexWrongDependencies < CompactIndexAPI + get "/info/:name" do + etag_response do + gem = gems.find {|g| g.name == params[:name] } + gem.versions.each {|gv| gv.dependencies.clear } if gem + CompactIndex.info(gem ? gem.versions : []) + end + end +end + +Artifice.activate_with(CompactIndexWrongDependencies) diff --git a/spec/support/artifice/endpoint.rb b/spec/support/artifice/endpoint.rb index 2955889a86..861ac49e93 100644 --- a/spec/support/artifice/endpoint.rb +++ b/spec/support/artifice/endpoint.rb @@ -3,12 +3,7 @@ require File.expand_path("../../path.rb", __FILE__) require File.expand_path("../../../../lib/bundler/deprecate", __FILE__) include Spec::Path -# Set up pretend http gem server with FakeWeb -$LOAD_PATH.unshift "#{Dir[base_system_gems.join("gems/artifice*/lib")].first}" -$LOAD_PATH.unshift "#{Dir[base_system_gems.join("gems/rack-*/lib")].first}" -$LOAD_PATH.unshift "#{Dir[base_system_gems.join("gems/rack-*/lib")].last}" -$LOAD_PATH.unshift "#{Dir[base_system_gems.join("gems/tilt*/lib")].first}" -$LOAD_PATH.unshift "#{Dir[base_system_gems.join("gems/sinatra*/lib")].first}" +$LOAD_PATH.unshift(*Dir[Spec::Path.base_system_gems.join("gems/{artifice,rack,tilt,sinatra}-*/lib")].map(&:to_s)) require "artifice" require "sinatra/base" @@ -24,7 +19,11 @@ class Endpoint < Sinatra::Base require "rubygems" require "bundler" Bundler::Deprecate.skip_during do - Marshal.load(File.open(gem_repo.join("specs.4.8")).read).map do |name, version, platform| + 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) { diff --git a/spec/support/artifice/endpoint_500.rb b/spec/support/artifice/endpoint_500.rb index 9bbbd1e2f2..993630b79e 100644 --- a/spec/support/artifice/endpoint_500.rb +++ b/spec/support/artifice/endpoint_500.rb @@ -2,11 +2,7 @@ require File.expand_path("../../path.rb", __FILE__) include Spec::Path -$LOAD_PATH.unshift "#{Dir[base_system_gems.join("gems/artifice*/lib")].first}" -$LOAD_PATH.unshift "#{Dir[base_system_gems.join("gems/rack-*/lib")].first}" -$LOAD_PATH.unshift "#{Dir[base_system_gems.join("gems/rack-*/lib")].last}" -$LOAD_PATH.unshift "#{Dir[base_system_gems.join("gems/tilt*/lib")].first}" -$LOAD_PATH.unshift "#{Dir[base_system_gems.join("gems/sinatra*/lib")].first}" +$LOAD_PATH.unshift(*Dir[Spec::Path.base_system_gems.join("gems/{artifice,rack,tilt,sinatra}-*/lib")].map(&:to_s)) require "artifice" require "sinatra/base" diff --git a/spec/support/artifice/fail.rb b/spec/support/artifice/fail.rb index e15768a328..1059c6df4e 100644 --- a/spec/support/artifice/fail.rb +++ b/spec/support/artifice/fail.rb @@ -1,23 +1,39 @@ # frozen_string_literal: true -require File.expand_path("../../path.rb", __FILE__) - -# Set up pretend http gem server with FakeWeb -$LOAD_PATH.unshift Dir[Spec::Path.base_system_gems.join("gems/artifice*/lib")].first.to_s -$LOAD_PATH.unshift Dir[Spec::Path.base_system_gems.join("gems/rack-*/lib")].first.to_s -$LOAD_PATH.unshift Dir[Spec::Path.base_system_gems.join("gems/rack-*/lib")].last.to_s -$LOAD_PATH.unshift Dir[Spec::Path.base_system_gems.join("gems/tilt*/lib")].first.to_s -require "artifice" - -class Fail - def call(env) - raise(exception(env)) +require "net/http" +begin + require "net/https" +rescue LoadError + nil # net/https or openssl +end + +# 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 + # to use a legacy implementation. Since we are subclassing + # Net::HTTP, we must set it + @newimpl = true + + def request(req, body = nil, &block) + raise(exception(req)) end - def exception(env) + # Ensure we don't start a connect here + def connect + 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! #{env["PATH_INFO"]}") + const.new("host down: Bundler spec artifice fail! #{req["PATH_INFO"]}") end end -Artifice.activate_with(Fail.new) + +# Replace Net::HTTP with our failing subclass +::Net.class_eval do + remove_const(:HTTP) + const_set(:HTTP, ::Fail) +end diff --git a/spec/support/artifice/windows.rb b/spec/support/artifice/windows.rb new file mode 100644 index 0000000000..c18ca454ec --- /dev/null +++ b/spec/support/artifice/windows.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true +require File.expand_path("../../path.rb", __FILE__) +include Spec::Path + +$LOAD_PATH.unshift Dir[base_system_gems.join("gems/artifice*/lib")].first.to_s +$LOAD_PATH.unshift(*Dir[base_system_gems.join("gems/rack-*/lib")]) +$LOAD_PATH.unshift Dir[base_system_gems.join("gems/tilt*/lib")].first.to_s +$LOAD_PATH.unshift Dir[base_system_gems.join("gems/sinatra*/lib")].first.to_s +require "artifice" +require "sinatra/base" + +Artifice.deactivate + +class Windows < Sinatra::Base + set :raise_errors, true + set :show_exceptions, false + + helpers do + def gem_repo + Pathname.new(ENV["BUNDLER_SPEC_GEM_REPO"] || Spec::Path.gem_repo1) + end + end + + files = ["specs.4.8.gz", + "prerelease_specs.4.8.gz", + "quick/Marshal.4.8/rcov-1.0-mswin32.gemspec.rz", + "gems/rcov-1.0-mswin32.gem"] + + files.each do |file| + get "/#{file}" do + File.read gem_repo.join(file) + end + end + + get "/gems/rcov-1.0-x86-mswin32.gem" do + halt 404 + end + + get "/api/v1/dependencies" do + halt 404 + end + + get "/versions" do + halt 500 + end +end + +Artifice.activate_with(Windows) diff --git a/spec/support/builders.rb b/spec/support/builders.rb index 7436779d15..bda808c0b2 100644 --- a/spec/support/builders.rb +++ b/spec/support/builders.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true require "bundler/shared_helpers" +require "shellwords" module Spec module Builders @@ -79,8 +80,8 @@ module Spec end build_gem "platform_specific" do |s| - s.platform = Gem::Platform.local - s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 #{Gem::Platform.local}'" + s.platform = Bundler.local_platform + s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 #{Bundler.local_platform}'" end build_gem "platform_specific" do |s| @@ -505,6 +506,10 @@ module Spec @spec.add_runtime_dependency(name, requirements) end + def development(name, requirements) + @spec.add_development_dependency(name, requirements) + end + def required_ruby_version=(*reqs) @spec.required_ruby_version = *reqs end @@ -660,14 +665,15 @@ module Spec if branch = options[:branch] raise "You can't specify `master` as the branch" if branch == "master" + escaped_branch = Shellwords.shellescape(branch) - if `git branch | grep #{branch}`.empty? - silently("git branch #{branch}") + if `git branch | grep #{escaped_branch}`.empty? + silently("git branch #{escaped_branch}") end - silently("git checkout #{branch}") + silently("git checkout #{escaped_branch}") elsif tag = options[:tag] - `git tag #{tag}` + `git tag #{Shellwords.shellescape(tag)}` elsif options[:remote] silently("git remote add origin file://#{options[:remote]}") elsif options[:push] diff --git a/spec/support/fakeweb/rack-1.0.0.marshal b/spec/support/fakeweb/rack-1.0.0.marshal deleted file mode 100644 index 383ce407f9..0000000000 --- a/spec/support/fakeweb/rack-1.0.0.marshal +++ /dev/null @@ -1,2 +0,0 @@ -[{ :dependencies[[" thin" >= 0["ruby-openid"
~> 2.0.0["mongrel" >= 0["memcache-client" >= 0[" fcgi" >= 0["camping" >= 0["test-spec" >= 0:
platform" ruby: name" rack:number" -1.0.0
\ No newline at end of file diff --git a/spec/support/fakeweb/windows.rb b/spec/support/fakeweb/windows.rb deleted file mode 100644 index f1f21eed3f..0000000000 --- a/spec/support/fakeweb/windows.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true -require File.expand_path("../../path.rb", __FILE__) -include Spec::Path - -files = ["specs.4.8.gz", - "prerelease_specs.4.8.gz", - "quick/Marshal.4.8/rcov-1.0-mswin32.gemspec.rz", - "gems/rcov-1.0-mswin32.gem"] - -# Set up pretend http gem server with FakeWeb -$LOAD_PATH.unshift "#{Dir[base_system_gems.join("gems/fakeweb*/lib")].first}" -require "fakeweb" - -FakeWeb.allow_net_connect = false - -files.each do |file| - FakeWeb.register_uri(:get, "http://localgemserver.test/#{file}", - :body => File.read("#{gem_repo1}/#{file}")) -end -FakeWeb.register_uri(:get, "http://localgemserver.test/gems/rcov-1.0-x86-mswin32.gem", - :status => ["404", "Not Found"]) - -FakeWeb.register_uri(:get, "http://localgemserver.test/api/v1/dependencies", - :status => ["404", "Not Found"]) - -FakeWeb.register_uri(:get, "http://localgemserver.test/versions", - :status => ["500", "Internal Server Error"]) diff --git a/spec/support/hax.rb b/spec/support/hax.rb index 2cca22c6ab..663d3527c5 100644 --- a/spec/support/hax.rb +++ b/spec/support/hax.rb @@ -1,12 +1,16 @@ # frozen_string_literal: true require "rubygems" -class Gem::Platform - @local = new(ENV["BUNDLER_SPEC_PLATFORM"]) if ENV["BUNDLER_SPEC_PLATFORM"] +module Gem + class Platform + @local = new(ENV["BUNDLER_SPEC_PLATFORM"]) if ENV["BUNDLER_SPEC_PLATFORM"] + end + @platforms = [Gem::Platform::RUBY, Gem::Platform.local] end if ENV["BUNDLER_SPEC_VERSION"] module Bundler + remove_const(:VERSION) if const_defined?(:VERSION) VERSION = ENV["BUNDLER_SPEC_VERSION"].dup end end diff --git a/spec/support/helpers.rb b/spec/support/helpers.rb index fe79604f30..1b2769ebf8 100644 --- a/spec/support/helpers.rb +++ b/spec/support/helpers.rb @@ -2,17 +2,17 @@ module Spec module Helpers def reset! - Dir["#{tmp}/{gems/*,*}"].each do |dir| - next if %(base remote1 gems rubygems).include?(File.basename(dir)) + Dir.glob("#{tmp}/{gems/*,*}", File::FNM_DOTMATCH).each do |dir| + next if %w(base remote1 gems rubygems . ..).include?(File.basename(dir)) if ENV["BUNDLER_SUDO_TESTS"] - `sudo rm -rf #{dir}` + `sudo rm -rf "#{dir}"` else FileUtils.rm_rf(dir) end end - FileUtils.mkdir_p(tmp) FileUtils.mkdir_p(home) - ENV["BUNDLE_DISABLE_POSTIT"] = "1" + FileUtils.mkdir_p(tmpdir) + ENV["BUNDLE_TRAMPOLINE_DISABLE"] = "1" Bundler.reset! Bundler.ui = nil Bundler.ui # force it to initialize @@ -84,22 +84,33 @@ module Spec with_sudo = options.delete(:sudo) sudo = with_sudo == :preserve_env ? "sudo -E" : "sudo" if with_sudo - options["no-color"] = true unless options.key?("no-color") || cmd.to_s.start_with?("exec", "exe", "ex", "e", "conf") + options["no-color"] = true unless options.key?("no-color") || cmd.to_s =~ /\A(e|ex|exe|exec|conf|confi|config)(\s|\z)/ bundle_bin = options.delete("bundle_bin") || File.expand_path("../../../exe/bundle", __FILE__) + if system_bundler = options.delete(:system_bundler) + bundle_bin = "-S bundle" + end + requires = options.delete(:requires) || [] - requires << File.expand_path("../fakeweb/" + options.delete(:fakeweb) + ".rb", __FILE__) if options.key?(:fakeweb) - requires << File.expand_path("../artifice/" + options.delete(:artifice) + ".rb", __FILE__) if options.key?(:artifice) + if artifice = options.delete(:artifice) { "fail" unless RSpec.current_example.metadata[:realworld] } + requires << File.expand_path("../artifice/#{artifice}.rb", __FILE__) + end requires << "support/hax" requires_str = requires.map {|r| "-r#{r}" }.join(" ") + load_path = [] + load_path << lib unless system_bundler + load_path << spec + load_path_str = "-I#{load_path.join(File::PATH_SEPARATOR)}" + env = (options.delete(:env) || {}).map {|k, v| "#{k}='#{v}'" }.join(" ") + env["PATH"].gsub!("#{Path.root}/exe", "") if env["PATH"] && system_bundler args = options.map do |k, v| v == true ? " --#{k}" : " --#{k} #{v}" if v end.join - cmd = "#{env} #{sudo} #{Gem.ruby} -I#{lib}:#{spec} #{requires_str} #{bundle_bin} #{cmd}#{args}" + cmd = "#{env} #{sudo} #{Gem.ruby} #{load_path_str} #{requires_str} #{bundle_bin} #{cmd}#{args}" sys_exec(cmd) {|i, o, thr| yield i, o, thr if block_given? } end bang :bundle @@ -110,19 +121,8 @@ module Spec end def bundle_ruby(options = {}) - options["no-color"] = true unless options.key?("no-color") - - bundle_bin = File.expand_path("../../../exe/bundle_ruby", __FILE__) - - requires = options.delete(:requires) || [] - requires << File.expand_path("../fakeweb/" + options.delete(:fakeweb) + ".rb", __FILE__) if options.key?(:fakeweb) - requires << File.expand_path("../artifice/" + options.delete(:artifice) + ".rb", __FILE__) if options.key?(:artifice) - requires_str = requires.map {|r| "-r#{r}" }.join(" ") - - env = (options.delete(:env) || {}).map {|k, v| "#{k}='#{v}' " }.join - cmd = "#{env}#{Gem.ruby} -I#{lib} #{requires_str} #{bundle_bin}" - - sys_exec(cmd) {|i, o, thr| yield i, o, thr if block_given? } + options["bundle_bin"] = File.expand_path("../../../exe/bundle_ruby", __FILE__) + bundle("", options) end def ruby(ruby, options = {}) @@ -208,7 +208,11 @@ module Spec end def gemfile(*args) - create_file("Gemfile", *args) + if args.empty? + File.open("Gemfile", "r", &:read) + else + create_file("Gemfile", *args) + end end def lockfile(*args) @@ -241,12 +245,20 @@ module Spec end def install_gems(*gems) + options = gems.last.is_a?(Hash) ? gems.pop : {} + gem_repo = options.fetch(:gem_repo) { gem_repo1 } gems.each do |g| - path = "#{gem_repo1}/gems/#{g}.gem" + path = if g == :bundler + Dir.chdir(root) { gem_command! :build, "#{root}/bundler.gemspec" } + bundler_path = root + "bundler-#{Bundler::VERSION}.gem" + else + "#{gem_repo}/gems/#{g}.gem" + end raise "OMG `#{path}` does not exist!" unless File.exist?(path) - gem_command! :install, "--no-rdoc --no-ri --ignore-dependencies #{path}" + gem_command! :install, "--no-rdoc --no-ri --ignore-dependencies '#{path}'" + bundler_path && bundler_path.rmtree end end diff --git a/spec/support/path.rb b/spec/support/path.rb index cf77adb509..2b929003fb 100644 --- a/spec/support/path.rb +++ b/spec/support/path.rb @@ -89,6 +89,10 @@ module Spec bundled_app ".bundle", "plugin", "gems", *args end + def tmpdir(*args) + tmp "tmpdir", *args + end + extend self end end diff --git a/spec/support/rubygems_ext.rb b/spec/support/rubygems_ext.rb index 4ddbc3312a..88886c3f1f 100644 --- a/spec/support/rubygems_ext.rb +++ b/spec/support/rubygems_ext.rb @@ -9,8 +9,9 @@ module Spec # rack 2.x requires Ruby version >= 2.2.2. # artifice doesn't support rack 2.x now. "rack" => "< 2", - "fakeweb artifice compact_index" => nil, - "sinatra" => "1.2.7", + "artifice" => "~> 0.6.0", + "compact_index" => "~> 0.11.0", + "sinatra" => "~> 1.4.7", # Rake version has to be consistent for tests to pass "rake" => "10.0.2", # 3.0.0 breaks 1.9.2 specs @@ -36,19 +37,25 @@ module Spec FileUtils.rm_rf(Path.base_system_gems) FileUtils.mkdir_p(Path.base_system_gems) puts "installing gems for the tests to use..." - DEPS.sort {|a, _| a[1].nil? ? 1 : -1 }.each {|n, v| install_gem(n, v) } + install_gems(DEPS) File.open(manifest_path, "w") {|f| f << manifest.join } end ENV["HOME"] = Path.home.to_s + ENV["TMPDIR"] = Path.tmpdir.to_s Gem::DefaultUserInteraction.ui = Gem::SilentUI.new end - def self.install_gem(name, version = nil) - cmd = "gem install #{name} --no-rdoc --no-ri" - cmd += " --version '#{version}'" if version - system(cmd) || raise("Installing gem #{name} for the tests to use failed!") + def self.install_gems(gems) + reqs, no_reqs = gems.partition {|_, req| !req.nil? && !req.split(" ").empty? } + reqs = reqs.sort_by {|name, _| name == "rack" ? 0 : 1 } # TODO: remove when we drop ruby 1.8.7 support + no_reqs.map!(&:first) + reqs.map! {|name, req| "'#{name}:#{req}'" } + deps = reqs.concat(no_reqs).join(" ") + cmd = "gem install #{deps} --no-rdoc --no-ri --conservative" + puts cmd + system(cmd) || raise("Installing gems #{deps} for the tests to use failed!") end end end diff --git a/spec/update/gems/post_install_spec.rb b/spec/update/gems/post_install_spec.rb new file mode 100644 index 0000000000..5a4fe7f321 --- /dev/null +++ b/spec/update/gems/post_install_spec.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true +require "spec_helper" + +RSpec.describe "bundle update" do + let(:config) {} + + before do + gemfile <<-G + source "file://#{gem_repo1}" + gem 'rack', "< 1.0" + gem 'thin' + G + + bundle! "config #{config}" if config + + bundle! :install + end + + shared_examples "a config observer" do + context "when ignore post-install messages for gem is set" do + let(:config) { "ignore_messages.rack true" } + + it "doesn't display gem's post-install message" do + expect(out).not_to include("Rack's post install message") + end + end + + context "when ignore post-install messages for all gems" do + let(:config) { "ignore_messages true" } + + it "doesn't display any post-install messages" do + expect(out).not_to include("Post-install message") + end + end + end + + shared_examples "a post-install message outputter" do + it "should display post-install messages for updated gems" do + expect(out).to include("Post-install message from rack:") + expect(out).to include("Rack's post install message") + end + + it "should not display the post-install message for non-updated gems" do + expect(out).not_to include("Thin's post install message") + end + end + + context "when listed gem is updated" do + before do + gemfile <<-G + source "file://#{gem_repo1}" + gem 'rack' + gem 'thin' + G + + bundle! :update + end + + it_behaves_like "a post-install message outputter" + it_behaves_like "a config observer" + end + + context "when dependency triggers update" do + before do + gemfile <<-G + source "file://#{gem_repo1}" + gem 'rack-obama' + gem 'thin' + G + + bundle! :update + end + + it_behaves_like "a post-install message outputter" + it_behaves_like "a config observer" + end +end diff --git a/spec/update/git_spec.rb b/spec/update/git_spec.rb index b67ddda202..021c8c942b 100644 --- a/spec/update/git_spec.rb +++ b/spec/update/git_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "bundle update" do +RSpec.describe "bundle update" do describe "git sources" do it "floats on a branch when :branch is used" do build_git "foo", "1.0" diff --git a/spec/update/path_spec.rb b/spec/update/path_spec.rb index aa220ad60e..5ac4f7b1fe 100644 --- a/spec/update/path_spec.rb +++ b/spec/update/path_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require "spec_helper" -describe "path sources" do +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") |