Merge pull request #18004 from Homebrew/more-srb-strict

This commit is contained in:
Mike McQuaid 2024-08-12 14:22:00 +01:00 committed by GitHub
commit 6105728c31
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 98 additions and 44 deletions

View File

@ -743,7 +743,7 @@ module Cask
def audit_github_prerelease_version
odebug "Auditing GitHub prerelease"
user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) if online?
return if user.nil?
return if user.nil? || repo.nil?
tag = SharedAudits.github_tag_from_url(cask.url)
tag ||= cask.version
@ -754,7 +754,7 @@ module Cask
sig { void }
def audit_gitlab_prerelease_version
user, repo = get_repo_data(%r{https?://gitlab\.com/([^/]+)/([^/]+)/?.*}) if online?
return if user.nil?
return if user.nil? || repo.nil?
odebug "Auditing GitLab prerelease"
@ -770,7 +770,7 @@ module Cask
return if cask.deprecated? || cask.disabled?
user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) if online?
return if user.nil?
return if user.nil? || repo.nil?
metadata = SharedAudits.github_repo_data(user, repo)
return if metadata.nil?
@ -784,7 +784,7 @@ module Cask
return if cask.deprecated? || cask.disabled?
user, repo = get_repo_data(%r{https?://gitlab\.com/([^/]+)/([^/]+)/?.*}) if online?
return if user.nil?
return if user.nil? || repo.nil?
odebug "Auditing GitLab repo archived"
@ -799,7 +799,7 @@ module Cask
return unless new_cask?
user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*})
return if user.nil?
return if user.nil? || repo.nil?
odebug "Auditing GitHub repo"
@ -812,7 +812,7 @@ module Cask
return unless new_cask?
user, repo = get_repo_data(%r{https?://gitlab\.com/([^/]+)/([^/]+)/?.*})
return if user.nil?
return if user.nil? || repo.nil?
odebug "Auditing GitLab repo"
@ -825,7 +825,7 @@ module Cask
return unless new_cask?
user, repo = get_repo_data(%r{https?://bitbucket\.org/([^/]+)/([^/]+)/?.*})
return if user.nil?
return if user.nil? || repo.nil?
odebug "Auditing Bitbucket repo"

View File

@ -1,4 +1,4 @@
# typed: true
# typed: strict
# frozen_string_literal: true
module Utils
@ -21,6 +21,7 @@ module Utils
alias generic_find_matching_tag find_matching_tag
sig { params(tag: Utils::Bottles::Tag, no_older_versions: T::Boolean).returns(T.nilable(Utils::Bottles::Tag)) }
def find_matching_tag(tag, no_older_versions: false)
# Used primarily by developers testing beta macOS releases.
if no_older_versions ||
@ -35,6 +36,7 @@ module Utils
end
# Find a bottle built for a previous version of macOS.
sig { params(tag: Utils::Bottles::Tag).returns(T.nilable(Utils::Bottles::Tag)) }
def find_older_compatible_tag(tag)
tag_version = begin
tag.to_macos_version

View File

@ -587,15 +587,13 @@ module Homebrew
metadata = SharedAudits.eol_data(name, formula.version.major)
metadata ||= SharedAudits.eol_data(name, formula.version.major_minor)
return if metadata.blank? || metadata["eol"] == false
return if metadata.blank? || (eol_date = metadata["eol"]).blank?
see_url = "see #{Formatter.url("https://endoflife.date/#{name}")}"
if metadata["eol"] == true
problem "Product is EOL, #{see_url}"
return
end
message = "Product is EOL"
message += " since #{eol_date}" if Date.parse(eol_date.to_s) <= Date.today
message += ", see #{Formatter.url("https://endoflife.date/#{name}")}"
problem "Product is EOL since #{metadata["eol"]}, #{see_url}" if Date.parse(metadata["eol"]) <= Date.today
problem message
end
def audit_wayback_url
@ -783,8 +781,8 @@ module Homebrew
problem "#{stable.version} is a development release"
when %r{https?://gitlab\.com/([\w-]+)/([\w-]+)}
owner = Regexp.last_match(1)
repo = Regexp.last_match(2)
owner = T.must(Regexp.last_match(1))
repo = T.must(Regexp.last_match(2))
tag = SharedAudits.gitlab_tag_from_url(url)
tag ||= stable.specs[:tag]
@ -795,8 +793,8 @@ module Homebrew
problem error if error
end
when %r{^https://github.com/([\w-]+)/([\w-]+)}
owner = Regexp.last_match(1)
repo = Regexp.last_match(2)
owner = T.must(Regexp.last_match(1))
repo = T.must(Regexp.last_match(2))
tag = SharedAudits.github_tag_from_url(url)
tag ||= formula.stable.specs[:tag]

View File

@ -1,27 +1,33 @@
# typed: true
# typed: strict
# frozen_string_literal: true
# Helper for checking if a file is considered a metadata file.
module Metafiles
LICENSES = Set.new(%w[copying copyright license licence]).freeze
LICENSES = T.let(Set.new(%w[copying copyright license licence]).freeze, T::Set[String])
# {https://github.com/github/markup#markups}
EXTENSIONS = Set.new(%w[
EXTENSIONS = T.let(Set.new(%w[
.adoc .asc .asciidoc .creole .html .markdown .md .mdown .mediawiki .mkdn
.org .pod .rdoc .rst .rtf .textile .txt .wiki
]).freeze
BASENAMES = Set.new(%w[about authors changelog changes history news notes notice readme todo]).freeze
]).freeze, T::Set[String])
BASENAMES = T.let(Set.new(%w[
about authors changelog changes history news notes notice readme todo
]).freeze, T::Set[String])
module_function
sig { params(file: String).returns(T::Boolean) }
def list?(file)
return false if %w[.DS_Store INSTALL_RECEIPT.json].include?(file)
!copy?(file)
end
sig { params(file: String).returns(T::Boolean) }
def copy?(file)
file = file.downcase
return true if LICENSES.include? file.split(/\.|-/).first
license = file.split(/\.|-/).first
return false unless license
return true if LICENSES.include?(license)
ext = File.extname(file)
file = File.basename(file, ext) if EXTENSIONS.include?(ext)

View File

@ -1,4 +1,4 @@
# typed: true
# typed: strict
# frozen_string_literal: true
require "formulary"
@ -7,11 +7,13 @@ module Homebrew
# Helper module for checking if there is a reason a formula is missing.
module MissingFormula
class << self
sig { params(name: String, silent: T::Boolean, show_info: T::Boolean).returns(T.nilable(String)) }
def reason(name, silent: false, show_info: false)
cask_reason(name, silent:, show_info:) || disallowed_reason(name) ||
tap_migration_reason(name) || deleted_reason(name, silent:)
end
sig { params(name: String).returns(T.nilable(String)) }
def disallowed_reason(name)
case name.downcase
when "gem", /^rubygems?$/ then <<~EOS
@ -93,6 +95,7 @@ module Homebrew
end
alias generic_disallowed_reason disallowed_reason
sig { params(name: String).returns(T.nilable(String)) }
def tap_migration_reason(name)
message = T.let(nil, T.nilable(String))
@ -127,6 +130,7 @@ module Homebrew
message
end
sig { params(name: String, silent: T::Boolean).returns(T.nilable(String)) }
def deleted_reason(name, silent: false)
path = Formulary.path name
return if File.exist? path

View File

@ -1,4 +1,4 @@
# typed: true
# typed: strict
# frozen_string_literal: true
require "formula"
@ -16,6 +16,7 @@ module Readall
private_class_method :cache
sig { params(ruby_files: T::Array[Pathname]).returns(T::Boolean) }
def self.valid_ruby_syntax?(ruby_files)
failed = T.let(false, T::Boolean)
ruby_files.each do |ruby_file|
@ -25,6 +26,7 @@ module Readall
!failed
end
sig { params(alias_dir: Pathname, formula_dir: Pathname).returns(T::Boolean) }
def self.valid_aliases?(alias_dir, formula_dir)
return true unless alias_dir.directory?
@ -46,6 +48,7 @@ module Readall
!failed
end
sig { params(tap: Tap, bottle_tag: T.nilable(Utils::Bottles::Tag)).returns(T::Boolean) }
def self.valid_formulae?(tap, bottle_tag: nil)
cache[:valid_formulae] ||= {}
@ -55,7 +58,7 @@ module Readall
next if valid == true || valid&.include?(bottle_tag)
formula_name = file.basename(".rb").to_s
formula_contents = file.read(encoding: "UTF-8")
formula_contents = file.read.force_encoding("UTF-8")
readall_namespace = "ReadallNamespace"
readall_formula_class = Formulary.load_formula(formula_name, file, formula_contents, readall_namespace,
@ -79,10 +82,16 @@ module Readall
success
end
sig { params(_tap: Tap, os_name: T.nilable(Symbol), arch: T.nilable(Symbol)).returns(T::Boolean) }
def self.valid_casks?(_tap, os_name: nil, arch: nil)
true
end
sig {
params(
tap: Tap, aliases: T::Boolean, no_simulate: T::Boolean, os_arch_combinations: T::Array[T::Array[String]],
).returns(T::Boolean)
}
def self.valid_tap?(tap, aliases: false, no_simulate: false,
os_arch_combinations: OnSystem::ALL_OS_ARCH_COMBINATIONS)
success = true
@ -110,6 +119,7 @@ module Readall
success
end
sig { params(filename: Pathname).returns(T::Boolean) }
private_class_method def self.syntax_errors_or_warnings?(filename)
# Retrieve messages about syntax errors/warnings printed to `$stderr`.
_, err, status = system_command(RUBY_PATH, args: ["-c", "-w", filename], print_stderr: false)

View File

@ -1,9 +1,10 @@
# typed: true
# typed: strict
# frozen_string_literal: true
module Homebrew
# Provides helper methods for unlinking formulae and kegs with consistent output.
module Unlink
sig { params(formula: Formula, verbose: T::Boolean).void }
def self.unlink_versioned_formulae(formula, verbose: false)
formula.versioned_formulae
.select(&:keg_only?)
@ -15,6 +16,7 @@ module Homebrew
end
end
sig { params(keg: Keg, dry_run: T::Boolean, verbose: T::Boolean).void }
def self.unlink(keg, dry_run: false, verbose: false)
options = { dry_run:, verbose: }

View File

@ -1,9 +1,10 @@
# typed: true
# typed: strict
# frozen_string_literal: true
module Utils
# Helper functions for creating symlinks.
module Link
sig { params(src_dir: Pathname, dst_dir: Pathname, command: String, link_dir: T::Boolean).void }
def self.link_src_dst_dirs(src_dir, dst_dir, command, link_dir: false)
return unless src_dir.exist?
@ -38,6 +39,7 @@ module Utils
end
private_class_method :link_src_dst_dirs
sig { params(src_dir: Pathname, dst_dir: Pathname, unlink_dir: T::Boolean).void }
def self.unlink_src_dst_dirs(src_dir, dst_dir, unlink_dir: false)
return unless src_dir.exist?
@ -52,26 +54,31 @@ module Utils
end
private_class_method :unlink_src_dst_dirs
sig { params(path: Pathname, command: String).void }
def self.link_manpages(path, command)
link_src_dst_dirs(path/"manpages", HOMEBREW_PREFIX/"share/man/man1", command)
end
sig { params(path: Pathname).void }
def self.unlink_manpages(path)
unlink_src_dst_dirs(path/"manpages", HOMEBREW_PREFIX/"share/man/man1")
end
sig { params(path: Pathname, command: String).void }
def self.link_completions(path, command)
link_src_dst_dirs(path/"completions/bash", HOMEBREW_PREFIX/"etc/bash_completion.d", command)
link_src_dst_dirs(path/"completions/zsh", HOMEBREW_PREFIX/"share/zsh/site-functions", command)
link_src_dst_dirs(path/"completions/fish", HOMEBREW_PREFIX/"share/fish/vendor_completions.d", command)
end
sig { params(path: Pathname).void }
def self.unlink_completions(path)
unlink_src_dst_dirs(path/"completions/bash", HOMEBREW_PREFIX/"etc/bash_completion.d")
unlink_src_dst_dirs(path/"completions/zsh", HOMEBREW_PREFIX/"share/zsh/site-functions")
unlink_src_dst_dirs(path/"completions/fish", HOMEBREW_PREFIX/"share/fish/vendor_completions.d")
end
sig { params(path: Pathname, command: String).void }
def self.link_docs(path, command)
link_src_dst_dirs(path/"docs", HOMEBREW_PREFIX/"share/doc/homebrew", command, link_dir: true)
end

View File

@ -1,4 +1,4 @@
# typed: true
# typed: strict
# frozen_string_literal: true
module Utils
@ -27,7 +27,7 @@ module Utils
return @launchctl if defined? @launchctl
return if ENV["HOMEBREW_TEST_GENERIC_OS"]
@launchctl = which("launchctl")
@launchctl = T.let(which("launchctl"), T.nilable(Pathname))
end
# Path to systemctl binary.
@ -36,7 +36,7 @@ module Utils
return @systemctl if defined? @systemctl
return if ENV["HOMEBREW_TEST_GENERIC_OS"]
@systemctl = which("systemctl")
@systemctl = T.let(which("systemctl"), T.nilable(Pathname))
end
sig { returns(T::Boolean) }

View File

@ -1,4 +1,4 @@
# typed: true
# typed: strict
# frozen_string_literal: true
require "utils/curl"
@ -10,8 +10,9 @@ module SharedAudits
module_function
sig { params(product: String, cycle: String).returns(T.nilable(T::Hash[String, T::Hash[Symbol, T.untyped]])) }
def eol_data(product, cycle)
@eol_data ||= {}
@eol_data ||= T.let({}, T.nilable(T::Hash[String, T::Hash[String, T.untyped]]))
@eol_data["#{product}/#{cycle}"] ||= begin
out, _, status = Utils::Curl.curl_output("--location", "https://endoflife.date/api/#{product}/#{cycle}.json")
json = JSON.parse(out) if status.success?
@ -20,8 +21,9 @@ module SharedAudits
end
end
sig { params(user: String, repo: String).returns(T.nilable(T::Hash[String, T.untyped])) }
def github_repo_data(user, repo)
@github_repo_data ||= {}
@github_repo_data ||= T.let({}, T.nilable(T::Hash[String, T.untyped]))
@github_repo_data["#{user}/#{repo}"] ||= GitHub.repository(user, repo)
@github_repo_data["#{user}/#{repo}"]
@ -31,10 +33,11 @@ module SharedAudits
raise unless e.message.match?(GitHub::API::GITHUB_IP_ALLOWLIST_ERROR)
end
sig { params(user: String, repo: String, tag: String).returns(T.nilable(T::Hash[String, T.untyped])) }
def github_release_data(user, repo, tag)
id = "#{user}/#{repo}/#{tag}"
url = "#{GitHub::API_URL}/repos/#{user}/#{repo}/releases/tags/#{tag}"
@github_release_data ||= {}
@github_release_data ||= T.let({}, T.nilable(T::Hash[String, T.untyped]))
@github_release_data[id] ||= GitHub::API.open_rest(url)
@github_release_data[id]
@ -44,6 +47,13 @@ module SharedAudits
raise unless e.message.match?(GitHub::API::GITHUB_IP_ALLOWLIST_ERROR)
end
sig {
params(
user: String, repo: String, tag: String, formula: T.nilable(Formula), cask: T.nilable(Cask::Cask),
).returns(
T.nilable(String),
)
}
def github_release(user, repo, tag, formula: nil, cask: nil)
release = github_release_data(user, repo, tag)
return unless release
@ -63,8 +73,9 @@ module SharedAudits
"#{tag} is a GitHub draft." if release["draft"]
end
sig { params(user: String, repo: String).returns(T.nilable(T::Hash[String, T.untyped])) }
def gitlab_repo_data(user, repo)
@gitlab_repo_data ||= {}
@gitlab_repo_data ||= T.let({}, T.nilable(T::Hash[String, T.untyped]))
@gitlab_repo_data["#{user}/#{repo}"] ||= begin
out, _, status = Utils::Curl.curl_output("https://gitlab.com/api/v4/projects/#{user}%2F#{repo}")
json = JSON.parse(out) if status.success?
@ -73,9 +84,10 @@ module SharedAudits
end
end
sig { params(user: String, repo: String, tag: String).returns(T.nilable(T::Hash[String, T.untyped])) }
def gitlab_release_data(user, repo, tag)
id = "#{user}/#{repo}/#{tag}"
@gitlab_release_data ||= {}
@gitlab_release_data ||= T.let({}, T.nilable(T::Hash[String, T.untyped]))
@gitlab_release_data[id] ||= begin
out, _, status = Utils::Curl.curl_output(
"https://gitlab.com/api/v4/projects/#{user}%2F#{repo}/releases/#{tag}", "--fail"
@ -84,6 +96,13 @@ module SharedAudits
end
end
sig {
params(
user: String, repo: String, tag: String, formula: T.nilable(Formula), cask: T.nilable(Cask::Cask),
).returns(
T.nilable(String),
)
}
def gitlab_release(user, repo, tag, formula: nil, cask: nil)
release = gitlab_release_data(user, repo, tag)
return unless release
@ -100,6 +119,7 @@ module SharedAudits
"#{tag} is a GitLab pre-release."
end
sig { params(user: String, repo: String).returns(T.nilable(String)) }
def github(user, repo)
metadata = github_repo_data(user, repo)
@ -117,6 +137,7 @@ module SharedAudits
"GitHub repository too new (<30 days old)"
end
sig { params(user: String, repo: String).returns(T.nilable(String)) }
def gitlab(user, repo)
metadata = gitlab_repo_data(user, repo)
@ -132,6 +153,7 @@ module SharedAudits
"GitLab repository too new (<30 days old)"
end
sig { params(user: String, repo: String).returns(T.nilable(String)) }
def bitbucket(user, repo)
api_url = "https://api.bitbucket.org/2.0/repositories/#{user}/#{repo}"
out, _, status = Utils::Curl.curl_output("--request", "GET", api_url)
@ -163,6 +185,7 @@ module SharedAudits
"Bitbucket repository not notable enough (<30 forks and <75 watchers)"
end
sig { params(url: String).returns(T.nilable(String)) }
def github_tag_from_url(url)
url = url.to_s
tag = url.match(%r{^https://github\.com/[\w-]+/[\w-]+/archive/refs/tags/([^/]+)\.(tar\.gz|zip)$})
@ -174,6 +197,7 @@ module SharedAudits
tag
end
sig { params(url: String).returns(T.nilable(String)) }
def gitlab_tag_from_url(url)
url = url.to_s
url.match(%r{^https://gitlab\.com/[\w-]+/[\w-]+/-/archive/([^/]+)/})

View File

@ -1,4 +1,4 @@
# typed: true
# typed: strict
# frozen_string_literal: true
require "system_command"
@ -19,7 +19,7 @@ module Utils
return @version if defined?(@version)
stdout, _, status = system_command(HOMEBREW_SHIMS_PATH/"shared/svn", args: ["--version"], print_stderr: false)
@version = status.success? ? stdout.chomp[/svn, version (\d+(?:\.\d+)*)/, 1] : nil
@version = T.let(status.success? ? stdout.chomp[/svn, version (\d+(?:\.\d+)*)/, 1] : nil, T.nilable(String))
end
sig { params(url: String).returns(T::Boolean) }
@ -34,7 +34,7 @@ module Utils
system_command("svn", args: args.concat(invalid_cert_flags), print_stderr: false).success?
end
sig { returns(Array) }
sig { returns(T::Array[String]) }
def invalid_cert_flags
opoo "Ignoring Subversion certificate errors!"
args = ["--non-interactive", "--trust-server-cert"]
@ -44,6 +44,7 @@ module Utils
args
end
sig { void }
def clear_version_cache
remove_instance_variable(:@version) if defined?(@version)
end

View File

@ -1,4 +1,4 @@
# typed: true
# typed: strict
# frozen_string_literal: true
require "delegate"
@ -29,6 +29,6 @@ class User < SimpleDelegator
pwuid = Etc.getpwuid(Process.euid)
return if pwuid.nil?
@current = new(pwuid.name)
@current = T.let(new(pwuid.name), T.nilable(T.attached_class))
end
end