diff --git a/Library/Homebrew/rubocops.rb b/Library/Homebrew/rubocops.rb index 50f01a9cf8..a88d0c4c72 100644 --- a/Library/Homebrew/rubocops.rb +++ b/Library/Homebrew/rubocops.rb @@ -22,6 +22,6 @@ require "rubocops/uses_from_macos" require "rubocops/files" require "rubocops/keg_only" require "rubocops/version" -require "rubocops/deprecate" +require "rubocops/deprecate_disable" require "rubocops/rubocop-cask" diff --git a/Library/Homebrew/rubocops/deprecate.rb b/Library/Homebrew/rubocops/deprecate.rb deleted file mode 100644 index f572e37769..0000000000 --- a/Library/Homebrew/rubocops/deprecate.rb +++ /dev/null @@ -1,74 +0,0 @@ -# frozen_string_literal: true - -require "rubocops/extend/formula" - -module RuboCop - module Cop - module FormulaAudit - # This cop audits deprecate! date - class DeprecateDate < FormulaCop - def audit_formula(_node, _class_node, _parent_class_node, body_node) - deprecate_node = find_node_method_by_name(body_node, :deprecate!) - - return if deprecate_node.nil? - - deprecate_date(deprecate_node) do |date_node| - Date.iso8601(string_content(date_node)) - rescue ArgumentError - fixed_date_string = Date.parse(string_content(date_node)).iso8601 - offending_node(date_node) - problem "Use `#{fixed_date_string}` to comply with ISO 8601" - end - end - - def autocorrect(node) - lambda do |corrector| - fixed_fixed_date_string = Date.parse(string_content(node)).iso8601 - corrector.replace(node.source_range, "\"#{fixed_fixed_date_string}\"") - end - end - - def_node_search :deprecate_date, <<~EOS - (pair (sym :date) $str) - EOS - end - - # This cop audits deprecate! reason - class DeprecateReason < FormulaCop - def audit_formula(_node, _class_node, _parent_class_node, body_node) - deprecate_node = find_node_method_by_name(body_node, :deprecate!) - - return if deprecate_node.nil? - - deprecate_reason(deprecate_node) do |reason_node| - offending_node(reason_node) - reason_string = string_content(reason_node) - - problem "Do not start the reason with `it`" if reason_string.start_with?("it ") - - problem "Do not end the reason with a punctuation mark" if %w[. ! ?].include?(reason_string[-1]) - - return - end - - problem 'Add a reason for deprecation: `deprecate! because: "..."`' - end - - def autocorrect(node) - return unless node.str_type? - - lambda do |corrector| - reason = string_content(node) - reason = reason[3..] if reason.start_with?("it ") - reason.chop! if %w[. ! ?].include?(reason[-1]) - corrector.replace(node.source_range, "\"#{reason}\"") - end - end - - def_node_search :deprecate_reason, <<~EOS - (pair (sym :because) $str) - EOS - end - end - end -end diff --git a/Library/Homebrew/rubocops/deprecate_disable.rb b/Library/Homebrew/rubocops/deprecate_disable.rb new file mode 100644 index 0000000000..df9688fad4 --- /dev/null +++ b/Library/Homebrew/rubocops/deprecate_disable.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +require "rubocops/extend/formula" + +module RuboCop + module Cop + module FormulaAudit + # This cop audits deprecate! date and disable! date + class DeprecateDisableDate < FormulaCop + def audit_formula(_node, _class_node, _parent_class_node, body_node) + [:deprecate!, :disable!].each do |method| + node = find_node_method_by_name(body_node, method) + + next if node.nil? + + date(node) do |date_node| + Date.iso8601(string_content(date_node)) + rescue ArgumentError + fixed_date_string = Date.parse(string_content(date_node)).iso8601 + offending_node(date_node) + problem "Use `#{fixed_date_string}` to comply with ISO 8601" + end + end + end + + def autocorrect(node) + lambda do |corrector| + fixed_fixed_date_string = Date.parse(string_content(node)).iso8601 + corrector.replace(node.source_range, "\"#{fixed_fixed_date_string}\"") + end + end + + def_node_search :date, <<~EOS + (pair (sym :date) $str) + EOS + end + + # This cop audits deprecate! reason + class DeprecateDisableReason < FormulaCop + def audit_formula(_node, _class_node, _parent_class_node, body_node) + [:deprecate!, :disable!].each do |method| + node = find_node_method_by_name(body_node, method) + + next if node.nil? + + reason_found = false + reason(node) do |reason_node| + reason_found = true + offending_node(reason_node) + reason_string = string_content(reason_node) + + problem "Do not start the reason with `it`" if reason_string.start_with?("it ") + + problem "Do not end the reason with a punctuation mark" if %w[. ! ?].include?(reason_string[-1]) + end + + next if reason_found + + case method + when :deprecate! + problem 'Add a reason for deprecation: `deprecate! because: "..."`' + when :disable! + problem 'Add a reason for disabling: `disable! because: "..."`' + end + end + end + + def autocorrect(node) + return unless node.str_type? + + lambda do |corrector| + reason = string_content(node) + reason = reason[3..] if reason.start_with?("it ") + reason.chop! if %w[. ! ?].include?(reason[-1]) + corrector.replace(node.source_range, "\"#{reason}\"") + end + end + + def_node_search :reason, <<~EOS + (pair (sym :because) $str) + EOS + end + end + end +end diff --git a/Library/Homebrew/sorbet/files.yaml b/Library/Homebrew/sorbet/files.yaml index a506566510..5bda58faa0 100644 --- a/Library/Homebrew/sorbet/files.yaml +++ b/Library/Homebrew/sorbet/files.yaml @@ -635,7 +635,7 @@ false: - ./test/rubocops/components_redundancy_spec.rb - ./test/rubocops/conflicts_spec.rb - ./test/rubocops/dependency_order_spec.rb - - ./test/rubocops/deprecate_spec.rb + - ./test/rubocops/deprecate_disable_spec.rb - ./test/rubocops/formula_desc_spec.rb - ./test/rubocops/homepage_spec.rb - ./test/rubocops/lines_spec.rb @@ -895,7 +895,7 @@ true: - ./rubocops/cask/constants/stanza.rb - ./rubocops/cask/desc.rb - ./rubocops/cask/extend/string.rb - - ./rubocops/deprecate.rb + - ./rubocops/deprecate_disable.rb - ./tap_constants.rb - ./test/support/helper/fixtures.rb - ./test/support/lib/config.rb diff --git a/Library/Homebrew/test/.rubocop_todo.yml b/Library/Homebrew/test/.rubocop_todo.yml index 5c35fce9cf..0fbc7c6b0a 100644 --- a/Library/Homebrew/test/.rubocop_todo.yml +++ b/Library/Homebrew/test/.rubocop_todo.yml @@ -93,7 +93,7 @@ RSpec/MultipleDescribes: - 'patch_spec.rb' - 'rubocops/checksum_spec.rb' - 'rubocops/class_spec.rb' - - 'rubocops/deprecate_spec.rb' + - 'rubocops/deprecate_disable_spec.rb' - 'rubocops/formula_desc_spec.rb' - 'rubocops/lines_spec.rb' - 'rubocops/text_spec.rb' diff --git a/Library/Homebrew/test/rubocops/deprecate_spec.rb b/Library/Homebrew/test/rubocops/deprecate_disable_spec.rb similarity index 50% rename from Library/Homebrew/test/rubocops/deprecate_spec.rb rename to Library/Homebrew/test/rubocops/deprecate_disable_spec.rb index e1ecde5f24..00e2e55836 100644 --- a/Library/Homebrew/test/rubocops/deprecate_spec.rb +++ b/Library/Homebrew/test/rubocops/deprecate_disable_spec.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require "rubocops/deprecate" +require "rubocops/deprecate_disable" -describe RuboCop::Cop::FormulaAudit::DeprecateDate do +describe RuboCop::Cop::FormulaAudit::DeprecateDisableDate do subject(:cop) { described_class.new } context "When auditing formula for deprecate! date:" do @@ -100,9 +100,105 @@ describe RuboCop::Cop::FormulaAudit::DeprecateDate do expect(new_source).to eq(corrected_source) end end + + context "When auditing formula for disable! date:" do + it "disable date is not ISO 8601 compliant" do + expect_offense(<<~RUBY) + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! date: "June 25, 2020" + ^^^^^^^^^^^^^^^ Use `2020-06-25` to comply with ISO 8601 + end + RUBY + end + + it "disable date is not ISO 8601 compliant with reason" do + expect_offense(<<~RUBY) + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! because: "is broken", date: "June 25, 2020" + ^^^^^^^^^^^^^^^ Use `2020-06-25` to comply with ISO 8601 + end + RUBY + end + + it "disable date is ISO 8601 compliant" do + expect_no_offenses(<<~RUBY) + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! date: "2020-06-25" + end + RUBY + end + + it "disable date is ISO 8601 compliant with reason" do + expect_no_offenses(<<~RUBY) + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! because: "is broken", date: "2020-06-25" + end + RUBY + end + + it "no disable date" do + expect_no_offenses(<<~RUBY) + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! + end + RUBY + end + + it "no disable date with reason" do + expect_no_offenses(<<~RUBY) + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! because: "is broken" + end + RUBY + end + + it "auto corrects to ISO 8601 format" do + source = <<~RUBY + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! date: "June 25, 2020" + end + RUBY + + corrected_source = <<~RUBY + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! date: "2020-06-25" + end + RUBY + + new_source = autocorrect_source(source) + expect(new_source).to eq(corrected_source) + end + + it "auto corrects to ISO 8601 format with reason" do + source = <<~RUBY + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! because: "is broken", date: "June 25, 2020" + end + RUBY + + corrected_source = <<~RUBY + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! because: "is broken", date: "2020-06-25" + end + RUBY + + new_source = autocorrect_source(source) + expect(new_source).to eq(corrected_source) + end + end end -describe RuboCop::Cop::FormulaAudit::DeprecateReason do +describe RuboCop::Cop::FormulaAudit::DeprecateDisableReason do subject(:cop) { described_class.new } context "When auditing formula for deprecate! because:" do @@ -242,4 +338,142 @@ describe RuboCop::Cop::FormulaAudit::DeprecateReason do expect(new_source).to eq(corrected_source) end end + + context "When auditing formula for disable! because:" do + it "disable reason is acceptable" do + expect_no_offenses(<<~RUBY) + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! because: "is broken" + end + RUBY + end + + it "disable reason is acceptable with date" do + expect_no_offenses(<<~RUBY) + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! date: "2020-08-28", because: "is broken" + end + RUBY + end + + it "disable reason is absent" do + expect_offense(<<~RUBY) + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! + ^^^^^^^^ Add a reason for disabling: `disable! because: "..."` + end + RUBY + end + + it "disable reason is absent with date" do + expect_offense(<<~RUBY) + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! date: "2020-08-28" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Add a reason for disabling: `disable! because: "..."` + end + RUBY + end + + it "disable reason starts with `it`" do + expect_offense(<<~RUBY) + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! because: "it is broken" + ^^^^^^^^^^^^^^ Do not start the reason with `it` + end + RUBY + end + + it "disable reason starts with `it` with date" do + expect_offense(<<~RUBY) + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! date: "2020-08-28", because: "it is broken" + ^^^^^^^^^^^^^^ Do not start the reason with `it` + end + RUBY + end + + it "disable reason ends with a period" do + expect_offense(<<~RUBY) + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! because: "is broken." + ^^^^^^^^^^^^ Do not end the reason with a punctuation mark + end + RUBY + end + + it "disable reason ends with an exclamation point" do + expect_offense(<<~RUBY) + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! because: "is broken!" + ^^^^^^^^^^^^ Do not end the reason with a punctuation mark + end + RUBY + end + + it "disable reason ends with a question mark" do + expect_offense(<<~RUBY) + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! because: "is broken?" + ^^^^^^^^^^^^ Do not end the reason with a punctuation mark + end + RUBY + end + + it "disable reason ends with a period with date" do + expect_offense(<<~RUBY) + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! date: "2020-08-28", because: "is broken." + ^^^^^^^^^^^^ Do not end the reason with a punctuation mark + end + RUBY + end + + it "auto corrects to remove `it`" do + source = <<~RUBY + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! because: "it is broken" + end + RUBY + + corrected_source = <<~RUBY + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! because: "is broken" + end + RUBY + + new_source = autocorrect_source(source) + expect(new_source).to eq(corrected_source) + end + + it "auto corrects to remove punctuation" do + source = <<~RUBY + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! because: "is broken." + end + RUBY + + corrected_source = <<~RUBY + class Foo < Formula + url 'https://brew.sh/foo-1.0.tgz' + disable! because: "is broken" + end + RUBY + + new_source = autocorrect_source(source) + expect(new_source).to eq(corrected_source) + end + end end