add verified parameter in url
This commit is contained in:
parent
58f279c72a
commit
058a1c3645
@ -26,10 +26,6 @@ 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
|
||||
|
||||
Cask/HomepageUrlTrailingSlash:
|
||||
Description: 'Ensure that the homepage url has a slash after the domain name.'
|
||||
Enabled: true
|
||||
|
@ -52,6 +52,9 @@ module Cask
|
||||
check_sha256
|
||||
check_desc
|
||||
check_url
|
||||
check_unnecessary_verified
|
||||
check_missing_verified
|
||||
check_no_match
|
||||
check_generic_artifacts
|
||||
check_token_valid
|
||||
check_token_bad_words
|
||||
@ -345,6 +348,80 @@ module Cask
|
||||
bad_url_format?(/osd/, [%r{\Ahttps?://([^/]+.)?dl\.osdn\.jp/}])
|
||||
end
|
||||
|
||||
def homepage
|
||||
URI(cask.homepage.to_s).host
|
||||
end
|
||||
|
||||
def domain
|
||||
URI(cask.url.to_s).host
|
||||
end
|
||||
|
||||
def url_match_homepage?
|
||||
host = cask.url.to_s.downcase
|
||||
host_uri = URI(host)
|
||||
host = if host.match?(/:\d/) && host_uri.port != 80
|
||||
"#{host_uri.host}:#{host_uri.port}"
|
||||
else
|
||||
host_uri.host
|
||||
end
|
||||
home = homepage.downcase
|
||||
if (split_host = host.split(".")).length >= 3
|
||||
host = split_host[-2..].join(".")
|
||||
end
|
||||
if (split_home = homepage.split(".")).length >= 3
|
||||
home = split_home[-2..].join(".")
|
||||
end
|
||||
host == home
|
||||
end
|
||||
|
||||
def strip_url_scheme(url)
|
||||
url.sub(%r{^.*://(www\.)?}, "")
|
||||
end
|
||||
|
||||
def url_from_verified
|
||||
cask.url.verified.sub(%r{^https?://}, "")
|
||||
end
|
||||
|
||||
def verified_matches_url?
|
||||
strip_url_scheme(cask.url.to_s).start_with?(url_from_verified)
|
||||
end
|
||||
|
||||
def verified_present?
|
||||
cask.url.verified.present?
|
||||
end
|
||||
|
||||
def url_includes_file?
|
||||
cask.url.to_s.start_with?("file://")
|
||||
end
|
||||
|
||||
def check_unnecessary_verified
|
||||
return unless verified_present?
|
||||
return unless url_match_homepage?
|
||||
return unless verified_matches_url?
|
||||
|
||||
add_warning "The URL's #{domain} matches the homepage #{homepage}, " \
|
||||
"the `verified` parameter of the `url` stanza is unnecessary. " \
|
||||
"See https://github.com/Homebrew/homebrew-cask/blob/master/doc/cask_language_reference/stanzas/url.md#when-url-and-homepage-hostnames-differ-add-verified"
|
||||
end
|
||||
|
||||
def check_missing_verified
|
||||
return if url_includes_file?
|
||||
return if url_match_homepage?
|
||||
return if verified_present?
|
||||
|
||||
add_warning "#{domain} does not match #{homepage}, a `verified` parameter of the `url` has to be added. " \
|
||||
" See https://github.com/Homebrew/homebrew-cask/blob/master/doc/cask_language_reference/stanzas/url.md#when-url-and-homepage-hostnames-differ-add-verified"
|
||||
end
|
||||
|
||||
def check_no_match
|
||||
return if url_match_homepage?
|
||||
return unless verified_present?
|
||||
return if !url_match_homepage? && verified_matches_url?
|
||||
|
||||
add_warning "#{url_from_verified} does not match #{strip_url_scheme(cask.url.to_s)}. " \
|
||||
"See https://github.com/Homebrew/homebrew-cask/blob/master/doc/cask_language_reference/stanzas/url.md#when-url-and-homepage-hostnames-differ-add-verified"
|
||||
end
|
||||
|
||||
def check_generic_artifacts
|
||||
cask.artifacts.select { |a| a.is_a?(Artifact::Artifact) }.each do |artifact|
|
||||
unless artifact.target.absolute?
|
||||
|
@ -8,7 +8,7 @@ class URL
|
||||
extend T::Sig
|
||||
|
||||
attr_reader :uri, :specs,
|
||||
:using,
|
||||
:verified, :using,
|
||||
:tag, :branch, :revisions, :revision,
|
||||
:trust_cert, :cookies, :referer, :header, :user_agent,
|
||||
:data
|
||||
@ -19,6 +19,7 @@ class URL
|
||||
sig do
|
||||
params(
|
||||
uri: T.any(URI::Generic, String),
|
||||
verified: T.nilable(String),
|
||||
using: T.nilable(Symbol),
|
||||
tag: T.nilable(String),
|
||||
branch: T.nilable(String),
|
||||
@ -34,6 +35,7 @@ class URL
|
||||
end
|
||||
def initialize(
|
||||
uri,
|
||||
verified: nil,
|
||||
using: nil,
|
||||
tag: nil,
|
||||
branch: nil,
|
||||
@ -49,6 +51,7 @@ class URL
|
||||
@uri = URI(uri)
|
||||
|
||||
specs = {}
|
||||
specs[:verified] = @verified = verified
|
||||
specs[:using] = @using = using
|
||||
specs[:tag] = @tag = tag
|
||||
specs[:branch] = @branch = branch
|
||||
|
@ -1,180 +0,0 @@
|
||||
# typed: false
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "forwardable"
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module Cask
|
||||
# This cop checks that a cask's homepage matches the download URL,
|
||||
# or if it doesn't, checks if a comment in the form
|
||||
# `# example.com was verified as official when first introduced to the cask`
|
||||
# is present.
|
||||
class HomepageMatchesUrl < Cop
|
||||
extend Forwardable
|
||||
include CaskHelp
|
||||
|
||||
REFERENCE_URL =
|
||||
"https://github.com/Homebrew/homebrew-cask/blob/HEAD/doc/" \
|
||||
"cask_language_reference/stanzas/url.md#when-url-and-homepage-hostnames-differ-add-a-comment"
|
||||
|
||||
COMMENT_FORMAT = /# [^ ]+ was verified as official when first introduced to the cask/.freeze
|
||||
|
||||
MSG_NO_MATCH = "`%<url>s` does not match `%<full_url>s`"
|
||||
|
||||
MSG_MISSING = ("`%<domain>s` does not match `%<homepage>s`, a comment has to be added " \
|
||||
"above the `url` stanza. For details, see " + REFERENCE_URL).freeze
|
||||
|
||||
MSG_WRONG_FORMAT = ("`%<comment>s` does not match the expected comment format. " \
|
||||
"For details, see " + REFERENCE_URL).freeze
|
||||
|
||||
MSG_UNNECESSARY = "The URL's domain `%<domain>s` matches the homepage `%<homepage>s`, " \
|
||||
"the comment above the `url` stanza is unnecessary"
|
||||
|
||||
def on_cask(cask_block)
|
||||
@cask_block = cask_block
|
||||
return unless homepage_stanza
|
||||
|
||||
add_offenses
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :cask_block
|
||||
|
||||
def_delegators :cask_block, :cask_node, :toplevel_stanzas,
|
||||
:sorted_toplevel_stanzas
|
||||
|
||||
def add_offenses
|
||||
toplevel_stanzas.select(&:url?).each do |url|
|
||||
next if add_offense_unnecessary_comment(url)
|
||||
next if add_offense_missing_comment(url)
|
||||
next if add_offense_no_match(url)
|
||||
next if add_offense_wrong_format(url)
|
||||
end
|
||||
end
|
||||
|
||||
def add_offense_unnecessary_comment(stanza)
|
||||
return unless comment?(stanza)
|
||||
return unless url_match_homepage?(stanza)
|
||||
return unless comment_matches_format?(stanza)
|
||||
return unless comment_matches_url?(stanza)
|
||||
|
||||
comment = comment(stanza).loc.expression
|
||||
add_offense(comment,
|
||||
location: comment,
|
||||
message: format(MSG_UNNECESSARY, domain: domain(stanza), homepage: homepage))
|
||||
end
|
||||
|
||||
def add_offense_missing_comment(stanza)
|
||||
return if url_match_homepage?(stanza)
|
||||
return if !url_match_homepage?(stanza) && comment?(stanza)
|
||||
|
||||
range = stanza.source_range
|
||||
url_domain = domain(stanza)
|
||||
add_offense(range, location: range, message: format(MSG_MISSING, domain: url_domain, homepage: homepage))
|
||||
end
|
||||
|
||||
def add_offense_no_match(stanza)
|
||||
return if url_match_homepage?(stanza)
|
||||
return unless comment?(stanza)
|
||||
return if !url_match_homepage?(stanza) && comment_matches_url?(stanza)
|
||||
|
||||
comment = comment(stanza).loc.expression
|
||||
add_offense(comment,
|
||||
location: comment,
|
||||
message: format(MSG_NO_MATCH, url: url_from_comment(stanza), full_url: full_url(stanza)))
|
||||
end
|
||||
|
||||
def add_offense_wrong_format(stanza)
|
||||
return if url_match_homepage?(stanza)
|
||||
return unless comment?(stanza)
|
||||
return if comment_matches_format?(stanza)
|
||||
|
||||
comment = comment(stanza).loc.expression
|
||||
add_offense(comment,
|
||||
location: comment,
|
||||
message: format(MSG_WRONG_FORMAT, comment: comment(stanza).text))
|
||||
end
|
||||
|
||||
def comment?(stanza)
|
||||
!stanza.comments.empty?
|
||||
end
|
||||
|
||||
def comment(stanza)
|
||||
stanza.comments.last
|
||||
end
|
||||
|
||||
def comment_matches_format?(stanza)
|
||||
comment(stanza).text =~ COMMENT_FORMAT
|
||||
end
|
||||
|
||||
def url_from_comment(stanza)
|
||||
comment(stanza).text
|
||||
.sub(/[^ ]*# ([^ ]+) .*/, '\1')
|
||||
end
|
||||
|
||||
def comment_matches_url?(stanza)
|
||||
full_url(stanza).include?(url_from_comment(stanza))
|
||||
end
|
||||
|
||||
def strip_url_scheme(url)
|
||||
url.sub(%r{^.*://(www\.)?}, "")
|
||||
end
|
||||
|
||||
def domain(stanza)
|
||||
strip_url_scheme(extract_url(stanza)).gsub(%r{^([^/]+).*}, '\1')
|
||||
end
|
||||
|
||||
def extract_url(stanza)
|
||||
string = stanza.stanza_node.children[2]
|
||||
return string.str_content if string.str_type?
|
||||
|
||||
string.to_s.gsub(%r{.*"([a-z0-9]+://[^"]+)".*}m, '\1')
|
||||
end
|
||||
|
||||
def url_match_homepage?(stanza)
|
||||
host = extract_url(stanza).downcase
|
||||
host_uri = begin
|
||||
URI(remove_non_ascii(host))
|
||||
rescue URI::InvalidURIError
|
||||
# Can't check if we can't parse.
|
||||
nil
|
||||
end
|
||||
|
||||
return true if host_uri.blank?
|
||||
|
||||
host = if host.match?(/:\d/) && host_uri.port != 80
|
||||
"#{host_uri.host}:#{host_uri.port}"
|
||||
else
|
||||
host_uri.host
|
||||
end
|
||||
home = homepage.downcase
|
||||
if (split_host = host.split(".")).length >= 3
|
||||
host = split_host[-2..].join(".")
|
||||
end
|
||||
if (split_home = homepage.split(".")).length >= 3
|
||||
home = split_home[-2..].join(".")
|
||||
end
|
||||
host == home
|
||||
end
|
||||
|
||||
def full_url(stanza)
|
||||
strip_url_scheme(extract_url(stanza))
|
||||
end
|
||||
|
||||
def homepage
|
||||
URI(remove_non_ascii(extract_url(homepage_stanza))).host
|
||||
end
|
||||
|
||||
def homepage_stanza
|
||||
toplevel_stanzas.find(&:homepage?)
|
||||
end
|
||||
|
||||
def remove_non_ascii(string)
|
||||
string.gsub(/\P{ASCII}/, "")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -13,7 +13,6 @@ 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"
|
||||
require "rubocops/cask/stanza_order"
|
||||
|
@ -887,5 +887,80 @@ describe Cask::Audit, :cask do
|
||||
expect(subject).to pass
|
||||
end
|
||||
end
|
||||
|
||||
context "when the url matches the homepage" do
|
||||
let(:cask_token) { "foo" }
|
||||
let(:cask) do
|
||||
tmp_cask cask_token.to_s, <<~RUBY
|
||||
cask '#{cask_token}' do
|
||||
version '1.0'
|
||||
sha256 '8dd95daa037ac02455435446ec7bc737b34567afe9156af7d20b2a83805c1d8a'
|
||||
url 'https://foo.brew.sh/foo.zip'
|
||||
name 'Audit'
|
||||
desc 'Audit Description'
|
||||
homepage 'https://foo.brew.sh'
|
||||
app 'Audit.app'
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it { is_expected.to pass }
|
||||
end
|
||||
|
||||
context "when the url does not match the homepage" do
|
||||
let(:cask_token) { "foo" }
|
||||
let(:cask) do
|
||||
tmp_cask cask_token.to_s, <<~RUBY
|
||||
cask '#{cask_token}' do
|
||||
version '1.8.0_72,8.13.0.5'
|
||||
sha256 '8dd95daa037ac02455435446ec7bc737b34567afe9156af7d20b2a83805c1d8a'
|
||||
url 'https://brew.sh/foo.zip'
|
||||
name 'Audit'
|
||||
desc 'Audit Description'
|
||||
homepage 'https://foo.example.org'
|
||||
app 'Audit.app'
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it { is_expected.to warn_with(/a `verified` parameter of the `url` has to be added./) }
|
||||
end
|
||||
|
||||
context "when the url does not match the homepage with verified" do
|
||||
let(:cask_token) { "foo" }
|
||||
let(:cask) do
|
||||
tmp_cask cask_token.to_s, <<~RUBY
|
||||
cask '#{cask_token}' do
|
||||
version '1.8.0_72,8.13.0.5'
|
||||
sha256 '8dd95daa037ac02455435446ec7bc737b34567afe9156af7d20b2a83805c1d8a'
|
||||
url 'https://brew.sh/foo.zip', verified: 'brew.sh'
|
||||
name 'Audit'
|
||||
desc 'Audit Description'
|
||||
homepage 'https://foo.example.org'
|
||||
app 'Audit.app'
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it { is_expected.to pass }
|
||||
end
|
||||
|
||||
context "when there is no homepage" do
|
||||
let(:cask_token) { "foo" }
|
||||
let(:cask) do
|
||||
tmp_cask cask_token.to_s, <<~RUBY
|
||||
cask '#{cask_token}' do
|
||||
version '1.8.0_72,8.13.0.5'
|
||||
sha256 '8dd95daa037ac02455435446ec7bc737b34567afe9156af7d20b2a83805c1d8a'
|
||||
url 'https://brew.sh/foo.zip'
|
||||
name 'Audit'
|
||||
desc 'Audit Description'
|
||||
app 'Audit.app'
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it { is_expected.to fail_with(/a homepage stanza is required/) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,216 +0,0 @@
|
||||
# typed: false
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "rubocops/rubocop-cask"
|
||||
require "test/rubocops/cask/shared_examples/cask_cop"
|
||||
|
||||
describe RuboCop::Cop::Cask::HomepageMatchesUrl do
|
||||
include CaskCop
|
||||
|
||||
subject(:cop) { described_class.new }
|
||||
|
||||
context "when the url matches the homepage and there is no comment" do
|
||||
let(:source) do
|
||||
<<-CASK.undent
|
||||
cask 'foo' do
|
||||
url 'https://foo.brew.sh/foo.zip'
|
||||
homepage 'https://foo.brew.sh'
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
include_examples "does not report any offenses"
|
||||
end
|
||||
|
||||
context "when the url matches the homepage and the url stanza has " \
|
||||
"a referrer and no interpolation" do
|
||||
let(:source) do
|
||||
<<-CASK.undent
|
||||
cask 'foo' do
|
||||
url 'https://foo.brew.sh/foo.zip',
|
||||
referrer: 'https://brew.sh/foo/'
|
||||
homepage 'https://foo.brew.sh'
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
include_examples "does not report any offenses"
|
||||
end
|
||||
|
||||
context "when the url matches the homepage and the url stanza has " \
|
||||
"a referrer and interpolation" do
|
||||
let(:source) do
|
||||
<<-CASK.undent
|
||||
cask 'foo' do
|
||||
version '1.8.0_72,8.13.0.5'
|
||||
url "https://foo.brew.sh/foo-\#{version.after_comma}-\#{version.minor}.\#{version.patch}.\#{version.before_comma.sub(\%r{.*_}, '')}.zip",
|
||||
referrer: 'https://brew.sh/foo/'
|
||||
homepage 'https://foo.brew.sh'
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
include_examples "does not report any offenses"
|
||||
end
|
||||
|
||||
context "when the url matches the homepage but there is a comment " \
|
||||
"which does not match the url" do
|
||||
let(:source) do
|
||||
<<-CASK.undent
|
||||
cask 'foo' do
|
||||
# this is just a comment with information
|
||||
url 'https://brew.sh/foo.zip'
|
||||
homepage 'https://brew.sh'
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
include_examples "does not report any offenses"
|
||||
end
|
||||
|
||||
context "when the url matches the homepage " \
|
||||
"but there is a comment matching the url" do
|
||||
let(:source) do
|
||||
<<-CASK.undent
|
||||
cask 'foo' do
|
||||
# foo.brew.sh was verified as official when first introduced to the cask
|
||||
url 'https://foo.brew.sh/foo.zip'
|
||||
homepage 'https://foo.brew.sh'
|
||||
end
|
||||
CASK
|
||||
end
|
||||
let(:expected_offenses) do
|
||||
[{
|
||||
message: "The URL's domain `foo.brew.sh` matches the homepage " \
|
||||
"`foo.brew.sh`, the comment above the `url` stanza is " \
|
||||
"unnecessary",
|
||||
severity: :convention,
|
||||
line: 2,
|
||||
column: 2,
|
||||
source: "# foo.brew.sh was verified as official when " \
|
||||
"first introduced to the cask",
|
||||
}]
|
||||
end
|
||||
|
||||
include_examples "reports offenses"
|
||||
end
|
||||
|
||||
context "when the url does not match the homepage" do
|
||||
context "when there is a comment matching the url " \
|
||||
"but not matching the expected format" do
|
||||
let(:source) do
|
||||
<<-CASK.undent
|
||||
cask 'foo' do
|
||||
# brew.sh was verified as official
|
||||
url 'https://brew.sh/foo.zip'
|
||||
homepage 'https://foo.example.org'
|
||||
end
|
||||
CASK
|
||||
end
|
||||
let(:expected_offenses) do
|
||||
[{
|
||||
message: "`# brew.sh was verified as official` does not " \
|
||||
"match the expected comment format. For details, see " \
|
||||
"https://github.com/Homebrew/homebrew-cask/blob/HEAD/doc/" \
|
||||
"cask_language_reference/stanzas/url.md#when-url-and-homepage-hostnames-differ-add-a-comment",
|
||||
severity: :convention,
|
||||
line: 2,
|
||||
column: 2,
|
||||
source: "# brew.sh was verified as official",
|
||||
}]
|
||||
end
|
||||
|
||||
include_examples "reports offenses"
|
||||
end
|
||||
|
||||
context "when there is a comment matching the url " \
|
||||
"and does not have slashes" do
|
||||
let(:source) do
|
||||
<<-CASK.undent
|
||||
cask 'foo' do
|
||||
# brew.sh was verified as official when first introduced to the cask
|
||||
url 'https://brew.sh/foo.zip'
|
||||
homepage 'https://foo.example.org'
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
include_examples "does not report any offenses"
|
||||
end
|
||||
|
||||
context "when there is a comment matching the url and has slashes" do
|
||||
let(:source) do
|
||||
<<-CASK.undent
|
||||
cask 'foo' do
|
||||
# brew.sh/vendor/app was verified as official when first introduced to the cask
|
||||
url 'https://downloads.brew.sh/vendor/app/foo.zip'
|
||||
homepage 'https://vendor.example.org/app/'
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
include_examples "does not report any offenses"
|
||||
end
|
||||
|
||||
context "when there is a comment which does not match the url" do
|
||||
let(:source) do
|
||||
<<-CASK.undent
|
||||
cask 'foo' do
|
||||
# brew.sh was verified as official when first introduced to the cask
|
||||
url 'https://example.org/foo.zip'
|
||||
homepage 'https://foo.brew.sh'
|
||||
end
|
||||
CASK
|
||||
end
|
||||
let(:expected_offenses) do
|
||||
[{
|
||||
message: "`brew.sh` does not match `example.org/foo.zip`",
|
||||
severity: :convention,
|
||||
line: 2,
|
||||
column: 2,
|
||||
source: "# brew.sh was verified as official when " \
|
||||
"first introduced to the cask",
|
||||
}]
|
||||
end
|
||||
|
||||
include_examples "reports offenses"
|
||||
end
|
||||
|
||||
context "when the comment is missing" do
|
||||
let(:source) do
|
||||
<<-CASK.undent
|
||||
cask 'foo' do
|
||||
url 'https://brew.sh/foo.zip'
|
||||
homepage 'https://example.org'
|
||||
end
|
||||
CASK
|
||||
end
|
||||
let(:expected_offenses) do
|
||||
[{
|
||||
message: "`brew.sh` does not match `example.org`, a comment " \
|
||||
"has to be added above the `url` stanza. For details, see " \
|
||||
"https://github.com/Homebrew/homebrew-cask/blob/HEAD/doc/" \
|
||||
"cask_language_reference/stanzas/url.md#when-url-and-homepage-hostnames-differ-add-a-comment",
|
||||
severity: :convention,
|
||||
line: 2,
|
||||
column: 2,
|
||||
source: "url 'https://brew.sh/foo.zip'",
|
||||
}]
|
||||
end
|
||||
|
||||
include_examples "reports offenses"
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is no homepage" do
|
||||
let(:source) do
|
||||
<<-CASK.undent
|
||||
cask 'foo' do
|
||||
url 'https://brew.sh/foo.zip'
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
include_examples "does not report any offenses"
|
||||
end
|
||||
end
|
@ -1,3 +1,11 @@
|
||||
cask "generic-artifact-relative-target" do
|
||||
version "1.2.3"
|
||||
sha256 "d5b2dfbef7ea28c25f7a77cd7fa14d013d82b626db1d82e00e25822464ba19e2"
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/AppWithBinary.zip"
|
||||
name "With Binary"
|
||||
desc "Cask with a binary stanza"
|
||||
homepage "https://brew.sh/with-binary"
|
||||
|
||||
artifact "Caffeine.app", target: "Caffeine.app"
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user