#!/usr/bin/env bash print_usage() { echo "Usage:" echo " $0" echo " $0 " echo " $0 --message \"\"" echo " $0 --message-file " } load_commit_message() { if [ $# -eq 0 ]; then local commit_ref="HEAD" echo "Checking latest commit..." >&2 git log -1 --pretty=format:"%s%n%b" "$commit_ref" return fi case "$1" in -h|--help) print_usage exit 0 ;; --message) shift if [ $# -eq 0 ]; then echo "[FAIL] --message option requires a commit message" print_usage exit 1 fi echo "Checking provided commit message..." >&2 printf '%s' "$*" ;; --message-file) shift if [ $# -ne 1 ]; then echo "[FAIL] --message-file option requires a file path" print_usage exit 1 fi if [ ! -f "$1" ]; then echo "[FAIL] Commit message file not found: $1" exit 1 fi echo "Checking commit message file: $1" >&2 cat "$1" ;; *) if [ $# -ne 1 ]; then echo "[FAIL] Invalid arguments" print_usage exit 1 fi local commit_ref="$1" if ! git rev-parse --verify "$commit_ref^{commit}" >/dev/null 2>&1; then echo "[FAIL] Invalid commit reference: $commit_ref" exit 1 fi echo "Checking commit: $commit_ref" >&2 git log -1 --pretty=format:"%s%n%b" "$commit_ref" ;; esac } commit_message=$(load_commit_message "$@") subject=$(printf '%s\n' "$commit_message" | head -n1) body=$(printf '%s\n' "$commit_message" | tail -n +2) echo "Checking commit message format..." echo "Subject: $subject" exit_code=0 if [ -z "$subject" ]; then echo "[FAIL] Subject must not be empty" exit 1 fi subject_pattern='^([a-z]+)(\([a-z0-9._/-]+\))?(!)?: (.+)$' if [[ "$subject" =~ $subject_pattern ]]; then type="${BASH_REMATCH[1]}" description="${BASH_REMATCH[4]}" echo "[PASS] Subject follows Conventional Commit format" echo "[PASS] Type is lowercase: $type" if printf '%s\n' "$description" | grep -Eq '[가-힣]'; then echo "[PASS] Description contains Korean text" else echo "[FAIL] Description must contain Korean text" exit_code=1 fi else echo "[FAIL] Subject must match: (scope): " echo " scope is optional, example: feat: 기능을 추가한다" exit_code=1 fi if [ -n "$body" ] && printf '%s\n' "$body" | grep -Eq '^Refs:'; then while IFS= read -r refs_line; do if ! printf '%s\n' "$refs_line" | grep -Eq '^Refs: #[0-9]+(, #[0-9]+)*$'; then echo "[FAIL] Refs footer format is invalid: $refs_line" echo " expected format: Refs: #123 or Refs: #123, #456" exit_code=1 fi done < <(printf '%s\n' "$body" | grep -E '^Refs:') if [ $exit_code -eq 0 ]; then echo "[PASS] Refs footer format is valid" fi fi if [ $exit_code -eq 0 ]; then echo "[PASS] Commit message follows AGENTS.md rules" else echo "[FAIL] Commit message violates AGENTS.md rules" fi exit $exit_code