Skip to content

Commit d758510

Browse files
themr0cclaude
andauthored
[RHDHBUGS-2954]: CQA check failures should fail the build (#2055)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b9ec14f commit d758510

File tree

3 files changed

+59
-9
lines changed

3 files changed

+59
-9
lines changed

.github/workflows/content-quality-assessment.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ jobs:
121121
cd pr-content
122122
git remote add base https://github.com/${{ github.event.pull_request.base.repo.full_name }}.git
123123
git fetch base ${{ github.event.pull_request.base.ref }}
124-
OUTPUT=$(node build/scripts/cqa/index.js --all 2>&1 || true)
124+
OUTPUT=$(node build/scripts/cqa/index.js --all 2>&1)
125125
echo "output<<EOF" >> $GITHUB_OUTPUT
126126
echo "$OUTPUT" >> $GITHUB_OUTPUT
127127
echo "EOF" >> $GITHUB_OUTPUT

build/scripts/build-orchestrator.js

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,31 @@ async function traceUrlToSource(url, repoRoot) {
383383
return output.trim().split('\n').map(f => f.replace(repoRoot + '/', ''));
384384
}
385385

386+
// ── CQA content quality assessment ─────────────────────────────────────────
387+
388+
async function runCqa(repoRoot, verbose) {
389+
const cqaScript = join(__dirname, 'cqa', 'index.js');
390+
const { code, duration, output } = await spawnCapture('node', [cqaScript, '--all'], {
391+
cwd: repoRoot, verbose, groupName: 'CQA',
392+
});
393+
394+
// Parse summary line from output: "Checks: 19 total, 19 pass, 0 fail"
395+
let checksTotal = 0, checksPass = 0, checksFail = 0;
396+
const summaryMatch = output.match(/Checks:\s+(\d+)\s+total,\s+(\d+)\s+pass,\s+(\d+)\s+fail/);
397+
if (summaryMatch) {
398+
checksTotal = Number.parseInt(summaryMatch[1], 10);
399+
checksPass = Number.parseInt(summaryMatch[2], 10);
400+
checksFail = Number.parseInt(summaryMatch[3], 10);
401+
}
402+
403+
return {
404+
status: code === 0 ? 'passed' : 'failed',
405+
duration,
406+
output,
407+
stats: { total: checksTotal, pass: checksPass, fail: checksFail },
408+
};
409+
}
410+
386411
// ── Index HTML generation ────────────────────────────────────────────────────
387412

388413
function getReleaseNotesLink(branch) {
@@ -497,7 +522,16 @@ function printLycheeSummary(lycheeResult) {
497522
console.log(lastLines.map(l => ' ' + l).join('\n'));
498523
}
499524

500-
function printSummary(results, lycheeResult, patterns, totalDuration) {
525+
function printCqaSummary(cqaResult) {
526+
console.log('\n=== CQA (Content Quality Assessment) ===');
527+
const s = cqaResult.stats || {};
528+
console.log(`Checks: ${s.total} total, ${s.pass} pass, ${s.fail} fail`);
529+
if (cqaResult.status === 'failed') {
530+
console.log('CQA validation failed — run `node build/scripts/cqa/index.js --all` for details');
531+
}
532+
}
533+
534+
function printSummary(results, lycheeResult, cqaResult, patterns, totalDuration) {
501535
const passed = results.filter(r => r.status === 'passed').length;
502536
const failed = results.filter(r => r.status === 'failed').length;
503537

@@ -511,11 +545,15 @@ function printSummary(results, lycheeResult, patterns, totalDuration) {
511545
if (lycheeResult) {
512546
printLycheeSummary(lycheeResult);
513547
}
548+
549+
if (cqaResult) {
550+
printCqaSummary(cqaResult);
551+
}
514552
}
515553

516554
// ── JSON report ──────────────────────────────────────────────────────────────
517555

518-
function writeReport(branch, results, lycheeResult, concurrency, totalDuration, repoRoot) {
556+
function writeReport(branch, results, lycheeResult, cqaResult, concurrency, totalDuration, repoRoot) {
519557
const passed = results.filter(r => r.status === 'passed').length;
520558
const failed = results.filter(r => r.status === 'failed').length;
521559

@@ -541,6 +579,10 @@ function writeReport(branch, results, lycheeResult, concurrency, totalDuration,
541579
stats: lycheeResult.stats || {},
542580
errors: lycheeResult.errors || [],
543581
} : null,
582+
cqa: cqaResult ? {
583+
status: cqaResult.status,
584+
stats: cqaResult.stats || {},
585+
} : null,
544586
};
545587

546588
const reportPath = join(repoRoot, 'build-report.json');
@@ -616,16 +658,22 @@ async function main() {
616658
lycheeResult.errors = classifyErrors(lycheeResult.output, patterns);
617659
}
618660

661+
// Run CQA content quality assessment
662+
console.log('\nRunning CQA content quality assessment...');
663+
const cqaResult = await runCqa(repoRoot, args.verbose);
664+
619665
const totalDuration = Math.round((Date.now() - totalStart) / 1000);
620666

621667
// Print summary
622-
printSummary(buildResults, lycheeResult, patterns, totalDuration);
668+
printSummary(buildResults, lycheeResult, cqaResult, patterns, totalDuration);
623669

624670
// Write JSON report
625-
writeReport(args.branch, buildResults, lycheeResult, args.jobs, totalDuration, repoRoot);
671+
writeReport(args.branch, buildResults, lycheeResult, cqaResult, args.jobs, totalDuration, repoRoot);
626672

627-
// Exit with error if any builds or lychee failed
628-
const hasFailed = buildResults.some(r => r.status === 'failed') || lycheeResult.status === 'failed';
673+
// Exit with error if any builds, lychee, or CQA failed
674+
const hasFailed = buildResults.some(r => r.status === 'failed')
675+
|| lycheeResult.status === 'failed'
676+
|| cqaResult.status === 'failed';
629677
process.exit(hasFailed ? 1 : 0);
630678
}
631679

build/scripts/cqa/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ async function runAllChecks(checks, titles, fixMode) {
139139

140140
// Output in alphabetical order by check ID
141141
const sortedChecks = [...checks].sort((a, b) => a.id.localeCompare(b.id));
142-
printAllChecksReport(sortedChecks, results, fixMode);
142+
return printAllChecksReport(sortedChecks, results, fixMode);
143143
}
144144

145145
async function collectAllResults(checks, titles, fixMode) {
@@ -236,6 +236,7 @@ function printAllChecksReport(sortedChecks, results, fixMode) {
236236
}
237237

238238
printFinalSummary({ checksPass, checksFail, totalAutofixable, totalManual, totalDelegated, totalFixed, fixMode });
239+
return { checksPass, checksFail };
239240
}
240241

241242
function printFinalSummary({ checksPass, checksFail, totalAutofixable, totalManual, totalDelegated, totalFixed, fixMode }) {
@@ -384,7 +385,8 @@ async function main() {
384385
}
385386

386387
if (allMode) {
387-
await runAllChecks(checks, titles, fixMode);
388+
const { checksFail } = await runAllChecks(checks, titles, fixMode);
389+
process.exit(checksFail > 0 ? 1 : 0);
388390
} else {
389391
runPerTitleMode(checks, titles, fixMode);
390392
}

0 commit comments

Comments
 (0)