feat(audit): add prune reports to rolling cadence flow
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { readdir, rm } from 'node:fs/promises';
|
||||
import { resolve } from 'node:path';
|
||||
import { mkdir, readdir, rm, writeFile } from 'node:fs/promises';
|
||||
import { dirname, resolve } from 'node:path';
|
||||
import { parseArgs } from 'node:util';
|
||||
import {
|
||||
planRollingPhase0ArtifactRetention,
|
||||
@@ -16,11 +16,19 @@ function usage(): string {
|
||||
' --artifacts-dir <path> Artifacts directory (default: docs/plans/artifacts)',
|
||||
' --keep-per-family <num> Keep newest rolling tags per family (default: 8)',
|
||||
' --apply Apply deletions (default: dry-run)',
|
||||
' --report-tag <tag> Report tag suffix (default: current UTC date)',
|
||||
' --write-default-artifacts Write report files to artifacts dir',
|
||||
' --summary-json-out <path> Write JSON report to path',
|
||||
' --summary-md-out <path> Write markdown report to path',
|
||||
' --format <text|json> Output format (default: text)',
|
||||
' --help Show usage',
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function isoDateTagNow(): string {
|
||||
return new Date().toISOString().slice(0, 10);
|
||||
}
|
||||
|
||||
function parseOptionalNumber(raw: string | undefined, flag: string): number | undefined {
|
||||
if (!raw) {
|
||||
return undefined;
|
||||
@@ -58,12 +66,21 @@ function renderText(plan: Phase0RollingArtifactRetentionPlan, artifactsDir: stri
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
async function writeTextFile(pathValue: string, contents: string): Promise<void> {
|
||||
await mkdir(dirname(pathValue), { recursive: true });
|
||||
await writeFile(pathValue, `${contents}\n`, 'utf8');
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const { values } = parseArgs({
|
||||
options: {
|
||||
'artifacts-dir': { type: 'string' },
|
||||
'keep-per-family': { type: 'string' },
|
||||
apply: { type: 'boolean' },
|
||||
'report-tag': { type: 'string' },
|
||||
'write-default-artifacts': { type: 'boolean' },
|
||||
'summary-json-out': { type: 'string' },
|
||||
'summary-md-out': { type: 'string' },
|
||||
format: { type: 'string' },
|
||||
help: { type: 'boolean', short: 'h' },
|
||||
},
|
||||
@@ -80,11 +97,25 @@ async function main(): Promise<void> {
|
||||
const keepPerFamily = parseOptionalNumber(values['keep-per-family'], '--keep-per-family') ?? 8;
|
||||
const apply = Boolean(values.apply);
|
||||
const format = values.format ?? 'text';
|
||||
const reportTag = values['report-tag'] ?? isoDateTagNow();
|
||||
const writeDefaultArtifacts = Boolean(values['write-default-artifacts']);
|
||||
|
||||
if (format !== 'text' && format !== 'json') {
|
||||
throw new Error(`Invalid --format value "${format}".`);
|
||||
}
|
||||
|
||||
const defaultBaseName = resolve(artifactsDir, `phase0_baseline_live_prune_${reportTag}`);
|
||||
const summaryJsonOut = values['summary-json-out']
|
||||
? resolve(values['summary-json-out'])
|
||||
: writeDefaultArtifacts
|
||||
? `${defaultBaseName}.json`
|
||||
: undefined;
|
||||
const summaryMdOut = values['summary-md-out']
|
||||
? resolve(values['summary-md-out'])
|
||||
: writeDefaultArtifacts
|
||||
? `${defaultBaseName}.md`
|
||||
: undefined;
|
||||
|
||||
const files = await readdir(artifactsDir);
|
||||
const plan = planRollingPhase0ArtifactRetention(files, keepPerFamily);
|
||||
|
||||
@@ -94,16 +125,32 @@ async function main(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
const payload = {
|
||||
generated_at: new Date().toISOString(),
|
||||
artifacts_dir: artifactsDir,
|
||||
keep_per_family: Math.floor(keepPerFamily),
|
||||
apply,
|
||||
report_tag: reportTag,
|
||||
reports: {
|
||||
summary_json_out: summaryJsonOut,
|
||||
summary_md_out: summaryMdOut,
|
||||
},
|
||||
plan,
|
||||
};
|
||||
const jsonOutput = JSON.stringify(payload, null, 2);
|
||||
const textOutput = renderText(plan, artifactsDir, Math.floor(keepPerFamily), apply);
|
||||
|
||||
if (summaryJsonOut) {
|
||||
await writeTextFile(summaryJsonOut, jsonOutput);
|
||||
}
|
||||
if (summaryMdOut) {
|
||||
await writeTextFile(summaryMdOut, textOutput);
|
||||
}
|
||||
|
||||
if (format === 'json') {
|
||||
process.stdout.write(`${JSON.stringify({
|
||||
generated_at: new Date().toISOString(),
|
||||
artifacts_dir: artifactsDir,
|
||||
keep_per_family: Math.floor(keepPerFamily),
|
||||
apply,
|
||||
plan,
|
||||
}, null, 2)}\n`);
|
||||
process.stdout.write(`${jsonOutput}\n`);
|
||||
} else {
|
||||
process.stdout.write(`${renderText(plan, artifactsDir, Math.floor(keepPerFamily), apply)}\n`);
|
||||
process.stdout.write(`${textOutput}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user