Type cask artifact options instead of **options - #24095
Conversation
There was a problem hiding this comment.
Copilot review overview
馃數 Needs a closer look
command_wrapper should default only nil options, so false receives the intended validation error.
Review effort: Lite
Findings: None
What changed in this PR
This PR replaces untyped cask artifact options with explicit typed keywords and strengthens stanza validation.
Changes:
- Types install, uninstall, and zap phase interfaces.
- Validates artifact, installer, and command-wrapper arguments.
- Adds regression tests for invalid arguments.
| File | Summary |
|---|---|
Library/鈥婬omebrew/鈥媡est/鈥媍ask/鈥媋rtifact/鈥媔nstaller_spec.rb |
Tests invalid installer arguments |
Library/鈥婬omebrew/鈥媡est/鈥媍ask/鈥媋rtifact/鈥媑eneric_artifact_spec.rb |
Tests unknown artifact keys |
Library/鈥婬omebrew/鈥媡est/鈥媍ask/鈥媋rtifact/鈥媍ommand_wrapper_spec.rb |
Tests invalid wrapper options |
Library/鈥婬omebrew/鈥媍md/鈥媢nlink.rb |
Passes explicit uninstall options |
Library/鈥婬omebrew/鈥媍md/鈥媗ink.rb |
Passes explicit install options |
Library/鈥婬omebrew/鈥媍ask/鈥媔nstaller.rb |
Forwards typed artifact options |
Library/鈥婬omebrew/鈥媍ask/鈥媋rtifact/鈥媧ap.rb |
Types zap options |
Library/鈥婬omebrew/鈥媍ask/鈥媋rtifact/鈥媢ninstall.rb |
Types uninstall options |
Library/鈥婬omebrew/鈥媍ask/鈥媋rtifact/鈥媠ymlinked.rb |
Types linking phases |
Library/鈥婬omebrew/鈥媍ask/鈥媋rtifact/鈥媟elocated.rb |
Validates relocation options |
Library/鈥婬omebrew/鈥媍ask/鈥媋rtifact/鈥媞lplugin.rb |
Types Quick Look phases |
Library/鈥婬omebrew/鈥媍ask/鈥媋rtifact/鈥媝kg.rb |
Types package options |
Library/鈥婬omebrew/鈥媍ask/鈥媋rtifact/鈥媘dimporter.rb |
Types importer installation |
Library/鈥婬omebrew/鈥媍ask/鈥媋rtifact/鈥媔nstaller.rb |
Validates installer arguments |
Library/鈥婬omebrew/鈥媍ask/鈥媋rtifact/鈥媔nstall_steps.rb |
Types install-step phases |
Library/鈥婬omebrew/鈥媍ask/鈥媋rtifact/鈥媑enerated_script.rb |
Validates generated script options |
Library/鈥婬omebrew/鈥媍ask/鈥媋rtifact/鈥媑enerated_completion.rb |
Types completion phases |
Library/鈥婬omebrew/鈥媍ask/鈥媋rtifact/鈥媍ommand_wrapper.rb |
Validates wrapper options |
Library/鈥婬omebrew/鈥媍ask/鈥媋rtifact/鈥媌inary.rb |
Types binary linking |
Library/鈥婬omebrew/鈥媍ask/鈥媋rtifact/鈥媋rtifact.rb |
Validates generic artifact options |
Library/鈥婬omebrew/鈥媍ask/鈥媋rtifact/鈥媋bstract_uninstall.rb |
Types uninstall dispatch |
Library/鈥婬omebrew/鈥媍ask/鈥媋rtifact/鈥媋bstract_flight_block.rb |
Types flight block phases |
馃挕 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
- The artifact phase methods took `**options` so that the single `Cask::Installer` call site could pass keywords each artifact ignores. A keyword mistyped there was absorbed by every artifact that splatted, so only the typed `Moved` subclasses caught it. - List the caller's keywords on each `install_phase`, `uninstall_phase`, `post_uninstall_phase` and `zap_phase`, including the ones an artifact does not read: `Library/.rubocop.yml` sets `AllowUnusedKeywordArguments`. - Keep `command` required on the `uninstall` and `zap` phases, which reached it through the splat, so omitting it still raises rather than running the privileged deletions with the default. - Type and forward `dispatch_uninstall_directive`'s keywords. It passed on `verbose` and `skip`, which no `uninstall_*` handler reads, so the handlers keep the `**_kwargs` that `send` dispatches into. - Drop the `options` hashes in `brew link` and `brew unlink` and the conditional `uninstall_options[:quit]`, without which the new signatures are unchecked at those call sites. - Keep `**` where a cask stanza is validated, so that `assert_valid_keys` still names an unknown key, but type its values as `DirectivesType` rather than `T.untyped`. - `Relocated#initialize` passes a target to `super` only when it has one, keeping `to_args` and so the JSON API free of `target: nil`. - `Artifact.from_args` validates and then calls `super` rather than `new`, so the generic `artifact` stanza rejects an unknown key as every other `Relocated` stanza already did. No `artifact` stanza in `homebrew/cask` passes one. - An `installer manual:` that is not a path, and a `command_wrapper` given something other than a hash, now name the stanza argument at fault instead of failing later with `Pathname.new requires a String` or `undefined method 'each_key'`. - An explicit `pkg` `choices: nil` no longer crashes on `nil.empty?`. Any other non-collection value still reaches `installer`, which rejects it as before.
4aa888d to
4e5152d
Compare
|
Copilot's overview note on |
MikeMcQuaid
left a comment
There was a problem hiding this comment.
Thanks, nice work! Should be good to go when 馃煝 and a rebase will fix you up (I'll do that for you now).
In general when we fix all these **options uses a RuboCop to prevent them in future would be great 鉂わ笍
**optionsin cask artifact phase methods and their callers with explicit keywords sobrew typecheckcatches mistyped options.commandrequired foruninstallandzap.DirectivesTypesoassert_valid_keysstill names unknown keys.artifactkeys like other relocated stanzas and explain invalidinstaller manual:andcommand_wrapperarguments.brew benchmarkresults.brewcommands to reproduce the bug?brew lgtm(style, typechecking and tests) locally?Claude Code with Opus 5, with local review and testing.