Skip to content

fix(install): render tera templates in tool postinstall hooks#8978

Merged
jdx merged 1 commit intomainfrom
fix/postinstall-tera-rendering
Apr 9, 2026
Merged

fix(install): render tera templates in tool postinstall hooks#8978
jdx merged 1 commit intomainfrom
fix/postinstall-tera-rendering

Conversation

@jdx
Copy link
Copy Markdown
Owner

@jdx jdx commented Apr 9, 2026

Summary

  • Tool-level postinstall scripts (e.g. [tools.ripgrep] postinstall) were passing the script directly to the shell without tera template rendering
  • Template variables like {{tools.ripgrep.path}} would fail silently as invalid shell syntax
  • Now renders through tera before execution, matching the behavior of project-level [hooks] postinstall

Fixes #8366

Test plan

  • Configure a tool with postinstall = "echo {{tools.ripgrep.path}}" and verify the path is rendered

🤖 Generated with Claude Code


Note

Low Risk
Low risk: this only changes how tool-level postinstall scripts are prepared (template rendering) before being passed to the shell, without altering installation/download logic.

Overview
Tool-level postinstall hooks are now rendered through Tera before execution, enabling template variables like {{tools.ripgrep.path}} to work in tool configuration.

run_postinstall_hook now builds a Tera context from the resolved toolset, renders the script with get_tera (scoped to the tool source directory), and executes the rendered result instead of the raw script.

Reviewed by Cursor Bugbot for commit 84fd7b8. Bugbot is set up for automated code reviews on this repo. Configure here.

Tool-level postinstall scripts (e.g. `[tools.ripgrep] postinstall`)
were passing the script directly to the shell without tera template
rendering, causing template variables like `{{tools.ripgrep.path}}`
to fail silently as invalid shell syntax.

Fixes #8366

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 9, 2026

Greptile Summary

This PR adds Tera template rendering to tool-level postinstall hooks (e.g. [tools.ripgrep] postinstall = "echo {{tools.ripgrep.path}}"), matching the behavior already present in project-level [hooks] postinstall. The fix is applied in run_postinstall_hook using the same get_tera + tera_ctx pattern used elsewhere in the codebase.

Confidence Score: 5/5

Safe to merge — the fix is correct for the primary use case and consistent with the existing hooks.rs pattern.

The single changed file applies a well-established pattern (get_tera + tera_ctx + render_str) that already exists for project-level hooks. The newly installed tool is guaranteed to appear in the tera context because its incomplete-file is removed before run_postinstall_hook is called. The one noted concern (OnceCell cache race under parallel installs) is an edge case that predates this PR and does not affect the stated fix; all remaining findings are P2.

No files require special attention.

Vulnerabilities

No security concerns identified. The rendered script is passed directly to the existing CmdLineRunner shell invocation, which already executed the raw script before this change — no new attack surface is introduced.

Important Files Changed

Filename Overview
src/backend/mod.rs Adds Tera context rendering before script execution in run_postinstall_hook; implementation is consistent with the hooks.rs pattern and correctly resolves the newly-installed tool because the incomplete-file is removed prior to this call.

Sequence Diagram

sequenceDiagram
    participant Install as install_version_
    participant PostHook as run_postinstall_hook
    participant TS as Toolset.tera_ctx (OnceCell)
    participant Tera as get_tera / render_str
    participant Shell as CmdLineRunner

    Install->>Install: remove incomplete_file_path
    Install->>PostHook: run_postinstall_hook(ctx, tv, script)
    PostHook->>PostHook: exec_env() → env_vars
    PostHook->>PostHook: list_bin_paths() → path_env
    PostHook->>TS: tera_ctx(&ctx.config)
    TS-->>PostHook: context with tools map (tool now installed)
    PostHook->>Tera: get_tera(source_dir)
    Tera-->>PostHook: tera instance
    PostHook->>Tera: render_str(script, tera_ctx)
    Tera-->>PostHook: rendered_script
    PostHook->>Shell: execute rendered_script
Loading

Fix All in Claude Code

Reviews (1): Last reviewed commit: "fix(install): render tera templates in t..." | Re-trigger Greptile

Comment thread src/backend/mod.rs
}

// Render tera template variables (e.g. {{tools.ripgrep.path}})
let tera_ctx = ctx.ts.tera_ctx(&ctx.config).await?;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Cached tera_ctx may omit concurrently-installing tools

tera_ctx is stored in a OnceCell on the shared Arc<Toolset>. When jobs > 1, tools are installed concurrently. The first tool to reach this line will compute and permanently cache the context; subsequent tools' postinstall hooks will reuse that snapshot. If Tool B's postinstall runs {{tools.B.path}} but Tool A's earlier postinstall already cached the context before B's incomplete-file was removed, B will be absent from tools and the template will silently produce an empty string or an error.

