diff --git a/Library/Homebrew/livecheck/strategy/json.rb b/Library/Homebrew/livecheck/strategy/json.rb index a4631c58e2..b8f05e29ae 100644 --- a/Library/Homebrew/livecheck/strategy/json.rb +++ b/Library/Homebrew/livecheck/strategy/json.rb @@ -58,8 +58,10 @@ module Homebrew end # Parses JSON text and identifies versions using a `strategy` block. - # If a regex is provided, it will be passed as the second argument to - # the `strategy` block (after the parsed JSON data). + # If the block has two parameters, the parsed JSON data will be used as + # the first argument and the regex (if any) will be the second. + # Otherwise, only the parsed JSON data will be passed to the block. + # # @param content [String] the JSON text to parse and check # @param regex [Regexp, nil] a regex used for matching versions in the # content @@ -77,10 +79,8 @@ module Homebrew json = parse_json(content) return [] if json.blank? - block_return_value = if regex.present? + block_return_value = if block.arity == 2 yield(json, regex) - elsif block.arity == 2 - raise "Two arguments found in `strategy` block but no regex provided." else yield(json) end diff --git a/Library/Homebrew/livecheck/strategy/pypi.rb b/Library/Homebrew/livecheck/strategy/pypi.rb index 66351f884c..8711a2264a 100644 --- a/Library/Homebrew/livecheck/strategy/pypi.rb +++ b/Library/Homebrew/livecheck/strategy/pypi.rb @@ -20,10 +20,14 @@ module Homebrew # The default `strategy` block used to extract version information when # a `strategy` block isn't provided. - DEFAULT_BLOCK = T.let(proc do |json| - json.dig("info", "version").presence + DEFAULT_BLOCK = T.let(proc do |json, regex| + version = json.dig("info", "version") + next if version.blank? + + regex ? version[regex, 1] : version end.freeze, T.proc.params( - arg0: T::Hash[String, T.untyped], + json: T::Hash[String, T.untyped], + regex: T.nilable(Regexp), ).returns(T.nilable(String))) # The `Regexp` used to extract the package name and suffix (e.g. file diff --git a/Library/Homebrew/test/livecheck/strategy/json_spec.rb b/Library/Homebrew/test/livecheck/strategy/json_spec.rb index dc18a8f074..5949d83e19 100644 --- a/Library/Homebrew/test/livecheck/strategy/json_spec.rb +++ b/Library/Homebrew/test/livecheck/strategy/json_spec.rb @@ -107,11 +107,6 @@ RSpec.describe Homebrew::Livecheck::Strategy::Json do expect(json.versions_from_content(content_simple, regex) { next }).to eq([]) end - it "errors if a block uses two arguments but a regex is not given" do - expect { json.versions_from_content(content_simple) { |json, regex| json["version"][regex, 1] } } - .to raise_error("Two arguments found in `strategy` block but no regex provided.") - end - it "errors on an invalid return type from a block" do expect { json.versions_from_content(content_simple, regex) { 123 } } .to raise_error(TypeError, Homebrew::Livecheck::Strategy::INVALID_BLOCK_RETURN_VALUE_MSG) diff --git a/Library/Homebrew/test/livecheck/strategy/pypi_spec.rb b/Library/Homebrew/test/livecheck/strategy/pypi_spec.rb index be93644477..d1f44376bb 100644 --- a/Library/Homebrew/test/livecheck/strategy/pypi_spec.rb +++ b/Library/Homebrew/test/livecheck/strategy/pypi_spec.rb @@ -8,7 +8,7 @@ RSpec.describe Homebrew::Livecheck::Strategy::Pypi do let(:pypi_url) { "https://files.pythonhosted.org/packages/ab/cd/efg/example-package-1.2.3.tar.gz" } let(:non_pypi_url) { "https://brew.sh/test" } - let(:regex) { /^v?(\d+(?:\.\d+)+)$/i } + let(:regex) { /^v?(\d+(?:\.\d+)+)/i } let(:generated) do { @@ -17,25 +17,26 @@ RSpec.describe Homebrew::Livecheck::Strategy::Pypi do end # This is a limited subset of a PyPI JSON API response object, for the sake - # of testing. + # of testing. Typical versions use a `1.2.3` format but this adds a suffix, + # so we can test regex matching. let(:content) do <<~JSON { "info": { - "version": "1.2.3" + "version": "1.2.3-456" } } JSON end - let(:matches) { ["1.2.3"] } + let(:matches) { ["1.2.3-456"] } let(:find_versions_return_hash) do { matches: { - "1.2.3" => Version.new("1.2.3"), + "1.2.3-456" => Version.new("1.2.3-456"), }, - regex: nil, + regex:, url: generated[:url], } end @@ -76,10 +77,17 @@ RSpec.describe Homebrew::Livecheck::Strategy::Pypi do { cached:, cached_default: cached.merge({ matches: {} }), + cached_regex: cached.merge({ + matches: { "1.2.3" => Version.new("1.2.3") }, + regex:, + }), } end it "finds versions in provided content" do + expect(pypi.find_versions(url: pypi_url, regex:, provided_content: content)) + .to eq(match_data[:cached_regex]) + expect(pypi.find_versions(url: pypi_url, provided_content: content)) .to eq(match_data[:cached]) end @@ -92,7 +100,7 @@ RSpec.describe Homebrew::Livecheck::Strategy::Pypi do next if match.blank? match[1] - end).to eq(match_data[:cached].merge({ regex: })) + end).to eq(match_data[:cached_regex]) expect(pypi.find_versions(url: pypi_url, provided_content: content) do |json| json.dig("info", "version").presence @@ -100,10 +108,14 @@ RSpec.describe Homebrew::Livecheck::Strategy::Pypi do end it "returns default match_data when block doesn't return version information" do + no_match_regex = /will_not_match/i + expect(pypi.find_versions(url: pypi_url, provided_content: '{"info":{"version":""}}')) .to eq(match_data[:cached_default]) expect(pypi.find_versions(url: pypi_url, provided_content: '{"other":true}')) .to eq(match_data[:cached_default]) + expect(pypi.find_versions(url: pypi_url, regex: no_match_regex, provided_content: content)) + .to eq(match_data[:cached_default].merge({ regex: no_match_regex })) end it "returns default match_data when url is blank" do