Merge pull request #17606 from Homebrew/sorbet-strict-devcmd
This commit is contained in:
commit
3773940382
@ -1,4 +1,4 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
@ -329,6 +329,7 @@ module Homebrew
|
||||
|
||||
private
|
||||
|
||||
sig { params(results: T::Hash[[Symbol, Pathname], T::Array[T::Hash[Symbol, T.untyped]]]).void }
|
||||
def print_problems(results)
|
||||
results.each do |(name, path), problems|
|
||||
problem_lines = format_problem_lines(problems)
|
||||
@ -343,6 +344,7 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(problems: T::Array[T::Hash[Symbol, T.untyped]]).returns(T::Array[String]) }
|
||||
def format_problem_lines(problems)
|
||||
problems.map do |problem|
|
||||
status = " #{Formatter.success("[corrected]")}" if problem.fetch(:corrected)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
@ -20,7 +20,7 @@ module Homebrew
|
||||
class Bottle < AbstractCommand
|
||||
include FileUtils
|
||||
|
||||
BOTTLE_ERB = <<-EOS.freeze
|
||||
BOTTLE_ERB = T.let(<<-EOS.freeze, String)
|
||||
bottle do
|
||||
<% if [HOMEBREW_BOTTLE_DEFAULT_DOMAIN.to_s,
|
||||
"#{HOMEBREW_BOTTLE_DEFAULT_DOMAIN}/bottles"].exclude?(root_url) %>
|
||||
@ -39,9 +39,9 @@ module Homebrew
|
||||
|
||||
MAXIMUM_STRING_MATCHES = 100
|
||||
|
||||
ALLOWABLE_HOMEBREW_REPOSITORY_LINKS = [
|
||||
ALLOWABLE_HOMEBREW_REPOSITORY_LINKS = T.let([
|
||||
%r{#{Regexp.escape(HOMEBREW_LIBRARY)}/Homebrew/os/(mac|linux)/pkgconfig},
|
||||
].freeze
|
||||
].freeze, T::Array[Regexp])
|
||||
|
||||
cmd_args do
|
||||
description <<~EOS
|
||||
@ -110,6 +110,10 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
|
||||
sig {
|
||||
params(tag: Symbol, digest: T.any(Checksum, String), cellar: T.nilable(T.any(String, Symbol)),
|
||||
tag_column: Integer, digest_column: Integer).returns(String)
|
||||
}
|
||||
def generate_sha256_line(tag, digest, cellar, tag_column, digest_column)
|
||||
line = "sha256 "
|
||||
tag_column += line.length
|
||||
@ -125,6 +129,7 @@ module Homebrew
|
||||
%Q(#{line}"#{digest}")
|
||||
end
|
||||
|
||||
sig { params(bottle: BottleSpecification, root_url_using: T.nilable(String)).returns(String) }
|
||||
def bottle_output(bottle, root_url_using)
|
||||
cellars = bottle.checksums.filter_map do |checksum|
|
||||
cellar = checksum["cellar"]
|
||||
@ -153,12 +158,14 @@ module Homebrew
|
||||
erb.result(erb_binding).gsub(/^\s*$\n/, "")
|
||||
end
|
||||
|
||||
sig { params(filenames: T::Array[String]).returns(T::Array[T::Hash[String, T.untyped]]) }
|
||||
def parse_json_files(filenames)
|
||||
filenames.map do |filename|
|
||||
JSON.parse(File.read(filename))
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(json_files: T::Array[T::Hash[String, T.untyped]]).returns(T::Hash[String, T.untyped]) }
|
||||
def merge_json_files(json_files)
|
||||
json_files.reduce({}) do |hash, json_file|
|
||||
json_file.each_value do |json_hash|
|
||||
@ -172,6 +179,10 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
|
||||
sig {
|
||||
params(old_keys: T::Array[String], old_bottle_spec: BottleSpecification,
|
||||
new_bottle_hash: T::Hash[String, T.untyped]).returns(T::Array[T::Array[String]])
|
||||
}
|
||||
def merge_bottle_spec(old_keys, old_bottle_spec, new_bottle_hash)
|
||||
mismatches = []
|
||||
checksums = []
|
||||
@ -214,16 +225,20 @@ module Homebrew
|
||||
|
||||
private
|
||||
|
||||
sig {
|
||||
params(string: String, keg: Keg, ignores: T::Array[String],
|
||||
formula_and_runtime_deps_names: T.nilable(T::Array[String])).returns(T::Boolean)
|
||||
}
|
||||
def keg_contain?(string, keg, ignores, formula_and_runtime_deps_names = nil)
|
||||
@put_string_exists_header, @put_filenames = nil
|
||||
|
||||
print_filename = lambda do |str, filename|
|
||||
unless @put_string_exists_header
|
||||
opoo "String '#{str}' still exists in these files:"
|
||||
@put_string_exists_header = true
|
||||
@put_string_exists_header = T.let(true, T.nilable(T::Boolean))
|
||||
end
|
||||
|
||||
@put_filenames ||= []
|
||||
@put_filenames ||= T.let([], T.nilable(T::Array[T.any(String, Pathname)]))
|
||||
|
||||
return false if @put_filenames.include?(filename)
|
||||
|
||||
@ -265,6 +280,7 @@ module Homebrew
|
||||
keg_contain_absolute_symlink_starting_with?(string, keg) || result
|
||||
end
|
||||
|
||||
sig { params(string: String, keg: Keg).returns(T::Boolean) }
|
||||
def keg_contain_absolute_symlink_starting_with?(string, keg)
|
||||
absolute_symlinks_start_with_string = []
|
||||
keg.find do |pn|
|
||||
@ -283,6 +299,7 @@ module Homebrew
|
||||
!absolute_symlinks_start_with_string.empty?
|
||||
end
|
||||
|
||||
sig { params(cellar: T.nilable(T.any(String, Symbol))).returns(T::Boolean) }
|
||||
def cellar_parameter_needed?(cellar)
|
||||
default_cellars = [
|
||||
Homebrew::DEFAULT_MACOS_CELLAR,
|
||||
@ -292,6 +309,7 @@ module Homebrew
|
||||
cellar.present? && default_cellars.exclude?(cellar)
|
||||
end
|
||||
|
||||
sig { returns(T.nilable(T::Boolean)) }
|
||||
def sudo_purge
|
||||
return unless ENV["HOMEBREW_BOTTLE_SUDO_PURGE"]
|
||||
|
||||
@ -354,6 +372,7 @@ module Homebrew
|
||||
[gnu_tar(gnu_tar_formula), reproducible_gnutar_args(mtime)].freeze
|
||||
end
|
||||
|
||||
sig { params(formula: T.untyped).returns(T::Array[T.untyped]) }
|
||||
def formula_ignores(formula)
|
||||
ignores = []
|
||||
cellar_regex = Regexp.escape(HOMEBREW_CELLAR)
|
||||
@ -384,6 +403,7 @@ module Homebrew
|
||||
ignores.compact
|
||||
end
|
||||
|
||||
sig { params(formula: Formula).void }
|
||||
def bottle_formula(formula)
|
||||
local_bottle_json = args.json? && formula.local_bottle_path.present?
|
||||
|
||||
@ -453,6 +473,8 @@ module Homebrew
|
||||
|
||||
if local_bottle_json
|
||||
bottle_path = formula.local_bottle_path
|
||||
return if bottle_path.blank?
|
||||
|
||||
local_filename = bottle_path.basename.to_s
|
||||
|
||||
tab_path = Utils::Bottles.receipt_path(bottle_path)
|
||||
@ -471,6 +493,7 @@ module Homebrew
|
||||
else
|
||||
tar_filename = filename.to_s.sub(/.gz$/, "")
|
||||
tar_path = Pathname.pwd/tar_filename
|
||||
return if tar_path.blank?
|
||||
|
||||
keg = Keg.new(formula.prefix)
|
||||
end
|
||||
@ -681,6 +704,7 @@ module Homebrew
|
||||
json_path.write(JSON.pretty_generate(json))
|
||||
end
|
||||
|
||||
sig { returns(T::Hash[String, T.untyped]) }
|
||||
def merge
|
||||
bottles_hash = merge_json_files(parse_json_files(args.named))
|
||||
|
||||
@ -750,7 +774,7 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
|
||||
all_bottle_hash = T.let(nil, T.nilable(Hash))
|
||||
all_bottle_hash = T.let(nil, T.nilable(T::Hash[String, T.untyped]))
|
||||
bottle_hash["bottle"]["tags"].each do |tag, tag_hash|
|
||||
filename = ::Bottle::Filename.new(
|
||||
formula_name,
|
||||
@ -801,7 +825,7 @@ module Homebrew
|
||||
checksums = old_checksums(formula, formula_ast, bottle_hash)
|
||||
update_or_add = checksums.nil? ? "add" : "update"
|
||||
|
||||
checksums&.each(&bottle.method(:sha256))
|
||||
checksums&.each { |checksum| bottle.sha256(checksum) }
|
||||
output = bottle_output(bottle, args.root_url_using)
|
||||
puts output
|
||||
|
||||
@ -835,8 +859,12 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
|
||||
sig {
|
||||
params(formula: Formula, formula_ast: Utils::AST::FormulaAST,
|
||||
bottle_hash: T::Hash[String, T.untyped]).returns(T.nilable(T::Array[String]))
|
||||
}
|
||||
def old_checksums(formula, formula_ast, bottle_hash)
|
||||
bottle_node = formula_ast.bottle_block
|
||||
bottle_node = T.cast(formula_ast.bottle_block, T.nilable(RuboCop::AST::BlockNode))
|
||||
return if bottle_node.nil?
|
||||
return [] unless args.keep_old?
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
@ -145,10 +145,10 @@ module Homebrew
|
||||
|
||||
old_mirrors = formula_spec.mirrors
|
||||
new_mirrors ||= args.mirror
|
||||
new_mirror ||= determine_mirror(new_url)
|
||||
new_mirrors ||= [new_mirror] if new_mirror.present?
|
||||
|
||||
check_for_mirrors(formula, old_mirrors, new_mirrors) if new_url.present?
|
||||
if new_url.present? && (new_mirror = determine_mirror(new_url))
|
||||
new_mirrors ||= [new_mirror]
|
||||
check_for_mirrors(formula, old_mirrors, new_mirrors)
|
||||
end
|
||||
|
||||
old_hash = formula_spec.checksum&.hexdigest
|
||||
new_hash = args.sha256
|
||||
@ -190,12 +190,14 @@ module Homebrew
|
||||
elsif new_url.blank? && new_version.blank?
|
||||
raise UsageError, "#{formula}: no `--url` or `--version` argument specified!"
|
||||
else
|
||||
new_url ||= PyPI.update_pypi_url(old_url, T.must(new_version))
|
||||
return unless new_version.present?
|
||||
|
||||
new_url ||= PyPI.update_pypi_url(old_url, new_version)
|
||||
if new_url.blank?
|
||||
new_url = update_url(old_url, old_version, T.must(new_version))
|
||||
new_url = update_url(old_url, old_version, new_version)
|
||||
if new_mirrors.blank? && old_mirrors.present?
|
||||
new_mirrors = old_mirrors.map do |old_mirror|
|
||||
update_url(old_mirror, old_version, T.must(new_version))
|
||||
update_url(old_mirror, old_version, new_version)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -271,9 +273,9 @@ module Homebrew
|
||||
|
||||
old_contents = formula.path.read
|
||||
|
||||
if new_mirrors.present?
|
||||
if new_mirrors.present? && new_url.present?
|
||||
replacement_pairs << [
|
||||
/^( +)(url "#{Regexp.escape(T.must(new_url))}"[^\n]*?\n)/m,
|
||||
/^( +)(url "#{Regexp.escape(new_url)}"[^\n]*?\n)/m,
|
||||
"\\1\\2\\1mirror \"#{new_mirrors.join("\"\n\\1mirror \"")}\"\n",
|
||||
]
|
||||
end
|
||||
@ -395,6 +397,7 @@ module Homebrew
|
||||
|
||||
private
|
||||
|
||||
sig { params(url: String).returns(T.nilable(String)) }
|
||||
def determine_mirror(url)
|
||||
case url
|
||||
when %r{.*ftp\.gnu\.org/gnu.*}
|
||||
@ -408,6 +411,7 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(formula: String, old_mirrors: T::Array[String], new_mirrors: T::Array[String]).void }
|
||||
def check_for_mirrors(formula, old_mirrors, new_mirrors)
|
||||
return if new_mirrors.present? || old_mirrors.empty?
|
||||
|
||||
@ -427,11 +431,17 @@ module Homebrew
|
||||
return new_url if (old_version_parts = old_version.split(".")).length < 2
|
||||
return new_url if (new_version_parts = new_version.split(".")).length != old_version_parts.length
|
||||
|
||||
partial_old_version = T.must(old_version_parts[0..-2]).join(".")
|
||||
partial_new_version = T.must(new_version_parts[0..-2]).join(".")
|
||||
partial_old_version = old_version_parts[0..-2]&.join(".")
|
||||
partial_new_version = new_version_parts[0..-2]&.join(".")
|
||||
return new_url if partial_old_version.blank? || partial_new_version.blank?
|
||||
|
||||
new_url.gsub(%r{/(v?)#{Regexp.escape(partial_old_version)}/}, "/\\1#{partial_new_version}/")
|
||||
end
|
||||
|
||||
sig {
|
||||
params(formula: Formula, new_version: T.nilable(String), url: String,
|
||||
specs: Float).returns(T::Array[T.untyped])
|
||||
}
|
||||
def fetch_resource_and_forced_version(formula, new_version, url, **specs)
|
||||
resource = Resource.new
|
||||
resource.url(url, **specs)
|
||||
@ -442,6 +452,7 @@ module Homebrew
|
||||
[resource.fetch, forced_version]
|
||||
end
|
||||
|
||||
sig { params(formula: Formula, contents: T.nilable(String)).returns(String) }
|
||||
def formula_version(formula, contents = nil)
|
||||
spec = :stable
|
||||
name = formula.name
|
||||
@ -453,17 +464,29 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(formula: Formula, tap_remote_repo: String).returns(T.nilable(T::Array[String])) }
|
||||
def check_open_pull_requests(formula, tap_remote_repo)
|
||||
GitHub.check_for_duplicate_pull_requests(formula.name, tap_remote_repo,
|
||||
state: "open",
|
||||
file: formula.path.relative_path_from(formula.tap.path).to_s,
|
||||
quiet: args.quiet?)
|
||||
tap = formula.tap
|
||||
return if tap.nil?
|
||||
|
||||
GitHub.check_for_duplicate_pull_requests(
|
||||
formula.name, tap_remote_repo,
|
||||
state: "open",
|
||||
file: formula.path.relative_path_from(tap.path).to_s,
|
||||
quiet: args.quiet?
|
||||
)
|
||||
end
|
||||
|
||||
sig {
|
||||
params(formula: Formula, tap_remote_repo: String, version: T.nilable(String), url: T.nilable(String),
|
||||
tag: T.nilable(String)).void
|
||||
}
|
||||
def check_new_version(formula, tap_remote_repo, version: nil, url: nil, tag: nil)
|
||||
if version.nil?
|
||||
specs = {}
|
||||
specs[:tag] = tag if tag.present?
|
||||
return if url.blank?
|
||||
|
||||
version = Version.detect(url, **specs).to_s
|
||||
return if version.blank?
|
||||
end
|
||||
@ -472,9 +495,13 @@ module Homebrew
|
||||
check_closed_pull_requests(formula, tap_remote_repo, version:)
|
||||
end
|
||||
|
||||
sig { params(formula: Formula, new_version: String).returns(NilClass) }
|
||||
def check_throttle(formula, new_version)
|
||||
tap = formula.tap
|
||||
return if tap.nil?
|
||||
|
||||
throttled_rate = formula.livecheck.throttle
|
||||
throttled_rate ||= if (rate = formula.tap.audit_exceptions.dig(:throttled_formulae, formula.name))
|
||||
throttled_rate ||= if (rate = tap.audit_exceptions.dig(:throttled_formulae, formula.name))
|
||||
odisabled "throttled_formulae.json", "Livecheck#throttle"
|
||||
rate
|
||||
end
|
||||
@ -486,27 +513,41 @@ module Homebrew
|
||||
odie "#{formula} should only be updated every #{throttled_rate} releases on multiples of #{throttled_rate}"
|
||||
end
|
||||
|
||||
sig {
|
||||
params(formula: Formula, tap_remote_repo: String,
|
||||
version: T.nilable(String)).returns(T.nilable(T::Array[String]))
|
||||
}
|
||||
def check_closed_pull_requests(formula, tap_remote_repo, version:)
|
||||
tap = formula.tap
|
||||
return if tap.nil?
|
||||
|
||||
# if we haven't already found open requests, try for an exact match across closed requests
|
||||
GitHub.check_for_duplicate_pull_requests(formula.name, tap_remote_repo,
|
||||
version:,
|
||||
state: "closed",
|
||||
file: formula.path.relative_path_from(formula.tap.path).to_s,
|
||||
quiet: args.quiet?)
|
||||
GitHub.check_for_duplicate_pull_requests(
|
||||
formula.name, tap_remote_repo,
|
||||
version:,
|
||||
state: "closed",
|
||||
file: formula.path.relative_path_from(tap.path).to_s,
|
||||
quiet: args.quiet?
|
||||
)
|
||||
end
|
||||
|
||||
sig { params(formula: Formula, new_formula_version: String).returns(T.nilable(T::Array[String])) }
|
||||
def alias_update_pair(formula, new_formula_version)
|
||||
versioned_alias = formula.aliases.grep(/^.*@\d+(\.\d+)?$/).first
|
||||
return if versioned_alias.nil?
|
||||
|
||||
name, old_alias_version = versioned_alias.split("@")
|
||||
return if old_alias_version.blank?
|
||||
|
||||
new_alias_regex = (old_alias_version.split(".").length == 1) ? /^\d+/ : /^\d+\.\d+/
|
||||
new_alias_version, = *new_formula_version.to_s.match(new_alias_regex)
|
||||
return if new_alias_version.blank?
|
||||
return if Version.new(new_alias_version) <= Version.new(old_alias_version)
|
||||
|
||||
[versioned_alias, "#{name}@#{new_alias_version}"]
|
||||
end
|
||||
|
||||
sig { params(formula: Formula, alias_rename: T.nilable(T::Array[String]), old_contents: String).void }
|
||||
def run_audit(formula, alias_rename, old_contents)
|
||||
audit_args = ["--formula"]
|
||||
audit_args << "--strict" if args.strict?
|
||||
@ -521,7 +562,9 @@ module Homebrew
|
||||
end
|
||||
return
|
||||
end
|
||||
FileUtils.mv alias_rename.first, alias_rename.last if alias_rename.present?
|
||||
if alias_rename && (source = alias_rename.first) && (destination = alias_rename.last)
|
||||
FileUtils.mv source, destination
|
||||
end
|
||||
failed_audit = false
|
||||
if args.no_audit?
|
||||
ohai "Skipping `brew audit`"
|
||||
@ -535,7 +578,9 @@ module Homebrew
|
||||
return unless failed_audit
|
||||
|
||||
formula.path.atomic_write(old_contents)
|
||||
FileUtils.mv alias_rename.last, alias_rename.first if alias_rename.present?
|
||||
if alias_rename && (source = alias_rename.first) && (destination = alias_rename.last)
|
||||
FileUtils.mv source, destination
|
||||
end
|
||||
odie "`brew audit` failed!"
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
@ -10,12 +10,12 @@ end
|
||||
module Homebrew
|
||||
module DevCmd
|
||||
class Contributions < AbstractCommand
|
||||
PRIMARY_REPOS = %w[brew core cask].freeze
|
||||
SUPPORTED_REPOS = [
|
||||
PRIMARY_REPOS = T.let(%w[brew core cask].freeze, T::Array[String])
|
||||
SUPPORTED_REPOS = T.let([
|
||||
PRIMARY_REPOS,
|
||||
OFFICIAL_CMD_TAPS.keys.map { |t| t.delete_prefix("homebrew/") },
|
||||
OFFICIAL_CASK_TAPS.reject { |t| t == "cask" },
|
||||
].flatten.freeze
|
||||
].flatten.freeze, T::Array[String])
|
||||
MAX_REPO_COMMITS = 1000
|
||||
|
||||
cmd_args do
|
||||
@ -50,9 +50,9 @@ module Homebrew
|
||||
results = {}
|
||||
grand_totals = {}
|
||||
|
||||
repos = if args.repositories.blank? || T.must(args.repositories).include?("primary")
|
||||
repos = if args.repositories.blank? || args.repositories&.include?("primary")
|
||||
PRIMARY_REPOS
|
||||
elsif T.must(args.repositories).include?("all")
|
||||
elsif args.repositories&.include?("all")
|
||||
SUPPORTED_REPOS
|
||||
else
|
||||
args.repositories
|
||||
@ -116,7 +116,7 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(totals: Hash).returns(String) }
|
||||
sig { params(totals: T::Hash[String, T::Hash[Symbol, Integer]]).returns(String) }
|
||||
def generate_csv(totals)
|
||||
CSV.generate do |csv|
|
||||
csv << %w[user repo author committer coauthor review total]
|
||||
@ -127,7 +127,14 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(user: String, grand_total: Hash).returns(Array) }
|
||||
sig {
|
||||
params(
|
||||
user: String,
|
||||
grand_total: T::Hash[Symbol, Integer],
|
||||
).returns(
|
||||
[String, String, T.nilable(Integer), T.nilable(Integer), T.nilable(Integer), T.nilable(Integer), Integer],
|
||||
)
|
||||
}
|
||||
def grand_total_row(user, grand_total)
|
||||
[
|
||||
user,
|
||||
@ -140,7 +147,10 @@ module Homebrew
|
||||
]
|
||||
end
|
||||
|
||||
sig { params(repos: T.nilable(T::Array[String]), person: String, from: String).void }
|
||||
def scan_repositories(repos, person, from:)
|
||||
return if repos.blank?
|
||||
|
||||
data = {}
|
||||
|
||||
repos.each do |repo|
|
||||
@ -168,7 +178,7 @@ module Homebrew
|
||||
data[repo] = {
|
||||
author: author_commits,
|
||||
committer: committer_commits,
|
||||
coauthor: git_log_trailers_cmd(T.must(repo_path), person, "Co-authored-by", from:, to: args.to),
|
||||
coauthor: git_log_trailers_cmd(repo_path, person, "Co-authored-by", from:, to: args.to),
|
||||
review: count_reviews(repo_full_name, person, from:, to: args.to),
|
||||
}
|
||||
end
|
||||
@ -176,7 +186,7 @@ module Homebrew
|
||||
data
|
||||
end
|
||||
|
||||
sig { params(results: Hash).returns(Hash) }
|
||||
sig { params(results: T::Hash[Symbol, T.untyped]).returns(T::Hash[Symbol, Integer]) }
|
||||
def total(results)
|
||||
totals = { author: 0, committer: 0, coauthor: 0, review: 0 }
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# typed: true
|
||||
# typed: true # This cannot be `# typed: strict` due to the use of `undef`.
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
@ -71,6 +71,7 @@ module Homebrew
|
||||
|
||||
private
|
||||
|
||||
sig { params(title: String).returns(String) }
|
||||
def html_template(title)
|
||||
<<~EOS
|
||||
---
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
@ -69,6 +69,7 @@ module Homebrew
|
||||
|
||||
private
|
||||
|
||||
sig { params(title: String).returns(String) }
|
||||
def html_template(title)
|
||||
<<~EOS
|
||||
---
|
||||
|
||||
@ -1,18 +1,20 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
require "formula"
|
||||
require "formulary"
|
||||
require "cask/cask_loader"
|
||||
|
||||
class String
|
||||
# @!visibility private
|
||||
sig { params(args: Integer).returns(Formula) }
|
||||
def f(*args)
|
||||
require "formula"
|
||||
Formulary.factory(self, *args)
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { params(config: T.nilable(T::Hash[Symbol, T.untyped])).returns(Cask::Cask) }
|
||||
def c(config: nil)
|
||||
Cask::CaskLoader.load(self, config:)
|
||||
end
|
||||
@ -20,11 +22,13 @@ end
|
||||
|
||||
class Symbol
|
||||
# @!visibility private
|
||||
sig { params(args: Integer).returns(Formula) }
|
||||
def f(*args)
|
||||
to_s.f(*args)
|
||||
end
|
||||
|
||||
# @!visibility private
|
||||
sig { params(config: T.nilable(T::Hash[Symbol, T.untyped])).returns(Cask::Cask) }
|
||||
def c(config: nil)
|
||||
to_s.c(config:)
|
||||
end
|
||||
@ -72,7 +76,6 @@ module Homebrew
|
||||
require "irb"
|
||||
end
|
||||
|
||||
require "formula"
|
||||
require "keg"
|
||||
require "cask"
|
||||
|
||||
@ -94,6 +97,7 @@ module Homebrew
|
||||
|
||||
# Remove the `--debug`, `--verbose` and `--quiet` options which cause problems
|
||||
# for IRB and have already been parsed by the CLI::Parser.
|
||||
sig { returns(T.nilable(T::Array[Symbol])) }
|
||||
def clean_argv
|
||||
global_options = Homebrew::CLI::Parser
|
||||
.global_options
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
@ -113,8 +113,9 @@ module Homebrew
|
||||
|
||||
private
|
||||
|
||||
sig { returns(String) }
|
||||
def watchlist_path
|
||||
@watchlist_path ||= File.expand_path(Homebrew::EnvConfig.livecheck_watchlist)
|
||||
@watchlist_path ||= T.let(File.expand_path(Homebrew::EnvConfig.livecheck_watchlist), T.nilable(String))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
@ -141,7 +141,7 @@ module Homebrew
|
||||
user, repo, pr, workflow_id: workflow, artifact_pattern:
|
||||
)
|
||||
if args.ignore_missing_artifacts.present? &&
|
||||
T.must(args.ignore_missing_artifacts).include?(workflow) &&
|
||||
args.ignore_missing_artifacts&.include?(workflow) &&
|
||||
workflow_run.first.blank?
|
||||
# Ignore that workflow as it was not executed and we specified
|
||||
# that we could skip it.
|
||||
@ -183,8 +183,10 @@ module Homebrew
|
||||
end
|
||||
|
||||
# Separates a commit message into subject, body and trailers.
|
||||
sig { params(message: String).returns([String, String, String]) }
|
||||
def separate_commit_message(message)
|
||||
subject = message.lines.first.strip
|
||||
first_line = message.lines.first
|
||||
return ["", "", ""] unless first_line
|
||||
|
||||
# Skip the subject and separate lines that look like trailers (e.g. "Co-authored-by")
|
||||
# from lines that look like regular body text.
|
||||
@ -193,11 +195,15 @@ module Homebrew
|
||||
trailers = trailers.uniq.join.strip
|
||||
body = body.join.strip.gsub(/\n{3,}/, "\n\n")
|
||||
|
||||
[subject, body, trailers]
|
||||
[first_line.strip, body, trailers]
|
||||
end
|
||||
|
||||
sig { params(git_repo: GitRepository, pull_request: T.nilable(String), dry_run: T::Boolean).void }
|
||||
def signoff!(git_repo, pull_request: nil, dry_run: false)
|
||||
subject, body, trailers = separate_commit_message(git_repo.commit_message)
|
||||
msg = git_repo.commit_message
|
||||
return if msg.blank?
|
||||
|
||||
subject, body, trailers = separate_commit_message(msg)
|
||||
|
||||
if pull_request
|
||||
# This is a tap pull request and approving reviewers should also sign-off.
|
||||
@ -210,7 +216,7 @@ module Homebrew
|
||||
|
||||
# Append the close message as well, unless the commit body already includes it.
|
||||
close_message = "Closes ##{pull_request}."
|
||||
body += "\n\n#{close_message}" unless body.include? close_message
|
||||
body.concat("\n\n#{close_message}") unless body.include?(close_message)
|
||||
end
|
||||
|
||||
git_args = Utils::Git.git, "-C", git_repo.pathname, "commit", "--amend", "--signoff", "--allow-empty",
|
||||
@ -223,6 +229,7 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(tap: Tap, subject_name: String, subject_path: Pathname, content: String).returns(T.untyped) }
|
||||
def get_package(tap, subject_name, subject_path, content)
|
||||
if subject_path.to_s.start_with?("#{tap.cask_dir}/")
|
||||
cask = begin
|
||||
@ -240,6 +247,10 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
|
||||
sig {
|
||||
params(old_contents: String, new_contents: String, subject_path: T.any(String, Pathname),
|
||||
reason: T.nilable(String)).returns(String)
|
||||
}
|
||||
def determine_bump_subject(old_contents, new_contents, subject_path, reason: nil)
|
||||
subject_path = Pathname(subject_path)
|
||||
tap = Tap.from_path(subject_path)
|
||||
@ -268,6 +279,10 @@ module Homebrew
|
||||
|
||||
# Cherry picks a single commit that modifies a single file.
|
||||
# Potentially rewords this commit using {determine_bump_subject}.
|
||||
sig {
|
||||
params(commit: String, file: String, git_repo: GitRepository, reason: T.nilable(String), verbose: T::Boolean,
|
||||
resolve: T::Boolean).void
|
||||
}
|
||||
def reword_package_commit(commit, file, git_repo:, reason: "", verbose: false, resolve: false)
|
||||
package_file = git_repo.pathname / file
|
||||
package_name = package_file.basename.to_s.chomp(".rb")
|
||||
@ -279,7 +294,10 @@ module Homebrew
|
||||
new_package = Utils::Git.file_at_commit(git_repo.to_s, file, "HEAD")
|
||||
|
||||
bump_subject = determine_bump_subject(old_package, new_package, package_file, reason:).strip
|
||||
subject, body, trailers = separate_commit_message(git_repo.commit_message)
|
||||
msg = git_repo.commit_message
|
||||
return if msg.blank?
|
||||
|
||||
subject, body, trailers = separate_commit_message(msg)
|
||||
|
||||
if subject != bump_subject && !subject.start_with?("#{package_name}:")
|
||||
safe_system("git", "-C", git_repo.pathname, "commit", "--amend", "-q",
|
||||
@ -293,6 +311,10 @@ module Homebrew
|
||||
# Cherry picks multiple commits that each modify a single file.
|
||||
# Words the commit according to {determine_bump_subject} with the body
|
||||
# corresponding to all the original commit messages combined.
|
||||
sig {
|
||||
params(commits: T::Array[String], file: String, git_repo: GitRepository, reason: T.nilable(String),
|
||||
verbose: T::Boolean, resolve: T::Boolean).void
|
||||
}
|
||||
def squash_package_commits(commits, file, git_repo:, reason: "", verbose: false, resolve: false)
|
||||
odebug "Squashing #{file}: #{commits.join " "}"
|
||||
|
||||
@ -304,7 +326,10 @@ module Homebrew
|
||||
messages = []
|
||||
trailers = []
|
||||
commits.each do |commit|
|
||||
subject, body, trailer = separate_commit_message(git_repo.commit_message(commit))
|
||||
msg = git_repo.commit_message(commit)
|
||||
next if msg.blank?
|
||||
|
||||
subject, body, trailer = separate_commit_message(msg)
|
||||
body = body.lines.map { |line| " #{line.strip}" }.join("\n")
|
||||
messages << "* #{subject}\n#{body}".strip
|
||||
trailers << trailer
|
||||
@ -340,9 +365,12 @@ module Homebrew
|
||||
end
|
||||
|
||||
# TODO: fix test in `test/dev-cmd/pr-pull_spec.rb` and assume `cherry_picked: false`.
|
||||
sig {
|
||||
params(original_commit: String, tap: Tap, reason: T.nilable(String), verbose: T::Boolean, resolve: T::Boolean,
|
||||
cherry_picked: T::Boolean).void
|
||||
}
|
||||
def autosquash!(original_commit, tap:, reason: "", verbose: false, resolve: false, cherry_picked: true)
|
||||
git_repo = tap.git_repository
|
||||
original_head = git_repo.head_ref
|
||||
|
||||
commits = Utils.safe_popen_read("git", "-C", tap.path, "rev-list",
|
||||
"--reverse", "#{original_commit}..HEAD").lines.map(&:strip)
|
||||
@ -402,14 +430,18 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
rescue
|
||||
original_head = git_repo&.head_ref
|
||||
return if original_head.nil?
|
||||
|
||||
opoo "Autosquash encountered an error; resetting to original state at #{original_head}"
|
||||
system "git", "-C", tap.path, "reset", "--hard", original_head
|
||||
system "git", "-C", tap.path, "cherry-pick", "--abort" if cherry_picked
|
||||
system "git", "-C", tap.path.to_s, "reset", "--hard", original_head
|
||||
system "git", "-C", tap.path.to_s, "cherry-pick", "--abort" if cherry_picked
|
||||
raise
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
sig { params(user: String, repo: String, pull_request: String, path: T.any(String, Pathname)).void }
|
||||
def cherry_pick_pr!(user, repo, pull_request, path: ".")
|
||||
if args.dry_run?
|
||||
puts <<~EOS
|
||||
@ -427,6 +459,7 @@ module Homebrew
|
||||
resolve: args.resolve?)
|
||||
end
|
||||
|
||||
sig { params(tap: Tap, original_commit: String, labels: T::Array[String]).returns(T::Boolean) }
|
||||
def formulae_need_bottles?(tap, original_commit, labels)
|
||||
return false if args.dry_run?
|
||||
|
||||
@ -437,6 +470,7 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(tap: Tap, original_commit: String).returns(T::Array[String]) }
|
||||
def changed_packages(tap, original_commit)
|
||||
formulae = Utils.popen_read("git", "-C", tap.path, "diff-tree",
|
||||
"-r", "--name-only", "--diff-filter=AM",
|
||||
@ -473,6 +507,7 @@ module Homebrew
|
||||
formulae + casks
|
||||
end
|
||||
|
||||
sig { params(repo: String, pull_request: String).void }
|
||||
def pr_check_conflicts(repo, pull_request)
|
||||
long_build_pr_files = GitHub.issues(
|
||||
repo:, state: "open", labels: "no long build conflict",
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
@ -120,6 +120,7 @@ module Homebrew
|
||||
|
||||
private
|
||||
|
||||
sig { params(bottles_hash: T::Hash[String, T.untyped]).void }
|
||||
def check_bottled_formulae!(bottles_hash)
|
||||
bottles_hash.each do |name, bottle_hash|
|
||||
formula_path = HOMEBREW_REPOSITORY/bottle_hash["formula"]["path"]
|
||||
@ -131,22 +132,25 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(bottles_hash: T::Hash[String, T.untyped]).returns(T::Boolean) }
|
||||
def github_releases?(bottles_hash)
|
||||
@github_releases ||= bottles_hash.values.all? do |bottle_hash|
|
||||
@github_releases ||= T.let(bottles_hash.values.all? do |bottle_hash|
|
||||
root_url = bottle_hash["bottle"]["root_url"]
|
||||
url_match = root_url.match GitHubReleases::URL_REGEX
|
||||
_, _, _, tag = *url_match
|
||||
|
||||
tag
|
||||
end
|
||||
end, T.nilable(T::Boolean))
|
||||
end
|
||||
|
||||
sig { params(bottles_hash: T::Hash[String, T.untyped]).returns(T::Boolean) }
|
||||
def github_packages?(bottles_hash)
|
||||
@github_packages ||= bottles_hash.values.all? do |bottle_hash|
|
||||
@github_packages ||= T.let(bottles_hash.values.all? do |bottle_hash|
|
||||
bottle_hash["bottle"]["root_url"].match? GitHubPackages::URL_REGEX
|
||||
end
|
||||
end, T.nilable(T::Boolean))
|
||||
end
|
||||
|
||||
sig { params(json_files: T::Array[String], args: T.untyped).returns(T::Hash[String, T.untyped]) }
|
||||
def bottles_hash_from_json_files(json_files, args)
|
||||
puts "Reading JSON files: #{json_files.join(", ")}" if args.verbose?
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
@ -197,6 +197,7 @@ module Homebrew
|
||||
|
||||
private
|
||||
|
||||
sig { params(tap: Tap, filename: T.any(String, Pathname), content: String).void }
|
||||
def write_path(tap, filename, content)
|
||||
path = tap.path/filename
|
||||
tap.path.mkpath
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
@ -110,8 +110,9 @@ module Homebrew
|
||||
|
||||
private
|
||||
|
||||
sig { params(formula: Formula).returns(T::Boolean) }
|
||||
def retry_test?(formula)
|
||||
@test_failed ||= Set.new
|
||||
@test_failed ||= T.let(Set.new, T.nilable(T::Set[T.untyped]))
|
||||
if args.retry? && @test_failed.add?(formula)
|
||||
oh1 "Testing #{formula.full_name} (again)"
|
||||
formula.clear_cache
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
@ -168,15 +168,17 @@ module Homebrew
|
||||
|
||||
private
|
||||
|
||||
sig { returns(T.nilable(T::Boolean)) }
|
||||
def use_buildpulse?
|
||||
return @use_buildpulse if defined?(@use_buildpulse)
|
||||
|
||||
@use_buildpulse = ENV["HOMEBREW_BUILDPULSE_ACCESS_KEY_ID"].present? &&
|
||||
@use_buildpulse = T.let(ENV["HOMEBREW_BUILDPULSE_ACCESS_KEY_ID"].present? &&
|
||||
ENV["HOMEBREW_BUILDPULSE_SECRET_ACCESS_KEY"].present? &&
|
||||
ENV["HOMEBREW_BUILDPULSE_ACCOUNT_ID"].present? &&
|
||||
ENV["HOMEBREW_BUILDPULSE_REPOSITORY_ID"].present?
|
||||
ENV["HOMEBREW_BUILDPULSE_REPOSITORY_ID"].present?, T.nilable(T::Boolean))
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def run_buildpulse
|
||||
require "formula"
|
||||
|
||||
@ -198,6 +200,7 @@ module Homebrew
|
||||
]
|
||||
end
|
||||
|
||||
sig { returns(T::Array[String]) }
|
||||
def changed_test_files
|
||||
changed_files = Utils.popen_read("git", "diff", "--name-only", "master")
|
||||
|
||||
@ -215,6 +218,7 @@ module Homebrew
|
||||
end.select(&:exist?)
|
||||
end
|
||||
|
||||
sig { returns(T::Array[String]) }
|
||||
def setup_environment!
|
||||
# Cleanup any unwanted user configuration.
|
||||
allowed_test_env = %w[
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
@ -34,11 +34,15 @@ module Homebrew
|
||||
def run
|
||||
Formulary.enable_factory_cache!
|
||||
|
||||
@bottle_tag = if (tag = args.tag)
|
||||
Utils::Bottles::Tag.from_symbol(tag.to_sym)
|
||||
else
|
||||
Utils::Bottles.tag
|
||||
end
|
||||
@bottle_tag = T.let(
|
||||
if (tag = args.tag)
|
||||
Utils::Bottles::Tag.from_symbol(tag.to_sym)
|
||||
else
|
||||
Utils::Bottles.tag
|
||||
end,
|
||||
T.nilable(Utils::Bottles::Tag),
|
||||
)
|
||||
return unless @bottle_tag
|
||||
|
||||
if args.lost?
|
||||
if args.named.present?
|
||||
@ -98,12 +102,17 @@ module Homebrew
|
||||
["installs", formula_installs]
|
||||
end
|
||||
|
||||
return if hash.nil?
|
||||
|
||||
output_unbottled(formulae, deps_hash, noun, hash, args.named.present?)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
sig {
|
||||
params(all: T::Boolean).returns([T::Array[Formula], T::Array[Formula], T.nilable(T::Hash[Symbol, Integer])])
|
||||
}
|
||||
def formulae_all_installs_from_args(all)
|
||||
if args.named.present?
|
||||
formulae = all_formulae = args.named.to_formulae
|
||||
@ -115,7 +124,7 @@ module Homebrew
|
||||
|
||||
formulae = all_formulae = Formula.all(eval_all: args.eval_all?)
|
||||
|
||||
@sort = " (sorted by number of dependents)"
|
||||
@sort = T.let(" (sorted by number of dependents)", T.nilable(String))
|
||||
elsif all
|
||||
formulae = all_formulae = Formula.all(eval_all: args.eval_all?)
|
||||
else
|
||||
@ -142,7 +151,7 @@ module Homebrew
|
||||
nil
|
||||
end
|
||||
end
|
||||
@sort = " (sorted by installs in the last 90 days; top 10,000 only)"
|
||||
@sort = T.let(" (sorted by installs in the last 90 days; top 10,000 only)", T.nilable(String))
|
||||
|
||||
all_formulae = Formula.all(eval_all: args.eval_all?)
|
||||
end
|
||||
@ -151,9 +160,11 @@ module Homebrew
|
||||
formulae = Array(formulae).reject(&:deprecated?) if formulae.present?
|
||||
all_formulae = Array(all_formulae).reject(&:deprecated?) if all_formulae.present?
|
||||
|
||||
[formulae, all_formulae, formula_installs]
|
||||
[T.let(formulae, T::Array[Formula]), T.let(all_formulae, T::Array[Formula]),
|
||||
T.let(formula_installs, T.nilable(T::Hash[Symbol, Integer]))]
|
||||
end
|
||||
|
||||
sig { params(all_formulae: T.untyped).returns([T::Hash[String, T.untyped], T::Hash[String, T.untyped]]) }
|
||||
def deps_uses_from_formulae(all_formulae)
|
||||
ohai "Populating dependency tree..."
|
||||
|
||||
@ -175,7 +186,10 @@ module Homebrew
|
||||
[deps_hash, uses_hash]
|
||||
end
|
||||
|
||||
sig { params(formulae: T::Array[Formula]).returns(NilClass) }
|
||||
def output_total(formulae)
|
||||
return unless @bottle_tag
|
||||
|
||||
ohai "Unbottled :#{@bottle_tag} formulae"
|
||||
unbottled_formulae = 0
|
||||
|
||||
@ -188,7 +202,14 @@ module Homebrew
|
||||
puts "#{unbottled_formulae}/#{formulae.length} remaining."
|
||||
end
|
||||
|
||||
sig {
|
||||
params(formulae: T::Array[Formula], deps_hash: T::Hash[T.any(Symbol, String), T.untyped],
|
||||
noun: T.nilable(String), hash: T::Hash[T.any(Symbol, String), T.untyped],
|
||||
any_named_args: T::Boolean).returns(NilClass)
|
||||
}
|
||||
def output_unbottled(formulae, deps_hash, noun, hash, any_named_args)
|
||||
return unless @bottle_tag
|
||||
|
||||
ohai ":#{@bottle_tag} bottle status#{@sort}"
|
||||
any_found = T.let(false, T::Boolean)
|
||||
|
||||
@ -258,6 +279,7 @@ module Homebrew
|
||||
puts "No unbottled dependencies found!"
|
||||
end
|
||||
|
||||
sig { returns(NilClass) }
|
||||
def output_lost_bottles
|
||||
ohai ":#{@bottle_tag} lost bottles"
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# typed: true
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "abstract_command"
|
||||
@ -62,14 +62,17 @@ module Homebrew
|
||||
|
||||
private
|
||||
|
||||
sig { params(sponsor: T::Hash[Symbol, T.untyped]).returns(T.nilable(String)) }
|
||||
def sponsor_name(sponsor)
|
||||
sponsor[:name] || sponsor[:login]
|
||||
end
|
||||
|
||||
sig { params(sponsor: T::Hash[Symbol, T.untyped]).returns(String) }
|
||||
def sponsor_logo(sponsor)
|
||||
"https://github.com/#{sponsor[:login]}.png?size=64"
|
||||
end
|
||||
|
||||
sig { params(sponsor: T::Hash[Symbol, T.untyped]).returns(String) }
|
||||
def sponsor_url(sponsor)
|
||||
"https://github.com/#{sponsor[:login]}"
|
||||
end
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user