91 lines
2.7 KiB
Python
91 lines
2.7 KiB
Python
#!/usr/bin/env python3
|
|
"""CHECK gate for the daily-commit-census extraction.
|
|
|
|
Re-derives the daily commit census from git at the PINNED head recorded in the
|
|
committed extraction_manifest.json, re-renders the CSV with the identical
|
|
format the extractor uses, and diffs it against the committed file. Exits 0 only
|
|
when every check matches exactly. This is a re-derivation, not an assertion of a
|
|
stored number.
|
|
|
|
Usage: python3 verify_daily_commit_census.py <artifact_dir>
|
|
"""
|
|
|
|
import difflib
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
REPO = "/root/troupe-standup"
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
sys.path.insert(0, HERE)
|
|
from extract_daily_commit_census import render_csv, build_rows # noqa: E402
|
|
|
|
CSV_NAME = "daily-commit-census.csv"
|
|
|
|
|
|
def git(*args):
|
|
return subprocess.run(
|
|
["git", "-C", REPO] + list(args), check=True, capture_output=True, text=True
|
|
).stdout
|
|
|
|
|
|
def read_bytes(name):
|
|
with open(name, "rb") as f:
|
|
return f.read()
|
|
|
|
|
|
def main():
|
|
artdir = sys.argv[1] if len(sys.argv) > 1 else "."
|
|
os.chdir(artdir)
|
|
|
|
with open("extraction_manifest.json", encoding="utf-8") as f:
|
|
manifest = json.load(f)
|
|
head = manifest.get("head_full")
|
|
if not head:
|
|
print("FAIL: manifest has no head_full")
|
|
sys.exit(1)
|
|
|
|
# Re-derive from the pinned head.
|
|
raw = git("log", "--date=short", "--pretty=format:%ad", head).splitlines()
|
|
from collections import Counter
|
|
|
|
counts = Counter(d for d in raw if d)
|
|
rows = [{"date": d, "commits": c} for d, c in sorted(counts.items())]
|
|
expected = render_csv(rows)
|
|
|
|
ok = True
|
|
|
|
with open(CSV_NAME, encoding="utf-8") as f:
|
|
committed = f.read()
|
|
|
|
if committed == expected:
|
|
print("PASS: daily-commit-census.csv re-derives byte-identically from git "
|
|
"at pinned head %s" % head)
|
|
else:
|
|
ok = False
|
|
print("FAIL: daily-commit-census.csv diverges from re-derivation at "
|
|
"pinned head %s" % head)
|
|
exp = expected.splitlines()
|
|
obs = committed.splitlines()
|
|
for line in list(difflib.unified_diff(exp, obs, "expected@", "committed@"))[:12]:
|
|
print(" " + line)
|
|
|
|
# Independent integrity: the TOTAL row must equal the sum of the day rows.
|
|
day_sum = sum(int(r["commits"]) for r in rows)
|
|
total_lines = [ln for ln in committed.splitlines() if ln.startswith("TOTAL,")]
|
|
if total_lines == ["TOTAL,%d" % day_sum]:
|
|
print("PASS: TOTAL row %r == sum of day rows %d" % (total_lines[0], day_sum))
|
|
else:
|
|
ok = False
|
|
print("FAIL: TOTAL row %r != sum of day rows %d" % (total_lines, day_sum))
|
|
|
|
if ok:
|
|
print("ALL CHECKS PASSED")
|
|
sys.exit(0)
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|