#!/usr/bin/env bun // Dump local git history into the same shape that the live-reports // pipeline expects from GitHub's commits API. Runs at deploy-time so // the container can render /reports/live for a private repo without // holding a GitHub token. Each deploy refreshes the bundle. // // Output: content/git-history/__.json // Schema: GithubCommit[] (see src/c14_github.ts) — newest first. import { spawnSync } from "node:child_process"; import { mkdirSync, writeFileSync } from "node:fs"; import { dirname, resolve } from "node:path"; const REPO_ROOT = resolve(import.meta.dir, "..", ".."); const OWNER = "syntaxai"; const NAME = "tdd.md"; const MAX = 200; // Use ASCII record separators (\x1e between commits, \x1f between // fields) so commit-message newlines pass through unmangled. const FMT = ["%H", "%aI", "%an", "%ae", "%B"].join("\x1f") + "\x1e"; const res = spawnSync( "git", ["log", `--max-count=${MAX}`, `--pretty=format:${FMT}`], { cwd: REPO_ROOT, encoding: "utf8", maxBuffer: 64 * 1024 * 1024 }, ); if (res.status !== 0) { console.error("git log failed:", res.stderr); process.exit(1); } const records = res.stdout.split("\x1e").map((s) => s.trim()).filter(Boolean); const commits = records.map((rec) => { const [sha, date, name, email, ...rest] = rec.split("\x1f"); const message = (rest.join("\x1f") ?? "").replace(/\n+$/, ""); return { sha: sha ?? "", commit: { author: { name: name ?? "", email: email ?? "", date: date ?? "", }, message, }, author: null, }; }); const outDir = resolve(REPO_ROOT, "content", "git-history"); const outPath = resolve(outDir, `${OWNER}__${NAME}.json`); mkdirSync(dirname(outPath), { recursive: true }); writeFileSync(outPath, JSON.stringify({ owner: OWNER, name: NAME, fetchedAt: Date.now(), commits }, null, 2)); console.log(`✓ wrote ${commits.length} commits → ${outPath}`);