feat(tooling): repo-stats imports its directory with improvise import <dir> (improvise-1xfb.5.1)

Folder import (improvise-lpzu, #314) keeps sparse records and makes a
view per file, so the category padding, the explicit file list and the
generated per-file views are gone.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
Claude (agent-stats)
2026-09-24 22:05:49 -07:00
committed by Edward Langley
parent 9639c577a4
commit 14a91c9cc2
+3 -33
View File
@@ -160,20 +160,6 @@ def build_dir(out, log, rows, min_revs, today):
finally: finally:
os.unlink(f.name) os.unlink(f.name)
flag_coupling(os.path.join(out, "coupling.csv")) flag_coupling(os.path.join(out, "coupling.csv"))
for name in ["churn"] + ANALYSES:
pad_categories(os.path.join(out, f"{name}.csv"))
def pad_categories(path):
"""Every category column, `-` where this CSV has none: improvise skips a record
that lacks any category's value, so a sparse merge imports nothing (tooling.md)."""
rows = read_csv(path)
with open(path, newline="") as f:
header = next(csv.reader(f))
for r in rows:
for c in CATEGORIES:
r.setdefault(c, "-")
write_csv(path, header + [c for c in CATEGORIES if c not in header], rows)
def improvise(out, *args): def improvise(out, *args):
@@ -185,34 +171,18 @@ def improvise(out, *args):
def run_improvise(out): def run_improvise(out):
"""Import the directory into one model, then build its views and export them. """Import the directory into one model, a view per file included, then build
Naming the files is interim until `improvise import <dir>` (improvise-lpzu).""" the report's views and export them."""
files = ["churn.csv"] + [f"{a}.csv" for a in ANALYSES]
flags = [f"--category={c}" for c in CATEGORIES] + [f"--measure={m}" for m in MEASURES] flags = [f"--category={c}" for c in CATEGORIES] + [f"--measure={m}" for m in MEASURES]
improvise(out, "import", *files, "--no-wizard", *flags, "--name=Repo stats", improvise(out, "import", ".", "--no-wizard", *flags, "--name=Repo stats",
"--formula=DeletionRatio = deleted / added FORMAT .3", "--formula=DeletionRatio = deleted / added FORMAT .3",
"-o", "repo-stats.improv") "-o", "repo-stats.improv")
os.makedirs(os.path.join(out, "report"), exist_ok=True) os.makedirs(os.path.join(out, "report"), exist_ok=True)
with open(os.path.join(out, "per-file-views.improvise"), "w") as f:
f.write(per_file_views(["churn"] + ANALYSES))
improvise(out, "script", "per-file-views.improvise", "-f", "repo-stats.improv")
improvise(out, "script", os.path.join(HERE, "repo-stats.improvise"), improvise(out, "script", os.path.join(HERE, "repo-stats.improvise"),
"-f", "repo-stats.improv") "-f", "repo-stats.improv")
return {t: read_rows(os.path.join(out, "report", f"{t}.csv")) for t in TABLES} return {t: read_rows(os.path.join(out, "report", f"{t}.csv")) for t in TABLES}
def per_file_views(names):
"""A records view per source CSV, paged to it. Interim: improvise-lpzu's folder
import makes these itself, showing only each file's own columns."""
lines = []
for n in names:
lines += [f'create-view "{n}"', f'switch-view "{n}"', "set-axis _Index row",
"set-axis _Dim column", "set-axis File page", f"set-page File {n}",
"set-axis _Measure none"]
lines += [f"set-axis {c} none" for c in CATEGORIES]
return "\n".join(lines) + "\n"
def read_rows(path): def read_rows(path):
with open(path, newline="") as f: with open(path, newline="") as f:
return list(csv.reader(f)) return list(csv.reader(f))