Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Library/Homebrew/cask/upgrade.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
require "cask/quarantine"
require "deprecate_disable"
require "install"
require "upgrade"
require "utils/output"

module Cask
Expand Down Expand Up @@ -92,7 +93,7 @@ def self.show_upgrade_summary(cask_upgrades, dry_run: false)

verb = dry_run ? "Would upgrade" : "Upgrading"
oh1 "#{verb} #{cask_upgrades.count} outdated #{::Utils.pluralize("package", cask_upgrades.count)}:"
puts cask_upgrades.join("\n")
puts Homebrew::Upgrade.format_upgrade_summary(cask_upgrades).join("\n")
end

sig {
Expand Down
5 changes: 3 additions & 2 deletions Library/Homebrew/cmd/upgrade.rb
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,8 @@ def formulae_upgrade_context(formulae, show_upgrade_summary: true, dry_run: args
verb = dry_run ? "Would upgrade" : "Upgrading"
oh1 "#{verb} #{formulae_to_install.count} outdated #{Utils.pluralize("package",
formulae_to_install.count)}:"
puts formula_upgrade_descriptions(formulae_to_install).join("\n") if args.no_ask?
puts Upgrade.format_upgrade_summary(formula_upgrade_descriptions(formulae_to_install)).join("\n") if
args.no_ask?
end

Install.perform_preinstall_checks_once
Expand Down Expand Up @@ -556,7 +557,7 @@ def show_final_upgrade_summary(dry_run: args.dry_run?)
show_final_upgrade_summary_section(
"#{dry_run ? "Would upgrade" : "Upgraded"} #{version_change_count} outdated " \
"#{Utils.pluralize("package", version_change_count)}",
summary.version_changes,
Upgrade.format_upgrade_summary(summary.version_changes),
)
Comment thread
paulogdm marked this conversation as resolved.
end
if summary.pinned_formulae.present?
Expand Down
72 changes: 64 additions & 8 deletions Library/Homebrew/test/cmd/upgrade_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,31 @@ def setup_pinned_dependency_upgrade
.to output(/minimum-version-formula 1\.2\.2 -> 1\.2\.3/).to_stdout
end

it "aligns formula-only no-ask upgrade summaries" do
write_formula "gh", <<~RUBY
url "https://brew.sh/gh-2.95.0"
RUBY
write_formula "visual-studio-code", <<~RUBY
url "https://brew.sh/visual-studio-code-1.125.1"
RUBY
install_formula_version "gh", "2.93.0", optlinked: true
install_formula_version "visual-studio-code", "1.111.0", optlinked: true
allow(Homebrew::Upgrade).to receive(:formula_installers).and_return([])
allow(Homebrew::Cleanup).to receive(:periodic_clean!)
allow(Homebrew::Reinstall).to receive(:reinstall_pkgconf_if_needed!)
allow(Homebrew.messages).to receive(:display_messages)

expected_summary = <<~EOS
==> Upgrading 2 outdated packages:
gh 2.93.0 -> 2.95.0
visual-studio-code 1.111.0 -> 1.125.1
EOS

expect do
described_class.new(["--yes", "--formula", "gh", "visual-studio-code"]).run
end.to output(a_string_starting_with(expected_summary)).to_stdout
end

it "does not upgrade a named formula installed at --minimum-version" do
write_formula "minimum-version-formula", <<~RUBY
url "https://brew.sh/minimum-version-formula-1.2.4"
Expand Down Expand Up @@ -535,6 +560,37 @@ def setup_pinned_dependency_upgrade
end.not_to output.to_stdout
end

it "aligns dependent formula upgrade summaries" do
formula = formula("sqlite") do
T.bind(self, T.class_of(Formula))
url "https://brew.sh/sqlite-3.53.2.tar.gz"
end
dependants = Homebrew::Upgrade::Dependents.new(
upgradeable: [
formula("gh") do
T.bind(self, T.class_of(Formula))
url "https://brew.sh/gh-2.95.0.tar.gz"
end,
formula("visual-studio-code") do
T.bind(self, T.class_of(Formula))
url "https://brew.sh/visual-studio-code-1.125.1.tar.gz"
end,
],
pinned: [],
skipped: [],
)

with_env(HOMEBREW_NO_ENV_HINTS: "1") do
expect do
Homebrew::Upgrade.upgrade_dependents(dependants, [formula], flags: [], dry_run: true)
end.to output(<<~EOS).to_stdout
==> Would upgrade 2 dependents of upgraded formula:
gh 2.95.0
visual-studio-code 1.125.1
EOS
end
end

