Skip to content

Commit ad356d3

Browse files
authored
Merge pull request #18903 from Homebrew/livecheck/pypi-handle-regex
Pypi: Restore regex support
2 parents ff7b953 + 270313f commit ad356d3

File tree

4 files changed

+31
-20
lines changed

4 files changed

+31
-20
lines changed

Library/Homebrew/livecheck/strategy/json.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,10 @@ def self.parse_json(content)
5858
end
5959

6060
# Parses JSON text and identifies versions using a `strategy` block.
61-
# If a regex is provided, it will be passed as the second argument to
62-
# the `strategy` block (after the parsed JSON data).
61+
# If the block has two parameters, the parsed JSON data will be used as
62+
# the first argument and the regex (if any) will be the second.
63+
# Otherwise, only the parsed JSON data will be passed to the block.
64+
#
6365
# @param content [String] the JSON text to parse and check
6466
# @param regex [Regexp, nil] a regex used for matching versions in the
6567
# content
@@ -77,10 +79,8 @@ def self.versions_from_content(content, regex = nil, &block)
7779
json = parse_json(content)
7880
return [] if json.blank?
7981

80-
block_return_value = if regex.present?
82+
block_return_value = if block.arity == 2
8183
yield(json, regex)
82-
elsif block.arity == 2
83-
raise "Two arguments found in `strategy` block but no regex provided."
8484
else
8585
yield(json)
8686
end

Library/Homebrew/livecheck/strategy/pypi.rb

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,14 @@ class Pypi
2020

2121
# The default `strategy` block used to extract version information when
2222
# a `strategy` block isn't provided.
23-
DEFAULT_BLOCK = T.let(proc do |json|
24-
json.dig("info", "version").presence
23+
DEFAULT_BLOCK = T.let(proc do |json, regex|
24+
version = json.dig("info", "version")
25+
next if version.blank?
26+
27+
regex ? version[regex, 1] : version
2528
end.freeze, T.proc.params(
26-
arg0: T::Hash[String, T.untyped],
29+
json: T::Hash[String, T.untyped],
30+
regex: T.nilable(Regexp),
2731
).returns(T.nilable(String)))
2832

2933
# The `Regexp` used to extract the package name and suffix (e.g. file

Library/Homebrew/test/livecheck/strategy/json_spec.rb

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,6 @@
107107
expect(json.versions_from_content(content_simple, regex) { next }).to eq([])
108108
end
109109

110-
it "errors if a block uses two arguments but a regex is not given" do
111-
expect { json.versions_from_content(content_simple) { |json, regex| json["version"][regex, 1] } }
112-
.to raise_error("Two arguments found in `strategy` block but no regex provided.")
113-
end
114-
115110
it "errors on an invalid return type from a block" do
116111
expect { json.versions_from_content(content_simple, regex) { 123 } }
117112
.to raise_error(TypeError, Homebrew::Livecheck::Strategy::INVALID_BLOCK_RETURN_VALUE_MSG)

Library/Homebrew/test/livecheck/strategy/pypi_spec.rb

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
let(:pypi_url) { "https://files.pythonhosted.org/packages/ab/cd/efg/example-package-1.2.3.tar.gz" }
99
let(:non_pypi_url) { "https://brew.sh/test" }
1010

11-
let(:regex) { /^v?(\d+(?:\.\d+)+)$/i }
11+
let(:regex) { /^v?(\d+(?:\.\d+)+)/i }
1212

1313
let(:generated) do
1414
{
@@ -17,25 +17,26 @@
1717
end
1818

1919
# This is a limited subset of a PyPI JSON API response object, for the sake
20-
# of testing.
20+
# of testing. Typical versions use a `1.2.3` format but this adds a suffix,
21+
# so we can test regex matching.
2122
let(:content) do
2223
<<~JSON
2324
{
2425
"info": {
25-
"version": "1.2.3"
26+
"version": "1.2.3-456"
2627
}
2728
}
2829
JSON
2930
end
3031

31-
let(:matches) { ["1.2.3"] }
32+
let(:matches) { ["1.2.3-456"] }
3233

3334
let(:find_versions_return_hash) do
3435
{
3536
matches: {
36-
"1.2.3" => Version.new("1.2.3"),
37+
"1.2.3-456" => Version.new("1.2.3-456"),
3738
},
38-
regex: nil,
39+
regex:,
3940
url: generated[:url],
4041
}
4142
end
@@ -76,10 +77,17 @@
7677
{
7778
cached:,
7879
cached_default: cached.merge({ matches: {} }),
80+
cached_regex: cached.merge({
81+
matches: { "1.2.3" => Version.new("1.2.3") },
82+
regex:,
83+
}),
7984
}
8085
end
8186

8287
it "finds versions in provided content" do
88+
expect(pypi.find_versions(url: pypi_url, regex:, provided_content: content))
89+
.to eq(match_data[:cached_regex])
90+
8391
expect(pypi.find_versions(url: pypi_url, provided_content: content))
8492
.to eq(match_data[:cached])
8593
end
@@ -92,18 +100,22 @@
92100
next if match.blank?
93101

94102
match[1]
95-
end).to eq(match_data[:cached].merge({ regex: }))
103+
end).to eq(match_data[:cached_regex])
96104

97105
expect(pypi.find_versions(url: pypi_url, provided_content: content) do |json|
98106
json.dig("info", "version").presence
99107
end).to eq(match_data[:cached])
100108
end
101109

102110
it "returns default match_data when block doesn't return version information" do
111+
no_match_regex = /will_not_match/i
112+
103113
expect(pypi.find_versions(url: pypi_url, provided_content: '{"info":{"version":""}}'))
104114
.to eq(match_data[:cached_default])
105115
expect(pypi.find_versions(url: pypi_url, provided_content: '{"other":true}'))
106116
.to eq(match_data[:cached_default])
117+
expect(pypi.find_versions(url: pypi_url, regex: no_match_regex, provided_content: content))
118+
.to eq(match_data[:cached_default].merge({ regex: no_match_regex }))
107119
end
108120

109121
it "returns default match_data when url is blank" do

0 commit comments

Comments
 (0)