diff --git a/Library/.rubocop_cask.yml b/Library/.rubocop_cask.yml index d265876fcb..cc6ccf9a5f 100644 --- a/Library/.rubocop_cask.yml +++ b/Library/.rubocop_cask.yml @@ -1,5 +1,9 @@ inherit_from: ./Homebrew/.rubocop.yml +Cask/Desc: + Description: 'Ensure that the desc stanza conforms to various content and style checks.' + Enabled: true + Cask/HomepageMatchesUrl: Description: 'Ensure that the homepage and url match, otherwise add a comment. More info at https://github.com/Homebrew/homebrew-cask/blob/HEAD/doc/cask_language_reference/stanzas/url.md#when-url-and-homepage-hostnames-differ-add-a-comment' Enabled: true diff --git a/Library/Homebrew/rubocops/cask/ast/cask_header.rb b/Library/Homebrew/rubocops/cask/ast/cask_header.rb index 8668c2daad..7646552eec 100644 --- a/Library/Homebrew/rubocops/cask/ast/cask_header.rb +++ b/Library/Homebrew/rubocops/cask/ast/cask_header.rb @@ -29,7 +29,13 @@ module RuboCop end def cask_token - @cask_token ||= pair_node.val_node.children.first + @cask_token ||= begin + if dsl_version? + pair_node.val_node.children.first + else + method_node.first_argument.str_content + end + end end def hash_node diff --git a/Library/Homebrew/rubocops/cask/desc.rb b/Library/Homebrew/rubocops/cask/desc.rb new file mode 100644 index 0000000000..90ceefab9f --- /dev/null +++ b/Library/Homebrew/rubocops/cask/desc.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require "forwardable" +require "uri" +require "rubocops/cask/mixin/on_desc_stanza" +require "rubocops/shared/desc_helper" + +module RuboCop + module Cop + module Cask + # This cop audits `desc` in Casks. + # See the `DescHelper` module for details of the checks. + class Desc < Cop + include OnDescStanza + include DescHelper + + def on_desc_stanza(stanza) + name = cask_block.header.cask_token + desc_call = stanza.stanza_node + audit_desc(:cask, name, desc_call) + end + + def autocorrect(node) + name = cask_block.header.cask_token + autocorrect_desc(node, name) + end + end + end + end +end diff --git a/Library/Homebrew/rubocops/cask/mixin/on_desc_stanza.rb b/Library/Homebrew/rubocops/cask/mixin/on_desc_stanza.rb new file mode 100644 index 0000000000..067b6c30e4 --- /dev/null +++ b/Library/Homebrew/rubocops/cask/mixin/on_desc_stanza.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Cask + # Common functionality for checking desc stanzas. + module OnDescStanza + extend Forwardable + include CaskHelp + + def on_cask(cask_block) + @cask_block = cask_block + + toplevel_stanzas.select(&:desc?).each do |stanza| + on_desc_stanza(stanza) + end + end + + private + + attr_reader :cask_block + + def_delegators :cask_block, + :toplevel_stanzas + end + end + end +end diff --git a/Library/Homebrew/rubocops/rubocop-cask.rb b/Library/Homebrew/rubocops/rubocop-cask.rb index 3af610ebef..646e483994 100644 --- a/Library/Homebrew/rubocops/rubocop-cask.rb +++ b/Library/Homebrew/rubocops/rubocop-cask.rb @@ -11,6 +11,7 @@ require "rubocops/cask/extend/string" require "rubocops/cask/extend/node" require "rubocops/cask/mixin/cask_help" require "rubocops/cask/mixin/on_homepage_stanza" +require "rubocops/cask/desc" require "rubocops/cask/homepage_matches_url" require "rubocops/cask/homepage_url_trailing_slash" require "rubocops/cask/no_dsl_version" diff --git a/Library/Homebrew/test/rubocops/cask/desc_spec.rb b/Library/Homebrew/test/rubocops/cask/desc_spec.rb new file mode 100644 index 0000000000..28a2b6d3f7 --- /dev/null +++ b/Library/Homebrew/test/rubocops/cask/desc_spec.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require "rubocops/rubocop-cask" +require "test/rubocops/cask/shared_examples/cask_cop" + +describe RuboCop::Cop::Cask::Desc do + include CaskCop + + subject(:cop) { described_class.new } + + context "with incorrect `desc` stanza" do + let(:source) { + <<~RUBY + cask "foo" do + desc "A bar program" + end + RUBY + } + let(:correct_source) { + <<~RUBY + cask "foo" do + desc "Bar program" + end + RUBY + } + let(:expected_offenses) do + [{ + message: "Description shouldn't start with an indefinite article, i.e. \"A\".", + severity: :convention, + line: 2, + column: 8, + source: "A", + }] + end + + include_examples "reports offenses" + + include_examples "autocorrects source" + end + + context "with correct `desc` stanza" do + let(:source) { + <<~RUBY + cask "foo" do + desc "Bar program" + end + RUBY + } + + include_examples "does not report any offenses" + end +end diff --git a/Library/Homebrew/test/rubocops/cask/no_dsl_version_spec.rb b/Library/Homebrew/test/rubocops/cask/no_dsl_version_spec.rb index 9f52bd7bf2..2f6d5747c7 100644 --- a/Library/Homebrew/test/rubocops/cask/no_dsl_version_spec.rb +++ b/Library/Homebrew/test/rubocops/cask/no_dsl_version_spec.rb @@ -8,31 +8,27 @@ describe RuboCop::Cop::Cask::NoDslVersion do subject(:cop) { described_class.new } - context "with header method `cask`" do - let(:header_method) { "cask" } + context "with no dsl version" do + let(:source) { "cask 'foo' do; end" } - context "with no dsl version" do - let(:source) { "cask 'foo' do; end" } + include_examples "does not report any offenses" + end - include_examples "does not report any offenses" + context "with dsl version" do + let(:source) { "cask :v1 => 'foo' do; end" } + let(:correct_source) { "cask 'foo' do; end" } + let(:expected_offenses) do + [{ + message: "Use `cask 'foo'` instead of `cask :v1 => 'foo'`", + severity: :convention, + line: 1, + column: 0, + source: "cask :v1 => 'foo'", + }] end - context "with dsl version" do - let(:source) { "cask :v1 => 'foo' do; end" } - let(:correct_source) { "cask 'foo' do; end" } - let(:expected_offenses) do - [{ - message: "Use `cask 'foo'` instead of `cask :v1 => 'foo'`", - severity: :convention, - line: 1, - column: 0, - source: "cask :v1 => 'foo'", - }] - end + include_examples "reports offenses" - include_examples "reports offenses" - - include_examples "autocorrects source" - end + include_examples "autocorrects source" end end