Add optional pre-commit hook for code formatting #5178
4 issues
High
Stashed unstaged changes are lost if `dotnet format` fails due to `set -e` - `.githooks/pre-commit:2-13`
The script uses set -e at the top, then stashes unstaged changes before running dotnet format. If dotnet format exits non-zero (e.g., build/compilation error, invalid project state), set -e causes immediate script termination, skipping the git stash pop block entirely. The developer's unstaged work-in-progress changes remain in the stash with no notification, appearing lost. This is a data-loss risk and unintended side effect on every commit attempt where formatting tooling errors occur.
Also found at:
.githooks/pre-commit:12-13.githooks/pre-commit:22-24
`set -e` plus failed `dotnet format` causes silent abort leaving stash unrestored - `.githooks/pre-commit:11-13`
With set -e at the top, if dotnet format exits non-zero (e.g., compile error, missing SDK, network issue during restore), the script terminates immediately at line 12. The stash pop on lines 22-24 is never reached, leaving the developer's unstaged changes trapped in the stash with a confusing name. The user sees no error message because stdout/stderr are redirected to /dev/null.
Also found at:
.githooks/pre-commit:9-19
Medium
Glob pattern `./**/*OptionsSetup.cs` is shell-expanded before being passed to dotnet format - `.githooks/pre-commit:12-13`
Bash will expand ./**/*OptionsSetup.cs (with globstar potentially disabled) and ./modules before invoking dotnet format. Without shopt -s globstar, ** is treated as *, so the exclude argument passed to dotnet format may not match the intended files. Additionally, multiple matched files become multiple positional arguments, which --exclude may not accept. This means CI and the hook can diverge in what files they exclude, defeating the stated goal of matching CI exactly.
Stash pop conflict can leave repository in inconsistent state without notifying developer - `.githooks/pre-commit:22-24`
On line 23, git stash pop --quiet 2>/dev/null || true swallows any conflict that occurs when reapplying unstaged changes. If dotnet format modified files that the developer also had unstaged edits to, the pop will conflict and leave the stash in place — but the script reports success (or the formatting failure) and never tells the developer their unstaged work is still stashed.
4 skills analyzed
| Skill | Findings | Duration | Cost |
|---|---|---|---|
| code-review | 1 | 46.0s | $0.58 |
| find-bugs | 3 | 47.7s | $0.44 |
| gha-security-review | 0 | 12.4s | $0.44 |
| security-review | 0 | 7.3s | $1.22 |
Duration: 1m 53s · Tokens: 235.7k in / 4.9k out · Cost: $2.69 (+merge: $0.00, +dedup: $0.00, +consolidate: $0.00)