From c2c7995a99fb54bb7795b4018d47e3b95bc8b1e0 Mon Sep 17 00:00:00 2001 From: Eric Wheeler Date: Sat, 11 Oct 2025 17:43:13 -0700 Subject: [PATCH] lib: fix: propagate exit codes from spawned processes The run-shared-scripts tool spawned child processes but never waited for them to complete or captured their exit codes, causing all scripts to appear successful even when they failed. This made it impossible for CI systems and build pipelines to detect failures. The run() function now returns a Promise that resolves with the child process exit code, and the bin script awaits this result and sets process.exitCode accordingly. - Modified lib/index.js: wrap spawn in Promise, resolve with exit code - Modified bin/rss.js: await run() and set process.exitCode - Return 0 for successful execution and dry-run mode - Return 1 when script name not found in rss configuration - Added example test scripts to verify exit code propagation Signed-off-by: Eric Wheeler --- bin/rss.js | 3 ++- example/package.json | 6 ++++++ example/scripts/test-failure.js | 4 ++++ example/scripts/test-success.js | 4 ++++ lib/index.js | 21 ++++++++++++++------- 5 files changed, 30 insertions(+), 8 deletions(-) create mode 100755 example/scripts/test-failure.js create mode 100755 example/scripts/test-success.js diff --git a/bin/rss.js b/bin/rss.js index 350c926..6c992fe 100755 --- a/bin/rss.js +++ b/bin/rss.js @@ -41,4 +41,5 @@ const cli = meow( const cmd = cli.input[0] || process.env.npm_lifecycle_event -run(cmd, args, cli.flags) +const exitCode = await run(cmd, args, cli.flags) +process.exitCode = exitCode diff --git a/example/package.json b/example/package.json index 6c82b8a..b82cbe7 100644 --- a/example/package.json +++ b/example/package.json @@ -19,6 +19,12 @@ "test": { "file": "./scripts/test.js" }, + "test-success": { + "file": "./scripts/test-success.js" + }, + "test-failure": { + "file": "./scripts/test-failure.js" + }, "pretest": "run-s -s clean:coverage", "start:1": "server --port {1}", "start:2": "server -a {1} --port {2}", diff --git a/example/scripts/test-failure.js b/example/scripts/test-failure.js new file mode 100755 index 0000000..c7005e9 --- /dev/null +++ b/example/scripts/test-failure.js @@ -0,0 +1,4 @@ +#!/usr/bin/env node + +console.log('test-failure: exiting with code 42') +process.exit(42) diff --git a/example/scripts/test-success.js b/example/scripts/test-success.js new file mode 100755 index 0000000..e6bdc87 --- /dev/null +++ b/example/scripts/test-success.js @@ -0,0 +1,4 @@ +#!/usr/bin/env node + +console.log('test-success: exiting with code 0') +process.exit(0) diff --git a/lib/index.js b/lib/index.js index fd52ece..a58acc1 100644 --- a/lib/index.js +++ b/lib/index.js @@ -131,13 +131,20 @@ export async function run(task, args, options) { ? fixFilePath(root, main) : await makeExecFile(root, task, main) - const child = spawn(exe, isFile ? args : [], { stdio: 'inherit' }) - - if (!isFile) { - child.on('exit', () => { fse.rm(exe) }) - } + return new Promise((resolve) => { + const child = spawn(exe, isFile ? args : [], { stdio: 'inherit' }) + + child.on('exit', (code) => { + if (!isFile) { + fse.rm(exe) + } + resolve(code ?? 0) + }) + }) } - } else { - console.error(`unknown script: [${task}]`) + return 0 } + + console.error(`unknown script: [${task}]`) + return 1 }