ci(githooks): enforce format, lint, and conventional commits
Run SwiftFormat and SwiftLint on staged Swift files in the pre-commit hook (formatting-and-linting.md), gracefully skipping when a tool is absent since CI re-runs both. Enforce the Conventional Commits subject format and the 72-character subject limit in the commit-msg hook (commits.md). Correct the pre-push comment that named the removed ci.yml.
This commit is contained in:
parent
c4f7f9dccc
commit
7270359d14
@ -123,4 +123,26 @@ for ident in "$(git var GIT_AUTHOR_IDENT 2>/dev/null)" "$(git var GIT_COMMITTER_
|
||||
fi
|
||||
done
|
||||
|
||||
# commits.md Rule 1/2: subject must follow Conventional Commits (lowercase type
|
||||
# from the allowed set, optional scope, optional ! for breaking) and be at most
|
||||
# 72 characters. Merge/revert/fixup/squash subjects are tooling-generated and
|
||||
# exempt.
|
||||
SUBJECT=$(printf '%s\n' "$CONTENT" | sed '/^[[:space:]]*$/d' | head -1)
|
||||
case "$SUBJECT" in
|
||||
"Merge "*|"Revert "*|"fixup! "*|"squash! "*|"") ;;
|
||||
*)
|
||||
if [ "${#SUBJECT}" -gt 72 ]; then
|
||||
printf 'commit-msg: subject is %s chars (max 72).\n' "${#SUBJECT}" >&2
|
||||
printf ' Rule: commits.md Rule 1\n' >&2
|
||||
FAIL=1
|
||||
fi
|
||||
if ! printf '%s' "$SUBJECT" | grep -qE '^(feat|fix|docs|style|refactor|perf|test|build|ci|chore)(\([a-z0-9._-]+\))?!?: .+'; then
|
||||
printf 'commit-msg: subject must be Conventional Commits: "type(scope): summary".\n' >&2
|
||||
printf ' Allowed types: feat fix docs style refactor perf test build ci chore\n' >&2
|
||||
printf ' Rule: commits.md Rule 1, Rule 2\n' >&2
|
||||
FAIL=1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
exit $FAIL
|
||||
|
||||
@ -224,6 +224,32 @@ while IFS= read -r file; do
|
||||
done <<<"$EMOJI_TELLS"
|
||||
done <<<"$SCAN_FILES"
|
||||
|
||||
# SwiftFormat + SwiftLint on staged Swift files (formatting-and-linting.md
|
||||
# acceptance item 2). Run only when the tool is installed; CI re-runs both as a
|
||||
# required gate (gates.yml), so a machine lacking the tools cannot land
|
||||
# unformatted or lint-dirty code regardless.
|
||||
STAGED_SWIFT=$(printf '%s\n' "$STAGED_FILES" | grep -E '\.swift$' || true)
|
||||
if [ -n "$STAGED_SWIFT" ]; then
|
||||
if command -v swiftformat >/dev/null 2>&1; then
|
||||
if ! printf '%s\n' "$STAGED_SWIFT" | xargs swiftformat --lint --config .swiftformat >/dev/null 2>&1; then
|
||||
printf 'pre-commit: SwiftFormat found unformatted staged Swift.\n' >&2
|
||||
printf ' Fix: swiftformat . --config .swiftformat\n' >&2
|
||||
FAIL=1
|
||||
fi
|
||||
else
|
||||
printf 'pre-commit: swiftformat not installed; format gate skipped (CI enforces).\n' >&2
|
||||
fi
|
||||
if command -v swiftlint >/dev/null 2>&1; then
|
||||
if ! printf '%s\n' "$STAGED_SWIFT" | xargs swiftlint lint --strict --quiet --config .swiftlint.yml >/dev/null 2>&1; then
|
||||
printf 'pre-commit: SwiftLint violations in staged Swift.\n' >&2
|
||||
printf ' Fix: swiftlint --config .swiftlint.yml --strict\n' >&2
|
||||
FAIL=1
|
||||
fi
|
||||
else
|
||||
printf 'pre-commit: swiftlint not installed; lint gate skipped (CI enforces).\n' >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$FAIL" -ne 0 ]; then
|
||||
printf '\n' >&2
|
||||
printf 'Hook scope: only ADDED lines in the staged diff are gated.\n' >&2
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# pre-push hook: run the mechanical gates locally before a push reaches GitHub.
|
||||
# These mirror the CI workflow (.github/workflows/ci.yml) so red is caught here
|
||||
# These mirror the CI workflows (.github/workflows/) so red is caught here
|
||||
# first. PureYAML is a root Swift package, so Swift gates run at repo root.
|
||||
#
|
||||
# Install (per repo): git config core.hooksPath .githooks
|
||||
|
||||
Loading…
Reference in New Issue
Block a user