nx 23.3.0-beta.4 → 23.3.0-beta.6

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 (113) hide show
  1. package/dist/nx-cloud-internals.d.ts +1 -0
  2. package/dist/nx-cloud-internals.js +9 -0
  3. package/dist/plugins/package-json.js +1 -1
  4. package/dist/src/command-line/affected/affected.js +51 -9
  5. package/dist/src/command-line/graph/graph.d.ts +31 -0
  6. package/dist/src/command-line/graph/graph.js +71 -17
  7. package/dist/src/command-line/release/publish.js +7 -11
  8. package/dist/src/command-line/release/utils/get-touched-projects-for-group.js +3 -3
  9. package/dist/src/command-line/run/run-one.js +5 -1
  10. package/dist/src/command-line/run-many/run-many.js +6 -12
  11. package/dist/src/command-line/show/projects.js +30 -1
  12. package/dist/src/config/task-graph.d.ts +1 -1
  13. package/dist/src/config/workspace-json-project-json.d.ts +21 -1
  14. package/dist/src/core/graph/main.js +1 -1
  15. package/dist/src/core/graph/runtime.js +1 -1
  16. package/dist/src/core/graph/styles.js +1 -1
  17. package/dist/src/daemon/client/client.d.ts +7 -2
  18. package/dist/src/daemon/client/client.js +15 -2
  19. package/dist/src/daemon/message-types/io-snapshot-version.d.ts +5 -0
  20. package/dist/src/daemon/message-types/io-snapshot-version.js +2 -0
  21. package/dist/src/daemon/message-types/select-affected-tasks.d.ts +18 -0
  22. package/dist/src/daemon/message-types/select-affected-tasks.js +11 -0
  23. package/dist/src/daemon/server/handle-hash-tasks.d.ts +2 -0
  24. package/dist/src/daemon/server/handle-hash-tasks.js +5 -3
  25. package/dist/src/daemon/server/handle-select-affected-tasks.d.ts +3 -0
  26. package/dist/src/daemon/server/handle-select-affected-tasks.js +23 -0
  27. package/dist/src/daemon/server/io-snapshots-state.d.ts +7 -0
  28. package/dist/src/daemon/server/io-snapshots-state.js +35 -0
  29. package/dist/src/daemon/server/planning-context.d.ts +8 -0
  30. package/dist/src/daemon/server/planning-context.js +18 -0
  31. package/dist/src/daemon/server/server.d.ts +1 -0
  32. package/dist/src/daemon/server/server.js +6 -0
  33. package/dist/src/executors/run-commands/run-commands.impl.d.ts +2 -1
  34. package/dist/src/executors/run-commands/run-commands.impl.js +19 -5
  35. package/dist/src/executors/run-commands/running-tasks.d.ts +5 -4
  36. package/dist/src/executors/run-commands/running-tasks.js +13 -13
  37. package/dist/src/hasher/create-task-hasher.d.ts +8 -1
  38. package/dist/src/hasher/create-task-hasher.js +13 -3
  39. package/dist/src/hasher/hash-plan-inspector.js +2 -2
  40. package/dist/src/hasher/hash-task.d.ts +2 -2
  41. package/dist/src/hasher/hash-task.js +7 -1
  42. package/dist/src/hasher/native-task-hasher-impl.d.ts +13 -5
  43. package/dist/src/hasher/native-task-hasher-impl.js +38 -15
  44. package/dist/src/hasher/task-hasher.d.ts +17 -9
  45. package/dist/src/hasher/task-hasher.js +16 -11
  46. package/dist/src/hasher/task-planning-context.d.ts +13 -0
  47. package/dist/src/hasher/task-planning-context.js +12 -0
  48. package/dist/src/io-snapshots/config.d.ts +23 -0
  49. package/dist/src/io-snapshots/config.js +32 -0
  50. package/dist/src/io-snapshots/fetch.d.ts +21 -0
  51. package/dist/src/io-snapshots/fetch.js +43 -0
  52. package/dist/src/io-snapshots/outputs.d.ts +12 -0
  53. package/dist/src/io-snapshots/outputs.js +33 -0
  54. package/dist/src/io-snapshots/overrides.d.ts +12 -0
  55. package/dist/src/io-snapshots/overrides.js +49 -0
  56. package/dist/src/io-snapshots/report.d.ts +13 -0
  57. package/dist/src/io-snapshots/report.js +68 -0
  58. package/dist/src/io-snapshots/store.d.ts +37 -0
  59. package/dist/src/io-snapshots/store.js +162 -0
  60. package/dist/src/native/index.d.ts +264 -2
  61. package/dist/src/native/native-bindings.js +10 -0
  62. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  63. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  64. package/dist/src/native/transform-objects.d.ts +11 -2
  65. package/dist/src/native/transform-objects.js +46 -0
  66. package/dist/src/nx-cloud/update-manager.d.ts +3 -0
  67. package/dist/src/plugins/js/project-graph/affected/lock-file-changes.d.ts +10 -2
  68. package/dist/src/plugins/js/project-graph/affected/lock-file-changes.js +51 -29
  69. package/dist/src/plugins/js/project-graph/affected/npm-packages.d.ts +10 -2
  70. package/dist/src/plugins/js/project-graph/affected/npm-packages.js +32 -11
  71. package/dist/src/plugins/package-json/create-nodes.d.ts +2 -2
  72. package/dist/src/plugins/package-json/create-nodes.js +13 -13
  73. package/dist/src/project-graph/affected/affected-project-graph-models.d.ts +14 -0
  74. package/dist/src/project-graph/affected/affected-project-graph.js +5 -18
  75. package/dist/src/project-graph/affected/affected-projects.d.ts +7 -0
  76. package/dist/src/project-graph/affected/affected-projects.js +42 -0
  77. package/dist/src/project-graph/affected/affected-tasks.d.ts +90 -0
  78. package/dist/src/project-graph/affected/affected-tasks.js +214 -0
  79. package/dist/src/project-graph/file-utils.js +6 -2
  80. package/dist/src/project-graph/utils/project-configuration/target-merging.js +67 -0
  81. package/dist/src/project-graph/utils/project-configuration/target-normalization.js +83 -0
  82. package/dist/src/project-graph/utils/project-configuration/utils.d.ts +1 -0
  83. package/dist/src/project-graph/utils/project-configuration/utils.js +1 -0
  84. package/dist/src/tasks-runner/create-task-graph.d.ts +24 -1
  85. package/dist/src/tasks-runner/create-task-graph.js +56 -2
  86. package/dist/src/tasks-runner/forked-process-task-runner.js +3 -3
  87. package/dist/src/tasks-runner/init-tasks-runner.d.ts +7 -2
  88. package/dist/src/tasks-runner/init-tasks-runner.js +17 -6
  89. package/dist/src/tasks-runner/run-command.d.ts +41 -5
  90. package/dist/src/tasks-runner/run-command.js +84 -18
  91. package/dist/src/tasks-runner/task-io-service.d.ts +11 -3
  92. package/dist/src/tasks-runner/task-io-service.js +14 -5
  93. package/dist/src/tasks-runner/task-orchestrator.js +1 -1
  94. package/dist/src/tasks-runner/utils.d.ts +5 -0
  95. package/dist/src/tasks-runner/utils.js +9 -0
  96. package/dist/src/utils/db-connection.d.ts +1 -0
  97. package/dist/src/utils/db-connection.js +1 -0
  98. package/dist/src/utils/json-diff.d.ts +4 -2
  99. package/dist/src/utils/json-diff.js +6 -94
  100. package/dist/src/utils/nx-cloud-utils.d.ts +2 -0
  101. package/dist/src/utils/nx-cloud-utils.js +6 -1
  102. package/dist/src/utils/project-graph-utils.d.ts +2 -0
  103. package/dist/src/utils/project-graph-utils.js +12 -0
  104. package/package.json +22 -13
  105. package/readme-template.md +16 -0
  106. package/schemas/nx-schema.json +34 -0
  107. package/schemas/project-schema.json +31 -0
  108. package/dist/src/project-graph/affected/locators/project-glob-changes.d.ts +0 -2
  109. package/dist/src/project-graph/affected/locators/project-glob-changes.js +0 -40
  110. package/dist/src/project-graph/affected/locators/workspace-json-changes.d.ts +0 -4
  111. package/dist/src/project-graph/affected/locators/workspace-json-changes.js +0 -47
  112. package/dist/src/project-graph/affected/locators/workspace-projects.d.ts +0 -3
  113. package/dist/src/project-graph/affected/locators/workspace-projects.js +0 -74
