livecheck: allow nil return from strategy blocks

This commit is contained in:
Sam Ford 2021-07-26 20:32:10 -04:00
parent 35f59eb3cb
commit a970780851
No known key found for this signature in database
GPG Key ID: 95209E46C7FFDEFE
20 changed files with 119 additions and 51 deletions

View File

@ -52,7 +52,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))), block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -59,7 +59,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))), block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -50,7 +50,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))), block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -37,19 +37,24 @@ module Homebrew
sig { sig {
params( params(
content: String, content: String,
block: T.nilable(T.proc.params(arg0: Hash).returns(String)), block: T.nilable(T.proc.params(arg0: T::Hash[String, T.untyped]).returns(T.nilable(String))),
).returns(T.nilable(String)) ).returns(T.nilable(String))
} }
def self.version_from_content(content, &block) def self.version_from_content(content, &block)
require "yaml" require "yaml"
return unless (yaml = YAML.safe_load(content)) yaml = YAML.safe_load(content)
return if yaml.blank?
if block if block
value = block.call(yaml) case (value = block.call(yaml))
return value if value.is_a?(String) when String
return value
raise TypeError, "Return value of `strategy :electron_builder` block must be a string." when nil
return
else
raise TypeError, "Return value of `strategy :electron_builder` block must be a string."
end
end end
yaml["version"] yaml["version"]
@ -65,7 +70,7 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: Hash).returns(String)), block: T.nilable(T.proc.params(arg0: T::Hash[String, T.untyped]).returns(T.nilable(String))),
).returns(T::Hash[Symbol, T.untyped]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -56,7 +56,7 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: Cask::Cask, cask: Cask::Cask,
block: T.nilable(T.proc.params(arg0: T::Hash[String, Item]).returns(String)), block: T.nilable(T.proc.params(arg0: T::Hash[String, Item]).returns(T.nilable(String))),
).returns(T::Hash[Symbol, T.untyped]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask:, &block) def self.find_versions(url, regex, cask:, &block)
@ -69,13 +69,14 @@ module Homebrew
versions = unversioned_cask_checker.all_versions.transform_values { |v| Item.new(bundle_version: v) } versions = unversioned_cask_checker.all_versions.transform_values { |v| Item.new(bundle_version: v) }
if block if block
match = block.call(versions) case (value = block.call(versions))
when String
unless T.unsafe(match).is_a?(String) match_data[:matches][value] = Version.new(value)
when nil
return match_data
else
raise TypeError, "Return value of `strategy :extract_plist` block must be a string." raise TypeError, "Return value of `strategy :extract_plist` block must be a string."
end end
match_data[:matches][match] = Version.new(match) if match
elsif versions.any? elsif versions.any?
versions.each_value do |item| versions.each_value do |item|
version = item.bundle_version.nice_version version = item.bundle_version.nice_version

View File

@ -81,8 +81,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: T::Array[String]) block: T.nilable(
.returns(T.any(T::Array[String], String))), T.proc.params(arg0: T::Array[String]).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)
@ -105,6 +106,8 @@ module Homebrew
value.each do |tag| value.each do |tag|
match_data[:matches][tag] = Version.new(tag) match_data[:matches][tag] = Version.new(tag)
end end
when nil
return match_data
else else
raise TypeError, "Return value of `strategy :git` block must be a string or array of strings." raise TypeError, "Return value of `strategy :git` block must be a string or array of strings."
end end

View File

@ -67,7 +67,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))), block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -55,7 +55,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))), block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -59,7 +59,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))), block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -52,7 +52,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))), block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -40,8 +40,7 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: T::Hash[String, String]) block: T.nilable(T.proc.params(arg0: T::Hash[String, String]).returns(T.nilable(String))),
.returns(T.any(T::Array[String], String))),
).returns(T::Hash[Symbol, T.untyped]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)
@ -52,31 +51,40 @@ module Homebrew
# Merge the headers from all responses into one hash # Merge the headers from all responses into one hash
merged_headers = headers.reduce(&:merge) merged_headers = headers.reduce(&:merge)
if block version = if block
match = yield merged_headers, regex case (value = block.call(merged_headers, regex))
when String
value
when nil
return match_data
else
raise TypeError, "Return value of `strategy :header_match` block must be a string."
end
else else
match = nil value = nil
if (filename = merged_headers["content-disposition"]) if (filename = merged_headers["content-disposition"])
if regex if regex
match ||= filename[regex, 1] value ||= filename[regex, 1]
else else
v = Version.parse(filename, detected_from_url: true) v = Version.parse(filename, detected_from_url: true)
match ||= v.to_s unless v.null? value ||= v.to_s unless v.null?
end end
end end
if (location = merged_headers["location"]) if (location = merged_headers["location"])
if regex if regex
match ||= location[regex, 1] value ||= location[regex, 1]
else else
v = Version.parse(location, detected_from_url: true) v = Version.parse(location, detected_from_url: true)
match ||= v.to_s unless v.null? value ||= v.to_s unless v.null?
end end
end end
value
end end
match_data[:matches][match] = Version.new(match) if match match_data[:matches][version] = Version.new(version) if version
match_data match_data
end end

