import re
import sys
from pathlib import Path
PATTERN = re.compile(
r"^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)"
r"(\([\w\s/.-]+\))?"
r"(!)?"
r":\s"
r".+"
)
ALLOWED_TYPES = {
"build", "chore", "ci", "docs", "feat", "fix",
"perf", "refactor", "revert", "style", "test",
}
def main():
if len(sys.argv) > 1:
msg_file = sys.argv[1]
else:
msg_file = ".git/COMMIT_EDITMSG"
path = Path(msg_file)
if not path.exists():
print(f" SKIP: commit message file not found: {msg_file}")
sys.exit(0)
lines = path.read_text(encoding="utf-8").split("\n")
msg_lines = [l for l in lines if l and not l.startswith("#")]
if not msg_lines:
print(" SKIP: empty commit message")
sys.exit(0)
subject = msg_lines[0]
subject = subject.strip()
if not subject:
print(" SKIP: empty subject line")
sys.exit(0)
if subject.startswith("Merge "):
sys.exit(0)
m = PATTERN.match(subject)
if not m:
print(f" FAIL: '{subject}'")
print(f" Expected format: type(scope)!: description")
print(f" Allowed types: {', '.join(sorted(ALLOWED_TYPES))}")
sys.exit(1)
commit_type = m.group(1)
if commit_type not in ALLOWED_TYPES:
print(f" FAIL: unknown type '{commit_type}'")
sys.exit(1)
print(f" OK: {subject}")
sys.exit(0)
if __name__ == "__main__":
main()