@@ -8,10 +8,11 @@ const dotenv_1 = require("../utils/dotenv");
8
8
  const life_cycle_1 = require("./life-cycle");
9
9
  const task_orchestrator_1 = require("./task-orchestrator");
10
10
  const create_task_hasher_1 = require("../hasher/create-task-hasher");
11
+ const outputs_1 = require("../io-snapshots/outputs");
11
12
  const client_1 = require("../daemon/client/client");
12
13
  const shared_running_task_1 = require("./running-tasks/shared-running-task");
13
14
  const task_results_life_cycle_1 = require("./life-cycles/task-results-life-cycle");
14
- async function createOrchestrator(tasks, projectGraph, fullTaskGraph, nxJson, lifeCycle) {
15
+ async function createOrchestrator(tasks, projectGraph, fullTaskGraph, nxJson, lifeCycle, ioSnapshots) {
15
16
  (0, dotenv_1.loadRootEnvFiles)();
16
17
  const invokeRunnerTerminalLifecycle = new invoke_runner_terminal_output_life_cycle_1.InvokeRunnerTerminalOutputLifeCycle(tasks);
17
18
  const taskResultsLifecycle = new task_results_life_cycle_1.TaskResultsLifeCycle();
@@ -21,7 +22,6 @@ async function createOrchestrator(tasks, projectGraph, fullTaskGraph, nxJson, li
21
22
  lifeCycle,
22
23
  ]);
23
24
  const { runnerOptions: options } = (0, run_command_1.getRunner)({}, nxJson);
24
- let hasher = (0, create_task_hasher_1.createTaskHasher)(projectGraph, nxJson, options);
25
25
  const taskGraph = {
26
26
  roots: tasks.map((task) => task.id),
27
27
  tasks: tasks.reduce((acc, task) => {
@@ -37,6 +37,13 @@ async function createOrchestrator(tasks, projectGraph, fullTaskGraph, nxJson, li
37
37
  return acc;
38
38
  }, {}),
39
39
  };
40
+ // As in run-command, unhashed tasks hash from the caller's set. Applying is
41
+ // idempotent, so both graphs may share the same Task objects.
42
+ if (ioSnapshots) {
43
+ (0, outputs_1.applyIoSnapshotOutputs)(projectGraph, fullTaskGraph, ioSnapshots);
44
+ (0, outputs_1.applyIoSnapshotOutputs)(projectGraph, taskGraph, ioSnapshots);
45
+ }
46
+ const hasher = (0, create_task_hasher_1.createTaskHasher)(projectGraph, nxJson, options, ioSnapshots);
40
47
  const nxArgs = {
41
48
  ...options,
42
49
  parallel: tasks.length,
@@ -57,8 +64,10 @@ async function createOrchestrator(tasks, projectGraph, fullTaskGraph, nxJson, li
57
64
  function logDisposeFailure(e) {
58
65
  console.error('Failed to dispose the task orchestrator:', e);
59
66
  }
60
- async function runDiscreteTasks(tasks, projectGraph, fullTaskGraph, nxJson, lifeCycle) {
61
- const orchestrator = await createOrchestrator(tasks, projectGraph, fullTaskGraph, nxJson, lifeCycle);
67
+ async function runDiscreteTasks(tasks, projectGraph, fullTaskGraph, nxJson, lifeCycle,
68
+ /** The set to hash from, e.g. from `importIoSnapshots`; omitted hashes natively. */
69
+ ioSnapshots) {
70
+ const orchestrator = await createOrchestrator(tasks, projectGraph, fullTaskGraph, nxJson, lifeCycle, ioSnapshots);
62
71
  let groupId = 0;
63
72
  let nextBatch = orchestrator.nextBatch();
64
73
  const batchResults = [];
@@ -96,8 +105,10 @@ async function runDiscreteTasks(tasks, projectGraph, fullTaskGraph, nxJson, life
96
105
  .catch(logDisposeFailure);
97
106
  return results;
98
107
  }
99
- async function runContinuousTasks(tasks, projectGraph, fullTaskGraph, nxJson, lifeCycle) {
100
- const orchestrator = await createOrchestrator(tasks, projectGraph, fullTaskGraph, nxJson, lifeCycle);
108
+ async function runContinuousTasks(tasks, projectGraph, fullTaskGraph, nxJson, lifeCycle,
109
+ /** The set to hash from, e.g. from `importIoSnapshots`; omitted hashes natively. */
110
+ ioSnapshots) {
111
+ const orchestrator = await createOrchestrator(tasks, projectGraph, fullTaskGraph, nxJson, lifeCycle, ioSnapshots);
101
112
  const runningTasks = tasks.reduce((current, task, index) => {
102
113
  current[task.id] = orchestrator.startContinuousTask(task, index);
103
114
  return current;
@@ -1,17 +1,42 @@
1
- import { NxJsonConfiguration } from '../config/nx-json';
2
- import { ProjectGraph, ProjectGraphProjectNode } from '../config/project-graph';
1
+ import { NxJsonConfiguration, TargetDependencies } from '../config/nx-json';
2
+ import { ProjectGraph } from '../config/project-graph';
3
3
  import { Task, TaskGraph } from '../config/task-graph';
4
4
  import { TargetDependencyConfig } from '../config/workspace-json-project-json';
5
5
  import { NxArgs } from '../utils/command-line-utils';
6
+ import { type IoSnapshotOutcome } from '../io-snapshots/store';
7
+ import type { TaskPlanningContext } from '../hasher/task-planning-context';
8
+ /** What a command runs. */
9
+ export interface TaskSelection {
10
+ taskGraph: TaskGraph;
11
+ /**
12
+ * The tasks the command asked for, as opposed to ones pulled in as
13
+ * dependencies. A graph rebuilt after a sync is built from their projects.
14
+ */
15
+ initiatingTaskIds: string[];
16
+ /**
17
+ * What a rebuilt graph is pruned to: the selected tasks and everything they
18
+ * depend on. Unset keeps the whole rebuilt graph.
19
+ */
20
+ taskIds?: string[];
21
+ /** The planner selection used. It remembers those plans, so hashing the run reuses them. */
22
+ planningContext?: TaskPlanningContext;
23
+ /** The I/O snapshot set selection planned with; the run hashes with the same one. */
24
+ ioSnapshotOutcome?: IoSnapshotOutcome | null;
25
+ }
6
26
  import { LifeCycle, TaskResult, TaskResults } from './life-cycle';
7
27
  import { TasksRunner } from './tasks-runner';
8
- export declare function runCommand(projectsToRun: ProjectGraphProjectNode[], currentProjectGraph: ProjectGraph, { nxJson }: {
28
+ /**
29
+ * `targets` on whole projects, as `run-many` runs them: every task of the
30
+ * projects' targets and what they depend on, with those tasks initiating.
31
+ */
32
+ export declare function selectTasksForProjects(projectGraph: ProjectGraph, projectNames: string[], nxArgs: NxArgs, overrides: any, extraTargetDependencies: TargetDependencies, excludeTaskDependencies: boolean): TaskSelection;
33
+ export declare function runCommand(taskSelection: TaskSelection, currentProjectGraph: ProjectGraph, { nxJson }: {
9
34
  nxJson: NxJsonConfiguration;
10
35
  }, nxArgs: NxArgs, overrides: any, initiatingProject: string | null, extraTargetDependencies: Record<string, (TargetDependencyConfig | string)[]>, extraOptions: {
11
36
  excludeTaskDependencies: boolean;
12
37
  loadDotEnvFiles: boolean;
13
38
  }): Promise<NodeJS.Process['exitCode']>;
14
- export declare function runCommandForTasks(projectsToRun: ProjectGraphProjectNode[], currentProjectGraph: ProjectGraph, { nxJson }: {
39
+ export declare function runTasksForCommand(taskSelection: TaskSelection, currentProjectGraph: ProjectGraph, { nxJson }: {
15
40
  nxJson: NxJsonConfiguration;
16
41
  }, nxArgs: NxArgs, overrides: any, initiatingProject: string | null, extraTargetDependencies: Record<string, (TargetDependencyConfig | string)[]>, extraOptions: {
17
42
  excludeTaskDependencies: boolean;
@@ -21,7 +46,7 @@ export declare function runCommandForTasks(projectsToRun: ProjectGraphProjectNod
21
46
  completed: boolean;
22
47
  }>;
23
48
  export declare function setEnvVarsBasedOnArgs(nxArgs: NxArgs, loadDotEnvFiles: boolean): void;
24
- export declare function invokeTasksRunner({ tasks, projectGraph, taskGraph, lifeCycle, nxJson, nxArgs, loadDotEnvFiles, initiatingProject, initiatingTasks, }: {
49
+ export declare function invokeTasksRunner({ tasks, projectGraph, taskGraph, lifeCycle, nxJson, nxArgs, loadDotEnvFiles, initiatingProject, initiatingTasks, planningContext, ioSnapshotOutcome: loadedIoSnapshotOutcome, }: {
25
50
  tasks: Task[];
26
51
  projectGraph: ProjectGraph;
27
52
  taskGraph: TaskGraph;
@@ -31,10 +56,21 @@ export declare function invokeTasksRunner({ tasks, projectGraph, taskGraph, life
31
56
  loadDotEnvFiles: boolean;
32
57
  initiatingProject: string | null;
33
58
  initiatingTasks: Task[];
59
+ planningContext?: TaskPlanningContext;
60
+ /** Already loaded for this command; `undefined` loads it here. */
61
+ ioSnapshotOutcome?: IoSnapshotOutcome | null;
34
62
  }): Promise<{
35
63
  [id: string]: TaskResult;
36
64
  }>;
37
65
  export declare function constructLifeCycles(lifeCycle: LifeCycle, taskGraph: TaskGraph, nxJson?: NxJsonConfiguration, skipNxCache?: boolean): LifeCycle[];
66
+ /**
67
+ * What affected task selection reads from the runner options, so it plans as
68
+ * the run hashes. The snapshot set is loaded once, for selection and the run.
69
+ */
70
+ export declare function runnerInputsForSelection(nxArgs: NxArgs, nxJson: NxJsonConfiguration): Promise<{
71
+ ioSnapshotOutcome: IoSnapshotOutcome | null;
72
+ selectivelyHashTsConfig: boolean;
73
+ }>;
38
74
  export declare function getRunner(nxArgs: NxArgs, nxJson: NxJsonConfiguration): {
39
75
  tasksRunner: TasksRunner;
40
76
  runnerOptions: any;
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.selectTasksForProjects = selectTasksForProjects;
3
4
  exports.runCommand = runCommand;
4
- exports.runCommandForTasks = runCommandForTasks;
5
+ exports.runTasksForCommand = runTasksForCommand;
5
6
  exports.setEnvVarsBasedOnArgs = setEnvVarsBasedOnArgs;
6
7
  exports.invokeTasksRunner = invokeTasksRunner;
7
8
  exports.constructLifeCycles = constructLifeCycles;
9
+ exports.runnerInputsForSelection = runnerInputsForSelection;
8
10
  exports.getRunner = getRunner;
9
11
  exports.getRunnerOptions = getRunnerOptions;
10
12
  const tslib_1 = require("tslib");
@@ -23,6 +25,10 @@ const is_ci_1 = require("../utils/is-ci");
23
25
  const nx_cloud_utils_1 = require("../utils/nx-cloud-utils");
24
26
  const update_manager_1 = require("../nx-cloud/update-manager");
25
27
  const logger_1 = require("../utils/logger");
28
+ const outputs_1 = require("../io-snapshots/outputs");
29
+ const overrides_1 = require("../io-snapshots/overrides");
30
+ const report_1 = require("../io-snapshots/report");
31
+ const store_1 = require("../io-snapshots/store");
26
32
  const nx_key_1 = require("../utils/nx-key");
27
33
  const output_1 = require("../utils/output");
28
34
  const configure_ai_agents_disclaimer_1 = require("../ai/configure-ai-agents-disclaimer");
@@ -305,8 +311,22 @@ async function getTerminalOutputLifeCycle(initiatingProject, initiatingTasks, pr
305
311
  }
306
312
  }
307
313
  }
308
- function createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies, projectNames, nxArgs, overrides, extraOptions) {
309
- const taskGraph = (0, create_task_graph_1.createTaskGraph)(projectGraph, extraTargetDependencies, projectNames, nxArgs.targets, nxArgs.configuration, overrides, extraOptions.excludeTaskDependencies);
314
+ /**
315
+ * `targets` on whole projects, as `run-many` runs them: every task of the
316
+ * projects' targets and what they depend on, with those tasks initiating.
317
+ */
318
+ function selectTasksForProjects(projectGraph, projectNames, nxArgs, overrides, extraTargetDependencies, excludeTaskDependencies) {
319
+ const taskGraph = (0, create_task_graph_1.createTaskGraph)(projectGraph, extraTargetDependencies, projectNames, nxArgs.targets, nxArgs.configuration, overrides, excludeTaskDependencies);
320
+ const projects = new Set(projectNames);
321
+ return {
322
+ taskGraph,
323
+ initiatingTaskIds: Object.values(taskGraph.tasks)
324
+ .filter((t) => projects.has(t.target.project) &&
325
+ nxArgs.targets.includes(t.target.target))
326
+ .map((t) => t.id),
327
+ };
328
+ }
329
+ function runValidations(projectGraph, taskGraph, nxArgs) {
310
330
  (0, task_graph_utils_1.assertTaskGraphDoesNotContainInvalidTargets)(taskGraph);
311
331
  const cycle = (0, task_graph_utils_1.findCycle)(taskGraph);
312
332
  if (cycle) {
@@ -332,7 +352,7 @@ function createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies,
332
352
  }
333
353
  return taskGraph;
334
354
  }
335
- async function runCommand(projectsToRun, currentProjectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
355
+ async function runCommand(taskSelection, currentProjectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
336
356
  const status = await (0, handle_errors_1.handleErrors)(process.env.NX_VERBOSE_LOGGING === 'true', async () => {
337
357
  const id = (0, native_1.hashArray)([...process.argv, Date.now().toString()]);
338
358
  await (0, tasks_execution_hooks_1.runPreTasksExecution)({
@@ -342,7 +362,7 @@ async function runCommand(projectsToRun, currentProjectGraph, { nxJson }, nxArgs
342
362
  argv: process.argv,
343
363
  });
344
364
  const startTime = Date.now();
345
- const { taskResults, completed } = await runCommandForTasks(projectsToRun, currentProjectGraph, { nxJson }, {
365
+ const { taskResults, completed } = await runTasksForCommand(taskSelection, currentProjectGraph, { nxJson }, {
346
366
  ...nxArgs,
347
367
  skipNxCache: nxArgs.skipNxCache ||
348
368
  process.env.NX_SKIP_NX_CACHE === 'true' ||
@@ -368,17 +388,20 @@ async function runCommand(projectsToRun, currentProjectGraph, { nxJson }, nxArgs
368
388
  });
369
389
  return status;
370
390
  }
371
- async function runCommandForTasks(projectsToRun, currentProjectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
391
+ async function runTasksForCommand(taskSelection, currentProjectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
372
392
  // Kick off the license lookup in the background so it overlaps with task
373
393
  // execution. The log itself is deferred to the print site below so it
374
394
  // never lands in the middle of task output.
375
395
  const nxKeyPromise = (0, nx_key_1.getNxKeyInformation)().catch(() => null);
376
- const projectNames = projectsToRun.map((t) => t.name);
377
- const projectNameSet = new Set(projectNames);
378
- const { projectGraph, taskGraph } = await ensureWorkspaceIsInSyncAndGetGraphs(currentProjectGraph, nxJson, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions);
396
+ const { projectGraph, taskGraph } = await ensureWorkspaceIsInSyncAndGetGraphs(currentProjectGraph, nxJson, nxArgs, overrides, extraTargetDependencies, extraOptions, taskSelection);
379
397
  const tasks = Object.values(taskGraph.tasks);
380
- const initiatingTasks = tasks.filter((t) => projectNameSet.has(t.target.project) &&
381
- nxArgs.targets.includes(t.target.target));
398
+ // A sync generator can remove a selected task, so absent ids are skipped.
399
+ const initiatingTasks = taskSelection.initiatingTaskIds
400
+ .map((id) => taskGraph.tasks[id])
401
+ .filter(Boolean);
402
+ const projectNames = [
403
+ ...new Set(initiatingTasks.map((t) => t.target.project)),
404
+ ];
382
405
  const { lifeCycle, renderIsDone, printSummary, restoreTerminal } = await getTerminalOutputLifeCycle(initiatingProject, initiatingTasks, projectNames, tasks, taskGraph, nxArgs, nxJson, overrides);
383
406
  try {
384
407
  const taskResults = await invokeTasksRunner({
@@ -391,6 +414,8 @@ async function runCommandForTasks(projectsToRun, currentProjectGraph, { nxJson }
391
414
  loadDotEnvFiles: extraOptions.loadDotEnvFiles,
392
415
  initiatingProject,
393
416
  initiatingTasks,
417
+ planningContext: taskSelection.planningContext,
418
+ ioSnapshotOutcome: taskSelection.ioSnapshotOutcome,
394
419
  });
395
420
  await renderIsDone.finally(() => restoreTerminal?.());
396
421
  if (printSummary) {
@@ -447,8 +472,8 @@ function didCommandComplete(tasks, taskResults) {
447
472
  // Any stopped task means the run was interrupted
448
473
  return !Object.values(taskResults).some((r) => r.status === 'stopped');
449
474
  }
450
- async function ensureWorkspaceIsInSyncAndGetGraphs(projectGraph, nxJson, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions) {
451
- let taskGraph = createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies ?? {}, projectNames, nxArgs, overrides, extraOptions);
475
+ async function ensureWorkspaceIsInSyncAndGetGraphs(projectGraph, nxJson, nxArgs, overrides, extraTargetDependencies, extraOptions, taskSelection) {
476
+ let taskGraph = runValidations(projectGraph, taskSelection.taskGraph, nxArgs);
452
477
  if (nxArgs.skipSync || (0, is_ci_1.isCI)()) {
453
478
  return { projectGraph, taskGraph };
454
479
  }
@@ -563,9 +588,21 @@ async function ensureWorkspaceIsInSyncAndGetGraphs(projectGraph, nxJson, project
563
588
  });
564
589
  await confirmRunningTasksWithSyncFailures();
565
590
  }
566
- // Re-create project graph and task graph
591
+ // Rebuild rather than carry: a sync generator may remove tasks or move inferred
592
+ // outputs, so the old graph and planning context are stale.
593
+ taskSelection.planningContext = undefined;
594
+ const projectNames = [
595
+ ...new Set(taskSelection.initiatingTaskIds
596
+ .filter((id) => taskGraph.tasks[id])
597
+ .map((id) => taskGraph.tasks[id].target.project)),
598
+ ];
567
599
  projectGraph = await (0, project_graph_1.createProjectGraphAsync)();
568
- taskGraph = createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies ?? {}, projectNames, nxArgs, overrides, extraOptions);
600
+ const rebuilt = selectTasksForProjects(projectGraph, projectNames, nxArgs, overrides, extraTargetDependencies ?? {}, extraOptions.excludeTaskDependencies).taskGraph;
601
+ taskGraph = runValidations(projectGraph,
602
+ // Before validation, so a cycle or atomizer error names what will actually run.
603
+ taskSelection.taskIds
604
+ ? (0, utils_1.pruneToSelectedTasks)(rebuilt, taskSelection.taskIds)
605
+ : rebuilt, nxArgs);
569
606
  const successTitle = anySyncGeneratorsFailed
570
607
  ? // the identified changes were synced successfully, but the workspace
571
608
  // is still not up to date, which we'll mention next
@@ -669,16 +706,26 @@ function setEnvVarsBasedOnArgs(nxArgs, loadDotEnvFiles) {
669
706
  process.env.NX_LOAD_DOT_ENV_FILES = 'true';
670
707
  }
671
708
  }
672
- async function invokeTasksRunner({ tasks, projectGraph, taskGraph, lifeCycle, nxJson, nxArgs, loadDotEnvFiles, initiatingProject, initiatingTasks, }) {
709
+ async function invokeTasksRunner({ tasks, projectGraph, taskGraph, lifeCycle, nxJson, nxArgs, loadDotEnvFiles, initiatingProject, initiatingTasks, planningContext, ioSnapshotOutcome: loadedIoSnapshotOutcome, }) {
673
710
  setEnvVarsBasedOnArgs(nxArgs, loadDotEnvFiles);
674
711
  // this needs to be done before we start to run the tasks
675
712
  const taskDetails = (0, hash_task_1.getTaskDetails)();
676
713
  const { tasksRunner, runnerOptions } = getRunner(nxArgs, nxJson);
677
- let hasher = (0, create_task_hasher_1.createTaskHasher)(projectGraph, nxJson, runnerOptions);
714
+ // Must precede hashing: the set is the snapshot source for task hashes,
715
+ // and observed outputs join the task outputs the hasher and cache see.
716
+ const ioSnapshotOutcome = loadedIoSnapshotOutcome !== undefined
717
+ ? loadedIoSnapshotOutcome
718
+ : await (0, store_1.loadIoSnapshotsForRun)(nxJson, runnerOptions);
719
+ const ioSnapshots = (0, store_1.snapshotsOf)(ioSnapshotOutcome);
720
+ if (ioSnapshots) {
721
+ (0, outputs_1.applyIoSnapshotOutputs)(projectGraph, taskGraph, ioSnapshots);
722
+ }
723
+ let hasher = (0, create_task_hasher_1.createTaskHasher)(projectGraph, nxJson, runnerOptions, ioSnapshots, planningContext);
678
724
  // this is used for two reasons: to fetch all remote cache hits AND
679
725
  // to submit everything that is known in advance to Nx Cloud to run in
680
726
  // a distributed fashion
681
- await (0, hash_task_1.hashTasksThatDoNotDependOnOutputsOfOtherTasks)(hasher, projectGraph, taskGraph, nxJson, taskDetails);
727
+ await (0, hash_task_1.hashTasksThatDoNotDependOnOutputsOfOtherTasks)(hasher, projectGraph, taskGraph, nxJson, taskDetails, ioSnapshots);
728
+ reportIoSnapshots(ioSnapshotOutcome, projectGraph, taskGraph, nxArgs);
682
729
  const taskResultsLifecycle = new task_results_life_cycle_1.TaskResultsLifeCycle();
683
730
  const compositedLifeCycle = new life_cycle_1.CompositeLifeCycle([
684
731
  ...constructLifeCycles(lifeCycle, taskGraph, nxJson, nxArgs.skipNxCache),
@@ -825,6 +872,25 @@ function loadTasksRunner(modulePath) {
825
872
  throw e;
826
873
  }
827
874
  }
875
+ function reportIoSnapshots(outcome, projectGraph, taskGraph, nxArgs) {
876
+ if (!outcome || outcome.status === 'skipped')
877
+ return;
878
+ if (!nxArgs.verbose && process.env.NX_VERBOSE_LOGGING !== 'true')
879
+ return;
880
+ const summary = (0, report_1.formatIoSnapshotSummary)((0, overrides_1.buildIoSnapshotOverrides)(projectGraph, taskGraph, outcome.snapshots), outcome.status);
881
+ output_1.output.note({ title: summary.line, bodyLines: summary.bodyLines });
882
+ }
883
+ /**
884
+ * What affected task selection reads from the runner options, so it plans as
885
+ * the run hashes. The snapshot set is loaded once, for selection and the run.
886
+ */
887
+ async function runnerInputsForSelection(nxArgs, nxJson) {
888
+ const { runnerOptions } = getRunner(nxArgs, nxJson);
889
+ return {
890
+ ioSnapshotOutcome: await (0, store_1.loadIoSnapshotsForRun)(nxJson, runnerOptions),
891
+ selectivelyHashTsConfig: runnerOptions?.selectivelyHashTsConfig ?? false,
892
+ };
893
+ }
828
894
  function getRunner(nxArgs, nxJson) {
829
895
  let runner = nxArgs.runner;
830
896
  runner = runner ?? 'default';
@@ -1,3 +1,4 @@
1
+ import type { Task } from '../config/task-graph';
1
2
  /**
2
3
  * Maps taskId -> PID. Note that this only Returns
3
4
  * the PID that the main task process is running under,
@@ -89,8 +90,15 @@ export declare function getTaskIOService(): TaskIOService;
89
90
  /**
90
91
  * Register a task process start with both IO and metrics services.
91
92
  * This is the standard way to notify the system that a task process has started.
92
- * Both services need to be notified together - TaskIOService for external subscribers
93
- * and ProcessMetricsService for native resource monitoring.
93
+ *
94
+ * A target on `ultracache: { mode: 'off' }` reports no PID, which suppresses IO
95
+ * tracing and therefore its report. Every other mode records — they differ in
96
+ * what is done with the recording, not in whether it is taken. Metrics are
97
+ * registered either way: the opt-out covers reporting, not the process
98
+ * management that cleanup and orphan reaping depend on.
99
+ *
100
+ * Narrower than a whole `Task` because `run-commands` can synthesize an id for
101
+ * a task that is not in any graph.
94
102
  */
95
- export declare function registerTaskProcessStart(taskId: string, pid: number): void;
103
+ export declare function registerTaskProcessStart(task: Pick<Task, 'id' | 'ultracache'>, pid: number): void;
96
104
  export {};
@@ -113,10 +113,19 @@ function getTaskIOService() {
113
113
  /**
114
114
  * Register a task process start with both IO and metrics services.
115
115
  * This is the standard way to notify the system that a task process has started.
116
- * Both services need to be notified together - TaskIOService for external subscribers
117
- * and ProcessMetricsService for native resource monitoring.
116
+ *
117
+ * A target on `ultracache: { mode: 'off' }` reports no PID, which suppresses IO
118
+ * tracing and therefore its report. Every other mode records — they differ in
119
+ * what is done with the recording, not in whether it is taken. Metrics are
120
+ * registered either way: the opt-out covers reporting, not the process
121
+ * management that cleanup and orphan reaping depend on.
122
+ *
123
+ * Narrower than a whole `Task` because `run-commands` can synthesize an id for
124
+ * a task that is not in any graph.
118
125
  */
119
- function registerTaskProcessStart(taskId, pid) {
120
- getTaskIOService().notifyPidUpdate({ taskId, pid });
121
- (0, process_metrics_service_1.getProcessMetricsService)().registerTaskProcess(taskId, pid);
126
+ function registerTaskProcessStart(task, pid) {
127
+ if (task.ultracache?.mode !== 'off') {
128
+ getTaskIOService().notifyPidUpdate({ taskId: task.id, pid });
129
+ }
130
+ (0, process_metrics_service_1.getProcessMetricsService)().registerTaskProcess(task.id, pid);
122
131
  }
@@ -1019,7 +1019,7 @@ class TaskOrchestrator {
1019
1019
  };
1020
1020
  const runningTask = await (0, run_commands_impl_1.runCommands)(runCommandsOptions, {
1021
1021
  root: workspace_root_1.workspaceRoot, // only root is needed in runCommands
1022
- }, task.id);
1022
+ }, task);
1023
1023
  this.runningRunCommandsTasks.set(task.id, runningTask);
1024
1024
  runningTask.onExit(() => {
1025
1025
  this.runningRunCommandsTasks.delete(task.id);
@@ -49,6 +49,11 @@ export declare function getExecutorForTask(task: Task, projects: Record<string,
49
49
  isNxExecutor: boolean;
50
50
  };
51
51
  export declare function getCustomHasher(task: Task, projects: Record<string, ProjectConfiguration>): CustomHasher | null;
52
+ /**
53
+ * `taskGraph` pruned to `required`, which must already hold its dependencies.
54
+ * Unknown ids are ignored: a sync generator can remove a task after selection.
55
+ */
56
+ export declare function pruneToSelectedTasks(taskGraph: TaskGraph, required: Iterable<string>): TaskGraph;
52
57
  export declare function removeTasksFromTaskGraph(graph: TaskGraph, ids: string[]): TaskGraph;
53
58
  export declare function calculateReverseDeps(taskGraph: TaskGraph): Record<string, string[]>;
54
59
  export declare function getCliPath(): string;
@@ -17,6 +17,7 @@ exports.getExecutorNameForTask = getExecutorNameForTask;
17
17
  exports.expandInitiatingTasksThroughNoop = expandInitiatingTasksThroughNoop;
18
18
  exports.getExecutorForTask = getExecutorForTask;
19
19
  exports.getCustomHasher = getCustomHasher;
20
+ exports.pruneToSelectedTasks = pruneToSelectedTasks;
20
21
  exports.removeTasksFromTaskGraph = removeTasksFromTaskGraph;
21
22
  exports.calculateReverseDeps = calculateReverseDeps;
22
23
  exports.getCliPath = getCliPath;
@@ -344,6 +345,14 @@ function getCustomHasher(task, projects) {
344
345
  const factory = getExecutorForTask(task, projects).hasherFactory;
345
346
  return factory ? factory() : null;
346
347
  }
348
+ /**
349
+ * `taskGraph` pruned to `required`, which must already hold its dependencies.
350
+ * Unknown ids are ignored: a sync generator can remove a task after selection.
351
+ */
352
+ function pruneToSelectedTasks(taskGraph, required) {
353
+ const keep = new Set(required);
354
+ return removeTasksFromTaskGraph(taskGraph, Object.keys(taskGraph.tasks).filter((id) => !keep.has(id)));
355
+ }
347
356
  function removeTasksFromTaskGraph(graph, ids) {
348
357
  const newGraph = removeIdsFromTaskGraph(graph, ids, graph.tasks);
349
358
  return {
@@ -1,4 +1,5 @@
1
1
  import { ExternalObject } from '../native';
2
+ export declare function sharedWorkspaceDataDirectory(root: string): string;
2
3
  export declare function getDbConnection(opts?: {
3
4
  directory?: string;
4
5
  dbName?: string;
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sharedWorkspaceDataDirectory = sharedWorkspaceDataDirectory;
3
4
  exports.getDbConnection = getDbConnection;
4
5
  exports.getLocalDbConnection = getLocalDbConnection;
5
6
  const native_1 = require("../native");
@@ -13,6 +13,8 @@ export interface JsonChange extends Change {
13
13
  };
14
14
  }
15
15
  export declare function isJsonChange(change: Change): change is JsonChange;
16
+ /**
17
+ * The changes from `lhs` to `rhs`: every path whose value was deleted or
18
+ * modified, containers included, then every added path.
19
+ */
16
20
  export declare function jsonDiff(lhs: any, rhs: any): JsonChange[];
17
- export declare function walkJsonTree(json: any, currPath: string[], visitor: (path: string[], value: any) => boolean): void;
18
- export declare function deepEquals(a: any, b: any): boolean;
@@ -3,8 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.JsonDiffType = void 0;
4
4
  exports.isJsonChange = isJsonChange;
5
5
  exports.jsonDiff = jsonDiff;
6
- exports.walkJsonTree = walkJsonTree;
7
- exports.deepEquals = deepEquals;
6
+ const native_1 = require("../native");
8
7
  var JsonDiffType;
9
8
  (function (JsonDiffType) {
10
9
  JsonDiffType["Deleted"] = "JsonPropertyDeleted";
@@ -16,97 +15,10 @@ function isJsonChange(change) {
16
15
  change.type === JsonDiffType.Deleted ||
17
16
  change.type === JsonDiffType.Modified);
18
17
  }
18
+ /**
19
+ * The changes from `lhs` to `rhs`: every path whose value was deleted or
20
+ * modified, containers included, then every added path.
21
+ */
19
22
  function jsonDiff(lhs, rhs) {
20
- const result = [];
21
- const seenInLhs = new Set();
22
- walkJsonTree(lhs, [], (path, lhsValue) => {
23
- seenInLhs.add(hashArray(path));
24
- const rhsValue = getJsonValue(path, rhs);
25
- if (rhsValue === undefined) {
26
- result.push({
27
- type: JsonDiffType.Deleted,
28
- path,
29
- value: {
30
- lhs: lhsValue,
31
- rhs: undefined,
32
- },
33
- });
34
- }
35
- else if (!deepEquals(lhsValue, rhsValue)) {
36
- result.push({
37
- type: JsonDiffType.Modified,
38
- path,
39
- value: {
40
- lhs: lhsValue,
41
- rhs: rhsValue,
42
- },
43
- });
44
- }
45
- return typeof lhsValue === 'object' || Array.isArray(lhsValue);
46
- });
47
- walkJsonTree(rhs, [], (path, rhsValue) => {
48
- const addedInRhs = !seenInLhs.has(hashArray(path));
49
- if (addedInRhs) {
50
- result.push({
51
- type: JsonDiffType.Added,
52
- path,
53
- value: {
54
- lhs: undefined,
55
- rhs: rhsValue,
56
- },
57
- });
58
- }
59
- return typeof rhsValue === 'object' || Array.isArray(rhsValue);
60
- });
61
- return result;
62
- }
63
- // Depth-first walk down JSON tree.
64
- function walkJsonTree(json, currPath, visitor) {
65
- if (!json || typeof json !== 'object') {
66
- return;
67
- }
68
- Object.keys(json).forEach((key) => {
69
- const path = currPath.concat([key]);
70
- const shouldContinue = visitor(path, json[key]);
71
- if (shouldContinue) {
72
- walkJsonTree(json[key], path, visitor);
73
- }
74
- });
75
- }
76
- function hashArray(ary) {
77
- return JSON.stringify(ary);
78
- }
79
- function getJsonValue(path, json) {
80
- let curr = json;
81
- for (const k of path) {
82
- curr = curr[k];
83
- if (curr === undefined) {
84
- break;
85
- }
86
- }
87
- return curr;
88
- }
89
- function deepEquals(a, b) {
90
- if (a === b) {
91
- return true;
92
- }
93
- // Values do not need to be checked for deep equality and the above is false
94
- if (
95
- // Values are different types
96
- typeof a !== typeof b ||
97
- // Values are the same type but not an object or array
98
- (typeof a !== 'object' && !Array.isArray(a)) ||
99
- // Objects are the same type, objects or arrays, but do not have the same number of keys
100
- Object.keys(a).length !== Object.keys(b).length) {
101
- return false;
102
- }
103
- // Values need to be checked for deep equality
104
- return Object.entries(a).reduce((equal, [key, aValue]) => {
105
- // Skip other keys if it is already not equal.
106
- if (!equal) {
107
- return equal;
108
- }
109
- // Traverse the object
110
- return deepEquals(aValue, b[key]);
111
- }, true);
23
+ return ((0, native_1.diffJson)(JSON.stringify(lhs ?? null), JSON.stringify(rhs ?? null)) ?? []);
112
24
  }
@@ -1,4 +1,6 @@
1
1
  import { NxJsonConfiguration } from '../config/nx-json';
2
2
  export declare function isNxCloudDisabled(nxJson: NxJsonConfiguration): boolean;
3
3
  export declare function isNxCloudUsed(nxJson: NxJsonConfiguration): boolean;
4
+ /** Whether nx.json connects the workspace to Nx Cloud, ignoring the env. */
5
+ export declare function isNxCloudConfigured(nxJson: NxJsonConfiguration): boolean;
4
6
  export declare function getNxCloudUrl(nxJson: NxJsonConfiguration): string;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isNxCloudDisabled = isNxCloudDisabled;
4
4
  exports.isNxCloudUsed = isNxCloudUsed;
5
+ exports.isNxCloudConfigured = isNxCloudConfigured;
5
6
  exports.getNxCloudUrl = getNxCloudUrl;
6
7
  function isNxCloudDisabled(nxJson) {
7
8
  return process.env.NX_NO_CLOUD === 'true' || nxJson.neverConnectToCloud;
@@ -12,7 +13,11 @@ function isNxCloudUsed(nxJson) {
12
13
  }
13
14
  return (!!process.env.NX_CLOUD_AUTH_TOKEN ||
14
15
  !!process.env.NX_CLOUD_ACCESS_TOKEN ||
15
- !!nxJson.nxCloudAccessToken ||
16
+ isNxCloudConfigured(nxJson));
17
+ }
18
+ /** Whether nx.json connects the workspace to Nx Cloud, ignoring the env. */
19
+ function isNxCloudConfigured(nxJson) {
20
+ return (!!nxJson.nxCloudAccessToken ||
16
21
  !!nxJson.nxCloudId ||
17
22
  !!Object.values(nxJson.tasksRunnerOptions ?? {}).find((r) => r.runner == '@nrwl/nx-cloud' || r.runner == 'nx-cloud'));
18
23
  }
@@ -1,6 +1,8 @@
1
1
  import { ProjectGraph, ProjectGraphProjectNode } from '../config/project-graph';
2
2
  import type { ProjectConfiguration } from '../config/workspace-json-project-json';
3
3
  export declare function projectHasTarget(project: ProjectGraphProjectNode, target: string): boolean;
4
+ /** The projects that define at least one of `targets`. */
5
+ export declare function runnableForTarget(projects: Record<string, ProjectGraphProjectNode>, targets: string[]): Set<string>;
4
6
  export declare function projectHasTargetAndConfiguration(project: ProjectGraphProjectNode, target: string, configuration: string): any;
5
7
  export declare function getSourceDirOfDependentProjects(projectName: string, projectGraph?: ProjectGraph): [
6
8
  projectDirs: string[],
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.projectHasTarget = projectHasTarget;
4
+ exports.runnableForTarget = runnableForTarget;
4
5
  exports.projectHasTargetAndConfiguration = projectHasTargetAndConfiguration;
5
6
  exports.getSourceDirOfDependentProjects = getSourceDirOfDependentProjects;
6
7
  exports.findAllProjectNodeDependencies = findAllProjectNodeDependencies;
@@ -13,6 +14,17 @@ function projectHasTarget(project, target) {
13
14
  project.data.targets &&
14
15
  project.data.targets[target]);
15
16
  }
17
+ /** The projects that define at least one of `targets`. */
18
+ function runnableForTarget(projects, targets) {
19
+ const runnable = new Set();
20
+ for (const projectName in projects) {
21
+ const project = projects[projectName];
22
+ if (targets.some((target) => projectHasTarget(project, target))) {
23
+ runnable.add(projectName);
24
+ }
25
+ }
26
+ return runnable;
27
+ }
16
28
  function projectHasTargetAndConfiguration(project, target, configuration) {
17
29
  return (projectHasTarget(project, target) &&
18
30
  project.data.targets[target].configurations &&