# frozen_string_literal: true RSpec.describe "bundle check" do it "returns success when the Gemfile is satisfied" do install_gemfile <<-G source "https://gem.repo1" gem "rails" G bundle :check expect(out).to include("The Gemfile's dependencies are satisfied") end it "works with the --gemfile flag when not in the directory" do install_gemfile <<-G source "https://gem.repo1" gem "rails" G bundle "check --gemfile bundled_app/Gemfile", dir: tmp expect(out).to include("The Gemfile's dependencies are satisfied") end it "creates a Gemfile.lock by default if one does not exist" do install_gemfile <<-G source "https://gem.repo1" gem "rails" G FileUtils.rm(bundled_app_lock) bundle "check" expect(bundled_app_lock).to exist end it "does not create a Gemfile.lock if --dry-run was passed" do install_gemfile <<-G source "https://gem.repo1" gem "rails" G FileUtils.rm(bundled_app_lock) bundle "check --dry-run" expect(bundled_app_lock).not_to exist end it "prints an error that shows missing gems" do system_gems ["rails-2.3.2"], path: default_bundle_path gemfile <<-G source "https://gem.repo1" gem "rails" G bundle :check, raise_on_error: false expect(err).to include("The following gems are missing") expect(err).to include(" * rake (13.2.1)") expect(err).to include(" * actionpack (2.3.2)") expect(err).to include(" * activerecord (2.3.2)") expect(err).to include(" * actionmailer (2.3.2)") expect(err).to include(" * activeresource (2.3.2)") expect(err).to include(" * activesupport (2.3.2)") expect(err).to include("Install missing gems with `bundle install`") end it "prints an error that shows missing gems if a Gemfile.lock does not exist and a toplevel dependency is missing" do gemfile <<-G source "https://gem.repo1" gem "rails" G bundle :check, raise_on_error: false expect(exitstatus).to be > 0 expect(err).to include("The following gems are missing") expect(err).to include(" * rails (2.3.2)") expect(err).to include(" * rake (13.2.1)") expect(err).to include(" * actionpack (2.3.2)") expect(err).to include(" * activerecord (2.3.2)") expect(err).to include(" * actionmailer (2.3.2)") expect(err).to include(" * activeresource (2.3.2)") expect(err).to include(" * activesupport (2.3.2)") expect(err).to include("Install missing gems with `bundle install`") end it "prints a generic error if gem git source is not checked out" do build_git "foo", path: lib_path("foo") bundle "config path vendor/bundle" install_gemfile <<-G source "https://gem.repo1" gem "foo", git: "#{lib_path("foo")}" G FileUtils.rm_r bundled_app("vendor/bundle") bundle :check, raise_on_error: false expect(exitstatus).to eq 1 expect(err).to include("Bundler can't satisfy your Gemfile's dependencies.") end it "prints a generic message if you changed your lockfile" do build_repo2 do build_gem "rails_pinned_to_old_activesupport" do |s| s.add_dependency "activesupport", "= 1.2.3" end end install_gemfile <<-G source "https://gem.repo2" gem 'rails' G gemfile <<-G source "https://gem.repo2" gem "rails" gem "rails_pinned_to_old_activesupport" G bundle :check, raise_on_error: false expect(err).to include("Bundler can't satisfy your Gemfile's dependencies.") end it "remembers --without option from install", bundler: "< 3" do gemfile <<-G source "https://gem.repo1" group :foo do gem "myrack" end G bundle "install --without foo" bundle "check" expect(out).to include("The Gemfile's dependencies are satisfied") end it "uses the without setting" do bundle "config set without foo" install_gemfile <<-G source "https://gem.repo1" group :foo do gem "myrack" end G bundle "check" expect(out).to include("The Gemfile's dependencies are satisfied") end it "ensures that gems are actually installed and not just cached" do gemfile <<-G source "https://gem.repo1" gem "myrack", :group => :foo G bundle "config set --local without foo" bundle :install gemfile <<-G source "https://gem.repo1" gem "myrack" G bundle "check", raise_on_error: false expect(err).to include("* myrack (1.0.0)") expect(exitstatus).to eq(1) end it "ensures that gems are actually installed and not just cached in applications' cache" do gemfile <<-G source "https://gem.repo1" gem "myrack" G bundle "config set --local path vendor/bundle" bundle :cache gem_command "uninstall myrack", env: { "GEM_HOME" => vendored_gems.to_s } bundle "check", raise_on_error: false expect(err).to include("* myrack (1.0.0)") expect(exitstatus).to eq(1) end it "ignores missing gems restricted to other platforms" do gemfile <<-G source "https://gem.repo1" gem "myrack" platforms :#{not_local_tag} do gem "activesupport" end G system_gems "myrack-1.0.0", path: default_bundle_path lockfile <<-G GEM remote: https://gem.repo1/ specs: activesupport (2.3.5) myrack (1.0.0) PLATFORMS #{generic_local_platform} #{not_local} DEPENDENCIES myrack activesupport G bundle :check expect(out).to include("The Gemfile's dependencies are satisfied") end it "works with env conditionals" do gemfile <<-G source "https://gem.repo1" gem "myrack" env :NOT_GOING_TO_BE_SET do gem "activesupport" end G system_gems "myrack-1.0.0", path: default_bundle_path lockfile <<-G GEM remote: https://gem.repo1/ specs: activesupport (2.3.5) myrack (1.0.0) PLATFORMS #{generic_local_platform} #{not_local} DEPENDENCIES myrack activesupport G bundle :check expect(out).to include("The Gemfile's dependencies are satisfied") end it "outputs an error when the default Gemfile is not found" do bundle :check, raise_on_error: false expect(exitstatus).to eq(10) expect(err).to include("Could not locate Gemfile") end it "does not output fatal error message" do bundle :check, raise_on_error: false expect(exitstatus).to eq(10) expect(err).not_to include("Unfortunately, a fatal error has occurred. ") end it "fails when there's no lockfile and frozen is set" do install_gemfile <<-G source "https://gem.repo1" gem "foo" G bundle "config set --local deployment true" bundle "install" FileUtils.rm(bundled_app_lock) bundle :check, raise_on_error: false expect(last_command).to be_failure end context "--path", bundler: "< 3" do context "after installing gems in the proper directory" do before do gemfile <<-G source "https://gem.repo1" gem "rails" G bundle "install --path vendor/bundle" FileUtils.rm_r(bundled_app(".bundle")) end it "returns success" do bundle "check --path vendor/bundle" expect(out).to include("The Gemfile's dependencies are satisfied") end it "should write to .bundle/config" do bundle "check --path vendor/bundle" bundle "check" end end context "after installing gems on a different directory" do before do install_gemfile <<-G source "https://gem.repo1" gem "rails" G bundle "check --path vendor/bundle", raise_on_error: false end it "returns false" do expect(exitstatus).to eq(1) expect(err).to match(/The following gems are missing/) end end end describe "when locked" do before :each do system_gems "myrack-1.0.0" install_gemfile <<-G source "https://gem.repo1" gem "myrack", "1.0" G end it "returns success when the Gemfile is satisfied" do bundle :install bundle :check expect(out).to include("The Gemfile's dependencies are satisfied") end it "shows what is missing with the current Gemfile if it is not satisfied" do FileUtils.rm_r default_bundle_path system_gems :bundler bundle :check, raise_on_error: false expect(err).to match(/The following gems are missing/) expect(err).to include("* myrack (1.0") end end describe "when locked with multiple dependents with different requirements" do before :each do build_repo4 do build_gem "depends_on_myrack" do |s| s.add_dependency "myrack", ">= 1.0" end build_gem "also_depends_on_myrack" do |s| s.add_dependency "myrack", "~> 1.0" end build_gem "myrack" end gemfile <<-G source "https://gem.repo4" gem "depends_on_myrack" gem "also_depends_on_myrack" G bundle "lock" end it "shows what is missing with the current Gemfile without duplications" do bundle :check, raise_on_error: false expect(err).to match(/The following gems are missing/) expect(err).to include("* myrack (1.0").once end end describe "when locked under multiple platforms" do before :each do build_repo4 do build_gem "myrack" end gemfile <<-G source "https://gem.repo4" gem "myrack" G lockfile <<-L GEM remote: https://gem.repo4/ specs: myrack (1.0) PLATFORMS ruby #{local_platform} DEPENDENCIES myrack BUNDLED WITH #{Bundler::VERSION} L end it "shows what is missing with the current Gemfile without duplications" do bundle :check, raise_on_error: false expect(err).to match(/The following gems are missing/) expect(err).to include("* myrack (1.0").once end end describe "when using only scoped rubygems sources" do before do gemfile <<~G source "https://gem.repo2" source "https://gem.repo1" do gem "myrack" end G end it "returns success when the Gemfile is satisfied" do system_gems "myrack-1.0.0", path: default_bundle_path bundle :check, artifice: "compact_index" expect(out).to include("The Gemfile's dependencies are satisfied") end end describe "when using only scoped rubygems sources with indirect dependencies" do before do build_repo4 do build_gem "depends_on_myrack" do |s| s.add_dependency "myrack" end build_gem "myrack" end gemfile <<~G source "https://gem.repo1" source "https://gem.repo4" do gem "depends_on_myrack" end G end it "returns success when the Gemfile is satisfied and generates a correct lockfile" do system_gems "depends_on_myrack-1.0", "myrack-1.0", gem_repo: gem_repo4, path: default_bundle_path bundle :check, artifice: "compact_index" checksums = checksums_section_when_enabled do |c| c.checksum gem_repo4, "depends_on_myrack", "1.0" c.checksum gem_repo4, "myrack", "1.0" end expect(out).to include("The Gemfile's dependencies are satisfied") expect(lockfile).to eq <<~L GEM remote: https://gem.repo1/ specs: GEM remote: https://gem.repo4/ specs: depends_on_myrack (1.0) myrack myrack (1.0) PLATFORMS #{lockfile_platforms} DEPENDENCIES depends_on_myrack! #{checksums} BUNDLED WITH #{Bundler::VERSION} L end end context "with gemspec directive and scoped sources" do before do build_repo4 do build_gem "awesome_print" end build_repo2 do build_gem "dex-dispatch-engine" end build_lib("bundle-check-issue", path: tmp("bundle-check-issue")) do |s| s.write "Gemfile", <<-G source "https://localgemserver.test" gemspec source "https://localgemserver.test/extra" do gem "dex-dispatch-engine" end G s.add_dependency "awesome_print" end bundle "install", artifice: "compact_index_extra", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }, dir: tmp("bundle-check-issue") end it "does not corrupt lockfile when changing version" do version_file = tmp("bundle-check-issue/bundle-check-issue.gemspec") File.write(version_file, File.read(version_file).gsub(/s\.version = .+/, "s.version = '9999'")) bundle "check --verbose", dir: tmp("bundle-check-issue") lockfile = File.read(tmp("bundle-check-issue/Gemfile.lock")) checksums = checksums_section_when_enabled(lockfile) do |c| c.checksum gem_repo4, "awesome_print", "1.0" c.no_checksum "bundle-check-issue", "9999" c.checksum gem_repo2, "dex-dispatch-engine", "1.0" end expect(lockfile).to eq <<~L PATH remote: . specs: bundle-check-issue (9999) awesome_print GEM remote: https://localgemserver.test/ specs: awesome_print (1.0) GEM remote: https://localgemserver.test/extra/ specs: dex-dispatch-engine (1.0) PLATFORMS #{lockfile_platforms} DEPENDENCIES bundle-check-issue! dex-dispatch-engine! #{checksums} BUNDLED WITH #{Bundler::VERSION} L end end context "with scoped and unscoped sources" do it "does not corrupt lockfile" do build_repo2 do build_gem "foo" build_gem "wadus" build_gem("baz") {|s| s.add_dependency "wadus" } end build_repo4 do build_gem "bar" end bundle "config set path.system true" # Add all gems to ensure all gems are installed so that a bundle check # would be successful install_gemfile(<<-G, artifice: "compact_index_extra") source "https://gem.repo2" source "https://gem.repo4" do gem "bar" end gem "foo" gem "baz" G original_lockfile = lockfile # Remove "baz" gem from the Gemfile, and bundle install again to generate # a functional lockfile with no "baz" dependency or "wadus" transitive # dependency install_gemfile(<<-G, artifice: "compact_index_extra") source "https://gem.repo2" source "https://gem.repo4" do gem "bar" end gem "foo" G # Add back "baz" gem back to the Gemfile, but _crucially_ we do not perform a # bundle install gemfile(gemfile + 'gem "baz"') bundle :check, verbose: true # Bundle check should succeed and restore the lockfile to its original # state expect(lockfile).to eq(original_lockfile) end end describe "BUNDLED WITH" do def lock_with(bundler_version = nil) lock = <<~L GEM remote: https://gem.repo1/ specs: myrack (1.0.0) PLATFORMS #{lockfile_platforms} DEPENDENCIES myrack L if bundler_version lock += "\nBUNDLED WITH\n #{bundler_version}\n" end lock end before do bundle "config set --local path vendor/bundle" install_gemfile <<-G source "https://gem.repo1" gem "myrack" G end context "is not present" do it "does not change the lock" do lockfile lock_with(nil) bundle :check expect(lockfile).to eq lock_with(nil) end end context "is newer" do it "does not change the lock and does not warn" do lockfile lock_with(Bundler::VERSION.succ) bundle :check expect(err).to be_empty expect(lockfile).to eq lock_with(Bundler::VERSION.succ) end end context "is older" do it "does not change the lock" do system_gems "bundler-1.18.0" lockfile lock_with("1.18.0") bundle :check expect(lockfile).to eq lock_with("1.18.0") end end end end