-
-
Notifications
You must be signed in to change notification settings - Fork 9.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
livecheck: add GithubLatest strategy #9381
Changes from all commits
f96b8e7
d173b57
e37da96
7ef88f1
524272a
28bfa0c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -52,19 +52,28 @@ def from_symbol(symbol) | |
# Returns an array of strategies that apply to the provided URL. | ||
# | ||
# @param url [String] the URL to check for matching strategies | ||
# @param regex_provided [Boolean] whether a regex is provided in a | ||
# @param livecheck_strategy [Symbol] a {Strategy} symbol from the | ||
# `livecheck` block | ||
# @param regex_provided [Boolean] whether a regex is provided in the | ||
# `livecheck` block | ||
# @return [Array] | ||
def from_url(url, regex_provided = nil) | ||
def from_url(url, livecheck_strategy: nil, regex_provided: nil) | ||
usable_strategies = strategies.values.select do |strategy| | ||
# Ignore strategies with a priority of 0 or lower | ||
next if strategy.const_defined?(:PRIORITY) && !strategy::PRIORITY.positive? | ||
if strategy == PageMatch | ||
# Only treat the `PageMatch` strategy as usable if a regex is | ||
# present in the `livecheck` block | ||
next unless regex_provided | ||
elsif strategy.const_defined?(:PRIORITY) && | ||
!strategy::PRIORITY.positive? && | ||
from_symbol(livecheck_strategy) != strategy | ||
# Ignore strategies with a priority of 0 or lower, unless the | ||
# strategy is specified in the `livecheck` block | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We explicitly state on line 17 of this file that strategies with priorities of 0 or lower are ignored. Why do we allow such strategies when they're specified in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As the comment on line 15 mentions, the 0-10 range is informal. It's technically possible for us to go above or below this range if it becomes necessary in the future and that's why we don't strictly enforce the range in the code. The only ideas that we strictly enforce in the code are:
I do think this explanation can be improved a little (e.g., I didn't mention here that the way to apply a strategy with a non-positive priority is using |
||
next | ||
end | ||
|
||
strategy.respond_to?(:match?) && strategy.match?(url) | ||
end | ||
|
||
usable_strategies << strategies[:page_match] if strategies.key?(:page_match) && regex_provided | ||
|
||
# Sort usable strategies in descending order by priority, using the | ||
# DEFAULT_PRIORITY when a strategy doesn't contain a PRIORITY constant | ||
usable_strategies.sort_by do |strategy| | ||
|
@@ -78,6 +87,7 @@ def from_url(url, regex_provided = nil) | |
require_relative "strategy/apache" | ||
require_relative "strategy/bitbucket" | ||
require_relative "strategy/git" | ||
require_relative "strategy/github_latest" | ||
require_relative "strategy/gnome" | ||
require_relative "strategy/gnu" | ||
require_relative "strategy/hackage" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# typed: false | ||
# frozen_string_literal: true | ||
|
||
module Homebrew | ||
module Livecheck | ||
module Strategy | ||
# The {GithubLatest} strategy identifies versions of software at | ||
# github.com by checking a repository's "latest" release page. | ||
# | ||
# GitHub URLs take a few different formats: | ||
# | ||
# * `https://github.com/example/example/releases/download/1.2.3/example-1.2.3.tar.gz` | ||
# * `https://github.com/example/example/archive/v1.2.3.tar.gz` | ||
nandahkrishna marked this conversation as resolved.
Show resolved
Hide resolved
nandahkrishna marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# * `https://github.com/downloads/example/example/example-1.2.3.tar.gz` | ||
# | ||
# A repository's `/releases/latest` URL normally redirects to a release | ||
# tag (e.g., `/releases/tag/1.2.3`). When there isn't a "latest" release, | ||
# it will redirect to the `/releases` page. | ||
# | ||
# This strategy should only be used when we know the upstream repository | ||
# has a "latest" release and the tagged release is appropriate to use | ||
# (e.g., "latest" isn't wrongly pointing to an unstable version, not | ||
# picking up the actual latest version, etc.). The strategy can only be | ||
# applied by using `strategy :github_latest` in a `livecheck` block. | ||
# | ||
# The default regex identifies versions like `1.2.3`/`v1.2.3` in `href` | ||
# attributes containing the tag URL (e.g., | ||
# `/example/example/releases/tag/v1.2.3`). This is a common tag format | ||
# but a modified regex can be provided in a `livecheck` block to override | ||
# the default if a repository uses a different format (e.g., | ||
# `example-1.2.3`, `1.2.3d`, `1.2.3-4`, etc.). | ||
# | ||
# @api public | ||
class GithubLatest | ||
nandahkrishna marked this conversation as resolved.
Show resolved
Hide resolved
|
||
NICE_NAME = "GitHub - Latest" | ||
|
||
# A priority of zero causes livecheck to skip the strategy. We do this | ||
# for {GithubLatest} so we can selectively apply the strategy using | ||
# `strategy :github_latest` in a `livecheck` block. | ||
PRIORITY = 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Previously, 0 priority was equivalent (specific) to the PageMatch strategy. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The original idea was that Since
I've thought about updating the I believe this is a better setup overall, as we wouldn't violate the That said, I believe the related changes in this PR are sufficient for now but let me know if I've overlooked anything important. |
||
|
||
nandahkrishna marked this conversation as resolved.
Show resolved
Hide resolved
samford marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# The `Regexp` used to determine if the strategy applies to the URL. | ||
URL_MATCH_REGEX = %r{//github\.com(?:/downloads)?(?:/[^/]+){2}}i.freeze | ||
|
||
# Whether the strategy can be applied to the provided URL. | ||
# | ||
# @param url [String] the URL to match against | ||
# @return [Boolean] | ||
def self.match?(url) | ||
URL_MATCH_REGEX.match?(url) | ||
end | ||
|
||
# Generates a URL and regex (if one isn't provided) and passes them | ||
# to {PageMatch.find_versions} to identify versions in the content. | ||
# | ||
# @param url [String] the URL of the content to check | ||
# @param regex [Regexp] a regex used for matching versions in content | ||
# @return [Hash] | ||
def self.find_versions(url, regex = nil) | ||
%r{github\.com/(?:downloads/)?(?<username>[^/]+)/(?<repository>[^/]+)}i =~ url.sub(/\.git$/i, "") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I checked Homebrew/core, and the following packages use
My understanding is that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've already been through the Can potentially be updated
Unlikely that we can update
|
||
|
||
# Example URL: `https://github.com/example/example/releases/latest` | ||
page_url = "https://github.com/#{username}/#{repository}/releases/latest" | ||
|
||
# The default regex is the same for all URLs using this strategy | ||
regex ||= %r{href=.*?/tag/v?(\d+(?:\.\d+)+)["' >]}i | ||
|
||
Homebrew::Livecheck::Strategy::PageMatch.find_versions(page_url, regex) | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# typed: false | ||
# frozen_string_literal: true | ||
|
||
require "livecheck/strategy/github_latest" | ||
|
||
describe Homebrew::Livecheck::Strategy::GithubLatest do | ||
subject(:github_latest) { described_class } | ||
|
||
let(:github_release_artifact_url) { | ||
"https://github.com/example/example/releases/download/1.2.3/example-1.2.3.tar.gz" | ||
} | ||
let(:github_tag_archive_url) { "https://github.com/example/example/archive/v1.2.3.tar.gz" } | ||
let(:github_repository_upload_url) { "https://github.com/downloads/example/example/example-1.2.3.tar.gz" } | ||
let(:non_github_url) { "https://brew.sh/test" } | ||
|
||
describe "::match?" do | ||
it "returns true if the argument provided is a GitHub release artifact URL" do | ||
expect(github_latest.match?(github_release_artifact_url)).to be true | ||
end | ||
|
||
it "returns true if the argument provided is a GitHub tag archive URL" do | ||
expect(github_latest.match?(github_tag_archive_url)).to be true | ||
end | ||
|
||
it "returns true if the argument provided is a GitHub repository upload URL" do | ||
expect(github_latest.match?(github_repository_upload_url)).to be true | ||
end | ||
|
||
it "returns false if the argument provided is not a GitHub URL" do | ||
expect(github_latest.match?(non_github_url)).to be false | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
preprocess_url
function (still) has the following bit:brew/Library/Homebrew/livecheck/livecheck.rb
Lines 327 to 332 in 24f7898
Shall we remove or make changes to it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thinking is that
/releases/latest
URLs shouldn't ever be processed and keeping this guard in place ensures this continues to be true regardless of whether#preprocess_url
is skipped for some strategies.Removing this guard would mess up checks for any formulae that use a
/releases/latest
URL in alivecheck
block (i.e., not updated to usestrategy :github_latest
).PageMatch
checks only skip preprocessing whenstrategy :page_match
is present in thelivecheck
block (i.e., checks that implicitly usePageMatch
don't skip preprocessing). Homebrew/homebrew-core#66134 will address this for homebrew/core but other taps could be affected if we removed this.There isn't any notable benefit to removing this simple guard but there are clear detriments under certain circumstances. With that in mind, I think we should simply keep this guard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it - thank you! Perhaps it would be helpful to add a comment to that block above explaining which cases it catches (formulae in non-homebrew/core taps + <some conditions> ) -- otherwise it's not obvious why we still check for
github.com
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since I'm not the target audience, do you think something short like
# Handles any `livecheck` blocks not using the `GithubLatest` strategy
would be sufficient? This guard would also apply if a check that uses a/releases/latest
URL mistakenly sneaks into homebrew/core, so I don't think we need to go into the details of when we're most likely to encounter this situation (e.g., non-core taps).