@@ -95,6 +95,17 @@ function removePathIfExists(targetPath) {
9595 fs . rmSync ( targetPath , { recursive : true , force : true } ) ;
9696}
9797
98+ function lstatIfExists ( targetPath ) {
99+ try {
100+ return fs . lstatSync ( targetPath ) ;
101+ } catch ( error ) {
102+ if ( error ?. code === "ENOENT" ) {
103+ return null ;
104+ }
105+ throw error ;
106+ }
107+ }
108+
98109function normalizePath ( filePath ) {
99110 return filePath . replaceAll ( "\\" , "/" ) ;
100111}
@@ -112,7 +123,15 @@ function listTreeEntries(rootName) {
112123 if ( ! current ) {
113124 continue ;
114125 }
115- const dirents = fs . readdirSync ( current , { withFileTypes : true } ) ;
126+ let dirents ;
127+ try {
128+ dirents = fs . readdirSync ( current , { withFileTypes : true } ) ;
129+ } catch ( error ) {
130+ if ( error ?. code === "ENOENT" ) {
131+ continue ;
132+ }
133+ throw error ;
134+ }
116135 for ( const dirent of dirents ) {
117136 const fullPath = path . join ( current , dirent . name ) ;
118137 const relativePath = normalizePath ( path . relative ( process . cwd ( ) , fullPath ) ) ;
@@ -159,7 +178,10 @@ function snapshotTree(rootName) {
159178 if ( ! current ) {
160179 continue ;
161180 }
162- const currentStats = fs . lstatSync ( current ) ;
181+ const currentStats = lstatIfExists ( current ) ;
182+ if ( ! currentStats ) {
183+ continue ;
184+ }
163185 stats . entries += 1 ;
164186 if ( currentStats . isDirectory ( ) ) {
165187 stats . directories += 1 ;
@@ -579,6 +601,14 @@ function buildRunNodeDeps(env) {
579601 } ;
580602}
581603
604+ export function shouldRefreshBuildStampForRestoredArtifacts ( params ) {
605+ return (
606+ params . skipBuild === true &&
607+ params . buildRequirement ?. shouldBuild === true &&
608+ params . buildRequirement . reason === "config_newer"
609+ ) ;
610+ }
611+
582612async function main ( ) {
583613 const options = parseArgs ( process . argv . slice ( 2 ) ) ;
584614 ensureDir ( options . outputDir ) ;
@@ -594,7 +624,19 @@ async function main() {
594624 writeBuildStamp ( { cwd : process . cwd ( ) } ) ;
595625 }
596626
597- const preflightBuildRequirement = resolveBuildRequirement ( buildRunNodeDeps ( process . env ) ) ;
627+ let preflightBuildRequirement = resolveBuildRequirement ( buildRunNodeDeps ( process . env ) ) ;
628+ if (
629+ shouldRefreshBuildStampForRestoredArtifacts ( {
630+ skipBuild : options . skipBuild ,
631+ buildRequirement : preflightBuildRequirement ,
632+ } )
633+ ) {
634+ // CI's skip-build path restores a built dist artifact after checkout.
635+ // Refresh the stamp so checkout mtimes for package/config files do not
636+ // force a duplicate build during the bounded gateway:watch window.
637+ writeBuildStamp ( { cwd : process . cwd ( ) } ) ;
638+ preflightBuildRequirement = resolveBuildRequirement ( buildRunNodeDeps ( process . env ) ) ;
639+ }
598640 if (
599641 preflightBuildRequirement . shouldBuild &&
600642 preflightBuildRequirement . reason === "dirty_watched_tree"
0 commit comments