Skip to content

cask: add generate_completions_from_executable DSL artifact#21781

Merged
MikeMcQuaid merged 6 commits intoHomebrew:mainfrom
mvanhorn:osc/21482-feat-cask-shell-completions
Mar 22, 2026
Merged

cask: add generate_completions_from_executable DSL artifact#21781
MikeMcQuaid merged 6 commits intoHomebrew:mainfrom
mvanhorn:osc/21482-feat-cask-shell-completions

Conversation

@mvanhorn
Copy link
Copy Markdown
Contributor

  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same change?
  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes? Here's an example.
  • Have you successfully run brew lgtm (style, typechecking and tests) with your changes locally?

  • AI was used to generate or assist with generating this PR.

This contribution was developed with AI assistance (Claude Code + Codex).


Implements a generate_completions_from_executable DSL stanza for Casks as an artifact, per the direction discussed in #21482.

Casks already support bash_completion, zsh_completion, and fish_completion stanzas for symlinking pre-existing completion files. This PR adds the ability to run an executable at install time to generate completion scripts, matching the existing Formula DSL method.

This is the artifact/DSL approach that @SMillerDev requested - not the postflight approach from #21671.

Changes

  • New Cask::Artifact::GeneratedCompletion class that:
    • Runs the specified executable during install_phase to generate completions
    • Removes generated files during uninstall_phase
    • Supports the same shell_parameter_format options as Formula (:arg, :clap, :click, :cobra, :flag, :none, :typer, and custom prefix strings)
    • Handles generation failures gracefully (warns, does not fail the install)
  • Registered as an ordinary artifact in the DSL
  • RSpec tests covering install, uninstall, shell filtering, and error handling

Usage

cask "example" do
  # ...
  generate_completions_from_executable "bin/foo", "completions"

  # With options:
  generate_completions_from_executable "bin/foo", "completions",
                                       shells: [:bash, :zsh],
                                       shell_parameter_format: :cobra,
                                       base_name: "foo"
end

Fixes #21482.

Adds a new `generate_completions_from_executable` stanza for Casks that
runs an executable at install time to generate shell completion scripts,
mirroring the existing Formula DSL method.

The new `GeneratedCompletion` artifact class supports the same
shell_parameter_format options as Formula (arg, clap, click, cobra,
flag, none, typer, and custom prefix strings).

Fixes Homebrew#21482.

This contribution was developed with AI assistance (Claude Code + Codex).
Copy link
Copy Markdown
Member

@SMillerDev SMillerDev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this! A few comments to make it easier to maintain.

Copy link
Copy Markdown
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Looks good so far. Agreed with @SMillerDev that this should be sharing a lot more code with the similar formula implementation.

Move completion_shell_parameter and default_completion_shells into a
shared Utils::ShellCompletion module used by both Formula and
Cask::Artifact::GeneratedCompletion, eliminating the duplication.
@mvanhorn
Copy link
Copy Markdown
Contributor Author

Extracted completion_shell_parameter and default_completion_shells into a shared Utils::ShellCompletion module in 130008c. Both Formula#generate_completions_from_executable and Cask::Artifact::GeneratedCompletion now call the same implementation.

completion_script_path stays local to each consumer since Formula and Cask resolve base directories differently (prefix/... vs config.bash_completion), but the shell parameter format logic and default shells are now in one place.

Typecheck, style, and tests all pass locally.

The cask installer's install_phase and uninstall_phase methods use
T.cast with an explicit union of artifact types. GeneratedCompletion
was missing, causing a runtime T.cast error during cask installation.
@mvanhorn
Copy link
Copy Markdown
Contributor Author

Also fixed a bug in cask/installer.rb in 4017d33 - GeneratedCompletion was missing from the T.cast union types in both install_phase and uninstall_phase. Without this, brew install --cask crashes at runtime with a T.cast error when the cask uses generate_completions_from_executable. The existing RSpec tests don't catch this because they call artifact.install_phase directly, bypassing the installer's artifact dispatch loop.

mvanhorn and others added 2 commits March 21, 2026 12:06
Move the shared popen_read invocation pattern from both
Formula#generate_completions_from_executable and
Cask::Artifact::GeneratedCompletion#install_phase into a single
Utils::ShellCompletion.generate_completion_output method.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n artifacts

Replace inline path computation in completion_script_path with calls to
BashCompletion, ZshCompletion, and FishCompletion resolve_target, reusing
the path logic already defined in the cask artifact hierarchy.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me so far! Would be good to have some utils/shell_completion specs too.

@MikeMcQuaid MikeMcQuaid requested a review from SMillerDev March 22, 2026 14:05
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@mvanhorn
Copy link
Copy Markdown
Contributor Author

