Files
ben-to/scripts/ci/pr-quality-report.mjs
2026-07-21 16:50:58 +02:00

98 lines
3.2 KiB
JavaScript

import { readFileSync, existsSync, writeFileSync } from "node:fs";
import path from "node:path";
import { globSync } from "glob";
const base = process.argv[2] ?? ".";
const outFile = process.argv[3] ?? "pr-quality-body.md";
function readJson(p) {
return JSON.parse(readFileSync(p, "utf8"));
}
const lines = [];
const covPath = path.join(base, "coverage", "coverage-summary.json");
if (existsSync(covPath)) {
const c = readJson(covPath);
const t = c.total;
lines.push("## Couverture (packages métier Vitest)");
lines.push(
`| Métrique | % |`,
`|----------|---|`,
`| Lignes | ${t.lines.pct.toFixed(2)} |`,
`| Branches | ${t.branches.pct.toFixed(2)} |`,
`| Fonctions | ${t.functions.pct.toFixed(2)} |`,
""
);
} else {
lines.push("## Couverture", "_Résumé indisponible (fichier coverage-summary manquant)._", "", "");
}
const a11yPath = path.join(base, "e2e", "a11y-summary.json");
if (existsSync(a11yPath)) {
const a = readJson(a11yPath);
lines.push("## Accessibilité (Axe / Playwright)");
lines.push(`- Violations : **${a.axeViolationCount}**`);
if (a.axeViolationIds?.length) lines.push(`- Ids : ${a.axeViolationIds.join(", ")}`);
lines.push("");
} else {
lines.push("## Accessibilité", "_Résumé Axe indisponible._", "", "");
}
const perfPath = path.join(base, "e2e", "perf-summary.json");
if (existsSync(perfPath)) {
const p = readJson(perfPath);
lines.push("## Performance (timings navigation)");
lines.push("```json");
lines.push(JSON.stringify(p.navigationTiming ?? p, null, 2));
lines.push("```", "");
}
const auditPath = path.join(base, "audit.json");
if (existsSync(auditPath)) {
const audit = readJson(auditPath);
const vulns = audit.vulnerabilities ?? {};
const metaV = audit.metadata?.vulnerabilities;
lines.push("## Sécurité (npm audit)");
if (metaV) {
lines.push(
`- Agrégat : critical ${metaV.critical}, high ${metaV.high}, moderate ${metaV.moderate}, low ${metaV.low}, info ${metaV.info}, total ${metaV.total}`
);
} else {
let high = 0;
let critical = 0;
for (const v of Object.values(vulns)) {
if (v.severity === "high") high++;
if (v.severity === "critical") critical++;
}
lines.push(`- Critical : ${critical}, High : ${high}`);
}
lines.push(`- Détail des paquets affectés : ${Object.keys(vulns).length}`, "");
} else {
lines.push("## Sécurité", "_npm audit non disponible._", "", "");
}
const lhr = globSync(path.join(base, "lhci", "**", "lhr-*.json").replace(/\\/g, "/"))[0];
if (lhr && existsSync(lhr)) {
const rep = readJson(lhr);
const cats = rep.categories ?? {};
const score = (c) => (c?.score != null ? Math.round(c.score * 100) : "n/a");
lines.push("## Lighthouse / SEO");
lines.push(
`| Catégorie | Score |`,
`|-----------|-------|`,
`| Performance | ${score(cats.performance)} |`,
`| Accessibilité | ${score(cats.accessibility)} |`,
`| Bonnes pratiques | ${score(cats["best-practices"])} |`,
`| SEO | ${score(cats.seo)} |`,
""
);
} else {
lines.push("## Lighthouse / SEO", "_Rapport LHCI indisponible._", "", "");
}
lines.push("---", "_Rapport généré par CI Ben-to._");
writeFileSync(outFile, lines.join("\n"), "utf8");
console.log(`Wrote ${outFile}`);