Skip to content

feat(config): add run field for hooks#9718

Merged
jdx merged 12 commits into
jdx:mainfrom
risu729:feat/hooks-run-field
May 10, 2026
Merged

feat(config): add run field for hooks#9718
jdx merged 12 commits into
jdx:mainfrom
risu729:feat/hooks-run-field

Conversation

@risu729
Copy link
Copy Markdown
Contributor

@risu729 risu729 commented May 8, 2026

Summary

  • Add { run = "..." } as the explicit inline-command hook form for all hook types.
  • Keep string hook values as run shorthand, so existing enter = "echo hi" behavior is unchanged and remains documented.
  • Allow { run = "...", shell = "bash -c" } to choose the inline shell command, matching task shell semantics.
  • Keep script + shell as the current-shell form for enter, leave, and cd hooks; here shell is a shell-name selector such as bash, not an inline shell command.
  • Align install-hook compatibility with fix(hooks): align hook run syntax with tasks #9604: preinstall/postinstall hooks using script still run as legacy inline commands, and script + shell warns that shell is ignored instead of silently skipping the hook.
  • Update hook docs, JSON schema wording, and e2e coverage.

Split From #9604

This PR is the smaller first slice of #9604. It only introduces the scalar run hook field and the compatibility behavior needed for existing script hooks.

Intentionally left for #9604 after this merges:

  • task-style hook run entries such as { task = "setup", args = [...] } and { tasks = [...] }
  • run = [...] arrays where each entry follows task run semantics
  • run_windows
  • script = [...] current-shell hook arrays
  • task executor integration for hook run entries

Fixes Discussion #9636

This also fixes the behavior reported in #9636, which is linked from #9604: postinstall = { script = "...", shell = "bash" } used to skip silently because install hooks do not have an active current shell.

With this PR, install hooks that use script + shell warn that shell is ignored and still run the script through the default inline shell. Users who want to choose the shell for an install hook should use run with an inline shell command:

[hooks]
postinstall = { run = "echo bash:$BASH_VERSION", shell = "bash -c" }

Behavior Examples

String shorthand remains valid and is equivalent to a scalar run hook:

[hooks]
enter = "echo entering"
postinstall = "echo installed"

The explicit scalar form is useful when adding shell:

[hooks]
enter = { run = "echo entering" }
preinstall = { run = "echo installing" }

run.shell uses the same shape as task shell: it replaces the default inline shell command and should include the command plus inline-eval argument, such as bash -c, zsh -c, or pwsh -Command. Without shell, run uses unix_default_inline_shell_args or windows_default_inline_shell_args.

Current-shell hooks still use script + shell and only apply to activation hooks:

[hooks.enter]
shell = "bash"
script = "source completions.sh"

For current-shell hooks, shell selects the active mise activate shell name. It is not the command used to spawn a subprocess.

Tests

  • cargo fmt --all --check
  • CARGO_BUILD_JOBS=1 cargo check -q
  • jq empty schema/mise.json
  • shellcheck -x e2e/config/test_hooks_run_warnings
  • shfmt -d --apply-ignore e2e/config/test_hooks_run_warnings
  • git diff --check
  • CARGO_BUILD_JOBS=1 mise run test:e2e e2e/config/test_hooks e2e/config/test_hooks_task_ref e2e/config/test_hooks_run_warnings
  • CARGO_BUILD_JOBS=1 mise run test:e2e e2e/config/test_hooks_run_warnings

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new { run = "..." } syntax for hooks to explicitly define subprocess execution, separating it from shell-based scripts. The changes include updates to documentation, end-to-end tests, and the JSON schema, along with Rust implementation changes that add deprecation warnings for ambiguous or unsupported hook configurations. Feedback suggests refactoring the JSON schema to utilize $defs and $ref for hook definitions to improve maintainability and reduce redundancy.

Comment thread schema/mise.json
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 8, 2026

Greptile Summary

This PR introduces an explicit run field for all hook types (and an optional shell to choose the inline shell command), while preserving string shorthand and current-shell script + shell semantics for enter/leave/cd hooks. It also fixes the #9636 regression where preinstall/postinstall hooks with script + shell silently skipped instead of running with a warning.

  • The flat script/shell/task_name fields on Hook are replaced with a typed HookAction enum (Run, CurrentShell, Task), cleanly separating subprocess, current-shell, and task-reference paths.
  • ScriptTable without a shell selector now routes through Run { legacy_script: true } and will emit a deprecation warning once mise 2026.9.0 ships.
  • The new e2e test test_hooks_run_warnings covers the script-on-install-hooks warning path, but has no assertion for the upcoming hook_script_table_spawned_run deprecation key.

Confidence Score: 5/5

