Merge pull request #15763 from razvanazamfirei/bump-add-arch-support
bump: add arch-specific support
This commit is contained in:
commit
0e098510c2
@ -1,15 +1,27 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "bump_version_parser"
|
||||
require "cli/parser"
|
||||
require "livecheck/livecheck"
|
||||
|
||||
module Homebrew
|
||||
module_function
|
||||
|
||||
class VersionBumpInfo < T::Struct
|
||||
const :type, Symbol
|
||||
const :multiple_versions, T::Boolean
|
||||
const :version_name, String
|
||||
const :current_version, BumpVersionParser
|
||||
const :repology_latest, T.any(String, Version)
|
||||
const :new_version, BumpVersionParser
|
||||
const :open_pull_requests, T.nilable(T.any(T::Array[String], String))
|
||||
const :closed_pull_requests, T.nilable(T.any(T::Array[String], String))
|
||||
end
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def bump_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Display out-of-date brew formulae and the latest version available. If the
|
||||
returned current and livecheck versions differ or when querying specific
|
||||
@ -29,6 +41,9 @@ module Homebrew
|
||||
description: "Limit number of package results returned."
|
||||
flag "--start-with=",
|
||||
description: "Letter or word that the list of package results should alphabetically follow."
|
||||
switch "-f", "--force",
|
||||
description: "Ignore duplicate open PRs.",
|
||||
hidden: true
|
||||
|
||||
conflicts "--cask", "--formula"
|
||||
conflicts "--no-pull-requests", "--open-pr"
|
||||
@ -37,6 +52,7 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def bump
|
||||
args = bump_args.parse
|
||||
|
||||
@ -55,8 +71,6 @@ module Homebrew
|
||||
formula_or_cask.respond_to?(:token) ? formula_or_cask.token : formula_or_cask.name
|
||||
end
|
||||
|
||||
limit = args.limit.to_i if args.limit.present?
|
||||
|
||||
unless Utils::Curl.curl_supports_tls13?
|
||||
begin
|
||||
ensure_formula_installed!("curl", reason: "Repology queries") unless HOMEBREW_BREWED_CURL_PATH.exist?
|
||||
@ -66,6 +80,14 @@ module Homebrew
|
||||
end
|
||||
|
||||
if formulae_and_casks.present?
|
||||
handle_formula_and_casks(formulae_and_casks, args)
|
||||
else
|
||||
handle_api_response(args)
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(formulae_and_casks: T::Array[T.any(Formula, Cask::Cask)], args: CLI::Args).void }
|
||||
def handle_formula_and_casks(formulae_and_casks, args)
|
||||
Livecheck.load_other_tap_strategies(formulae_and_casks)
|
||||
|
||||
ambiguous_casks = []
|
||||
@ -80,8 +102,8 @@ module Homebrew
|
||||
|
||||
ambiguous_names = []
|
||||
unless args.full_name?
|
||||
ambiguous_names =
|
||||
(formulae_and_casks - ambiguous_casks).group_by { |item| Livecheck.package_or_resource_name(item) }
|
||||
ambiguous_names = (formulae_and_casks - ambiguous_casks)
|
||||
.group_by { |item| Livecheck.package_or_resource_name(item) }
|
||||
.values
|
||||
.select { |items| items.length > 1 }
|
||||
.flatten
|
||||
@ -94,7 +116,6 @@ module Homebrew
|
||||
name = Livecheck.package_or_resource_name(formula_or_cask, full_name: use_full_name)
|
||||
repository = if formula_or_cask.is_a?(Formula)
|
||||
if formula_or_cask.head_only?
|
||||
ohai name
|
||||
puts "Formula is HEAD-only."
|
||||
next
|
||||
end
|
||||
@ -118,7 +139,12 @@ module Homebrew
|
||||
ambiguous_cask: ambiguous_casks.include?(formula_or_cask),
|
||||
)
|
||||
end
|
||||
else
|
||||
end
|
||||
|
||||
sig { params(args: CLI::Args).void }
|
||||
def handle_api_response(args)
|
||||
limit = args.limit.to_i if args.limit.present?
|
||||
|
||||
api_response = {}
|
||||
unless args.cask?
|
||||
api_response[:formulae] =
|
||||
@ -174,13 +200,18 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
sig {
|
||||
params(formula_or_cask: T.any(Formula, Cask::Cask)).returns(T.any(Version, String))
|
||||
}
|
||||
def livecheck_result(formula_or_cask)
|
||||
name = Livecheck.package_or_resource_name(formula_or_cask)
|
||||
|
||||
referenced_formula_or_cask, =
|
||||
Livecheck.resolve_livecheck_reference(formula_or_cask, full_name: false, debug: false)
|
||||
referenced_formula_or_cask, = Livecheck.resolve_livecheck_reference(
|
||||
formula_or_cask,
|
||||
full_name: false,
|
||||
debug: false,
|
||||
)
|
||||
|
||||
# Check skip conditions for a referenced formula/cask
|
||||
if referenced_formula_or_cask
|
||||
@ -192,7 +223,12 @@ module Homebrew
|
||||
)
|
||||
end
|
||||
|
||||
skip_info ||= Livecheck::SkipConditions.skip_information(formula_or_cask, full_name: false, verbose: false)
|
||||
skip_info ||= Livecheck::SkipConditions.skip_information(
|
||||
formula_or_cask,
|
||||
full_name: false,
|
||||
verbose: false,
|
||||
)
|
||||
|
||||
if skip_info.present?
|
||||
return "#{skip_info[:status]}#{" - #{skip_info[:messages].join(", ")}" if skip_info[:messages].present?}"
|
||||
end
|
||||
@ -211,6 +247,14 @@ module Homebrew
|
||||
"error: #{e}"
|
||||
end
|
||||
|
||||
sig {
|
||||
params(
|
||||
formula_or_cask: T.any(Formula, Cask::Cask),
|
||||
name: String,
|
||||
state: String,
|
||||
version: T.nilable(String),
|
||||
).returns T.nilable(T.any(T::Array[String], String))
|
||||
}
|
||||
def retrieve_pull_requests(formula_or_cask, name, state:, version: nil)
|
||||
tap_remote_repo = formula_or_cask.tap&.remote_repo || formula_or_cask.tap&.full_name
|
||||
pull_requests = GitHub.fetch_pull_requests(name, tap_remote_repo, state: state, version: version)
|
||||
@ -221,55 +265,165 @@ module Homebrew
|
||||
pull_requests
|
||||
end
|
||||
|
||||
def retrieve_and_display_info_and_open_pr(formula_or_cask, name, repositories, args:, ambiguous_cask: false)
|
||||
sig {
|
||||
params(
|
||||
formula_or_cask: T.any(Formula, Cask::Cask),
|
||||
repositories: T::Array[T.untyped],
|
||||
args: T.untyped,
|
||||
name: String,
|
||||
).returns(VersionBumpInfo)
|
||||
}
|
||||
def retrieve_versions_by_arch(formula_or_cask:, repositories:, args:, name:)
|
||||
is_cask_with_blocks = formula_or_cask.is_a?(Cask::Cask) && formula_or_cask.on_system_blocks_exist?
|
||||
type, version_name = formula_or_cask.is_a?(Formula) ? [:formula, "formula version:"] : [:cask, "cask version: "]
|
||||
|
||||
old_versions = {}
|
||||
new_versions = {}
|
||||
|
||||
repology_latest = repositories.present? ? Repology.latest_version(repositories) : "not found"
|
||||
|
||||
# When blocks are absent, arch is not relevant. For consistency, we simulate the arm architecture.
|
||||
arch_options = is_cask_with_blocks ? OnSystem::ARCH_OPTIONS : [:arm]
|
||||
|
||||
arch_options.each do |arch|
|
||||
SimulateSystem.with arch: arch do
|
||||
version_key = is_cask_with_blocks ? arch : :general
|
||||
|
||||
# We reload the formula/cask here to ensure we're getting the correct version for the current arch
|
||||
if formula_or_cask.is_a?(Formula)
|
||||
current_version = T.must(formula_or_cask.stable).version
|
||||
type = :formula
|
||||
version_name = "formula version"
|
||||
loaded_formula_or_cask = formula_or_cask
|
||||
current_version_value = T.must(loaded_formula_or_cask.stable).version
|
||||
else
|
||||
current_version = Version.new(formula_or_cask.version)
|
||||
type = :cask
|
||||
version_name = "cask version "
|
||||
loaded_formula_or_cask = Cask::CaskLoader.load(formula_or_cask.sourcefile_path)
|
||||
current_version_value = Version.new(loaded_formula_or_cask.version)
|
||||
end
|
||||
|
||||
livecheck_latest = livecheck_result(formula_or_cask)
|
||||
livecheck_latest = livecheck_result(loaded_formula_or_cask)
|
||||
|
||||
repology_latest = if repositories.present?
|
||||
Repology.latest_version(repositories)
|
||||
else
|
||||
"not found"
|
||||
end
|
||||
|
||||
new_version = if livecheck_latest.is_a?(Version) && livecheck_latest > current_version
|
||||
new_version_value = if (livecheck_latest.is_a?(Version) && livecheck_latest >= current_version_value) ||
|
||||
current_version_value == "latest"
|
||||
livecheck_latest
|
||||
elsif repology_latest.is_a?(Version) &&
|
||||
repology_latest > current_version &&
|
||||
!formula_or_cask.livecheckable? &&
|
||||
current_version != "latest"
|
||||
repology_latest > current_version_value &&
|
||||
!loaded_formula_or_cask.livecheckable? &&
|
||||
current_version_value != "latest"
|
||||
repology_latest
|
||||
end.presence
|
||||
|
||||
open_pull_requests = if !args.no_pull_requests? && (args.named.present? || new_version)
|
||||
# Store old and new versions
|
||||
old_versions[version_key] = current_version_value
|
||||
new_versions[version_key] = new_version_value
|
||||
end
|
||||
end
|
||||
|
||||
# If arm and intel versions are identical, as it happens with casks where only the checksums differ,
|
||||
# we consolidate them into a single version.
|
||||
if old_versions[:arm].present? && old_versions[:arm] == old_versions[:intel]
|
||||
old_versions = { general: old_versions[:arm] }
|
||||
end
|
||||
if new_versions[:arm].present? && new_versions[:arm] == new_versions[:intel]
|
||||
new_versions = { general: new_versions[:arm] }
|
||||
end
|
||||
|
||||
multiple_versions = old_versions.values_at(:arm, :intel).all?(&:present?) ||
|
||||
new_versions.values_at(:arm, :intel).all?(&:present?)
|
||||
|
||||
current_version = BumpVersionParser.new(general: old_versions[:general],
|
||||
arm: old_versions[:arm],
|
||||
intel: old_versions[:intel])
|
||||
|
||||
begin
|
||||
new_version = BumpVersionParser.new(general: new_versions[:general],
|
||||
arm: new_versions[:arm],
|
||||
intel: new_versions[:intel])
|
||||
rescue
|
||||
# When livecheck fails, we fail gracefully. Otherwise VersionParser will
|
||||
# raise a usage error
|
||||
new_version = BumpVersionParser.new(general: "unable to get versions")
|
||||
end
|
||||
|
||||
# We use the arm version for the pull request version. This is consistent
|
||||
# with the behavior of bump-cask-pr.
|
||||
pull_request_version = if multiple_versions && new_version.general != "unable to get versions"
|
||||
new_version.arm.to_s
|
||||
else
|
||||
new_version.general.to_s
|
||||
end
|
||||
|
||||
open_pull_requests = if !args.no_pull_requests? && (args.named.present? || new_version.present?)
|
||||
retrieve_pull_requests(formula_or_cask, name, state: "open")
|
||||
end.presence
|
||||
|
||||
closed_pull_requests = if !args.no_pull_requests? && !open_pull_requests && new_version.present?
|
||||
# if we haven't already found open requests, try for an exact match across closed requests
|
||||
retrieve_pull_requests(formula_or_cask, name, state: "closed", version: new_version)
|
||||
closed_pull_requests = if !args.no_pull_requests? && open_pull_requests.blank? && new_version.present?
|
||||
retrieve_pull_requests(formula_or_cask, name, state: "closed", version: pull_request_version)
|
||||
end.presence
|
||||
|
||||
VersionBumpInfo.new(
|
||||
type: type,
|
||||
multiple_versions: multiple_versions,
|
||||
version_name: version_name,
|
||||
current_version: current_version,
|
||||
repology_latest: repology_latest,
|
||||
new_version: new_version,
|
||||
open_pull_requests: open_pull_requests,
|
||||
closed_pull_requests: closed_pull_requests,
|
||||
)
|
||||
end
|
||||
|
||||
sig {
|
||||
params(
|
||||
formula_or_cask: T.any(Formula, Cask::Cask),
|
||||
name: String,
|
||||
repositories: T::Array[T.untyped],
|
||||
args: T.untyped,
|
||||
ambiguous_cask: T::Boolean,
|
||||
).void
|
||||
}
|
||||
def retrieve_and_display_info_and_open_pr(formula_or_cask, name, repositories, args:, ambiguous_cask: false)
|
||||
version_info = retrieve_versions_by_arch(formula_or_cask: formula_or_cask,
|
||||
repositories: repositories,
|
||||
args: args,
|
||||
name: name)
|
||||
|
||||
current_version = version_info.current_version
|
||||
new_version = version_info.new_version
|
||||
repology_latest = version_info.repology_latest
|
||||
|
||||
# Check if all versions are equal
|
||||
versions_equal = [:arm, :intel, :general].all? do |key|
|
||||
current_version.send(key) == new_version.send(key)
|
||||
end
|
||||
|
||||
title_name = ambiguous_cask ? "#{name} (cask)" : name
|
||||
title = if current_version == repology_latest &&
|
||||
current_version == livecheck_latest
|
||||
title = if (repology_latest == current_version.general || !repology_latest.is_a?(Version)) && versions_equal
|
||||
"#{title_name} #{Tty.green}is up to date!#{Tty.reset}"
|
||||
else
|
||||
title_name
|
||||
end
|
||||
|
||||
# Conditionally format output based on type of formula_or_cask
|
||||
current_versions = if version_info.multiple_versions
|
||||
"arm: #{current_version.arm}
|
||||
intel: #{current_version.intel}"
|
||||
else
|
||||
current_version.general
|
||||
end
|
||||
|
||||
new_versions = if version_info.multiple_versions && new_version.arm && new_version.intel
|
||||
"arm: #{new_version.arm}
|
||||
intel: #{new_version.intel}"
|
||||
else
|
||||
new_version.general
|
||||
end
|
||||
|
||||
version_label = version_info.version_name
|
||||
open_pull_requests = version_info.open_pull_requests.presence
|
||||
closed_pull_requests = version_info.closed_pull_requests.presence
|
||||
|
||||
ohai title
|
||||
puts <<~EOS
|
||||
Current #{version_name}: #{current_version}
|
||||
Latest livecheck version: #{livecheck_latest}
|
||||
Current #{version_label} #{current_versions}
|
||||
Latest livecheck version: #{new_versions}
|
||||
Latest Repology version: #{repology_latest}
|
||||
Open pull requests: #{open_pull_requests || "none"}
|
||||
Closed pull requests: #{closed_pull_requests || "none"}
|
||||
@ -278,17 +432,33 @@ module Homebrew
|
||||
return unless args.open_pr?
|
||||
|
||||
if repology_latest.is_a?(Version) &&
|
||||
repology_latest > current_version &&
|
||||
repology_latest > livecheck_latest &&
|
||||
repology_latest > current_version.general &&
|
||||
repology_latest > new_version.general &&
|
||||
formula_or_cask.livecheckable?
|
||||
puts "#{title_name} was not bumped to the Repology version because it's livecheckable."
|
||||
end
|
||||
if new_version.blank? || versions_equal ||
|
||||
(!new_version.general.is_a?(Version) && !version_info.multiple_versions)
|
||||
return
|
||||
end
|
||||
|
||||
return unless new_version
|
||||
return if open_pull_requests
|
||||
return if closed_pull_requests
|
||||
return if !args.force? && (open_pull_requests.present? || closed_pull_requests.present?)
|
||||
|
||||
system HOMEBREW_BREW_FILE, "bump-#{type}-pr", "--no-browse",
|
||||
"--message=Created by `brew bump`", "--version=#{new_version}", name
|
||||
version_args = if version_info.multiple_versions
|
||||
%W[--version-arm=#{new_version.arm} --version-intel=#{new_version.intel}]
|
||||
else
|
||||
"--version=#{new_version.general}"
|
||||
end
|
||||
|
||||
bump_cask_pr_args = [
|
||||
"bump-#{version_info.type}-pr",
|
||||
name,
|
||||
*version_args,
|
||||
"--no-browse",
|
||||
"--message=Created by `brew bump`",
|
||||
]
|
||||
bump_cask_pr_args << "--force" if args.force?
|
||||
|
||||
system HOMEBREW_BREW_FILE, *bump_cask_pr_args
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user