The convention was documented in CONTRIBUTING.md but nothing enforced it, and no decision was on record for the pre-self-hosting `Phase` history. - tools/git-hooks/commit-msg — rejects a summary that is not a Conventional Commit. tools/git-hooks/lib.sh holds the single rule (types, scope, `!`, and the merge/revert/autosquash exemptions) so the hook and CI cannot drift. - tools/git-hooks/lint-range.sh — lints a commit range with that same rule. - .forgejo/workflows/commit-lint.yml — runs it over the new commits on every push and PR, as the backstop for contributors who have not enabled the hook. - Fix the pre-commit hook, which pointed at the old build/ludic-fmt path (the toolchain moved to bin/) and so silently no-op'd; it now finds bin/ludic-fmt. - CONTRIBUTING.md — full type/scope table, the one-line enable (`git config core.hooksPath tools/git-hooks`), and a **Git history** section recording the decision: leave the pushed `Phase`-era history as-is (a rewrite is destructive and non-reversible for anyone who cloned); enforce the convention going forward; let #33's first release tag double as the clean `v0` baseline that brackets the old prefix without touching a commit. Verified: the hook accepts feat/fix/ci/refactor(!)/merge/revert and rejects "added regex" / "Fix bug" / "WIP"; lint-range passes recent history and flags the old `Phase 8b:` commit. Closes #34 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
34 lines
1.5 KiB
Bash
34 lines
1.5 KiB
Bash
# lib.sh — shared Conventional Commits validation, sourced by the commit-msg
|
|
# hook and by the CI commit-lint job so the rule lives in exactly one place.
|
|
# POSIX sh; no bashisms.
|
|
|
|
# The allowed commit types (Conventional Commits + the ones this repo uses).
|
|
CONVENTIONAL_TYPES='feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert'
|
|
|
|
# conventional_ok <header-line> -> 0 if it conforms, non-zero otherwise.
|
|
# Accepts `type(scope): summary`, an optional `!` for a breaking change, and the
|
|
# housekeeping headers git itself writes (merge/revert) or autosquash markers.
|
|
conventional_ok() {
|
|
header="$1"
|
|
[ -n "$header" ] || return 1
|
|
case "$header" in
|
|
"Merge "*|"Revert "*|"fixup! "*|"squash! "*|"amend! "*) return 0 ;;
|
|
esac
|
|
printf '%s\n' "$header" \
|
|
| grep -qE "^($CONVENTIONAL_TYPES)(\([a-z0-9][a-z0-9,._/ -]*\))?(!)?: .+"
|
|
}
|
|
|
|
# conventional_help <header-line> — print a short, actionable explanation.
|
|
conventional_help() {
|
|
echo " commit summary is not a Conventional Commit:"
|
|
echo " ${1:-<empty>}"
|
|
echo
|
|
echo " expected: type(scope): summary (scope is optional)"
|
|
echo " types: feat fix docs style refactor perf test build ci chore revert"
|
|
echo " examples: feat(stdlib): add Regex.* namespace"
|
|
echo " fix(emit): stop fixed compares widening the int literal"
|
|
echo " ci: cache the clang toolchain between runs"
|
|
echo " refactor(stdlib)!: drop the deprecated System.env alias"
|
|
echo
|
|
echo " see https://www.conventionalcommits.org"
|
|
}
|