diff --git a/bin/index.spec.ts b/bin/index.spec.ts index 4536a9d1..8586f7eb 100644 --- a/bin/index.spec.ts +++ b/bin/index.spec.ts @@ -185,7 +185,7 @@ describe('exiting conditions', () => { expect(exit.code).toBeGreaterThan(0); }); - it('is of success when a SIGINT is sent', async () => { + it('propagates SIGINT on POSIX when interrupted', async () => { // Windows doesn't support sending signals like on POSIX platforms. // However, in a console, processes can be interrupted with CTRL+C (like a SIGINT). // This is what we simulate here with the help of a wrapper application. @@ -204,7 +204,9 @@ describe('exiting conditions', () => { const lines = await child.getLogLines(); const exit = await child.exit; - expect(exit.code).toBe(0); + expect(exit).toMatchObject( + isWindows ? { code: 0, signal: null } : { code: null, signal: 'SIGINT' }, + ); expect(lines).toContainEqual( expect.stringMatching( createKillMessage( diff --git a/bin/index.ts b/bin/index.ts index 19ba5d28..f4dfc88f 100755 --- a/bin/index.ts +++ b/bin/index.ts @@ -225,6 +225,15 @@ assertDeprecated( 'Use commas as name separators instead.', ); +let interruptedBySigint = false; +if (process.platform !== 'win32') { + // On POSIX, exit with SIGINT after children finish so shell callers don't treat Ctrl+C as + // a successful run. + process.once('SIGINT', () => { + interruptedBySigint = true; + }); +} + // Get names of commands by the specified separator const names = (args.names || '').split(args.nameSeparator); @@ -269,6 +278,6 @@ concurrently( additionalArguments: args.passthroughArguments ? additionalArguments : undefined, }, ).result.then( - () => process.exit(0), - () => process.exit(1), + () => (interruptedBySigint ? process.kill(process.pid, 'SIGINT') : process.exit(0)), + () => (interruptedBySigint ? process.kill(process.pid, 'SIGINT') : process.exit(1)), );