nx 21.0.0-canary.20250419-8619c1d → 21.0.0-canary.20250423-16fc551

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nx",
3
- "version": "21.0.0-canary.20250419-8619c1d",
3
+ "version": "21.0.0-canary.20250423-16fc551",
4
4
  "private": false,
5
5
  "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.",
6
6
  "repository": {
@@ -83,16 +83,16 @@
83
83
  }
84
84
  },
85
85
  "optionalDependencies": {
86
- "@nx/nx-darwin-arm64": "21.0.0-canary.20250419-8619c1d",
87
- "@nx/nx-darwin-x64": "21.0.0-canary.20250419-8619c1d",
88
- "@nx/nx-freebsd-x64": "21.0.0-canary.20250419-8619c1d",
89
- "@nx/nx-linux-arm-gnueabihf": "21.0.0-canary.20250419-8619c1d",
90
- "@nx/nx-linux-arm64-gnu": "21.0.0-canary.20250419-8619c1d",
91
- "@nx/nx-linux-arm64-musl": "21.0.0-canary.20250419-8619c1d",
92
- "@nx/nx-linux-x64-gnu": "21.0.0-canary.20250419-8619c1d",
93
- "@nx/nx-linux-x64-musl": "21.0.0-canary.20250419-8619c1d",
94
- "@nx/nx-win32-arm64-msvc": "21.0.0-canary.20250419-8619c1d",
95
- "@nx/nx-win32-x64-msvc": "21.0.0-canary.20250419-8619c1d"
86
+ "@nx/nx-darwin-arm64": "21.0.0-canary.20250423-16fc551",
87
+ "@nx/nx-darwin-x64": "21.0.0-canary.20250423-16fc551",
88
+ "@nx/nx-freebsd-x64": "21.0.0-canary.20250423-16fc551",
89
+ "@nx/nx-linux-arm-gnueabihf": "21.0.0-canary.20250423-16fc551",
90
+ "@nx/nx-linux-arm64-gnu": "21.0.0-canary.20250423-16fc551",
91
+ "@nx/nx-linux-arm64-musl": "21.0.0-canary.20250423-16fc551",
92
+ "@nx/nx-linux-x64-gnu": "21.0.0-canary.20250423-16fc551",
93
+ "@nx/nx-linux-x64-musl": "21.0.0-canary.20250423-16fc551",
94
+ "@nx/nx-win32-arm64-msvc": "21.0.0-canary.20250423-16fc551",
95
+ "@nx/nx-win32-x64-msvc": "21.0.0-canary.20250423-16fc551"
96
96
  },
97
97
  "nx-migrations": {
98
98
  "migrations": "./migrations.json",
@@ -322,7 +322,8 @@ export declare const enum TaskStatus {
322
322
  RemoteCache = 5,
323
323
  NotStarted = 6,
324
324
  InProgress = 7,
325
- Shared = 8
325
+ Shared = 8,
326
+ Stopped = 9
326
327
  }
327
328
 
328
329
  export interface TaskTarget {
Binary file
@@ -65,7 +65,7 @@ const defaultTasksRunner = async (tasks, options, context) => {
65
65
  };
66
66
  exports.defaultTasksRunner = defaultTasksRunner;
67
67
  async function runAllTasks(options, context) {
68
- const orchestrator = new task_orchestrator_1.TaskOrchestrator(context.hasher, context.initiatingProject, context.projectGraph, context.taskGraph, context.nxJson, options, context.nxArgs?.nxBail, context.daemon, context.nxArgs?.outputStyle);
68
+ const orchestrator = new task_orchestrator_1.TaskOrchestrator(context.hasher, context.initiatingProject, context.initiatingTasks, context.projectGraph, context.taskGraph, context.nxJson, options, context.nxArgs?.nxBail, context.daemon, context.nxArgs?.outputStyle);
69
69
  return orchestrator.run();
70
70
  }
71
71
  exports.default = exports.defaultTasksRunner;
@@ -140,6 +140,9 @@ class ForkedProcessTaskRunner {
140
140
  }
141
141
  this.pseudoTerminals.delete(pseudoTerminal);
142
142
  this.processes.delete(p);
143
+ if (!streamOutput) {
144
+ this.options.lifeCycle.printTaskTerminalOutput(task, code === 0 ? 'success' : 'failure', terminalOutput);
145
+ }
143
146
  this.writeTerminalOutput(temporaryOutputPath, terminalOutput);
144
147
  });
