99 * node build/scripts/build-orchestrator.js -b main
1010 * node build/scripts/build-orchestrator.js -b pr-123 --verbose
1111 * node build/scripts/build-orchestrator.js -b main --jobs 4
12+ * node build/scripts/build-orchestrator.js -b main --no-cqa --no-lychee
1213 */
1314
1415import { existsSync , readFileSync , writeFileSync , mkdirSync , rmSync , readdirSync , renameSync , copyFileSync } from 'node:fs' ;
1516import { resolve , dirname , join } from 'node:path' ;
1617import { spawn } from 'node:child_process' ;
1718import { cpus } from 'node:os' ;
1819import { fileURLToPath } from 'node:url' ;
19- import { get as httpsGet } from 'node:https' ;
2020const __filename = fileURLToPath ( import . meta. url ) ;
2121const __dirname = dirname ( __filename ) ;
2222
@@ -32,12 +32,14 @@ const SAFE_PATH = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
3232// ── Argument parsing ─────────────────────────────────────────────────────────
3333
3434function parseArgs ( argv ) {
35- const args = { branch : 'main' , verbose : false , jobs : cpus ( ) . length } ;
35+ const args = { branch : 'main' , verbose : false , jobs : cpus ( ) . length , lychee : true , cqa : true } ;
3636 for ( let i = 2 ; i < argv . length ; i ++ ) {
3737 switch ( argv [ i ] ) {
3838 case '-b' : args . branch = argv [ ++ i ] ; break ;
3939 case '--verbose' : args . verbose = true ; break ;
4040 case '--jobs' : args . jobs = Number . parseInt ( argv [ ++ i ] , 10 ) ; break ;
41+ case '--no-lychee' : args . lychee = false ; break ;
42+ case '--no-cqa' : args . cqa = false ; break ;
4143 }
4244 }
4345 return args ;
@@ -437,51 +439,6 @@ function generateBranchIndex(branch, results, repoRoot) {
437439 writeFileSync ( join ( indexDir , 'index.html' ) , html ) ;
438440}
439441
440- function fetchUrl ( url ) {
441- return new Promise ( ( resolve , reject ) => {
442- httpsGet ( url , ( res ) => {
443- if ( res . statusCode >= 300 && res . statusCode < 400 && res . headers . location ) {
444- fetchUrl ( res . headers . location ) . then ( resolve , reject ) ;
445- return ;
446- }
447- if ( res . statusCode !== 200 ) {
448- res . resume ( ) ;
449- reject ( new Error ( `HTTP ${ res . statusCode } ` ) ) ;
450- return ;
451- }
452- let data = '' ;
453- res . on ( 'data' , ( chunk ) => { data += chunk ; } ) ;
454- res . on ( 'end' , ( ) => resolve ( data ) ) ;
455- res . on ( 'error' , reject ) ;
456- } ) . on ( 'error' , reject ) ;
457- } ) ;
458- }
459-
460- async function updateRootIndex ( branch , repoRoot ) {
461- const isPR = branch . startsWith ( 'pr-' ) ;
462- const indexFile = isPR ? 'pulls.html' : 'index.html' ;
463- const indexPath = join ( repoRoot , 'titles-generated' , indexFile ) ;
464- const url = `${ PAGES_BASE } /${ indexFile } ` ;
465-
466- // Fetch existing index from GitHub Pages
467- try {
468- const data = await fetchUrl ( url ) ;
469- writeFileSync ( indexPath , data ) ;
470- } catch {
471- // If fetch fails, create a minimal file
472- writeFileSync ( indexPath , '<html><body><ul>\n</ul></body></html>' ) ;
473- }
474-
475- const content = readFileSync ( indexPath , 'utf8' ) ;
476- const link = `./${ branch } /index.html` ;
477- if ( ! content . includes ( link ) ) {
478- console . log ( `Building root index for ${ branch } in titles-generated/${ indexFile } ...` ) ;
479- const entry = `<li><a href=${ link } >${ branch } </a></li>` ;
480- const updated = content . replace ( '</ul>' , `${ entry } \n</ul>` ) ;
481- writeFileSync ( indexPath , updated ) ;
482- }
483- }
484-
485442// ── Summary output ───────────────────────────────────────────────────────────
486443
487444function printFailedTitle ( r ) {
@@ -653,31 +610,39 @@ async function main() {
653610 // Generate branch index HTML (only for passed titles)
654611 generateBranchIndex ( args . branch , buildResults , repoRoot ) ;
655612
656- // Update root index
657- await updateRootIndex ( args . branch , repoRoot ) ;
658-
659613 // Run lychee link validation
660- console . log ( '\nRunning link validation (lychee)...' ) ;
661- const lycheeResult = await runLychee ( repoRoot , args . branch , args . verbose ) ;
662- if ( lycheeResult . errors . length === 0 ) {
663- lycheeResult . errors = classifyErrors ( lycheeResult . output , patterns ) ;
614+ const skippedResult = { status : 'skipped' , duration : 0 , output : '' , stats : { total : 0 , successful : 0 , errors : 0 , excludes : 0 , timeouts : 0 } , errors : [ ] } ;
615+ let lycheeResult ;
616+ if ( args . lychee ) {
617+ console . log ( '\nRunning link validation (lychee)...' ) ;
618+ lycheeResult = await runLychee ( repoRoot , args . branch , args . verbose ) ;
619+ if ( lycheeResult . errors . length === 0 ) {
620+ lycheeResult . errors = classifyErrors ( lycheeResult . output , patterns ) ;
621+ }
622+ } else {
623+ console . log ( '\nSkipping link validation (--no-lychee)' ) ;
624+ lycheeResult = { ...skippedResult } ;
664625 }
665626
666627 // Run CQA content quality assessment
667- // Skip when CQA_RUNNING env is set (CQA-14 recursion guard)
668- const cqaResult = ( process . env . CQA_RUNNING )
669- ? { status : 'skipped' , duration : 0 , output : '' , stats : { total : 0 , pass : 0 , fail : 0 } }
670- : await ( async ( ) => {
671- console . log ( '\nRunning CQA content quality assessment...' ) ;
672- return runCqa ( repoRoot , args . verbose ) ;
673- } ) ( ) ;
628+ const skippedCqa = { status : 'skipped' , duration : 0 , output : '' , stats : { total : 0 , pass : 0 , fail : 0 } } ;
629+ let cqaResult ;
630+ if ( ! args . cqa || process . env . CQA_RUNNING ) {
631+ if ( ! args . cqa ) console . log ( '\nSkipping CQA (--no-cqa)' ) ;
632+ cqaResult = skippedCqa ;
633+ } else {
634+ // Write preliminary report so CQA-14 can read lychee results without rebuilding
635+ const pendingCqa = { status : 'pending' , duration : 0 , output : '' , stats : { total : 0 , pass : 0 , fail : 0 } } ;
636+ writeReport ( args . branch , buildResults , lycheeResult , pendingCqa , args . jobs , 0 , repoRoot ) ;
637+
638+ console . log ( '\nRunning CQA content quality assessment...' ) ;
639+ process . env . CQA_RUNNING = '1' ;
640+ cqaResult = await runCqa ( repoRoot , args . verbose ) ;
641+ delete process . env . CQA_RUNNING ;
642+ }
674643
675644 const totalDuration = Math . round ( ( Date . now ( ) - totalStart ) / 1000 ) ;
676-
677- // Print summary
678645 printSummary ( buildResults , lycheeResult , cqaResult , patterns , totalDuration ) ;
679-
680- // Write JSON report
681646 writeReport ( args . branch , buildResults , lycheeResult , cqaResult , args . jobs , totalDuration , repoRoot ) ;
682647
683648 // Exit with error if any builds, lychee, or CQA failed
0 commit comments