Safe to merge — all hook paths are well-covered, backward compatibility is preserved, and the one latent test gap has no impact on runtime correctness today.

The HookAction enum refactor is clean and all hook routing paths correctly preserve backward compatibility. The regression fix for install hooks with script + shell is correct. No data-loss or incorrect-behavior paths were found.

e2e/config/test_hooks_run_warnings — the { script = 'echo PRE_SCRIPT' } entry carries legacy_script: true and will produce a deprecated [hook_script_table_spawned_run] message once 2026.9.0 ships; no assertion currently covers that output.

Important Files Changed

Filename Overview
src/hooks.rs Core hook engine refactored: flat script/shell/task_name fields replaced with typed HookAction enum (Run, CurrentShell, Task); new run hook variant added; matches_shell helper extracted; deprecation path for legacy script tables wired in.
src/config/config_file/mise_toml.rs Template rendering for hooks delegated to the new Hook::render_templates method, removing the previous field-by-field pattern.
schema/mise.json New run+shell object shape added to both scalar and array hook positions; required: [script] added to the script object shape; descriptions updated to distinguish current-shell vs inline semantics.
e2e/config/test_hooks_run_warnings New e2e test covering run/script warning paths; uses { script = 'echo PRE_SCRIPT' } which carries legacy_script: true and will emit a deprecation message once mise >= 2026.9.0 ships — the test has no assertion covering the new deprecation key hook_script_table_spawned_run.
docs/hooks.md Documentation updated to describe the run/shell inline hook form, clarify current-shell vs subprocess semantics, note the script deprecation path, and fix a typo in the multi-hook example.

Reviews (9): Last reviewed commit: "Merge branch 'main' into feat/hooks-run-..." | Re-trigger Greptile

Comment thread src/hooks.rs Outdated
@risu729

This comment was marked as outdated.

@risu729 risu729 marked this pull request as ready for review May 8, 2026 14:25
@risu729 risu729 marked this pull request as draft May 8, 2026 14:25
Comment thread e2e/config/test_hooks_run_warnings
@risu729

This comment was marked as outdated.

@risu729

This comment was marked as outdated.

Clarified deprecation notice for the 'script' alias in install hooks.
@risu729 risu729 marked this pull request as ready for review May 9, 2026 18:05
@jdx jdx merged commit c7f9de0 into jdx:main May 10, 2026
34 checks passed
@risu729 risu729 deleted the feat/hooks-run-field branch May 10, 2026 13:32
mise-en-dev added a commit that referenced this pull request May 11, 2026
### 🚀 Features

- **(cli)** add minimum release age flag to lock and ls-remote by
@risu729 in [#9269](#9269)
- **(config)** add run field for hooks by @risu729 in
[#9718](#9718)
- **(github)** add native oauth token source by @jdx in
[#9654](#9654)
- **(oci)** scope build to project config by default by @jdx in
[#9766](#9766)
- add support for prefixed latest version queries in outdated checks by
@roele in [#9767](#9767)

### 🐛 Bug Fixes

- **(activate)** guard bash chpwd hook under nounset by @risu729 in
[#9716](#9716)
- **(backend)** date-check latest stable fast path by @risu729 in
[#9650](#9650)
- **(config)** parse core tool options consistently by @risu729 in
[#9742](#9742)
- **(exec)** propagate __MISE_DIFF so nested mise recovers pristine PATH
by @jdx in [#9765](#9765)
- **(forgejo)** include prereleases when opted in by @risu729 in
[#9717](#9717)
- **(github)** avoid caching empty release assets by @risu729 in
[#9616](#9616)
- **(java)** resolve lockfile URLs from metadata by @risu729 in
[#9719](#9719)
- **(lock)** cache unavailable github attestations by @risu729 in
[#9741](#9741)
- **(pipx)** preserve options when reinstalling tools by @risu729 in
[#9663](#9663)
- **(python)** skip redundant lockfile provenance verification by
@risu729 in [#9739](#9739)
- **(vfox)** run pre_uninstall hook by @risu729 in
[#9662](#9662)

### 🚜 Refactor

- **(schema)** extract tool options definition by @risu729 in
[#9649](#9649)

### ⚡ Performance

- **(aqua)** bake rkyv aqua package blobs by @risu729 in
[#9535](#9535)

### 📦️ Dependency Updates

- lock file maintenance by @renovate[bot] in
[#9773](#9773)

### 📦 Registry

- add vector
([github:vectordotdev/vector](https://github.com/vectordotdev/vector))
by @kquinsland in [#9761](#9761)
- add oc and openshift-install (http backend) by @konono in
[#9669](#9669)

### New Contributors

- @konono made their first contribution in
[#9669](#9669)
- @kquinsland made their first contribution in
[#9761](#9761)
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.

2 participants