145
148
  return p;
@@ -61,6 +61,7 @@ async function initTasksRunner(nxArgs) {
61
61
  nxArgs: { ...nxArgs, parallel: opts.parallel },
62
62
  loadDotEnvFiles: true,
63
63
  initiatingProject: null,
64
+ initiatingTasks: [],
64
65
  });
65
66
  return {
66
67
  status: Object.values(taskResults).some((taskResult) => taskResult.status === 'failure' || taskResult.status === 'skipped')
@@ -98,7 +99,7 @@ async function createOrchestrator(tasks, projectGraph, taskGraphForHashing, nxJs
98
99
  return acc;
99
100
  }, {}),
100
101
  };
101
- const orchestrator = new task_orchestrator_1.TaskOrchestrator(hasher, null, projectGraph, taskGraph, nxJson, { ...options, parallel: tasks.length, lifeCycle: compositedLifeCycle }, false, client_1.daemonClient, undefined, taskGraphForHashing);
102
+ const orchestrator = new task_orchestrator_1.TaskOrchestrator(hasher, null, [], projectGraph, taskGraph, nxJson, { ...options, parallel: tasks.length, lifeCycle: compositedLifeCycle }, false, client_1.daemonClient, undefined, taskGraphForHashing);
102
103
  await orchestrator.init();
103
104
  await Promise.all(tasks.map((task) => orchestrator.processTask(task.id)));
104
105
  return orchestrator;
@@ -36,7 +36,7 @@ export interface LifeCycle {
36
36
  startTasks?(task: Task[], metadata: TaskMetadata): void | Promise<void>;
37
37
  endTasks?(taskResults: TaskResult[], metadata: TaskMetadata): void | Promise<void>;
38
38
  printTaskTerminalOutput?(task: Task, status: TaskStatus, output: string): void;
39
- registerRunningTask?(taskId: string, parserAndWriter: ExternalObject<[any, any]>): Promise<void>;
39
+ registerRunningTask?(taskId: string, parserAndWriter: ExternalObject<[any, any]>): void;
40
40
  setTaskStatus?(taskId: string, status: NativeTaskStatus): void;
41
41
  registerForcedShutdownCallback?(callback: () => void): void;
42
42
  }
@@ -51,7 +51,7 @@ export declare class CompositeLifeCycle implements LifeCycle {
51
51
  startTasks(tasks: Task[], metadata: TaskMetadata): Promise<void>;
52
52
  endTasks(taskResults: TaskResult[], metadata: TaskMetadata): Promise<void>;
53
53
  printTaskTerminalOutput(task: Task, status: TaskStatus, output: string): void;
54
- registerRunningTask(taskId: string, parserAndWriter: ExternalObject<[any, any]>): Promise<void>;
54
+ registerRunningTask(taskId: string, parserAndWriter: ExternalObject<[any, any]>): void;
55
55
  setTaskStatus(taskId: string, status: NativeTaskStatus): void;
56
56
  registerForcedShutdownCallback(callback: () => void): void;
57
57
  }
@@ -67,10 +67,10 @@ class CompositeLifeCycle {
67
67
  }
68
68
  }
69
69
  }
70
- async registerRunningTask(taskId, parserAndWriter) {
70
+ registerRunningTask(taskId, parserAndWriter) {
71
71
  for (let l of this.lifeCycles) {
72
72
  if (l.registerRunningTask) {
73
- await l.registerRunningTask(taskId, parserAndWriter);
73
+ l.registerRunningTask(taskId, parserAndWriter);
74
74
  }
75
75
  }
76
76
  }
@@ -1,6 +1,6 @@
1
1
  import { Task } from '../../config/task-graph';
2
2
  import type { LifeCycle } from '../life-cycle';
3
- export declare function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, args, overrides, initiatingProject, resolveRenderIsDonePromise, }: {
3
+ export declare function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, args, overrides, initiatingProject, initiatingTasks, resolveRenderIsDonePromise, }: {
4
4
  projectNames: string[];
5
5
  tasks: Task[];
6
6
  args: {
@@ -10,6 +10,7 @@ export declare function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, ar
10
10
  };
11
11
  overrides: Record<string, unknown>;
12
12
  initiatingProject: string;
13
+ initiatingTasks: Task[];
13
14
  resolveRenderIsDonePromise: (value: void) => void;
14
15
  }): {
15
16
  lifeCycle: Partial<LifeCycle>;
@@ -10,7 +10,7 @@ const figures = require("figures");
10
10
  const LEFT_PAD = ` `;
11
11
  const SPACER = ` `;
12
12
  const EXTENDED_LEFT_PAD = ` `;
13
- function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, args, overrides, initiatingProject, resolveRenderIsDonePromise, }) {
13
+ function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, args, overrides, initiatingProject, initiatingTasks, resolveRenderIsDonePromise, }) {
14
14
  const lifeCycle = {};
15
15
  const start = process.hrtime();
16
16
  const targets = args.targets;
@@ -19,6 +19,7 @@ function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, args, overrides,
19
19
  let totalSuccessfulTasks = 0;
20
20
  let totalFailedTasks = 0;
21
21
  let totalCompletedTasks = 0;
22
+ let totalStoppedTasks = 0;
22
23
  let timeTakenText;
23
24
  const failedTasks = new Set();
24
25
  const inProgressTasks = new Set();
@@ -30,14 +31,19 @@ function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, args, overrides,
30
31
  }
