githooks conf:check¶
Validate the configuration file with deep checks.
Synopsis¶
Options¶
| Option | Description |
|---|---|
--config=PATH |
Path to configuration file. |
--format=text\|json |
Output format: text (default, tables) or json (machine-readable, clean stdout). An unknown value warns on stderr and falls back to text. The exit code is the same in both formats (invalid config exits non-zero). |
What it checks¶
- File exists in the expected location.
- Structure is correct (hooks/flows/jobs).
- Job types are supported.
- Argument types are valid (paths must be array, rules must be string, etc.).
- Flow and hook references point to existing jobs/flows.
- Hook names are valid git events.
- Unknown configuration keys (warnings, with did-you-mean suggestions for typos).
- Meta-flows: each
flows.<X>declares exactly one ofjobsorflows;flows.<alias>.flowsonly references existing normal flows (no nesting); the jobs/flows/meta-flows namespace is flat. - Multi-report: only
json,junit,sarif,codeclimatekeys are accepted; paths must be strings and writable. - Time budget: positive integers;
warn-after < fail-after;time-budgetrejected inside a job (canonical keys at job level are flatwarn-after/fail-after). - Memory budget: positive integers;
warn-above < fail-above; per-jobmemory > memory-budget.warn-aboveis flagged as a could-never-run configuration. - Allocator: only
fifoandgreedyare valid. - Cores / native thread flag:
coresmust be a positive integer; declaring bothcoresand the tool's native flag (parallel,threads,jobs,processes) emits a conflict warning; declaringcores > 1on a single-threaded tool (phpmd,phpunit,phpcpd) emits a no-benefit warning. - The flow rules: for uncontrollable jobs whose declaration cannot be clamped by the runtime (
phpstanreads.neon,type: customis opaque),conf:checkemits a cross-flow warning whencores(custom) ormaximumNumberOfProcesses(phpstan) exceeds a flow'sprocesses. The warning names the affected flow and explains that other jobs in it will wait in serial while the offending job runs. Same job referenced from multiple flows is validated against each flow independently. --files/--files-from: rejected when declared as keys insideflow.optionsor a job (CLI-only by design).- Per-entry admission rules (
only-files/exclude-files): flow entries declared as{job, only-files?, exclude-files?}accept arrays of glob strings ornull(cancels an inherited rule from.local.php). Empty list[]is rejected with a pointer tonullfor the cancel-inheritance pattern. - Branch-driven execution mode (
on):flows.<X>.onmust be abranch_pattern => attrsmap. Eachattrsarray accepts only scalar keys (today onlyexecution). Unsupportedexecutionvalues are rejected with a did-you-mean suggestion (full,fast,fast-branch,fast-dirty). Missing catch-all*pattern emits a warning.flows.<X>.on.<branch>.executiontypos surface the same did-you-mean. - Job dependencies (
needs): the per-flow DAG is validated with DFS. Cycles of any length (A -> A,A -> B -> A, …) are rejected with the offending chain in the error message.needstargets must exist as job declarations in the same flow. The same job declared twice inflows.<X>.jobsis rejected. An emptyneeds => []list is rejected — the user is pointed atnull(which cancels an inherited rule from.local.php). - Fast-dirty execution mode (
fast-dirty): accepted as a valid value ofexecutioninflows.<X>.execution,flows.<X>.on.<branch>.executionandjobs.<X>.execution, alongsidefull,fast,fast-branch.
Deep validation¶
The output includes tables with Options, Hooks, Flows, Jobs and the full command each job will execute. The Jobs table includes a Status column with:
- Executable — checks that the binary exists in the filesystem or PATH.
- Paths — checks that configured directories exist.
- Config files — checks that referenced config files (
.neon,.xml) are accessible.
Error levels¶
- Errors prevent execution.
- Warnings allow execution but indicate potential issues.
JSON output¶
--format=json emits the full check as a single parseable document: global
options, hooks, flows, and a jobs array where each job carries its
resolved command, a status (ok / warning / error) and the list of
issues. Top-level errors, warnings and deprecations mirror the text
report; valid is true only when there are no errors (same exit code as text
mode).
{
"version": 1,
"valid": true,
"legacy": false,
"file": { "path": "githooks.php", "localPath": null },
"options": { "processes": 8, "failFast": false, "timeBudget": null, "memoryBudget": null, "...": "..." },
"hooks": [ { "event": "pre-commit", "targets": [ { "target": "qa", "onlyOn": [], "excludeOn": [], "onlyFiles": [], "excludeFiles": [] } ] } ],
"flows": [ { "name": "qa", "meta": false, "jobs": ["phpstan", "phpcs"], "flows": [] } ],
"jobs": [ { "name": "phpstan", "command": "…", "status": "ok", "issues": [] } ],
"errors": [],
"warnings": [],
"deprecations": []
}
The options object always carries the full execution-option set with a
stable shape — processes, failFast, mainBranch, fastBranchFallback,
executablePrefix, reports, timeBudget, memoryBudget, allocator,
stats, historySize. The two budgets are serialised symmetrically: null
when unset, or an object (timeBudget: {warnAfter, failAfter},
memoryBudget: {warnAbove, failAbove}) when declared — so a consumer never has
to guess whether a key is simply absent. reports is always an object, {}
when no report is configured.
Every job declared in the file appears in jobs[], including the ones the
parser rejected: those carry "status": "error", an empty command and the
rejection reasons in issues, so jobs[] | select(.status != "ok") never
misses the most broken entries.
A legacy (v2) configuration is reported as {"version":1,"valid":…,"legacy":true,…}:
the v3 blocks (options, hooks, flows, jobs) are omitted and a top-level
hint to run conf:migrate is added instead. Branch on legacy
before reading those blocks.
Examples¶
githooks conf:check
githooks conf:check --config=qa/custom-githooks.php
githooks conf:check --format=json # machine-readable, clean stdout
githooks conf:check --format=json | jq '.jobs[] | select(.status != "ok")'
See also¶
- Configuration File
githooks conf:init— generate a configuration file.