2020-10-10 14:16:11 +02:00
|
|
|
# typed: false
|
2019-04-19 15:38:03 +09:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2015-05-24 16:14:44 +01:00
|
|
|
require "formula"
|
2016-01-14 13:33:56 +08:00
|
|
|
require "formula_versions"
|
2017-12-03 14:02:55 +01:00
|
|
|
require "utils/curl"
|
2020-09-10 22:00:18 +02:00
|
|
|
require "utils/github/actions"
|
2020-08-26 09:42:39 +02:00
|
|
|
require "utils/shared_audits"
|
2020-08-04 10:07:57 -07:00
|
|
|
require "utils/spdx"
|
2015-05-24 16:14:44 +01:00
|
|
|
require "extend/ENV"
|
|
|
|
require "formula_cellar_checks"
|
2015-05-31 18:40:28 +08:00
|
|
|
require "cmd/search"
|
2018-06-05 23:19:18 -04:00
|
|
|
require "style"
|
2015-07-09 15:28:27 +01:00
|
|
|
require "date"
|
2017-03-18 17:02:08 +02:00
|
|
|
require "missing_formula"
|
2017-02-02 21:25:29 +00:00
|
|
|
require "digest"
|
2019-04-17 18:25:08 +09:00
|
|
|
require "cli/parser"
|
2020-06-16 01:00:36 +08:00
|
|
|
require "json"
|
2020-11-18 10:25:12 +01:00
|
|
|
require "formula_auditor"
|
2020-11-18 10:05:23 +01:00
|
|
|
require "tap_auditor"
|
2012-03-17 19:49:49 -07:00
|
|
|
|
2014-06-18 22:41:47 -05:00
|
|
|
module Homebrew
|
2020-10-20 12:03:48 +02:00
|
|
|
extend T::Sig
|
|
|
|
|
2016-09-26 01:44:51 +02:00
|
|
|
module_function
|
|
|
|
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(CLI::Parser) }
|
2018-07-30 18:25:38 +05:30
|
|
|
def audit_args
|
|
|
|
Homebrew::CLI::Parser.new do
|
2018-09-08 22:21:04 +05:30
|
|
|
usage_banner <<~EOS
|
2019-08-06 14:17:17 -04:00
|
|
|
`audit` [<options>] [<formula>]
|
2018-06-28 09:28:19 +05:30
|
|
|
|
2019-01-30 21:33:03 +00:00
|
|
|
Check <formula> for Homebrew coding style violations. This should be run before
|
2019-08-20 00:04:14 -04:00
|
|
|
submitting a new formula. If no <formula> are provided, check all locally
|
2020-06-08 15:00:09 +01:00
|
|
|
available formulae and skip style checks. Will exit with a non-zero status if any
|
|
|
|
errors are found.
|
2018-06-28 09:28:19 +05:30
|
|
|
EOS
|
2018-09-22 09:31:30 +05:30
|
|
|
switch "--strict",
|
2020-04-16 08:24:38 +01:00
|
|
|
description: "Run additional, stricter style checks."
|
2020-06-08 15:00:09 +01:00
|
|
|
switch "--git",
|
|
|
|
description: "Run additional, slower style checks that navigate the Git repository."
|
2018-09-22 09:31:30 +05:30
|
|
|
switch "--online",
|
2020-04-16 08:24:38 +01:00
|
|
|
description: "Run additional, slower style checks that require a network connection."
|
2018-09-22 09:31:30 +05:30
|
|
|
switch "--new-formula",
|
2019-04-30 08:44:35 +01:00
|
|
|
description: "Run various additional style checks to determine if a new formula is eligible "\
|
|
|
|
"for Homebrew. This should be used when creating new formula and implies "\
|
|
|
|
"`--strict` and `--online`."
|
2020-08-06 09:43:02 +01:00
|
|
|
flag "--tap=",
|
|
|
|
description: "Check the formulae within the given tap, specified as <user>`/`<repo>."
|
2018-09-22 09:31:30 +05:30
|
|
|
switch "--fix",
|
2019-04-30 08:44:35 +01:00
|
|
|
description: "Fix style violations automatically using RuboCop's auto-correct feature."
|
2018-09-22 09:31:30 +05:30
|
|
|
switch "--display-cop-names",
|
2019-04-30 08:44:35 +01:00
|
|
|
description: "Include the RuboCop cop name for each violation in the output."
|
2018-09-22 09:31:30 +05:30
|
|
|
switch "--display-filename",
|
2019-08-06 14:22:24 -04:00
|
|
|
description: "Prefix every line of output with the file or formula name being audited, to "\
|
2019-04-30 08:44:35 +01:00
|
|
|
"make output easy to grep."
|
2020-04-16 08:24:38 +01:00
|
|
|
switch "--skip-style",
|
|
|
|
description: "Skip running non-RuboCop style checks. Useful if you plan on running "\
|
2020-11-12 10:40:48 -05:00
|
|
|
"`brew style` separately. Enabled by default unless a formula is specified by name."
|
2018-09-22 09:31:30 +05:30
|
|
|
switch "-D", "--audit-debug",
|
2019-04-30 08:44:35 +01:00
|
|
|
description: "Enable debugging and profiling of audit methods."
|
2018-09-22 09:31:30 +05:30
|
|
|
comma_array "--only",
|
2019-04-30 08:44:35 +01:00
|
|
|
description: "Specify a comma-separated <method> list to only run the methods named "\
|
|
|
|
"`audit_`<method>."
|
2018-09-22 09:31:30 +05:30
|
|
|
comma_array "--except",
|
2019-04-30 08:44:35 +01:00
|
|
|
description: "Specify a comma-separated <method> list to skip running the methods named "\
|
|
|
|
"`audit_`<method>."
|
2018-09-22 09:31:30 +05:30
|
|
|
comma_array "--only-cops",
|
2019-04-30 08:44:35 +01:00
|
|
|
description: "Specify a comma-separated <cops> list to check for violations of only the listed "\
|
|
|
|
"RuboCop cops."
|
2018-09-22 09:31:30 +05:30
|
|
|
comma_array "--except-cops",
|
2019-04-30 08:44:35 +01:00
|
|
|
description: "Specify a comma-separated <cops> list to skip checking for violations of the listed "\
|
|
|
|
"RuboCop cops."
|
2020-07-30 18:40:10 +02:00
|
|
|
|
2018-10-08 22:49:03 -04:00
|
|
|
conflicts "--only", "--except"
|
2019-12-11 14:59:47 -05:00
|
|
|
conflicts "--only-cops", "--except-cops", "--strict"
|
|
|
|
conflicts "--only-cops", "--except-cops", "--only"
|
2020-04-16 08:24:38 +01:00
|
|
|
conflicts "--display-cop-names", "--skip-style"
|
|
|
|
conflicts "--display-cop-names", "--only-cops"
|
|
|
|
conflicts "--display-cop-names", "--except-cops"
|
2018-03-25 17:48:22 +05:30
|
|
|
end
|
2018-07-30 18:25:38 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
def audit
|
2020-07-23 06:25:35 +02:00
|
|
|
args = audit_args.parse
|
2018-02-04 22:09:35 +05:30
|
|
|
|
2017-09-02 12:38:18 +05:30
|
|
|
Homebrew.auditing = true
|
2018-02-04 22:09:35 +05:30
|
|
|
inject_dump_stats!(FormulaAuditor, /^audit_/) if args.audit_debug?
|
2016-04-18 17:39:21 -04:00
|
|
|
|
2012-08-07 01:37:46 -05:00
|
|
|
formula_count = 0
|
|
|
|
problem_count = 0
|
2018-08-26 19:33:19 +05:30
|
|
|
corrected_problem_count = 0
|
2018-05-22 18:16:46 +05:30
|
|
|
new_formula_problem_count = 0
|
2018-02-04 22:09:35 +05:30
|
|
|
new_formula = args.new_formula?
|
|
|
|
strict = new_formula || args.strict?
|
|
|
|
online = new_formula || args.online?
|
2020-06-08 15:00:09 +01:00
|
|
|
git = args.git?
|
2020-08-06 09:43:02 +01:00
|
|
|
skip_style = args.skip_style? || args.no_named? || args.tap
|
2015-07-09 12:31:17 +01:00
|
|
|
|
2020-07-28 02:04:50 +02:00
|
|
|
ENV.activate_extensions!
|
|
|
|
ENV.setup_build_environment
|
2013-05-07 18:39:45 -05:00
|
|
|
|
2020-08-06 09:43:02 +01:00
|
|
|
audit_formulae = if args.tap
|
|
|
|
Tap.fetch(args.tap).formula_names.map { |name| Formula[name] }
|
|
|
|
elsif args.no_named?
|
|
|
|
Formula
|
|
|
|
else
|
2020-08-19 10:34:48 -04:00
|
|
|
args.named.to_resolved_formulae
|
2020-08-06 09:43:02 +01:00
|
|
|
end
|
2020-08-19 10:34:48 -04:00
|
|
|
style_files = args.named.to_formulae_paths unless skip_style
|
2016-08-16 17:00:31 +01:00
|
|
|
|
2018-02-04 22:09:35 +05:30
|
|
|
only_cops = args.only_cops
|
|
|
|
except_cops = args.except_cops
|
2020-08-02 03:36:09 +02:00
|
|
|
options = { fix: args.fix?, debug: args.debug?, verbose: args.verbose? }
|
2017-05-03 11:33:00 +05:30
|
|
|
|
2018-02-04 22:09:35 +05:30
|
|
|
if only_cops
|
2017-05-03 11:33:00 +05:30
|
|
|
options[:only_cops] = only_cops
|
2018-02-04 22:09:35 +05:30
|
|
|
elsif args.new_formula?
|
2017-07-28 05:01:01 +05:30
|
|
|
nil
|
2018-02-04 22:09:35 +05:30
|
|
|
elsif except_cops
|
2017-05-03 11:33:00 +05:30
|
|
|
options[:except_cops] = except_cops
|
|
|
|
elsif !strict
|
2020-04-16 08:24:38 +01:00
|
|
|
options[:except_cops] = [:FormulaAuditStrict]
|
2012-08-07 01:37:46 -05:00
|
|
|
end
|
2014-12-27 12:38:04 +00:00
|
|
|
|
2020-11-05 01:25:13 -05:00
|
|
|
# Run tap audits first
|
2020-11-06 10:12:09 -05:00
|
|
|
tap_problem_count = 0
|
|
|
|
tap_count = 0
|
|
|
|
Tap.each do |tap|
|
|
|
|
next if args.tap && tap != args.tap
|
|
|
|
|
|
|
|
ta = TapAuditor.new tap, strict: args.strict?
|
2020-11-05 01:25:13 -05:00
|
|
|
ta.audit
|
|
|
|
|
2020-11-06 11:23:11 -05:00
|
|
|
next if ta.problems.blank?
|
2020-11-05 01:25:13 -05:00
|
|
|
|
2020-11-06 10:12:09 -05:00
|
|
|
tap_count += 1
|
|
|
|
tap_problem_count += ta.problems.size
|
|
|
|
tap_problem_lines = format_problem_lines(ta.problems)
|
|
|
|
|
|
|
|
puts "#{tap.name}:", tap_problem_lines.map { |s| " #{s}" }
|
2020-11-05 01:25:13 -05:00
|
|
|
end
|
|
|
|
|
2017-04-23 04:09:13 +05:30
|
|
|
# Check style in a single batch run up front for performance
|
2020-09-01 20:07:21 +02:00
|
|
|
style_offenses = Style.check_style_json(style_files, options) if style_files
|
2020-06-16 00:19:32 +08:00
|
|
|
# load licenses
|
2020-08-18 11:00:17 -04:00
|
|
|
spdx_license_data = SPDX.license_data
|
|
|
|
spdx_exception_data = SPDX.exception_data
|
2018-04-30 01:22:04 +05:30
|
|
|
new_formula_problem_lines = []
|
2020-04-16 08:24:38 +01:00
|
|
|
audit_formulae.sort.each do |f|
|
2018-10-30 23:44:14 +05:30
|
|
|
only = only_cops ? ["style"] : args.only
|
2020-06-08 15:00:09 +01:00
|
|
|
options = {
|
2020-11-04 23:42:42 -05:00
|
|
|
new_formula: new_formula,
|
|
|
|
strict: strict,
|
|
|
|
online: online,
|
|
|
|
git: git,
|
|
|
|
only: only,
|
|
|
|
except: args.except,
|
|
|
|
spdx_license_data: spdx_license_data,
|
|
|
|
spdx_exception_data: spdx_exception_data,
|
|
|
|
tap_audit_exceptions: f.tap.audit_exceptions,
|
2020-06-08 15:00:09 +01:00
|
|
|
}
|
2020-09-01 20:07:21 +02:00
|
|
|
options[:style_offenses] = style_offenses.for_path(f.path) if style_offenses
|
2019-09-02 10:48:19 +01:00
|
|
|
options[:display_cop_names] = args.display_cop_names?
|
2020-07-26 09:44:10 +02:00
|
|
|
options[:build_stable] = args.build_stable?
|
2019-09-02 10:48:19 +01:00
|
|
|
|
2016-04-18 17:39:21 -04:00
|
|
|
fa = FormulaAuditor.new(f, options)
|
2012-08-07 01:37:46 -05:00
|
|
|
fa.audit
|
2018-05-22 17:02:20 +05:30
|
|
|
next if fa.problems.empty? && fa.new_formula_problems.empty?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-04-18 17:39:21 -04:00
|
|
|
formula_count += 1
|
|
|
|
problem_count += fa.problems.size
|
2018-04-30 01:22:04 +05:30
|
|
|
problem_lines = format_problem_lines(fa.problems)
|
2020-06-08 15:00:09 +01:00
|
|
|
corrected_problem_count = options[:style_offenses].count(&:corrected?) if options[:style_offenses]
|
2018-04-30 01:22:04 +05:30
|
|
|
new_formula_problem_lines = format_problem_lines(fa.new_formula_problems)
|
2018-02-04 22:09:35 +05:30
|
|
|
if args.display_filename?
|
2016-05-16 18:46:47 +01:00
|
|
|
puts problem_lines.map { |s| "#{f.path}: #{s}" }
|
2016-05-11 09:19:45 -07:00
|
|
|
else
|
2016-05-16 18:46:47 +01:00
|
|
|
puts "#{f.full_name}:", problem_lines.map { |s| " #{s}" }
|
2016-05-11 09:19:45 -07:00
|
|
|
end
|
2020-09-10 22:00:18 +02:00
|
|
|
|
|
|
|
next unless ENV["GITHUB_ACTIONS"]
|
|
|
|
|
|
|
|
(fa.problems + fa.new_formula_problems).each do |message:, location:|
|
|
|
|
annotation = GitHub::Actions::Annotation.new(
|
|
|
|
:error, message, file: f.path, line: location&.line, column: location&.column
|
|
|
|
)
|
|
|
|
puts annotation if annotation.relevant?
|
|
|
|
end
|
2012-08-07 01:37:46 -05:00
|
|
|
end
|
|
|
|
|
2020-05-18 13:50:43 +01:00
|
|
|
new_formula_problem_count += new_formula_problem_lines.size
|
|
|
|
puts new_formula_problem_lines.map { |s| " #{s}" }
|
2018-04-30 01:22:04 +05:30
|
|
|
|
2020-11-06 10:12:09 -05:00
|
|
|
total_problems_count = problem_count + new_formula_problem_count + tap_problem_count
|
|
|
|
return unless total_problems_count.positive?
|
|
|
|
|
2018-09-17 20:11:11 +02:00
|
|
|
problem_plural = "#{total_problems_count} #{"problem".pluralize(total_problems_count)}"
|
|
|
|
formula_plural = "#{formula_count} #{"formula".pluralize(formula_count)}"
|
2020-11-06 10:12:09 -05:00
|
|
|
tap_plural = "#{tap_count} #{"tap".pluralize(tap_count)}"
|
2018-09-17 20:11:11 +02:00
|
|
|
corrected_problem_plural = "#{corrected_problem_count} #{"problem".pluralize(corrected_problem_count)}"
|
2020-11-06 10:12:09 -05:00
|
|
|
errors_summary = if tap_count.zero?
|
|
|
|
"#{problem_plural} in #{formula_plural} detected"
|
|
|
|
elsif formula_count.zero?
|
|
|
|
"#{problem_plural} in #{tap_plural} detected"
|
|
|
|
else
|
|
|
|
"#{problem_plural} in #{formula_plural} and #{tap_plural} detected"
|
|
|
|
end
|
2019-02-19 13:11:32 +00:00
|
|
|
errors_summary += ", #{corrected_problem_plural} corrected" if corrected_problem_count.positive?
|
2018-05-22 18:16:46 +05:30
|
|
|
|
2020-11-06 10:12:09 -05:00
|
|
|
ofail errors_summary
|
2018-04-30 01:22:04 +05:30
|
|
|
end
|
2016-09-22 20:12:28 +02:00
|
|
|
|
2018-04-30 01:22:04 +05:30
|
|
|
def format_problem_lines(problems)
|
2020-09-10 22:00:18 +02:00
|
|
|
problems.uniq
|
|
|
|
.map { |message:, location:| format_problem(message, location) }
|
|
|
|
end
|
|
|
|
|
|
|
|
def format_problem(message, location)
|
|
|
|
"* #{location&.to_s&.dup&.concat(": ")}#{message.chomp.gsub("\n", "\n ")}"
|
2012-08-07 01:37:46 -05:00
|
|
|
end
|
2013-09-18 18:08:50 -05:00
|
|
|
end
|