nx 21.0.0-beta.0 → 21.0.0-canary.20250205-45d5140

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.
Files changed (31) hide show
  1. package/package.json +11 -12
  2. package/src/command-line/graph/graph.js +0 -2
  3. package/src/commands-runner/get-command-projects.js +2 -17
  4. package/src/config/task-graph.d.ts +0 -5
  5. package/src/config/workspace-json-project-json.d.ts +0 -4
  6. package/src/executors/run-commands/run-commands.impl.d.ts +13 -16
  7. package/src/executors/run-commands/run-commands.impl.js +263 -24
  8. package/src/native/index.d.ts +0 -1
  9. package/src/native/nx.wasm32-wasi.wasm +0 -0
  10. package/src/tasks-runner/create-task-graph.d.ts +0 -3
  11. package/src/tasks-runner/create-task-graph.js +5 -36
  12. package/src/tasks-runner/forked-process-task-runner.d.ts +12 -6
  13. package/src/tasks-runner/forked-process-task-runner.js +263 -110
  14. package/src/tasks-runner/init-tasks-runner.js +0 -4
  15. package/src/tasks-runner/pseudo-terminal.d.ts +1 -7
  16. package/src/tasks-runner/pseudo-terminal.js +12 -26
  17. package/src/tasks-runner/task-orchestrator.d.ts +1 -7
  18. package/src/tasks-runner/task-orchestrator.js +82 -137
  19. package/src/tasks-runner/tasks-schedule.js +1 -5
  20. package/src/tasks-runner/utils.d.ts +8 -0
  21. package/src/tasks-runner/utils.js +4 -12
  22. package/src/executors/run-commands/running-tasks.d.ts +0 -38
  23. package/src/executors/run-commands/running-tasks.js +0 -349
  24. package/src/tasks-runner/running-tasks/batch-process.d.ts +0 -14
  25. package/src/tasks-runner/running-tasks/batch-process.js +0 -70
  26. package/src/tasks-runner/running-tasks/node-child-process.d.ts +0 -36
  27. package/src/tasks-runner/running-tasks/node-child-process.js +0 -184
  28. package/src/tasks-runner/running-tasks/noop-child-process.d.ts +0 -15
  29. package/src/tasks-runner/running-tasks/noop-child-process.js +0 -19
  30. package/src/tasks-runner/running-tasks/running-task.d.ts +0 -8
  31. package/src/tasks-runner/running-tasks/running-task.js +0 -6
@@ -15,7 +15,6 @@ const task_env_1 = require("./task-env");
15
15
  const workspace_root_1 = require("../utils/workspace-root");
16
16
  const output_1 = require("../utils/output");
17
17
  const params_1 = require("../utils/params");
