#!/bin/sh # Pre-commit: the docs pages under apps/docs/content are generated from work/1 # by `bun run sync`, and deploy.yml publishes whatever main holds. Regenerate # them now and stage what sync changed, so a solution and its page land in the # same commit and a stale `## Solution` never reaches main. # # Sync reads the working tree, not the index, so the pages it writes only # match this commit when work/1 has nothing unstaged: an untracked or # half-staged solution would ship a page whose source is not in the commit. # In that case refuse and say what to stage. # # Only paths that became dirty during sync are staged. Anything already dirty # beforehand (hand-written `## Approach` prose in progress, a new index.mdx) # stays where the author left it. # # Bypass for a deliberate partial commit: git commit --no-verify set -eu cd "$(git rev-parse --show-toplevel)" unstaged=$(git status --porcelain -- work/1 | grep -v '^[MADR] ' || true) if [ -n "$unstaged" ]; then printf 'pre-commit: work/1 has unstaged changes; stage or stash them so the generated pages match this commit:\n%s\n' "$unstaged" >&2 exit 1 fi before=$(mktemp) trap 'rm -f "$before"' EXIT git status --porcelain -- apps/docs/content | sort > "$before" report=$(bun run --silent sync) generated=$(git status --porcelain -- apps/docs/content | sort | comm -13 "$before" - | cut -c4-) if [ -n "$generated" ]; then printf '%s\n' "$report" | grep -v 'skipped (in sync)' >&2 printf '%s\n' "$generated" | xargs git add -- fi