n8n/packages/testing/code-health/src/cli.ts
Declan Carroll 6f365bf3c8
ci: Enforce migration ordering in code-health rule (no-changelog) (#30511)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 10:12:55 +00:00

105 lines
2.4 KiB
JavaScript

#!/usr/bin/env node
import {
toJSON,
loadBaseline,
generateBaseline,
saveBaseline,
filterReportByBaseline,
} from '@n8n/rules-engine';
import * as fs from 'node:fs';
import * as path from 'node:path';
import { parseArgs } from './cli/arg-parser.js';
import type { CodeHealthContext } from './context.js';
import { createDefaultRunner } from './index.js';
const BASELINE_FILENAME = '.code-health-baseline.json';
async function main(): Promise<void> {
const args = process.argv.slice(2);
const options = parseArgs(args);
const rootDir = findMonorepoRoot(process.cwd());
const baselinePath = path.join(rootDir, BASELINE_FILENAME);
const context: CodeHealthContext = {
rootDir,
changedFiles: parseChangedFiles(process.env.CODE_HEALTH_CHANGED_FILES),
};
const runner = createDefaultRunner();
if (options.command === 'rules') {
console.log(JSON.stringify(runner.getRuleDetails(), null, 2));
return;
}
if (options.rule) {
runner.enableOnly([options.rule]);
}
let report = options.rule
? await runner.runRule(options.rule, context, rootDir)
: await runner.run(context, rootDir);
if (!report) {
console.error(JSON.stringify({ error: `Unknown rule: ${options.rule}` }));
process.exit(1);
}
if (options.command === 'baseline') {
const baseline = generateBaseline(report, rootDir);
saveBaseline(baseline, baselinePath);
console.log(
JSON.stringify(
{
action: 'baseline-created',
totalViolations: baseline.totalViolations,
path: baselinePath,
},
null,
2,
),
);
return;
}
if (!options.ignoreBaseline && fs.existsSync(baselinePath)) {
const baseline = loadBaseline(baselinePath);
if (baseline) {
report = filterReportByBaseline(report, baseline, rootDir);
}
}
console.log(toJSON(report, rootDir));
if (report.summary.totalViolations > 0) {
process.exit(1);
}
}
function parseChangedFiles(raw: string | undefined): string[] | undefined {
if (!raw) return undefined;
const entries = raw
.split(/[\n,]/)
.map((entry) => entry.trim())
.filter((entry) => entry.length > 0);
return entries.length > 0 ? entries : undefined;
}
function findMonorepoRoot(startDir: string): string {
let dir = startDir;
while (dir !== path.dirname(dir)) {
if (fs.existsSync(path.join(dir, 'pnpm-workspace.yaml'))) {
return dir;
}
dir = path.dirname(dir);
}
return startDir;
}
main().catch((error) => {
console.error(JSON.stringify({ error: (error as Error).message }));
process.exit(2);
});