#!/usr/bin/env bash
#
# commit-msg — enforce Conventional Commits 1.0.0
#   https://www.conventionalcommits.org/en/v1.0.0/
#
# Subject format:  <type>(<scope>)!: <description>
#   - <type> must be one of the angular types (feat, fix, ...)
#   - (<scope>) is optional
#   - !       is optional and marks a breaking change
#   - <description> is mandatory and must be non-empty
#
# Bypass: commit with --no-verify.
# Merge, revert, fixup!, squash!, and amend! messages are passed through.

set -eu

COMMIT_MSG_FILE="${1:-}"
if [ -z "$COMMIT_MSG_FILE" ] || [ ! -f "$COMMIT_MSG_FILE" ]; then
    echo "commit-msg: missing commit message file" >&2
    exit 1
fi

# First non-comment, non-empty line is the subject.
subject=""
while IFS= read -r line || [ -n "$line" ]; do
    case "$line" in
        ''|'#'*) continue ;;
    esac
    subject="$line"
    break
done < "$COMMIT_MSG_FILE"

if [ -z "$subject" ]; then
    echo "commit-msg: empty commit message" >&2
    exit 1
fi

# Pass-through commits generated by git itself.
case "$subject" in
    "Merge "*|"Revert \""*|"fixup! "*|"squash! "*|"amend! "*)
        exit 0
        ;;
esac

ALLOWED_TYPES="feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert"
# Description must not start with an uppercase letter — kept in sync with the
# subjectPattern in .github/workflows/conventional-commits.yml so the local
# hook is the strictly tighter of the two gates. (Without this guard, a commit
# like "feat: Add thing" passes locally but fails the PR-title CI check.)
PATTERN="^(${ALLOWED_TYPES})(\([^)]+\))?!?: [^A-Z].*"

if printf '%s' "$subject" | grep -Eq "$PATTERN"; then
    exit 0
fi

cat >&2 <<EOF
✗ Commit message does not follow Conventional Commits.

  Got:      $subject

  Expected: <type>(<scope>)!: <description>
            (description must start with a lowercase letter)

  Allowed types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
  Examples:
    feat(router): add weighted round-robin strategy
    fix(bedrock): decouple STS region from aws_region_name
    chore(deps): bump black to 26.3.1
    refactor!: drop Python 3.8 support

See https://www.conventionalcommits.org/en/v1.0.0/

To bypass (use sparingly): git commit --no-verify
EOF
exit 1
