From 28b20ddd49751d4f52f73f8c7716336bd11d9374 Mon Sep 17 00:00:00 2001 From: Eric Mueller Date: Wed, 15 Jul 2026 15:31:16 -0700 Subject: [PATCH 1/4] Fix bundle outdated --groups to actually group output print_indented unconditionally sorted table rows by gem name, discarding the group clustering that --groups had already computed, so --groups produced output identical to plain outdated (#9333). Skip that re-sort when a --group/--groups option is active, since specs_for_outdated_check already sorts by name and group_by preserves that order within each group. Also fixes the outdated_spec.rb "--groups" test, which previously passed regardless of whether grouping worked because its expected output happened to match alphabetical-by-name ordering. --- lib/bundler/cli/outdated.rb | 6 +++--- spec/commands/outdated_spec.rb | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/bundler/cli/outdated.rb b/lib/bundler/cli/outdated.rb index f355955a5a70..6df79c82e016 100644 --- a/lib/bundler/cli/outdated.rb +++ b/lib/bundler/cli/outdated.rb @@ -209,7 +209,7 @@ def print_gems_table(gems_list) ) end - print_indented([table_header] + data) + print_indented([table_header] + data, !options_include_groups) end def print_gem(current_spec, active_spec, dependency, groups) @@ -323,7 +323,7 @@ def get_version_semver_portion_value(spec, version_portion_index) version_section.to_a[0].to_i end - def print_indented(matrix) + def print_indented(matrix, sort = true) header = matrix[0] data = matrix[1..-1] @@ -333,7 +333,7 @@ def print_indented(matrix) Bundler.ui.info justify(header, column_sizes) - data.sort_by! {|row| row[0] } + data.sort_by! {|row| row[0] } if sort data.each do |row| Bundler.ui.info justify(row, column_sizes) diff --git a/spec/commands/outdated_spec.rb b/spec/commands/outdated_spec.rb index e6a276cceafd..0f9652c4d5e8 100644 --- a/spec/commands/outdated_spec.rb +++ b/spec/commands/outdated_spec.rb @@ -274,6 +274,7 @@ def test_group_option(group) build_repo2 do build_git "foo", path: lib_path("foo") build_git "zebra", path: lib_path("zebra") + build_gem "zondrian", "1.2" end install_gemfile <<-G @@ -284,6 +285,7 @@ def test_group_option(group) group :development, :test do gem 'activesupport', '2.3.5' gem "duradura", '7.0' + gem "zondrian", '1.2' end G end @@ -298,15 +300,17 @@ def test_group_option(group) build_gem "activesupport", "3.0" build_gem "terranova", "9" build_gem "duradura", "8.0" + build_gem "zondrian", "1.3" end bundle "outdated --groups", raise_on_error: false expected_output = <<~TABLE.strip Gem Current Latest Requested Groups Release Date + terranova 8 9 = 8 default activesupport 2.3.5 3.0 = 2.3.5 development, test duradura 7.0 8.0 = 7.0 development, test - terranova 8 9 = 8 default + zondrian 1.2 1.3 = 1.2 development, test TABLE expect(out).to end_with(expected_output) From c4544e084265939bbfe36755b0780321b0bcbb83 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 15 Sep 2026 18:09:27 +0900 Subject: [PATCH 2/4] Keep bundle outdated --group sorted by gem name Skipping the name sort for --group left the rows in the order of their group sets, so a group spread over several sets was listed out of order. Filtering the name-sorted list directly keeps that order and makes the sort in print_indented unnecessary. Co-Authored-By: Claude Opus 5 --- lib/bundler/cli/outdated.rb | 17 ++++++----------- spec/commands/outdated_spec.rb | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/lib/bundler/cli/outdated.rb b/lib/bundler/cli/outdated.rb index 6df79c82e016..bb50c1169a53 100644 --- a/lib/bundler/cli/outdated.rb +++ b/lib/bundler/cli/outdated.rb @@ -101,13 +101,10 @@ def run } end - relevant_outdated_gems = if options_include_groups - outdated_gems.group_by {|g| g[:groups] }.sort.flat_map do |groups, gems| - contains_group = groups.split(", ").include?(options[:group]) - next unless options[:groups] || contains_group - - gems - end.compact + relevant_outdated_gems = if options[:groups] + outdated_gems.group_by {|g| g[:groups] }.sort.flat_map(&:last) + elsif options_include_groups + outdated_gems.select {|g| g[:groups].split(", ").include?(options[:group]) } else outdated_gems end @@ -209,7 +206,7 @@ def print_gems_table(gems_list) ) end - print_indented([table_header] + data, !options_include_groups) + print_indented([table_header] + data) end def print_gem(current_spec, active_spec, dependency, groups) @@ -323,7 +320,7 @@ def get_version_semver_portion_value(spec, version_portion_index) version_section.to_a[0].to_i end - def print_indented(matrix, sort = true) + def print_indented(matrix) header = matrix[0] data = matrix[1..-1] @@ -333,8 +330,6 @@ def print_indented(matrix, sort = true) Bundler.ui.info justify(header, column_sizes) - data.sort_by! {|row| row[0] } if sort - data.each do |row| Bundler.ui.info justify(row, column_sizes) end diff --git a/spec/commands/outdated_spec.rb b/spec/commands/outdated_spec.rb index 0f9652c4d5e8..db916892ed0d 100644 --- a/spec/commands/outdated_spec.rb +++ b/spec/commands/outdated_spec.rb @@ -231,6 +231,30 @@ def test_group_option(group) expect(out).to end_with(expected_output) end + + it "returns a sorted list of outdated gems from one group spread over several group sets" do + install_gemfile <<-G + source "https://gem.repo2" + + gem "weakling", "~> 0.0.1" + group :development do + gem "terranova", '8' + end + group :development, :test do + gem 'activesupport', '2.3.5' + end + G + + test_group_option("development") + + expected_output = <<~TABLE.strip + Gem Current Latest Requested Groups Release Date + activesupport 2.3.5 3.0 = 2.3.5 development, test + terranova 8 9 = 8 development + TABLE + + expect(out).to end_with(expected_output) + end end describe "with --groups option and outdated transitive dependencies" do From 8a0d6f72beb1ea7f59c275eacb23cb6edae93975 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 15 Sep 2026 18:10:05 +0900 Subject: [PATCH 3/4] Sort the group names of each gem in bundle outdated --groups The groups were joined in the order they were declared, so gems in `group :test, :development` and `group :development, :test` were listed in two separate sets. Co-Authored-By: Claude Opus 5 --- lib/bundler/cli/outdated.rb | 4 +++- spec/commands/outdated_spec.rb | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/bundler/cli/outdated.rb b/lib/bundler/cli/outdated.rb index bb50c1169a53..c86810730529 100644 --- a/lib/bundler/cli/outdated.rb +++ b/lib/bundler/cli/outdated.rb @@ -90,7 +90,9 @@ def run dependency = current_dependencies[current_spec.name] groups = "" if dependency && !options[:parseable] - groups = dependency.groups.join(", ") + groups = dependency.groups + groups = groups.sort if options_include_groups + groups = groups.join(", ") end outdated_gems << { diff --git a/spec/commands/outdated_spec.rb b/spec/commands/outdated_spec.rb index db916892ed0d..86a9a016cd92 100644 --- a/spec/commands/outdated_spec.rb +++ b/spec/commands/outdated_spec.rb @@ -339,6 +339,37 @@ def test_group_option(group) expect(out).to end_with(expected_output) end + + it "puts together the gems from the same groups declared in a different order" do + install_gemfile <<-G + source "https://gem.repo2" + + gem "terranova", '8' + group :test, :development do + gem 'activesupport', '2.3.5' + end + group :development, :test do + gem "duradura", '7.0' + end + G + + update_repo2 do + build_gem "activesupport", "3.0" + build_gem "terranova", "9" + build_gem "duradura", "8.0" + end + + bundle "outdated --groups", raise_on_error: false + + expected_output = <<~TABLE.strip + Gem Current Latest Requested Groups Release Date + terranova 8 9 = 8 default + activesupport 2.3.5 3.0 = 2.3.5 development, test + duradura 7.0 8.0 = 7.0 development, test + TABLE + + expect(out).to end_with(expected_output) + end end describe "with --local option" do From 2bff2a5d30e61d6fe3fabf7725f389124bb92761 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 15 Sep 2026 18:12:08 +0900 Subject: [PATCH 4/4] List gems without groups last in bundle outdated --groups Transitive dependencies have an empty group set, which sorted before every named set and put them at the top of the table. Co-Authored-By: Claude Opus 5 --- lib/bundler/cli/outdated.rb | 3 ++- spec/commands/outdated_spec.rb | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/bundler/cli/outdated.rb b/lib/bundler/cli/outdated.rb index c86810730529..73b120799f69 100644 --- a/lib/bundler/cli/outdated.rb +++ b/lib/bundler/cli/outdated.rb @@ -104,7 +104,8 @@ def run end relevant_outdated_gems = if options[:groups] - outdated_gems.group_by {|g| g[:groups] }.sort.flat_map(&:last) + without_groups, with_groups = outdated_gems.partition {|g| g[:groups].empty? } + with_groups.group_by {|g| g[:groups] }.sort.flat_map(&:last) + without_groups elsif options_include_groups outdated_gems.select {|g| g[:groups].split(", ").include?(options[:group]) } else diff --git a/spec/commands/outdated_spec.rb b/spec/commands/outdated_spec.rb index 86a9a016cd92..fb0ec8417d67 100644 --- a/spec/commands/outdated_spec.rb +++ b/spec/commands/outdated_spec.rb @@ -291,6 +291,31 @@ def test_group_option(group) expect(out).to end_with(expected_output) end + + it "lists the outdated gems without groups after the grouped ones" do + install_gemfile <<-G + source "https://gem.repo2" + + gem "bar_dependant", '7.0' + gem "myrack_middleware" + gem "terranova", '8' + G + + update_repo2 do + build_gem "terranova", "9" + end + + bundle "outdated --groups", raise_on_error: false + + expected_output = <<~TABLE.strip + Gem Current Latest Requested Groups Release Date + terranova 8 9 = 8 default + bar 2.0.0 3.0.0 + myrack 0.9.1 1.0.0 + TABLE + + expect(out).to end_with(expected_output) + end end describe "with --groups option" do