@@ -326,7 +326,7 @@ const tasks = Array.from(sourcesMap).flatMap(([type, definition]) => {
326326 }
327327 } )
328328
329- return gulp . src ( source , { ignore : [ '**/target/**' ] } )
329+ return gulp . src ( source , { ignore : [ '**/target/**' , '**/.camel-jbang/**' ] , allowEmpty : true } )
330330 . pipe ( filterFn )
331331 . pipe (
332332 map ( ( file , done ) => {
@@ -409,7 +409,7 @@ const tasks = Array.from(sourcesMap).flatMap(([type, definition]) => {
409409 return done ( )
410410 }
411411
412- return gulp . src ( source , { ignore : [ '**/target/**' ] } ) // asciidoc files
412+ return gulp . src ( source , { ignore : [ '**/target/**' , '**/.camel-jbang/**' ] , allowEmpty : true } ) // asciidoc files
413413 . pipe ( through2 . obj ( extractExamples ) ) // extracted example files
414414 // symlink links from a fixed directory, i.e. we could link to
415415 // the example files from `destination`, that would not work for
@@ -448,14 +448,42 @@ const tasks = Array.from(sourcesMap).flatMap(([type, definition]) => {
448448 return n
449449 }
450450
451+ // Wraps a stream-returning task with retry logic to handle ENOENT errors
452+ // from ephemeral directories (e.g. target/ temp dirs created/deleted by
453+ // tests running in parallel via mvnd during CI builds)
454+ const namedWithRetry = ( name , task , ...args ) => {
455+ const maxRetries = 3
456+ const { [ name ] : n } = { [ name ] : async ( ) => {
457+ for ( let attempt = 1 ; attempt <= maxRetries ; attempt ++ ) {
458+ try {
459+ await new Promise ( ( resolve , reject ) => {
460+ const stream = task ( ...args )
461+ stream . on ( 'end' , resolve )
462+ stream . on ( 'finish' , resolve )
463+ stream . on ( 'error' , reject )
464+ } )
465+ return
466+ } catch ( err ) {
467+ if ( err . code === 'ENOENT' && attempt < maxRetries ) {
468+ console . warn ( `⚠️ ENOENT in ${ name } (attempt ${ attempt } /${ maxRetries } ), retrying: ${ err . path } ` )
469+ await new Promise ( r => setTimeout ( r , 1000 ) )
470+ } else {
471+ throw err
472+ }
473+ }
474+ }
475+ } }
476+ return n
477+ }
478+
451479 // accumulates all tasks performed per _kind_.
452480 const allTasks = [ ]
453481
454482 if ( asciidoc && asciidoc . source ) {
455483 allTasks . push (
456484 gulp . series (
457485 named ( `clean:asciidoc:${ type } ` , clean , asciidoc . destination , asciidoc . keep ) ,
458- named ( `symlink:asciidoc:${ type } ` , createSymlinks , asciidoc . source , asciidoc . destination ) ,
486+ namedWithRetry ( `symlink:asciidoc:${ type } ` , createSymlinks , asciidoc . source , asciidoc . destination ) ,
459487 named ( `nav:asciidoc:${ type } ` , createNav , asciidoc . destination )
460488 )
461489 )
@@ -465,7 +493,7 @@ const tasks = Array.from(sourcesMap).flatMap(([type, definition]) => {
465493 allTasks . push (
466494 gulp . series (
467495 named ( `clean:image:${ type } ` , clean , image . destination , image . keep ) ,
468- named ( `symlink:image:${ type } ` , createSymlinks , image . source , image . destination )
496+ namedWithRetry ( `symlink:image:${ type } ` , createSymlinks , image . source , image . destination )
469497 )
470498 )
471499 }
@@ -474,15 +502,15 @@ const tasks = Array.from(sourcesMap).flatMap(([type, definition]) => {
474502 allTasks . push (
475503 gulp . series (
476504 named ( `clean:example:${ type } ` , clean , example . destination , [ 'json' , 'js' ] ) ,
477- named ( `symlink:example:${ type } ` , createExampleSymlinks , example . source , example . destination )
505+ namedWithRetry ( `symlink:example:${ type } ` , createExampleSymlinks , example . source , example . destination )
478506 )
479507 )
480508 }
481509
482510 if ( json ) {
483511 let tasks = [
484512 named ( `clean:json:${ type } ` , clean , json . destination , json . keep ) ,
485- named ( `symlink:json:${ type } ` , createSymlinks , json . source , json . destination , json . filter )
513+ namedWithRetry ( `symlink:json:${ type } ` , createSymlinks , json . source , json . destination , json . filter )
486514 ]
487515
488516 if ( asciidoc && ! asciidoc . source ) {
0 commit comments