diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb index 08cb33977a..87faf0b725 100644 --- a/Library/Homebrew/dev-cmd/audit.rb +++ b/Library/Homebrew/dev-cmd/audit.rb @@ -435,40 +435,6 @@ module Homebrew end end - def audit_keg_only - return unless formula.keg_only? - - whitelist = %w[ - Apple - macOS - OS - Homebrew - Xcode - GPG - GNOME - BSD - Firefox - ].freeze - - reason = formula.keg_only_reason.to_s - # Formulae names can legitimately be uppercase/lowercase/both. - name = Regexp.new(formula.name, Regexp::IGNORECASE) - reason.sub!(name, "") - first_word = reason.split.first - - if reason =~ /\A[A-Z]/ && !reason.start_with?(*whitelist) - # TODO: check could be in RuboCop - problem <<~EOS - '#{first_word}' from the keg_only reason should be '#{first_word.downcase}'. - EOS - end - - return unless reason.end_with?(".") - - # TODO: check could be in RuboCop - problem "keg_only reason should not end with a period." - end - def audit_postgresql return unless formula.name == "postgresql" return unless @core_tap diff --git a/Library/Homebrew/rubocops.rb b/Library/Homebrew/rubocops.rb index 6252f64b58..6b43b6f937 100644 --- a/Library/Homebrew/rubocops.rb +++ b/Library/Homebrew/rubocops.rb @@ -20,5 +20,6 @@ require "rubocops/lines" require "rubocops/class" require "rubocops/uses_from_macos" require "rubocops/files" +require "rubocops/keg_only" require "rubocops/rubocop-cask" diff --git a/Library/Homebrew/rubocops/keg_only.rb b/Library/Homebrew/rubocops/keg_only.rb new file mode 100644 index 0000000000..e2969f2df1 --- /dev/null +++ b/Library/Homebrew/rubocops/keg_only.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require "rubocops/extend/formula" + +module RuboCop + module Cop + module FormulaAudit + class KegOnly < FormulaCop + def audit_formula(_node, _class_node, _parent_class_node, body_node) + keg_only_node = find_node_method_by_name(body_node, :keg_only) + return unless keg_only_node + + whitelist = %w[ + Apple + macOS + OS + Homebrew + Xcode + GPG + GNOME + BSD + Firefox + ].freeze + + reason = string_content(parameters(keg_only_node).first) + name = Regexp.new(@formula_name, Regexp::IGNORECASE) + reason = reason.sub(name, "") + first_word = reason.split.first + + if reason =~ /\A[A-Z]/ && !reason.start_with?(*whitelist) + problem "'#{first_word}' from the keg_only reason should be '#{first_word.downcase}'." + end + + return unless reason.end_with?(".") + + problem "keg_only reason should not end with a period." + end + end + end + end +end diff --git a/Library/Homebrew/test/.rubocop_todo.yml b/Library/Homebrew/test/.rubocop_todo.yml index d3da7961bc..a5a6d80cc5 100644 --- a/Library/Homebrew/test/.rubocop_todo.yml +++ b/Library/Homebrew/test/.rubocop_todo.yml @@ -46,6 +46,7 @@ RSpec/FilePath: - 'rubocops/conflicts_spec.rb' - 'rubocops/dependency_order_spec.rb' - 'rubocops/files_spec.rb' + - 'rubocops/keg_only_spec.rb' - 'rubocops/homepage_spec.rb' - 'rubocops/options_spec.rb' - 'rubocops/patches_spec.rb' diff --git a/Library/Homebrew/test/dev-cmd/audit_spec.rb b/Library/Homebrew/test/dev-cmd/audit_spec.rb index 895d339aef..132d70bf40 100644 --- a/Library/Homebrew/test/dev-cmd/audit_spec.rb +++ b/Library/Homebrew/test/dev-cmd/audit_spec.rb @@ -300,69 +300,6 @@ module Homebrew end end - describe "#audit_keg_only" do - specify "keg_only_needs_downcasing" do - fa = formula_auditor "foo", <<~RUBY, strict: true - class Foo < Formula - url "https://brew.sh/foo-1.0.tgz" - - keg_only "Because why not" - end - RUBY - - fa.audit_keg_only - expect(fa.problems) - .to eq(["'Because' from the keg_only reason should be 'because'.\n"]) - end - - specify "keg_only_redundant_period" do - fa = formula_auditor "foo", <<~RUBY, strict: true - class Foo < Formula - url "https://brew.sh/foo-1.0.tgz" - - keg_only "because this line ends in a period." - end - RUBY - - fa.audit_keg_only - expect(fa.problems) - .to eq(["keg_only reason should not end with a period."]) - end - - specify "keg_only_handles_block_correctly" do - fa = formula_auditor "foo", <<~RUBY, strict: true - class Foo < Formula - url "https://brew.sh/foo-1.0.tgz" - - keg_only <<~EOF - this line starts with a lowercase word. - - This line does not but that shouldn't be a - problem - EOF - end - RUBY - - fa.audit_keg_only - expect(fa.problems) - .to eq([]) - end - - specify "keg_only_handles_whitelist_correctly" do - fa = formula_auditor "foo", <<~RUBY, strict: true - class Foo < Formula - url "https://brew.sh/foo-1.0.tgz" - - keg_only "Apple ships foo in the CLT package" - end - RUBY - - fa.audit_keg_only - expect(fa.problems) - .to eq([]) - end - end - describe "#audit_revision_and_version_scheme" do subject { fa = described_class.new(Formulary.factory(formula_path)) diff --git a/Library/Homebrew/test/rubocops/keg_only_spec.rb b/Library/Homebrew/test/rubocops/keg_only_spec.rb new file mode 100644 index 0000000000..81112da206 --- /dev/null +++ b/Library/Homebrew/test/rubocops/keg_only_spec.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +require "rubocops/keg_only" + +describe RuboCop::Cop::FormulaAudit::KegOnly do + subject(:cop) { described_class.new } + + specify "keg_only_needs_downcasing" do + expect_offense(<<~RUBY) + class Foo < Formula + + url "https://brew.sh/foo-1.0.tgz" + homepage "https://brew.sh" + + keg_only "Because why not" + ^^^^^^^^^^^^^^^^^^^^^^^^^^ 'Because' from the keg_only reason should be 'because'. + end + RUBY + end + + specify "keg_only_redundant_period" do + expect_offense(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + homepage "https://brew.sh" + + keg_only "ending with a period." + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ keg_only reason should not end with a period. + end + RUBY + end + + specify "keg_only_handles_block_correctly" do + expect_no_offenses(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + homepage "https://brew.sh" + + keg_only <<~EOF + this line starts with a lowercase word. + + This line does not but that shouldn't be a + problem + EOF + end + RUBY + end + + specify "keg_only_handles_whitelist_correctly" do + expect_no_offenses(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + homepage "https://brew.sh" + + keg_only "Apple ships foo in the CLT package" + end + RUBY + end + + specify "keg_only does not need downcasing of formula name in reason" do + filename = Formulary.core_path("foo") + File.open(filename, "w") do |file| + FileUtils.chmod "-rwx", filename + + expect_no_offenses(<<~RUBY, file) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + + keg_only "Foo is the formula name hence downcasing is not required" + end + RUBY + end + end +end