nx 19.7.3 → 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/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;
|