@@ -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 ( / C h e c k s : \s + ( \d + ) \s + t o t a l , \s + ( \d + ) \s + p a s s , \s + ( \d + ) \s + f a i l / ) ;
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
388413function 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
0 commit comments