#!/usr/bin/env python3 """CI entry point for commit-message lint. This file only locates and delegates. Every rule, the type/emoji mapping and the policy schema belong to the commit-message skill validator, which reads `skills/commit-message/references/commit_policy.json`. Do not reimplement validation here and do not parse rules out of `docs/common/commit_message.md`: that document is human guidance, not a machine policy source. See `skills/commit-message/references/ci-wiring.md`. """ from __future__ import annotations import os import pathlib import subprocess import sys VALIDATOR_CANDIDATES = ( ("skills", "commit-message", "scripts", "validate_commit_message.py"), ( "docs", "standards", "playbook", "skills", "commit-message", "scripts", "validate_commit_message.py", ), ) def _eprint(*args: object) -> None: print(*args, file=sys.stderr) def _repo_root() -> pathlib.Path: output = subprocess.check_output( ["git", "rev-parse", "--show-toplevel"], text=True ) return pathlib.Path(output.strip()) def _find_validator(root: pathlib.Path) -> pathlib.Path: tried: list[pathlib.Path] = [] for parts in VALIDATOR_CANDIDATES: path = root.joinpath(*parts) tried.append(path) if path.is_file(): return path raise FileNotFoundError( "commit-message skill validator not found; expected one of:\n" + "\n".join(f"- {path}" for path in tried) ) def main() -> int: try: root = _repo_root() except Exception as exc: _eprint(f"ERROR: not a git repository: {exc}") return 2 os.chdir(root) try: validator = _find_validator(root) except FileNotFoundError as exc: _eprint(f"ERROR: {exc}") return 2 print(f"validator: {validator}") sys.stdout.flush() # No arguments: the validator selects its CI input mode from the event # payload. Exit codes pass through unchanged (0 pass / 1 lint / 2 input). return subprocess.run([sys.executable, str(validator)], cwd=root).returncode if __name__ == "__main__": raise SystemExit(main())