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
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "bump_version_parser"
|
||||||
require "cli/parser"
|
require "cli/parser"
|
||||||
require "livecheck/livecheck"
|
require "livecheck/livecheck"
|
||||||
|
|
||||||
module Homebrew
|
module Homebrew
|
||||||
module_function
|
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) }
|
sig { returns(CLI::Parser) }
|
||||||
def bump_args
|
def bump_args
|
||||||
Homebrew::CLI::Parser.new do
|
CLI::Parser.new do
|
||||||
description <<~EOS
|
description <<~EOS
|
||||||
Display out-of-date brew formulae and the latest version available. If the
|
Display out-of-date brew formulae and the latest version available. If the
|
||||||
returned current and livecheck versions differ or when querying specific
|
returned current and livecheck versions differ or when querying specific
|
||||||
@ -29,6 +41,9 @@ module Homebrew
|
|||||||
description: "Limit number of package results returned."
|
description: "Limit number of package results returned."
|
||||||
flag "--start-with=",
|
flag "--start-with=",
|
||||||
description: "Letter or word that the list of package results should alphabetically follow."
|
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 "--cask", "--formula"
|
||||||
conflicts "--no-pull-requests", "--open-pr"
|
conflicts "--no-pull-requests", "--open-pr"
|
||||||
@ -37,6 +52,7 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sig { void }
|
||||||
def bump
|
def bump
|
||||||
args = bump_args.parse
|
args = bump_args.parse
|
||||||
|
|
||||||
@ -55,8 +71,6 @@ module Homebrew
|
|||||||
formula_or_cask.respond_to?(:token) ? formula_or_cask.token : formula_or_cask.name
|
formula_or_cask.respond_to?(:token) ? formula_or_cask.token : formula_or_cask.name
|
||||||
end
|
end
|
||||||
|
|
||||||
limit = args.limit.to_i if args.limit.present?
|
|
||||||
|
|
||||||
unless Utils::Curl.curl_supports_tls13?
|
unless Utils::Curl.curl_supports_tls13?
|
||||||
begin
|
begin
|
||||||
ensure_formula_installed!("curl", reason: "Repology queries") unless HOMEBREW_BREWED_CURL_PATH.exist?
|
ensure_formula_installed!("curl", reason: "Repology queries") unless HOMEBREW_BREWED_CURL_PATH.exist?
|
||||||
@ -66,6 +80,14 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
|
|
||||||
if formulae_and_casks.present?
|
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)
|
Livecheck.load_other_tap_strategies(formulae_and_casks)
|
||||||
|
|
||||||
ambiguous_casks = []
|
ambiguous_casks = []
|
||||||
@ -80,8 +102,8 @@ module Homebrew
|
|||||||
|
|
||||||
ambiguous_names = []
|
ambiguous_names = []
|
||||||
unless args.full_name?
|
unless args.full_name?
|
||||||
ambiguous_names =
|
ambiguous_names = (formulae_and_casks - ambiguous_casks)
|
||||||
(formulae_and_casks - ambiguous_casks).group_by { |item| Livecheck.package_or_resource_name(item) }
|
.group_by { |item| Livecheck.package_or_resource_name(item) }
|
||||||
.values
|
.values
|
||||||
.select { |items| items.length > 1 }
|
.select { |items| items.length > 1 }
|
||||||
.flatten
|
.flatten
|
||||||
@ -94,7 +116,6 @@ module Homebrew
|
|||||||
name = Livecheck.package_or_resource_name(formula_or_cask, full_name: use_full_name)
|
name = Livecheck.package_or_resource_name(formula_or_cask, full_name: use_full_name)
|
||||||
repository = if formula_or_cask.is_a?(Formula)
|
repository = if formula_or_cask.is_a?(Formula)
|
||||||
if formula_or_cask.head_only?
|
if formula_or_cask.head_only?
|
||||||
ohai name
|
|
||||||
puts "Formula is HEAD-only."
|
puts "Formula is HEAD-only."
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
@ -118,7 +139,12 @@ module Homebrew
|
|||||||
ambiguous_cask: ambiguous_casks.include?(formula_or_cask),
|
ambiguous_cask: ambiguous_casks.include?(formula_or_cask),
|
||||||
)
|
)
|
||||||
end
|
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 = {}
|
api_response = {}
|
||||||
unless args.cask?
|
unless args.cask?
|
||||||
api_response[:formulae] =
|
api_response[:formulae] =
|
||||||
@ -174,13 +200,18 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
end
|
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)
|
def livecheck_result(formula_or_cask)
|
||||||
name = Livecheck.package_or_resource_name(formula_or_cask)
|
name = Livecheck.package_or_resource_name(formula_or_cask)
|
||||||
|
|
||||||
referenced_formula_or_cask, =
|
referenced_formula_or_cask, = Livecheck.resolve_livecheck_reference(
|
||||||
Livecheck.resolve_livecheck_reference(formula_or_cask, full_name: false, debug: false)
|
formula_or_cask,
|
||||||
|
full_name: false,
|
||||||
|
debug: false,
|
||||||
|
)
|
||||||
|
|
||||||
# Check skip conditions for a referenced formula/cask
|
# Check skip conditions for a referenced formula/cask
|
||||||
if referenced_formula_or_cask
|
if referenced_formula_or_cask
|
||||||
@ -192,7 +223,12 @@ module Homebrew
|
|||||||
)
|
)
|
||||||
end
|
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?
|
if skip_info.present?
|
||||||
return "#{skip_info[:status]}#{" - #{skip_info[:messages].join(", ")}" if skip_info[:messages].present?}"
|
return "#{skip_info[:status]}#{" - #{skip_info[:messages].join(", ")}" if skip_info[:messages].present?}"
|
||||||
end
|
end
|
||||||
@ -211,6 +247,14 @@ module Homebrew
|
|||||||
"error: #{e}"
|
"error: #{e}"
|
||||||
end
|
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)
|
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
|
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)
|
pull_requests = GitHub.fetch_pull_requests(name, tap_remote_repo, state: state, version: version)
|
||||||
@ -221,55 +265,165 @@ module Homebrew
|
|||||||
pull_requests
|
pull_requests
|
||||||
end
|
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)
|
if formula_or_cask.is_a?(Formula)
|
||||||
current_version = T.must(formula_or_cask.stable).version
|
loaded_formula_or_cask = formula_or_cask
|
||||||
type = :formula
|
current_version_value = T.must(loaded_formula_or_cask.stable).version
|
||||||
version_name = "formula version"
|
|
||||||
else
|
else
|
||||||
current_version = Version.new(formula_or_cask.version)
|
loaded_formula_or_cask = Cask::CaskLoader.load(formula_or_cask.sourcefile_path)
|
||||||
type = :cask
|
current_version_value = Version.new(loaded_formula_or_cask.version)
|
||||||
version_name = "cask version "
|
|
||||||
end
|
end
|
||||||
|
|
||||||
livecheck_latest = livecheck_result(formula_or_cask)
|
livecheck_latest = livecheck_result(loaded_formula_or_cask)
|
||||||
|
|
||||||
repology_latest = if repositories.present?
|
new_version_value = if (livecheck_latest.is_a?(Version) && livecheck_latest >= current_version_value) ||
|
||||||
Repology.latest_version(repositories)
|
current_version_value == "latest"
|
||||||
else
|
|
||||||
"not found"
|
|
||||||
end
|
|
||||||
|
|
||||||
new_version = if livecheck_latest.is_a?(Version) && livecheck_latest > current_version
|
|
||||||
livecheck_latest
|
livecheck_latest
|
||||||
elsif repology_latest.is_a?(Version) &&
|
elsif repology_latest.is_a?(Version) &&
|
||||||
repology_latest > current_version &&
|
repology_latest > current_version_value &&
|
||||||
!formula_or_cask.livecheckable? &&
|
!loaded_formula_or_cask.livecheckable? &&
|
||||||
current_version != "latest"
|
current_version_value != "latest"
|
||||||
repology_latest
|
repology_latest
|
||||||
end.presence
|
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")
|
retrieve_pull_requests(formula_or_cask, name, state: "open")
|
||||||
end.presence
|
end.presence
|
||||||
|
|
||||||
closed_pull_requests = if !args.no_pull_requests? && !open_pull_requests && new_version.present?
|
closed_pull_requests = if !args.no_pull_requests? && open_pull_requests.blank? && 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: pull_request_version)
|
||||||
retrieve_pull_requests(formula_or_cask, name, state: "closed", version: new_version)
|
|
||||||
end.presence
|
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_name = ambiguous_cask ? "#{name} (cask)" : name
|
||||||
title = if current_version == repology_latest &&
|
title = if (repology_latest == current_version.general || !repology_latest.is_a?(Version)) && versions_equal
|
||||||
current_version == livecheck_latest
|
|
||||||
"#{title_name} #{Tty.green}is up to date!#{Tty.reset}"
|
"#{title_name} #{Tty.green}is up to date!#{Tty.reset}"
|
||||||
else
|
else
|
||||||
title_name
|
title_name
|
||||||
end
|
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
|
ohai title
|
||||||
puts <<~EOS
|
puts <<~EOS
|
||||||
Current #{version_name}: #{current_version}
|
Current #{version_label} #{current_versions}
|
||||||
Latest livecheck version: #{livecheck_latest}
|
Latest livecheck version: #{new_versions}
|
||||||
Latest Repology version: #{repology_latest}
|
Latest Repology version: #{repology_latest}
|
||||||
Open pull requests: #{open_pull_requests || "none"}
|
Open pull requests: #{open_pull_requests || "none"}
|
||||||
Closed pull requests: #{closed_pull_requests || "none"}
|
Closed pull requests: #{closed_pull_requests || "none"}
|
||||||
@ -278,17 +432,33 @@ module Homebrew
|
|||||||
return unless args.open_pr?
|
return unless args.open_pr?
|
||||||
|
|
||||||
if repology_latest.is_a?(Version) &&
|
if repology_latest.is_a?(Version) &&
|
||||||
repology_latest > current_version &&
|
repology_latest > current_version.general &&
|
||||||
repology_latest > livecheck_latest &&
|
repology_latest > new_version.general &&
|
||||||
formula_or_cask.livecheckable?
|
formula_or_cask.livecheckable?
|
||||||
puts "#{title_name} was not bumped to the Repology version because it's livecheckable."
|
puts "#{title_name} was not bumped to the Repology version because it's livecheckable."
|
||||||
end
|
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 !args.force? && (open_pull_requests.present? || closed_pull_requests.present?)
|
||||||
return if open_pull_requests
|
|
||||||
return if closed_pull_requests
|
|
||||||
|
|
||||||
system HOMEBREW_BREW_FILE, "bump-#{type}-pr", "--no-browse",
|
version_args = if version_info.multiple_versions
|
||||||
"--message=Created by `brew bump`", "--version=#{new_version}", name
|
%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
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user