-
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
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
Use Sparkle sorting/filtering in #livecheck_min_os #16196
Use Sparkle sorting/filtering in #livecheck_min_os #16196
Conversation
c876354
to
57cda29
Compare
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.
Thanks @samford, almost there, a few nits.
# `item`) contain arbitrary logic that ignores/overrides the strategy's | ||
# sorting, so we can't identify which item would be first/newest here. | ||
return if cask.livecheck.strategy_block.present? && | ||
cask.livecheck.strategy_block.parameters[0] == [:opt, :items] |
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.
This seems to know way too much about the internals of this strategy block and would be better placed with something like a cannot_do_this?
method.
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.
I'm not sure that I follow. Could you explain a bit more?
For context, Sparkle
strategy
blocks that use the items
argument will categorically do something instead of or in addition to the default sorting. The usual argument is item
(i.e., the first item after sorting/filtering) and we only use items
when there's some issue where the first-sorted item isn't the newest version (e.g., an older version may have a more recent pubDate
).
Sometimes appcasts contain empty elements/attributes and the `Item` values end up as an empty string because of how they're handled in `#items_from_content`. It's reasonable to expect that empty values would be `nil` instead, so this adds `#presence` calls to ensure this is the case.
We need to be able to replicate the `Sparkle` strategy's sorting and filtering behavior in a related cask audit, so this extracts the logic into reusable methods. This also stores `item.minimum_system_version` as a `MacOSVersion` object (instead of a string), so we can do proper version comparison (instead of naive string comparison) wherever needed.
The `#livecheck_min_os` cask audit method should be skipped when a `Sparkle` `livecheck` block contains a `strategy` block that uses the `items` argument (instead of `item`). These `strategy` blocks contain arbitrary logic that ignores/overrides the strategy's sorting, so we can't identify which item would be first/newest.
The `#livecheck_min_os` cask audit method manually replicates some of the `Sparkle` strategy's behavior but in an incomplete way that has lead to inappropriate audit failures at times. This reimplements it to use `Livecheck` methods, so it will align with the `Sparkle` strategy's behavior.
This change doesn't affect the behavior of the `#audit_min_os` method and simply reorders the array members to place `plist_min_os` before `sparkle_min_os` for the sake of consistency (using the same order as the preceding lines).
57cda29
to
75ce724
Compare
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.
Thanks @samford!
brew style
with your changes locally?brew typecheck
with your changes locally?brew tests
with your changes locally?The
#livecheck_min_os
cask audit is intended to use a Sparkle feed'sminimumSystemVersion
information to ensure that the cask has a correctdepends_on macos: ...
value. It reimplements some of the logic in livecheck'sSparkle
strategy but naively treats the firstitem
in the appcast as newest and doesn't adhere to theSparkle
strategy's sorting/filtering.Some appcasts are sorted from oldest to newest and some have
item
s with out-of-orderpubDate
values, so naively using the firstitem
in the audit has led to incorrect audit failures at times. As one example, this issue affected thehyperkey
cask until upstream updated the appcast to sort items from newest to oldest. This issue is also mitigated by #16013, as that PR introduced logic to check the minimum system version from cask artifact plist files in addition to the existinglivecheck
block audit.To be able to easily use the
Sparkle
strategy'sItem
sorting/filtering logic in the audit, I've refactored that code into#filter_items
and#sort_items
methods. As a side effect, this also means that the#items_from_content
method doesn't filter (or sort) items anymore, which may be useful in the future (e.g., if we ever need to add the ability to pass unfiltered/unsorted items to astrategy
block).That said, this PR reimplements
#livecheck_min_os
to useLivecheck::Strategy#page_content
to fetch the appcast content,#items_from_content
to parse the appcast, and the new#filter_items
and#sort_items
methods. This aligns the audit with theSparkle
strategy's behavior and resolves the aforementioned issue.If you wish to manually replicate this issue (for testing), you can edit the
hyperkey
cask to use an old snapshot of the appcast and theversion
/depends_on
values from the previously-mentioned cask PR:On the [brew]
master
branch, you will also need to setplist_min_os
tonil
in#audit_min_os
to ensure that only the#livecheck_min_os
value is used. This is the simplest way of replicating the behavior before #16013 introduced a mitigation.With those changes in place,
brew audit --cask --online --strict hyperkey
should fail withUpstream defined :sierra as the minimum OS version and the cask defined :high_sierra
(basically the same as the previoushyperkey
PR). [Fair warning, archive.org is being weird and you may need to use20230618095239
or20230618095239im_
in the URL to get the unmodified XML (despite both being incorrect).id_
is the correct way of fetching the unmodified file but the server alternates between returning it from only one of these URLs at a time (probably due to a caching bug 🤷).]After that, you can check out this PR branch (keeping the
plist_min_os = nil
change in place) and the samebrew audit
command should correctly pass.This PR also modifies
#items_from_content
to use aMacOSVersion
object as theItem.minimum_system_version
value instead of a string. This reduces boilerplate when making comparisons (e.g.,item.minimum_system_version >= :ventura
) inSparkle#filter_items
,strategy
blocks, and the#livecheck_min_os
audit method, by removing the need to replicate theMacOSVersion
error handling everywhere. I wanted to include this as part of #16158 but it was easier to do as part of the aforementioned refactoring.Somewhat related, I've also added
#presence
calls toItem
value assignments, to ensure that empty strings becomenil
. While debugging, I was surprised to find that someItem
values were an empty string instead ofnil
, so this ensures that the values are consistent/predictable.Lastly, this modifies
Cask::Audit#livecheck_min_os
to skiplivecheck
blocks with aSparkle
strategy
block using theitems
argument (instead ofitem
), as these ignore/override theSparkle
strategy's default sorting such that we can't predictably replicate the logic in the audit method.To be clear, we could execute the
strategy
block but it will only return version strings. The source of the version information varies betweenstrategy
blocks, so it's not really feasible to correlate versions toItem
objects to identify theminimumSystemVersion
of the newest version. However,#cask_plist_min_os
may take care of those instances, so it's not a total loss.