31
32
  };
32
33
  lifeCycle.printTaskTerminalOutput = (task, taskStatus, terminalOutput) => {
33
- tasksToTerminalOutputs[task.id] = { terminalOutput, taskStatus };
34
34
  taskIdsInOrderOfCompletion.push(task.id);
35
+ tasksToTerminalOutputs[task.id] = { terminalOutput, taskStatus };
36
+ };
37
+ lifeCycle.setTaskStatus = (taskId, taskStatus) => {
38
+ if (taskStatus === 9 /* NativeTaskStatus.Stopped */) {
39
+ totalStoppedTasks++;
40
+ }
35
41
  };
36
42
  lifeCycle.endTasks = (taskResults) => {
37
- for (let t of taskResults) {
43
+ for (const { task, status } of taskResults) {
38
44
  totalCompletedTasks++;
39
- inProgressTasks.delete(t.task.id);
40
- switch (t.status) {
45
+ inProgressTasks.delete(task.id);
46
+ switch (status) {
41
47
  case 'remote-cache':
42
48
  case 'local-cache':
43
49
  case 'local-cache-kept-existing':
@@ -49,7 +55,7 @@ function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, args, overrides,
49
55
  break;
50
56
  case 'failure':
51
57
  totalFailedTasks++;
52
- failedTasks.add(t.task.id);
58
+ failedTasks.add(task.id);
53
59
  break;
54
60
  }
55
61
  }
@@ -75,7 +81,7 @@ function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, args, overrides,
75
81
  };
76
82
  const printRunOneSummary = () => {
77
83
  let lines = [];
78
- const failure = totalSuccessfulTasks !== totalTasks;
84
+ const failure = totalSuccessfulTasks + totalStoppedTasks !== totalTasks;
79
85
  // Prints task outputs in the order they were completed
80
86
  // above the summary, since run-one should print all task results.
81
87
  for (const taskId of taskIdsInOrderOfCompletion) {
@@ -99,7 +105,7 @@ function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, args, overrides,
99
105
  }
100
106
  lines = [output_1.output.colors.green(lines.join(node_os_1.EOL))];
101
107
  }
102
- else if (totalCompletedTasks === totalTasks) {
108
+ else if (totalCompletedTasks + totalStoppedTasks === totalTasks) {
103
109
  let text = `Ran target ${output_1.output.bold(targets[0])} for project ${output_1.output.bold(initiatingProject)}`;
104
110
  if (tasks.length > 1) {
105
111
  text += ` and ${output_1.output.bold(tasks.length - 1)} task(s) they depend on`;
@@ -137,7 +143,7 @@ function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, args, overrides,
137
143
  const printRunManySummary = () => {
138
144
  console.log('');
139
145
  const lines = [];
140
- const failure = totalSuccessfulTasks !== totalTasks;
146
+ const failure = totalSuccessfulTasks + totalStoppedTasks !== totalTasks;
141
147
  for (const taskId of taskIdsInOrderOfCompletion) {
142
148
  const { terminalOutput, taskStatus } = tasksToTerminalOutputs[taskId];
143
149
  if (taskStatus === 'failure') {
@@ -149,7 +155,7 @@ function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, args, overrides,
149
155
  }
150
156
  }
151
157
  lines.push(...output_1.output.getVerticalSeparatorLines(failure ? 'red' : 'green'));
152
- if (totalSuccessfulTasks === totalTasks) {
158
+ if (totalSuccessfulTasks + totalStoppedTasks === totalTasks) {
153
159
  const successSummaryRows = [];
154
160
  const text = `Successfully ran ${(0, formatting_utils_1.formatTargetsAndProjects)(projectNames, targets, tasks)}`;
155
161
  const taskOverridesRows = [];
@@ -17,7 +17,7 @@ export declare function runCommandForTasks(projectsToRun: ProjectGraphProjectNod
17
17
  excludeTaskDependencies: boolean;
18
18
  loadDotEnvFiles: boolean;
19
19
  }): Promise<TaskResults>;
20
- export declare function invokeTasksRunner({ tasks, projectGraph, taskGraph, lifeCycle, nxJson, nxArgs, loadDotEnvFiles, initiatingProject, }: {
20
+ export declare function invokeTasksRunner({ tasks, projectGraph, taskGraph, lifeCycle, nxJson, nxArgs, loadDotEnvFiles, initiatingProject, initiatingTasks, }: {
21
21
  tasks: Task[];
22
22
  projectGraph: ProjectGraph;
23
23
  taskGraph: TaskGraph;
@@ -26,6 +26,7 @@ export declare function invokeTasksRunner({ tasks, projectGraph, taskGraph, life
26
26
  nxArgs: NxArgs;
27
27
  loadDotEnvFiles: boolean;
28
28
  initiatingProject: string | null;
29
+ initiatingTasks: Task[];
29
30
  }): Promise<{
30
31
  [id: string]: TaskResult;
31
32
  }>;
@@ -46,7 +46,7 @@ const originalStdoutWrite = process.stdout.write.bind(process.stdout);
46
46
  const originalStderrWrite = process.stderr.write.bind(process.stderr);
47
47
  const originalConsoleLog = console.log.bind(console);
48
48
  const originalConsoleError = console.error.bind(console);
49
- async function getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks, taskGraph, nxArgs, nxJson, overrides) {
49
+ async function getTerminalOutputLifeCycle(initiatingProject, initiatingTasks, projectNames, tasks, taskGraph, nxArgs, nxJson, overrides) {
50
50
  const overridesWithoutHidden = { ...overrides };
51
51
  delete overridesWithoutHidden['__overrides_unparsed__'];
52
52
  if ((0, is_tui_enabled_1.isTuiEnabled)(nxJson)) {
@@ -82,7 +82,7 @@ async function getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks
82
82
  const projectText = projectNames.length === 1 ? 'project' : 'projects';
83
83
  let titleText = '';
84
84
  if (isRunOne) {
85
- const mainTaskId = (0, create_task_graph_1.createTaskId)(initiatingProject, nxArgs.targets[0], nxArgs.configuration);
85
+ const mainTaskId = initiatingTasks[0].id;
86
86
  pinnedTasks.push(mainTaskId);
87
87
  const mainContinuousDependencies = taskGraph.continuousDependencies[mainTaskId];
88
88
  if (mainContinuousDependencies.length > 0) {
@@ -111,6 +111,7 @@ async function getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks
111
111
  args: nxArgs,
112
112
  overrides: overridesWithoutHidden,
113
113
  initiatingProject,
114
+ initiatingTasks,
114
115
  resolveRenderIsDonePromise,
115
116
  });
116
117
  if (tasks.length === 0) {
@@ -120,7 +121,6 @@ async function getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks
120
121
  process.stderr.write = originalStderrWrite;
121
122
  console.log = originalConsoleLog;
122
123
  console.error = originalConsoleError;
123
- printSummary();
124
124
  });
125
125
  }
126
126
  const lifeCycles = [tsLifeCycle];
@@ -183,7 +183,6 @@ async function getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks
183
183
  process.stderr.write = originalStderrWrite;
184
184
  console.log = originalConsoleLog;
185
185
  console.error = originalConsoleError;
186
- printSummary();
187
186
  // Print the intercepted Nx Cloud logs
188
187
  for (const log of interceptedNxCloudLogs) {
189
188
  const logString = log.toString().trimStart();
@@ -196,6 +195,7 @@ async function getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks
196
195
  }
197
196
  return {
198
197
  lifeCycle: new life_cycle_1.CompositeLifeCycle(lifeCycles),
198
+ printSummary,
199
199
  renderIsDone,
200
200
  };
201
201
  }
@@ -285,9 +285,12 @@ async function runCommand(projectsToRun, currentProjectGraph, { nxJson }, nxArgs
285
285
  }
286
286
  async function runCommandForTasks(projectsToRun, currentProjectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
287
287
  const projectNames = projectsToRun.map((t) => t.name);
288
+ const projectNameSet = new Set(projectNames);
288
289
  const { projectGraph, taskGraph } = await ensureWorkspaceIsInSyncAndGetGraphs(currentProjectGraph, nxJson, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions);
289
290
  const tasks = Object.values(taskGraph.tasks);
290
- const { lifeCycle, renderIsDone } = await getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks, taskGraph, nxArgs, nxJson, overrides);
291
+ const initiatingTasks = tasks.filter((t) => projectNameSet.has(t.target.project) &&
292
+ nxArgs.targets.includes(t.target.target));
293
+ const { lifeCycle, renderIsDone, printSummary } = await getTerminalOutputLifeCycle(initiatingProject, initiatingTasks, projectNames, tasks, taskGraph, nxArgs, nxJson, overrides);
291
294
  const taskResults = await invokeTasksRunner({
292
295
  tasks,
293
296
  projectGraph,
@@ -297,8 +300,12 @@ async function runCommandForTasks(projectsToRun, currentProjectGraph, { nxJson }
297
300
  nxArgs,
298
301
  loadDotEnvFiles: extraOptions.loadDotEnvFiles,
299
302
  initiatingProject,
303
+ initiatingTasks,
300
304
  });
301
305
  await renderIsDone;
306
+ if (printSummary) {
307
+ printSummary();
308
+ }
302
309
  await (0, nx_key_1.printNxKey)();
303
310
  return taskResults;
304
311
  }
@@ -535,7 +542,7 @@ function setEnvVarsBasedOnArgs(nxArgs, loadDotEnvFiles) {
535
542
  process.env.NX_LOAD_DOT_ENV_FILES = 'true';
536
543
  }
537
544
  }
538
- async function invokeTasksRunner({ tasks, projectGraph, taskGraph, lifeCycle, nxJson, nxArgs, loadDotEnvFiles, initiatingProject, }) {
545
+ async function invokeTasksRunner({ tasks, projectGraph, taskGraph, lifeCycle, nxJson, nxArgs, loadDotEnvFiles, initiatingProject, initiatingTasks, }) {
539
546
  setEnvVarsBasedOnArgs(nxArgs, loadDotEnvFiles);
540
547
  // this needs to be done before we start to run the tasks
541
548
  const taskDetails = (0, hash_task_1.getTaskDetails)();
@@ -555,6 +562,7 @@ async function invokeTasksRunner({ tasks, projectGraph, taskGraph, lifeCycle, nx
555
562
  lifeCycle: compositedLifeCycle,
556
563
  }, {
557
564
  initiatingProject: nxArgs.outputStyle === 'compact' ? null : initiatingProject,
565
+ initiatingTasks,
558
566
  projectGraph,
559
567
  nxJson,
560
568
  nxArgs,
@@ -153,18 +153,11 @@ class NodeChildProcessWithDirectOutput {
153
153
  this.exitCallbacks.push(cb);
154
154
  }
155
155
  async getResults() {
156
- const terminalOutput = this.getTerminalOutput();
157
- if (this.exited) {
158
- return Promise.resolve({
159
- code: this.exitCode,
160
- terminalOutput,
161
- });
156
+ if (!this.exited) {
157
+ await this.waitForExit();
162
158
  }
163
- await this.waitForExit();
164
- return Promise.resolve({
165
- code: this.exitCode,
166
- terminalOutput,
167
- });
159
+ const terminalOutput = this.getTerminalOutput();
160
+ return { code: this.exitCode, terminalOutput };
168
161
  }
169
162
  waitForExit() {
170
163
  return new Promise((res) => {
@@ -1,3 +1,4 @@
1
+ import type { Serializable } from 'child_process';
1
2
  export declare abstract class RunningTask {
2
3
  abstract getResults(): Promise<{
3
4
  code: number;
@@ -5,4 +6,5 @@ export declare abstract class RunningTask {
5
6
  }>;
6
7
  abstract onExit(cb: (code: number) => void): void;
7
8
  abstract kill(signal?: NodeJS.Signals | number): Promise<void> | void;
9
+ abstract send?(message: Serializable): void;
8
10
  }
@@ -0,0 +1,14 @@
1
+ import { RunningTask } from './running-task';
2
+ import { RunningTasksService } from '../../native';
3
+ export declare class SharedRunningTask implements RunningTask {
4
+ private runningTasksService;
5
+ private exitCallbacks;
6
+ constructor(runningTasksService: RunningTasksService, taskId: string);
7
+ getResults(): Promise<{
8
+ code: number;
9
+ terminalOutput: string;
10
+ }>;
11
+ kill(): void;
12
+ onExit(cb: (code: number) => void): void;
13
+ private waitForTaskToFinish;
14
+ }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SharedRunningTask = void 0;
4
+ class SharedRunningTask {
5
+ constructor(runningTasksService, taskId) {
6
+ this.runningTasksService = runningTasksService;
7
+ this.exitCallbacks = [];
8
+ this.waitForTaskToFinish(taskId).then(() => {
9
+ // notify exit callbacks
10
+ this.exitCallbacks.forEach((cb) => cb(0));
11
+ });
12
+ }
13
+ async getResults() {
14
+ throw new Error('Results cannot be retrieved from a shared task');
15
+ }
16
+ kill() {
17
+ this.exitCallbacks.forEach((cb) => cb(0));
18
+ }
19
+ onExit(cb) {
20
+ this.exitCallbacks.push(cb);
21
+ }
22
+ async waitForTaskToFinish(taskId) {
23
+ console.log(`Waiting for ${taskId} in another nx process`);
24
+ // wait for the running task to finish
25
+ do {
26
+ await new Promise((resolve) => setTimeout(resolve, 100));
27
+ } while (this.runningTasksService.getRunningTasks([taskId]).length);
28
+ }
29
+ }
30
+ exports.SharedRunningTask = SharedRunningTask;
@@ -7,9 +7,11 @@ import { NxArgs } from '../utils/command-line-utils';
7
7
  import { DefaultTasksRunnerOptions } from './default-tasks-runner';
8
8
  import { RunningTask } from './running-tasks/running-task';
9
9
  import { TaskStatus } from './tasks-runner';
10
+ import { SharedRunningTask } from './running-tasks/shared-running-task';
10
11
  export declare class TaskOrchestrator {
11
12
  private readonly hasher;
12
13
  private readonly initiatingProject;
14
+ private readonly initiatingTasks;
13
15
  private readonly projectGraph;
14
16
  private readonly taskGraph;
15
17
  private readonly nxJson;
@@ -26,6 +28,7 @@ export declare class TaskOrchestrator {
26
28
  private tasksSchedule;
27
29
  private batchEnv;
28
30
  private reverseTaskDeps;
31
+ private initializingTaskIds;
29
32
  private processedTasks;
30
33
  private processedBatches;
31
34
  private completedTasks;
@@ -33,8 +36,7 @@ export declare class TaskOrchestrator {
33
36
  private groups;
34
37
  private bailed;
35
38
  private runningContinuousTasks;
36
- private cleaningUp;
37
- constructor(hasher: TaskHasher, initiatingProject: string | undefined, projectGraph: ProjectGraph, taskGraph: TaskGraph, nxJson: NxJsonConfiguration, options: NxArgs & DefaultTasksRunnerOptions, bail: boolean, daemon: DaemonClient, outputStyle: string, taskGraphForHashing?: TaskGraph);
39
+ constructor(hasher: TaskHasher, initiatingProject: string | undefined, initiatingTasks: Task[], projectGraph: ProjectGraph, taskGraph: TaskGraph, nxJson: NxJsonConfiguration, options: NxArgs & DefaultTasksRunnerOptions, bail: boolean, daemon: DaemonClient, outputStyle: string, taskGraphForHashing?: TaskGraph);
38
40
  init(): Promise<void>;
39
41
  run(): Promise<{
40
42
  [id: string]: TaskStatus;
@@ -55,7 +57,7 @@ export declare class TaskOrchestrator {
55
57
  }>;
56
58
  private runTask;
57
59
  private runTaskInForkedProcess;
58
- startContinuousTask(task: Task, groupId: number): Promise<RunningTask>;
60
+ startContinuousTask(task: Task, groupId: number): Promise<RunningTask | SharedRunningTask>;
59
61
  private preRunSteps;
60
62
  private postRunSteps;
61
63
  private scheduleNextTasksAndReleaseThreads;
@@ -67,5 +69,6 @@ export declare class TaskOrchestrator {
67
69
  private shouldCopyOutputsFromCache;
68
70
  private recordOutputsHash;
69
71
  private cleanup;
72
+ private cleanUpUnneededContinuousTasks;
70
73
  }
71
74
  export declare function getThreadCount(options: NxArgs & DefaultTasksRunnerOptions, taskGraph: TaskGraph): number;
@@ -21,11 +21,13 @@ const noop_child_process_1 = require("./running-tasks/noop-child-process");
21
21
  const task_env_1 = require("./task-env");
22
22
  const tasks_schedule_1 = require("./tasks-schedule");
23
23
  const utils_1 = require("./utils");
24
+ const shared_running_task_1 = require("./running-tasks/shared-running-task");
24
25
  class TaskOrchestrator {
25
26
  // endregion internal state
26
- constructor(hasher, initiatingProject, projectGraph, taskGraph, nxJson, options, bail, daemon, outputStyle, taskGraphForHashing = taskGraph) {
27
+ constructor(hasher, initiatingProject, initiatingTasks, projectGraph, taskGraph, nxJson, options, bail, daemon, outputStyle, taskGraphForHashing = taskGraph) {
27
28
  this.hasher = hasher;
28
29
  this.initiatingProject = initiatingProject;
30
+ this.initiatingTasks = initiatingTasks;
29
31
  this.projectGraph = projectGraph;
30
32
  this.taskGraph = taskGraph;
31
33
  this.nxJson = nxJson;
@@ -43,6 +45,7 @@ class TaskOrchestrator {
43
45
  // region internal state
44
46
  this.batchEnv = (0, task_env_1.getEnvVariablesForBatchProcess)(this.options.skipNxCache, this.options.captureStderr);
45
47
  this.reverseTaskDeps = (0, utils_1.calculateReverseDeps)(this.taskGraph);
48
+ this.initializingTaskIds = new Set(this.initiatingTasks.map((t) => t.id));
46
49
  this.processedTasks = new Map();
47
50
  this.processedBatches = new Map();
48
51
  this.completedTasks = {};
@@ -50,7 +53,6 @@ class TaskOrchestrator {
50
53
  this.groups = [];
51
54
  this.bailed = false;
52
55
  this.runningContinuousTasks = new Map();
53
- this.cleaningUp = false;
54
56
  }
55
57
  async init() {
56
58
  // Init the ForkedProcessTaskRunner, TasksSchedule, and Cache
@@ -397,15 +399,27 @@ class TaskOrchestrator {
397
399
  if (this.tuiEnabled) {
398
400
  this.options.lifeCycle.setTaskStatus(task.id, 8 /* NativeTaskStatus.Shared */);
399
401
  }
402
+ const runningTask = new shared_running_task_1.SharedRunningTask(this.runningTasksService, task.id);
403
+ this.runningContinuousTasks.set(task.id, runningTask);
404
+ runningTask.onExit(() => {
405
+ this.runningContinuousTasks.delete(task.id);
406
+ });
400
407
  // task is already running by another process, we schedule the next tasks
401
408
  // and release the threads
402
409
  await this.scheduleNextTasksAndReleaseThreads();
403
- // wait for the running task to finish
404
- do {
405
- console.log(`Waiting for ${task.id} in another nx process`);
406
- await new Promise((resolve) => setTimeout(resolve, 100));
407
- } while (this.runningTasksService.getRunningTasks([task.id]).length);
408
- return;
410
+ if (this.initializingTaskIds.has(task.id)) {
411
+ await new Promise((res) => {
412
+ runningTask.onExit((code) => {
413
+ if (!this.tuiEnabled) {
414
+ if (code > 128) {
415
+ process.exit(code);
416
+ }
417
+ }
418
+ res();
419
+ });
420
+ });
421
+ }
422
+ return runningTask;
409
423
  }
410
424
  const taskSpecificEnv = await this.processedTasks.get(task.id);
411
425
  await this.preRunSteps([task], { groupId });
@@ -425,14 +439,20 @@ class TaskOrchestrator {
425
439
  this.runningContinuousTasks.set(task.id, childProcess);
426
440
  childProcess.onExit(() => {
427
441
  this.runningTasksService.removeRunningTask(task.id);
442
+ this.runningContinuousTasks.delete(task.id);
428
443
  });
429
- if (this.initiatingProject === task.target.project &&
430
- this.options.targets.length === 1 &&
431
- this.options.targets[0] === task.target.target) {
432
- await childProcess.getResults();
433
- }
434
- else {
435
- await this.scheduleNextTasksAndReleaseThreads();
444
+ await this.scheduleNextTasksAndReleaseThreads();
445
+ if (this.initializingTaskIds.has(task.id)) {
446
+ await new Promise((res) => {
447
+ childProcess.onExit((code) => {
448
+ if (!this.tuiEnabled) {
449
+ if (code > 128) {
450
+ process.exit(code);
451
+ }
452
+ }
453
+ res();
454
+ });
455
+ });
436
456
  }
437
457
  return childProcess;
438
458
  }
@@ -505,6 +525,7 @@ class TaskOrchestrator {
505
525
  }
506
526
  complete(taskResults) {
507
527
  this.tasksSchedule.complete(taskResults.map(({ taskId }) => taskId));
528
+ this.cleanUpUnneededContinuousTasks();
508
529
  for (const { taskId, status } of taskResults) {
509
530
  if (this.completedTasks[taskId] === undefined) {
510
531
  this.completedTasks[taskId] = status;
@@ -571,10 +592,10 @@ class TaskOrchestrator {
571
592
  }
572
593
  // endregion utils
573
594
  async cleanup() {
574
- this.cleaningUp = true;
575
595
  await Promise.all(Array.from(this.runningContinuousTasks).map(async ([taskId, t]) => {
576
596
  try {
577
- return t.kill();
597
+ await t.kill();
598
+ this.options.lifeCycle.setTaskStatus(taskId, 9 /* NativeTaskStatus.Stopped */);
578
599
  }
579
600
  catch (e) {
580
601
  console.error(`Unable to terminate ${taskId}\nError:`, e);
@@ -584,6 +605,25 @@ class TaskOrchestrator {
584
605
  }
585
606
  }));
586
607
  }
608
+ cleanUpUnneededContinuousTasks() {
609
+ const incompleteTasks = this.tasksSchedule.getIncompleteTasks();
610
+ const neededContinuousTasks = new Set(this.initializingTaskIds);
611
+ for (const task of incompleteTasks) {
612
+ const continuousDependencies = this.taskGraph.continuousDependencies[task.id];
613
+ for (const continuousDependency of continuousDependencies) {
614
+ neededContinuousTasks.add(continuousDependency);
615
+ }
616
+ }
617
+ for (const taskId of this.runningContinuousTasks.keys()) {
618
+ if (!neededContinuousTasks.has(taskId)) {
619
+ const runningTask = this.runningContinuousTasks.get(taskId);
620
+ if (runningTask) {
621
+ runningTask.kill();
622
+ this.options.lifeCycle.setTaskStatus(taskId, 9 /* NativeTaskStatus.Stopped */);
623
+ }
624
+ }
625
+ }
626
+ }
587
627
  }
588
628
  exports.TaskOrchestrator = TaskOrchestrator;
589
629
  function getThreadCount(options, taskGraph) {
@@ -12,6 +12,7 @@ export type TaskStatus = 'success' | 'failure' | 'skipped' | 'local-cache-kept-e
12
12
  export type TasksRunner<T = unknown> = (tasks: Task[], options: T, context?: {
13
13
  target?: string;
14
14
  initiatingProject?: string | null;
15
+ initiatingTasks: Task[];
15
16
  projectGraph: ProjectGraph;
16
17
  nxJson: NxJsonConfiguration;
17
18
  nxArgs: NxArgs;
@@ -31,6 +31,7 @@ export declare class TasksSchedule {
31
31
  };
32
32
  nextTask(): Task;
33
33
  nextBatch(): Batch;
34
+ getIncompleteTasks(): Task[];
34
35
  private scheduleTasks;
35
36
  private scheduleTask;
36
37
  private scheduleBatches;
@@ -68,6 +68,15 @@ class TasksSchedule {
68
68
  ? this.scheduledBatches.shift()
69
69
  : null;
70
70
  }
71
+ getIncompleteTasks() {
72
+ const incompleteTasks = [];
73
+ for (const taskId in this.taskGraph.tasks) {
74
+ if (!this.completedTasks.has(taskId)) {
75
+ incompleteTasks.push(this.taskGraph.tasks[taskId]);
76
+ }
77
+ }
78
+ return incompleteTasks;
79
+ }
71
80
  async scheduleTasks() {
72
81
  if (this.options.batch || process.env.NX_BATCH_MODE === 'true') {
73
82
  await this.scheduleBatches();