diff --git a/Library/Homebrew/cask/audit.rb b/Library/Homebrew/cask/audit.rb index 1d6fa742e4df8..217b7250a4eb3 100644 --- a/Library/Homebrew/cask/audit.rb +++ b/Library/Homebrew/cask/audit.rb @@ -9,6 +9,7 @@ require "source_location" require "system_command" require "utils/backtrace" +require "formula_name_cask_token_auditor" require "utils/curl" require "utils/git" require "utils/shared_audits" @@ -392,6 +393,15 @@ def audit_languages end end + sig { void } + def audit_token + token_auditor = Homebrew::FormulaNameCaskTokenAuditor.new(cask.token) + return if (errors = token_auditor.errors).none? + + add_error "Cask token '#{cask.token}' must not contain #{errors.to_sentence(two_words_connector: " or ", + last_word_connector: " or ")}." + end + sig { void } def audit_token_conflicts return unless token_conflicts? @@ -406,27 +416,6 @@ def audit_token_conflicts end end - sig { void } - def audit_token_valid - add_error "cask token contains non-ascii characters" unless cask.token.ascii_only? - add_error "cask token + should be replaced by -plus-" if cask.token.include? "+" - add_error "cask token whitespace should be replaced by hyphens" if cask.token.include? " " - add_error "cask token underscores should be replaced by hyphens" if cask.token.include? "_" - add_error "cask token should not contain double hyphens" if cask.token.include? "--" - - if cask.token.match?(/[^@a-z0-9-]/) - add_error "cask token should only contain lowercase alphanumeric characters, hyphens and @" - end - - if cask.token.start_with?("-", "@") || cask.token.end_with?("-", "@") - add_error "cask token should not have leading or trailing hyphens and/or @" - end - - add_error "cask token @ unrelated to versioning should be replaced by -at-" if cask.token.count("@") > 1 - add_error "cask token should not contain a hyphen followed by @" if cask.token.include? "-@" - add_error "cask token should not contain @ followed by a hyphen" if cask.token.include? "@-" - end - sig { void } def audit_token_bad_words return unless new_cask? diff --git a/Library/Homebrew/formula_auditor.rb b/Library/Homebrew/formula_auditor.rb index f0c63a2e51426..1c0319a6307da 100644 --- a/Library/Homebrew/formula_auditor.rb +++ b/Library/Homebrew/formula_auditor.rb @@ -3,6 +3,7 @@ require "deprecate_disable" require "formula_versions" +require "formula_name_cask_token_auditor" require "resource_auditor" require "utils/shared_audits" @@ -160,10 +161,14 @@ def audit_synced_versions_formulae end end - def audit_formula_name + def audit_name name = formula.name - problem "Formula name '#{name}' must not contain uppercase letters." if name != name.downcase + name_auditor = Homebrew::FormulaNameCaskTokenAuditor.new(name) + if (errors = name_auditor.errors).any? + problem "Formula name '#{name}' must not contain #{errors.to_sentence(two_words_connector: " or ", + last_word_connector: " or ")}." + end return unless @strict return unless @core_tap diff --git a/Library/Homebrew/formula_name_cask_token_auditor.rb b/Library/Homebrew/formula_name_cask_token_auditor.rb new file mode 100644 index 0000000000000..2789db89f6a7d --- /dev/null +++ b/Library/Homebrew/formula_name_cask_token_auditor.rb @@ -0,0 +1,36 @@ +# typed: true +# frozen_string_literal: true + +module Homebrew + class FormulaNameCaskTokenAuditor + sig { returns(String) } + attr_reader :token + + sig { params(token: String).void } + def initialize(token) + @token = token + end + + sig { returns(T::Array[String]) } + def errors + errors = [] + + errors << "uppercase letters" if token.match?(/[A-Z]/) + errors << "whitespace" if token.match?(/\s/) + errors << "non-ASCII characters" unless token.ascii_only? + errors << "double hyphens" if token.include?("--") + + errors << "a leading @" if token.start_with?("@") + errors << "a trailing @" if token.end_with?("@") + errors << "a leading hyphen" if token.start_with?("-") + errors << "a trailing hyphen" if token.end_with?("-") + + errors << "multiple @ symbols" if token.count("@") > 1 + + errors << "a hyphen followed by an @" if token.include? "-@" + errors << "an @ followed by a hyphen" if token.include? "@-" + + errors + end + end +end diff --git a/Library/Homebrew/test/cask/audit_spec.rb b/Library/Homebrew/test/cask/audit_spec.rb index 6da7326f7fdf9..c38f0b481e321 100644 --- a/Library/Homebrew/test/cask/audit_spec.rb +++ b/Library/Homebrew/test/cask/audit_spec.rb @@ -182,7 +182,7 @@ def tmp_cask(name, text) describe "token validation" do let(:strict) { true } - let(:only) { ["token_valid"] } + let(:only) { ["token"] } let(:cask) do tmp_cask cask_token.to_s, <<~RUBY cask '#{cask_token}' do @@ -200,7 +200,7 @@ def tmp_cask(name, text) let(:cask_token) { "Upper-Case" } it "fails" do - expect(run).to error_with(/lowercase/) + expect(run).to error_with(/not contain uppercase/) end end @@ -208,15 +208,7 @@ def tmp_cask(name, text) let(:cask_token) { "asciiāŒ˜" } it "fails" do - expect(run).to error_with(/contains non-ascii characters/) - end - end - - context "when cask token has +" do - let(:cask_token) { "app++" } - - it "fails" do - expect(run).to error_with(/\+ should be replaced by -plus-/) + expect(run).to error_with(/not contain non-ASCII characters/) end end @@ -240,7 +232,7 @@ def tmp_cask(name, text) let(:cask_token) { "app@stuff@beta" } it "fails" do - expect(run).to error_with(/@ unrelated to versioning should be replaced by -at-/) + expect(run).to error_with(/not contain multiple @ symbols/) end end @@ -248,7 +240,7 @@ def tmp_cask(name, text) let(:cask_token) { "app-@beta" } it "fails" do - expect(run).to error_with(/should not contain a hyphen followed by @/) + expect(run).to error_with(/not contain a hyphen followed by an @/) end end @@ -256,7 +248,7 @@ def tmp_cask(name, text) let(:cask_token) { "app@-beta" } it "fails" do - expect(run).to error_with(/should not contain @ followed by a hyphen/) + expect(run).to error_with(/not contain an @ followed by a hyphen/) end end @@ -264,23 +256,7 @@ def tmp_cask(name, text) let(:cask_token) { "app stuff" } it "fails" do - expect(run).to error_with(/whitespace should be replaced by hyphens/) - end - end - - context "when cask token has underscores" do - let(:cask_token) { "app_stuff" } - - it "fails" do - expect(run).to error_with(/underscores should be replaced by hyphens/) - end - end - - context "when cask token has non-alphanumeric characters" do - let(:cask_token) { "app(stuff)" } - - it "fails" do - expect(run).to error_with(/alphanumeric characters, hyphens and @/) + expect(run).to error_with(/not contain whitespace/) end end @@ -288,7 +264,7 @@ def tmp_cask(name, text) let(:cask_token) { "app--stuff" } it "fails" do - expect(run).to error_with(/should not contain double hyphens/) + expect(run).to error_with(/not contain double hyphens/) end end @@ -296,7 +272,7 @@ def tmp_cask(name, text) let(:cask_token) { "-app" } it "fails" do - expect(run).to error_with(/should not have leading or trailing hyphens/) + expect(run).to error_with(/not contain a leading hyphen/) end end @@ -304,7 +280,7 @@ def tmp_cask(name, text) let(:cask_token) { "app-" } it "fails" do - expect(run).to error_with(/should not have leading or trailing hyphens/) + expect(run).to error_with(/not contain a trailing hyphen/) end end end diff --git a/Library/Homebrew/test/formula_auditor_spec.rb b/Library/Homebrew/test/formula_auditor_spec.rb index 84178498491d6..b32615cbf4c25 100644 --- a/Library/Homebrew/test/formula_auditor_spec.rb +++ b/Library/Homebrew/test/formula_auditor_spec.rb @@ -476,7 +476,7 @@ class Foo < Formula end end - describe "#audit_formula_name" do + describe "#audit_name" do specify "no issue" do fa = formula_auditor "foo", <<~RUBY, core_tap: true, strict: true class Foo < Formula @@ -485,7 +485,7 @@ class Foo < Formula end RUBY - fa.audit_formula_name + fa.audit_name expect(fa.problems).to be_empty end @@ -497,7 +497,7 @@ class Foo < Formula end RUBY - fa.audit_formula_name + fa.audit_name expect(fa.problems.first[:message]).to match "must not contain uppercase letters" end end