aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHomu <homu@barosl.com>2016-10-22 07:10:45 +0900
committerHomu <homu@barosl.com>2016-10-22 07:10:45 +0900
commit3ccc0db369267bb477608dfef3b0aa645eeceb33 (patch)
tree3f8fc1ad7d6cd5e38e18547a33b6738730523303
parent03c864aa348b056ac2962aa6f3593726ccdad0ae (diff)
parent9c1c3a0e3a3cf5b65b5f6d499eb368de4ec23dff (diff)
downloadbundler-3ccc0db369267bb477608dfef3b0aa645eeceb33.tar.gz
Auto merge of #5061 - chrismo:cons_outdated, r=indirect
Conservative updates on outdated Add conservative resolving behavior to outdated command. - [x] convert existing flags to --filter-* - [x] deal with strict flag - [x] make a 2.0 issue to consider making strict flags more consistent - [x] fix #5065 (outdated filter options don't work with `--strict') - [x] fix #5076 (outdated shouldn't say "Bundle up to date!" if results are just filtered out.) - [ ] document breaking change reasons? (_commit comment has something at least now_) - [x] what about `bundle show --outdated`? (_it's a much simpler version ... prolly just going to leave it alone for now?_) The flags as passed to the GemVersionPromoter _change_ resolution. <=1.13.2 of bundle outdated, those flags merely filter the output, with no influence on resolution. If the lockfile is set to foo 1.0.0, and all of the following exist: 1.0.1, 1.1.0, 2.0.0, then <=1.13.2 bundle outdated currently will show: `foo (newest 2.0.0, installed 1.0.0)` <=1.13.2 `bundle outdated --minor` simply filters away that line and won't show it. With these changes, `bundle outdated --minor` would be fed to the GemVersionPromoter and actually only resolve `foo` up to `1.1.0`. This gist shows how it currently works, filtering the output: https://gist.github.com/chrismo/0bc6cfa00f539787101a9a2c900616d3 It's unfortunate timing. They were only added in 1.12 ... I'm biased, but feel like the affect the flags have on resolution is of greater value, and would be better to keep in sync with how they work fed to the `bundle update` command as of 1.13, and we could add new --filter-patch flags to replace what they do currently. IIRC, there was some confusion at the time that Andre perhaps even thought these flags as of 1.12 would be affecting what the newest would resolve to, instead of just filtering the output, so - _if_ I'm remembering correctly, that's also influencing my opinion. But, I can be swayed by the breaking behavior argument. from @indirect in [this comment](https://github.com/bundler/bundler/pull/4841#discussion_r82021277): "IMO, this is what we were trying to do in 1.12, and failed to do because resolving is complicated. :/ I would be okay with this change on the grounds that the previous flags were documented so it sounded like they cause the new resolver aware behavior. 👍"
-rw-r--r--lib/bundler/cli.rb14
-rw-r--r--lib/bundler/cli/common.rb10
-rw-r--r--lib/bundler/cli/lock.rb2
-rw-r--r--lib/bundler/cli/outdated.rb36
-rw-r--r--lib/bundler/cli/update.rb2
-rw-r--r--spec/commands/outdated_spec.rb190
6 files changed, 221 insertions, 33 deletions
diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb
index 6ee9adf4..37556f49 100644
--- a/lib/bundler/cli.rb
+++ b/lib/bundler/cli.rb
@@ -270,6 +270,9 @@ module Bundler
in the given source. Calling outdated with [GEM [GEM]] will only check for newer
versions of the given gems. Prerelease gems are ignored by default. If your gems
are up to date, Bundler will exit with a status of 0. Otherwise, it will exit 1.
+
+ For more information on conservative resolution options (--major, --minor,
+ --patch, --strict) see documentation on the same options on the update command.
D
method_option "group", :aliases => "--group", :type => :string, :banner => "List gems from a specific group"
method_option "groups", :aliases => "--groups", :type => :boolean, :banner => "List gems organized by groups"
@@ -279,9 +282,14 @@ module Bundler
method_option "source", :type => :array, :banner => "Check against a specific source"
method_option "strict", :type => :boolean, :banner =>
"Only list newer versions allowed by your Gemfile requirements"
- method_option "major", :type => :boolean, :banner => "Only list major newer versions"
- method_option "minor", :type => :boolean, :banner => "Only list minor newer versions"
- method_option "patch", :type => :boolean, :banner => "Only list patch newer versions"
+ method_option "update-strict", :type => :boolean, :banner =>
+ "Strict conservative resolution, do not allow any gem to be updated past latest --patch/--minor/--major"
+ method_option "minor", :type => :boolean, :banner => "Prefer updating only to next minor version"
+ method_option "major", :type => :boolean, :banner => "Prefer updating to next major version (default)"
+ method_option "patch", :type => :boolean, :banner => "Prefer updating only to next patch version"
+ method_option "filter-major", :type => :boolean, :banner => "Only list major newer versions"
+ method_option "filter-minor", :type => :boolean, :banner => "Only list minor newer versions"
+ method_option "filter-patch", :type => :boolean, :banner => "Only list patch newer versions"
method_option "parseable", :aliases => "--porcelain", :type => :boolean, :banner =>
"Use minimal formatting for more parseable output"
def outdated(*gems)
diff --git a/lib/bundler/cli/common.rb b/lib/bundler/cli/common.rb
index 6f45322d..40a429ba 100644
--- a/lib/bundler/cli/common.rb
+++ b/lib/bundler/cli/common.rb
@@ -53,13 +53,17 @@ module Bundler
message
end
- def self.config_gem_version_promoter(definition, opts)
- patch_level = [:major, :minor, :patch].select {|v| opts.keys.include?(v.to_s) }
+ def self.configure_gem_version_promoter(definition, options)
+ patch_level = patch_level_options(options)
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]
+ gvp.strict = options[:strict] || options["update-strict"]
end
end
+
+ def self.patch_level_options(options)
+ [:major, :minor, :patch].select {|v| options.keys.include?(v.to_s) }
+ end
end
end
diff --git a/lib/bundler/cli/lock.rb b/lib/bundler/cli/lock.rb
index 225a07aa..2ccaba86 100644
--- a/lib/bundler/cli/lock.rb
+++ b/lib/bundler/cli/lock.rb
@@ -25,7 +25,7 @@ module Bundler
update = { :gems => update, :lock_shared_dependencies => options[:conservative] } if update.is_a?(Array)
definition = Bundler.definition(update)
- Bundler::CLI::Common.config_gem_version_promoter(Bundler.definition, options) if options[:update]
+ Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) if options[:update]
options["remove-platform"].each do |platform|
definition.remove_platform(platform)
diff --git a/lib/bundler/cli/outdated.rb b/lib/bundler/cli/outdated.rb
index 5729c07f..1d5b8e02 100644
--- a/lib/bundler/cli/outdated.rb
+++ b/lib/bundler/cli/outdated.rb
@@ -31,6 +31,10 @@ module Bundler
Bundler.definition(:gems => gems, :sources => sources)
end
+ Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options)
+ # the patch level options don't work without strict also being true
+ strict = options[:strict] || Bundler::CLI::Common.patch_level_options(options).any?
+
definition_resolution = proc { options[:local] ? definition.resolve_with_cache! : definition.resolve_remotely! }
if options[:parseable]
Bundler.ui.silence(&definition_resolution)
@@ -49,7 +53,7 @@ module Bundler
dependency = current_dependencies[current_spec.name]
- if options[:strict]
+ if strict
active_spec = definition.specs.detect {|spec| spec.name == current_spec.name && spec.platform == current_spec.platform }
else
active_specs = definition.index[current_spec.name].select {|spec| spec.platform == current_spec.platform }.sort_by(&:version)
@@ -57,11 +61,11 @@ module Bundler
active_spec = active_specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? }
end
active_spec = active_specs.last
+ end
- if options[:major] || options[:minor] || options[:patch]
- update_present = update_present_via_semver_portions(current_spec, active_spec, options)
- active_spec = nil unless update_present
- end
+ if options["filter-major"] || options["filter-minor"] || options["filter-patch"]
+ update_present = update_present_via_semver_portions(current_spec, active_spec, options)
+ active_spec = nil unless update_present
end
next if active_spec.nil?
@@ -90,7 +94,7 @@ module Bundler
end
if outdated_gems_list.empty?
- Bundler.ui.info "Bundle up to date!\n" unless options[:parseable]
+ display_nothing_outdated_message
else
unless options[:parseable]
if options[:pre]
@@ -137,6 +141,18 @@ module Bundler
private
+ def display_nothing_outdated_message
+ unless options[:parseable]
+ filter_options = options.keys & %w(filter-major filter-minor filter-patch)
+ if filter_options.any?
+ display = filter_options.map {|o| o.sub("filter-", "") }.join(" or ")
+ Bundler.ui.info "No #{display} updates to display.\n"
+ else
+ Bundler.ui.info "Bundle up to date!\n"
+ end
+ end
+ end
+
def print_gem(current_spec, active_spec, dependency, groups, options_include_groups)
spec_version = "#{active_spec.version}#{active_spec.git_version}"
current_version = "#{current_spec.version}#{current_spec.git_version}"
@@ -167,15 +183,15 @@ module Bundler
active_major = active_spec.version.segments.first
update_present = false
- update_present = active_major > current_major if options[:major]
+ update_present = active_major > current_major if options["filter-major"]
- if !update_present && (options[:minor] || options[:patch]) && current_major == active_major
+ if !update_present && (options["filter-minor"] || options["filter-patch"]) && current_major == active_major
current_minor = get_version_semver_portion_value(current_spec, 1)
active_minor = get_version_semver_portion_value(active_spec, 1)
- update_present = active_minor > current_minor if options[:minor]
+ update_present = active_minor > current_minor if options["filter-minor"]
- if !update_present && options[:patch] && current_minor == active_minor
+ if !update_present && options["filter-patch"] && current_minor == active_minor
current_patch = get_version_semver_portion_value(current_spec, 2)
active_patch = get_version_semver_portion_value(active_spec, 2)
diff --git a/lib/bundler/cli/update.rb b/lib/bundler/cli/update.rb
index 585fe38e..bc8231d3 100644
--- a/lib/bundler/cli/update.rb
+++ b/lib/bundler/cli/update.rb
@@ -41,7 +41,7 @@ module Bundler
:lock_shared_dependencies => options[:conservative])
end
- Bundler::CLI::Common.config_gem_version_promoter(Bundler.definition, options)
+ Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options)
Bundler::Fetcher.disable_endpoint = options["full-index"]
diff --git a/spec/commands/outdated_spec.rb b/spec/commands/outdated_spec.rb
index ab00e64b..b3d9a97b 100644
--- a/spec/commands/outdated_spec.rb
+++ b/spec/commands/outdated_spec.rb
@@ -309,6 +309,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
@@ -416,7 +472,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")
@@ -456,59 +512,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")
+ expect(out).to include("minor (newest")
+ expect(out).to include("major (newest")
+ 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")
+ expect(out).to include("major (newest")
+ 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