nx 19.7.4 → 19.8.0-beta.0

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 (39) hide show
  1. package/package.json +12 -12
  2. package/src/command-line/generate/generator-utils.d.ts +2 -1
  3. package/src/command-line/import/command-object.js +1 -1
  4. package/src/command-line/import/import.js +6 -2
  5. package/src/command-line/init/init-v2.d.ts +1 -1
  6. package/src/command-line/init/init-v2.js +8 -2
  7. package/src/command-line/sync/command-object.js +2 -2
  8. package/src/core/graph/main.js +1 -1
  9. package/src/core/graph/styles.css +1 -1
  10. package/src/daemon/client/client.d.ts +2 -1
  11. package/src/daemon/client/client.js +7 -0
  12. package/src/daemon/message-types/task-history.d.ts +9 -3
  13. package/src/daemon/message-types/task-history.js +10 -2
  14. package/src/daemon/server/handle-task-history.d.ts +5 -1
  15. package/src/daemon/server/handle-task-history.js +11 -9
  16. package/src/daemon/server/server.js +5 -2
  17. package/src/native/index.d.ts +1 -0
  18. package/src/native/nx.wasm32-wasi.wasm +0 -0
  19. package/src/tasks-runner/init-tasks-runner.d.ts +1 -1
  20. package/src/tasks-runner/init-tasks-runner.js +5 -3
  21. package/src/tasks-runner/life-cycles/invoke-runner-terminal-output-life-cycle.d.ts +0 -2
  22. package/src/tasks-runner/life-cycles/invoke-runner-terminal-output-life-cycle.js +0 -5
  23. package/src/tasks-runner/life-cycles/static-run-many-terminal-output-life-cycle.d.ts +2 -6
  24. package/src/tasks-runner/life-cycles/static-run-one-terminal-output-life-cycle.d.ts +2 -6
  25. package/src/tasks-runner/life-cycles/store-run-information-life-cycle.d.ts +2 -7
  26. package/src/tasks-runner/life-cycles/task-history-life-cycle.js +1 -1
  27. package/src/tasks-runner/life-cycles/task-profiling-life-cycle.d.ts +2 -7
  28. package/src/tasks-runner/life-cycles/task-results-life-cycle.d.ts +6 -0
  29. package/src/tasks-runner/life-cycles/task-results-life-cycle.js +17 -0
  30. package/src/tasks-runner/life-cycles/task-timings-life-cycle.d.ts +2 -7
  31. package/src/tasks-runner/run-command.d.ts +12 -2
  32. package/src/tasks-runner/run-command.js +50 -59
  33. package/src/tasks-runner/task-orchestrator.js +4 -1
  34. package/src/tasks-runner/tasks-schedule.d.ts +3 -0
  35. package/src/tasks-runner/tasks-schedule.js +26 -4
  36. package/src/utils/git-utils.d.ts +1 -0
  37. package/src/utils/git-utils.js +4 -0
  38. package/src/utils/task-history.d.ts +12 -1
  39. package/src/utils/task-history.js +23 -0
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runCommand = runCommand;
4
+ exports.runCommandForTasks = runCommandForTasks;
4
5
  exports.invokeTasksRunner = invokeTasksRunner;
5
6
  exports.getRunner = getRunner;
6
7
  exports.getRunnerOptions = getRunnerOptions;
@@ -31,6 +32,7 @@ const task_history_life_cycle_1 = require("./life-cycles/task-history-life-cycle
31
32
  const task_history_life_cycle_old_1 = require("./life-cycles/task-history-life-cycle-old");
32
33
  const task_profiling_life_cycle_1 = require("./life-cycles/task-profiling-life-cycle");
33
34
  const task_timings_life_cycle_1 = require("./life-cycles/task-timings-life-cycle");
35
+ const task_results_life_cycle_1 = require("./life-cycles/task-results-life-cycle");
34
36
  const task_graph_utils_1 = require("./task-graph-utils");
35
37
  const utils_1 = require("./utils");
36
38
  const chalk = require("chalk");
@@ -99,25 +101,31 @@ function createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies,
99
101
  }
100
102
  async function runCommand(projectsToRun, currentProjectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
101
103
  const status = await (0, handle_errors_1.handleErrors)(process.env.NX_VERBOSE_LOGGING === 'true', async () => {
102
- const projectNames = projectsToRun.map((t) => t.name);
103
- const { projectGraph, taskGraph } = await ensureWorkspaceIsInSyncAndGetGraphs(currentProjectGraph, nxJson, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions);
104
- const tasks = Object.values(taskGraph.tasks);
105
- const { lifeCycle, renderIsDone } = await getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks, nxArgs, nxJson, overrides);
106
- const status = await invokeTasksRunner({
107
- tasks,
108
- projectGraph,
109
- taskGraph,
110
- lifeCycle,
111
- nxJson,
112
- nxArgs,
113
- loadDotEnvFiles: extraOptions.loadDotEnvFiles,
114
- initiatingProject,
115
- });
116
- await renderIsDone;
117
- return status;
104
+ const taskResults = await runCommandForTasks(projectsToRun, currentProjectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions);
105
+ return Object.values(taskResults).some((taskResult) => taskResult.status === 'failure' || taskResult.status === 'skipped')
106
+ ? 1
107
+ : 0;
118
108
  });
