# frozen_string_literal: true require "spec_helper" 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 source "file://#{gem_repo1}" G bundle :install expect(out).to match(/no dependencies/) end it "does not make a lockfile if the install fails" do install_gemfile <<-G raise StandardError, "FAIL" G expect(err).to lack_errors expect(out).to match(/StandardError, "FAIL"/) expect(bundled_app("Gemfile.lock")).not_to exist end it "creates a Gemfile.lock" do install_gemfile <<-G source "file://#{gem_repo1}" gem "rack" G expect(bundled_app("Gemfile.lock")).to exist end it "does not create ./.bundle by default" do gemfile <<-G source "file://#{gem_repo1}" gem "rack" G bundle :install # can't use install_gemfile since it sets retry expect(bundled_app(".bundle")).not_to exist end it "creates lock files based on the Gemfile name" do gemfile bundled_app("OmgFile"), <<-G source "file://#{gem_repo1}" gem "rack", "1.0" G bundle "install --gemfile OmgFile" expect(bundled_app("OmgFile.lock")).to exist end it "doesn't delete the lockfile if one already exists" do install_gemfile <<-G source "file://#{gem_repo1}" gem 'rack' G lockfile = File.read(bundled_app("Gemfile.lock")) install_gemfile <<-G raise StandardError, "FAIL" G expect(File.read(bundled_app("Gemfile.lock"))).to eq(lockfile) end it "does not touch the lockfile if nothing changed" do install_gemfile <<-G source "file://#{gem_repo1}" gem "rack" G expect { run "1" }.not_to change { File.mtime(bundled_app("Gemfile.lock")) } end it "fetches gems" do install_gemfile <<-G source "file://#{gem_repo1}" gem 'rack' G expect(default_bundle_path("gems/rack-1.0.0")).to exist expect(the_bundle).to include_gems("rack 1.0.0") end it "fetches gems when multiple versions are specified" do install_gemfile <<-G source "file://#{gem_repo1}" gem 'rack', "> 0.9", "< 1.0" G expect(default_bundle_path("gems/rack-0.9.1")).to exist expect(the_bundle).to include_gems("rack 0.9.1") end it "fetches gems when multiple versions are specified take 2" do install_gemfile <<-G source "file://#{gem_repo1}" gem 'rack', "< 1.0", "> 0.9" G expect(default_bundle_path("gems/rack-0.9.1")).to exist expect(the_bundle).to include_gems("rack 0.9.1") end it "raises an appropriate error when gems are specified using symbols" do install_gemfile(<<-G) source "file://#{gem_repo1}" gem :rack G expect(exitstatus).to eq(4) if exitstatus end it "pulls in dependencies" do install_gemfile <<-G source "file://#{gem_repo1}" gem "rails" G expect(the_bundle).to include_gems "actionpack 2.3.2", "rails 2.3.2" end it "does the right version" do install_gemfile <<-G source "file://#{gem_repo1}" gem "rack", "0.9.1" G expect(the_bundle).to include_gems "rack 0.9.1" end it "does not install the development dependency" do install_gemfile <<-G source "file://#{gem_repo1}" gem "with_development_dependency" G expect(the_bundle).to include_gems("with_development_dependency 1.0.0"). and not_include_gems("activesupport 2.3.5") end it "resolves correctly" do install_gemfile <<-G source "file://#{gem_repo1}" gem "activemerchant" gem "rails" G expect(the_bundle).to include_gems "activemerchant 1.0", "activesupport 2.3.2", "actionpack 2.3.2" end it "activates gem correctly according to the resolved gems" do install_gemfile <<-G source "file://#{gem_repo1}" gem "activesupport", "2.3.5" G install_gemfile <<-G source "file://#{gem_repo1}" gem "activemerchant" gem "rails" G expect(the_bundle).to include_gems "activemerchant 1.0", "activesupport 2.3.2", "actionpack 2.3.2" end it "does not reinstall any gem that is already available locally" do system_gems "activesupport-2.3.2" build_repo2 do build_gem "activesupport", "2.3.2" do |s| s.write "lib/activesupport.rb", "ACTIVESUPPORT = 'fail'" end end install_gemfile <<-G source "file://#{gem_repo2}" gem "activerecord", "2.3.2" G expect(the_bundle).to include_gems "activesupport 2.3.2" end it "works when the gemfile specifies gems that only exist in the system" do build_gem "foo", :to_system => true install_gemfile <<-G source "file://#{gem_repo1}" gem "rack" gem "foo" G expect(the_bundle).to include_gems "rack 1.0.0", "foo 1.0.0" end it "prioritizes local gems over remote gems" do build_gem "rack", "1.0.0", :to_system => true do |s| s.add_dependency "activesupport", "2.3.5" end install_gemfile <<-G source "file://#{gem_repo1}" gem "rack" G expect(the_bundle).to include_gems "rack 1.0.0", "activesupport 2.3.5" end describe "with a gem that installs multiple platforms" do it "installs gems for the local platform as first choice" do install_gemfile <<-G source "file://#{gem_repo1}" gem "platform_specific" G run "require 'platform_specific' ; puts PLATFORM_SPECIFIC" expect(out).to eq("1.0.0 #{Bundler.local_platform}") end it "falls back on plain ruby" do simulate_platform "foo-bar-baz" install_gemfile <<-G source "file://#{gem_repo1}" gem "platform_specific" G run "require 'platform_specific' ; puts PLATFORM_SPECIFIC" expect(out).to eq("1.0.0 RUBY") end it "installs gems for java" do simulate_platform "java" install_gemfile <<-G source "file://#{gem_repo1}" gem "platform_specific" G run "require 'platform_specific' ; puts PLATFORM_SPECIFIC" expect(out).to eq("1.0.0 JAVA") end it "installs gems for windows" do simulate_platform mswin install_gemfile <<-G source "file://#{gem_repo1}" gem "platform_specific" G run "require 'platform_specific' ; puts PLATFORM_SPECIFIC" expect(out).to eq("1.0.0 MSWIN") end end describe "doing bundle install foo" do before do gemfile <<-G source "file://#{gem_repo1}" gem "rack" G end it "works" do bundle "install --path vendor" expect(the_bundle).to include_gems "rack 1.0" end it "allows running bundle install --system without deleting foo" do bundle "install --path vendor" bundle "install --system" FileUtils.rm_rf(bundled_app("vendor")) expect(the_bundle).to include_gems "rack 1.0" end it "allows running bundle install --system after deleting foo" do bundle "install --path vendor" FileUtils.rm_rf(bundled_app("vendor")) bundle "install --system" expect(the_bundle).to include_gems "rack 1.0" end end it "finds gems in multiple sources" do build_repo2 update_repo2 install_gemfile <<-G source "file://#{gem_repo1}" source "file://#{gem_repo2}" gem "activesupport", "1.2.3" gem "rack", "1.2" G expect(the_bundle).to include_gems "rack 1.2", "activesupport 1.2.3" end it "gives a useful error if no sources are set" do install_gemfile <<-G gem "rack" G bundle :install expect(out).to include("Your Gemfile has no gem server sources") end it "creates a Gemfile.lock on a blank Gemfile" do install_gemfile <<-G G expect(File.exist?(bundled_app("Gemfile.lock"))).to eq(true) end it "gracefully handles error when rubygems server is unavailable" do install_gemfile <<-G, :artifice => nil source "file://#{gem_repo1}" source "http://localhost:9384" gem 'foo' G bundle :install, :artifice => nil expect(out).to include("Could not fetch specs from http://localhost:9384/") expect(out).not_to include("file://") end it "fails gracefully when downloading an invalid specification from the full index", :rubygems => "2.5" do build_repo2 do build_gem "ajp-rails", "0.0.0", :gemspec => false, :skip_validation => true do |s| bad_deps = [["ruby-ajp", ">= 0.2.0"], ["rails", ">= 0.14"]] s. instance_variable_get(:@spec). instance_variable_set(:@dependencies, bad_deps) raise "failed to set bad deps" unless s.dependencies == bad_deps end build_gem "ruby-ajp", "1.0.0" end install_gemfile <<-G, :full_index => true source "file://#{gem_repo2}" gem "ajp-rails", "0.0.0" G expect(out).not_to match(/Error Report/i) expect(err).not_to match(/Error Report/i) expect(out).to include("An error occurred while installing ajp-rails (0.0.0), and Bundler cannot continue."). and include("Make sure that `gem install ajp-rails -v '0.0.0'` succeeds before bundling.") end it "doesn't blow up when the local .bundle/config is empty" do FileUtils.mkdir_p(bundled_app(".bundle")) FileUtils.touch(bundled_app(".bundle/config")) install_gemfile(<<-G) source "file://#{gem_repo1}" gem 'foo' G expect(exitstatus).to eq(0) if exitstatus end it "doesn't blow up when the global .bundle/config is empty" do FileUtils.mkdir_p("#{Bundler.rubygems.user_home}/.bundle") FileUtils.touch("#{Bundler.rubygems.user_home}/.bundle/config") install_gemfile(<<-G) source "file://#{gem_repo1}" gem 'foo' G expect(exitstatus).to eq(0) if exitstatus end end describe "Ruby version in Gemfile.lock" do include Bundler::GemHelpers context "and using an unsupported Ruby version" do it "prints an error" do install_gemfile <<-G ::RUBY_VERSION = '1.8.7' ruby '~> 2.1' G expect(out).to include("Your Ruby version is 1.8.7, but your Gemfile specified ~> 2.1") end end context "and using a supported Ruby version" do before do install_gemfile <<-G ::RUBY_VERSION = '2.1.3' ::RUBY_PATCHLEVEL = 100 ruby '~> 2.1.0' G end it "writes current Ruby version to Gemfile.lock" do lockfile_should_be <<-L GEM specs: PLATFORMS ruby DEPENDENCIES RUBY VERSION ruby 2.1.3p100 BUNDLED WITH #{Bundler::VERSION} L end it "updates Gemfile.lock with updated incompatible ruby version" do install_gemfile <<-G ::RUBY_VERSION = '2.2.3' ::RUBY_PATCHLEVEL = 100 ruby '~> 2.2.0' G lockfile_should_be <<-L GEM specs: PLATFORMS ruby DEPENDENCIES RUBY VERSION ruby 2.2.3p100 BUNDLED WITH #{Bundler::VERSION} L end end end describe "when Bundler root contains regex chars" do before do root_dir = tmp("foo[]bar") FileUtils.mkdir_p(root_dir) in_app_root_custom(root_dir) end it "doesn't blow up" do build_lib "foo" gemfile = <<-G gem 'foo', :path => "#{lib_path("foo-1.0")}" G File.open("Gemfile", "w") do |file| file.puts gemfile end bundle :install expect(exitstatus).to eq(0) if exitstatus end end describe "when requesting a quiet install via --quiet" do it "should be quiet" do gemfile <<-G gem 'rack' G bundle :install, :quiet => true expect(out).to include("Could not find gem 'rack'") expect(out).to_not include("Your Gemfile has no gem server sources") end end describe "when bundle path does not have write access" do before do FileUtils.mkdir_p(bundled_app("vendor")) gemfile <<-G source "file://#{gem_repo1}" gem 'rack' G end it "should display a proper message to explain the problem" do FileUtils.chmod(0o500, bundled_app("vendor")) bundle :install, :path => "vendor" expect(out).to include(bundled_app("vendor").to_s) expect(out).to include("grant write permissions") end end describe "when bundle install is executed with unencoded authentication" do before do gemfile <<-G source 'https://rubygems.org/' gem 'bundler' G end it "should display a helpful messag explaining how to fix it" do bundle :install, :env => { "BUNDLE_RUBYGEMS__ORG" => "user:pass{word" } expect(exitstatus).to eq(17) if exitstatus expect(out).to eq("Please CGI escape your usernames and passwords before " \ "setting them for authentication.") end end end