Skip to content

Commit

Permalink
Pypi: Restore regex support
Browse files Browse the repository at this point in the history
We recently updated the `Pypi` strategy to use the PyPI JSON API and
the default strategy behavior no longer relies on a regex, so the initial implementation didn't include regex handling. This restores
support for a `livecheck` block regex by updating the `DEFAULT_BLOCK`
logic to handle an optional regex. This allows us to use a regex to
omit parts of the `info.version` value without having to duplicate
the default block logic in a `strategy` block only to use a regex.

This isn't currently necessary for any existing formulae using the
`Pypi` strategy but we have a few that needed a custom regex with
the previous strategy approach, so they may need this functionality
in the future. Besides that, restoring regex support to `Pypi`
ensures that `livecheck`/`strategy` blocks work in a fairly
consistent manner across strategies.
  • Loading branch information
samford committed Dec 8, 2024
1 parent 08c927b commit 270313f
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 10 deletions.
10 changes: 7 additions & 3 deletions Library/Homebrew/livecheck/strategy/pypi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@ class Pypi

# 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
Expand Down
26 changes: 19 additions & 7 deletions Library/Homebrew/test/livecheck/strategy/pypi_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
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
{
Expand All @@ -17,25 +17,26 @@
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
Expand Down Expand Up @@ -76,10 +77,17 @@
{
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
Expand All @@ -92,18 +100,22 @@
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
end).to eq(match_data[:cached])
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
Expand Down

0 comments on commit 270313f

Please sign in to comment.