it "does not print aggregate package sizes" do
cmd = described_class.new(["--dry-run"])
summary = Homebrew::Cmd::UpgradeCmd::FinalUpgradeSummary.new(
Expand All @@ -545,8 +601,8 @@ def setup_pinned_dependency_upgrade

expect { cmd.send(:show_final_upgrade_summary) }.to output(<<~EOS).to_stdout
==> Would upgrade 2 outdated packages
testball 0.1 -> 0.2 (500B)
codex 1.0 -> 2.0
testball 0.1 -> 0.2 (500B)
codex 1.0 -> 2.0
EOS
end

Expand Down Expand Up @@ -606,8 +662,8 @@ def setup_pinned_dependency_upgrade

expect { cmd.run }.to output(<<~EOS).to_stdout
==> Upgrading 2 outdated packages:
deno 2.7.10 -> 2.7.11
codex 0.117.0 -> 0.118.0
deno 2.7.10 -> 2.7.11
codex 0.117.0 -> 0.118.0
==> Fetching downloads for: deno and codex
EOS
end
Expand Down Expand Up @@ -705,8 +761,8 @@ def setup_pinned_dependency_upgrade
expect { cmd.run }.to output(<<~EOS).to_stdout
==> Downloading Cask files
==> Upgrading 2 outdated packages:
deno 2.7.10 -> 2.7.11
codex 0.117.0 -> 0.118.0
deno 2.7.10 -> 2.7.11
codex 0.117.0 -> 0.118.0
==> Fetching downloads for: deno and codex
EOS
end
Expand Down Expand Up @@ -751,8 +807,8 @@ def setup_pinned_dependency_upgrade

expect { cmd.run }.to output(<<~EOS).to_stdout
==> Upgrading 2 outdated packages:
deno 2.7.10 -> 2.7.11
codex 0.117.0 -> 0.118.0
deno 2.7.10 -> 2.7.11
codex 0.117.0 -> 0.118.0
==> Fetching downloads for: deno and codex
EOS
end
Expand Down
48 changes: 48 additions & 0 deletions Library/Homebrew/test/upgrade_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# typed: true
# frozen_string_literal: true

require "upgrade"

RSpec.describe Homebrew::Upgrade do
describe "::format_upgrade_summary" do
it "aligns a large mixed list of package names and versions" do
upgrades = [
"sqlite 3.53.1 -> 3.53.2 (2.4MB)",
"docker 29.5.2 -> 29.6.0 (9.3MB)",
"gh 2.93.0 -> 2.95.0 (13.4MB)",
"python@3.14 3.14.5 -> 3.14.6 (19.2MB)",
"pnpm 11.5.1 -> 11.8.0 (4MB)",
"usage 3.4.0 -> 3.5.2 (2.9MB)",
"certifi 2026.5.20 -> 2026.6.17 (5.7KB)",
"libvmaf 3.1.0 -> 3.2.0 (1.2MB)",
"kubernetes-cli 1.36.1 -> 1.36.2 (18.2MB)",
"jq 1.8.1 -> 1.8.2 (441KB)",
"mise 2026.6.0 -> 2026.6.11 (34.8MB)",
"sdl2 2.32.70 (636.8KB)",
"opencode-desktop 1.14.48 -> 1.17.9",
"slack 4.48.102 -> 4.50.140",
"spotify 1.2.84.476 -> 1.2.92.148",
"visual-studio-code 1.111.0 -> 1.125.1",
]

expect(described_class.format_upgrade_summary(upgrades)).to eq([
"sqlite 3.53.1 -> 3.53.2 (2.4MB)",
"docker 29.5.2 -> 29.6.0 (9.3MB)",
"gh 2.93.0 -> 2.95.0 (13.4MB)",
"python@3.14 3.14.5 -> 3.14.6 (19.2MB)",
"pnpm 11.5.1 -> 11.8.0 (4MB)",
"usage 3.4.0 -> 3.5.2 (2.9MB)",
"certifi 2026.5.20 -> 2026.6.17 (5.7KB)",
"libvmaf 3.1.0 -> 3.2.0 (1.2MB)",
"kubernetes-cli 1.36.1 -> 1.36.2 (18.2MB)",
"jq 1.8.1 -> 1.8.2 (441KB)",
"mise 2026.6.0 -> 2026.6.11 (34.8MB)",
"sdl2 2.32.70 (636.8KB)",
"opencode-desktop 1.14.48 -> 1.17.9",
"slack 4.48.102 -> 4.50.140",
"spotify 1.2.84.476 -> 1.2.92.148",
"visual-studio-code 1.111.0 -> 1.125.1",
])
end
end
end
33 changes: 32 additions & 1 deletion Library/Homebrew/upgrade.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,37 @@ class Dependents < T::Struct
end

class << self
sig { params(upgrades: T::Array[String]).returns(T::Array[String]) }
def format_upgrade_summary(upgrades)
return upgrades if upgrades.size < 2

name_width = upgrades.map { |upgrade| upgrade.split(" ", 2).fetch(0).length }.max
name_width ||= 0
old_version_width = upgrades.filter_map do |upgrade|
versions = upgrade.split(" ", 2).fetch(1, "")
next unless versions.include?(" -> ")

versions.split(" -> ", 2).fetch(0).length
end.max
old_version_width ||= 0

upgrades.map do |upgrade|
parts = upgrade.split(" ", 2)
name = parts.fetch(0)
versions = parts.fetch(1, "")
next name if versions.blank?

if versions.include?(" -> ")
version_parts = versions.split(" -> ", 2)
old_version = version_parts.fetch(0)
new_version = version_parts.fetch(1)
"#{name.ljust(name_width)} #{old_version.ljust(old_version_width)} -> #{new_version}"
else
"#{name.ljust(name_width)} #{versions}"
end
end
end

sig {
params(
formulae_to_install: T::Array[Formula], flags: T::Array[String], dry_run: T::Boolean,
Expand Down Expand Up @@ -303,7 +334,7 @@ def upgrade_dependents(deps, formulae,
"#{name} #{f.pkg_version}"
end
end
puts formulae_upgrades.join("\n")
puts format_upgrade_summary(formulae_upgrades).join("\n")
end

return if upgradeable.blank?
Expand Down
Loading