fix(lint): hard-fail on main when a release tag is needed
.pre-commit-hooks.yaml now exposes hooks to external consumers pinning rev: <tag>, but nothing enforced that a tag actually gets cut when the files it references change — relying on memory is exactly what this repo's governance rules say to avoid for a repeatable, deterministic check. scripts/check-release-needed.sh hard-fails at pre-push, but only when PRE_COMMIT_REMOTE_BRANCH (set by pre-commit's hook-impl) is refs/heads/main: it diffs .pre-commit-hooks.yaml's referenced paths against the last tag reachable from HEAD, and fails if either no tag exists yet or something changed since. It's a silent no-op on every other branch — hard-failing on feature-branch pushes mid-review would force a premature tag on a commit that might not survive a squash-merge, the exact risk the repo: local (vs. pinned self- reference) decision in ADR-0014 already avoids for this repo's own dev-time gate. Verified against the real git pre-push hook path (not just the script in isolation): simulated stdin matching git's pre-push protocol through .git/hooks/pre-push, confirmed it correctly fires and fails when targeting main with no tag, and is silent otherwise. ADR: 0014 Refs: #87
This commit is contained in:
97
tests/test-check-release-needed.sh
Executable file
97
tests/test-check-release-needed.sh
Executable file
@@ -0,0 +1,97 @@
|
||||
#!/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: a fixture repo with one release-relevant file, committed and tagged.
|
||||
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)
|
||||
mkdir -p "$dir/scripts"
|
||||
echo "v1" > "$dir/scripts/skill-size-check.sh"
|
||||
(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)
|
||||
}
|
||||
|
||||
# --- 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)"
|
||||
trap 'rm -rf "$FIXTURE1"' EXIT
|
||||
(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)"
|
||||
trap 'rm -rf "$FIXTURE1" "$FIXTURE2"' EXIT
|
||||
(cd "$FIXTURE2" && git init -q && git config user.email t@t.t && git config user.name t)
|
||||
mkdir -p "$FIXTURE2/scripts"
|
||||
echo "v1" > "$FIXTURE2/scripts/skill-size-check.sh"
|
||||
(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)"
|
||||
trap 'rm -rf "$FIXTURE1" "$FIXTURE2" "$FIXTURE3"' EXIT
|
||||
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)"
|
||||
trap 'rm -rf "$FIXTURE1" "$FIXTURE2" "$FIXTURE3" "$FIXTURE4"' EXIT
|
||||
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)"
|
||||
trap 'rm -rf "$FIXTURE1" "$FIXTURE2" "$FIXTURE3" "$FIXTURE4" "$FIXTURE5"' EXIT
|
||||
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
|
||||
|
||||
echo ""
|
||||
echo "Results: $PASS passed, $FAIL failed"
|
||||
[[ $FAIL -eq 0 ]]
|
||||
Reference in New Issue
Block a user