55 lines
2.2 KiB
Python
55 lines
2.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Reject commits consisting only of generated indexes/projection refreshes.
|
|
|
|
Applies to every author: automation must accompany an actual source change.
|
|
--staged supports a pre-commit hook; BASE..HEAD checks every commit for CI.
|
|
"""
|
|
import argparse
|
|
from pathlib import PurePosixPath
|
|
import subprocess
|
|
|
|
|
|
def generated(path):
|
|
parsed = PurePosixPath(path.lower())
|
|
name = parsed.name
|
|
return (name in {"work-records.md", ".custodian-brief.md", "source-index.md",
|
|
"publication-index.md", "index.generated.md"}
|
|
# The root config is authored generator input, not its output.
|
|
# Keep similarly named evidence and generated-directory copies gated.
|
|
or (name.startswith("source-inventory")
|
|
and str(parsed) != "source-inventory.config.json")
|
|
or name.startswith("decision-packets")
|
|
or name.startswith("publication-index") or name.startswith("projection-refresh")
|
|
or str(parsed).startswith("generated/")
|
|
or str(parsed).startswith("docs/attended-window/")
|
|
or any(part in {"evidence", "decision-packets", "evidence-packets"}
|
|
for part in parsed.parts[:-1]))
|
|
|
|
|
|
def standalone(paths):
|
|
return bool(paths) and all(generated(path) for path in paths)
|
|
|
|
|
|
def git(*args):
|
|
return subprocess.check_output(["git", *args])
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--staged", action="store_true")
|
|
parser.add_argument("--range", default="HEAD^..HEAD")
|
|
args = parser.parse_args()
|
|
commits = [None] if args.staged else git("rev-list", "--reverse", args.range).decode().splitlines()
|
|
failed = []
|
|
for commit in commits:
|
|
raw = git("diff", "--cached", "--name-only", "-z") if commit is None else git(
|
|
"diff-tree", "--root", "--no-commit-id", "-r", "--name-only", "-z", commit)
|
|
paths = [path.decode() for path in raw.split(b"\0") if path]
|
|
if standalone(paths):
|
|
failed.append(commit or "staged")
|
|
if failed:
|
|
parser.exit(1, "Generated-only commits rejected: " + ", ".join(failed) + "\n")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|