ruby/spec/bundler/commands/check_spec.rb
Samuel Giddins c5fd94073f
[rubygems/rubygems] Refactor to checksums stored via source
This gets the specs passing, and handles the fact that we expect
checkums to be pinned only to a particular source

This also avoids reading in .gem files during lockfile generation,
instead allowing us to query the source for each resolved gem to grab
the checksum

Finally, this opens up a route to having user-stored checksum databases,
similar to how other package managers do this!

Add checksums to dev lockfiles

Handle full name conflicts from different original_platforms when adding checksums to store from compact index

Specs passing on Bundler 3

86c7084e1c
2023-10-23 13:59:01 +09:00

563 lines
14 KiB
Ruby

# frozen_string_literal: true
RSpec.describe "bundle check" do
it "returns success when the Gemfile is satisfied" do
install_gemfile <<-G
source "#{file_uri_for(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 "#{file_uri_for(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 "#{file_uri_for(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 "#{file_uri_for(gem_repo1)}"
gem "rails"
G
FileUtils.rm(bundled_app_lock)
bundle "check --dry-run"
expect(bundled_app_lock).not_to exist
end
it "prints a generic error if the missing gems are unresolvable" do
system_gems ["rails-2.3.2"]
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
bundle :check, :raise_on_error => false
expect(err).to include("Bundler can't satisfy your Gemfile's dependencies.")
end
it "prints a generic error if a Gemfile.lock does not exist and a toplevel dependency does not exist" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
bundle :check, :raise_on_error => false
expect(exitstatus).to be > 0
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 "#{file_uri_for(gem_repo2)}"
gem 'rails'
G
gemfile <<-G
source "#{file_uri_for(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 "#{file_uri_for(gem_repo1)}"
group :foo do
gem "rack"
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 "#{file_uri_for(gem_repo1)}"
group :foo do
gem "rack"
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 "#{file_uri_for(gem_repo1)}"
gem "rack", :group => :foo
G
bundle "config set --local without foo"
bundle :install
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
G
bundle "check", :raise_on_error => false
expect(err).to include("* rack (1.0.0)")
expect(exitstatus).to eq(1)
end
it "ensures that gems are actually installed and not just cached in applications' cache" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
G
bundle "config set --local path vendor/bundle"
bundle :cache
gem_command "uninstall rack", :env => { "GEM_HOME" => vendored_gems.to_s }
bundle "check", :raise_on_error => false
expect(err).to include("* rack (1.0.0)")
expect(exitstatus).to eq(1)
end
it "ignores missing gems restricted to other platforms" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
platforms :#{not_local_tag} do
gem "activesupport"
end
G
system_gems "rack-1.0.0", :path => default_bundle_path
lockfile <<-G
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
activesupport (2.3.5)
rack (1.0.0)
PLATFORMS
#{generic_local_platform}
#{not_local}
DEPENDENCIES
rack
activesupport
G
bundle :check
expect(out).to include("The Gemfile's dependencies are satisfied")
end
it "works with env conditionals" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
env :NOT_GOING_TO_BE_SET do
gem "activesupport"
end
G
system_gems "rack-1.0.0", :path => default_bundle_path
lockfile <<-G
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
activesupport (2.3.5)
rack (1.0.0)
PLATFORMS
#{generic_local_platform}
#{not_local}
DEPENDENCIES
rack
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 lock file and frozen is set" do
install_gemfile <<-G
source "#{file_uri_for(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 "#{file_uri_for(gem_repo1)}"
gem "rails"
G
bundle "install --path vendor/bundle"
FileUtils.rm_rf(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 "#{file_uri_for(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 "rack-1.0.0"
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack", "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
simulate_new_machine
bundle :check, :raise_on_error => false
expect(err).to match(/The following gems are missing/)
expect(err).to include("* rack (1.0")
end
end
describe "when locked with multiple dependents with different requirements" do
before :each do
build_repo4 do
build_gem "depends_on_rack" do |s|
s.add_dependency "rack", ">= 1.0"
end
build_gem "also_depends_on_rack" do |s|
s.add_dependency "rack", "~> 1.0"
end
build_gem "rack"
end
gemfile <<-G
source "#{file_uri_for(gem_repo4)}"
gem "depends_on_rack"
gem "also_depends_on_rack"
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("* rack (1.0").once
end
end
describe "when locked under multiple platforms" do
before :each do
build_repo4 do
build_gem "rack"
end
gemfile <<-G
source "#{file_uri_for(gem_repo4)}"
gem "rack"
G
lockfile <<-L
GEM
remote: #{file_uri_for(gem_repo4)}/
specs:
rack (1.0)
PLATFORMS
ruby
#{local_platform}
DEPENDENCIES
rack
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "shows what is missing with the current Gemfile without duplications" do
bundle :check, :raise_on_error => false
expect(err).to match(/The following gems are missing/)
expect(err).to include("* rack (1.0").once
end
end
describe "when using only scoped rubygems sources" do
before do
gemfile <<~G
source "#{file_uri_for(gem_repo2)}"
source "#{file_uri_for(gem_repo1)}" do
gem "rack"
end
G
end
it "returns success when the Gemfile is satisfied" do
system_gems "rack-1.0.0", :path => default_bundle_path
bundle :check
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_rack" do |s|
s.add_dependency "rack"
end
build_gem "rack"
end
gemfile <<~G
source "#{file_uri_for(gem_repo1)}"
source "#{file_uri_for(gem_repo4)}" do
gem "depends_on_rack"
end
G
end
it "returns success when the Gemfile is satisfied and generates a correct lockfile" do
system_gems "depends_on_rack-1.0", "rack-1.0", :gem_repo => gem_repo4, :path => default_bundle_path
bundle :check
expect(out).to include("The Gemfile's dependencies are satisfied")
expect(lockfile).to eq <<~L
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
GEM
remote: #{file_uri_for(gem_repo4)}/
specs:
depends_on_rack (1.0)
rack
rack (1.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
depends_on_rack!
CHECKSUMS
depends_on_rack (1.0)
rack (1.0)
BUNDLED WITH
#{Bundler::VERSION}
L
end
end
context "with gemspec directive and scoped sources" do
before do
build_repo4 do
build_gem "awesome_print"
end
build_repo2 do
build_gem "dex-dispatch-engine"
end
build_lib("bundle-check-issue", :path => tmp.join("bundle-check-issue")) do |s|
s.write "Gemfile", <<-G
source "https://localgemserver.test"
gemspec
source "https://localgemserver.test/extra" do
gem "dex-dispatch-engine"
end
G
s.add_dependency "awesome_print"
end
bundle "install", :artifice => "compact_index_extra", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }, :dir => tmp.join("bundle-check-issue")
end
it "does not corrupt lockfile when changing version" do
version_file = tmp.join("bundle-check-issue/bundle-check-issue.gemspec")
File.write(version_file, File.read(version_file).gsub(/s\.version = .+/, "s.version = '9999'"))
bundle "check --verbose", :dir => tmp.join("bundle-check-issue")
expect(File.read(tmp.join("bundle-check-issue/Gemfile.lock"))).to eq <<~L
PATH
remote: .
specs:
bundle-check-issue (9999)
awesome_print
GEM
remote: https://localgemserver.test/
specs:
awesome_print (1.0)
GEM
remote: https://localgemserver.test/extra/
specs:
dex-dispatch-engine (1.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
bundle-check-issue!
dex-dispatch-engine!
CHECKSUMS
#{checksum_for_repo_gem gem_repo4, "awesome_print", "1.0"}
bundle-check-issue (9999)
#{checksum_for_repo_gem gem_repo2, "dex-dispatch-engine", "1.0"}
BUNDLED WITH
#{Bundler::VERSION}
L
end
end
describe "BUNDLED WITH" do
def lock_with(bundler_version = nil)
lock = <<~L
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
rack
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 "#{file_uri_for(gem_repo1)}"
gem "rack"
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