# prek.toml - Git hooks configuration # Run: prek run --all-files # Install: prek install && prek install --hook-type commit-msg # Built-in hooks (fast, Rust-native — no external dependencies) [[repos]] repo = "builtin" hooks = [ { id = "trailing-whitespace" }, { id = "end-of-file-fixer" }, { id = "check-added-large-files", args = [ "--maxkb=1000", ] }, { id = "check-merge-conflict" }, { id = "check-json" }, { id = "check-toml" }, { id = "check-case-conflict" }, { id = "detect-private-key" }, { id = "check-executables-have-shebangs" }, ] # check-yaml with --unsafe (builtin fast path doesn't support --unsafe yet) [[repos]] repo = "https://github.com/pre-commit/pre-commit-hooks" rev = "v6.0.0" hooks = [{ id = "check-yaml", args = ["--unsafe"] }] # Secret detection [[repos]] repo = "https://github.com/trufflesecurity/trufflehog" rev = "v3.93.4" hooks = [ { id = "trufflehog", entry = "trufflehog git file://. --since-commit HEAD --no-verification --fail", stages = [ "pre-commit", "pre-push", ] }, ] # YAML linting [[repos]] repo = "https://github.com/adrienverge/yamllint" rev = "v1.38.0" hooks = [{ id = "yamllint", args = ["-c", ".yamllint.yaml"] }] # Python - ruff for linting and formatting [[repos]] repo = "https://github.com/astral-sh/ruff-pre-commit" rev = "v0.15.2" hooks = [{ id = "ruff", args = ["--fix"] }, { id = "ruff-format" }] # Shell scripts - shellcheck and shfmt [[repos]] repo = "https://github.com/shellcheck-py/shellcheck-py" rev = "v0.11.0.1" hooks = [{ id = "shellcheck", args = ["--severity=warning"] }] [[repos]] repo = "https://github.com/scop/pre-commit-shfmt" rev = "v3.12.0-2" hooks = [{ id = "shfmt", args = ["-i", "2", "-ci", "-bn"] }] # TOML - taplo # Only the formatter is enabled. taplo-lint is intentionally omitted: it fetches # the remote SchemaStore catalog on every run, which requires network access # (breaking sandboxed CI) and is broken in the pinned taplo CLI ("data did not # match any variant of untagged enum SchemaCatalog"). TOML syntax is already # validated by the check-toml hook above, and taplo upstream is dormant. [[repos]] repo = "https://github.com/ComPWA/taplo-pre-commit" rev = "v0.9.3" hooks = [{ id = "taplo-format" }] # JSON formatting (prettier for consistent style) [[repos]] repo = "https://github.com/rbubley/mirrors-prettier" rev = "v3.8.1" hooks = [{ id = "prettier", types_or = ["json"], args = ["--tab-width", "2"] }] # Rust formatting - cargo fmt over the whole workspace, in place (like the other # formatters above). Uses the system toolchain; CI also enforces it via # `dagger call check` (cargo fmt --check). Runs whenever a .rs file is staged. [[repos]] repo = "local" [[repos.hooks]] id = "cargo-fmt" name = "cargo-fmt" entry = "cargo fmt --all" language = "system" files = '\.rs$' pass_filenames = false # Rust linting - cargo clippy over the whole workspace, denying warnings to # match CI (`dagger call check` / .forgejo/scripts/build run the same command). # Catches lints (e.g. clippy::single_match) before they reach CI. Uses the # system toolchain; runs whenever a .rs file is staged. [[repos.hooks]] id = "cargo-clippy" name = "cargo-clippy" entry = "cargo clippy --all-targets --all-features -- -D warnings" language = "system" files = '\.rs$' pass_filenames = false # Pre-push safety net. The pre-commit cargo-fmt hook above reformats in place, # but only when it is installed and actually runs — a commit made before # `prek install`, or via a tool that skips hooks, can still carry unformatted # Rust to CI (where the Dagger `check` step runs `cargo fmt --all --check` and # fails). This hook re-checks at push time, mirroring CI byte-for-byte, so an # unformatted commit is blocked locally before it can reach the runner. It runs # only when the push range touches a .rs file, so Rust-free pushes pay nothing. [[repos.hooks]] id = "cargo-fmt-check" name = "cargo-fmt-check" entry = "cargo fmt --all --check" language = "system" files = '\.rs$' pass_filenames = false stages = ["pre-push"] # GitHub/Forgejo Actions workflow linting [[repos]] repo = "https://github.com/rhysd/actionlint" rev = "v1.7.11" hooks = [ { id = "actionlint-system", args = [ "-config-file", ".github/actionlint.yaml", ], files = '\.forgejo/workflows/' }, ] # Custom local hooks # Changelog fragment validation (no subdirectories) [[repos]] repo = "local" [[repos.hooks]] id = "changelog-check" name = "changelog-check" entry = "mise run changelog-check" language = "system" files = '^docs/changelog\.d/' pass_filenames = false # Mikado Branch Invariant (C2 changes) [[repos]] repo = "local" [[repos.hooks]] id = "mikado-branch-invariant-check" name = "mikado-branch-invariant-check" entry = "mise run mikado-branch-invariant-check" language = "system" always_run = true stages = ["commit-msg"] # Documentation validation [[repos]] repo = "local" [[repos.hooks]] id = "docs-check-filenames" name = "docs-check-filenames" entry = "mise run docs-check-filenames" language = "system" files = '^docs/.*\.md$' pass_filenames = false [[repos.hooks]] id = "docs-check-links" name = "docs-check-links" entry = "mise run docs-check-links" language = "system" files = '^docs/.*\.md$' pass_filenames = false [[repos.hooks]] id = "docs-check-index" name = "docs-check-index" entry = "mise run docs-check-index" language = "system" files = '^docs/.*\.md$' pass_filenames = false [[repos.hooks]] id = "docs-check-frontmatter" name = "docs-check-frontmatter" entry = "mise run docs-check-frontmatter" language = "system" files = '^docs/.*\.md$' pass_filenames = false