mirror of
https://github.com/samsonjs/spirit-tracker.git
synced 2026-03-25 09:25:51 +00:00
93 lines
2.7 KiB
JavaScript
Executable file
93 lines
2.7 KiB
JavaScript
Executable file
#!/usr/bin/env node
|
|
"use strict";
|
|
|
|
const { execFileSync } = require("child_process");
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
|
|
function runGit(args) {
|
|
return execFileSync("git", args, { encoding: "utf8" }).trimEnd();
|
|
}
|
|
|
|
function listDbFiles(dbDir) {
|
|
try {
|
|
return fs
|
|
.readdirSync(dbDir, { withFileTypes: true })
|
|
.filter((e) => e.isFile() && e.name.endsWith(".json"))
|
|
.map((e) => path.join(dbDir, e.name));
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
function dateOnly(iso) {
|
|
const m = String(iso ?? "").match(/^(\d{4}-\d{2}-\d{2})/);
|
|
return m ? m[1] : "";
|
|
}
|
|
|
|
function main() {
|
|
const repoRoot = process.cwd();
|
|
const dbDir = path.join(repoRoot, "data", "db");
|
|
const outDir = path.join(repoRoot, "viz", "data");
|
|
const outFile = path.join(outDir, "db_commits.json");
|
|
|
|
fs.mkdirSync(outDir, { recursive: true });
|
|
|
|
const files = listDbFiles(dbDir).map((abs) => path.posix.join("data/db", path.basename(abs)));
|
|
|
|
const payload = {
|
|
generatedAt: new Date().toISOString(),
|
|
branch: "data",
|
|
files: {},
|
|
};
|
|
|
|
// We want the viz to show ONE point per day (the most recent run that day).
|
|
// So we collapse multiple commits per day down to the newest commit for that date.
|
|
//
|
|
// With multiple runs/day, we also want to keep a long-ish daily history.
|
|
// Raw commits per day could be ~4, so grab a larger raw window and then collapse.
|
|
const MAX_RAW_PER_FILE = 2400; // ~600 days @ 4 runs/day
|
|
const MAX_DAYS_PER_FILE = 600; // daily points kept after collapsing
|
|
|
|
for (const rel of files.sort()) {
|
|
let txt = "";
|
|
try {
|
|
// %H = sha, %cI = committer date strict ISO 8601 (includes time + tz)
|
|
txt = runGit(["log", "--format=%H %cI", `-${MAX_RAW_PER_FILE}`, "--", rel]);
|
|
} catch {
|
|
continue;
|
|
}
|
|
|
|
const lines = txt.split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
|
|
// git log is newest -> oldest.
|
|
// Keep the FIRST commit we see for each date (that is the most recent commit for that date).
|
|
const byDate = new Map(); // date -> { sha, date, ts }
|
|
for (const line of lines) {
|
|
const m = line.match(/^([0-9a-f]{7,40})\s+(.+)$/i);
|
|
if (!m) continue;
|
|
|
|
const sha = m[1];
|
|
const ts = m[2];
|
|
const d = dateOnly(ts);
|
|
if (!d) continue;
|
|
|
|
if (!byDate.has(d)) byDate.set(d, { sha, date: d, ts });
|
|
}
|
|
|
|
// Convert to oldest -> newest
|
|
let arr = [...byDate.values()].reverse();
|
|
|
|
// Keep only the newest MAX_DAYS_PER_FILE (still oldest -> newest)
|
|
if (arr.length > MAX_DAYS_PER_FILE) {
|
|
arr = arr.slice(arr.length - MAX_DAYS_PER_FILE);
|
|
}
|
|
|
|
payload.files[rel] = arr;
|
|
}
|
|
|
|
fs.writeFileSync(outFile, JSON.stringify(payload, null, 2) + "\n", "utf8");
|
|
process.stdout.write(`Wrote ${outFile} (${Object.keys(payload.files).length} files)\n`);
|
|
}
|
|
|
|
main();
|