This only affects the (currently uncommon) case of multiple tools with postinstall hooks installed in the same parallel batch. For a single tool — the primary use-case here — the tool is guaranteed to be in the context because its incomplete-file is removed before this call.

Fix in Claude Code

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 integrates tera templating into the backend's script execution, enabling dynamic rendering of variables within scripts before they are run. A review comment highlights a potential edge case where the directory provided to get_tera might be None for non-path-based tools, suggesting that the get_tera function and the rendering context should be robustly designed to handle such scenarios.

Comment thread src/backend/mod.rs
Comment on lines 1147 to +1153
}

// Render tera template variables (e.g. {{tools.ripgrep.path}})
let tera_ctx = ctx.ts.tera_ctx(&ctx.config).await?;
let dir = tv.request.source().path().and_then(|p| p.parent());
let mut tera = get_tera(dir);
let rendered_script = tera.render_str(script, tera_ctx)?;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The get_tera function is called with dir which is derived from tv.request.source().path().and_then(|p| p.parent()). If tv.request.source().path() is None (e.g., for non-path based tools), dir will be None. This is acceptable, but it is better to ensure that get_tera handles None correctly and that the rendering context is robust against missing file system context.

@jdx jdx enabled auto-merge (squash) April 9, 2026 15:51
@jdx jdx merged commit 141e336 into main Apr 9, 2026
38 checks passed
@jdx jdx deleted the fix/postinstall-tera-rendering branch April 9, 2026 15:54
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 9, 2026

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.7 x -- echo 24.4 ± 0.3 23.7 27.7 1.00
mise x -- echo 25.1 ± 0.5 24.3 29.7 1.03 ± 0.02

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.7 env 23.6 ± 0.7 22.7 30.2 1.00
mise env 23.9 ± 0.6 23.2 31.2 1.01 ± 0.04

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.7 hook-env 24.9 ± 1.1 23.6 35.8 1.00
mise hook-env 25.4 ± 0.7 24.1 27.7 1.02 ± 0.05

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.7 ls 21.6 ± 0.6 20.7 24.2 1.00
mise ls 22.0 ± 0.8 21.3 30.5 1.01 ± 0.05

xtasks/test/perf

Command mise-2026.4.7 mise Variance
install (cached) 155ms 155ms +0%
ls (cached) 81ms 81ms +0%
bin-paths (cached) 85ms 85ms +0%
task-ls (cached) 815ms 797ms +2%

mise-en-dev added a commit that referenced this pull request Apr 10, 2026
### 🚀 Features

- **(config)** add lockfile_platforms setting to restrict lockfile
platforms by @cameronbrill in
[#8966](#8966)
- **(sandbox)** support wildcard patterns in allow_env by @jdx in
[#8974](#8974)
- bump usage-lib v2 → v3 to render examples in task --help by @baby-joel
in [#8890](#8890)

### 🐛 Bug Fixes

- **(activate)** handle empty __MISE_FLAGS array with set -u on bash 3.2
by @jdx in [#8988](#8988)
- **(env)** add trace logging for module hook PATH diagnostics by @jdx
in [#8981](#8981)
- **(go)** Query module proxy directly for version resolution by @c22 in
[#8968](#8968)
- **(install)** render tera templates in tool postinstall hooks by @jdx
in [#8978](#8978)
- **(install)** add missing env vars to tool postinstall hooks by @jdx
in [#8977](#8977)
- **(task)** prevent hang when skipped task has dependents by @jdx in
[#8937](#8937)
- **(task)** invalidate dependent task sources when dependency runs by
@jdx in [#8975](#8975)
- **(task)** prevent deadlock when MISE_JOBS=1 with sub-task references
by @jdx in [#8976](#8976)
- **(task)** fetch remote task files before parsing usage specs by @jdx
in [#8979](#8979)
- **(task)** prevent panic when running parallel sub-tasks with
replacing output by @jdx in
[#8986](#8986)
- **(upgrade)** update lockfile and config when upgrading to specific
version by @jdx in [#8983](#8983)

### 📚 Documentation

- **(node)** remove "recommended for teams" from pin example by @jdx in
[b334363](b334363)

### 📦️ Dependency Updates

- update ghcr.io/jdx/mise:alpine docker digest to 17a29f2 by
@renovate[bot] in [#8995](#8995)
- update docker/dockerfile:1 docker digest to 2780b5c by @renovate[bot]
in [#8994](#8994)

### New Contributors

- @baby-joel made their first contribution in
[#8890](#8890)
- @cameronbrill made their first contribution in
[#8966](#8966)
- @c22 made their first contribution in
[#8968](#8968)
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.

1 participant