From 4b097e85b0d5b83212596bd934f4e2ad70028631 Mon Sep 17 00:00:00 2001 From: Ryan Lewis Date: Sat, 30 May 2026 15:47:45 +0100 Subject: [PATCH] feat(release): ship shell completions in the cask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR 2 of #88. Wire generate_completions_from_executable into the Homebrew cask so `brew install` runs `things completions ` (PR 1) and drops completion scripts into the Homebrew prefix — zero post-install steps. Move the quarantine-removal hook from postflight to preflight: completion generation runs the binary during artifact install, which is *before* postflight, so the unsigned binary must be de-quarantined first or Gatekeeper blocks it and no completion files get written. Preflight runs before artifact install, so the same xattr removal there also keeps runtime `things` working. Flip the README / SKILL.md wording now that Homebrew generates completions. Verified: `goreleaser check` passes, and `goreleaser release --snapshot --clean --skip=publish` emits Casks/things.rb with the generate_completions_from_executable block (shell_parameter_format: :arg, shells [bash zsh fish]) and a preflight de-quarantine. Part of #88 --- .goreleaser.yaml | 14 +++++++++++++- README.md | 10 +++++----- internal/skill/SKILL.md | 2 +- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 5189605..956888e 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -55,6 +55,14 @@ homebrew_casks: - name: things binaries: - things + # Run `things completions ` at cask install time to drop bash/zsh/fish + # completion scripts into the Homebrew prefix. `` is a positional arg + # (shell_parameter_format: arg) — matches the CLI added in #88 PR 1. + generate_completions_from_executable: + args: [completions] + base_name: things + shell_parameter_format: arg + shells: [bash, zsh, fish] repository: owner: ryanlewis name: homebrew-tap @@ -69,8 +77,12 @@ homebrew_casks: name: goreleaserbot email: bot@goreleaser.com commit_msg_template: "chore(brew): {{ .ProjectName }} {{ .Tag }}" + # De-quarantine in preflight (before artifact install) rather than postflight, + # so the binary is runnable when generate_completions_from_executable invokes + # it during install — otherwise Gatekeeper blocks the unsigned binary and no + # completion files are written. hooks: - post: + pre: install: | if OS.mac? system_command "/usr/bin/xattr", args: ["-dr", "com.apple.quarantine", "#{staged_path}/things"] diff --git a/README.md b/README.md index 720c0db..69a05b7 100644 --- a/README.md +++ b/README.md @@ -355,11 +355,11 @@ goes stale as the command surface changes — `things ` completes subcommands and flag names, and a flag's values complete once you've typed it (`things list --color ` → `auto`, `always`, `never`). -The Homebrew cask installs the binary but doesn't generate completions yet — -that's a planned follow-up. Until it lands, and on every install path, load the -script yourself. Completion shells out to `things` by name, so it works as long -as `things` is on your `PATH` (the Homebrew, `go install`, and `make install` -paths all put it there): +The Homebrew cask generates these on install, so cask users get `things ` +with no extra steps. On every other install path, load the script yourself. +Completion shells out to `things` by name, so it works as long as `things` is on +your `PATH` (the Homebrew, `go install`, and `make install` paths all put it +there): ```sh # bash — add to ~/.bashrc (complete -C is a bash builtin; no extra package needed) diff --git a/internal/skill/SKILL.md b/internal/skill/SKILL.md index d139aa1..2eaed88 100644 --- a/internal/skill/SKILL.md +++ b/internal/skill/SKILL.md @@ -117,7 +117,7 @@ things --json list today | jq '.[] | .title' ## Shell completions -`things completions ` prints a completion script for that shell. It delegates back to the binary (which must be on `PATH`), so it stays in sync with the CLI surface. The Homebrew cask installs the binary but doesn't generate completions yet (a planned follow-up); for now the user loads it with `source <(things completions zsh)` (bash/zsh) or `things completions fish | source`. Completion is flag/subcommand-name only — it never reads the Things database. +`things completions ` prints a completion script for that shell. It delegates back to the binary (which must be on `PATH`), so it stays in sync with the CLI surface. The Homebrew cask generates these on install; on other install paths the user loads it with `source <(things completions zsh)` (bash/zsh) or `things completions fish | source`. Completion is flag/subcommand-name only — it never reads the Things database. ## Tips