chore(ci): add the changelog-touched gate verification.md requires

verification.md listed scripts/check-changelog-touched.sh in the local
gate, but the script did not exist (exit 127). Adds it: when a change set
modifies Sources/*.swift it must also update CHANGELOG.md, comparing the
branch against its base plus the working tree, no-op on a clean base, with
a CHANGELOG_SKIP escape hatch for refactor-only changes. Wires it into
check-all.sh alongside the other shell gates.
This commit is contained in:
Mihaela Mihaljevic 2026-06-08 17:49:21 +02:00
parent 0171697c37
commit e06a29ae1c
2 changed files with 65 additions and 0 deletions

View File

@ -18,6 +18,7 @@ run_gate() {
run_gate "style" bash scripts/check-style.sh
run_gate "namespacing" bash scripts/check-namespacing.sh
run_gate "forbidden patterns" bash scripts/check-forbidden-patterns.sh
run_gate "changelog" bash scripts/check-changelog-touched.sh
run_gate "swiftformat" swiftformat . --config .swiftformat --lint
run_gate "swiftlint" swiftlint --config .swiftlint.yml --strict
run_gate "swift build" swift build

View File

@ -0,0 +1,64 @@
#!/usr/bin/env bash
# Changelog currency gate. When a change set modifies library sources under
# Sources/, it must also update CHANGELOG.md, so the Keep a Changelog
# "Unreleased" section stays current. See docs/rules/verification.md.
#
# The change set is the union of (a) commits on this branch since it forked
# from the base branch (origin/main, else main) and (b) the staged and unstaged
# working tree. With nothing to compare (a clean checkout sitting on the base
# branch) the gate is a no-op. Pure test, doc, or script edits do not require a
# changelog entry; only Sources/*.swift changes do. Set CHANGELOG_SKIP=1 to
# bypass the gate for an intentional refactor-only change with no notable effect.
set -u
CHANGELOG="CHANGELOG.md"
FAIL=0
fail() {
echo "changelog: $1" >&2
FAIL=1
}
if [ "${CHANGELOG_SKIP:-0}" = "1" ]; then
echo "changelog: skipped (CHANGELOG_SKIP=1)"
exit 0
fi
base_ref=""
for ref in origin/main main; do
if git rev-parse --verify --quiet "$ref" >/dev/null 2>&1; then
base_ref="$ref"
break
fi
done
changed=""
if [ -n "$base_ref" ]; then
merge_base=$(git merge-base "$base_ref" HEAD 2>/dev/null || true)
if [ -n "$merge_base" ]; then
changed=$(git diff --name-only "$merge_base" HEAD)
fi
fi
changed=$(printf '%s\n%s\n%s\n' \
"$changed" \
"$(git diff --cached --name-only)" \
"$(git diff --name-only)")
source_changed=$(printf '%s\n' "$changed" | grep -E '^Sources/.*\.swift$' | sort -u)
if [ -z "$source_changed" ]; then
echo "changelog: OK (no library source changes)"
exit 0
fi
if printf '%s\n' "$changed" | grep -qx "$CHANGELOG"; then
echo "changelog: OK"
exit 0
fi
fail "library sources changed but $CHANGELOG was not updated:"
printf '%s\n' "$source_changed" | sed 's/^/ /' >&2
echo " (add an Unreleased entry, or set CHANGELOG_SKIP=1 for a refactor-only change)" >&2
exit "$FAIL"