Just realized that
[`cargo-binstall`](https://github.com/cargo-bins/cargo-binstall) also
installs things into `~/.cargo/bin`, so there’s no (easy) way to tell
whether something was installed with `cargo install` or `cargo
binstall`.
Partially reverts #1540
Detects how prek was installed (Homebrew or Cargo) by inspecting the
executable path, then provides actionable upgrade hints when:
- `prek self update` fails because prek wasn't installed via standalone
scripts
- `minimum_prek_version` isn't satisfied
Based largely on the approach uv implemented in
[astral-sh/uv#16838](https://github.com/astral-sh/uv/pull/16838).
Detection heuristics:
- Homebrew: path contains `/Cellar/prek/`
- Cargo: path contains `/.cargo/bin/`
Example output:
```console
error: prek was installed via an external package manager and cannot self-update.
hint: You installed prek via Homebrew. To update, run brew update && brew upgrade prek
```
See discussion in #1490 for further context.
---------
Co-authored-by: Jo <10510431+j178@users.noreply.github.com>
- Remove `todo.md` as remaining items have been addressed or documented
elsewhere.
- Move note to `diff.md` that `pre-commit hazmat` subcommand (v4.5.0) is
not implemented.
## Summary
PR #1488 removed symlinks from `bin_dir` but only updated `run()` to
prepend the toolchain directory to PATH. The `install()` functions still
only prepended `bin_dir`, causing `npm install` to fail when no system
node is available in PATH.
## MRE
With `.pre-commit-config.yaml`:
```yaml
repos:
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.1.0
hooks:
- id: prettier
language_version: "24.13.0"
```
When no system node is in PATH (can be simulated with
`PATH=/usr/bin:/bin`, running:
```bash
prek run --all-files
```
Fails with
```
error: Failed to install hook `prettier`
caused by: Command `npm install` exited with an error:
env: node: No such file or directory
```
With system node in PATH, `npm install` "works" but uses wrong node
version (system instead of requested).
## Fix
Mirror the `run()` PATH setup in `install()` by including the
toolchain's parent directory:
```rust
let node_bin = node.node().parent().expect("Node binary must have parent");
let new_path = prepend_paths(&[&bin_dir, node_bin])?;
```
Note: Bun fix is for consistency/edge cases (bun is a native binary, not
a shebang script like npm).
---------
Co-authored-by: Jo <10510431+j178@users.noreply.github.com>
## Summary
Previously, `prek install` would silently fall back to default hook
types when the config file existed but contained errors (e.g., invalid
YAML or missing required fields). This made it hard to notice
configuration mistakes.
Now it shows a warning with the specific error:
```
$ prek install
warning: Failed to parse `.pre-commit-config.yaml`: Invalid remote repo: missing field `rev`
prek installed at `.git/hooks/pre-commit`
```
## Test plan
- [x] Added `install_invalid_config_warning` test
- [x] All existing install tests pass
🤖 Generated with [Claude Code](https://claude.ai/code)
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Jo <10510431+j178@users.noreply.github.com>
Closes#1493
Adds
[actions/attest-build-provenance](https://github.com/actions/attest-build-provenance)
to the release workflow so consumers can verify artifacts were built by
CI:
```bash
gh attestation verify <artifact> --repo j178/prek
```
GitHub already generates release attestations that verify file integrity
(checksums), but build provenance additionally proves the artifacts were
produced by the CI workflow rather than uploaded manually.