diff --git a/Library/Homebrew/rubocops/conflicts.rb b/Library/Homebrew/rubocops/conflicts.rb index 08c1f37ffa..318a79d47b 100644 --- a/Library/Homebrew/rubocops/conflicts.rb +++ b/Library/Homebrew/rubocops/conflicts.rb @@ -15,11 +15,40 @@ module RuboCop bash-completion@2 ].freeze - def audit_formula(_node, _class_node, _parent_class_node, body) + def audit_formula(_node, _class_node, _parent_class_node, body_node) + find_method_calls_by_name(body_node, :conflicts_with).each do |conflicts_with_call| + next unless parameters(conflicts_with_call).last.respond_to? :values + + reason = parameters(conflicts_with_call).last.values.first + offending_node(reason) + name = Regexp.new(@formula_name, Regexp::IGNORECASE) + reason = string_content(reason).sub(name, "") + first_word = reason.split.first + + if reason.match?(/\A[A-Z]/) + problem "'#{first_word}' from the `conflicts_with` reason should be '#{first_word.downcase}'." + end + + problem "`conflicts_with` reason should not end with a period." if reason.end_with?(".") + end + return unless versioned_formula? problem MSG if !ALLOWLIST.include?(@formula_name) && - method_called_ever?(body, :conflicts_with) + method_called_ever?(body_node, :conflicts_with) + end + + def autocorrect(node) + lambda do |corrector| + if versioned_formula? + corrector.replace(node.source_range, "keg_only :versioned_formula") + else + reason = string_content(node) + reason[0] = reason[0].downcase + reason = reason.delete_suffix(".") + corrector.replace(node.source_range, "\"#{reason}\"") + end + end end end end diff --git a/Library/Homebrew/test/rubocops/conflicts_spec.rb b/Library/Homebrew/test/rubocops/conflicts_spec.rb index 58524603f8..6a1a839ce5 100644 --- a/Library/Homebrew/test/rubocops/conflicts_spec.rb +++ b/Library/Homebrew/test/rubocops/conflicts_spec.rb @@ -5,14 +5,34 @@ require "rubocops/conflicts" describe RuboCop::Cop::FormulaAudit::Conflicts do subject(:cop) { described_class.new } - context "When auditing formula for conflicts with" do - it "multiple conflicts_with" do + context "When auditing conflicts_with" do + it "conflicts_with reason is capitalized" do + expect_offense(<<~RUBY, "/homebrew-core/Formula/foo.rb") + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + conflicts_with "bar", :because => "Reason" + ^^^^^^^^ 'Reason' from the `conflicts_with` reason should be 'reason'. + conflicts_with "baz", :because => "Foo is the formula name which does not require downcasing" + end + RUBY + end + + it "conflicts_with reason ends with a period" do + expect_offense(<<~RUBY) + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + conflicts_with "bar", "baz", :because => "reason." + ^^^^^^^^^ `conflicts_with` reason should not end with a period. + end + RUBY + end + + it "conflicts_with in a versioned formula" do expect_offense(<<~RUBY, "/homebrew-core/Formula/foo@2.0.rb") class FooAT20 < Formula url 'https://brew.sh/foo-2.0.tgz' - conflicts_with "mysql", "mariadb", "percona-server", - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Versioned formulae should not use `conflicts_with`. Use `keg_only :versioned_formula` instead. - :because => "both install plugins" + conflicts_with "mysql", "mariadb" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Versioned formulae should not use `conflicts_with`. Use `keg_only :versioned_formula` instead. end RUBY end @@ -21,10 +41,48 @@ describe RuboCop::Cop::FormulaAudit::Conflicts do expect_no_offenses(<<~RUBY, "/homebrew-core/Formula/foo@2.0.rb") class FooAT20 < Formula url 'https://brew.sh/foo-2.0.tgz' - desc 'Bar' + homepage "https://brew.sh" end RUBY end + + it "auto-corrects capitalized reason" do + source = <<~RUBY + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + conflicts_with "bar", :because => "Reason" + end + RUBY + + corrected_source = <<~RUBY + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + conflicts_with "bar", :because => "reason" + end + RUBY + + new_source = autocorrect_source(source) + expect(new_source).to eq(corrected_source) + end + + it "auto-corrects trailing period" do + source = <<~RUBY + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + conflicts_with "bar", :because => "reason." + end + RUBY + + corrected_source = <<~RUBY + class Foo < Formula + url "https://brew.sh/foo-1.0.tgz" + conflicts_with "bar", :because => "reason" + end + RUBY + + new_source = autocorrect_source(source) + expect(new_source).to eq(corrected_source) + end end include_examples "formulae exist", described_class::ALLOWLIST