nx 19.7.3 → 19.8.0-beta.0
Sign up to get free protection for your applications and to get access to all the features.
- package/package.json +12 -12
- package/schemas/nx-schema.json +2 -2
- 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 +9 -4
- package/src/command-line/import/utils/prepare-source-repo.js +7 -35
- package/src/command-line/init/init-v2.d.ts +1 -1
- package/src/command-line/init/init-v2.js +14 -4
- package/src/command-line/release/command-object.d.ts +2 -2
- package/src/command-line/release/config/config.js +10 -3
- package/src/command-line/release/utils/git.d.ts +2 -2
- package/src/command-line/release/utils/git.js +12 -2
- package/src/command-line/release/utils/shared.d.ts +1 -1
- package/src/command-line/release/version.js +4 -0
- package/src/command-line/sync/command-object.js +2 -2
- package/src/config/nx-json.d.ts +13 -5
- 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/hasher/hash-task.js +2 -2
- package/src/native/index.d.ts +1 -0
- package/src/native/nx.wasi-browser.js +42 -54
- package/src/native/nx.wasi.cjs +42 -54
- package/src/native/nx.wasm32-wasi.wasm +0 -0
- package/src/plugins/js/utils/register.js +7 -0
- package/src/tasks-runner/cache.js +2 -1
- 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 +53 -60
- package/src/tasks-runner/task-orchestrator.d.ts +0 -1
- package/src/tasks-runner/task-orchestrator.js +7 -7
- 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 +4 -2
- package/src/utils/git-utils.index-filter.d.ts +0 -0
- package/src/utils/git-utils.index-filter.js +20 -0
- package/src/utils/git-utils.js +48 -13
- package/src/utils/git-utils.tree-filter.d.ts +11 -0
- package/src/utils/git-utils.tree-filter.js +43 -0
- package/src/utils/task-history.d.ts +12 -1
- package/src/utils/task-history.js +23 -0
@@ -39,7 +39,7 @@ async function initTasksRunner(nxArgs) {
|
|
39
39
|
return acc;
|
40
40
|
}, {}),
|
41
41
|
};
|
42
|
-
const
|
42
|
+
const taskResults = await (0, run_command_1.invokeTasksRunner)({
|
43
43
|
tasks: opts.tasks,
|
44
44
|
projectGraph,
|
45
45
|
taskGraph,
|
@@ -50,9 +50,11 @@ async function initTasksRunner(nxArgs) {
|
|
50
50
|
initiatingProject: null,
|
51
51
|
});
|
52
52
|
return {
|
53
|
-
status
|
53
|
+
status: Object.values(taskResults).some((taskResult) => taskResult.status === 'failure' || taskResult.status === 'skipped')
|
54
|
+
? 1
|
55
|
+
: 0,
|
54
56
|
taskGraph,
|
55
|
-
taskResults
|
57
|
+
taskResults,
|
56
58
|
};
|
57
59
|
},
|
58
60
|
};
|
@@ -5,11 +5,9 @@ export declare class InvokeRunnerTerminalOutputLifeCycle implements LifeCycle {
|
|
5
5
|
private readonly tasks;
|
6
6
|
failedTasks: Task[];
|
7
7
|
cachedTasks: Task[];
|
8
|
-
private taskResults;
|
9
8
|
constructor(tasks: Task[]);
|
10
9
|
startCommand(): void;
|
11
10
|
endCommand(): void;
|
12
11
|
endTasks(taskResults: TaskResult[]): void;
|
13
12
|
printTaskTerminalOutput(task: Task, cacheStatus: TaskStatus, terminalOutput: string): void;
|
14
|
-
getTaskResults(): Record<string, TaskResult>;
|
15
13
|
}
|
@@ -8,7 +8,6 @@ class InvokeRunnerTerminalOutputLifeCycle {
|
|
8
8
|
this.tasks = tasks;
|
9
9
|
this.failedTasks = [];
|
10
10
|
this.cachedTasks = [];
|
11
|
-
this.taskResults = {};
|
12
11
|
}
|
13
12
|
startCommand() {
|
14
13
|
output_1.output.log({
|
@@ -46,7 +45,6 @@ class InvokeRunnerTerminalOutputLifeCycle {
|
|
46
45
|
}
|
47
46
|
endTasks(taskResults) {
|
48
47
|
for (let t of taskResults) {
|
49
|
-
this.taskResults[t.task.id] = t;
|
50
48
|
if (t.status === 'failure') {
|
51
49
|
this.failedTasks.push(t.task);
|
52
50
|
}
|
@@ -65,8 +63,5 @@ class InvokeRunnerTerminalOutputLifeCycle {
|
|
65
63
|
const args = (0, utils_1.getPrintableCommandArgsForTask)(task);
|
66
64
|
output_1.output.logCommandOutput(args.join(' '), cacheStatus, terminalOutput);
|
67
65
|
}
|
68
|
-
getTaskResults() {
|
69
|
-
return this.taskResults;
|
70
|
-
}
|
71
66
|
}
|
72
67
|
exports.InvokeRunnerTerminalOutputLifeCycle = InvokeRunnerTerminalOutputLifeCycle;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { TaskStatus } from '../tasks-runner';
|
2
|
-
import type { LifeCycle } from '../life-cycle';
|
2
|
+
import type { LifeCycle, TaskResult } from '../life-cycle';
|
3
3
|
import { Task } from '../../config/task-graph';
|
4
4
|
/**
|
5
5
|
* The following life cycle's outputs are static, meaning no previous content
|
@@ -24,10 +24,6 @@ export declare class StaticRunManyTerminalOutputLifeCycle implements LifeCycle {
|
|
24
24
|
startCommand(): void;
|
25
25
|
endCommand(): void;
|
26
26
|
private skippedTasks;
|
27
|
-
endTasks(taskResults:
|
28
|
-
task: Task;
|
29
|
-
status: TaskStatus;
|
30
|
-
code: number;
|
31
|
-
}[]): void;
|
27
|
+
endTasks(taskResults: TaskResult[]): void;
|
32
28
|
printTaskTerminalOutput(task: Task, cacheStatus: TaskStatus, terminalOutput: string): void;
|
33
29
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { TaskStatus } from '../tasks-runner';
|
2
|
-
import type { LifeCycle } from '../life-cycle';
|
2
|
+
import type { LifeCycle, TaskResult } from '../life-cycle';
|
3
3
|
import { Task } from '../../config/task-graph';
|
4
4
|
/**
|
5
5
|
* The following life cycle's outputs are static, meaning no previous content
|
@@ -23,10 +23,6 @@ export declare class StaticRunOneTerminalOutputLifeCycle implements LifeCycle {
|
|
23
23
|
});
|
24
24
|
startCommand(): void;
|
25
25
|
endCommand(): void;
|
26
|
-
endTasks(taskResults:
|
27
|
-
task: Task;
|
28
|
-
status: TaskStatus;
|
29
|
-
code: number;
|
30
|
-
}[]): void;
|
26
|
+
endTasks(taskResults: TaskResult[]): void;
|
31
27
|
printTaskTerminalOutput(task: Task, status: TaskStatus, terminalOutput: string): void;
|
32
28
|
}
|
@@ -1,6 +1,5 @@
|
|
1
|
-
import { LifeCycle } from '../../tasks-runner/life-cycle';
|
1
|
+
import { LifeCycle, TaskResult } from '../../tasks-runner/life-cycle';
|
2
2
|
import { Task } from '../../config/task-graph';
|
3
|
-
import { TaskStatus } from '../../tasks-runner/tasks-runner';
|
4
3
|
export declare class StoreRunInformationLifeCycle implements LifeCycle {
|
5
4
|
private readonly command;
|
6
5
|
private readonly storeFile;
|
@@ -10,11 +9,7 @@ export declare class StoreRunInformationLifeCycle implements LifeCycle {
|
|
10
9
|
private taskResults;
|
11
10
|
constructor(command?: string, storeFile?: typeof storeFileFunction, now?: () => string);
|
12
11
|
startTasks(tasks: Task[]): void;
|
13
|
-
endTasks(taskResults:
|
14
|
-
task: Task;
|
15
|
-
status: TaskStatus;
|
16
|
-
code: number;
|
17
|
-
}>): void;
|
12
|
+
endTasks(taskResults: TaskResult[]): void;
|
18
13
|
startCommand(): void;
|
19
14
|
endCommand(): any;
|
20
15
|
}
|
@@ -8,7 +8,7 @@ class TaskHistoryLifeCycle {
|
|
8
8
|
constructor() {
|
9
9
|
this.startTimings = {};
|
10
10
|
this.taskRuns = new Map();
|
11
|
-
this.taskHistory =
|
11
|
+
this.taskHistory = (0, task_history_1.getTaskHistory)();
|
12
12
|
}
|
13
13
|
startTasks(tasks) {
|
14
14
|
for (let task of tasks) {
|
@@ -1,5 +1,4 @@
|
|
1
|
-
import { LifeCycle, TaskMetadata } from '../life-cycle';
|
2
|
-
import { TaskStatus } from '../tasks-runner';
|
1
|
+
import { LifeCycle, TaskMetadata, TaskResult } from '../life-cycle';
|
3
2
|
import { Task } from '../../config/task-graph';
|
4
3
|
export declare class TaskProfilingLifeCycle implements LifeCycle {
|
5
4
|
private timings;
|
@@ -8,11 +7,7 @@ export declare class TaskProfilingLifeCycle implements LifeCycle {
|
|
8
7
|
private registeredGroups;
|
9
8
|
constructor(_profileFile: string);
|
10
9
|
startTasks(tasks: Task[], { groupId }: TaskMetadata): void;
|
11
|
-
endTasks(taskResults:
|
12
|
-
task: Task;
|
13
|
-
status: TaskStatus;
|
14
|
-
code: number;
|
15
|
-
}>, metadata: TaskMetadata): void;
|
10
|
+
endTasks(taskResults: TaskResult[], metadata: TaskMetadata): void;
|
16
11
|
endCommand(): void;
|
17
12
|
private recordTaskCompletions;
|
18
13
|
private registerGroup;
|
@@ -0,0 +1,17 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.TaskResultsLifeCycle = void 0;
|
4
|
+
class TaskResultsLifeCycle {
|
5
|
+
constructor() {
|
6
|
+
this.taskResults = {};
|
7
|
+
}
|
8
|
+
endTasks(taskResults) {
|
9
|
+
for (let t of taskResults) {
|
10
|
+
this.taskResults[t.task.id] = t;
|
11
|
+
}
|
12
|
+
}
|
13
|
+
getTaskResults() {
|
14
|
+
return this.taskResults;
|
15
|
+
}
|
16
|
+
}
|
17
|
+
exports.TaskResultsLifeCycle = TaskResultsLifeCycle;
|
@@ -1,13 +1,8 @@
|
|
1
1
|
import { Task } from '../../config/task-graph';
|
2
|
-
import { LifeCycle } from '../life-cycle';
|
3
|
-
import { TaskStatus } from '../tasks-runner';
|
2
|
+
import { LifeCycle, TaskResult } from '../life-cycle';
|
4
3
|
export declare class TaskTimingsLifeCycle implements LifeCycle {
|
5
4
|
private timings;
|
6
5
|
startTasks(tasks: Task[]): void;
|
7
|
-
endTasks(taskResults:
|
8
|
-
task: Task;
|
9
|
-
status: TaskStatus;
|
10
|
-
code: number;
|
11
|
-
}>): void;
|
6
|
+
endTasks(taskResults: TaskResult[]): void;
|
12
7
|
endCommand(): void;
|
13
8
|
}
|
@@ -3,7 +3,7 @@ import { ProjectGraph, ProjectGraphProjectNode } 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 { LifeCycle } from './life-cycle';
|
6
|
+
import { LifeCycle, TaskResult } from './life-cycle';
|
7
7
|
import { TasksRunner } from './tasks-runner';
|
8
8
|
export declare function runCommand(projectsToRun: ProjectGraphProjectNode[], currentProjectGraph: ProjectGraph, { nxJson }: {
|
9
9
|
nxJson: NxJsonConfiguration;
|
@@ -11,6 +11,14 @@ export declare function runCommand(projectsToRun: ProjectGraphProjectNode[], cur
|
|
11
11
|
excludeTaskDependencies: boolean;
|
12
12
|
loadDotEnvFiles: boolean;
|
13
13
|
}): Promise<NodeJS.Process['exitCode']>;
|
14
|
+
export declare function runCommandForTasks(projectsToRun: ProjectGraphProjectNode[], currentProjectGraph: ProjectGraph, { nxJson }: {
|
15
|
+
nxJson: NxJsonConfiguration;
|
16
|
+
}, nxArgs: NxArgs, overrides: any, initiatingProject: string | null, extraTargetDependencies: Record<string, (TargetDependencyConfig | string)[]>, extraOptions: {
|
17
|
+
excludeTaskDependencies: boolean;
|
18
|
+
loadDotEnvFiles: boolean;
|
19
|
+
}): Promise<{
|
20
|
+
[id: string]: TaskResult;
|
21
|
+
}>;
|
14
22
|
export declare function invokeTasksRunner({ tasks, projectGraph, taskGraph, lifeCycle, nxJson, nxArgs, loadDotEnvFiles, initiatingProject, }: {
|
15
23
|
tasks: Task[];
|
16
24
|
projectGraph: ProjectGraph;
|
@@ -20,7 +28,9 @@ export declare function invokeTasksRunner({ tasks, projectGraph, taskGraph, life
|
|
20
28
|
nxArgs: NxArgs;
|
21
29
|
loadDotEnvFiles: boolean;
|
22
30
|
initiatingProject: string | null;
|
23
|
-
}): Promise<
|
31
|
+
}): Promise<{
|
32
|
+
[id: string]: TaskResult;
|
33
|
+
}>;
|
24
34
|
export declare function getRunner(nxArgs: NxArgs, nxJson: NxJsonConfiguration): {
|
25
35
|
tasksRunner: TasksRunner;
|
26
36
|
runnerOptions: any;
|
@@ -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 = [];
|
@@ -439,45 +448,29 @@ function constructLifeCycles(lifeCycle) {
|
|
439
448
|
lifeCycles.push(new task_profiling_life_cycle_1.TaskProfilingLifeCycle(process.env.NX_PROFILE));
|
440
449
|
}
|
441
450
|
if (!(0, nx_cloud_utils_1.isNxCloudUsed)((0, nx_json_1.readNxJson)())) {
|
442
|
-
lifeCycles.push(
|
451
|
+
lifeCycles.push(process.env.NX_DISABLE_DB !== 'true' && !native_1.IS_WASM
|
452
|
+
? new task_history_life_cycle_1.TaskHistoryLifeCycle()
|
453
|
+
: new task_history_life_cycle_old_1.LegacyTaskHistoryLifeCycle());
|
443
454
|
}
|
444
455
|
return lifeCycles;
|
445
456
|
}
|
446
|
-
function
|
447
|
-
const res = {};
|
448
|
-
Object.keys(defaults ?? {}).forEach((k) => {
|
449
|
-
res[k] = defaults[k].dependsOn;
|
450
|
-
});
|
451
|
-
if (deps) {
|
452
|
-
Object.keys(deps).forEach((k) => {
|
453
|
-
if (res[k]) {
|
454
|
-
res[k] = [...res[k], deps[k]];
|
455
|
-
}
|
456
|
-
else {
|
457
|
-
res[k] = deps[k];
|
458
|
-
}
|
459
|
-
});
|
460
|
-
return res;
|
461
|
-
}
|
462
|
-
}
|
463
|
-
async function anyFailuresInPromise(promise) {
|
464
|
-
return Object.values(await promise).some((v) => v === 'failure' || v === 'skipped');
|
465
|
-
}
|
466
|
-
async function anyFailuresInObservable(obs) {
|
457
|
+
async function convertObservableToPromise(obs) {
|
467
458
|
return await new Promise((res) => {
|
468
|
-
let
|
469
|
-
obs.subscribe(
|
470
|
-
|
471
|
-
|
472
|
-
}
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
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
|
+
},
|
481
474
|
});
|
482
475
|
});
|
483
476
|
}
|
@@ -41,9 +41,12 @@ 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
|
-
await this.scheduleNextTasks();
|
49
|
+
await this.tasksSchedule.scheduleNextTasks();
|
47
50
|
perf_hooks_1.performance.mark('task-execution:start');
|
48
51
|
const threads = [];
|
49
52
|
process.stdout.setMaxListeners(this.options.parallel + events_1.defaultMaxListeners);
|
@@ -65,6 +68,7 @@ class TaskOrchestrator {
|
|
65
68
|
}
|
66
69
|
const doNotSkipCache = this.options.skipNxCache === false ||
|
67
70
|
this.options.skipNxCache === undefined;
|
71
|
+
this.processAllScheduledTasks();
|
68
72
|
const batch = this.tasksSchedule.nextBatch();
|
69
73
|
if (batch) {
|
70
74
|
const groupId = this.closeGroup();
|
@@ -373,15 +377,11 @@ class TaskOrchestrator {
|
|
373
377
|
status,
|
374
378
|
};
|
375
379
|
}));
|
376
|
-
await this.scheduleNextTasks();
|
380
|
+
await this.tasksSchedule.scheduleNextTasks();
|
377
381
|
// release blocked threads
|
378
382
|
this.waitingForTasks.forEach((f) => f(null));
|
379
383
|
this.waitingForTasks.length = 0;
|
380
384
|
}
|
381
|
-
async scheduleNextTasks() {
|
382
|
-
await this.tasksSchedule.scheduleNextTasks();
|
383
|
-
this.processAllScheduledTasks();
|
384
|
-
}
|
385
385
|
complete(taskResults) {
|
386
386
|
this.tasksSchedule.complete(taskResults.map(({ taskId }) => taskId));
|
387
387
|
for (const { taskId, status } of taskResults) {
|
@@ -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[]>;
|
@@ -25,10 +26,11 @@ export declare class GitRepository {
|
|
25
26
|
deleteGitRemote(name: string): Promise<string>;
|
26
27
|
addGitRemote(name: string, url: string): Promise<string>;
|
27
28
|
hasFilterRepoInstalled(): Promise<boolean>;
|
28
|
-
filterRepo(
|
29
|
-
filterBranch(
|
29
|
+
filterRepo(source: string, destination: string): Promise<void>;
|
30
|
+
filterBranch(source: string, destination: string, branchName: string): Promise<void>;
|
30
31
|
private execAsync;
|
31
32
|
private quotePath;
|
33
|
+
private quoteArg;
|
32
34
|
}
|
33
35
|
/**
|
34
36
|
* This is currently duplicated in Nx Console. Please let @MaxKless know if you make changes here.
|
File without changes
|
@@ -0,0 +1,20 @@
|
|
1
|
+
/**
|
2
|
+
* This is meant to be used with `git filter-branch --index-filter` to rewrite
|
3
|
+
* history such that only commits related to the subdirectory is kept.
|
4
|
+
*
|
5
|
+
* Example:
|
6
|
+
* NX_IMPORT_SOURCE=<source> git filter-branch --index-filter 'node git-utils.index-filter.js' --prune-empty -- --all
|
7
|
+
*/
|
8
|
+
try {
|
9
|
+
const { execSync } = require('child_process');
|
10
|
+
// NOTE: Using env vars because Windows PowerShell has its own handling of quotes (") messes up quotes in args, even if escaped.
|
11
|
+
const src = process.env.NX_IMPORT_SOURCE;
|
12
|
+
execSync('git read-tree --empty', { stdio: 'inherit' });
|
13
|
+
execSync(`git reset ${process.env.GIT_COMMIT} -- "${src}"`, {
|
14
|
+
stdio: 'inherit',
|
15
|
+
});
|
16
|
+
}
|
17
|
+
catch (error) {
|
18
|
+
console.error(`Error executing Git commands: ${error}`);
|
19
|
+
process.exit(1);
|
20
|
+
}
|
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
|
}
|
@@ -105,32 +109,63 @@ class GitRepository {
|
|
105
109
|
}
|
106
110
|
// git-filter-repo is much faster than filter-branch, but needs to be installed by user
|
107
111
|
// Use `hasFilterRepoInstalled` to check if it's installed
|
108
|
-
async filterRepo(
|
109
|
-
// filter-repo requires POSIX path to work
|
110
|
-
const
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
112
|
+
async filterRepo(source, destination) {
|
113
|
+
// NOTE: filter-repo requires POSIX path to work
|
114
|
+
const sourcePosixPath = source.split(path_1.sep).join(path_1.posix.sep);
|
115
|
+
const destinationPosixPath = destination.split(path_1.sep).join(path_1.posix.sep);
|
116
|
+
await this.execAsync(`git filter-repo -f ${source !== '' ? `--path ${this.quotePath(sourcePosixPath)}` : ''} ${source !== destination
|
117
|
+
? `--path-rename ${this.quotePath(sourcePosixPath, true)}:${this.quotePath(destinationPosixPath, true)}`
|
118
|
+
: ''}`);
|
119
|
+
}
|
120
|
+
async filterBranch(source, destination, branchName) {
|
116
121
|
// We need non-ASCII file names to not be quoted, or else filter-branch will exclude them.
|
117
122
|
await this.execAsync(`git config core.quotepath false`);
|
118
|
-
|
123
|
+
// NOTE: filter-repo requires POSIX path to work
|
124
|
+
const sourcePosixPath = source.split(path_1.sep).join(path_1.posix.sep);
|
125
|
+
const destinationPosixPath = destination.split(path_1.sep).join(path_1.posix.sep);
|
126
|
+
// First, if the source is not a root project, then only include commits relevant to the subdirectory.
|
127
|
+
if (source !== '') {
|
128
|
+
const indexFilterCommand = this.quoteArg(`node ${(0, path_1.join)(__dirname, 'git-utils.index-filter.js')}`);
|
129
|
+
await this.execAsync(`git filter-branch -f --index-filter ${indexFilterCommand} --prune-empty -- ${branchName}`, {
|
130
|
+
NX_IMPORT_SOURCE: sourcePosixPath,
|
131
|
+
NX_IMPORT_DESTINATION: destinationPosixPath,
|
132
|
+
});
|
133
|
+
}
|
134
|
+
// Then, move files to their new location if necessary.
|
135
|
+
if (source === '' || source !== destination) {
|
136
|
+
const treeFilterCommand = this.quoteArg(`node ${(0, path_1.join)(__dirname, 'git-utils.tree-filter.js')}`);
|
137
|
+
await this.execAsync(`git filter-branch -f --tree-filter ${treeFilterCommand} -- ${branchName}`, {
|
138
|
+
NX_IMPORT_SOURCE: sourcePosixPath,
|
139
|
+
NX_IMPORT_DESTINATION: destinationPosixPath,
|
140
|
+
});
|
141
|
+
}
|
119
142
|
}
|
120
|
-
execAsync(command) {
|
143
|
+
execAsync(command, env) {
|
121
144
|
return execAsync(command, {
|
122
145
|
cwd: this.root,
|
123
146
|
maxBuffer: 10 * 1024 * 1024,
|
147
|
+
env: {
|
148
|
+
...process.env,
|
149
|
+
...env,
|
150
|
+
},
|
124
151
|
});
|
125
152
|
}
|
126
|
-
quotePath(path) {
|
153
|
+
quotePath(path, ensureTrailingSlash) {
|
154
|
+
return this.quoteArg(ensureTrailingSlash && path !== '' && !path.endsWith('/')
|
155
|
+
? `${path}/`
|
156
|
+
: path);
|
157
|
+
}
|
158
|
+
quoteArg(arg) {
|
127
159
|
return process.platform === 'win32'
|
128
160
|
? // Windows/CMD only understands double-quotes, single-quotes are treated as part of the file name
|
129
161
|
// Bash and other shells will substitute `$` in file names with a variable value.
|
130
|
-
`"${
|
162
|
+
`"${arg
|
163
|
+
// Need to keep two slashes for Windows or else the path will be invalid.
|
164
|
+
// e.g. 'C:\Users\bob\projects\repo' is invalid, but 'C:\\Users\\bob\\projects\\repo' is valid
|
165
|
+
.replaceAll('\\', '\\\\')}"`
|
131
166
|
: // e.g. `git mv "$$file.txt" "libs/a/$$file.txt"` will not work since `$$` is swapped with the PID of the last process.
|
132
167
|
// Using single-quotes prevents this substitution.
|
133
|
-
`'${
|
168
|
+
`'${arg}'`;
|
134
169
|
}
|
135
170
|
}
|
136
171
|
exports.GitRepository = GitRepository;
|