The `eol_data` method uses `@eol_data["#{product}/#{cycle}"] ||=`,
which can unncessarily allow a duplicate API call if the same
product/cycle combination was previously tried but returned a 404
(Not Found) response. In this scenario, the value would be `nil` but
the existing logic doesn't check whether this is a missing key or a
`nil` value. If the key is present, we shouldn't make the same
request again.
This updates the method to return the existing value if the key
exists, which effectively prevents duplicate fetches. This new logic
only modifies `@eol_data` if `curl` is successful, so it does allow
the request to be made again if it failed before.
That said, this shouldn't normally be an issue and this is mostly
about refactoring the method to allow for nicer code organization.
This approach reduces the `begin` block to only the `JSON.parse` call,
which allows us to use `return unless result.status.success?` (this
previously led to a RuboCop offense because it was called within a
`begin` block).
The endoflife.date API has been updated, so this modifies the URL in
`SharedAudits.eol_data` to use the up to date URL and modifies the
related logic in `FormulaAuditor.audit_eol` to work with the new
response format. Specifically, there is now an `isEol` boolean value
and the EOL date is found in `eolFrom`.
One wrinkle of the new setup is that 404 responses now return HTML
content even if the request includes an `Accept: application/json`
header. This handles these types of responses by catching
`JSON::ParserError` but ideally we would parse the response headers
and use `Utils::Curl.http_status_ok?` to check for a good response
status before trying to parse the response body as JSON.
This upgrades `utils/curl.rb` to `typed: strict`, which requires
a number of changes to pass `brew typecheck`. The most
straightforward are adding type signatures to methods, adding type
annotations (e.g., `T.let`) to variables that need them, and ensuring
that methods always use the expected return type.
I had to refactor areas where we call a `Utils::Curl` method and use
array destructuring on a `SystemCommand::Result` return value
(e.g., `output, errors, status = curl_output(...)`), as Sorbet
doesn't understand implicit array conversion. As suggested by Markus,
I've switched these areas to use `#stdout`, `#stderr`, and `#status`.
This requires the use of an intermediate variable (`result`) in some
cases but this was a fairly straightforward substitution.
I also had to refactor how `Cask::URL::BlockDSL::PageWithURL` works.
It currently uses `page.extend PageWithURL` to add a `url` attribute
but this reworks it to subclass `SimpleDelegator` and use an
`initialize` method instead. This achieves the same goal but in a way
that Sorbet can understand.