Skip to content

Commit

Permalink
Add conservative update options to bundle lock
Browse files Browse the repository at this point in the history
Fix rubygems#4912.

The bundle lock command produces a lockfile same as bundle update but
won't install all the gems. If the `--update` option is fed to `bundle
lock` you can also specify the `--patch`, `--minor`, `--major` and
`--strict` options added to `bundle update` in 1.13.
chrismo committed Oct 4, 2016

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
1 parent e499c51 commit 565d5ad
Showing 5 changed files with 72 additions and 7 deletions.
8 changes: 8 additions & 0 deletions lib/bundler/cli.rb
Original file line number Diff line number Diff line change
@@ -457,6 +457,14 @@ def inject(name, version, *gems)
"add a new platform to the lockfile"
method_option "remove-platform", :type => :array, :default => [], :banner =>
"remove a platform from the lockfile"
method_option "patch", :type => :boolean, :hide => true, :banner =>
"Prefer updating only to next patch version"
method_option "minor", :type => :boolean, :hide => true, :banner =>
"Prefer updating only to next minor version"
method_option "major", :type => :boolean, :hide => true, :banner =>
"Prefer updating to next major version (default)"
method_option "strict", :type => :boolean, :hide => true, :banner =>
"Do not allow any gem to be updated past latest --patch/--minor/--major"
def lock
require "bundler/cli/lock"
Lock.new(options).run
9 changes: 9 additions & 0 deletions lib/bundler/cli/common.rb
Original file line number Diff line number Diff line change
@@ -52,5 +52,14 @@ def self.gem_not_found_message(missing_gem_name, alternatives)
message += "\nDid you mean #{suggestions}?" if suggestions
message
end

def self.config_gem_version_promoter(definition, opts)
patch_level = [:major, :minor, :patch].select {|v| opts.keys.include?(v.to_s) }
raise InvalidOption, "Provide only one of the following options: #{patch_level.join(", ")}" unless patch_level.length <= 1
definition.gem_version_promoter.tap do |gvp|
gvp.level = patch_level.first || :major
gvp.strict = opts[:strict]
end
end
end
end
4 changes: 4 additions & 0 deletions lib/bundler/cli/lock.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# frozen_string_literal: true
require "bundler/cli/common"

module Bundler
class CLI::Lock
attr_reader :options
@@ -23,6 +25,8 @@ def run
update = { :gems => update } if update.is_a?(Array)
definition = Bundler.definition(update)

Bundler::CLI::Common.config_gem_version_promoter(Bundler.definition, options) if options[:update]

options["remove-platform"].each do |platform|
definition.remove_platform(platform)
end
10 changes: 3 additions & 7 deletions lib/bundler/cli/update.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# frozen_string_literal: true
require "bundler/cli/common"

module Bundler
class CLI::Update
attr_reader :options, :gems
@@ -27,7 +29,6 @@ def run
names = Bundler.locked_gems.specs.map(&:name)
gems.each do |g|
next if names.include?(g)
require "bundler/cli/common"
raise GemNotFound, Bundler::CLI::Common.gem_not_found_message(g, names)
end

@@ -39,12 +40,7 @@ def run
Bundler.definition(:gems => gems, :sources => sources, :ruby => options[:ruby])
end

patch_level = [:major, :minor, :patch].select {|v| options.keys.include?(v.to_s) }
raise InvalidOption, "Provide only one of the following options: #{patch_level.join(", ")}" unless patch_level.length <= 1
Bundler.definition.gem_version_promoter.tap do |gvp|
gvp.level = patch_level.first || :major
gvp.strict = options[:strict]
end
Bundler::CLI::Common.config_gem_version_promoter(Bundler.definition, options)

Bundler::Fetcher.disable_endpoint = options["full-index"]

48 changes: 48 additions & 0 deletions spec/commands/lock_spec.rb
Original file line number Diff line number Diff line change
@@ -106,6 +106,54 @@ def read_lockfile(file = "Gemfile.lock")
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"

0 comments on commit 565d5ad

Please sign in to comment.