View File

@ -50,7 +50,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))), block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -46,7 +46,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))), block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -45,13 +45,24 @@ module Homebrew
# @param regex [Regexp] a regex used for matching versions in the # @param regex [Regexp] a regex used for matching versions in the
# content # content
# @return [Array] # @return [Array]
sig {
params(
content: String,
regex: Regexp,
block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Array[String])
}
def self.page_matches(content, regex, &block) def self.page_matches(content, regex, &block)
if block if block
case (value = block.call(content, regex)) case (value = block.call(content, regex))
when String when String
return [value] return [value]
when Array when Array
return value return value.compact.uniq
when nil
return []
else else
raise TypeError, "Return value of `strategy :page_match` block must be a string or array of strings." raise TypeError, "Return value of `strategy :page_match` block must be a string or array of strings."
end end
@ -61,10 +72,10 @@ module Homebrew
case match case match
when String when String
match match
else when Array
match.first match.first
end end
end.uniq end.compact.uniq
end end
# Checks the content at the URL for new versions, using the provided # Checks the content at the URL for new versions, using the provided
@ -78,10 +89,12 @@ module Homebrew
sig { sig {
params( params(
url: String, url: String,
regex: T.nilable(Regexp), regex: Regexp,
cask: T.nilable(Cask::Cask), cask: T.nilable(Cask::Cask),
provided_content: T.nilable(String), provided_content: T.nilable(String),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))), block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, provided_content: nil, &block) def self.find_versions(url, regex, cask: nil, provided_content: nil, &block)

View File

@ -56,7 +56,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))), block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -62,7 +62,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))), block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -144,7 +144,7 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: Item).returns(String)), block: T.nilable(T.proc.params(arg0: Item).returns(T.nilable(String))),
).returns(T::Hash[Symbol, T.untyped]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)
@ -156,19 +156,20 @@ module Homebrew
content = match_data.delete(:content) content = match_data.delete(:content)
if (item = item_from_content(content)) if (item = item_from_content(content))
match = if block version = if block
value = block.call(item) case (value = block.call(item))
when String
unless T.unsafe(value).is_a?(String) value
when nil
return match_data
else
raise TypeError, "Return value of `strategy :sparkle` block must be a string." raise TypeError, "Return value of `strategy :sparkle` block must be a string."
end end
value
else else
item.bundle_version&.nice_version item.bundle_version&.nice_version
end end
match_data[:matches][match] = Version.new(match) if match match_data[:matches][version] = Version.new(version) if version
end end
match_data match_data

View File

@ -85,7 +85,9 @@ module Homebrew
url: String, url: String,
regex: T.nilable(Regexp), regex: T.nilable(Regexp),
cask: T.nilable(Cask::Cask), cask: T.nilable(Cask::Cask),
block: T.nilable(T.proc.params(arg0: String).returns(T.any(T::Array[String], String))), block: T.nilable(
T.proc.params(arg0: String, arg1: Regexp).returns(T.any(String, T::Array[String], NilClass)),
),
).returns(T::Hash[Symbol, T.untyped]) ).returns(T::Hash[Symbol, T.untyped])
} }
def self.find_versions(url, regex, cask: nil, &block) def self.find_versions(url, regex, cask: nil, &block)

View File

@ -54,5 +54,14 @@ describe Homebrew::Livecheck::Strategy::ElectronBuilder do
expect(version).to eq "1.2.4" expect(version).to eq "1.2.4"
end end
it "allows a nil return from a strategy block" do
expect(electron_builder.version_from_content(electron_builder_yaml) { next }).to eq(nil)
end
it "errors on an invalid return type from a strategy block" do
expect { electron_builder.version_from_content(electron_builder_yaml) { 123 } }
.to raise_error(TypeError, "Return value of `strategy :electron_builder` block must be a string.")
end
end end
end end

View File

@ -72,9 +72,13 @@ describe Homebrew::Livecheck::Strategy::PageMatch do
end end
it "finds matching text in page content using a strategy block" do it "finds matching text in page content using a strategy block" do
expect(page_match.page_matches(page_content, regex) { |content| content.scan(regex).map(&:first).uniq }) expect(page_match.page_matches(page_content, regex) { |content, regex| content.scan(regex).map(&:first).uniq })
.to eq(page_content_matches) .to eq(page_content_matches)
end end
it "allows a nil return from a strategy block" do
expect(page_match.page_matches(page_content, regex) { next }).to eq([])
end
end end
describe "::find_versions?" do describe "::find_versions?" do