@@ -27,6 +27,25 @@ function commandExists(cmd) {
2727 return spawnSync ( 'bash' , [ '-lc' , `command -v ${ cmd } >/dev/null 2>&1` ] , { stdio : 'ignore' } ) . status === 0 ;
2828}
2929
30+ function runWithHardTimeout ( { cmd, args, cwd, env, encoding, maxBuffer, timeoutMs } ) {
31+ if ( commandExists ( 'timeout' ) ) {
32+ const seconds = Math . max ( 1 , Math . ceil ( timeoutMs / 1000 ) ) ;
33+ return spawnSync ( 'timeout' , [ '--signal=KILL' , '--kill-after=30s' , `${ seconds } s` , cmd , ...args ] , {
34+ cwd,
35+ encoding,
36+ env,
37+ maxBuffer,
38+ } ) ;
39+ }
40+ return spawnSync ( cmd , args , {
41+ cwd,
42+ encoding,
43+ env,
44+ maxBuffer,
45+ timeout : timeoutMs ,
46+ } ) ;
47+ }
48+
3049function currentTarget ( ) {
3150 const os = process . platform === 'linux' ? 'linux' : process . platform === 'darwin' ? 'darwin' : '' ;
3251 const arch = process . arch === 'x64' ? 'x64' : process . arch === 'arm64' ? 'arm64' : '' ;
@@ -65,25 +84,20 @@ test('compiled happier and server binaries execute from isolated cwd', async (t)
6584 const repoRoot = resolve ( fileURLToPath ( new URL ( '../../..' , import . meta. url ) ) ) ;
6685 const version = `0.0.0-smoke.${ Date . now ( ) } ` ;
6786
68- const buildCli = spawnSync (
69- process . execPath ,
70- [
87+ const buildCli = runWithHardTimeout ( {
88+ cmd : process . execPath ,
89+ args : [
7190 'scripts/release/build-cli-binaries.mjs' ,
7291 '--channel=preview' ,
7392 `--version=${ version } ` ,
7493 `--targets=${ target } ` ,
7594 ] ,
76- {
77- cwd : repoRoot ,
78- encoding : 'utf-8' ,
79- env : { ...process . env } ,
80- // `inherit` makes it easier to read interactively, but on CI failures we need the full output.
81- // Increase buffer because build logs can be large.
82- maxBuffer : 50 * 1024 * 1024 ,
83- // If this ever hangs on CI, fail with a clear timeout rather than blocking the entire suite.
84- timeout : 15 * 60 * 1000 ,
85- }
86- ) ;
95+ cwd : repoRoot ,
96+ encoding : 'utf-8' ,
97+ env : { ...process . env } ,
98+ maxBuffer : 50 * 1024 * 1024 ,
99+ timeoutMs : 15 * 60 * 1000 ,
100+ } ) ;
87101 assert . equal ( buildCli . status , 0 , formatSpawnSyncResult ( buildCli ) ) ;
88102
89103 const cliArtifactPath = join ( repoRoot , 'dist' , 'release-assets' , 'cli' , `happier-v${ version } -${ target } .tar.gz` ) ;
@@ -107,23 +121,20 @@ test('compiled happier and server binaries execute from isolated cwd', async (t)
107121 ) ;
108122
109123 if ( isLinuxTarget ( target ) ) {
110- const buildServer = spawnSync (
111- process . execPath ,
112- [
124+ const buildServer = runWithHardTimeout ( {
125+ cmd : process . execPath ,
126+ args : [
113127 'scripts/release/build-server-binaries.mjs' ,
114128 '--channel=preview' ,
115129 `--version=${ version } ` ,
116130 `--targets=${ target } ` ,
117131 ] ,
118- {
119- cwd : repoRoot ,
120- encoding : 'utf-8' ,
121- env : { ...process . env } ,
122- maxBuffer : 50 * 1024 * 1024 ,
123- // If this ever hangs on CI, fail with a clear timeout rather than blocking the entire suite.
124- timeout : 15 * 60 * 1000 ,
125- }
126- ) ;
132+ cwd : repoRoot ,
133+ encoding : 'utf-8' ,
134+ env : { ...process . env } ,
135+ maxBuffer : 50 * 1024 * 1024 ,
136+ timeoutMs : 15 * 60 * 1000 ,
137+ } ) ;
127138 assert . equal ( buildServer . status , 0 , formatSpawnSyncResult ( buildServer ) ) ;
128139
129140 const serverArtifactPath = join ( repoRoot , 'dist' , 'release-assets' , 'server' , `happier-server-v${ version } -${ target } .tar.gz` ) ;
0 commit comments