Files

119 lines
4.1 KiB
Python

#!/usr/bin/env python3
"""Extract the git commit census of the troupe-standup repo.
Lane: Extract -- data extraction and tables.
Source (single source of truth):
git (local clone, branch main) -- every commit reachable from HEAD.
Artifacts written beside this script (all re-derivable, none hand-typed):
- commits-census.csv commits per author (unique author name)
- commits-by-day.csv commits per calendar day (author date)
- commits-full.csv one row per commit: hash, author, email, date, subject
- README-commits-census.md
Verification: verify_commits_census.py re-derives every table cell from git
and exits 0 iff the committed tables match. The CHECK file runs that script.
Run: python3 extract_commits_census.py
"""
import csv
import os
import subprocess
import sys
from collections import Counter
REPO = "/root/troupe-standup"
OUT = "/root/troupe-standup/wizard-work/ledger"
# Pinned revision so the census is deterministic: other agents keep pushing to
# main while this artifact is being produced. Verify against this hash only.
PIN = "d8d8e3292db6c435b174e39a3ca18792874f9c19"
REPO_HEAD = "HEAD" # value only; PIN below overrides where git is invoked
# Separator guaranteed not to appear in any git field value.
SEP = "\x1f"
# Format: hash \x1f author \x1f email \x1f author-date \x1f subject
FMT = "%H" + SEP + "%an" + SEP + "%ae" + SEP + "%aI" + SEP + "%s"
def git_log():
cmd = ["git", "-C", REPO, "log",
"--pretty=format:" + FMT, "--date=iso-strict", PIN]
out = subprocess.run(cmd, check=True, capture_output=True, text=True).stdout
rows = []
for c in out.splitlines():
if not c:
continue
h, an, ae, ad, s = c.split(SEP)
rows.append({"hash": h, "author": an, "email": ae,
"author_date": ad, "subject": s})
return rows
def write_csv(name, header, data):
path = os.path.join(OUT, name)
with open(path, "w", newline="", encoding="utf-8") as f:
w = csv.writer(f)
w.writerow(header)
w.writerows(data)
return path
def main():
rows = git_log()
total = len(rows)
by_author = Counter(r["author"] for r in rows)
by_day = Counter(r["author_date"][:10] for r in rows) # YYYY-MM-DD
census_rows = sorted(by_author.items(), key=lambda kv: (-kv[1], kv[0]))
day_rows = sorted(by_day.items(), key=lambda kv: kv[0])
os.makedirs(OUT, exist_ok=True)
write_csv("commits-census.csv",
["author", "commits"], [(a, c) for a, c in census_rows])
write_csv("commits-by-day.csv",
["date", "commits"], [(d, c) for d, c in day_rows])
write_csv("commits-full.csv",
["hash", "author", "email", "author_date", "subject"],
[(r["hash"], r["author"], r["email"], r["author_date"], r["subject"]) for r in rows])
lines = []
lines.append("# Git commit census — troupe-standup")
lines.append("")
lines.append("Source: `git log --pretty=format:` over the pinned revision %s (fields: "
"hash, author, email, author-date, subject)." % PIN)
lines.append("")
lines.append("Pinned revision (sha): `%s`" % PIN)
lines.append("Total commits: **%d**" % total)
lines.append("")
lines.append("## Commits by author")
lines.append("")
lines.append("| author | commits |")
lines.append("|---|---|")
for a, c in census_rows:
lines.append("| %s | %d |" % (a, c))
lines.append("| **total** | **%d** |" % total)
lines.append("")
lines.append("## Commits by calendar day")
lines.append("")
lines.append("| date | commits |")
lines.append("|---|---|")
for d, c in day_rows:
lines.append("| %s | %d |" % (d, c))
lines.append("| **total** | **%d** |" % total)
lines.append("")
with open(os.path.join(OUT, "README-commits-census.md"), "w", encoding="utf-8") as f:
f.write("\n".join(lines))
print("commits:", total)
print("authors:", len(census_rows))
print("days:", len(day_rows))
print("wrote: commits-census.csv, commits-by-day.csv, commits-full.csv, README-commits-census.md")
if __name__ == "__main__":
sys.exit(main())