#!/bin/sh commit_msg_file="$1" if [ ! -f "$commit_msg_file" ]; then echo "commit-msg hook error: commit message file not found" exit 1 fi header="$(sed -n '/^[[:space:]]*#/!{/^[[:space:]]*$/!{p;q;}}' "$commit_msg_file")" if [ -z "$header" ]; then echo "Invalid commit message: empty message" exit 1 fi case "$header" in Merge\ *|Revert\ *|fixup!\ *|squash!\ *) exit 0 ;; esac type_pattern="feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert|wip|workflow|types|release" commit_pattern="^($type_pattern)(\([a-z0-9][a-z0-9._/-]*\))?!?: .{1,}$" if ! printf '%s\n' "$header" | grep -Eq "$commit_pattern"; then echo "Invalid commit message format." echo "" echo "Expected Conventional Commits format:" echo " [optional scope][optional !]: " echo "" echo "Allowed types:" echo " feat, fix, docs, style, refactor, perf, test, build, ci, chore," echo " revert, wip, workflow, types, release" echo "" echo "Examples:" echo " feat: add user search" echo " fix(backend): handle token expiry" echo " docs(readme): update setup guide" echo " refactor(web)!: remove legacy auth flow" exit 1 fi exit 0