From d7106f5ede08c2cb2a28f9c4846e8a2ecbb6f5f3 Mon Sep 17 00:00:00 2001 From: Jason Jean Date: Thu, 29 May 2025 09:48:03 -0400 Subject: [PATCH] fix(core): handle run-commands targets with no commands (#31364) ## Current Behavior Nx hangs when here is a `run-commands` target with no commands. ## Expected Behavior Nx does not hang when there is a `run-commands` target with no commands. ## Related Issue(s) Fixes #31345 --- .../executors/run-commands/run-commands.impl.spec.ts | 12 ++++++++++++ .../src/executors/run-commands/run-commands.impl.ts | 6 ++++++ .../tasks-runner/running-tasks/noop-child-process.ts | 9 ++++++--- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/nx/src/executors/run-commands/run-commands.impl.spec.ts b/packages/nx/src/executors/run-commands/run-commands.impl.spec.ts index c2f7624634..0a475b78c0 100644 --- a/packages/nx/src/executors/run-commands/run-commands.impl.spec.ts +++ b/packages/nx/src/executors/run-commands/run-commands.impl.spec.ts @@ -22,6 +22,18 @@ describe('Run Commands', () => { jest.clearAllMocks(); }); + it('should handle empty commands array', async () => { + const result = await runCommands( + { + commands: [], + __unparsed__: [], + }, + context + ); + expect(result.success).toEqual(true); + expect(result.terminalOutput).toEqual(''); + }); + it('should interpolate provided --args', async () => { const f = fileSync().name; const result = await runCommands( diff --git a/packages/nx/src/executors/run-commands/run-commands.impl.ts b/packages/nx/src/executors/run-commands/run-commands.impl.ts index ec1e9f7619..87dbc89b1f 100644 --- a/packages/nx/src/executors/run-commands/run-commands.impl.ts +++ b/packages/nx/src/executors/run-commands/run-commands.impl.ts @@ -2,6 +2,7 @@ import * as yargsParser from 'yargs-parser'; import { ExecutorContext } from '../../config/misc-interfaces'; import { isTuiEnabled } from '../../tasks-runner/is-tui-enabled'; import { PseudoTerminal } from '../../tasks-runner/pseudo-terminal'; +import { NoopChildProcess } from '../../tasks-runner/running-tasks/noop-child-process'; import { ParallelRunningTasks, runSingleCommandWithPseudoTerminal, @@ -117,6 +118,11 @@ export async function runCommands( ); } + // Handle empty commands array - return immediately with success + if (normalized.commands.length === 0) { + return new NoopChildProcess({ code: 0, terminalOutput: '' }); + } + const isSingleCommand = normalized.commands.length === 1; const usePseudoTerminal = diff --git a/packages/nx/src/tasks-runner/running-tasks/noop-child-process.ts b/packages/nx/src/tasks-runner/running-tasks/noop-child-process.ts index 173acc121d..8f222d1fbc 100644 --- a/packages/nx/src/tasks-runner/running-tasks/noop-child-process.ts +++ b/packages/nx/src/tasks-runner/running-tasks/noop-child-process.ts @@ -1,4 +1,3 @@ -import { Serializable } from 'child_process'; import { RunningTask } from './running-task'; export class NoopChildProcess implements RunningTask { @@ -14,7 +13,11 @@ export class NoopChildProcess implements RunningTask { return; } - onExit(cb: (code: number) => void): void { - cb(this.results.code); + onExit(cb: (code: number, terminalOutput: string) => void): void { + cb(this.results.code, this.results.terminalOutput); + } + + onOutput(cb: (terminalOutput: string) => void): void { + cb(this.results.terminalOutput); } }