nx 19.4.0-beta.0 → 19.4.0-beta.2
Sign up to get free protection for your applications and to get access to all the features.
- package/package.json +14 -14
- package/release/changelog-renderer/index.d.ts +6 -0
- package/release/changelog-renderer/index.js +1 -1
- package/src/command-line/connect/connect-to-nx-cloud.d.ts +1 -1
- package/src/command-line/connect/connect-to-nx-cloud.js +16 -25
- package/src/command-line/graph/graph.d.ts +1 -0
- package/src/command-line/graph/graph.js +12 -1
- package/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +5 -6
- package/src/command-line/release/changelog.js +6 -1
- package/src/command-line/release/config/config.js +3 -0
- package/src/command-line/run/command-object.js +2 -1
- package/src/config/workspace-json-project-json.d.ts +2 -0
- package/src/core/graph/main.js +1 -1
- package/src/core/graph/styles.css +1 -1
- package/src/daemon/client/client.d.ts +5 -0
- package/src/daemon/client/client.js +14 -0
- package/src/daemon/message-types/task-history.d.ts +13 -0
- package/src/daemon/message-types/task-history.js +19 -0
- package/src/daemon/server/handle-get-task-history.d.ts +4 -0
- package/src/daemon/server/handle-get-task-history.js +12 -0
- package/src/daemon/server/handle-write-task-runs-to-history.d.ts +5 -0
- package/src/daemon/server/handle-write-task-runs-to-history.js +12 -0
- package/src/daemon/server/plugins.js +12 -2
- package/src/daemon/server/server.js +9 -0
- package/src/daemon/socket-utils.d.ts +1 -0
- package/src/daemon/socket-utils.js +6 -1
- package/src/executors/run-commands/run-commands.impl.js +29 -20
- package/src/nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud.d.ts +1 -0
- package/src/nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud.js +68 -33
- package/src/nx-cloud/generators/connect-to-nx-cloud/schema.json +5 -0
- package/src/nx-cloud/utilities/url-shorten.d.ts +2 -1
- package/src/nx-cloud/utilities/url-shorten.js +47 -11
- package/src/plugins/package-json-workspaces/create-nodes.js +12 -7
- package/src/plugins/project-json/build-nodes/package-json-next-to-project-json.js +10 -2
- package/src/plugins/target-defaults/target-defaults-plugin.d.ts +5 -0
- package/src/project-graph/plugins/internal-api.js +1 -1
- package/src/project-graph/plugins/isolation/index.d.ts +1 -1
- package/src/project-graph/plugins/isolation/index.js +8 -13
- package/src/project-graph/plugins/isolation/messaging.d.ts +6 -3
- package/src/project-graph/plugins/isolation/messaging.js +9 -3
- package/src/project-graph/plugins/isolation/plugin-pool.d.ts +1 -1
- package/src/project-graph/plugins/isolation/plugin-pool.js +123 -43
- package/src/project-graph/plugins/isolation/plugin-worker.js +128 -107
- package/src/project-graph/project-graph.js +7 -1
- package/src/project-graph/utils/normalize-project-nodes.d.ts +1 -5
- package/src/project-graph/utils/normalize-project-nodes.js +2 -17
- package/src/project-graph/utils/project-configuration-utils.js +14 -3
- package/src/project-graph/utils/retrieve-workspace-files.d.ts +3 -3
- package/src/tasks-runner/default-tasks-runner.js +2 -2
- package/src/tasks-runner/life-cycle.d.ts +10 -10
- package/src/tasks-runner/life-cycle.js +10 -10
- package/src/tasks-runner/life-cycles/task-history-life-cycle.d.ts +9 -0
- package/src/tasks-runner/life-cycles/task-history-life-cycle.js +54 -0
- package/src/tasks-runner/run-command.js +6 -0
- package/src/tasks-runner/task-env.d.ts +13 -0
- package/src/tasks-runner/task-env.js +41 -26
- package/src/tasks-runner/task-orchestrator.js +4 -4
- package/src/utils/git-utils.d.ts +1 -1
- package/src/utils/git-utils.js +13 -2
- package/src/utils/nx-cloud-utils.d.ts +1 -1
- package/src/utils/nx-cloud-utils.js +1 -1
- package/src/utils/package-json.d.ts +3 -0
- package/src/utils/package-json.js +15 -3
- package/src/utils/serialize-target.d.ts +1 -0
- package/src/utils/serialize-target.js +7 -0
- package/src/utils/task-history.d.ts +8 -0
- package/src/utils/task-history.js +97 -0
@@ -3,116 +3,137 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const messaging_1 = require("./messaging");
|
4
4
|
const loader_1 = require("../loader");
|
5
5
|
const serializable_error_1 = require("../../../utils/serializable-error");
|
6
|
+
const net_1 = require("net");
|
7
|
+
const consume_messages_from_socket_1 = require("../../../utils/consume-messages-from-socket");
|
8
|
+
const fs_1 = require("fs");
|
6
9
|
if (process.env.NX_PERF_LOGGING === 'true') {
|
7
10
|
require('../../../utils/perf-logging');
|
8
11
|
}
|
9
12
|
global.NX_GRAPH_CREATION = true;
|
10
13
|
let plugin;
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
14
|
+
const socketPath = process.argv[2];
|
15
|
+
const server = (0, net_1.createServer)((socket) => {
|
16
|
+
socket.on('data', (0, consume_messages_from_socket_1.consumeMessagesFromSocket)((raw) => {
|
17
|
+
const message = JSON.parse(raw.toString());
|
18
|
+
if (!(0, messaging_1.isPluginWorkerMessage)(message)) {
|
19
|
+
return;
|
20
|
+
}
|
21
|
+
return (0, messaging_1.consumeMessage)(socket, message, {
|
22
|
+
load: async ({ plugin: pluginConfiguration, root }) => {
|
23
|
+
process.chdir(root);
|
24
|
+
try {
|
25
|
+
const [promise] = (0, loader_1.loadNxPlugin)(pluginConfiguration, root);
|
26
|
+
plugin = await promise;
|
27
|
+
return {
|
28
|
+
type: 'load-result',
|
29
|
+
payload: {
|
30
|
+
name: plugin.name,
|
31
|
+
include: plugin.include,
|
32
|
+
exclude: plugin.exclude,
|
33
|
+
createNodesPattern: plugin.createNodes?.[0],
|
34
|
+
hasCreateDependencies: 'createDependencies' in plugin && !!plugin.createDependencies,
|
35
|
+
hasProcessProjectGraph: 'processProjectGraph' in plugin &&
|
36
|
+
!!plugin.processProjectGraph,
|
37
|
+
hasCreateMetadata: 'createMetadata' in plugin && !!plugin.createMetadata,
|
38
|
+
success: true,
|
39
|
+
},
|
40
|
+
};
|
41
|
+
}
|
42
|
+
catch (e) {
|
43
|
+
return {
|
44
|
+
type: 'load-result',
|
45
|
+
payload: {
|
46
|
+
success: false,
|
47
|
+
error: (0, serializable_error_1.createSerializableError)(e),
|
48
|
+
},
|
49
|
+
};
|
50
|
+
}
|
51
|
+
},
|
52
|
+
createNodes: async ({ configFiles, context, tx }) => {
|
53
|
+
try {
|
54
|
+
const result = await plugin.createNodes[1](configFiles, context);
|
55
|
+
return {
|
56
|
+
type: 'createNodesResult',
|
57
|
+
payload: { result, success: true, tx },
|
58
|
+
};
|
59
|
+
}
|
60
|
+
catch (e) {
|
61
|
+
return {
|
62
|
+
type: 'createNodesResult',
|
63
|
+
payload: {
|
64
|
+
success: false,
|
65
|
+
error: (0, serializable_error_1.createSerializableError)(e),
|
66
|
+
tx,
|
67
|
+
},
|
68
|
+
};
|
69
|
+
}
|
70
|
+
},
|
71
|
+
createDependencies: async ({ context, tx }) => {
|
72
|
+
try {
|
73
|
+
const result = await plugin.createDependencies(context);
|
74
|
+
return {
|
75
|
+
type: 'createDependenciesResult',
|
76
|
+
payload: { dependencies: result, success: true, tx },
|
77
|
+
};
|
78
|
+
}
|
79
|
+
catch (e) {
|
80
|
+
return {
|
81
|
+
type: 'createDependenciesResult',
|
82
|
+
payload: {
|
83
|
+
success: false,
|
84
|
+
error: (0, serializable_error_1.createSerializableError)(e),
|
85
|
+
tx,
|
86
|
+
},
|
87
|
+
};
|
88
|
+
}
|
89
|
+
},
|
90
|
+
processProjectGraph: async ({ graph, ctx, tx }) => {
|
91
|
+
try {
|
92
|
+
const result = await plugin.processProjectGraph(graph, ctx);
|
93
|
+
return {
|
94
|
+
type: 'processProjectGraphResult',
|
95
|
+
payload: { graph: result, success: true, tx },
|
96
|
+
};
|
97
|
+
}
|
98
|
+
catch (e) {
|
99
|
+
return {
|
100
|
+
type: 'processProjectGraphResult',
|
101
|
+
payload: {
|
102
|
+
success: false,
|
103
|
+
error: (0, serializable_error_1.createSerializableError)(e),
|
104
|
+
tx,
|
105
|
+
},
|
106
|
+
};
|
107
|
+
}
|
108
|
+
},
|
109
|
+
createMetadata: async ({ graph, context, tx }) => {
|
110
|
+
try {
|
111
|
+
const result = await plugin.createMetadata(graph, context);
|
112
|
+
return {
|
113
|
+
type: 'createMetadataResult',
|
114
|
+
payload: { metadata: result, success: true, tx },
|
115
|
+
};
|
116
|
+
}
|
117
|
+
catch (e) {
|
118
|
+
return {
|
119
|
+
type: 'createMetadataResult',
|
120
|
+
payload: { success: false, error: e.stack, tx },
|
121
|
+
};
|
122
|
+
}
|
123
|
+
},
|
124
|
+
});
|
125
|
+
}));
|
118
126
|
});
|
127
|
+
server.listen(socketPath);
|
128
|
+
const exitHandler = (exitCode) => () => {
|
129
|
+
server.close();
|
130
|
+
try {
|
131
|
+
(0, fs_1.unlinkSync)(socketPath);
|
132
|
+
}
|
133
|
+
catch (e) { }
|
134
|
+
process.exit(exitCode);
|
135
|
+
};
|
136
|
+
const events = ['SIGINT', 'SIGTERM', 'SIGQUIT', 'exit'];
|
137
|
+
events.forEach((event) => process.once(event, exitHandler(0)));
|
138
|
+
process.once('uncaughtException', exitHandler(1));
|
139
|
+
process.once('unhandledRejection', exitHandler(1));
|
@@ -110,7 +110,13 @@ async function buildProjectGraphAndSourceMapsWithoutDaemon() {
|
|
110
110
|
}
|
111
111
|
}
|
112
112
|
finally {
|
113
|
-
|
113
|
+
// When plugins are isolated we don't clean them up during
|
114
|
+
// a single run of the CLI. They are cleaned up when the CLI
|
115
|
+
// process exits. Cleaning them here could cause issues if pending
|
116
|
+
// promises are not resolved.
|
117
|
+
if (process.env.NX_ISOLATE_PLUGINS !== 'true') {
|
118
|
+
cleanup();
|
119
|
+
}
|
114
120
|
}
|
115
121
|
const { projectGraph, projectFileMapCache } = projectGraphResult;
|
116
122
|
perf_hooks_1.performance.mark('build-project-graph-using-project-file-map:end');
|
@@ -1,10 +1,6 @@
|
|
1
1
|
import { ProjectGraphProjectNode } from '../../config/project-graph';
|
2
2
|
import { ProjectGraphBuilder } from '../project-graph-builder';
|
3
|
-
import { ProjectConfiguration
|
3
|
+
import { ProjectConfiguration } from '../../config/workspace-json-project-json';
|
4
4
|
import { CreateDependenciesContext } from '../plugins';
|
5
5
|
export declare function normalizeProjectNodes({ projects }: CreateDependenciesContext, builder: ProjectGraphBuilder): Promise<void>;
|
6
|
-
/**
|
7
|
-
* Apply target defaults and normalization
|
8
|
-
*/
|
9
|
-
export declare function normalizeProjectTargets(project: ProjectConfiguration, projectName: string): Record<string, TargetConfiguration>;
|
10
6
|
export declare function normalizeImplicitDependencies(source: string, implicitDependencies: ProjectConfiguration['implicitDependencies'], projects: Record<string, ProjectGraphProjectNode>): string[];
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.normalizeImplicitDependencies = exports.
|
3
|
+
exports.normalizeImplicitDependencies = exports.normalizeProjectNodes = void 0;
|
4
4
|
const find_matching_projects_1 = require("../../utils/find-matching-projects");
|
5
5
|
async function normalizeProjectNodes({ projects }, builder) {
|
6
6
|
// Sorting projects by name to make sure that the order of projects in the graph is deterministic.
|
@@ -23,7 +23,7 @@ async function normalizeProjectNodes({ projects }, builder) {
|
|
23
23
|
for (const key of sortedProjectNames) {
|
24
24
|
const p = projects[key];
|
25
25
|
p.implicitDependencies = normalizeImplicitDependencies(key, p.implicitDependencies, partialProjectGraphNodes);
|
26
|
-
p.targets
|
26
|
+
p.targets ??= {};
|
27
27
|
// TODO: remove in v16
|
28
28
|
const projectType = p.projectType === 'application'
|
29
29
|
? key.endsWith('-e2e') || key === 'e2e'
|
@@ -57,21 +57,6 @@ async function normalizeProjectNodes({ projects }, builder) {
|
|
57
57
|
});
|
58
58
|
}
|
59
59
|
exports.normalizeProjectNodes = normalizeProjectNodes;
|
60
|
-
/**
|
61
|
-
* Apply target defaults and normalization
|
62
|
-
*/
|
63
|
-
function normalizeProjectTargets(project, projectName) {
|
64
|
-
// Any node on the graph will have a targets object, it just may be empty
|
65
|
-
const targets = project.targets ?? {};
|
66
|
-
for (const target in targets) {
|
67
|
-
if (!targets[target].command && !targets[target].executor) {
|
68
|
-
delete targets[target];
|
69
|
-
continue;
|
70
|
-
}
|
71
|
-
}
|
72
|
-
return targets;
|
73
|
-
}
|
74
|
-
exports.normalizeProjectTargets = normalizeProjectTargets;
|
75
60
|
function normalizeImplicitDependencies(source, implicitDependencies, projects) {
|
76
61
|
if (!implicitDependencies?.length) {
|
77
62
|
return implicitDependencies ?? [];
|
@@ -293,7 +293,7 @@ function mergeCreateNodesResults(results, errors) {
|
|
293
293
|
const externalNodes = {};
|
294
294
|
const configurationSourceMaps = {};
|
295
295
|
for (const result of results.flat()) {
|
296
|
-
const [
|
296
|
+
const [pluginName, file, nodes] = result;
|
297
297
|
const { projects: projectNodes, externalNodes: pluginExternalNodes } = nodes;
|
298
298
|
const sourceInfo = [file, pluginName];
|
299
299
|
if (result[symbols_1.OVERRIDE_SOURCE_FILE]) {
|
@@ -436,9 +436,20 @@ function validateAndNormalizeProjectRootMap(projectRootMap) {
|
|
436
436
|
}
|
437
437
|
for (const targetName in project.targets) {
|
438
438
|
project.targets[targetName] = normalizeTarget(project.targets[targetName], project);
|
439
|
-
if (
|
439
|
+
if (
|
440
|
+
// If the target has no executor or command, it doesn't do anything
|
441
|
+
!project.targets[targetName].executor &&
|
440
442
|
!project.targets[targetName].command) {
|
441
|
-
|
443
|
+
// But it may have dependencies that do something
|
444
|
+
if (project.targets[targetName].dependsOn &&
|
445
|
+
project.targets[targetName].dependsOn.length > 0) {
|
446
|
+
project.targets[targetName].executor = 'nx:noop';
|
447
|
+
}
|
448
|
+
else {
|
449
|
+
// If it does nothing, and has no depenencies,
|
450
|
+
// we can remove it.
|
451
|
+
delete project.targets[targetName];
|
452
|
+
}
|
442
453
|
}
|
443
454
|
}
|
444
455
|
}
|
@@ -9,12 +9,12 @@ import { LoadedNxPlugin } from '../plugins/internal-api';
|
|
9
9
|
* @param nxJson
|
10
10
|
*/
|
11
11
|
export declare function retrieveWorkspaceFiles(workspaceRoot: string, projectRootMap: Record<string, string>): Promise<{
|
12
|
-
allWorkspaceFiles: import("
|
12
|
+
allWorkspaceFiles: import("../file-utils").FileData[];
|
13
13
|
fileMap: {
|
14
14
|
projectFileMap: ProjectFiles;
|
15
|
-
nonProjectFiles: import("
|
15
|
+
nonProjectFiles: import("../../native").FileData[];
|
16
16
|
};
|
17
|
-
rustReferences: import("
|
17
|
+
rustReferences: import("../../native").NxWorkspaceFilesExternals;
|
18
18
|
}>;
|
19
19
|
/**
|
20
20
|
* Walk through the workspace and return `ProjectConfigurations`. Only use this if the projectFileMap is not needed.
|
@@ -13,12 +13,12 @@ const defaultTasksRunner = async (tasks, options, context) => {
|
|
13
13
|
options['parallel'] === '') {
|
14
14
|
options['parallel'] = Number(options['maxParallel'] || 3);
|
15
15
|
}
|
16
|
-
options.lifeCycle.startCommand();
|
16
|
+
await options.lifeCycle.startCommand();
|
17
17
|
try {
|
18
18
|
return await runAllTasks(tasks, options, context);
|
19
19
|
}
|
20
20
|
finally {
|
21
|
-
options.lifeCycle.endCommand();
|
21
|
+
await options.lifeCycle.endCommand();
|
22
22
|
}
|
23
23
|
};
|
24
24
|
exports.defaultTasksRunner = defaultTasksRunner;
|
@@ -10,9 +10,9 @@ export interface TaskMetadata {
|
|
10
10
|
groupId: number;
|
11
11
|
}
|
12
12
|
export interface LifeCycle {
|
13
|
-
startCommand?(): void
|
14
|
-
endCommand?(): void
|
15
|
-
scheduleTask?(task: Task): void
|
13
|
+
startCommand?(): void | Promise<void>;
|
14
|
+
endCommand?(): void | Promise<void>;
|
15
|
+
scheduleTask?(task: Task): void | Promise<void>;
|
16
16
|
/**
|
17
17
|
* @deprecated use startTasks
|
18
18
|
*
|
@@ -25,19 +25,19 @@ export interface LifeCycle {
|
|
25
25
|
* endTask won't be supported after Nx 14 is released.
|
26
26
|
*/
|
27
27
|
endTask?(task: Task, code: number): void;
|
28
|
-
startTasks?(task: Task[], metadata: TaskMetadata): void
|
29
|
-
endTasks?(taskResults: TaskResult[], metadata: TaskMetadata): void
|
28
|
+
startTasks?(task: Task[], metadata: TaskMetadata): void | Promise<void>;
|
29
|
+
endTasks?(taskResults: TaskResult[], metadata: TaskMetadata): void | Promise<void>;
|
30
30
|
printTaskTerminalOutput?(task: Task, status: TaskStatus, output: string): void;
|
31
31
|
}
|
32
32
|
export declare class CompositeLifeCycle implements LifeCycle {
|
33
33
|
private readonly lifeCycles;
|
34
34
|
constructor(lifeCycles: LifeCycle[]);
|
35
|
-
startCommand(): void
|
36
|
-
endCommand(): void
|
37
|
-
scheduleTask(task: Task): void
|
35
|
+
startCommand(): Promise<void>;
|
36
|
+
endCommand(): Promise<void>;
|
37
|
+
scheduleTask(task: Task): Promise<void>;
|
38
38
|
startTask(task: Task): void;
|
39
39
|
endTask(task: Task, code: number): void;
|
40
|
-
startTasks(tasks: Task[], metadata: TaskMetadata): void
|
41
|
-
endTasks(taskResults: TaskResult[], metadata: TaskMetadata): void
|
40
|
+
startTasks(tasks: Task[], metadata: TaskMetadata): Promise<void>;
|
41
|
+
endTasks(taskResults: TaskResult[], metadata: TaskMetadata): Promise<void>;
|
42
42
|
printTaskTerminalOutput(task: Task, status: TaskStatus, output: string): void;
|
43
43
|
}
|
@@ -5,24 +5,24 @@ class CompositeLifeCycle {
|
|
5
5
|
constructor(lifeCycles) {
|
6
6
|
this.lifeCycles = lifeCycles;
|
7
7
|
}
|
8
|
-
startCommand() {
|
8
|
+
async startCommand() {
|
9
9
|
for (let l of this.lifeCycles) {
|
10
10
|
if (l.startCommand) {
|
11
|
-
l.startCommand();
|
11
|
+
await l.startCommand();
|
12
12
|
}
|
13
13
|
}
|
14
14
|
}
|
15
|
-
endCommand() {
|
15
|
+
async endCommand() {
|
16
16
|
for (let l of this.lifeCycles) {
|
17
17
|
if (l.endCommand) {
|
18
|
-
l.endCommand();
|
18
|
+
await l.endCommand();
|
19
19
|
}
|
20
20
|
}
|
21
21
|
}
|
22
|
-
scheduleTask(task) {
|
22
|
+
async scheduleTask(task) {
|
23
23
|
for (let l of this.lifeCycles) {
|
24
24
|
if (l.scheduleTask) {
|
25
|
-
l.scheduleTask(task);
|
25
|
+
await l.scheduleTask(task);
|
26
26
|
}
|
27
27
|
}
|
28
28
|
}
|
@@ -40,20 +40,20 @@ class CompositeLifeCycle {
|
|
40
40
|
}
|
41
41
|
}
|
42
42
|
}
|
43
|
-
startTasks(tasks, metadata) {
|
43
|
+
async startTasks(tasks, metadata) {
|
44
44
|
for (let l of this.lifeCycles) {
|
45
45
|
if (l.startTasks) {
|
46
|
-
l.startTasks(tasks, metadata);
|
46
|
+
await l.startTasks(tasks, metadata);
|
47
47
|
}
|
48
48
|
else if (l.startTask) {
|
49
49
|
tasks.forEach((t) => l.startTask(t));
|
50
50
|
}
|
51
51
|
}
|
52
52
|
}
|
53
|
-
endTasks(taskResults, metadata) {
|
53
|
+
async endTasks(taskResults, metadata) {
|
54
54
|
for (let l of this.lifeCycles) {
|
55
55
|
if (l.endTasks) {
|
56
|
-
l.endTasks(taskResults, metadata);
|
56
|
+
await l.endTasks(taskResults, metadata);
|
57
57
|
}
|
58
58
|
else if (l.endTask) {
|
59
59
|
taskResults.forEach((t) => l.endTask(t.task, t.code));
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import { Task } from '../../config/task-graph';
|
2
|
+
import { LifeCycle, TaskResult } from '../life-cycle';
|
3
|
+
export declare class TaskHistoryLifeCycle implements LifeCycle {
|
4
|
+
private startTimings;
|
5
|
+
private taskRuns;
|
6
|
+
startTasks(tasks: Task[]): void;
|
7
|
+
endTasks(taskResults: TaskResult[]): Promise<void>;
|
8
|
+
endCommand(): Promise<void>;
|
9
|
+
}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.TaskHistoryLifeCycle = void 0;
|
4
|
+
const serialize_target_1 = require("../../utils/serialize-target");
|
5
|
+
const output_1 = require("../../utils/output");
|
6
|
+
const task_history_1 = require("../../utils/task-history");
|
7
|
+
class TaskHistoryLifeCycle {
|
8
|
+
constructor() {
|
9
|
+
this.startTimings = {};
|
10
|
+
this.taskRuns = [];
|
11
|
+
}
|
12
|
+
startTasks(tasks) {
|
13
|
+
for (let task of tasks) {
|
14
|
+
this.startTimings[task.id] = new Date().getTime();
|
15
|
+
}
|
16
|
+
}
|
17
|
+
async endTasks(taskResults) {
|
18
|
+
const taskRuns = taskResults.map((taskResult) => ({
|
19
|
+
project: taskResult.task.target.project,
|
20
|
+
target: taskResult.task.target.target,
|
21
|
+
configuration: taskResult.task.target.configuration,
|
22
|
+
hash: taskResult.task.hash,
|
23
|
+
code: taskResult.code.toString(),
|
24
|
+
status: taskResult.status,
|
25
|
+
start: (taskResult.task.startTime ?? this.startTimings[taskResult.task.id]).toString(),
|
26
|
+
end: (taskResult.task.endTime ?? new Date().getTime()).toString(),
|
27
|
+
}));
|
28
|
+
this.taskRuns.push(...taskRuns);
|
29
|
+
}
|
30
|
+
async endCommand() {
|
31
|
+
await (0, task_history_1.writeTaskRunsToHistory)(this.taskRuns);
|
32
|
+
const history = await (0, task_history_1.getHistoryForHashes)(this.taskRuns.map((t) => t.hash));
|
33
|
+
const flakyTasks = [];
|
34
|
+
// check if any hash has different exit codes => flaky
|
35
|
+
for (let hash in history) {
|
36
|
+
if (history[hash].length > 1 &&
|
37
|
+
history[hash].some((run) => run.code !== history[hash][0].code)) {
|
38
|
+
flakyTasks.push((0, serialize_target_1.serializeTarget)(history[hash][0].project, history[hash][0].target, history[hash][0].configuration));
|
39
|
+
}
|
40
|
+
}
|
41
|
+
if (flakyTasks.length > 0) {
|
42
|
+
output_1.output.warn({
|
43
|
+
title: `Nx detected ${flakyTasks.length === 1 ? 'a flaky task' : ' flaky tasks'}`,
|
44
|
+
bodyLines: [
|
45
|
+
,
|
46
|
+
...flakyTasks.map((t) => ` ${t}`),
|
47
|
+
'',
|
48
|
+
`Flaky tasks can disrupt your CI pipeline. Automatically retry them with Nx Cloud. Learn more at https://nx.dev/ci/features/flaky-tasks`,
|
49
|
+
],
|
50
|
+
});
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|
54
|
+
exports.TaskHistoryLifeCycle = TaskHistoryLifeCycle;
|
@@ -14,6 +14,7 @@ const dynamic_run_many_terminal_output_life_cycle_1 = require("./life-cycles/dyn
|
|
14
14
|
const task_profiling_life_cycle_1 = require("./life-cycles/task-profiling-life-cycle");
|
15
15
|
const is_ci_1 = require("../utils/is-ci");
|
16
16
|
const dynamic_run_one_terminal_output_life_cycle_1 = require("./life-cycles/dynamic-run-one-terminal-output-life-cycle");
|
17
|
+
const nx_json_1 = require("../config/nx-json");
|
17
18
|
const create_task_graph_1 = require("./create-task-graph");
|
18
19
|
const task_graph_utils_1 = require("./task-graph-utils");
|
19
20
|
const params_1 = require("../utils/params");
|
@@ -21,6 +22,8 @@ const hash_task_1 = require("../hasher/hash-task");
|
|
21
22
|
const client_1 = require("../daemon/client/client");
|
22
23
|
const store_run_information_life_cycle_1 = require("./life-cycles/store-run-information-life-cycle");
|
23
24
|
const create_task_hasher_1 = require("../hasher/create-task-hasher");
|
25
|
+
const task_history_life_cycle_1 = require("./life-cycles/task-history-life-cycle");
|
26
|
+
const nx_cloud_utils_1 = require("../utils/nx-cloud-utils");
|
24
27
|
async function getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks, nxArgs, nxJson, overrides) {
|
25
28
|
const { runnerOptions } = getRunner(nxArgs, nxJson);
|
26
29
|
const isRunOne = initiatingProject != null;
|
@@ -203,6 +206,9 @@ function constructLifeCycles(lifeCycle) {
|
|
203
206
|
if (process.env.NX_PROFILE) {
|
204
207
|
lifeCycles.push(new task_profiling_life_cycle_1.TaskProfilingLifeCycle(process.env.NX_PROFILE));
|
205
208
|
}
|
209
|
+
if (!(0, nx_cloud_utils_1.isNxCloudUsed)((0, nx_json_1.readNxJson)())) {
|
210
|
+
lifeCycles.push(new task_history_life_cycle_1.TaskHistoryLifeCycle());
|
211
|
+
}
|
206
212
|
return lifeCycles;
|
207
213
|
}
|
208
214
|
function mergeTargetDependencies(defaults, deps) {
|
@@ -6,3 +6,16 @@ export declare function getEnvVariablesForTask(task: Task, taskSpecificEnv: Node
|
|
6
6
|
[x: string]: string;
|
7
7
|
TZ?: string;
|
8
8
|
};
|
9
|
+
/**
|
10
|
+
* This function loads a .env file and expands the variables in it.
|
11
|
+
* It is going to override existing environmentVariables.
|
12
|
+
* @param filename
|
13
|
+
* @param environmentVariables
|
14
|
+
*/
|
15
|
+
export declare function loadAndExpandDotEnvFile(filename: string, environmentVariables: NodeJS.ProcessEnv, override?: boolean): import("dotenv-expand").DotenvExpandOutput;
|
16
|
+
/**
|
17
|
+
* This function unloads a .env file and removes the variables in it from the environmentVariables.
|
18
|
+
* @param filename
|
19
|
+
* @param environmentVariables
|
20
|
+
*/
|
21
|
+
export declare function unloadDotEnvFile(filename: string, environmentVariables: NodeJS.ProcessEnv, override?: boolean): void;
|