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.
- package/package.json +12 -12
- package/src/command-line/generate/generator-utils.d.ts +2 -1
- package/src/command-line/import/command-object.js +1 -1
- package/src/command-line/import/import.js +6 -2
- package/src/command-line/init/init-v2.d.ts +1 -1
- package/src/command-line/init/init-v2.js +8 -2
- package/src/command-line/sync/command-object.js +2 -2
- package/src/core/graph/main.js +1 -1
- package/src/core/graph/styles.css +1 -1
- package/src/daemon/client/client.d.ts +2 -1
- package/src/daemon/client/client.js +7 -0
- package/src/daemon/message-types/task-history.d.ts +9 -3
- package/src/daemon/message-types/task-history.js +10 -2
- package/src/daemon/server/handle-task-history.d.ts +5 -1
- package/src/daemon/server/handle-task-history.js +11 -9
- package/src/daemon/server/server.js +5 -2
- package/src/native/index.d.ts +1 -0
- package/src/native/nx.wasm32-wasi.wasm +0 -0
- package/src/tasks-runner/init-tasks-runner.d.ts +1 -1
- package/src/tasks-runner/init-tasks-runner.js +5 -3
- package/src/tasks-runner/life-cycles/invoke-runner-terminal-output-life-cycle.d.ts +0 -2
- package/src/tasks-runner/life-cycles/invoke-runner-terminal-output-life-cycle.js +0 -5
- package/src/tasks-runner/life-cycles/static-run-many-terminal-output-life-cycle.d.ts +2 -6
- package/src/tasks-runner/life-cycles/static-run-one-terminal-output-life-cycle.d.ts +2 -6
- package/src/tasks-runner/life-cycles/store-run-information-life-cycle.d.ts +2 -7
- package/src/tasks-runner/life-cycles/task-history-life-cycle.js +1 -1
- package/src/tasks-runner/life-cycles/task-profiling-life-cycle.d.ts +2 -7
- package/src/tasks-runner/life-cycles/task-results-life-cycle.d.ts +6 -0
- package/src/tasks-runner/life-cycles/task-results-life-cycle.js +17 -0
- package/src/tasks-runner/life-cycles/task-timings-life-cycle.d.ts +2 -7
- package/src/tasks-runner/run-command.d.ts +12 -2
- package/src/tasks-runner/run-command.js +50 -59
- package/src/tasks-runner/task-orchestrator.js +4 -1
- package/src/tasks-runner/tasks-schedule.d.ts +3 -0
- package/src/tasks-runner/tasks-schedule.js +26 -4
- package/src/utils/git-utils.d.ts +1 -0
- package/src/utils/git-utils.js +4 -0
- package/src/utils/task-history.d.ts +12 -1
- 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
|
103
|
-
|
104
|
-
|
105
|
-
|
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
|
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:
|
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
|
-
|
424
|
-
}
|
425
|
-
else {
|
426
|
-
// simply await the promise
|
427
|
-
anyFailures = await anyFailuresInPromise(promiseOrObservable);
|
435
|
+
promiseOrObservable = convertObservableToPromise(promiseOrObservable);
|
428
436
|
}
|
429
|
-
|
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
|
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
|
471
|
-
obs.subscribe(
|
472
|
-
|
473
|
-
|
474
|
-
}
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
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
|
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
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
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
|
}
|
package/src/utils/git-utils.d.ts
CHANGED
@@ -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[]>;
|
package/src/utils/git-utils.js
CHANGED
@@ -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
|
+
}
|