#!/usr/bin/env bash set -euo pipefail REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" SCRIPT="$REPO_ROOT/scripts/check-release-needed.sh" PASS=0 FAIL=0 pass() { echo " PASS: $1"; PASS=$((PASS + 1)); } fail() { echo " FAIL: $1"; FAIL=$((FAIL + 1)); } # Helper: write a minimal .pre-commit-hooks.yaml exposing one script entry and # one --config-bearing entry, so RELEASE_PATHS (derived from the manifest, not # hand-maintained) has both shapes to parse. write_manifest() { local dir="$1" mkdir -p "$dir/vale" cat > "$dir/.pre-commit-hooks.yaml" <<'EOF' - id: fake-size-check entry: scripts/skill-size-check.sh language: script - id: fake-vale-check entry: scripts/vale-wrap.sh --config vale/.vale.ini language: script EOF } # Helper: a fixture repo with a manifest and its two referenced release-relevant # paths, committed and tagged v1.0.0. make_tagged_fixture() { local dir dir="$(mktemp -d)" (cd "$dir" && git init -q && git config user.email t@t.t && git config user.name t) write_manifest "$dir" mkdir -p "$dir/scripts" echo "v1" > "$dir/scripts/skill-size-check.sh" echo "cfg" > "$dir/vale/.vale.ini" (cd "$dir" && git add -A && git commit -q -m "initial" && git tag v1.0.0) echo "$dir" } run_check() { local dir="$1" branch="$2" (cd "$dir" && PRE_COMMIT_REMOTE_BRANCH="$branch" bash "$SCRIPT" 2>&1) } CLEANUP_DIRS=() trap 'rm -rf "${CLEANUP_DIRS[@]}"' EXIT track() { CLEANUP_DIRS+=("$1"); } # --- 1. Not targeting main: silent no-op regardless of state --- echo "" echo "--- exits 0 when not pushing to main, even with no tags ---" FIXTURE1="$(mktemp -d)"; track "$FIXTURE1" (cd "$FIXTURE1" && git init -q) if run_check "$FIXTURE1" "refs/heads/feature-branch" > /dev/null; then pass "exits 0 when target branch isn't main" else fail "exited non-zero on a non-main target branch" fi # --- 2. Targeting main, no tag exists at all: hard fail --- echo "" echo "--- exits 1 when targeting main and no tag exists ---" FIXTURE2="$(mktemp -d)"; track "$FIXTURE2" (cd "$FIXTURE2" && git init -q && git config user.email t@t.t && git config user.name t) write_manifest "$FIXTURE2" mkdir -p "$FIXTURE2/scripts" echo "v1" > "$FIXTURE2/scripts/skill-size-check.sh" echo "cfg" > "$FIXTURE2/vale/.vale.ini" (cd "$FIXTURE2" && git add -A && git commit -q -m "initial") if run_check "$FIXTURE2" "refs/heads/main" > /dev/null; then fail "exited 0 when targeting main with no tag — expected exit 1" else pass "exits non-zero when targeting main and no tag exists yet" fi # --- 3. Targeting main, tag exists, no release-relevant changes since: passes --- echo "" echo "--- exits 0 when targeting main and nothing release-relevant changed since the tag ---" FIXTURE3="$(make_tagged_fixture)"; track "$FIXTURE3" echo "unrelated" > "$FIXTURE3/README.md" (cd "$FIXTURE3" && git add -A && git commit -q -m "unrelated change") if run_check "$FIXTURE3" "refs/heads/main" > /dev/null; then pass "exits 0 when only unrelated files changed since the tag" else fail "exited non-zero despite no release-relevant changes since the tag" fi # --- 4. Targeting main, tag exists, a release-relevant file changed since: hard fail --- echo "" echo "--- exits 1 when a release-relevant file changed since the tag ---" FIXTURE4="$(make_tagged_fixture)"; track "$FIXTURE4" echo "v2" > "$FIXTURE4/scripts/skill-size-check.sh" (cd "$FIXTURE4" && git add -A && git commit -q -m "update release-relevant script") OUT4=$(run_check "$FIXTURE4" "refs/heads/main" || true) if echo "$OUT4" | grep -q "skill-size-check.sh"; then pass "exits non-zero and names the changed file when a release-relevant path changed since the tag" else fail "did not flag the release-relevant file that changed since the tag" fi # --- 5. Not targeting main even with release-relevant changes and a tag: still a no-op --- echo "" echo "--- exits 0 on a feature branch even with release-relevant changes since the tag ---" FIXTURE5="$(make_tagged_fixture)"; track "$FIXTURE5" echo "v2" > "$FIXTURE5/scripts/skill-size-check.sh" (cd "$FIXTURE5" && git add -A && git commit -q -m "update release-relevant script") if run_check "$FIXTURE5" "refs/heads/some-feature" > /dev/null; then pass "exits 0 on a feature branch regardless of un-tagged release-relevant changes" else fail "hard-failed on a feature branch — should only ever fail when targeting main" fi # --- 6. A release-relevant path deleted since the tag is still flagged --- echo "" echo "--- exits 1 when a release-relevant path was deleted since the tag, not just modified ---" FIXTURE6="$(make_tagged_fixture)"; track "$FIXTURE6" rm -rf "$FIXTURE6/vale" (cd "$FIXTURE6" && git add -A && git commit -q -m "delete the vale config dir") OUT6=$(run_check "$FIXTURE6" "refs/heads/main" || true) if echo "$OUT6" | grep -q "vale/.vale.ini"; then pass "flags a deleted release-relevant path instead of silently dropping it from the diff" else fail "did not flag deletion of a release-relevant path since the tag" fi # --- 7. A git diff failure hard-fails instead of reading as a clean pass --- echo "" echo "--- exits 1 (not a silent pass) when the underlying git diff errors out ---" FIXTURE7="$(make_tagged_fixture)"; track "$FIXTURE7" TAG_TREE="$(cd "$FIXTURE7" && git rev-parse 'v1.0.0^{tree}')" echo "v2" > "$FIXTURE7/scripts/skill-size-check.sh" (cd "$FIXTURE7" && git add -A && git commit -q -m "advance past the tag") rm -f "$FIXTURE7/.git/objects/${TAG_TREE:0:2}/${TAG_TREE:2}" if run_check "$FIXTURE7" "refs/heads/main" > /dev/null; then fail "silently exited 0 when the underlying git diff failed" else pass "hard-fails instead of silently passing when git diff can't be computed" fi # --- 8. A non-version tag reachable from HEAD does not become the diff baseline --- echo "" echo "--- ignores a non-vX.Y.Z tag and still flags a change since the real release tag ---" FIXTURE8="$(make_tagged_fixture)"; track "$FIXTURE8" echo "checkpoint" > "$FIXTURE8/scripts/skill-size-check.sh" (cd "$FIXTURE8" && git add -A && git commit -q -m "checkpoint work" && git tag checkpoint-1) echo "v2" > "$FIXTURE8/scripts/skill-size-check.sh" (cd "$FIXTURE8" && git add -A && git commit -q -m "real release-relevant change") OUT8=$(run_check "$FIXTURE8" "refs/heads/main" || true) if echo "$OUT8" | grep -q "skill-size-check.sh"; then pass "still flags the release-relevant change since v1.0.0, ignoring the non-version checkpoint tag" else fail "an incidental non-version tag shifted the baseline and hid a real release-relevant change" fi # --- 9. A file outside every manifest entry does not trigger a fail --- echo "" echo "--- exits 0 when a changed file sits near, but isn't referenced by, a manifest entry ---" FIXTURE9="$(make_tagged_fixture)"; track "$FIXTURE9" echo "irrelevant" > "$FIXTURE9/scripts/unrelated-helper.sh" (cd "$FIXTURE9" && git add -A && git commit -q -m "add an unrelated script alongside the exposed one") if run_check "$FIXTURE9" "refs/heads/main" > /dev/null; then pass "exits 0 for a file that lives alongside, but isn't referenced by, any manifest entry" else fail "flagged a file that no .pre-commit-hooks.yaml entry actually exposes" fi echo "" echo "Results: $PASS passed, $FAIL failed" [[ $FAIL -eq 0 ]]