119
109
  return status;
120
110
  }
111
+ async function runCommandForTasks(projectsToRun, currentProjectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
112
+ const projectNames = projectsToRun.map((t) => t.name);
113
+ const { projectGraph, taskGraph } = await ensureWorkspaceIsInSyncAndGetGraphs(currentProjectGraph, nxJson, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions);
114
+ const tasks = Object.values(taskGraph.tasks);
115
+ const { lifeCycle, renderIsDone } = await getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks, nxArgs, nxJson, overrides);
116
+ const taskResults = await invokeTasksRunner({
117
+ tasks,
118
+ projectGraph,
119
+ taskGraph,
120
+ lifeCycle,
121
+ nxJson,
122
+ nxArgs,
123
+ loadDotEnvFiles: extraOptions.loadDotEnvFiles,
124
+ initiatingProject,
125
+ });
126
+ await renderIsDone;
127
+ return taskResults;
128
+ }
121
129
  async function ensureWorkspaceIsInSyncAndGetGraphs(projectGraph, nxJson, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions) {
122
130
  let taskGraph = createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies ?? {}, projectNames, nxArgs, overrides, extraOptions);
123
131
  if (nxArgs.skipSync) {
@@ -359,9 +367,14 @@ async function invokeTasksRunner({ tasks, projectGraph, taskGraph, lifeCycle, nx
359
367
  // to submit everything that is known in advance to Nx Cloud to run in
360
368
  // a distributed fashion
361
369
  await (0, hash_task_1.hashTasksThatDoNotDependOnOutputsOfOtherTasks)(hasher, projectGraph, taskGraph, nxJson);
362
- const promiseOrObservable = tasksRunner(tasks, {
370
+ const taskResultsLifecycle = new task_results_life_cycle_1.TaskResultsLifeCycle();
371
+ const compositedLifeCycle = new life_cycle_1.CompositeLifeCycle([
372
+ ...constructLifeCycles(lifeCycle),
373
+ taskResultsLifecycle,
374
+ ]);
375
+ let promiseOrObservable = tasksRunner(tasks, {
363
376
  ...runnerOptions,
364
- lifeCycle: new life_cycle_1.CompositeLifeCycle(constructLifeCycles(lifeCycle)),
377
+ lifeCycle: compositedLifeCycle,
365
378
  }, {
366
379
  initiatingProject: nxArgs.outputStyle === 'compact' ? null : initiatingProject,
367
380
  projectGraph,
@@ -418,15 +431,11 @@ async function invokeTasksRunner({ tasks, projectGraph, taskGraph, lifeCycle, nx
418
431
  },
419
432
  daemon: client_1.daemonClient,
420
433
  });
421
- let anyFailures;
422
434
  if (promiseOrObservable.subscribe) {
423
- anyFailures = await anyFailuresInObservable(promiseOrObservable);
424
- }
425
- else {
426
- // simply await the promise
427
- anyFailures = await anyFailuresInPromise(promiseOrObservable);
435
+ promiseOrObservable = convertObservableToPromise(promiseOrObservable);
428
436
  }
429
- return anyFailures ? 1 : 0;
437
+ await promiseOrObservable;
438
+ return taskResultsLifecycle.getTaskResults();
430
439
  }
431
440
  function constructLifeCycles(lifeCycle) {
432
441
  const lifeCycles = [];
@@ -445,41 +454,23 @@ function constructLifeCycles(lifeCycle) {
445
454
  }
446
455
  return lifeCycles;
447
456
  }
448
- function mergeTargetDependencies(defaults, deps) {
449
- const res = {};
450
- Object.keys(defaults ?? {}).forEach((k) => {
451
- res[k] = defaults[k].dependsOn;
452
- });
453
- if (deps) {
454
- Object.keys(deps).forEach((k) => {
455
- if (res[k]) {
456
- res[k] = [...res[k], deps[k]];
457
- }
458
- else {
459
- res[k] = deps[k];
460
- }
461
- });
462
- return res;
463
- }
464
- }
465
- async function anyFailuresInPromise(promise) {
466
- return Object.values(await promise).some((v) => v === 'failure' || v === 'skipped');
467
- }
468
- async function anyFailuresInObservable(obs) {
457
+ async function convertObservableToPromise(obs) {
469
458
  return await new Promise((res) => {
470
- let anyFailures = false;
471
- obs.subscribe((t) => {
472
- if (!t.success) {
473
- anyFailures = true;
474
- }
475
- }, (error) => {
476
- output_1.output.error({
477
- title: 'Unhandled error in task executor',
478
- });
479
- console.error(error);
480
- res(true);
481
- }, () => {
482
- res(anyFailures);
459
+ let tasksResults = {};
460
+ obs.subscribe({
461
+ next: (t) => {
462
+ tasksResults[t.task.id] = t.success ? 'success' : 'failure';
463
+ },
464
+ error: (error) => {
465
+ output_1.output.error({
466
+ title: 'Unhandled error in task executor',
467
+ });
468
+ console.error(error);
469
+ res(tasksResults);
470
+ },
471
+ complete: () => {
472
+ res(tasksResults);
473
+ },
483
474
  });
484
475
  });
485
476
  }
@@ -41,7 +41,10 @@ class TaskOrchestrator {
41
41
  }
42
42
  async run() {
43
43
  // Init the ForkedProcessTaskRunner
44
- await this.forkedProcessTaskRunner.init();
44
+ await Promise.all([
45
+ this.forkedProcessTaskRunner.init(),
46
+ this.tasksSchedule.init(),
47
+ ]);
45
48
  // initial scheduling
46
49
  await this.tasksSchedule.scheduleNextTasks();
47
50
  perf_hooks_1.performance.mark('task-execution:start');
@@ -12,12 +12,15 @@ export declare class TasksSchedule {
12
12
  private notScheduledTaskGraph;
13
13
  private reverseTaskDeps;
14
14
  private reverseProjectGraph;
15
+ private taskHistory;
15
16
  private scheduledBatches;
16
17
  private scheduledTasks;
17
18
  private runningTasks;
18
19
  private completedTasks;
19
20
  private scheduleRequestsExecutionChain;
21
+ private estimatedTaskTimings;
20
22
  constructor(projectGraph: ProjectGraph, taskGraph: TaskGraph, options: DefaultTasksRunnerOptions);
23
+ init(): Promise<void>;
21
24
  scheduleNextTasks(): Promise<void>;
22
25
  hasTasks(): boolean;
23
26
  complete(taskIds: string[]): void;
@@ -4,6 +4,7 @@ exports.TasksSchedule = void 0;
4
4
  const utils_1 = require("./utils");
5
5
  const project_graph_utils_1 = require("../utils/project-graph-utils");
6
6
  const operators_1 = require("../project-graph/operators");
7
+ const task_history_1 = require("../utils/task-history");
7
8
  class TasksSchedule {
8
9
  constructor(projectGraph, taskGraph, options) {
9
10
  this.projectGraph = projectGraph;
@@ -12,11 +13,19 @@ class TasksSchedule {
12
13
  this.notScheduledTaskGraph = this.taskGraph;
13
14
  this.reverseTaskDeps = (0, utils_1.calculateReverseDeps)(this.taskGraph);
14
15
  this.reverseProjectGraph = (0, operators_1.reverse)(this.projectGraph);
16
+ this.taskHistory = process.env.NX_DISABLE_DB !== 'true' ? (0, task_history_1.getTaskHistory)() : null;
15
17
  this.scheduledBatches = [];
16
18
  this.scheduledTasks = [];
17
19
  this.runningTasks = new Set();
18
20
  this.completedTasks = new Set();
19
21
  this.scheduleRequestsExecutionChain = Promise.resolve();
22
+ this.estimatedTaskTimings = {};
23
+ }
24
+ async init() {
25
+ if (this.taskHistory) {
26
+ this.estimatedTaskTimings =
27
+ await this.taskHistory.getEstimatedTaskTimings(Object.values(this.taskGraph.tasks).map((t) => t.target));
28
+ }
20
29
  }
21
30
  async scheduleNextTasks() {
22
31
  this.scheduleRequestsExecutionChain =
@@ -81,10 +90,23 @@ class TasksSchedule {
81
90
  // Most likely tasks with no dependencies such as test
82
91
  const project1 = this.taskGraph.tasks[taskId1].target.project;
83
92
  const project2 = this.taskGraph.tasks[taskId2].target.project;
84
- return ((0, project_graph_utils_1.findAllProjectNodeDependencies)(project2, this.reverseProjectGraph)
85
- .length -
86
- (0, project_graph_utils_1.findAllProjectNodeDependencies)(project1, this.reverseProjectGraph)
87
- .length);
93
+ const project1NodeDependencies = (0, project_graph_utils_1.findAllProjectNodeDependencies)(project1, this.reverseProjectGraph).length;
94
+ const project2NodeDependencies = (0, project_graph_utils_1.findAllProjectNodeDependencies)(project2, this.reverseProjectGraph).length;
95
+ const dependenciesDiff = project2NodeDependencies - project1NodeDependencies;
96
+ if (dependenciesDiff !== 0) {
97
+ return dependenciesDiff;
98
+ }
99
+ const task1Timing = this.estimatedTaskTimings[taskId1];
100
+ if (!task1Timing) {
101
+ // if no timing or 0, put task1 at beginning
102
+ return -1;
103
+ }
104
+ const task2Timing = this.estimatedTaskTimings[taskId2];
105
+ if (!task2Timing) {
106
+ // if no timing or 0, put task2 at beginning
107
+ return 1;
108
+ }
109
+ return task2Timing - task1Timing;
88
110
  });
89
111
  this.runningTasks.add(taskId);
90
112
  }
@@ -7,6 +7,7 @@ export declare class GitRepository {
7
7
  root: string;
8
8
  constructor(directory: string);
9
9
  getGitRootPath(cwd: string): string;
10
+ hasUncommittedChanges(): Promise<boolean>;
10
11
  addFetchRemote(remoteName: string, branch: string): Promise<string>;
11
12
  showStat(): Promise<string>;
12
13
  listBranches(): Promise<string[]>;
@@ -40,6 +40,10 @@ class GitRepository {
40
40
  .toString()
41
41
  .trim();
42
42
  }
43
+ async hasUncommittedChanges() {
44
+ const data = await this.execAsync(`git status --porcelain`);
45
+ return data.trim() !== '';
46
+ }
43
47
  async addFetchRemote(remoteName, branch) {
44
48
  return await this.execAsync(`git config --add remote.${remoteName}.fetch "+refs/heads/${branch}:refs/remotes/${remoteName}/${branch}"`);
45
49
  }
@@ -1,6 +1,17 @@
1
- import { NxTaskHistory, TaskRun } from '../native';
1
+ import { NxTaskHistory, TaskRun, TaskTarget } from '../native';
2
2
  export declare class TaskHistory {
3
3
  taskHistory: NxTaskHistory;
4
+ /**
5
+ * This function returns estimated timings per task
6
+ * @param targets
7
+ * @returns a map where key is task id (project:target:configuration), value is average time of historical runs
8
+ */
9
+ getEstimatedTaskTimings(targets: TaskTarget[]): Promise<Record<string, number>>;
4
10
  getFlakyTasks(hashes: string[]): Promise<string[]>;
5
11
  recordTaskRuns(taskRuns: TaskRun[]): Promise<void>;
6
12
  }
13
+ /**
14
+ * This function returns the singleton instance of TaskHistory
15
+ * @returns singleton instance of TaskHistory
16
+ */
17
+ export declare function getTaskHistory(): TaskHistory;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TaskHistory = void 0;
4
+ exports.getTaskHistory = getTaskHistory;
4
5
  const client_1 = require("../daemon/client/client");
5
6
  const is_on_daemon_1 = require("../daemon/is-on-daemon");
6
7
  const native_1 = require("../native");
@@ -9,6 +10,17 @@ class TaskHistory {
9
10
  constructor() {
10
11
  this.taskHistory = new native_1.NxTaskHistory((0, db_connection_1.getDbConnection)());
11
12
  }
13
+ /**
14
+ * This function returns estimated timings per task
15
+ * @param targets
16
+ * @returns a map where key is task id (project:target:configuration), value is average time of historical runs
17
+ */
18
+ async getEstimatedTaskTimings(targets) {
19
+ if ((0, is_on_daemon_1.isOnDaemon)() || !client_1.daemonClient.enabled()) {
20
+ return this.taskHistory.getEstimatedTaskTimings(targets);
21
+ }
22
+ return await client_1.daemonClient.getEstimatedTaskTimings(targets);
23
+ }
12
24
  async getFlakyTasks(hashes) {
13
25
  if ((0, is_on_daemon_1.isOnDaemon)() || !client_1.daemonClient.enabled()) {
14
26
  return this.taskHistory.getFlakyTasks(hashes);
@@ -23,3 +35,14 @@ class TaskHistory {
23
35
  }
24
36
  }
25
37
  exports.TaskHistory = TaskHistory;
38
+ let taskHistory;
39
+ /**
40
+ * This function returns the singleton instance of TaskHistory
41
+ * @returns singleton instance of TaskHistory
42
+ */
43
+ function getTaskHistory() {
44
+ if (!taskHistory) {
45
+ taskHistory = new TaskHistory();
46
+ }
47
+ return taskHistory;
48
+ }