diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-28 09:11:47 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-28 09:11:47 -0500 |
| commit | 9f84ea2c7854e35ae30c0fb5fbd63f7b7115fb41 (patch) | |
| tree | c6cd922c6286c5a6a0c6803ed8311683a3e538af /scripts/tests | |
| parent | beb646e827802c0491b422ce03c7687eb66a717b (diff) | |
| download | rulesets-9f84ea2c7854e35ae30c0fb5fbd63f7b7115fb41.tar.gz rulesets-9f84ea2c7854e35ae30c0fb5fbd63f7b7115fb41.zip | |
feat(sync-check): canonical/mirror drift detection + pre-commit hook
scripts/sync-check.sh diffs claude-templates/.ai/{protocols.org,
workflows,scripts} against the .ai/ mirror. Exits 0 when clean, 1 with
a diff report on drift, 2 outside a rulesets-shaped repo or git
checkout. --fix mode rsyncs canonical -> mirror and re-checks, then
prompts to re-stage.
githooks/pre-commit wraps the script. Commits abort on drift so the
issue surfaces at publish time, not at the next session's startup
rsync.
Two new Makefile targets:
- make sync-check [FIX=1] runs the script (FIX=1 passes --fix
through).
- make install-githooks sets core.hooksPath=githooks (idempotent).
scripts/tests/sync-check.bats holds 8 tests covering clean,
drift-per-path, --fix, extra-file removal, missing canonical, and
outside-git. All eight pass.
This catches the exact drift I had to fix manually during this
morning's audit pass. The mirror's open-tasks.org PROPERTIES drawer
sat below a sub-heading because the mirror commit was older than
canonical.
Diffstat (limited to 'scripts/tests')
| -rw-r--r-- | scripts/tests/sync-check.bats | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/scripts/tests/sync-check.bats b/scripts/tests/sync-check.bats new file mode 100644 index 0000000..df775b3 --- /dev/null +++ b/scripts/tests/sync-check.bats @@ -0,0 +1,86 @@ +#!/usr/bin/env bats +# +# Tests for scripts/sync-check.sh +# +# Sandboxes a fake rulesets-shaped git repo under $BATS_TMPDIR, drops the +# real script in via PATH override, and exercises clean / drift / --fix +# behavior. + +setup() { + SANDBOX="$BATS_TEST_TMPDIR/repo" + SCRIPT_SRC="$BATS_TEST_DIRNAME/../sync-check.sh" + mkdir -p "$SANDBOX/scripts" "$SANDBOX/claude-templates/.ai/workflows" \ + "$SANDBOX/claude-templates/.ai/scripts" "$SANDBOX/.ai/workflows" \ + "$SANDBOX/.ai/scripts" + cp "$SCRIPT_SRC" "$SANDBOX/scripts/sync-check.sh" + chmod +x "$SANDBOX/scripts/sync-check.sh" + cd "$SANDBOX" + git init -q + git config user.email test@example.com + git config user.name test + echo "protocols content" > claude-templates/.ai/protocols.org + echo "protocols content" > .ai/protocols.org + echo "workflow a" > claude-templates/.ai/workflows/a.org + echo "workflow a" > .ai/workflows/a.org + echo "script b" > claude-templates/.ai/scripts/b.sh + echo "script b" > .ai/scripts/b.sh +} + +@test "clean tree: exit 0" { + run scripts/sync-check.sh + [ "$status" -eq 0 ] +} + +@test "drift in protocols.org: exit 1, names the file" { + echo "drifted" > .ai/protocols.org + run scripts/sync-check.sh + [ "$status" -eq 1 ] + [[ "$output" == *"protocols.org"* ]] +} + +@test "drift in workflows/: exit 1, names workflows" { + echo "workflow a modified" > .ai/workflows/a.org + run scripts/sync-check.sh + [ "$status" -eq 1 ] + [[ "$output" == *"workflows"* ]] +} + +@test "drift in scripts/: exit 1, names scripts" { + echo "script b modified" > .ai/scripts/b.sh + run scripts/sync-check.sh + [ "$status" -eq 1 ] + [[ "$output" == *"scripts"* ]] +} + +@test "drift with --fix: syncs and exits 0" { + echo "drifted" > .ai/protocols.org + run scripts/sync-check.sh --fix + [ "$status" -eq 0 ] + run cat .ai/protocols.org + [ "$output" = "protocols content" ] +} + +@test "extra file in mirror: --delete removes it" { + echo "stale" > .ai/workflows/stale.org + run scripts/sync-check.sh --fix + [ "$status" -eq 0 ] + [ ! -f .ai/workflows/stale.org ] +} + +@test "missing canonical: exit 2 with clear error" { + rm -rf claude-templates + run scripts/sync-check.sh + [ "$status" -eq 2 ] + [[ "$output" == *"not a rulesets-shaped repo"* ]] +} + +@test "outside a git checkout: exit 2" { + cd "$BATS_TEST_TMPDIR" + mkdir not-a-repo + cp "$SCRIPT_SRC" not-a-repo/sync-check.sh + chmod +x not-a-repo/sync-check.sh + cd not-a-repo + run ./sync-check.sh + [ "$status" -eq 2 ] + [[ "$output" == *"not inside a git checkout"* ]] +} |
