GRM-21: Implement commit validation, CI/CD workflows and repo automation
- Add scripts/validate_commit_msg.py with conventional commit enforcement - Add scripts/configure_repo.py for Gitea branch protection and labels - Add scripts/__init__.py for Python package importability - Create Gitea Actions workflows: ci, auto-merge, post-merge, publish - Update .pre-commit-config.yaml with commit-msg hook - Update pyproject.toml pythonpath and coverage for scripts - Add comprehensive unit tests for both scripts with 100% coverage
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Validate commit messages for GRM.
|
||||
|
||||
Rules:
|
||||
- On master branch: allow anything (merge commits already have task ID).
|
||||
- On feature branches: must use conventional commit format, must NOT include GRM-N prefix.
|
||||
"""
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
CONVENTIONAL_RE = re.compile(
|
||||
r"^(feat|fix|chore|docs|style|refactor|perf|test|ci|build|revert|BREAKING CHANGE)(\(.+\))?: .+"
|
||||
)
|
||||
TASK_ID_RE = re.compile(r"^GRM-\d+:")
|
||||
|
||||
|
||||
def first_line(text: str) -> str:
|
||||
return text.split("\n")[0]
|
||||
|
||||
|
||||
def get_branch() -> str:
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["git", "symbolic-ref", "--short", "HEAD"],
|
||||
capture_output=True, text=True, check=True,
|
||||
)
|
||||
return result.stdout.strip()
|
||||
except subprocess.CalledProcessError:
|
||||
return ""
|
||||
|
||||
|
||||
def main(args=None) -> None:
|
||||
argv = args if args is not None else sys.argv
|
||||
if len(argv) < 2:
|
||||
print("Usage: validate_commit_msg.py <commit-msg-file>")
|
||||
sys.exit(1)
|
||||
|
||||
with open(argv[1]) as f:
|
||||
msg = f.read().strip()
|
||||
|
||||
branch = get_branch()
|
||||
|
||||
if branch == "master":
|
||||
return
|
||||
|
||||
subject = first_line(msg)
|
||||
|
||||
if TASK_ID_RE.match(subject):
|
||||
print("ERROR: Do not include task ID (GRM-N) in feature branch commits.")
|
||||
print(" Task ID will be added automatically on merge via CI.")
|
||||
sys.exit(1)
|
||||
|
||||
if not CONVENTIONAL_RE.match(subject):
|
||||
print("ERROR: Commit message must follow conventional commit format.")
|
||||
print(" Expected: <type>: <description>")
|
||||
print(f" Got: {subject}")
|
||||
print(" Allowed types: feat, fix, chore, docs, style, refactor,")
|
||||
print(" perf, test, ci, build, revert, BREAKING CHANGE")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
main()
|
||||
Reference in New Issue
Block a user