Added Utils::ShellCompletion specs in 7276dd4 - covers default_completion_shells, completion_shell_parameter (all format variants including cobra, clap, click, typer, flag, arg, none, custom string, and pwsh mapping), and generate_completion_output (argument flattening, nil handling).

@MikeMcQuaid MikeMcQuaid enabled auto-merge March 22, 2026 16:09
@MikeMcQuaid
Copy link
Copy Markdown
Member

Thanks @mvanhorn!

@MikeMcQuaid MikeMcQuaid added this pull request to the merge queue Mar 22, 2026
Merged via the queue into Homebrew:main with commit e837d42 Mar 22, 2026
54 of 56 checks passed
@mvanhorn
Copy link
Copy Markdown
Contributor Author

Thanks for the reviews and merge, @MikeMcQuaid and @SMillerDev! The back-and-forth on extracting Utils::ShellCompletion made the final result way cleaner than my first pass.

@caarlos0
Copy link
Copy Markdown

This is amazing! Thanks, everyone!

PS: do we need to update this? https://docs.brew.sh/Cask-Cookbook

@SMillerDev
Copy link
Copy Markdown
Member

Yeah, an adjustment to the docs would be nice. @mvanhorn are you up for that? I don't want to steal your thunder for that one.

caarlos0 added a commit to goreleaser/goreleaser that referenced this pull request Mar 25, 2026
Implements the generate_completions_from_executable DSL stanza for
Homebrew Casks, mirroring the support added to Homebrew in
Homebrew/brew#21781 (merged 2026-03-22).

Config:
  generate_completions_from_executable:
    executable: "bin/myapp"
    args: ["completions"]
    base_name: "myapp"
    shell_parameter_format: cobra  # arg|clap|click|cobra|flag|none|typer or custom string
    shells: [bash, zsh, fish, pwsh]

Generated Ruby output:
  generate_completions_from_executable "bin/myapp", "completions",
      base_name: "myapp",
      shell_parameter_format: :cobra,
      shells: [:bash, :zsh, :fish, :pwsh]

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
caarlos0 added a commit to goreleaser/goreleaser that referenced this pull request Mar 25, 2026
Implements the generate_completions_from_executable DSL stanza for
Homebrew Casks, mirroring the support added to Homebrew in
Homebrew/brew#21781 (merged 2026-03-22).

Config:
  generate_completions_from_executable:
    executable: "bin/myapp"   # optional, defaults to first binary
    args: ["completions"]
    base_name: "myapp"
    shell_parameter_format: cobra  # arg|clap|click|cobra|flag|none|typer or custom string
    shells: [bash, zsh, fish, pwsh]

Generated Ruby output:
  generate_completions_from_executable "bin/myapp", "completions",
      base_name: "myapp",
      shell_parameter_format: :cobra,
      shells: [:bash, :zsh, :fish, :pwsh]

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
caarlos0 added a commit to goreleaser/goreleaser that referenced this pull request Mar 25, 2026
Implements the generate_completions_from_executable DSL stanza for
Homebrew Casks, mirroring the support added to Homebrew in
Homebrew/brew#21781 (merged 2026-03-22).

Config:
  generate_completions_from_executable:
    executable: "bin/myapp"   # optional, defaults to first binary
    args: ["completions"]
    base_name: "myapp"
    shell_parameter_format: cobra  # arg|clap|click|cobra|flag|none|typer or custom string
    shells: [bash, zsh, fish, pwsh]

Generated Ruby output:
  generate_completions_from_executable "bin/myapp", "completions",
      base_name: "myapp",
      shell_parameter_format: :cobra,
      shells: [:bash, :zsh, :fish, :pwsh]

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
caarlos0 added a commit to goreleaser/goreleaser that referenced this pull request Mar 25, 2026
…6485)

Implements the generate_completions_from_executable DSL stanza for
Homebrew Casks, mirroring the support added to Homebrew in
Homebrew/brew#21781 (merged 2026-03-22).

Config:

```yaml
  generate_completions_from_executable:
    executable: "bin/myapp"   # optional, defaults to first binary
    args: ["completions"]
    base_name: "myapp"
    shell_parameter_format: cobra  # arg|clap|click|cobra|flag|none|typer or custom string
    shells: [bash, zsh, fish, pwsh]
```

Generated Ruby output:
```ruby
  generate_completions_from_executable "bin/myapp", "completions",
      base_name: "myapp",
      shell_parameter_format: :cobra,
      shells: [:bash, :zsh, :fish, :pwsh]
```

---------

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Casks cannot generate shell completions like formulae

4 participants