nx 23.3.0-beta.4 → 23.3.0-beta.6
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/dist/nx-cloud-internals.d.ts +1 -0
- package/dist/nx-cloud-internals.js +9 -0
- package/dist/plugins/package-json.js +1 -1
- package/dist/src/command-line/affected/affected.js +51 -9
- package/dist/src/command-line/graph/graph.d.ts +31 -0
- package/dist/src/command-line/graph/graph.js +71 -17
- package/dist/src/command-line/release/publish.js +7 -11
- package/dist/src/command-line/release/utils/get-touched-projects-for-group.js +3 -3
- package/dist/src/command-line/run/run-one.js +5 -1
- package/dist/src/command-line/run-many/run-many.js +6 -12
- package/dist/src/command-line/show/projects.js +30 -1
- package/dist/src/config/task-graph.d.ts +1 -1
- package/dist/src/config/workspace-json-project-json.d.ts +21 -1
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/core/graph/runtime.js +1 -1
- package/dist/src/core/graph/styles.js +1 -1
- package/dist/src/daemon/client/client.d.ts +7 -2
- package/dist/src/daemon/client/client.js +15 -2
- package/dist/src/daemon/message-types/io-snapshot-version.d.ts +5 -0
- package/dist/src/daemon/message-types/io-snapshot-version.js +2 -0
- package/dist/src/daemon/message-types/select-affected-tasks.d.ts +18 -0
- package/dist/src/daemon/message-types/select-affected-tasks.js +11 -0
- package/dist/src/daemon/server/handle-hash-tasks.d.ts +2 -0
- package/dist/src/daemon/server/handle-hash-tasks.js +5 -3
- package/dist/src/daemon/server/handle-select-affected-tasks.d.ts +3 -0
- package/dist/src/daemon/server/handle-select-affected-tasks.js +23 -0
- package/dist/src/daemon/server/io-snapshots-state.d.ts +7 -0
- package/dist/src/daemon/server/io-snapshots-state.js +35 -0
- package/dist/src/daemon/server/planning-context.d.ts +8 -0
- package/dist/src/daemon/server/planning-context.js +18 -0
- package/dist/src/daemon/server/server.d.ts +1 -0
- package/dist/src/daemon/server/server.js +6 -0
- package/dist/src/executors/run-commands/run-commands.impl.d.ts +2 -1
- package/dist/src/executors/run-commands/run-commands.impl.js +19 -5
- package/dist/src/executors/run-commands/running-tasks.d.ts +5 -4
- package/dist/src/executors/run-commands/running-tasks.js +13 -13
- package/dist/src/hasher/create-task-hasher.d.ts +8 -1
- package/dist/src/hasher/create-task-hasher.js +13 -3
- package/dist/src/hasher/hash-plan-inspector.js +2 -2
- package/dist/src/hasher/hash-task.d.ts +2 -2
- package/dist/src/hasher/hash-task.js +7 -1
- package/dist/src/hasher/native-task-hasher-impl.d.ts +13 -5
- package/dist/src/hasher/native-task-hasher-impl.js +38 -15
- package/dist/src/hasher/task-hasher.d.ts +17 -9
- package/dist/src/hasher/task-hasher.js +16 -11
- package/dist/src/hasher/task-planning-context.d.ts +13 -0
- package/dist/src/hasher/task-planning-context.js +12 -0
- package/dist/src/io-snapshots/config.d.ts +23 -0
- package/dist/src/io-snapshots/config.js +32 -0
- package/dist/src/io-snapshots/fetch.d.ts +21 -0
- package/dist/src/io-snapshots/fetch.js +43 -0
- package/dist/src/io-snapshots/outputs.d.ts +12 -0
- package/dist/src/io-snapshots/outputs.js +33 -0
- package/dist/src/io-snapshots/overrides.d.ts +12 -0
- package/dist/src/io-snapshots/overrides.js +49 -0
- package/dist/src/io-snapshots/report.d.ts +13 -0
- package/dist/src/io-snapshots/report.js +68 -0
- package/dist/src/io-snapshots/store.d.ts +37 -0
- package/dist/src/io-snapshots/store.js +162 -0
- package/dist/src/native/index.d.ts +264 -2
- package/dist/src/native/native-bindings.js +10 -0
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/native/transform-objects.d.ts +11 -2
- package/dist/src/native/transform-objects.js +46 -0
- package/dist/src/nx-cloud/update-manager.d.ts +3 -0
- package/dist/src/plugins/js/project-graph/affected/lock-file-changes.d.ts +10 -2
- package/dist/src/plugins/js/project-graph/affected/lock-file-changes.js +51 -29
- package/dist/src/plugins/js/project-graph/affected/npm-packages.d.ts +10 -2
- package/dist/src/plugins/js/project-graph/affected/npm-packages.js +32 -11
- package/dist/src/plugins/package-json/create-nodes.d.ts +2 -2
- package/dist/src/plugins/package-json/create-nodes.js +13 -13
- package/dist/src/project-graph/affected/affected-project-graph-models.d.ts +14 -0
- package/dist/src/project-graph/affected/affected-project-graph.js +5 -18
- package/dist/src/project-graph/affected/affected-projects.d.ts +7 -0
- package/dist/src/project-graph/affected/affected-projects.js +42 -0
- package/dist/src/project-graph/affected/affected-tasks.d.ts +90 -0
- package/dist/src/project-graph/affected/affected-tasks.js +214 -0
- package/dist/src/project-graph/file-utils.js +6 -2
- package/dist/src/project-graph/utils/project-configuration/target-merging.js +67 -0
- package/dist/src/project-graph/utils/project-configuration/target-normalization.js +83 -0
- package/dist/src/project-graph/utils/project-configuration/utils.d.ts +1 -0
- package/dist/src/project-graph/utils/project-configuration/utils.js +1 -0
- package/dist/src/tasks-runner/create-task-graph.d.ts +24 -1
- package/dist/src/tasks-runner/create-task-graph.js +56 -2
- package/dist/src/tasks-runner/forked-process-task-runner.js +3 -3
- package/dist/src/tasks-runner/init-tasks-runner.d.ts +7 -2
- package/dist/src/tasks-runner/init-tasks-runner.js +17 -6
- package/dist/src/tasks-runner/run-command.d.ts +41 -5
- package/dist/src/tasks-runner/run-command.js +84 -18
- package/dist/src/tasks-runner/task-io-service.d.ts +11 -3
- package/dist/src/tasks-runner/task-io-service.js +14 -5
- package/dist/src/tasks-runner/task-orchestrator.js +1 -1
- package/dist/src/tasks-runner/utils.d.ts +5 -0
- package/dist/src/tasks-runner/utils.js +9 -0
- package/dist/src/utils/db-connection.d.ts +1 -0
- package/dist/src/utils/db-connection.js +1 -0
- package/dist/src/utils/json-diff.d.ts +4 -2
- package/dist/src/utils/json-diff.js +6 -94
- package/dist/src/utils/nx-cloud-utils.d.ts +2 -0
- package/dist/src/utils/nx-cloud-utils.js +6 -1
- package/dist/src/utils/project-graph-utils.d.ts +2 -0
- package/dist/src/utils/project-graph-utils.js +12 -0
- package/package.json +22 -13
- package/readme-template.md +16 -0
- package/schemas/nx-schema.json +34 -0
- package/schemas/project-schema.json +31 -0
- package/dist/src/project-graph/affected/locators/project-glob-changes.d.ts +0 -2
- package/dist/src/project-graph/affected/locators/project-glob-changes.js +0 -40
- package/dist/src/project-graph/affected/locators/workspace-json-changes.d.ts +0 -4
- package/dist/src/project-graph/affected/locators/workspace-json-changes.js +0 -47
- package/dist/src/project-graph/affected/locators/workspace-projects.d.ts +0 -3
- package/dist/src/project-graph/affected/locators/workspace-projects.js +0 -74
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.selectsAffectedTasks = selectsAffectedTasks;
|
|
4
|
+
exports.computeAffectedTasks = computeAffectedTasks;
|
|
5
|
+
exports.selectAffectedTasks = selectAffectedTasks;
|
|
6
|
+
const native_1 = require("../../native");
|
|
7
|
+
const outputs_1 = require("../../io-snapshots/outputs");
|
|
8
|
+
const overrides_1 = require("../../io-snapshots/overrides");
|
|
9
|
+
const store_1 = require("../../io-snapshots/store");
|
|
10
|
+
const create_task_graph_1 = require("../../tasks-runner/create-task-graph");
|
|
11
|
+
const project_graph_utils_1 = require("../../utils/project-graph-utils");
|
|
12
|
+
const utils_1 = require("../../tasks-runner/utils");
|
|
13
|
+
const project_graph_1 = require("../project-graph");
|
|
14
|
+
const file_utils_1 = require("../file-utils");
|
|
15
|
+
const find_matching_projects_1 = require("../../utils/find-matching-projects");
|
|
16
|
+
const logger_1 = require("../../utils/logger");
|
|
17
|
+
const error_types_1 = require("../error-types");
|
|
18
|
+
const workspace_root_1 = require("../../utils/workspace-root");
|
|
19
|
+
const task_planning_context_1 = require("../../hasher/task-planning-context");
|
|
20
|
+
const client_1 = require("../../daemon/client/client");
|
|
21
|
+
const is_on_daemon_1 = require("../../daemon/is-on-daemon");
|
|
22
|
+
const affected_projects_1 = require("./affected-projects");
|
|
23
|
+
const lock_file_changes_1 = require("../../plugins/js/project-graph/affected/lock-file-changes");
|
|
24
|
+
const npm_packages_1 = require("../../plugins/js/project-graph/affected/npm-packages");
|
|
25
|
+
/**
|
|
26
|
+
* Whether `nx affected` selects the individual tasks whose inputs a change
|
|
27
|
+
* reaches, rather than whole projects. Off by default while the task path
|
|
28
|
+
* settles.
|
|
29
|
+
*
|
|
30
|
+
* Env-var only, so `nx show projects --affected` and `nx affected` in one CI
|
|
31
|
+
* script agree. The run also executes the selected tasks' dependencies.
|
|
32
|
+
*/
|
|
33
|
+
function selectsAffectedTasks() {
|
|
34
|
+
return process.env.NX_LEGACY_AFFECTED === 'false';
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Selects the tasks a change reaches, rather than the projects that own a
|
|
38
|
+
* changed file.
|
|
39
|
+
*
|
|
40
|
+
* With the daemon on, the daemon selects: it hashes the run's tasks, so its
|
|
41
|
+
* planner is the one that remembers the plans. It returns the graph it selected
|
|
42
|
+
* against, which the command must run with.
|
|
43
|
+
*/
|
|
44
|
+
async function computeAffectedTasks(opts) {
|
|
45
|
+
const request = {
|
|
46
|
+
targets: opts.targets,
|
|
47
|
+
changedFiles: opts.touchedFiles.map((f) => f.file),
|
|
48
|
+
fileChangeArgs: opts.fileChangeArgs,
|
|
49
|
+
configuration: opts.configuration,
|
|
50
|
+
overrides: opts.overrides ?? {},
|
|
51
|
+
extraTargetDependencies: opts.extraTargetDependencies ?? {},
|
|
52
|
+
excludeTaskDependencies: opts.excludeTaskDependencies ?? false,
|
|
53
|
+
exclude: opts.exclude ?? [],
|
|
54
|
+
selectivelyHashTsConfig: opts.selectivelyHashTsConfig,
|
|
55
|
+
};
|
|
56
|
+
const ioSnapshots = (0, store_1.snapshotsOf)(opts.ioSnapshotOutcome ?? null);
|
|
57
|
+
if (ioSnapshots) {
|
|
58
|
+
request.ioSnapshots = {
|
|
59
|
+
commit: ioSnapshots.commit,
|
|
60
|
+
fetchedAt: ioSnapshots.resolution.fetchedAt,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (!(0, is_on_daemon_1.isOnDaemon)() && client_1.daemonClient.enabled()) {
|
|
64
|
+
try {
|
|
65
|
+
const selection = await client_1.daemonClient.selectAffectedTasks(request);
|
|
66
|
+
return {
|
|
67
|
+
...selection,
|
|
68
|
+
affectedTaskIds: new Set(selection.affectedTaskIds),
|
|
69
|
+
taskSelection: {
|
|
70
|
+
...selection.taskSelection,
|
|
71
|
+
ioSnapshotOutcome: opts.ioSnapshotOutcome,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
if (e?.name === error_types_1.DaemonProjectGraphError.name) {
|
|
77
|
+
throw error_types_1.ProjectGraphError.fromDaemonProjectGraphError(e);
|
|
78
|
+
}
|
|
79
|
+
// Not rethrown: the graph fetch handles an unreachable daemon, and a
|
|
80
|
+
// selection error recurs in-process below.
|
|
81
|
+
logger_1.logger.verbose(`Selecting affected tasks in the daemon failed: ${e}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const projectGraph = opts.projectGraph ?? (await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true }));
|
|
85
|
+
const planningContext = (0, task_planning_context_1.createTaskPlanningContext)(projectGraph, opts.nxJson);
|
|
86
|
+
const selection = await selectAffectedTasks(projectGraph, opts.nxJson, planningContext, request, {
|
|
87
|
+
touchedFiles: opts.touchedFiles,
|
|
88
|
+
packageJson: opts.packageJson,
|
|
89
|
+
ioSnapshots,
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
projectGraph,
|
|
93
|
+
affectedTaskIds: selection.affectedTaskIds,
|
|
94
|
+
taskGraph: selection.taskGraph,
|
|
95
|
+
taskSelection: {
|
|
96
|
+
...selection.taskSelection,
|
|
97
|
+
// The planner remembers what selection planned, so the run's hashing reuses it.
|
|
98
|
+
planningContext,
|
|
99
|
+
ioSnapshotOutcome: opts.ioSnapshotOutcome,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Plans the targets' full task graph and matches the changed paths against
|
|
105
|
+
* every plan. No project-level prefilter: under an I/O snapshot a task can read
|
|
106
|
+
* files no affected project owns. Shared by the client and the daemon.
|
|
107
|
+
*/
|
|
108
|
+
async function selectAffectedTasks(projectGraph, nxJson, planningContext, request, { touchedFiles = (0, file_utils_1.calculateFileChanges)(request.changedFiles, request.fileChangeArgs), packageJson, ioSnapshots, } = {}) {
|
|
109
|
+
const { targets } = request;
|
|
110
|
+
// Only projects that have one of the targets: with a single target,
|
|
111
|
+
// createTaskGraph tries to create a task for projects that lack it and
|
|
112
|
+
// createTask throws.
|
|
113
|
+
const candidates = [...(0, project_graph_utils_1.runnableForTarget)(projectGraph.nodes, targets)];
|
|
114
|
+
if (!candidates.length) {
|
|
115
|
+
const empty = {
|
|
116
|
+
roots: [],
|
|
117
|
+
tasks: {},
|
|
118
|
+
dependencies: {},
|
|
119
|
+
continuousDependencies: {},
|
|
120
|
+
};
|
|
121
|
+
return {
|
|
122
|
+
affectedTaskIds: new Set(),
|
|
123
|
+
taskGraph: empty,
|
|
124
|
+
taskSelection: { taskGraph: empty, initiatingTaskIds: [], taskIds: [] },
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
const { taskGraph, dependencyOverrides } = (0, create_task_graph_1.createTaskGraphWithDependencyOverrides)(projectGraph, request.extraTargetDependencies, candidates, targets, request.configuration, request.overrides,
|
|
128
|
+
// Dependencies carry a change even when they won't run; `keep` drops them.
|
|
129
|
+
false);
|
|
130
|
+
const taskIds = Object.keys(taskGraph.tasks);
|
|
131
|
+
// As the run hashes: observed outputs carry output reads, observed inputs match changes.
|
|
132
|
+
if (ioSnapshots) {
|
|
133
|
+
(0, outputs_1.applyIoSnapshotOutputs)(projectGraph, taskGraph, ioSnapshots);
|
|
134
|
+
}
|
|
135
|
+
const plans = ioSnapshots
|
|
136
|
+
? planningContext.planner.getPlansReference(taskIds, taskGraph, ioSnapshots, (0, overrides_1.ioSnapshotEligibilityOptions)(projectGraph, taskGraph))
|
|
137
|
+
: planningContext.planner.getPlansReference(taskIds, taskGraph);
|
|
138
|
+
const dependencies = dependencyChanges(projectGraph, touchedFiles, nxJson, packageJson);
|
|
139
|
+
const namedProjects = new Set(dependencies.projects);
|
|
140
|
+
const projects = (0, project_graph_1.readProjectsConfigurationFromProjectGraph)(projectGraph).projects;
|
|
141
|
+
const selection = (0, native_1.affectedTasks)(planningContext.projectGraphRef, plans, taskGraph, request.changedFiles, {
|
|
142
|
+
projectGlobPatterns: await (0, affected_projects_1.getProjectGlobPatterns)(nxJson),
|
|
143
|
+
workspaceRoot: workspace_root_1.workspaceRoot,
|
|
144
|
+
alwaysTouchedTaskIds: taskIds.filter((id) => namedProjects.has(taskGraph.tasks[id].target.project) ||
|
|
145
|
+
hasCustomHasher(taskGraph.tasks[id], projects)),
|
|
146
|
+
changedExternals: dependencies.externals,
|
|
147
|
+
changedExternalTypes: dependencies.changedExternalTypes,
|
|
148
|
+
excludedProjects: request.exclude.length
|
|
149
|
+
? (0, find_matching_projects_1.findMatchingProjects)(request.exclude, projectGraph.nodes)
|
|
150
|
+
: [],
|
|
151
|
+
targets,
|
|
152
|
+
revisions: fileRevisions(request.fileChangeArgs),
|
|
153
|
+
selectivelyHashTsConfig: request.selectivelyHashTsConfig ?? false,
|
|
154
|
+
});
|
|
155
|
+
// The run builds from the owning projects, so only their requested tasks
|
|
156
|
+
// take the CLI overrides there; every other task is a dependency.
|
|
157
|
+
const owning = new Set(selection.affected.map((id) => taskGraph.tasks[id].target.project));
|
|
158
|
+
const initial = new Set(taskIds.filter((id) => {
|
|
159
|
+
const { project, target } = taskGraph.tasks[id].target;
|
|
160
|
+
return owning.has(project) && targets.includes(target);
|
|
161
|
+
}));
|
|
162
|
+
// Without dependencies the run builds its initial tasks and nothing else.
|
|
163
|
+
const keep = request.excludeTaskDependencies
|
|
164
|
+
? selection.required.filter((id) => initial.has(id))
|
|
165
|
+
: selection.required;
|
|
166
|
+
return {
|
|
167
|
+
affectedTaskIds: new Set(selection.affected),
|
|
168
|
+
taskGraph,
|
|
169
|
+
taskSelection: {
|
|
170
|
+
// Edges that disagree on a dependency's overrides leave it to a build
|
|
171
|
+
// from the owning projects, which settles them the way the run always has.
|
|
172
|
+
taskGraph: (0, create_task_graph_1.filterTaskGraphToSelection)(projectGraph, taskGraph, dependencyOverrides, initial, new Set(keep)) ??
|
|
173
|
+
(0, utils_1.pruneToSelectedTasks)((0, create_task_graph_1.createTaskGraph)(projectGraph, request.extraTargetDependencies, [...owning], targets, request.configuration, request.overrides, request.excludeTaskDependencies), keep),
|
|
174
|
+
initiatingTaskIds: keep.filter((id) => initial.has(id)),
|
|
175
|
+
taskIds: keep,
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/** Unset for `--files`, which names files without a diff to compare. */
|
|
180
|
+
function fileRevisions(args) {
|
|
181
|
+
return args?.base && !args.files?.length
|
|
182
|
+
? { base: args.base, head: args.head }
|
|
183
|
+
: undefined;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* A custom hasher hashes outside the task's plan, so no instruction says what
|
|
187
|
+
* reaches it and the task is always selected. An executor that cannot be
|
|
188
|
+
* resolved cannot run either, so it is left to the plan.
|
|
189
|
+
*/
|
|
190
|
+
function hasCustomHasher(task, projects) {
|
|
191
|
+
try {
|
|
192
|
+
return !!(0, utils_1.getExecutorForTask)(task, projects).hasherFactory;
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* A lockfile or package.json change reaches a hash as `External(name)`, a
|
|
200
|
+
* package rather than a path, so it is handed to the plans as package names.
|
|
201
|
+
*/
|
|
202
|
+
function dependencyChanges(projectGraph, touchedFiles, nxJson, packageJson = (0, file_utils_1.readPackageJson)()) {
|
|
203
|
+
const changes = [
|
|
204
|
+
(0, lock_file_changes_1.lockFileDependencyChanges)(touchedFiles, projectGraph.nodes, nxJson, packageJson, projectGraph),
|
|
205
|
+
(0, npm_packages_1.packageJsonDependencyChanges)(touchedFiles, nxJson, projectGraph),
|
|
206
|
+
];
|
|
207
|
+
return {
|
|
208
|
+
externals: [...new Set(changes.flatMap((c) => c.externals))],
|
|
209
|
+
changedExternalTypes: [
|
|
210
|
+
...new Set(changes.flatMap((c) => c.changedExternalTypes)),
|
|
211
|
+
],
|
|
212
|
+
projects: [...new Set(changes.flatMap((c) => c.projects))],
|
|
213
|
+
};
|
|
214
|
+
}
|
|
@@ -15,6 +15,7 @@ const path_1 = require("path");
|
|
|
15
15
|
const fileutils_1 = require("../utils/fileutils");
|
|
16
16
|
const git_revision_1 = require("../utils/git-revision");
|
|
17
17
|
const ignore_1 = require("../utils/ignore");
|
|
18
|
+
const native_1 = require("../native");
|
|
18
19
|
const json_diff_1 = require("../utils/json-diff");
|
|
19
20
|
const workspace_root_1 = require("../utils/workspace-root");
|
|
20
21
|
class WholeFileChange {
|
|
@@ -90,7 +91,10 @@ function calculateFileChanges(files, nxArgs, readFileAtRevision = defaultReadFil
|
|
|
90
91
|
try {
|
|
91
92
|
const atBase = readFileAtRevision(f, nxArgs.base);
|
|
92
93
|
const atHead = readFileAtRevision(f, nxArgs.head);
|
|
93
|
-
|
|
94
|
+
// Unset when either side is not strict JSON.
|
|
95
|
+
return ((0, native_1.diffJson)(atBase, atHead) ?? [
|
|
96
|
+
new WholeFileChange(),
|
|
97
|
+
]);
|
|
94
98
|
}
|
|
95
99
|
catch (e) {
|
|
96
100
|
return [new WholeFileChange()];
|
|
@@ -128,7 +132,7 @@ function defaultReadFileAtRevision(file, revision) {
|
|
|
128
132
|
try {
|
|
129
133
|
const filePathInGitRepository = getFilePathInGitRepository(file);
|
|
130
134
|
return !revision
|
|
131
|
-
? (0, fs_1.readFileSync)(file, 'utf-8')
|
|
135
|
+
? (0, fs_1.readFileSync)((0, path_1.join)(workspace_root_1.workspaceRoot, file), 'utf-8')
|
|
132
136
|
: (0, child_process_1.execFileSync)('git', ['show', `${revision}:${filePathInGitRepository}`], {
|
|
133
137
|
maxBuffer: exports.TEN_MEGABYTES,
|
|
134
138
|
stdio: ['pipe', 'pipe', 'ignore'],
|
|
@@ -139,6 +139,60 @@ function mergeConfigurationValue(newConfig, baseConfig, projectConfigSourceMap,
|
|
|
139
139
|
}
|
|
140
140
|
return merged;
|
|
141
141
|
}
|
|
142
|
+
// `ultracache` keeps replace-unless-`'...'` semantics at the object level, but its
|
|
143
|
+
// values still have to be merged per key: neither the wholesale replace nor
|
|
144
|
+
// `mergeObjectWithSpread` recurses, so an `ignoredReads: ['...', 'tmp/**']`
|
|
145
|
+
// would otherwise reach the task graph with `'...'` intact — a glob matching
|
|
146
|
+
// nothing, silently dropping the inherited patterns.
|
|
147
|
+
function mergeUltracache(newUltracache, baseUltracache, projectConfigSourceMap, sourceInformation, targetIdentifier, deferSpreadsWithoutBase) {
|
|
148
|
+
if (newUltracache === undefined) {
|
|
149
|
+
return baseUltracache;
|
|
150
|
+
}
|
|
151
|
+
const sourceMapContext = projectConfigSourceMap
|
|
152
|
+
? {
|
|
153
|
+
sourceMap: projectConfigSourceMap,
|
|
154
|
+
key: `${targetIdentifier}.ultracache`,
|
|
155
|
+
sourceInformation,
|
|
156
|
+
}
|
|
157
|
+
: undefined;
|
|
158
|
+
// Object level first: this settles which keys survive, their order, and
|
|
159
|
+
// their source-map attribution.
|
|
160
|
+
const merged = (0, utils_1.getMergeValueResult)(baseUltracache, newUltracache, sourceMapContext, deferSpreadsWithoutBase);
|
|
161
|
+
if (!merged || typeof merged !== 'object' || Array.isArray(merged)) {
|
|
162
|
+
return merged;
|
|
163
|
+
}
|
|
164
|
+
// Copy before resolving: with no object-level spread `getMergeValueResult`
|
|
165
|
+
// returns `newUltracache` itself, and writing through it would edit the
|
|
166
|
+
// caller's target in place, corrupting later merge layers.
|
|
167
|
+
const resolved = { ...merged };
|
|
168
|
+
// Keys authored before `'...'` let the base win, exactly as they do at the
|
|
169
|
+
// target level. Re-resolving those would overwrite the object-level merge's
|
|
170
|
+
// decision and make authored position meaningless for array keys while
|
|
171
|
+
// still honouring it for scalar ones.
|
|
172
|
+
const authoredKeys = Object.keys(newUltracache);
|
|
173
|
+
const spreadPosition = authoredKeys.indexOf(utils_1.NX_SPREAD_TOKEN);
|
|
174
|
+
const keysBeforeSpread = spreadPosition >= 0
|
|
175
|
+
? new Set(authoredKeys.slice(0, spreadPosition))
|
|
176
|
+
: new Set();
|
|
177
|
+
// Then re-resolve any key the target authored as an array, so a nested
|
|
178
|
+
// `'...'` expands against the inherited value rather than surviving as a
|
|
179
|
+
// literal element.
|
|
180
|
+
for (const key of Object.keys(resolved)) {
|
|
181
|
+
if (!Array.isArray(newUltracache[key]))
|
|
182
|
+
continue;
|
|
183
|
+
if (keysBeforeSpread.has(key) && baseUltracache && key in baseUltracache) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
resolved[key] = (0, utils_1.getMergeValueResult)(baseUltracache?.[key], newUltracache[key], projectConfigSourceMap
|
|
187
|
+
? {
|
|
188
|
+
sourceMap: projectConfigSourceMap,
|
|
189
|
+
key: `${targetIdentifier}.ultracache.${key}`,
|
|
190
|
+
sourceInformation,
|
|
191
|
+
}
|
|
192
|
+
: undefined, deferSpreadsWithoutBase);
|
|
193
|
+
}
|
|
194
|
+
return resolved;
|
|
195
|
+
}
|
|
142
196
|
function mergeConfigurations(newConfigurations, baseConfigurations, projectConfigSourceMap, sourceInformation, targetIdentifier, deferSpreadsWithoutBase) {
|
|
143
197
|
const mergedConfigurations = {};
|
|
144
198
|
// Keys before '...' let base win for shared names; keys after '...'
|
|
@@ -305,6 +359,7 @@ function mergeTargetConfigurations(target, baseTarget, projectConfigSourceMap, s
|
|
|
305
359
|
const skipForOwnMerge = new Set([
|
|
306
360
|
'options',
|
|
307
361
|
'configurations',
|
|
362
|
+
'ultracache',
|
|
308
363
|
utils_1.NX_SPREAD_TOKEN,
|
|
309
364
|
]);
|
|
310
365
|
const processKey = (key) => {
|
|
@@ -428,6 +483,18 @@ function mergeTargetConfigurations(target, baseTarget, projectConfigSourceMap, s
|
|
|
428
483
|
sourceInformation;
|
|
429
484
|
}
|
|
430
485
|
}
|
|
486
|
+
// merge ultracache if either side declares one
|
|
487
|
+
// as with options, an incompatible target discards the base.
|
|
488
|
+
// `ultracache` is in `skipForOwnMerge` so the key-by-key pass leaves it to
|
|
489
|
+
// this block; removing it from that set would change only the key's position
|
|
490
|
+
// in the result, since this overwrites whatever the generic pass produced.
|
|
491
|
+
if ('ultracache' in target ||
|
|
492
|
+
(isCompatible && baseTarget && 'ultracache' in baseTarget)) {
|
|
493
|
+
const mergedUltracache = mergeUltracache(target.ultracache, isCompatible ? baseTarget?.ultracache : undefined, projectConfigSourceMap, sourceInformation, targetIdentifier, deferSpreadsWithoutBase);
|
|
494
|
+
if (mergedUltracache !== undefined) {
|
|
495
|
+
result.ultracache = mergedUltracache;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
431
498
|
if (target.metadata) {
|
|
432
499
|
result.metadata = mergeMetadata(projectConfigSourceMap, sourceInformation, `${targetIdentifier}.metadata`, target.metadata, baseTarget?.metadata);
|
|
433
500
|
}
|
|
@@ -10,6 +10,7 @@ const output_1 = require("../../../utils/output");
|
|
|
10
10
|
const to_project_name_1 = require("../../../config/to-project-name");
|
|
11
11
|
const error_types_1 = require("../../error-types");
|
|
12
12
|
const target_merging_1 = require("./target-merging");
|
|
13
|
+
const utils_1 = require("./utils");
|
|
13
14
|
const node_fs_1 = require("node:fs");
|
|
14
15
|
const git_worktrees_1 = require("../../../utils/git-worktrees");
|
|
15
16
|
const path_1 = require("path");
|
|
@@ -176,6 +177,87 @@ function warnAboutLegacyCachedTargets(legacyCacheReads) {
|
|
|
176
177
|
bodyLines,
|
|
177
178
|
});
|
|
178
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Nothing downstream rejects a key it does not know — the Rust hasher drops it,
|
|
182
|
+
* the Cloud runner reads only the keys it reads, and the Kotlin API decodes with
|
|
183
|
+
* `ignoreUnknownKeys`. So a typo is silent everywhere else, and this is the only
|
|
184
|
+
* place a misspelled option can be reported at all. `'...'` is listed because a
|
|
185
|
+
* spread with no base to resolve against survives merging.
|
|
186
|
+
*/
|
|
187
|
+
const KNOWN_ULTRACACHE_KEYS = new Set([
|
|
188
|
+
'mode',
|
|
189
|
+
'ignoredReads',
|
|
190
|
+
'ignoredWrites',
|
|
191
|
+
utils_1.NX_SPREAD_TOKEN,
|
|
192
|
+
]);
|
|
193
|
+
const ULTRACACHE_MODES = ['on', 'warn', 'error', 'off'];
|
|
194
|
+
function describeUltracacheValue(value) {
|
|
195
|
+
if (Array.isArray(value))
|
|
196
|
+
return 'an array';
|
|
197
|
+
if (value === null)
|
|
198
|
+
return 'null';
|
|
199
|
+
return `a ${typeof value}`;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Describes every way an `ultracache` violates the shape the schema forbids.
|
|
203
|
+
*
|
|
204
|
+
* The schema is editor-only, and everything downstream — the Rust task hasher,
|
|
205
|
+
* the cloud runner's Go and Kotlin deserializers — is strict. A bad value that
|
|
206
|
+
* gets this far is reported far from its source, or silently drops the task's
|
|
207
|
+
* tracking, so it is worth reporting here where the project, target and file
|
|
208
|
+
* are all still in hand.
|
|
209
|
+
*
|
|
210
|
+
* Returns messages rather than throwing: only a WorkspaceValidityError is
|
|
211
|
+
* collected by `validateAndNormalizeProjectRootMap`, and anything else escapes
|
|
212
|
+
* as far as the daemon, which exits on an error it cannot classify.
|
|
213
|
+
*/
|
|
214
|
+
function validateTargetUltracache(ultracache, projectName, projectRoot, targetName, sourceMaps) {
|
|
215
|
+
if (ultracache === undefined) {
|
|
216
|
+
return [];
|
|
217
|
+
}
|
|
218
|
+
const targetSourceMaps = sourceMaps?.[projectRoot];
|
|
219
|
+
const [file, plugin] = targetSourceMaps?.[`targets.${targetName}.ultracache`] ??
|
|
220
|
+
targetSourceMaps?.[`targets.${targetName}`] ??
|
|
221
|
+
[];
|
|
222
|
+
const origin = file
|
|
223
|
+
? ` (defined in ${file})`
|
|
224
|
+
: plugin
|
|
225
|
+
? ` (defined by ${plugin})`
|
|
226
|
+
: '';
|
|
227
|
+
const where = `"${targetName}" in project "${projectName}"${origin}`;
|
|
228
|
+
if (!(0, utils_1.isObject)(ultracache)) {
|
|
229
|
+
return [
|
|
230
|
+
`The "ultracache" configuration for target ${where} must be an object, but it is ${describeUltracacheValue(ultracache)}.`,
|
|
231
|
+
];
|
|
232
|
+
}
|
|
233
|
+
const errors = [];
|
|
234
|
+
for (const key of Object.keys(ultracache)) {
|
|
235
|
+
if (!KNOWN_ULTRACACHE_KEYS.has(key)) {
|
|
236
|
+
errors.push(`"ultracache.${key}" for target ${where} is not an ultracache option. Supported options are "mode", "ignoredReads" and "ignoredWrites".`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (ultracache.mode !== undefined &&
|
|
240
|
+
!ULTRACACHE_MODES.includes(ultracache.mode)) {
|
|
241
|
+
const supported = ULTRACACHE_MODES.map((mode) => `"${mode}"`).join(', ');
|
|
242
|
+
errors.push(`"ultracache.mode" for target ${where} must be one of ${supported}, but it is ${typeof ultracache.mode === 'string'
|
|
243
|
+
? `"${ultracache.mode}"`
|
|
244
|
+
: describeUltracacheValue(ultracache.mode)}.`);
|
|
245
|
+
}
|
|
246
|
+
for (const key of ['ignoredReads', 'ignoredWrites']) {
|
|
247
|
+
const value = ultracache[key];
|
|
248
|
+
if (value === undefined)
|
|
249
|
+
continue;
|
|
250
|
+
if (!Array.isArray(value)) {
|
|
251
|
+
errors.push(`"ultracache.${key}" for target ${where} must be an array of glob patterns, but it is ${describeUltracacheValue(value)}.`);
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
const badIndex = value.findIndex((glob) => typeof glob !== 'string');
|
|
255
|
+
if (badIndex !== -1) {
|
|
256
|
+
errors.push(`"ultracache.${key}[${badIndex}]" for target ${where} must be a glob pattern string, but it is ${describeUltracacheValue(value[badIndex])}.`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return errors;
|
|
260
|
+
}
|
|
179
261
|
function normalizeTargets(project, sourceMaps, nxJsonConfiguration, workspaceRoot,
|
|
180
262
|
/**
|
|
181
263
|
* Project configurations keyed by project name
|
|
@@ -190,6 +272,7 @@ legacyCacheReads) {
|
|
|
190
272
|
for (const targetName in project.targets) {
|
|
191
273
|
project.targets[targetName] = normalizeTarget(project.targets[targetName], project, workspaceRoot, projects, [project.root, targetName].join(':'));
|
|
192
274
|
const target = project.targets[targetName];
|
|
275
|
+
targetErrorMessage.push(...validateTargetUltracache(target.ultracache, project.name ?? project.root, project.root, targetName, sourceMaps).map((message) => `- ${message}`));
|
|
193
276
|
const targetDefaults = nxJsonConfiguration.targetDefaults;
|
|
194
277
|
if (isLegacyCachedTarget(targetName, targetDefaults, target)) {
|
|
195
278
|
target.cache = true;
|
|
@@ -35,4 +35,5 @@ type SourceMapContext = {
|
|
|
35
35
|
* preserved so a later merge layer can expand it.
|
|
36
36
|
*/
|
|
37
37
|
export declare function getMergeValueResult<T>(baseValue: unknown, newValue: T | undefined, sourceMapContext?: SourceMapContext, deferSpreadsWithoutBase?: boolean): T | undefined;
|
|
38
|
+
export declare function isObject(value: unknown): value is Record<string, unknown>;
|
|
38
39
|
export {};
|
|
@@ -4,6 +4,7 @@ exports.IntegerLikeSpreadKeyError = exports.INTEGER_LIKE_KEY_PATTERN = exports.N
|
|
|
4
4
|
exports.uniqueKeysInObjects = uniqueKeysInObjects;
|
|
5
5
|
exports.assertNoIntegerLikeSpreadKey = assertNoIntegerLikeSpreadKey;
|
|
6
6
|
exports.getMergeValueResult = getMergeValueResult;
|
|
7
|
+
exports.isObject = isObject;
|
|
7
8
|
const source_maps_1 = require("./source-maps");
|
|
8
9
|
exports.NX_SPREAD_TOKEN = '...';
|
|
9
10
|
/**
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import { ProjectGraph, ProjectGraphProjectNode } from '../config/project-graph';
|
|
2
2
|
import { Task, TaskGraph } from '../config/task-graph';
|
|
3
3
|
import { TargetDependencies } from '../config/nx-json';
|
|
4
|
+
/**
|
|
5
|
+
* For each task, the overrides every `dependsOn` edge into it would give it,
|
|
6
|
+
* whether or not that edge created the task. `from` is the task the edge
|
|
7
|
+
* leaves; an edge crossing a project without the target is recorded against
|
|
8
|
+
* the task it started from.
|
|
9
|
+
*/
|
|
10
|
+
export type DependencyOverrides = Record<string, Array<{
|
|
11
|
+
from: string;
|
|
12
|
+
overrides: Record<string, unknown>;
|
|
13
|
+
}>>;
|
|
4
14
|
export declare class ProcessTasks {
|
|
5
15
|
private readonly extraTargetDependencies;
|
|
6
16
|
private readonly projectGraph;
|
|
17
|
+
private readonly recordDependencyOverrides;
|
|
7
18
|
private readonly seen;
|
|
8
19
|
readonly tasks: {
|
|
9
20
|
[id: string]: Task;
|
|
@@ -14,18 +25,30 @@ export declare class ProcessTasks {
|
|
|
14
25
|
readonly continuousDependencies: {
|
|
15
26
|
[k: string]: string[];
|
|
16
27
|
};
|
|
28
|
+
readonly dependencyOverrides: DependencyOverrides;
|
|
17
29
|
private readonly allTargetNames;
|
|
18
|
-
constructor(extraTargetDependencies: TargetDependencies, projectGraph: ProjectGraph);
|
|
30
|
+
constructor(extraTargetDependencies: TargetDependencies, projectGraph: ProjectGraph, recordDependencyOverrides?: boolean);
|
|
19
31
|
processTasks(projectNames: string[], targets: string[], configuration: string, overrides: Record<string, unknown>, excludeTaskDependencies: boolean): string[];
|
|
20
32
|
processTask(task: Task, projectUsedToDeriveDependencies: string, configuration: string, overrides: Record<string, unknown>): void;
|
|
21
33
|
private processTasksForMultipleProjects;
|
|
22
34
|
private processTasksForSingleProject;
|
|
23
35
|
private processTasksForDependencies;
|
|
36
|
+
private recordEdge;
|
|
24
37
|
private createDummyTask;
|
|
25
38
|
createTask(id: string, project: ProjectGraphProjectNode, target: string, resolvedConfiguration: string | undefined, overrides: Record<string, unknown>): Task;
|
|
26
39
|
resolveConfiguration(project: ProjectGraphProjectNode, target: string, configuration: string | undefined): string;
|
|
27
40
|
}
|
|
28
41
|
export declare function createTaskGraph(projectGraph: ProjectGraph, extraTargetDependencies: TargetDependencies, projectNames: string[], targets: string[], configuration: string | undefined, overrides: Record<string, unknown>, excludeTaskDependencies?: boolean): TaskGraph;
|
|
42
|
+
/** `createTaskGraph`, plus the overrides each dependency edge would give. */
|
|
43
|
+
export declare function createTaskGraphWithDependencyOverrides(projectGraph: ProjectGraph, extraTargetDependencies: TargetDependencies, projectNames: string[], targets: string[], configuration: string | undefined, overrides: Record<string, unknown>, excludeTaskDependencies?: boolean): {
|
|
44
|
+
taskGraph: TaskGraph;
|
|
45
|
+
dependencyOverrides: DependencyOverrides;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* `taskGraph` pruned to `keep`, as if built from `initial` alone: a kept dependency
|
|
49
|
+
* takes the overrides its edges give it. Undefined when those edges disagree or are missing.
|
|
50
|
+
*/
|
|
51
|
+
export declare function filterTaskGraphToSelection(projectGraph: ProjectGraph, taskGraph: TaskGraph, dependencyOverrides: DependencyOverrides, initial: Set<string>, keep: Set<string>): TaskGraph | undefined;
|
|
29
52
|
/**
|
|
30
53
|
* This function is used to filter out the dummy tasks from the dependencies
|
|
31
54
|
* It will manipulate the dependencies object in place
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ProcessTasks = void 0;
|
|
4
4
|
exports.createTaskGraph = createTaskGraph;
|
|
5
|
+
exports.createTaskGraphWithDependencyOverrides = createTaskGraphWithDependencyOverrides;
|
|
6
|
+
exports.filterTaskGraphToSelection = filterTaskGraphToSelection;
|
|
5
7
|
exports.filterDummyTasks = filterDummyTasks;
|
|
6
8
|
exports.getNonDummyDeps = getNonDummyDeps;
|
|
7
9
|
const utils_1 = require("./utils");
|
|
@@ -10,13 +12,15 @@ const output_1 = require("../utils/output");
|
|
|
10
12
|
const task_graph_utils_1 = require("./task-graph-utils");
|
|
11
13
|
const DUMMY_TASK_TARGET = '__nx_dummy_task__';
|
|
12
14
|
class ProcessTasks {
|
|
13
|
-
constructor(extraTargetDependencies, projectGraph) {
|
|
15
|
+
constructor(extraTargetDependencies, projectGraph, recordDependencyOverrides = false) {
|
|
14
16
|
this.extraTargetDependencies = extraTargetDependencies;
|
|
15
17
|
this.projectGraph = projectGraph;
|
|
18
|
+
this.recordDependencyOverrides = recordDependencyOverrides;
|
|
16
19
|
this.seen = new Set();
|
|
17
20
|
this.tasks = {};
|
|
18
21
|
this.dependencies = {};
|
|
19
22
|
this.continuousDependencies = {};
|
|
23
|
+
this.dependencyOverrides = {};
|
|
20
24
|
const allTargetNames = new Set();
|
|
21
25
|
for (const projectName in projectGraph.nodes) {
|
|
22
26
|
const project = projectGraph.nodes[projectName];
|
|
@@ -126,6 +130,7 @@ class ProcessTasks {
|
|
|
126
130
|
this.processTask(newTask, newTask.target.project, configuration, overrides);
|
|
127
131
|
}
|
|
128
132
|
if (task.id !== selfTaskId) {
|
|
133
|
+
this.recordEdge(task, selfTaskId, taskOverrides);
|
|
129
134
|
if (this.tasks[selfTaskId].continuous) {
|
|
130
135
|
this.continuousDependencies[task.id].push(selfTaskId);
|
|
131
136
|
}
|
|
@@ -149,6 +154,7 @@ class ProcessTasks {
|
|
|
149
154
|
const depTargetId = (0, utils_1.createTaskId)(depProject.name, dependencyConfig.target, resolvedConfiguration);
|
|
150
155
|
const depTargetConfiguration = this.projectGraph.nodes[depProject.name].data.targets[dependencyConfig.target];
|
|
151
156
|
if (task.id !== depTargetId) {
|
|
157
|
+
this.recordEdge(task, depTargetId, taskOverrides);
|
|
152
158
|
if (depTargetConfiguration.continuous) {
|
|
153
159
|
this.continuousDependencies[task.id].push(depTargetId);
|
|
154
160
|
}
|
|
@@ -180,6 +186,14 @@ class ProcessTasks {
|
|
|
180
186
|
}
|
|
181
187
|
}
|
|
182
188
|
}
|
|
189
|
+
recordEdge(task, dependencyId, overrides) {
|
|
190
|
+
if (!this.recordDependencyOverrides) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
// A dummy task keeps its creator's target, so `from` is the real task the edge started from.
|
|
194
|
+
const from = (0, utils_1.createTaskId)(task.target.project, task.target.target, task.target.configuration);
|
|
195
|
+
(this.dependencyOverrides[dependencyId] ??= []).push({ from, overrides });
|
|
196
|
+
}
|
|
183
197
|
createDummyTask(id, task) {
|
|
184
198
|
return {
|
|
185
199
|
...task,
|
|
@@ -208,6 +222,7 @@ class ProcessTasks {
|
|
|
208
222
|
cache: project.data.targets[target].cache ?? false,
|
|
209
223
|
parallelism: project.data.targets[target].parallelism ?? true,
|
|
210
224
|
continuous: project.data.targets[target].continuous ?? false,
|
|
225
|
+
ultracache: project.data.targets[target].ultracache,
|
|
211
226
|
};
|
|
212
227
|
}
|
|
213
228
|
resolveConfiguration(project, target, configuration) {
|
|
@@ -220,7 +235,46 @@ class ProcessTasks {
|
|
|
220
235
|
}
|
|
221
236
|
exports.ProcessTasks = ProcessTasks;
|
|
222
237
|
function createTaskGraph(projectGraph, extraTargetDependencies, projectNames, targets, configuration, overrides, excludeTaskDependencies = false) {
|
|
223
|
-
|
|
238
|
+
return buildTaskGraph(new ProcessTasks(extraTargetDependencies, projectGraph), projectNames, targets, configuration, overrides, excludeTaskDependencies);
|
|
239
|
+
}
|
|
240
|
+
/** `createTaskGraph`, plus the overrides each dependency edge would give. */
|
|
241
|
+
function createTaskGraphWithDependencyOverrides(projectGraph, extraTargetDependencies, projectNames, targets, configuration, overrides, excludeTaskDependencies = false) {
|
|
242
|
+
const p = new ProcessTasks(extraTargetDependencies, projectGraph, true);
|
|
243
|
+
const taskGraph = buildTaskGraph(p, projectNames, targets, configuration, overrides, excludeTaskDependencies);
|
|
244
|
+
return { taskGraph, dependencyOverrides: p.dependencyOverrides };
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* `taskGraph` pruned to `keep`, as if built from `initial` alone: a kept dependency
|
|
248
|
+
* takes the overrides its edges give it. Undefined when those edges disagree or are missing.
|
|
249
|
+
*/
|
|
250
|
+
function filterTaskGraphToSelection(projectGraph, taskGraph, dependencyOverrides, initial, keep) {
|
|
251
|
+
const tasks = {};
|
|
252
|
+
for (const id of keep) {
|
|
253
|
+
const task = taskGraph.tasks[id];
|
|
254
|
+
if (initial.has(id)) {
|
|
255
|
+
tasks[id] = { ...task };
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
const edges = dependencyOverrides[id] ?? [];
|
|
259
|
+
if (!edges.length) {
|
|
260
|
+
return undefined;
|
|
261
|
+
}
|
|
262
|
+
const first = JSON.stringify(edges[0].overrides);
|
|
263
|
+
if (edges.some((e) => JSON.stringify(e.overrides) !== first)) {
|
|
264
|
+
return undefined;
|
|
265
|
+
}
|
|
266
|
+
const project = projectGraph.nodes[task.target.project];
|
|
267
|
+
const overrides = interpolateOverrides(edges[0].overrides, project.name, project.data);
|
|
268
|
+
tasks[id] = {
|
|
269
|
+
...task,
|
|
270
|
+
overrides,
|
|
271
|
+
outputs: (0, utils_1.getOutputs)(projectGraph.nodes, task.target, overrides),
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
const pruned = (0, utils_1.removeTasksFromTaskGraph)(taskGraph, Object.keys(taskGraph.tasks).filter((id) => !keep.has(id)));
|
|
275
|
+
return { ...pruned, tasks };
|
|
276
|
+
}
|
|
277
|
+
function buildTaskGraph(p, projectNames, targets, configuration, overrides, excludeTaskDependencies) {
|
|
224
278
|
const roots = p.processTasks(projectNames, targets, configuration, overrides, excludeTaskDependencies);
|
|
225
279
|
return {
|
|
226
280
|
roots,
|
|
@@ -144,7 +144,7 @@ class ForkedProcessTaskRunner {
|
|
|
144
144
|
// Register forked process for metrics collection
|
|
145
145
|
const pid = p.getPid();
|
|
146
146
|
if (pid) {
|
|
147
|
-
(0, task_io_service_1.registerTaskProcessStart)(task
|
|
147
|
+
(0, task_io_service_1.registerTaskProcessStart)(task, pid);
|
|
148
148
|
}
|
|
149
149
|
p.send({
|
|
150
150
|
targetDescription: task.target,
|
|
@@ -181,7 +181,7 @@ class ForkedProcessTaskRunner {
|
|
|
181
181
|
});
|
|
182
182
|
// Register forked process for metrics collection
|
|
183
183
|
if (p.pid) {
|
|
184
|
-
(0, task_io_service_1.registerTaskProcessStart)(task
|
|
184
|
+
(0, task_io_service_1.registerTaskProcessStart)(task, p.pid);
|
|
185
185
|
}
|
|
186
186
|
// Send message to run the executor
|
|
187
187
|
p.send({
|
|
@@ -224,7 +224,7 @@ class ForkedProcessTaskRunner {
|
|
|
224
224
|
});
|
|
225
225
|
// Register forked process for metrics collection
|
|
226
226
|
if (p.pid) {
|
|
227
|
-
(0, task_io_service_1.registerTaskProcessStart)(task
|
|
227
|
+
(0, task_io_service_1.registerTaskProcessStart)(task, p.pid);
|
|
228
228
|
}
|
|
229
229
|
const cp = new node_child_process_1.NodeChildProcessWithDirectOutput(p, temporaryOutputPath);
|
|
230
230
|
this.processes.add(cp);
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import type { NxJsonConfiguration } from '../config/nx-json';
|
|
2
2
|
import { Task, TaskGraph } from '../config/task-graph';
|
|
3
3
|
import { LifeCycle, TaskResult } from './life-cycle';
|
|
4
|
+
import type { IoSnapshots } from '../native';
|
|
4
5
|
import type { ProjectGraph } from '../config/project-graph';
|
|
5
6
|
import { RunningTask } from './running-tasks/running-task';
|
|
6
|
-
export declare function runDiscreteTasks(tasks: Task[], projectGraph: ProjectGraph, fullTaskGraph: TaskGraph, nxJson: NxJsonConfiguration, lifeCycle: LifeCycle
|
|
7
|
-
|
|
7
|
+
export declare function runDiscreteTasks(tasks: Task[], projectGraph: ProjectGraph, fullTaskGraph: TaskGraph, nxJson: NxJsonConfiguration, lifeCycle: LifeCycle,
|
|
8
|
+
/** The set to hash from, e.g. from `importIoSnapshots`; omitted hashes natively. */
|
|
9
|
+
ioSnapshots?: IoSnapshots): Promise<Array<Promise<TaskResult[]>>>;
|
|
10
|
+
export declare function runContinuousTasks(tasks: Task[], projectGraph: ProjectGraph, fullTaskGraph: TaskGraph, nxJson: NxJsonConfiguration, lifeCycle: LifeCycle,
|
|
11
|
+
/** The set to hash from, e.g. from `importIoSnapshots`; omitted hashes natively. */
|
|
12
|
+
ioSnapshots?: IoSnapshots): Promise<Record<string, Promise<RunningTask>>>;
|