18
- const noop_child_process_1 = require("./running-tasks/noop-child-process");
19
18
  class TaskOrchestrator {
20
19
  // endregion internal state
21
20
  constructor(hasher, initiatingProject, projectGraph, taskGraph, nxJson, options, bail, daemon, outputStyle) {
@@ -41,8 +40,6 @@ class TaskOrchestrator {
41
40
  this.waitingForTasks = [];
42
41
  this.groups = [];
43
42
  this.bailed = false;
44
- this.runningContinuousTasks = new Map();
45
- this.cleaningUp = false;
46
43
  }
47
44
  async run() {
48
45
  // Init the ForkedProcessTaskRunner, TasksSchedule, and Cache
@@ -54,20 +51,17 @@ class TaskOrchestrator {
54
51
  // initial scheduling
55
52
  await this.tasksSchedule.scheduleNextTasks();
56
53
  perf_hooks_1.performance.mark('task-execution:start');
57
- const threadCount = this.options.parallel +
58
- Object.values(this.taskGraph.tasks).filter((t) => t.continuous).length;
59
54
  const threads = [];
60
- process.stdout.setMaxListeners(threadCount + events_1.defaultMaxListeners);
61
- process.stderr.setMaxListeners(threadCount + events_1.defaultMaxListeners);
55
+ process.stdout.setMaxListeners(this.options.parallel + events_1.defaultMaxListeners);
56
+ process.stderr.setMaxListeners(this.options.parallel + events_1.defaultMaxListeners);
62
57
  // initial seeding of the queue
63
- for (let i = 0; i < threadCount; ++i) {
58
+ for (let i = 0; i < this.options.parallel; ++i) {
64
59
  threads.push(this.executeNextBatchOfTasksUsingTaskSchedule());
65
60
  }
66
61
  await Promise.all(threads);
67
62
  perf_hooks_1.performance.mark('task-execution:end');
68
63
  perf_hooks_1.performance.measure('task-execution', 'task-execution:start', 'task-execution:end');
69
64
  this.cache.removeOldCacheRecords();
70
- await this.cleanup();
71
65
  return this.completedTasks;
72
66
  }
73
67
  async executeNextBatchOfTasksUsingTaskSchedule() {
@@ -88,12 +82,7 @@ class TaskOrchestrator {
88
82
  const task = this.tasksSchedule.nextTask();
89
83
  if (task) {
90
84
  const groupId = this.closeGroup();
91
- if (task.continuous) {
92
- await this.startContinuousTask(task, groupId);
93
- }
94
- else {
95
- await this.applyFromCacheOrRunTask(doNotSkipCache, task, groupId);
96
- }
85
+ await this.applyFromCacheOrRunTask(doNotSkipCache, task, groupId);
97
86
  this.openGroup(groupId);
98
87
  return this.executeNextBatchOfTasksUsingTaskSchedule();
99
88
  }
@@ -188,8 +177,7 @@ class TaskOrchestrator {
188
177
  }
189
178
  async runBatch(batch, env) {
190
179
  try {
191
- const batchProcess = await this.forkedProcessTaskRunner.forkProcessForBatch(batch, this.taskGraph, env);
192
- const results = await batchProcess.getResults();
180
+ const results = await this.forkedProcessTaskRunner.forkProcessForBatch(batch, this.taskGraph, env);
193
181
  const batchResultEntries = Object.entries(results);
194
182
  return batchResultEntries.map(([taskId, result]) => ({
195
183
  ...result,
@@ -229,84 +217,88 @@ class TaskOrchestrator {
229
217
  let results = doNotSkipCache ? await this.applyCachedResults([task]) : [];
230
218
  // the task wasn't cached
231
219
  if (results.length === 0) {
232
- const childProcess = await this.runTask(task, streamOutput, env, temporaryOutputPath, pipeOutput);
233
- const { code, terminalOutput } = await childProcess.getResults();
234
- results.push({
235
- task,
236
- status: code === 0 ? 'success' : 'failure',
237
- terminalOutput,
238
- });
239
- }
240
- await this.postRunSteps([task], results, doNotSkipCache, { groupId });
241
- }
242
- async runTask(task, streamOutput, env, temporaryOutputPath, pipeOutput) {
243
- const shouldPrefix = streamOutput && process.env.NX_PREFIX_OUTPUT === 'true';
244
- const targetConfiguration = (0, utils_1.getTargetConfigurationForTask)(task, this.projectGraph);
245
- if (process.env.NX_RUN_COMMANDS_DIRECTLY !== 'false' &&
246
- targetConfiguration.executor === 'nx:run-commands' &&
247
- !shouldPrefix) {
248
- try {
249
- const { schema } = (0, utils_1.getExecutorForTask)(task, this.projectGraph);
250
- const isRunOne = this.initiatingProject != null;
251
- const combinedOptions = (0, params_1.combineOptionsForExecutor)(task.overrides, task.target.configuration ?? targetConfiguration.defaultConfiguration, targetConfiguration, schema, task.target.project, (0, path_1.relative)(task.projectRoot ?? workspace_root_1.workspaceRoot, process.cwd()), process.env.NX_VERBOSE_LOGGING === 'true');
252
- if (combinedOptions.env) {
253
- env = {
254
- ...env,
255
- ...combinedOptions.env,
256
- };
257
- }
258
- if (streamOutput) {
259
- const args = (0, utils_1.getPrintableCommandArgsForTask)(task);
260
- output_1.output.logCommand(args.join(' '));
261
- }
262
- const runningTask = await (0, run_commands_impl_1.runCommands)({
263
- ...combinedOptions,
264
- env,
265
- usePty: isRunOne &&
266
- !this.tasksSchedule.hasTasks() &&
267
- this.runningContinuousTasks.size === 0,
268
- streamOutput,
269
- }, {
270
- root: workspace_root_1.workspaceRoot, // only root is needed in runCommands
271
- });
272
- runningTask.onExit((code, terminalOutput) => {
220
+ const shouldPrefix = streamOutput && process.env.NX_PREFIX_OUTPUT === 'true';
221
+ const targetConfiguration = (0, utils_1.getTargetConfigurationForTask)(task, this.projectGraph);
222
+ if (process.env.NX_RUN_COMMANDS_DIRECTLY !== 'false' &&
223
+ targetConfiguration.executor === 'nx:run-commands' &&
224
+ !shouldPrefix) {
225
+ try {
226
+ const { schema } = (0, utils_1.getExecutorForTask)(task, this.projectGraph);
227
+ const isRunOne = this.initiatingProject != null;
228
+ const combinedOptions = (0, params_1.combineOptionsForExecutor)(task.overrides, task.target.configuration ??
229
+ targetConfiguration.defaultConfiguration, targetConfiguration, schema, task.target.project, (0, path_1.relative)(task.projectRoot ?? workspace_root_1.workspaceRoot, process.cwd()), process.env.NX_VERBOSE_LOGGING === 'true');
230
+ if (combinedOptions.env) {
231
+ env = {
232
+ ...env,
233
+ ...combinedOptions.env,
234
+ };
235
+ }
236
+ if (streamOutput) {
237
+ const args = (0, utils_1.getPrintableCommandArgsForTask)(task);
238
+ output_1.output.logCommand(args.join(' '));
239
+ }
240
+ const { success, terminalOutput } = await (0, run_commands_impl_1.default)({
241
+ ...combinedOptions,
242
+ env,
243
+ usePty: isRunOne && !this.tasksSchedule.hasTasks(),
244
+ streamOutput,
245
+ }, {
246
+ root: workspace_root_1.workspaceRoot, // only root is needed in runCommandsImpl
247
+ });
248
+ const status = success ? 'success' : 'failure';
273
249
  if (!streamOutput) {
274
- this.options.lifeCycle.printTaskTerminalOutput(task, code === 0 ? 'success' : 'failure', terminalOutput);
275
- (0, fs_1.writeFileSync)(temporaryOutputPath, terminalOutput);
250
+ this.options.lifeCycle.printTaskTerminalOutput(task, status, terminalOutput);
276
251
  }
277
- });
278
- return runningTask;
279
- }
280
- catch (e) {
281
- if (process.env.NX_VERBOSE_LOGGING === 'true') {
282
- console.error(e);
252
+ (0, fs_1.writeFileSync)(temporaryOutputPath, terminalOutput);
253
+ results.push({
254
+ task,
255
+ status,
256
+ terminalOutput,
257
+ });
283
258
  }
284
- else {
285
- console.error(e.message);
259
+ catch (e) {
260
+ if (process.env.NX_VERBOSE_LOGGING === 'true') {
261
+ console.error(e);
262
+ }
263
+ else {
264
+ console.error(e.message);
265
+ }
266
+ const terminalOutput = e.stack ?? e.message ?? '';
267
+ (0, fs_1.writeFileSync)(temporaryOutputPath, terminalOutput);
268
+ results.push({
269
+ task,
270
+ status: 'failure',
271
+ terminalOutput,
272
+ });
286
273
  }
287
- const terminalOutput = e.stack ?? e.message ?? '';
288
- (0, fs_1.writeFileSync)(temporaryOutputPath, terminalOutput);
274
+ }
275
+ else if (targetConfiguration.executor === 'nx:noop') {
276
+ (0, fs_1.writeFileSync)(temporaryOutputPath, '');
277
+ results.push({
278
+ task,
279
+ status: 'success',
280
+ terminalOutput: '',
281
+ });
282
+ }
283
+ else {
284
+ // cache prep
285
+ const { code, terminalOutput } = await this.runTaskInForkedProcess(task, env, pipeOutput, temporaryOutputPath, streamOutput);
286
+ results.push({
287
+ task,
288
+ status: code === 0 ? 'success' : 'failure',
289
+ terminalOutput,
290
+ });
289
291
  }
290
292
  }
291
- else if (targetConfiguration.executor === 'nx:noop') {
292
- (0, fs_1.writeFileSync)(temporaryOutputPath, '');
293
- return new noop_child_process_1.NoopChildProcess({
294
- code: 0,
295
- terminalOutput: '',
296
- });
297
- }
298
- else {
299
- // cache prep
300
- return await this.runTaskInForkedProcess(task, env, pipeOutput, temporaryOutputPath, streamOutput);
301
- }
293
+ await this.postRunSteps([task], results, doNotSkipCache, { groupId });
302
294
  }
303
295
  async runTaskInForkedProcess(task, env, pipeOutput, temporaryOutputPath, streamOutput) {
304
296
  try {
305
297
  const usePtyFork = process.env.NX_NATIVE_COMMAND_RUNNER !== 'false';
306
- // Disable the pseudo terminal if this is a run-many or when running a continuous task as part of a run-one
307
- const disablePseudoTerminal = !this.initiatingProject || task.continuous;
298
+ // Disable the pseudo terminal if this is a run-many
299
+ const disablePseudoTerminal = !this.initiatingProject;
308
300
  // execution
309
- const childProcess = usePtyFork
301
+ const { code, terminalOutput } = usePtyFork
310
302
  ? await this.forkedProcessTaskRunner.forkProcess(task, {
311
303
  temporaryOutputPath,
312
304
  streamOutput,
@@ -322,54 +314,19 @@ class TaskOrchestrator {
322
314
  taskGraph: this.taskGraph,
323
315
  env,
324
316
  });
325
- return childProcess;
317
+ return {
318
+ code,
319
+ terminalOutput,
320
+ };
326
321
  }
327
322
  catch (e) {
328
323
  if (process.env.NX_VERBOSE_LOGGING === 'true') {
329
324
  console.error(e);
330
325
  }
331
- return new noop_child_process_1.NoopChildProcess({
326
+ return {
332
327
  code: 1,
333
- terminalOutput: undefined,
334
- });
335
- }
336
- }
337
- async startContinuousTask(task, groupId) {
338
- const taskSpecificEnv = await this.processedTasks.get(task.id);
339
- await this.preRunSteps([task], { groupId });
340
- const pipeOutput = await this.pipeOutputCapture(task);
341
- // obtain metadata
342
- const temporaryOutputPath = this.cache.temporaryOutputPath(task);
343
- const streamOutput = this.outputStyle === 'static'
344
- ? false
345
- : (0, utils_1.shouldStreamOutput)(task, this.initiatingProject);
346
- let env = pipeOutput
347
- ? (0, task_env_1.getEnvVariablesForTask)(task, taskSpecificEnv, process.env.FORCE_COLOR === undefined
348
- ? 'true'
349
- : process.env.FORCE_COLOR, this.options.skipNxCache, this.options.captureStderr, null, null)
350
- : (0, task_env_1.getEnvVariablesForTask)(task, taskSpecificEnv, undefined, this.options.skipNxCache, this.options.captureStderr, temporaryOutputPath, streamOutput);
351
- const childProcess = await this.runTask(task, streamOutput, env, temporaryOutputPath, pipeOutput);
352
- this.runningContinuousTasks.set(task.id, childProcess);
353
- childProcess.onExit((code) => {
354
- if (!this.cleaningUp) {
355
- console.error(`Task "${task.id}" is continuous but exited with code ${code}`);
356
- this.cleanup().then(() => {
357
- process.exit(1);
358
- });
359
- }
360
- });
361
- if (this.initiatingProject === task.target.project &&
362
- this.options.targets.length === 1 &&
363
- this.options.targets[0] === task.target.target) {
364
- await childProcess.getResults();
365
- }
366
- else {
367
- await this.tasksSchedule.scheduleNextTasks();
368
- // release blocked threads
369
- this.waitingForTasks.forEach((f) => f(null));
370
- this.waitingForTasks.length = 0;
328
+ };
371
329
  }
372
- return childProcess;
373
330
  }
374
331
  // endregion Single Task
375
332
  // region Lifecycle
@@ -501,17 +458,5 @@ class TaskOrchestrator {
501
458
  return this.daemon.recordOutputsHash(task.outputs, task.hash);
502
459
  }
503
460
  }
504
- // endregion utils
505
- async cleanup() {
506
- this.cleaningUp = true;
507
- await Promise.all(Array.from(this.runningContinuousTasks).map(async ([taskId, t]) => {
508
- try {
509
- return t.kill();
510
- }
511
- catch (e) {
512
- console.error(`Unable to terminate ${taskId}\nError:`, e);
513
- }
514
- }));
515
- }
516
461
  }
517
462
  exports.TaskOrchestrator = TaskOrchestrator;
@@ -147,14 +147,11 @@ class TasksSchedule {
147
147
  {
148
148
  tasks: {},
149
149
  dependencies: {},
150
- continuousDependencies: {},
151
150
  roots: [],
152
151
  });
153
152
  batch.tasks[task.id] = task;
154
153
  batch.dependencies[task.id] =
155
154
  this.notScheduledTaskGraph.dependencies[task.id];
156
- batch.continuousDependencies[task.id] =
157
- this.notScheduledTaskGraph.continuousDependencies[task.id];
158
155
  if (isRoot) {
159
156
  batch.roots.push(task.id);
160
157
  }
@@ -171,9 +168,8 @@ class TasksSchedule {
171
168
  }
172
169
  canBeScheduled(taskId) {
173
170
  const hasDependenciesCompleted = this.taskGraph.dependencies[taskId].every((id) => this.completedTasks.has(id));
174
- const hasContinuousDependenciesStarted = this.taskGraph.continuousDependencies[taskId].every((id) => this.runningTasks.has(id));
175
171
  // if dependencies have not completed, cannot schedule
176
- if (!hasDependenciesCompleted || !hasContinuousDependenciesStarted) {
172
+ if (!hasDependenciesCompleted) {
177
173
  return false;
178
174
  }
179
175
  // if there are no running tasks, can schedule anything
@@ -37,6 +37,14 @@ export declare function getExecutorForTask(task: Task, projectGraph: ProjectGrap
37
37
  };
38
38
  export declare function getCustomHasher(task: Task, projectGraph: ProjectGraph): CustomHasher | null;
39
39
  export declare function removeTasksFromTaskGraph(graph: TaskGraph, ids: string[]): TaskGraph;
40
+ export declare function removeIdsFromGraph<T>(graph: {
41
+ roots: string[];
42
+ dependencies: Record<string, string[]>;
43
+ }, ids: string[], mapWithIds: Record<string, T>): {
44
+ mapWithIds: Record<string, T>;
45
+ roots: string[];
46
+ dependencies: Record<string, string[]>;
47
+ };
40
48
  export declare function calculateReverseDeps(taskGraph: TaskGraph): Record<string, string[]>;
41
49
  export declare function getCliPath(): string;
42
50
  export declare function getPrintableCommandArgsForTask(task: Task): string[];
@@ -17,6 +17,7 @@ exports.getExecutorNameForTask = getExecutorNameForTask;
17
17
  exports.getExecutorForTask = getExecutorForTask;
18
18
  exports.getCustomHasher = getCustomHasher;
19
19
  exports.removeTasksFromTaskGraph = removeTasksFromTaskGraph;
20
+ exports.removeIdsFromGraph = removeIdsFromGraph;
20
21
  exports.calculateReverseDeps = calculateReverseDeps;
21
22
  exports.getCliPath = getCliPath;
22
23
  exports.getPrintableCommandArgsForTask = getPrintableCommandArgsForTask;
@@ -301,31 +302,27 @@ function getCustomHasher(task, projectGraph) {
301
302
  return factory ? factory() : null;
302
303
  }
303
304
  function removeTasksFromTaskGraph(graph, ids) {
304
- const newGraph = removeIdsFromTaskGraph(graph, ids, graph.tasks);
305
+ const newGraph = removeIdsFromGraph(graph, ids, graph.tasks);
305
306
  return {
306
307
  dependencies: newGraph.dependencies,
307
- continuousDependencies: newGraph.continuousDependencies,
308
308
  roots: newGraph.roots,
309
309
  tasks: newGraph.mapWithIds,
310
310
  };
311
311
  }
312
- function removeIdsFromTaskGraph(graph, ids, mapWithIds) {
312
+ function removeIdsFromGraph(graph, ids, mapWithIds) {
313
313
  const filteredMapWithIds = {};
314
314
  const dependencies = {};
315
- const continuousDependencies = {};
316
315
  const removedSet = new Set(ids);
317
316
  for (let id of Object.keys(mapWithIds)) {
318
317
  if (!removedSet.has(id)) {
319
318
  filteredMapWithIds[id] = mapWithIds[id];
320
319
  dependencies[id] = graph.dependencies[id].filter((depId) => !removedSet.has(depId));
321
- continuousDependencies[id] = graph.continuousDependencies[id].filter((depId) => !removedSet.has(depId));
322
320
  }
323
321
  }
324
322
  return {
325
323
  mapWithIds: filteredMapWithIds,
326
324
  dependencies: dependencies,
327
- continuousDependencies,
328
- roots: Object.keys(filteredMapWithIds).filter((k) => dependencies[k].length === 0 && continuousDependencies[k].length === 0),
325
+ roots: Object.keys(dependencies).filter((k) => dependencies[k].length === 0),
329
326
  };
330
327
  }
331
328
  function calculateReverseDeps(taskGraph) {
@@ -338,11 +335,6 @@ function calculateReverseDeps(taskGraph) {
338
335
  reverseTaskDeps[d].push(taskId);
339
336
  });
340
337
  });
341
- Object.keys(taskGraph.continuousDependencies).forEach((taskId) => {
342
- taskGraph.continuousDependencies[taskId].forEach((d) => {
343
- reverseTaskDeps[d].push(taskId);
344
- });
345
- });
346
338
  return reverseTaskDeps;
347
339
  }
348
340
  function getCliPath() {
@@ -1,38 +0,0 @@
1
- import { Serializable } from 'child_process';
2
- import { RunningTask } from '../../tasks-runner/running-tasks/running-task';
3
- import { ExecutorContext } from '../../config/misc-interfaces';
4
- import { NormalizedRunCommandsOptions } from './run-commands.impl';
5
- import { PseudoTerminal } from '../../tasks-runner/pseudo-terminal';
6
- export declare class ParallelRunningTasks implements RunningTask {
7
- private readonly childProcesses;
8
- private readyWhenStatus;
9
- private readonly streamOutput;
10
- private exitCallbacks;
11
- constructor(options: NormalizedRunCommandsOptions, context: ExecutorContext);
12
- getResults(): Promise<{
13
- code: number;
14
- terminalOutput: string;
15
- }>;
16
- onExit(cb: (code: number, terminalOutput: string) => void): void;
17
- send(message: Serializable): void;
18
- kill(signal?: NodeJS.Signals | number): Promise<void>;
19
- private run;
20
- }
21
- export declare class SeriallyRunningTasks implements RunningTask {
22
- private pseudoTerminal?;
23
- private terminalOutput;
24
- private currentProcess;
25
- private exitCallbacks;
26
- private code;
27
- private error;
28
- constructor(options: NormalizedRunCommandsOptions, context: ExecutorContext, pseudoTerminal?: PseudoTerminal);
29
- getResults(): Promise<{
30
- code: number;
31
- terminalOutput: string;
32
- }>;
33
- onExit(cb: (code: number, terminalOutput: string) => void): void;
34
- send(message: Serializable): void;
35
- kill(signal?: NodeJS.Signals | number): void | Promise<void>;
36
- private run;
37
- private createProcess;
38
- }