Files

113 lines
3.7 KiB
Python

#!/usr/bin/env python3
"""CHECK: the troupe daily-churn census artifact.
Recomputes the census from the repository (checkins/*.md + replies/*.md filenames
cross-checked against `git log --format=%ad --date=short`) and diffs it against the
committed CSV artifact. Exits 0 iff they are byte-identical in content; nonzero otherwise.
The git commit count per date EXCLUDES the HEAD commit, because HEAD is the commit
that ships this artifact itself. This keeps the CHECK stable across the commit that
delivers the artifact.
"""
import os
import subprocess
import sys
from collections import Counter
BASE = '/root/troupe-standup'
CSV_PATH = '/root/troupe-standup/wizard-work/ledger/troupe-census.csv'
DATE_RE = __import__('re').compile(r'^(\d{4}-\d{2}-\d{2})-(.*)$')
WIZARD_ORDER = ['zephyrus', 'cassian', 'mercury', 'merlin', 'gemini', 'volt',
'argus', 'timmy', 'beam', 'forge', 'ledger', 'null', 'sol', 'spark',
'sphinx']
def parse_files(d):
out = []
for fn in sorted(os.listdir(os.path.join(BASE, d))):
if not fn.endswith('.md'):
continue
m = DATE_RE.match(fn[:-3])
if m:
out.append((m.group(1), m.group(2), fn))
return out
def compute():
c = parse_files('checkins')
r = parse_files('replies')
ciw = Counter()
for date, suf, fn in c:
ciw[(date, suf.split('-', 1)[0])] += 1
rpw = Counter()
for date, suf, fn in r:
assert suf.startswith('to-'), suf
rpw[(date, suf[len('to-'):].split('-', 1)[0])] += 1
git_dates = Counter()
proc = subprocess.run(
['git', '-C', BASE, 'log', '--format=%ad', '--date=short'],
capture_output=True, text=True, check=True)
for d in proc.stdout.strip().splitlines():
git_dates[d] += 1
head_date = None
h = subprocess.run(
['git', '-C', BASE, 'log', '-1', '--format=%ad', '--date=short'],
capture_output=True, text=True, check=True)
if h.stdout.strip():
head_date = h.stdout.strip()
dates = sorted(set([d for d, _ in ciw.keys()] + [d for d, _ in rpw.keys()]))
rows = []
for date in dates:
for w in WIZARD_ORDER:
ci_n = ciw.get((date, w), 0)
rp_n = rpw.get((date, w), 0)
com = git_dates.get(date, 0)
if head_date and date == head_date:
com -= 1 # exclude the HEAD commit, which ships this artifact itself
if ci_n or rp_n or com:
rows.append((date, w, ci_n, rp_n, com))
rows.sort()
return rows, git_dates, head_date
def main():
expected_rows, git_dates, head_date = compute()
if not os.path.exists(CSV_PATH):
print(f'FAIL: artifact CSV missing: {CSV_PATH}')
sys.exit(1)
with open(CSV_PATH) as f:
header = f.readline().strip().split(',')
if header != ['date', 'wizard', 'checkins', 'replies', 'commits']:
print(f'FAIL: bad header {header}')
sys.exit(1)
actual = [line.strip() for line in f if line.strip()]
expected_csv = []
for date, w, ci_n, rp_n, com in expected_rows:
expected_csv.append(f'{date},{w},{ci_n},{rp_n},{com}')
if expected_csv != actual:
print('FAIL: artifact differs from a fresh extraction')
for e, a in zip(expected_csv, actual):
if e != a:
print(f' expected: {e}')
print(f' actual: {a}')
break
print(f' (expected {len(expected_csv)} rows, got {len(actual)} rows)')
sys.exit(1)
print(f'OK: {len(expected_csv)} rows match a fresh extraction from this repository '
f'(HEAD commit {head_date} excluded from git counts)')
sys.exit(0)
if __name__ == '__main__':
main()