feat(binary): onPost hook — runs after install/update#153
Merged
Conversation
Adds a per-binary post-install/update hook: a shell command that runs
after a successful download, receiving B_EVENT (install|update),
B_NAME, B_VERSION, and B_FILE as env vars. Non-zero exit is surfaced
as a warning, not a fatal error. Skipped when the binary didn't
change.
b.yaml:
binaries:
github.com/arg-sh/argsh:
onPost: argsh builtin ${B_EVENT}
CLI:
b install --add github.com/arg-sh/argsh --on-post 'argsh builtin ${B_EVENT}'
Implementation:
- LocalBinary gains OnPost (yaml:"onPost") — round-trips via
BinaryList Marshal/Unmarshal.
- managedKey updated so SaveConfig preserves the field but can also
remove it when the user deletes it from config.
- RunHook helper in pkg/binary/hook.go — exec.Command with the four
B_ env vars set, runs in the project root directory.
- install.go / update.go call RunHook after a successful EnsureBinary
/ DownloadBinary, with event="install" or "update" respectively.
- --on-post flag on 'b install' feeds into addToConfig.
Tests:
- TestRunHook_{SetsEnvVars,EmptyIsNoOp,NonZeroExitReturnsError,RunsInDir}
- TestBinaryListMarshalYAML_OnPostRoundTrip
- TestAddToConfig_WithOnPost
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces a per-binary onPost hook that runs a user-provided shell command after binary install/update, and persists that hook via b.yaml/--add so it can be replayed on subsequent runs.
Changes:
- Add
onPostto the binary config model and YAML merge/round-trip behavior. - Execute
onPostafterb install/b updateoperations. - Add unit tests covering hook env vars + YAML/config persistence.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/state/yamlmerge.go | Treat binaries.<name>.onPost as a managed key when rewriting YAML. |
| pkg/state/types.go | Emit onPost during BinaryList.MarshalYAML. |
| pkg/state/types_test.go | Add YAML round-trip test for onPost. |
| pkg/cli/shared.go | Plumb OnPost from config into resolved binary.Binary. |
| pkg/cli/install.go | Add --on-post flag, persist it with --add, and run hook post-install. |
| pkg/cli/update.go | Run hook post-update. |
| pkg/cli/cli_extra_test.go | Test that --on-post persists to config via addToConfig. |
| pkg/binary/types.go | Add OnPost fields to Binary/LocalBinary types and document semantics. |
| pkg/binary/hook.go | Introduce RunHook helper that sets B_* env vars and executes a shell command. |
| pkg/binary/hook_test.go | Add tests for env vars, no-op behavior, non-zero exit, and working directory. |
Copilot review round 1: 1. RunHook signature changed from *os.File to io.Writer so callers can route through the CLI's IO streams (respecting --quiet, output capture). nil defaults to io.Discard. Added docstring noting hooks are POSIX-only (sh -c), consistent with existing env hooks. 2. install.go: track wasMissing before EnsureBinary(false) so the hook only fires when a download actually happened. Force mode always counts as downloaded. Streams routed through o.IO. 3. update.go: track 'downloaded' per branch — DownloadBinary branches set it on err==nil; EnsureBinary compares pre/post SHA to detect whether the file actually changed. Hook gated behind '!o.effectiveDryRun()' for --dry-run/--plan-json respect. Streams routed through o.IO. 4. Types.go docstring updated to match actual guarantees: only fires when on-disk binary changed, not on no-op skip or dry-run. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
macOS /var → /private/var symlink causes t.TempDir() to return the unresolved path while pwd in the hook resolves it. Use filepath.EvalSymlinks + strings.TrimSpace for the comparison. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. RunHook now filters existing B_EVENT/B_NAME/B_VERSION/B_FILE from os.Environ() before appending the new values, so platform-dependent duplicate-env-key precedence can't make the hook observe a stale value from the parent process. 2. addToConfig was persisting o.OnPost (the CLI flag) instead of b.OnPost (the per-binary value). Changed to b.OnPost for consistency with asset/version/alias which all read from the Binary struct. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Only compute pre/post SHA256 in the EnsureBinary branch when b.OnPost is non-empty and not dry-run — avoids O(file-size) hashing on every update for binaries without hooks. 2. Renamed local 'preSHA' → 'beforeHash' to avoid shadowing the outer preSHA map used by refreshLockDigests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. EnsureBinary branch now tracks wasMissing before hashing. If the binary was deleted from disk, the pre-SHA would fail and downloaded would stay false, silently skipping the hook. Now wasMissing=true sets downloaded=true after a successful EnsureBinary. 2. Tightened RunHook env-filter comment to say "the four hook-specific variables" not "any existing B_ vars". Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
If SHA256File fails before or after EnsureBinary (e.g. transient I/O error), assume the binary changed and run the hook. Better to run it unnecessarily than silently skip due to an unrelated file-read error. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…corruption Hook stdout was routed to o.IO.Out while the progress writer renders to the same stream concurrently. Any hook output would interleave with progress bars and corrupt the terminal display. Route both hook stdout and stderr to o.IO.ErrOut so hook output stays clean and separate from progress rendering. This is consistent with how hook warnings are already printed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fentas
added a commit
that referenced
this pull request
May 8, 2026
## Summary Documentation for the `onPost` per-binary hook feature (PR #153). ## Changes - **docs/b/subcommands/install.mdx** — new "Post-install hooks" section: `--on-post` flag, env vars table (`B_EVENT`, `B_NAME`, `B_VERSION`, `B_FILE`), `b.yaml` examples, and behaviour notes (POSIX-only, non-fatal, stderr output). Added `--on-post` to the flags table. - **docs/b/subcommands/update.mdx** — "Post-update hooks" section explaining that `onPost` also fires on update, with a cross-reference to the install docs. - **docs/getting-started.mdx** — `onPost` example in the config walkthrough. - **docs/glossary.mdx** — `onPost` term definition. - **README.md** — `--on-post` CLI example in the quick-use block + `onPost` in the config example section. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
fentas
pushed a commit
that referenced
this pull request
May 8, 2026
🤖 I have created a release *beep* *boop* --- ## [4.17.0](v4.16.0...v4.17.0) (2026-05-08) ### Features * **binary:** onPost hook — runs after install/update ([#153](#153)) ([8c03360](8c03360)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Per-binary post-install/update hook. A shell command that runs after a successful download, with context about what happened.
Usage
CLI:
b install --add github.com/arg-sh/argsh --on-post 'argsh builtin ${B_EVENT}'b.yaml:
Environment variables
The hook receives:
Behaviour
Use cases
Test plan
🤖 Generated with Claude Code