From 10e906b95947f415366a6522e262c168a14acd32 Mon Sep 17 00:00:00 2001 From: Emily Xiong Date: Fri, 16 Feb 2024 00:21:51 -0500 Subject: [PATCH] feat(core): run commands directly --- docs/generated/devkit/Task.md | 18 +++ .../packages/nx/executors/run-commands.json | 6 + e2e/webpack/src/webpack.test.ts | 1 - packages/nx/src/config/task-graph.ts | 8 ++ .../run-commands/run-commands.impl.ts | 122 ++++++++++++------ .../nx/src/executors/run-commands/schema.json | 6 + .../tasks-runner/create-task-graph.spec.ts | 42 ++++++ .../nx/src/tasks-runner/create-task-graph.ts | 6 +- .../src/tasks-runner/default-tasks-runner.ts | 1 - .../forked-process-task-runner.ts | 4 +- .../nx/src/tasks-runner/task-orchestrator.ts | 64 +++++++-- 11 files changed, 218 insertions(+), 60 deletions(-) diff --git a/docs/generated/devkit/Task.md b/docs/generated/devkit/Task.md index 686bac2a5e6f20..bc638023fc5a91 100644 --- a/docs/generated/devkit/Task.md +++ b/docs/generated/devkit/Task.md @@ -8,9 +8,11 @@ A representation of the invocation of an Executor - [cache](../../devkit/documents/Task#cache): boolean - [endTime](../../devkit/documents/Task#endtime): number +- [executor](../../devkit/documents/Task#executor): string - [hash](../../devkit/documents/Task#hash): string - [hashDetails](../../devkit/documents/Task#hashdetails): Object - [id](../../devkit/documents/Task#id): string +- [options](../../devkit/documents/Task#options): Record - [outputs](../../devkit/documents/Task#outputs): string[] - [overrides](../../devkit/documents/Task#overrides): any - [projectRoot](../../devkit/documents/Task#projectroot): string @@ -35,6 +37,14 @@ Unix timestamp of when a Batch Task ends --- +### executor + +• `Optional` **executor**: `string` + +the executor to use to run the task + +--- + ### hash • `Optional` **hash**: `string` @@ -68,6 +78,14 @@ Unique ID --- +### options + +• `Optional` **options**: `Record`\<`string`, `any`\> + +The options of the executor + +--- + ### outputs • **outputs**: `string`[] diff --git a/docs/generated/packages/nx/executors/run-commands.json b/docs/generated/packages/nx/executors/run-commands.json index b4717441fd9446..c756fad9a41db9 100644 --- a/docs/generated/packages/nx/executors/run-commands.json +++ b/docs/generated/packages/nx/executors/run-commands.json @@ -121,6 +121,12 @@ "items": { "type": "string" }, "$default": { "$source": "unparsed" }, "x-priority": "internal" + }, + "mode": { + "type": "string", + "description": "Mode to trigger the command.", + "enum": ["run-one", "run-many"], + "x-priority": "internal" } }, "additionalProperties": true, diff --git a/e2e/webpack/src/webpack.test.ts b/e2e/webpack/src/webpack.test.ts index 9837e29e1efa15..240bcc65bee872 100644 --- a/e2e/webpack/src/webpack.test.ts +++ b/e2e/webpack/src/webpack.test.ts @@ -1,5 +1,4 @@ import { - checkFilesExist, cleanupProject, newProject, rmDist, diff --git a/packages/nx/src/config/task-graph.ts b/packages/nx/src/config/task-graph.ts index 573f691ccc220d..49b585eb64e360 100644 --- a/packages/nx/src/config/task-graph.ts +++ b/packages/nx/src/config/task-graph.ts @@ -27,6 +27,14 @@ export interface Task { * Overrides for the configured options of the target */ overrides: any; + /** + * the executor to use to run the task + */ + executor?: string; + /** + * The options of the executor + */ + options?: Record; /** * The outputs the task may produce 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 e1e7b4d5c4cac7..a81bc2d9a7e03e 100644 --- a/packages/nx/src/executors/run-commands/run-commands.impl.ts +++ b/packages/nx/src/executors/run-commands/run-commands.impl.ts @@ -51,6 +51,7 @@ export interface RunCommandsOptions extends Json { args?: string | string[]; envFile?: string; __unparsed__: string[]; + mode?: 'run-one' | 'run-many'; } const propKeys = [ @@ -80,6 +81,7 @@ export default async function ( context: ExecutorContext ): Promise<{ success: boolean; + terminalOutput: string; }> { await loadEnvVars(options.envFile); const normalized = normalizeOptions(options); @@ -100,10 +102,10 @@ export default async function ( } try { - const success = options.parallel + const result = options.parallel ? await runInParallel(normalized, context) : await runSerially(normalized, context); - return { success }; + return result; } catch (e) { if (process.env.NX_VERBOSE_LOGGING === 'true') { console.error(e); @@ -117,7 +119,11 @@ export default async function ( async function runInParallel( options: NormalizedRunCommandsOptions, context: ExecutorContext -) { +): Promise<{ success: boolean; terminalOutput: string }> { + console.log( + 'runInParallel calculateCwd(options.cwd, context),', + calculateCwd(options.cwd, context) + ); const procs = options.commands.map((c) => createProcess( c, @@ -125,35 +131,48 @@ async function runInParallel( options.color, calculateCwd(options.cwd, context), options.env ?? {}, - true - ).then((result) => ({ + true, + options.mode + ).then((result: { success: boolean; terminalOutput: string }) => ({ result, command: c.command, })) ); if (options.readyWhen) { - const r = await Promise.race(procs); - if (!r.result) { + const r: { + result: { success: boolean; terminalOutput: string }; + command: string; + } = await Promise.race(procs); + if (!r.result.success) { process.stderr.write( `Warning: command "${r.command}" exited with non-zero status code` ); - return false; + return { success: false, terminalOutput: r.result.terminalOutput }; } else { - return true; + return { success: true, terminalOutput: r.result.terminalOutput }; } } else { - const r = await Promise.all(procs); - const failed = r.filter((v) => !v.result); + const r: { + result: { success: boolean; terminalOutput: string }; + command: string; + }[] = await Promise.all(procs); + const failed = r.filter((v) => !v.result.success); if (failed.length > 0) { failed.forEach((f) => { process.stderr.write( `Warning: command "${f.command}" exited with non-zero status code` ); }); - return false; + return { + success: false, + terminalOutput: r.map((f) => f.result.terminalOutput).join(''), + }; } else { - return true; + return { + success: true, + terminalOutput: r.map((f) => f.result.terminalOutput).join(''), + }; } } } @@ -182,31 +201,40 @@ function normalizeOptions( c.forwardAllArgs ?? true ); }); + console.log(options); return options as NormalizedRunCommandsOptions; } async function runSerially( options: NormalizedRunCommandsOptions, context: ExecutorContext -) { +): Promise<{ success: boolean; terminalOutput: string }> { + let terminalOutput = ''; for (const c of options.commands) { - const success = await createProcess( - c, - undefined, - options.color, - calculateCwd(options.cwd, context), - options.env ?? {}, - false + console.log( + 'runSerially calculateCwd(options.cwd, context),', + calculateCwd(options.cwd, context) ); - if (!success) { + const result: { success: boolean; terminalOutput: string } = + await createProcess( + c, + undefined, + options.color, + calculateCwd(options.cwd, context), + options.env ?? {}, + false, + options.mode + ); + terminalOutput += result.terminalOutput; + if (!result.success) { process.stderr.write( `Warning: command "${c.command}" exited with non-zero status code` ); - return false; + return { success: false, terminalOutput: result.terminalOutput }; } } - return true; + return { success: true, terminalOutput: terminalOutput }; } async function createProcess( @@ -220,8 +248,9 @@ async function createProcess( color: boolean, cwd: string, env: Record, - isParallel: boolean -): Promise { + isParallel: boolean, + mode: 'run-one' | 'run-many' = 'run-one' +): Promise<{ success: boolean; terminalOutput: string }> { env = processEnv(color, cwd, env); // The rust runCommand is always a tty, so it will not look nice in parallel and if we need prefixes // currently does not work properly in windows @@ -229,32 +258,35 @@ async function createProcess( process.env.NX_NATIVE_COMMAND_RUNNER !== 'false' && process.stdout.isTTY && !commandConfig.prefix && - !isParallel + !isParallel && + mode !== 'run-many' ) { const cp = new PseudoTtyProcess( runCommand(commandConfig.command, cwd, env) ); return new Promise((res) => { + let terminalOutput = ''; cp.onOutput((output) => { + terminalOutput += output; if (readyWhen && output.indexOf(readyWhen) > -1) { - res(true); + res({ success: true, terminalOutput }); } }); cp.onExit((code) => { if (code === 0) { - res(true); + res({ success: true, terminalOutput }); } else if (code >= 128) { process.exit(code); } else { - res(false); + res({ success: false, terminalOutput }); } }); }); } - return nodeProcess(commandConfig, color, cwd, env, readyWhen); + return nodeProcess(commandConfig, cwd, env, readyWhen); } function nodeProcess( @@ -264,12 +296,12 @@ function nodeProcess( bgColor?: string; prefix?: string; }, - color: boolean, cwd: string, env: Record, readyWhen: string -): Promise { +): Promise<{ success: boolean; terminalOutput: string }> { return new Promise((res) => { + console.log('nodeProcess', { cwd, env, readyWhen }); const childProcess = exec(commandConfig.command, { maxBuffer: LARGE_BUFFER, env, @@ -286,25 +318,32 @@ function nodeProcess( process.on('SIGINT', processExitListener); process.on('SIGQUIT', processExitListener); + let terminalOutput = ''; childProcess.stdout.on('data', (data) => { - process.stdout.write(addColorAndPrefix(data, commandConfig)); + const output = addColorAndPrefix(data, commandConfig); + terminalOutput += output; + process.stdout.write(output); if (readyWhen && data.toString().indexOf(readyWhen) > -1) { - res(true); + res({ success: true, terminalOutput }); } }); childProcess.stderr.on('data', (err) => { - process.stderr.write(addColorAndPrefix(err, commandConfig)); + const output = addColorAndPrefix(err, commandConfig); + terminalOutput += output; + process.stderr.write(output); if (readyWhen && err.toString().indexOf(readyWhen) > -1) { - res(true); + res({ success: true, terminalOutput }); } }); childProcess.on('error', (err) => { - process.stderr.write(addColorAndPrefix(err.toString(), commandConfig)); - res(false); + const ouptput = addColorAndPrefix(err.toString(), commandConfig); + terminalOutput += ouptput; + process.stderr.write(ouptput); + res({ success: false, terminalOutput }); }); childProcess.on('exit', (code) => { if (!readyWhen) { - res(code === 0); + res({ success: code === 0, terminalOutput }); } }); }); @@ -339,6 +378,7 @@ function calculateCwd( cwd: string | undefined, context: ExecutorContext ): string { + console.log('calculateCwd', cwd, context.root); if (!cwd) return context.root; if (path.isAbsolute(cwd)) return cwd; return path.join(context.root, cwd); @@ -364,7 +404,7 @@ export function interpolateArgsIntoCommand( 'args' | 'parsedArgs' | '__unparsed__' >, forwardAllArgs: boolean -) { +): string { if (command.indexOf('{args.') > -1) { const regex = /{args\.([^}]+)}/g; return command.replace(regex, (_, group: string) => diff --git a/packages/nx/src/executors/run-commands/schema.json b/packages/nx/src/executors/run-commands/schema.json index cfb307d521c351..2fc2ef593adf02 100644 --- a/packages/nx/src/executors/run-commands/schema.json +++ b/packages/nx/src/executors/run-commands/schema.json @@ -135,6 +135,12 @@ "$source": "unparsed" }, "x-priority": "internal" + }, + "mode": { + "type": "string", + "description": "Mode to trigger the command.", + "enum": ["run-one", "run-many"], + "x-priority": "internal" } }, "additionalProperties": true, diff --git a/packages/nx/src/tasks-runner/create-task-graph.spec.ts b/packages/nx/src/tasks-runner/create-task-graph.spec.ts index dde29f32678aa6..62a4d2f92890f5 100644 --- a/packages/nx/src/tasks-runner/create-task-graph.spec.ts +++ b/packages/nx/src/tasks-runner/create-task-graph.spec.ts @@ -104,6 +104,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'test', }, + executor: 'nx:run-commands', outputs: [], overrides: { a: 123 }, projectRoot: 'app1-root', @@ -134,6 +135,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'test', }, + executor: 'nx:run-commands', outputs: [], overrides: { a: 123 }, projectRoot: 'app1-root', @@ -144,6 +146,7 @@ describe('createTaskGraph', () => { project: 'lib1', target: 'test', }, + executor: 'nx:run-commands', outputs: [], overrides: { a: 123 }, projectRoot: 'lib1-root', @@ -283,6 +286,7 @@ describe('createTaskGraph', () => { target: 'compile', configuration: 'libDefault', }, + executor: 'my-executor', outputs: [], overrides: {}, projectRoot: 'lib1-root', @@ -293,6 +297,7 @@ describe('createTaskGraph', () => { project: 'lib2', target: 'compile', }, + executor: 'my-executor', outputs: [], overrides: { __overrides_unparsed__: [], @@ -325,6 +330,7 @@ describe('createTaskGraph', () => { target: 'compile', configuration: 'ci', }, + executor: 'my-executor', outputs: [], overrides: {}, projectRoot: 'app1-root', @@ -336,6 +342,7 @@ describe('createTaskGraph', () => { target: 'compile', configuration: 'libDefault', }, + executor: 'my-executor', outputs: [], overrides: { __overrides_unparsed__: [], @@ -349,6 +356,7 @@ describe('createTaskGraph', () => { target: 'compile', configuration: 'ci', }, + executor: 'my-executor', outputs: [], overrides: { __overrides_unparsed__: [], @@ -454,6 +462,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'compile', }, + executor: 'my-executor', }, 'lib3:compile': { id: 'lib3:compile', @@ -466,6 +475,7 @@ describe('createTaskGraph', () => { project: 'lib3', target: 'compile', }, + executor: 'my-executor', }, }, }); @@ -491,6 +501,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'test', }, + executor: 'nx:run-commands', outputs: [], overrides: { a: '--value=app1-root' }, projectRoot: 'app1-root', @@ -522,6 +533,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'test', }, + executor: 'nx:run-commands', outputs: [], overrides: { a: '--base-href=/app1-root${deploymentId}' }, projectRoot: 'app1-root', @@ -636,6 +648,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { myFlag: 'flag value' }, projectRoot: 'app1-root', @@ -646,6 +659,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'precompile', }, + executor: 'nx:run-commands', outputs: [], overrides: { myFlag: 'flag value' }, projectRoot: 'app1-root', @@ -656,6 +670,7 @@ describe('createTaskGraph', () => { project: 'lib1', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { myFlag: 'flag value' }, projectRoot: 'lib1-root', @@ -666,6 +681,7 @@ describe('createTaskGraph', () => { project: 'lib2', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [] }, projectRoot: 'lib2-root', @@ -701,6 +717,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -713,6 +730,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'precompile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -725,6 +743,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'precompile2', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -737,6 +756,7 @@ describe('createTaskGraph', () => { project: 'lib1', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -774,6 +794,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -786,6 +807,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'precompile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -798,6 +820,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'precompile2', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -810,6 +833,7 @@ describe('createTaskGraph', () => { project: 'lib1', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -916,6 +940,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -928,6 +953,7 @@ describe('createTaskGraph', () => { project: 'lib1', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -940,6 +966,7 @@ describe('createTaskGraph', () => { project: 'lib2', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -952,6 +979,7 @@ describe('createTaskGraph', () => { project: 'lib3', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -1077,6 +1105,7 @@ describe('createTaskGraph', () => { 'infra1:apply': { id: 'infra1:apply', target: { project: 'infra1', target: 'apply' }, + executor: 'nx:run-commands', projectRoot: 'infra1-root', outputs: [], overrides: { myFlag: 'flag value' }, @@ -1084,6 +1113,7 @@ describe('createTaskGraph', () => { 'app2:compile': { id: 'app2:compile', target: { project: 'app2', target: 'compile' }, + executor: 'nx:run-commands', projectRoot: 'app2-root', outputs: [], overrides: { __overrides_unparsed__: [] }, @@ -1091,6 +1121,7 @@ describe('createTaskGraph', () => { 'coreInfra:apply': { id: 'coreInfra:apply', target: { project: 'coreInfra', target: 'apply' }, + executor: 'nx:run-commands', projectRoot: 'infra3-root', outputs: [], overrides: { myFlag: 'flag value' }, @@ -1098,6 +1129,7 @@ describe('createTaskGraph', () => { 'app1:compile': { id: 'app1:compile', target: { project: 'app1', target: 'compile' }, + executor: 'nx:run-commands', projectRoot: 'app1-root', outputs: [], overrides: { __overrides_unparsed__: [] }, @@ -1105,6 +1137,7 @@ describe('createTaskGraph', () => { 'infra2:apply': { id: 'infra2:apply', target: { project: 'infra2', target: 'apply' }, + executor: 'nx:run-commands', projectRoot: 'infra2-root', outputs: [], overrides: { myFlag: 'flag value' }, @@ -1169,6 +1202,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -1181,6 +1215,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'test', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -1262,6 +1297,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -1274,6 +1310,7 @@ describe('createTaskGraph', () => { project: 'app3', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -1352,6 +1389,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -1364,6 +1402,7 @@ describe('createTaskGraph', () => { project: 'app3', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -1440,6 +1479,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -1473,6 +1513,7 @@ describe('createTaskGraph', () => { project: 'app1', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], @@ -1485,6 +1526,7 @@ describe('createTaskGraph', () => { project: 'app2', target: 'compile', }, + executor: 'nx:run-commands', outputs: [], overrides: { __overrides_unparsed__: [], diff --git a/packages/nx/src/tasks-runner/create-task-graph.ts b/packages/nx/src/tasks-runner/create-task-graph.ts index 41ac9c9b48fe44..13e33dea0abd6d 100644 --- a/packages/nx/src/tasks-runner/create-task-graph.ts +++ b/packages/nx/src/tasks-runner/create-task-graph.ts @@ -317,7 +317,9 @@ export class ProcessTasks { ); } - if (!project.data.targets[target].executor) { + const executor = project.data.targets[target].executor; + const options = project.data.targets[target].options; + if (!executor) { throw new Error( `Target "${project.name}:${target}" does not have an executor configured` ); @@ -347,6 +349,8 @@ export class ProcessTasks { ), // TODO(v19): Remove cast here after typing is moved back onto TargetConfiguration cache: (project.data.targets[target] as any).cache, + executor, + options, }; } diff --git a/packages/nx/src/tasks-runner/default-tasks-runner.ts b/packages/nx/src/tasks-runner/default-tasks-runner.ts index 75e80cdc9386b8..a5cb33bfd7473d 100644 --- a/packages/nx/src/tasks-runner/default-tasks-runner.ts +++ b/packages/nx/src/tasks-runner/default-tasks-runner.ts @@ -1,6 +1,5 @@ import { TasksRunner, TaskStatus } from './tasks-runner'; import { TaskOrchestrator } from './task-orchestrator'; -import { performance } from 'perf_hooks'; import { TaskHasher } from '../hasher/task-hasher'; import { LifeCycle } from './life-cycle'; import { ProjectGraph } from '../config/project-graph'; diff --git a/packages/nx/src/tasks-runner/forked-process-task-runner.ts b/packages/nx/src/tasks-runner/forked-process-task-runner.ts index fe661918e6a430..15730c733b0795 100644 --- a/packages/nx/src/tasks-runner/forked-process-task-runner.ts +++ b/packages/nx/src/tasks-runner/forked-process-task-runner.ts @@ -14,8 +14,8 @@ import { } from './batch/batch-messages'; import { stripIndents } from '../utils/strip-indents'; import { Task, TaskGraph } from '../config/task-graph'; -import { Readable, Transform } from 'stream'; -import { ChildProcess as NativeChildProcess, nxFork } from '../native'; +import { Transform } from 'stream'; +import { nxFork } from '../native'; import { PsuedoIPCServer } from './psuedo-ipc'; import { FORKED_PROCESS_OS_SOCKET_PATH } from '../daemon/socket-utils'; import { PseudoTtyProcess } from '../utils/child-process'; diff --git a/packages/nx/src/tasks-runner/task-orchestrator.ts b/packages/nx/src/tasks-runner/task-orchestrator.ts index da7daa0450ebd5..62ea24993d3a12 100644 --- a/packages/nx/src/tasks-runner/task-orchestrator.ts +++ b/packages/nx/src/tasks-runner/task-orchestrator.ts @@ -1,6 +1,7 @@ import { defaultMaxListeners } from 'events'; import { performance } from 'perf_hooks'; import { TaskHasher } from '../hasher/task-hasher'; +import runCommandsImpl from '../executors/run-commands/run-commands.impl'; import { ForkedProcessTaskRunner } from './forked-process-task-runner'; import { Cache } from './cache'; import { DefaultTasksRunnerOptions } from './default-tasks-runner'; @@ -24,6 +25,8 @@ import { getTaskSpecificEnv, } from './task-env'; import * as os from 'os'; +import { workspaceRoot } from '../utils/workspace-root'; +import { getPackageManagerCommand } from '../utils/package-manager'; export class TaskOrchestrator { private cache = new Cache(this.options); @@ -376,20 +379,53 @@ export class TaskOrchestrator { // the task wasn't cached if (results.length === 0) { - // cache prep - const { code, terminalOutput } = await this.runTaskInForkedProcess( - task, - env, - pipeOutput, - temporaryOutputPath, - streamOutput - ); - - results.push({ - task, - status: code === 0 ? 'success' : 'failure', - terminalOutput, - }); + if (task.executor === 'nx:run-commands') { + const pmc = getPackageManagerCommand(); + if ( + task.options.command && + !task.options.command.startsWith(pmc.exec) + ) { + task.options.command = `${pmc.exec} ${task.options.command}`; + } + task.options.commands = task.options.commands?.map((command) => { + if (typeof command === 'string') { + command = `${pmc.exec} ${command}`; + } else { + command.command = `${pmc.exec} ${command.command}`; + } + }); + const { success, terminalOutput } = await runCommandsImpl( + { + ...task.options, + env, + __unparsed__: task.overrides?.['__overrides_unparsed__'] ?? [], + verbose: process.env.NX_VERBOSE_LOGGING === 'true', + mode: this.tasksSchedule.hasTasks() ? 'run-many' : 'run-one', + }, + { + root: workspaceRoot, // only root is needed in runCommandsImpl + } as any + ); + results.push({ + task, + status: success ? 'success' : 'failure', + terminalOutput, + }); + } else { + // cache prep + const { code, terminalOutput } = await this.runTaskInForkedProcess( + task, + env, + pipeOutput, + temporaryOutputPath, + streamOutput + ); + results.push({ + task, + status: code === 0 ? 'success' : 'failure', + terminalOutput, + }); + } } await this.postRunSteps([task], results, doNotSkipCache, { groupId }); }