nx 23.0.0-beta.1 → 23.0.0-pr.33655.cdc3e72
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/bin/nx.js +2 -2
- package/dist/src/command-line/release/utils/shared.js +22 -12
- package/dist/src/executors/run-commands/running-tasks.js +94 -85
- package/dist/src/executors/run-script/run-script.impl.js +3 -10
- package/dist/src/native/index.d.ts +18 -1
- package/dist/src/native/native-bindings.js +2 -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/tasks-runner/forked-process-task-runner.d.ts +1 -1
- package/dist/src/tasks-runner/forked-process-task-runner.js +19 -6
- package/dist/src/tasks-runner/pseudo-terminal.d.ts +1 -1
- package/dist/src/tasks-runner/pseudo-terminal.js +22 -10
- package/dist/src/tasks-runner/running-tasks/batch-process.d.ts +1 -1
- package/dist/src/tasks-runner/running-tasks/batch-process.js +3 -5
- package/dist/src/tasks-runner/running-tasks/node-child-process.d.ts +2 -2
- package/dist/src/tasks-runner/running-tasks/node-child-process.js +5 -7
- package/dist/src/tasks-runner/task-orchestrator.d.ts +1 -0
- package/dist/src/tasks-runner/task-orchestrator.js +39 -25
- package/dist/src/tasks-runner/utils.d.ts +11 -0
- package/dist/src/tasks-runner/utils.js +37 -0
- package/package.json +11 -12
package/dist/bin/nx.js
CHANGED
|
@@ -109,10 +109,10 @@ async function main() {
|
|
|
109
109
|
warnIfUsingOutdatedGlobalInstall(GLOBAL_NX_VERSION, LOCAL_NX_VERSION);
|
|
110
110
|
if (localNx.includes('.nx')) {
|
|
111
111
|
const nxWrapperPath = localNx.replace(/\.nx.*/, '.nx/') + 'nxw.js';
|
|
112
|
-
|
|
112
|
+
require(nxWrapperPath);
|
|
113
113
|
}
|
|
114
114
|
else {
|
|
115
|
-
|
|
115
|
+
require(localNx);
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
}
|
|
@@ -15,6 +15,7 @@ const semver_1 = require("semver");
|
|
|
15
15
|
const utils_1 = require("../../../tasks-runner/utils");
|
|
16
16
|
const output_1 = require("../../../utils/output");
|
|
17
17
|
const git_1 = require("./git");
|
|
18
|
+
const find_matching_projects_1 = require("../../../utils/find-matching-projects");
|
|
18
19
|
exports.noDiffInChangelogMessage = pc.yellow(`NOTE: There was no diff detected for the changelog entry. Maybe you intended to pass alternative git references via --from and --to?`);
|
|
19
20
|
function isPrerelease(version) {
|
|
20
21
|
// prerelease returns an array of matching prerelease "components", or null if the version is not a prerelease
|
|
@@ -329,23 +330,32 @@ async function getCommitsRelevantToProjects(projectGraph, commits, projects, nxR
|
|
|
329
330
|
// Try to get the graph associated with the commit shortHash
|
|
330
331
|
// if not available, calculate it and store it in the cache
|
|
331
332
|
let affectedGraph = await releaseGraph.resolveAffectedFilesPerCommitInProjectGraph(commit, projectGraph);
|
|
333
|
+
// Resolve commit scopes using Nx matcher
|
|
334
|
+
const scopePatterns = commit.scope
|
|
335
|
+
? commit.scope.split(',').map((s) => s.trim())
|
|
336
|
+
: [];
|
|
337
|
+
let scopedProjects = null;
|
|
338
|
+
if (scopePatterns.length > 0) {
|
|
339
|
+
const matches = (0, find_matching_projects_1.findMatchingProjects)(scopePatterns, projectGraph.nodes);
|
|
340
|
+
// detect ambiguity
|
|
341
|
+
for (const pattern of scopePatterns) {
|
|
342
|
+
const perPatternMatches = (0, find_matching_projects_1.findMatchingProjects)([pattern], projectGraph.nodes);
|
|
343
|
+
if (perPatternMatches.length > 1) {
|
|
344
|
+
throw new Error(`Ambiguous scope "${pattern}" in commit "${commit.message}". ` +
|
|
345
|
+
`Matches: ${perPatternMatches.join(', ')}`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
scopedProjects = new Set(matches);
|
|
349
|
+
}
|
|
332
350
|
for (const projectName of Object.keys(affectedGraph.nodes)) {
|
|
333
351
|
if (projectSet.has(projectName)) {
|
|
334
352
|
if (!relevantCommits.has(projectName)) {
|
|
335
353
|
relevantCommits.set(projectName, []);
|
|
336
354
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
.get(projectName)
|
|
342
|
-
?.push({ commit, isProjectScopedCommit: true });
|
|
343
|
-
}
|
|
344
|
-
else {
|
|
345
|
-
relevantCommits
|
|
346
|
-
.get(projectName)
|
|
347
|
-
?.push({ commit, isProjectScopedCommit: false });
|
|
348
|
-
}
|
|
355
|
+
const isProjectScopedCommit = scopedProjects === null || scopedProjects.has(projectName);
|
|
356
|
+
relevantCommits
|
|
357
|
+
.get(projectName)
|
|
358
|
+
?.push({ commit, isProjectScopedCommit });
|
|
349
359
|
}
|
|
350
360
|
}
|
|
351
361
|
}
|
|
@@ -7,7 +7,7 @@ const pc = tslib_1.__importStar(require("picocolors"));
|
|
|
7
7
|
const child_process_1 = require("child_process");
|
|
8
8
|
const npm_run_path_1 = require("npm-run-path");
|
|
9
9
|
const path_1 = require("path");
|
|
10
|
-
const
|
|
10
|
+
const native_1 = require("../../native");
|
|
11
11
|
const pseudo_terminal_1 = require("../../tasks-runner/pseudo-terminal");
|
|
12
12
|
const task_env_1 = require("../../tasks-runner/task-env");
|
|
13
13
|
const task_io_service_1 = require("../../tasks-runner/task-io-service");
|
|
@@ -40,14 +40,7 @@ class ParallelRunningTasks {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
async kill(signal) {
|
|
43
|
-
await Promise.
|
|
44
|
-
try {
|
|
45
|
-
return p.kill();
|
|
46
|
-
}
|
|
47
|
-
catch (e) {
|
|
48
|
-
console.error(`Unable to terminate "${p.command}"\nError:`, e);
|
|
49
|
-
}
|
|
50
|
-
}));
|
|
43
|
+
await Promise.allSettled(this.childProcesses.map((p) => p.kill(signal)));
|
|
51
44
|
}
|
|
52
45
|
async run() {
|
|
53
46
|
if (this.readyWhenStatus.length) {
|
|
@@ -93,7 +86,7 @@ class ParallelRunningTasks {
|
|
|
93
86
|
hasFailure = true;
|
|
94
87
|
failureDetails = { childProcess, code, terminalOutput };
|
|
95
88
|
// Immediately terminate all other running processes
|
|
96
|
-
|
|
89
|
+
this.terminateRemainingProcesses(runningProcesses, childProcess);
|
|
97
90
|
}
|
|
98
91
|
runningProcesses.delete(childProcess);
|
|
99
92
|
}));
|
|
@@ -116,25 +109,11 @@ class ParallelRunningTasks {
|
|
|
116
109
|
}
|
|
117
110
|
}
|
|
118
111
|
}
|
|
119
|
-
|
|
120
|
-
const terminationPromises = [];
|
|
112
|
+
terminateRemainingProcesses(runningProcesses, failedProcess) {
|
|
121
113
|
const processesToTerminate = [...runningProcesses].filter((p) => p !== failedProcess);
|
|
122
114
|
for (const process of processesToTerminate) {
|
|
123
115
|
runningProcesses.delete(process);
|
|
124
|
-
|
|
125
|
-
terminationPromises.push(process.kill('SIGTERM').catch((err) => {
|
|
126
|
-
// Log error but don't fail the entire operation
|
|
127
|
-
if (this.streamOutput) {
|
|
128
|
-
console.error(`Failed to terminate process "${process.command}":`, err);
|
|
129
|
-
}
|
|
130
|
-
}));
|
|
131
|
-
}
|
|
132
|
-
// Wait for all terminations to complete with a timeout
|
|
133
|
-
if (terminationPromises.length > 0) {
|
|
134
|
-
await Promise.race([
|
|
135
|
-
Promise.all(terminationPromises),
|
|
136
|
-
new Promise((resolve) => setTimeout(resolve, 5_000)),
|
|
137
|
-
]);
|
|
116
|
+
process.kill('SIGTERM').catch(() => { });
|
|
138
117
|
}
|
|
139
118
|
}
|
|
140
119
|
}
|
|
@@ -182,7 +161,7 @@ class SeriallyRunningTasks {
|
|
|
182
161
|
throw new Error('Not implemented');
|
|
183
162
|
}
|
|
184
163
|
kill(signal) {
|
|
185
|
-
return this.currentProcess
|
|
164
|
+
return this.currentProcess?.kill(signal);
|
|
186
165
|
}
|
|
187
166
|
async run(options, context) {
|
|
188
167
|
for (const c of options.commands) {
|
|
@@ -236,6 +215,7 @@ class RunningNodeProcess {
|
|
|
236
215
|
this.terminalOutputChunks = [];
|
|
237
216
|
this.exitCallbacks = [];
|
|
238
217
|
this.outputCallbacks = [];
|
|
218
|
+
this.killPromise = null;
|
|
239
219
|
env = processEnv(color, cwd, env, envFile);
|
|
240
220
|
this.command = commandConfig.command;
|
|
241
221
|
const header = pc.dim('> ') + commandConfig.command + '\r\n\r\n';
|
|
@@ -245,9 +225,14 @@ class RunningNodeProcess {
|
|
|
245
225
|
}
|
|
246
226
|
this.childProcess = (0, child_process_1.spawn)(commandConfig.command, [], {
|
|
247
227
|
shell: true,
|
|
228
|
+
detached: process.platform !== 'win32',
|
|
248
229
|
env,
|
|
249
230
|
cwd,
|
|
250
231
|
windowsHide: true,
|
|
232
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
233
|
+
});
|
|
234
|
+
this.closedPromise = new Promise((resolve) => {
|
|
235
|
+
this.childProcess.on('close', resolve);
|
|
251
236
|
});
|
|
252
237
|
this.childProcess.stdout?.setEncoding('utf8');
|
|
253
238
|
this.childProcess.stderr?.setEncoding('utf8');
|
|
@@ -275,18 +260,21 @@ class RunningNodeProcess {
|
|
|
275
260
|
this.childProcess.send(message);
|
|
276
261
|
}
|
|
277
262
|
kill(signal) {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
263
|
+
if (this.killPromise)
|
|
264
|
+
return this.killPromise;
|
|
265
|
+
if (!this.childProcess.pid)
|
|
266
|
+
return Promise.resolve();
|
|
267
|
+
// Cache the promise so concurrent callers (e.g. cleanup() after a
|
|
268
|
+
// fire-and-forget kill from cleanUpUnneededContinuousTasks) await the
|
|
269
|
+
// same in-progress operation instead of no-oping.
|
|
270
|
+
this.killPromise = (0, native_1.killProcessTreeGraceful)(this.childProcess.pid, signal).then(() =>
|
|
271
|
+
// Wait for stdio drain and close events before the orchestrator
|
|
272
|
+
// tears down the event loop via process.exit().
|
|
273
|
+
Promise.race([
|
|
274
|
+
this.closedPromise,
|
|
275
|
+
new Promise((resolve) => setTimeout(resolve, 1000)),
|
|
276
|
+
]));
|
|
277
|
+
return this.killPromise;
|
|
290
278
|
}
|
|
291
279
|
triggerOutputListeners(output) {
|
|
292
280
|
for (const cb of this.outputCallbacks) {
|
|
@@ -294,6 +282,34 @@ class RunningNodeProcess {
|
|
|
294
282
|
}
|
|
295
283
|
}
|
|
296
284
|
addListeners(commandConfig, streamOutput) {
|
|
285
|
+
// Named handlers so they can be removed when the child exits.
|
|
286
|
+
// Otherwise each RunningNodeProcess leaks process listeners; with
|
|
287
|
+
// many run-commands tasks this triggers MaxListenersExceededWarning.
|
|
288
|
+
const isForked = !!process.env.NX_FORKED_TASK_EXECUTOR;
|
|
289
|
+
const onProcessExit = () => {
|
|
290
|
+
if (this.childProcess.pid && !this.killPromise) {
|
|
291
|
+
(0, native_1.killProcessTree)(this.childProcess.pid);
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
const onSigInt = () => {
|
|
295
|
+
this.kill('SIGTERM');
|
|
296
|
+
};
|
|
297
|
+
const onSigTerm = () => {
|
|
298
|
+
this.kill('SIGTERM');
|
|
299
|
+
};
|
|
300
|
+
const onSigHup = () => {
|
|
301
|
+
this.kill('SIGTERM');
|
|
302
|
+
};
|
|
303
|
+
const removeProcessListeners = () => {
|
|
304
|
+
process.removeListener('exit', onProcessExit);
|
|
305
|
+
if (isForked) {
|
|
306
|
+
process.removeListener('SIGINT', onSigInt);
|
|
307
|
+
process.removeListener('SIGTERM', onSigTerm);
|
|
308
|
+
process.removeListener('SIGHUP', onSigHup);
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
this.childProcess.stdout.setEncoding('utf8');
|
|
312
|
+
this.childProcess.stderr.setEncoding('utf8');
|
|
297
313
|
this.childProcess.stdout.on('data', (data) => {
|
|
298
314
|
const output = addColorAndPrefix(data, commandConfig);
|
|
299
315
|
this.terminalOutputChunks.push(output);
|
|
@@ -301,8 +317,7 @@ class RunningNodeProcess {
|
|
|
301
317
|
if (streamOutput) {
|
|
302
318
|
process.stdout.write(output);
|
|
303
319
|
}
|
|
304
|
-
if (this.readyWhenStatus.length &&
|
|
305
|
-
isReady(this.readyWhenStatus, data.toString())) {
|
|
320
|
+
if (this.readyWhenStatus.length && isReady(this.readyWhenStatus, data)) {
|
|
306
321
|
for (const cb of this.exitCallbacks) {
|
|
307
322
|
cb(0, this.terminalOutputChunks.join(''));
|
|
308
323
|
}
|
|
@@ -315,8 +330,7 @@ class RunningNodeProcess {
|
|
|
315
330
|
if (streamOutput) {
|
|
316
331
|
process.stderr.write(output);
|
|
317
332
|
}
|
|
318
|
-
if (this.readyWhenStatus.length &&
|
|
319
|
-
isReady(this.readyWhenStatus, err.toString())) {
|
|
333
|
+
if (this.readyWhenStatus.length && isReady(this.readyWhenStatus, err)) {
|
|
320
334
|
for (const cb of this.exitCallbacks) {
|
|
321
335
|
cb(1, this.terminalOutputChunks.join(''));
|
|
322
336
|
}
|
|
@@ -335,29 +349,6 @@ class RunningNodeProcess {
|
|
|
335
349
|
cb(1, terminalOutput);
|
|
336
350
|
}
|
|
337
351
|
});
|
|
338
|
-
// Store signal/exit handlers so they can be removed when the child exits.
|
|
339
|
-
// Without cleanup, each RunningNodeProcess leaks 4 process listeners.
|
|
340
|
-
// In a large monorepo (2600+ run-commands tasks), these accumulate and
|
|
341
|
-
// cause a multi-minute synchronous hang at process.exit() as each handler
|
|
342
|
-
// calls treeKill on an already-dead PID.
|
|
343
|
-
const onExit = () => {
|
|
344
|
-
this.kill();
|
|
345
|
-
};
|
|
346
|
-
const onSigInt = () => {
|
|
347
|
-
this.kill('SIGTERM');
|
|
348
|
-
};
|
|
349
|
-
const onSigTerm = () => {
|
|
350
|
-
this.kill('SIGTERM');
|
|
351
|
-
};
|
|
352
|
-
const onSigHup = () => {
|
|
353
|
-
this.kill('SIGTERM');
|
|
354
|
-
};
|
|
355
|
-
const removeProcessListeners = () => {
|
|
356
|
-
process.removeListener('exit', onExit);
|
|
357
|
-
process.removeListener('SIGINT', onSigInt);
|
|
358
|
-
process.removeListener('SIGTERM', onSigTerm);
|
|
359
|
-
process.removeListener('SIGHUP', onSigHup);
|
|
360
|
-
};
|
|
361
352
|
this.childProcess.on('exit', (code, signal) => {
|
|
362
353
|
if (code === null) {
|
|
363
354
|
code = (0, exit_codes_1.signalToCode)(signal);
|
|
@@ -371,11 +362,19 @@ class RunningNodeProcess {
|
|
|
371
362
|
}
|
|
372
363
|
}
|
|
373
364
|
});
|
|
374
|
-
// Terminate any task processes on exit
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
process.on('
|
|
378
|
-
|
|
365
|
+
// Terminate any task processes on exit (sync, last resort).
|
|
366
|
+
// Skip if graceful kill is already in progress — it tracks cleanup
|
|
367
|
+
// subprocesses and we must not interfere with them.
|
|
368
|
+
process.on('exit', onProcessExit);
|
|
369
|
+
// In the direct path, detached children don't get OS SIGINT (own process
|
|
370
|
+
// group via setsid); the orchestrator's cleanup() sends SIGTERM via
|
|
371
|
+
// killProcessTreeGraceful. Signal handlers here are only needed in the
|
|
372
|
+
// forked path where there's no orchestrator to dispatch signals.
|
|
373
|
+
if (isForked) {
|
|
374
|
+
process.on('SIGINT', onSigInt);
|
|
375
|
+
process.on('SIGTERM', onSigTerm);
|
|
376
|
+
process.on('SIGHUP', onSigHup);
|
|
377
|
+
}
|
|
379
378
|
}
|
|
380
379
|
}
|
|
381
380
|
async function runSingleCommandWithPseudoTerminal(normalized, context, taskId) {
|
|
@@ -493,21 +492,31 @@ function registerProcessListener(runningTask, pseudoTerminal) {
|
|
|
493
492
|
runningTask.send(message);
|
|
494
493
|
}
|
|
495
494
|
});
|
|
496
|
-
// Terminate any task processes on exit
|
|
495
|
+
// Terminate any task processes on exit (sync, last resort).
|
|
496
|
+
// The per-child exit handlers and PseudoTerminal.shutdown() use the
|
|
497
|
+
// sync killProcessTree for this path. We call kill() here as a
|
|
498
|
+
// best-effort fallback — it returns a Promise but on 'exit' only
|
|
499
|
+
// synchronous work runs, so the initial signal is sent but the
|
|
500
|
+
// grace period won't be awaited. That's acceptable: 'exit' is the
|
|
501
|
+
// last resort after SIGINT/SIGTERM handlers have already had their
|
|
502
|
+
// chance to do graceful shutdown.
|
|
497
503
|
process.on('exit', () => {
|
|
498
504
|
runningTask.kill();
|
|
499
505
|
});
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
process.
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
506
|
+
// In the direct path, the orchestrator handles signal dispatch to children.
|
|
507
|
+
// These handlers are only needed in the forked path where there's no
|
|
508
|
+
// orchestrator.
|
|
509
|
+
if (process.env.NX_FORKED_TASK_EXECUTOR) {
|
|
510
|
+
process.on('SIGINT', () => {
|
|
511
|
+
Promise.resolve(runningTask.kill('SIGTERM')).finally(() => {
|
|
512
|
+
process.exit((0, exit_codes_1.signalToCode)('SIGINT'));
|
|
513
|
+
});
|
|
514
|
+
});
|
|
515
|
+
process.on('SIGTERM', () => {
|
|
516
|
+
runningTask.kill('SIGTERM');
|
|
517
|
+
});
|
|
518
|
+
process.on('SIGHUP', () => {
|
|
519
|
+
runningTask.kill('SIGTERM');
|
|
520
|
+
});
|
|
521
|
+
}
|
|
513
522
|
}
|
|
@@ -4,7 +4,7 @@ exports.default = default_1;
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const child_process_1 = require("child_process");
|
|
6
6
|
const path = tslib_1.__importStar(require("path"));
|
|
7
|
-
const
|
|
7
|
+
const native_1 = require("../../native");
|
|
8
8
|
const pseudo_terminal_1 = require("../../tasks-runner/pseudo-terminal");
|
|
9
9
|
const package_manager_1 = require("../../utils/package-manager");
|
|
10
10
|
async function default_1(options, context) {
|
|
@@ -56,15 +56,8 @@ function nodeProcess(command, cwd, env) {
|
|
|
56
56
|
});
|
|
57
57
|
const exitHandler = (signal) => {
|
|
58
58
|
if (cp && cp.pid && !cp.killed) {
|
|
59
|
-
(0,
|
|
60
|
-
|
|
61
|
-
// Ignore the errors, otherwise we will log them unnecessarily.
|
|
62
|
-
if (error && process.platform !== 'win32') {
|
|
63
|
-
rej(error);
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
res();
|
|
67
|
-
}
|
|
59
|
+
(0, native_1.killProcessTreeGraceful)(cp.pid, signal).finally(() => {
|
|
60
|
+
res();
|
|
68
61
|
});
|
|
69
62
|
}
|
|
70
63
|
};
|
|
@@ -52,7 +52,7 @@ export declare class AppLifeCycle {
|
|
|
52
52
|
export declare class ChildProcess {
|
|
53
53
|
getParserAndWriter(): ExternalObject<[ParserArc, WriterArc]>
|
|
54
54
|
getPid(): number
|
|
55
|
-
kill(signal?: NodeJS.Signals): void
|
|
55
|
+
kill(signal?: NodeJS.Signals | number): void
|
|
56
56
|
onExit(callback: (message: string) => void): void
|
|
57
57
|
onOutput(callback: (message: string) => void): void
|
|
58
58
|
cleanup(): void
|
|
@@ -465,6 +465,23 @@ export interface JsonInput {
|
|
|
465
465
|
excludeFields?: Array<string>
|
|
466
466
|
}
|
|
467
467
|
|
|
468
|
+
/**
|
|
469
|
+
* Kill a process and all its descendants (fire-and-forget).
|
|
470
|
+
*
|
|
471
|
+
* Sends the requested signal but does NOT wait for processes to exit.
|
|
472
|
+
* Use `killProcessTreeGraceful` when cleanup handlers must run.
|
|
473
|
+
*/
|
|
474
|
+
export declare function killProcessTree(rootPid: number, signal?: string | number | undefined | null): void
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Kill a process tree gracefully: signal → wait → SIGKILL.
|
|
478
|
+
*
|
|
479
|
+
* Signals leaf processes first, waits for them to exit, then signals
|
|
480
|
+
* their parents (now leaves). Repeats until the tree is empty or the
|
|
481
|
+
* grace period expires, then force-kills survivors.
|
|
482
|
+
*/
|
|
483
|
+
export declare function killProcessTreeGraceful(rootPid: number, signal?: string | number | undefined | null, gracePeriodMs?: number | undefined | null): Promise<void>
|
|
484
|
+
|
|
468
485
|
export declare function logDebug(message: string): void
|
|
469
486
|
|
|
470
487
|
/** Combined metadata for groups and processes */
|
|
@@ -620,6 +620,8 @@ module.exports.installNxConsoleForEditor = nativeBinding.installNxConsoleForEdit
|
|
|
620
620
|
module.exports.IS_WASM = nativeBinding.IS_WASM
|
|
621
621
|
module.exports.isAiAgent = nativeBinding.isAiAgent
|
|
622
622
|
module.exports.isEditorInstalled = nativeBinding.isEditorInstalled
|
|
623
|
+
module.exports.killProcessTree = nativeBinding.killProcessTree
|
|
624
|
+
module.exports.killProcessTreeGraceful = nativeBinding.killProcessTreeGraceful
|
|
623
625
|
module.exports.logDebug = nativeBinding.logDebug
|
|
624
626
|
module.exports.parseTaskStatus = nativeBinding.parseTaskStatus
|
|
625
627
|
module.exports.remove = nativeBinding.remove
|
|
Binary file
|
|
Binary file
|
|
@@ -37,6 +37,6 @@ export declare class ForkedProcessTaskRunner {
|
|
|
37
37
|
private forkProcessWithPrefixAndNotTTY;
|
|
38
38
|
private forkProcessDirectOutputCapture;
|
|
39
39
|
private writeTerminalOutput;
|
|
40
|
-
cleanup(signal?: NodeJS.Signals): void
|
|
40
|
+
cleanup(signal?: NodeJS.Signals): Promise<void>;
|
|
41
41
|
private setupProcessEventListeners;
|
|
42
42
|
}
|
|
@@ -264,10 +264,8 @@ class ForkedProcessTaskRunner {
|
|
|
264
264
|
writeTerminalOutput(outputPath, content) {
|
|
265
265
|
(0, fs_1.writeFileSync)(outputPath, content);
|
|
266
266
|
}
|
|
267
|
-
cleanup(signal) {
|
|
268
|
-
this.processes.
|
|
269
|
-
p.kill(signal);
|
|
270
|
-
});
|
|
267
|
+
async cleanup(signal) {
|
|
268
|
+
await Promise.all([...this.processes].map((p) => p.kill(signal)));
|
|
271
269
|
this.cleanUpBatchProcesses();
|
|
272
270
|
}
|
|
273
271
|
setupProcessEventListeners() {
|
|
@@ -283,12 +281,27 @@ class ForkedProcessTaskRunner {
|
|
|
283
281
|
};
|
|
284
282
|
// When the nx process gets a message, it will be sent into the task's process
|
|
285
283
|
process.on('message', messageHandler);
|
|
286
|
-
// Terminate any task processes on exit
|
|
284
|
+
// Terminate any task processes on exit (sync, last resort).
|
|
285
|
+
// cleanup() is async but the initial signal dispatch is synchronous
|
|
286
|
+
// (killProcessTreeGraceful snapshots and signals before the async
|
|
287
|
+
// grace period). The grace period won't complete here, but each
|
|
288
|
+
// child also has its own sync exit handler as a final fallback.
|
|
287
289
|
process.once('exit', () => {
|
|
288
290
|
this.cleanup();
|
|
289
291
|
process.off('message', messageHandler);
|
|
290
292
|
});
|
|
291
|
-
|
|
293
|
+
process.once('SIGINT', () => {
|
|
294
|
+
this.cleanup('SIGTERM').finally(() => {
|
|
295
|
+
process.off('message', messageHandler);
|
|
296
|
+
// No process.exit() here — the orchestrator's setupSignalHandlers()
|
|
297
|
+
// owns the exit decision for the direct path, and in the forked path
|
|
298
|
+
// the cleanup above is a no-op (0 processes).
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
// SIGTERM/SIGHUP are NOT handled here. The orchestrator's
|
|
302
|
+
// setupSignalHandlers() handles them and calls FPTR.cleanup()
|
|
303
|
+
// as part of its own cleanup sequence. Using process.once() here
|
|
304
|
+
// would consume the event before the orchestrator sees it.
|
|
292
305
|
}
|
|
293
306
|
}
|
|
294
307
|
exports.ForkedProcessTaskRunner = ForkedProcessTaskRunner;
|
|
@@ -45,7 +45,7 @@ export declare class PseudoTtyProcess implements RunningTask {
|
|
|
45
45
|
onExit(callback: (code: number, terminalOutput: string) => void): void;
|
|
46
46
|
onOutput(callback: (message: string) => void): void;
|
|
47
47
|
getPid(): number | undefined;
|
|
48
|
-
kill(s?: NodeJS.Signals): void
|
|
48
|
+
kill(s?: NodeJS.Signals): Promise<void>;
|
|
49
49
|
getParserAndWriter(): import("../native").ExternalObject<[import("../native").ParserArc, import("../native").WriterArc]>;
|
|
50
50
|
}
|
|
51
51
|
export declare class PseudoTtyProcessWithSend extends PseudoTtyProcess {
|
|
@@ -41,9 +41,14 @@ class PseudoTerminal {
|
|
|
41
41
|
this.initialized = true;
|
|
42
42
|
}
|
|
43
43
|
shutdown(code) {
|
|
44
|
+
// Called from process.on('exit') — must be synchronous/best-effort.
|
|
45
|
+
// Use fire-and-forget killProcessTree, not the async graceful variant.
|
|
44
46
|
for (const cp of this.childProcesses) {
|
|
45
47
|
try {
|
|
46
|
-
cp.
|
|
48
|
+
const pid = cp.getPid();
|
|
49
|
+
if (pid) {
|
|
50
|
+
(0, native_1.killProcessTree)(pid, (0, exit_codes_1.codeToSignal)(code));
|
|
51
|
+
}
|
|
47
52
|
}
|
|
48
53
|
catch { }
|
|
49
54
|
}
|
|
@@ -110,17 +115,24 @@ class PseudoTtyProcess {
|
|
|
110
115
|
getPid() {
|
|
111
116
|
return this.childProcess.getPid();
|
|
112
117
|
}
|
|
113
|
-
kill(s) {
|
|
118
|
+
async kill(s) {
|
|
114
119
|
if (this.isAlive) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
120
|
+
this.isAlive = false;
|
|
121
|
+
const pid = this.childProcess.getPid();
|
|
122
|
+
// Gracefully kill the entire process tree. This snapshots the tree
|
|
123
|
+
// BEFORE sending signals, so even if the root exits quickly from
|
|
124
|
+
// the signal, all descendants are already tracked and will be
|
|
125
|
+
// cleaned up (including any reparented to init/PID 1).
|
|
126
|
+
if (pid) {
|
|
127
|
+
await (0, native_1.killProcessTreeGraceful)(pid, s || 'SIGTERM');
|
|
121
128
|
}
|
|
122
|
-
|
|
123
|
-
|
|
129
|
+
else {
|
|
130
|
+
try {
|
|
131
|
+
this.childProcess.kill(s || 'SIGTERM');
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// child may have already exited
|
|
135
|
+
}
|
|
124
136
|
}
|
|
125
137
|
}
|
|
126
138
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BatchProcess = void 0;
|
|
4
|
-
const
|
|
5
|
-
const tree_kill_1 = tslib_1.__importDefault(require("tree-kill"));
|
|
4
|
+
const native_1 = require("../../native");
|
|
6
5
|
const exit_codes_1 = require("../../utils/exit-codes");
|
|
7
6
|
const batch_messages_1 = require("../batch/batch-messages");
|
|
8
7
|
class BatchProcess {
|
|
@@ -103,10 +102,9 @@ class BatchProcess {
|
|
|
103
102
|
}
|
|
104
103
|
kill(signal) {
|
|
105
104
|
if (this.childProcess?.pid) {
|
|
106
|
-
(0,
|
|
107
|
-
// Ignore errors - process may have already exited
|
|
108
|
-
});
|
|
105
|
+
return (0, native_1.killProcessTreeGraceful)(this.childProcess.pid, signal);
|
|
109
106
|
}
|
|
107
|
+
return Promise.resolve();
|
|
110
108
|
}
|
|
111
109
|
}
|
|
112
110
|
exports.BatchProcess = BatchProcess;
|
|
@@ -18,7 +18,7 @@ export declare class NodeChildProcessWithNonDirectOutput implements RunningTask
|
|
|
18
18
|
terminalOutput: string;
|
|
19
19
|
}>;
|
|
20
20
|
send(message: Serializable): void;
|
|
21
|
-
kill(signal?: NodeJS.Signals): void
|
|
21
|
+
kill(signal?: NodeJS.Signals): Promise<void>;
|
|
22
22
|
}
|
|
23
23
|
export declare class NodeChildProcessWithDirectOutput implements RunningTask {
|
|
24
24
|
private childProcess;
|
|
@@ -36,5 +36,5 @@ export declare class NodeChildProcessWithDirectOutput implements RunningTask {
|
|
|
36
36
|
}>;
|
|
37
37
|
waitForExit(): Promise<void>;
|
|
38
38
|
getTerminalOutput(): string;
|
|
39
|
-
kill(signal?: NodeJS.Signals): void
|
|
39
|
+
kill(signal?: NodeJS.Signals): Promise<void>;
|
|
40
40
|
}
|
|
@@ -5,7 +5,7 @@ const tslib_1 = require("tslib");
|
|
|
5
5
|
const pc = tslib_1.__importStar(require("picocolors"));
|
|
6
6
|
const fs_1 = require("fs");
|
|
7
7
|
const stream_1 = require("stream");
|
|
8
|
-
const
|
|
8
|
+
const native_1 = require("../../native");
|
|
9
9
|
const exit_codes_1 = require("../../utils/exit-codes");
|
|
10
10
|
const output_prefix_1 = require("./output-prefix");
|
|
11
11
|
class NodeChildProcessWithNonDirectOutput {
|
|
@@ -97,10 +97,9 @@ class NodeChildProcessWithNonDirectOutput {
|
|
|
97
97
|
}
|
|
98
98
|
kill(signal) {
|
|
99
99
|
if (this.childProcess?.pid) {
|
|
100
|
-
(0,
|
|
101
|
-
// Ignore errors - process may have already exited
|
|
102
|
-
});
|
|
100
|
+
return (0, native_1.killProcessTreeGraceful)(this.childProcess.pid, signal);
|
|
103
101
|
}
|
|
102
|
+
return Promise.resolve();
|
|
104
103
|
}
|
|
105
104
|
}
|
|
106
105
|
exports.NodeChildProcessWithNonDirectOutput = NodeChildProcessWithNonDirectOutput;
|
|
@@ -168,10 +167,9 @@ class NodeChildProcessWithDirectOutput {
|
|
|
168
167
|
}
|
|
169
168
|
kill(signal) {
|
|
170
169
|
if (this.childProcess?.pid) {
|
|
171
|
-
(0,
|
|
172
|
-
// Ignore errors - process may have already exited
|
|
173
|
-
});
|
|
170
|
+
return (0, native_1.killProcessTreeGraceful)(this.childProcess.pid, signal);
|
|
174
171
|
}
|
|
172
|
+
return Promise.resolve();
|
|
175
173
|
}
|
|
176
174
|
}
|
|
177
175
|
exports.NodeChildProcessWithDirectOutput = NodeChildProcessWithDirectOutput;
|
|
@@ -166,6 +166,7 @@ export declare class TaskOrchestrator {
|
|
|
166
166
|
private shouldCopyOutputsFromCacheBatch;
|
|
167
167
|
private recordOutputsHashBatch;
|
|
168
168
|
private handleContinuousTaskExit;
|
|
169
|
+
private isContinuousTaskNeeded;
|
|
169
170
|
private completeContinuousTask;
|
|
170
171
|
private cleanup;
|
|
171
172
|
private performCleanup;
|
|
@@ -57,7 +57,12 @@ class TaskOrchestrator {
|
|
|
57
57
|
// region internal state
|
|
58
58
|
this.batchEnv = (0, task_env_1.getEnvVariablesForBatchProcess)(this.options.skipNxCache, this.options.captureStderr);
|
|
59
59
|
this.reverseTaskDeps = (0, utils_1.calculateReverseDeps)(this.taskGraph);
|
|
60
|
-
|
|
60
|
+
// `nx:noop` initiating tasks exit instantly via the fast-path in
|
|
61
|
+
// `spawnProcess`. If we treat the noop itself as the keep-alive anchor for
|
|
62
|
+
// its continuous dependencies, `cleanUpUnneededContinuousTasks` kills those
|
|
63
|
+
// children the moment the noop finishes. Expand through noops so the
|
|
64
|
+
// underlying real tasks become the anchors.
|
|
65
|
+
this.initializingTaskIds = (0, utils_1.expandInitiatingTasksThroughNoop)(this.initiatingTasks, this.taskGraph, this.projectGraph);
|
|
61
66
|
this.processedTasks = new Map();
|
|
62
67
|
this.completedTasks = new Map();
|
|
63
68
|
this.waitingForTasks = [];
|
|
@@ -1071,11 +1076,21 @@ class TaskOrchestrator {
|
|
|
1071
1076
|
const reason = stoppingReason === 'fulfilled' ? 'fulfilled' : 'interrupted';
|
|
1072
1077
|
await this.completeContinuousTask(task, groupId, ownsRunningTasksService, reason);
|
|
1073
1078
|
}
|
|
1079
|
+
else if (!this.isContinuousTaskNeeded(task.id)) {
|
|
1080
|
+
// No remaining tasks depend on this — the task was about to be
|
|
1081
|
+
// killed by cleanUpUnneededContinuousTasks anyway.
|
|
1082
|
+
await this.completeContinuousTask(task, groupId, ownsRunningTasksService, 'fulfilled');
|
|
1083
|
+
}
|
|
1074
1084
|
else {
|
|
1075
1085
|
console.error(`Task "${task.id}" is continuous but exited with code ${code}`);
|
|
1076
1086
|
await this.completeContinuousTask(task, groupId, ownsRunningTasksService, 'crashed');
|
|
1077
1087
|
}
|
|
1078
1088
|
}
|
|
1089
|
+
isContinuousTaskNeeded(taskId) {
|
|
1090
|
+
return this.tasksSchedule
|
|
1091
|
+
.getIncompleteTasks()
|
|
1092
|
+
.some((t) => this.taskGraph.continuousDependencies[t.id]?.includes(taskId));
|
|
1093
|
+
}
|
|
1079
1094
|
async completeContinuousTask(task, groupId, ownsRunningTasksService, reason) {
|
|
1080
1095
|
if (this.completedTasks.has(task.id))
|
|
1081
1096
|
return;
|
|
@@ -1129,9 +1144,11 @@ class TaskOrchestrator {
|
|
|
1129
1144
|
continue;
|
|
1130
1145
|
await this.completeContinuousTask(task, groupId, ownsRunningTasksService, reason);
|
|
1131
1146
|
}
|
|
1132
|
-
// Kill all processes
|
|
1133
|
-
this.forkedProcessTaskRunner.cleanup();
|
|
1147
|
+
// Kill all processes — await forked runner cleanup for graceful shutdown
|
|
1148
|
+
const forkedCleanup = this.forkedProcessTaskRunner.cleanup();
|
|
1149
|
+
const continuousTaskIds = new Set(continuousSnapshot.map(([id]) => id));
|
|
1134
1150
|
await Promise.all([
|
|
1151
|
+
forkedCleanup,
|
|
1135
1152
|
...continuousSnapshot.map(async ([taskId, { runningTask }]) => {
|
|
1136
1153
|
try {
|
|
1137
1154
|
await runningTask.kill();
|
|
@@ -1148,7 +1165,10 @@ class TaskOrchestrator {
|
|
|
1148
1165
|
console.error(`Unable to terminate ${taskId}\nError:`, e);
|
|
1149
1166
|
}
|
|
1150
1167
|
}),
|
|
1151
|
-
|
|
1168
|
+
// Skip tasks already killed via continuousSnapshot to avoid duplicate signals
|
|
1169
|
+
...Array.from(this.runningRunCommandsTasks)
|
|
1170
|
+
.filter(([taskId]) => !continuousTaskIds.has(taskId))
|
|
1171
|
+
.map(async ([taskId, t]) => {
|
|
1152
1172
|
try {
|
|
1153
1173
|
await t.kill();
|
|
1154
1174
|
}
|
|
@@ -1163,19 +1183,26 @@ class TaskOrchestrator {
|
|
|
1163
1183
|
await Promise.all(this.discreteTaskExitHandled.values());
|
|
1164
1184
|
}
|
|
1165
1185
|
setupSignalHandlers() {
|
|
1166
|
-
process.
|
|
1186
|
+
// Use process.on (not once) so the handler stays registered and absorbs
|
|
1187
|
+
// re-raised signals from signal-exit. Without this, signal-exit's handler
|
|
1188
|
+
// sees no remaining listeners after our once-handler auto-removes, and
|
|
1189
|
+
// re-raises the signal — killing the process before async cleanup completes.
|
|
1190
|
+
// The cleanup() idempotency guard (cleanupPromise) prevents double execution.
|
|
1191
|
+
const handleSignal = (signal) => {
|
|
1192
|
+
if (this.stopRequested)
|
|
1193
|
+
return;
|
|
1167
1194
|
this.stopRequested = true;
|
|
1168
1195
|
if (!this.tuiEnabled) {
|
|
1169
1196
|
// Synchronously remove DB entries before async cleanup to prevent
|
|
1170
1197
|
// new nx processes from seeing stale "Waiting for ..." messages.
|
|
1171
|
-
// This replicates the cleanup that process.exit() + Rust Drop
|
|
1172
|
-
// previously provided.
|
|
1173
1198
|
for (const [taskId, { ownsRunningTasksService }] of this
|
|
1174
1199
|
.runningContinuousTasks) {
|
|
1175
1200
|
if (ownsRunningTasksService) {
|
|
1176
1201
|
this.runningTasksService?.removeRunningTask(taskId);
|
|
1177
1202
|
}
|
|
1178
1203
|
}
|
|
1204
|
+
}
|
|
1205
|
+
if (signal === 'SIGINT' && !this.tuiEnabled) {
|
|
1179
1206
|
// Silence output — pnpm (and similar wrappers) may exit before nx
|
|
1180
1207
|
// finishes cleanup, returning the shell prompt. Any output after
|
|
1181
1208
|
// that point would appear after the prompt.
|
|
@@ -1192,26 +1219,13 @@ class TaskOrchestrator {
|
|
|
1192
1219
|
this.resolveStopPromise();
|
|
1193
1220
|
}
|
|
1194
1221
|
else {
|
|
1195
|
-
process.exit((0, exit_codes_1.signalToCode)(
|
|
1196
|
-
}
|
|
1197
|
-
});
|
|
1198
|
-
});
|
|
1199
|
-
process.once('SIGTERM', () => {
|
|
1200
|
-
this.stopRequested = true;
|
|
1201
|
-
this.cleanup().finally(() => {
|
|
1202
|
-
if (this.resolveStopPromise) {
|
|
1203
|
-
this.resolveStopPromise();
|
|
1222
|
+
process.exit((0, exit_codes_1.signalToCode)(signal));
|
|
1204
1223
|
}
|
|
1205
1224
|
});
|
|
1206
|
-
}
|
|
1207
|
-
process.
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
if (this.resolveStopPromise) {
|
|
1211
|
-
this.resolveStopPromise();
|
|
1212
|
-
}
|
|
1213
|
-
});
|
|
1214
|
-
});
|
|
1225
|
+
};
|
|
1226
|
+
process.on('SIGINT', () => handleSignal('SIGINT'));
|
|
1227
|
+
process.on('SIGTERM', () => handleSignal('SIGTERM'));
|
|
1228
|
+
process.on('SIGHUP', () => handleSignal('SIGHUP'));
|
|
1215
1229
|
}
|
|
1216
1230
|
cleanUpUnneededContinuousTasks() {
|
|
1217
1231
|
const incompleteTasks = this.tasksSchedule.getIncompleteTasks();
|
|
@@ -31,6 +31,17 @@ export declare function getOutputsForTargetAndConfiguration(target: Task['target
|
|
|
31
31
|
export declare function interpolate(template: string, data: any): string;
|
|
32
32
|
export declare function getTargetConfigurationForTask(task: Task, projectGraph: ProjectGraph): TargetConfiguration | undefined;
|
|
33
33
|
export declare function getExecutorNameForTask(task: Task, projectGraph: ProjectGraph): string;
|
|
34
|
+
/**
|
|
35
|
+
* Expand a set of initiating task IDs by walking through any `nx:noop` tasks
|
|
36
|
+
* and replacing them with their direct dependencies + continuous dependencies.
|
|
37
|
+
* Non-noop tasks are kept as-is; cycles are safe.
|
|
38
|
+
*
|
|
39
|
+
* An `nx:noop` executor returns immediately, so if it is the only thing
|
|
40
|
+
* anchoring a continuous child, the child gets killed by
|
|
41
|
+
* `cleanUpUnneededContinuousTasks` the moment the noop completes. Treating the
|
|
42
|
+
* noop's dependencies as the real anchors preserves the intended orchestration.
|
|
43
|
+
*/
|
|
44
|
+
export declare function expandInitiatingTasksThroughNoop(initiatingTasks: Task[], taskGraph: TaskGraph, projectGraph: ProjectGraph): Set<string>;
|
|
34
45
|
export declare function getExecutorForTask(task: Task, projects: Record<string, ProjectConfiguration>): ExecutorConfig & {
|
|
35
46
|
isNgCompat: boolean;
|
|
36
47
|
isNxExecutor: boolean;
|
|
@@ -14,6 +14,7 @@ exports.getOutputsForTargetAndConfiguration = getOutputsForTargetAndConfiguratio
|
|
|
14
14
|
exports.interpolate = interpolate;
|
|
15
15
|
exports.getTargetConfigurationForTask = getTargetConfigurationForTask;
|
|
16
16
|
exports.getExecutorNameForTask = getExecutorNameForTask;
|
|
17
|
+
exports.expandInitiatingTasksThroughNoop = expandInitiatingTasksThroughNoop;
|
|
17
18
|
exports.getExecutorForTask = getExecutorForTask;
|
|
18
19
|
exports.getCustomHasher = getCustomHasher;
|
|
19
20
|
exports.removeTasksFromTaskGraph = removeTasksFromTaskGraph;
|
|
@@ -291,6 +292,42 @@ function getTargetConfigurationForTask(task, projectGraph) {
|
|
|
291
292
|
function getExecutorNameForTask(task, projectGraph) {
|
|
292
293
|
return getTargetConfigurationForTask(task, projectGraph)?.executor;
|
|
293
294
|
}
|
|
295
|
+
/**
|
|
296
|
+
* Expand a set of initiating task IDs by walking through any `nx:noop` tasks
|
|
297
|
+
* and replacing them with their direct dependencies + continuous dependencies.
|
|
298
|
+
* Non-noop tasks are kept as-is; cycles are safe.
|
|
299
|
+
*
|
|
300
|
+
* An `nx:noop` executor returns immediately, so if it is the only thing
|
|
301
|
+
* anchoring a continuous child, the child gets killed by
|
|
302
|
+
* `cleanUpUnneededContinuousTasks` the moment the noop completes. Treating the
|
|
303
|
+
* noop's dependencies as the real anchors preserves the intended orchestration.
|
|
304
|
+
*/
|
|
305
|
+
function expandInitiatingTasksThroughNoop(initiatingTasks, taskGraph, projectGraph) {
|
|
306
|
+
const expanded = new Set();
|
|
307
|
+
const visited = new Set();
|
|
308
|
+
const queue = initiatingTasks.map((t) => t.id);
|
|
309
|
+
while (queue.length > 0) {
|
|
310
|
+
const taskId = queue.shift();
|
|
311
|
+
if (visited.has(taskId))
|
|
312
|
+
continue;
|
|
313
|
+
visited.add(taskId);
|
|
314
|
+
const task = taskGraph.tasks[taskId];
|
|
315
|
+
if (!task)
|
|
316
|
+
continue;
|
|
317
|
+
if (getExecutorNameForTask(task, projectGraph) === 'nx:noop') {
|
|
318
|
+
for (const dep of taskGraph.dependencies[taskId] ?? []) {
|
|
319
|
+
queue.push(dep);
|
|
320
|
+
}
|
|
321
|
+
for (const dep of taskGraph.continuousDependencies[taskId] ?? []) {
|
|
322
|
+
queue.push(dep);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
expanded.add(taskId);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return expanded;
|
|
330
|
+
}
|
|
294
331
|
function getExecutorForTask(task, projects) {
|
|
295
332
|
const executor = projects[task.target.project]?.targets?.[task.target.target]?.executor;
|
|
296
333
|
const [nodeModule, executorName] = (0, executor_utils_1.parseExecutor)(executor);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nx",
|
|
3
|
-
"version": "23.0.0-
|
|
3
|
+
"version": "23.0.0-pr.33655.cdc3e72",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.",
|
|
@@ -146,7 +146,6 @@
|
|
|
146
146
|
"supports-color": "7.2.0",
|
|
147
147
|
"tar-stream": "2.2.0",
|
|
148
148
|
"tmp": "0.2.4",
|
|
149
|
-
"tree-kill": "1.2.2",
|
|
150
149
|
"tsconfig-paths": "4.2.0",
|
|
151
150
|
"tslib": "2.8.1",
|
|
152
151
|
"util-deprecate": "1.0.2",
|
|
@@ -171,16 +170,16 @@
|
|
|
171
170
|
}
|
|
172
171
|
},
|
|
173
172
|
"optionalDependencies": {
|
|
174
|
-
"@nx/nx-darwin-arm64": "23.0.0-
|
|
175
|
-
"@nx/nx-darwin-x64": "23.0.0-
|
|
176
|
-
"@nx/nx-freebsd-x64": "23.0.0-
|
|
177
|
-
"@nx/nx-linux-arm-gnueabihf": "23.0.0-
|
|
178
|
-
"@nx/nx-linux-arm64-gnu": "23.0.0-
|
|
179
|
-
"@nx/nx-linux-arm64-musl": "23.0.0-
|
|
180
|
-
"@nx/nx-linux-x64-gnu": "23.0.0-
|
|
181
|
-
"@nx/nx-linux-x64-musl": "23.0.0-
|
|
182
|
-
"@nx/nx-win32-arm64-msvc": "23.0.0-
|
|
183
|
-
"@nx/nx-win32-x64-msvc": "23.0.0-
|
|
173
|
+
"@nx/nx-darwin-arm64": "23.0.0-pr.33655.cdc3e72",
|
|
174
|
+
"@nx/nx-darwin-x64": "23.0.0-pr.33655.cdc3e72",
|
|
175
|
+
"@nx/nx-freebsd-x64": "23.0.0-pr.33655.cdc3e72",
|
|
176
|
+
"@nx/nx-linux-arm-gnueabihf": "23.0.0-pr.33655.cdc3e72",
|
|
177
|
+
"@nx/nx-linux-arm64-gnu": "23.0.0-pr.33655.cdc3e72",
|
|
178
|
+
"@nx/nx-linux-arm64-musl": "23.0.0-pr.33655.cdc3e72",
|
|
179
|
+
"@nx/nx-linux-x64-gnu": "23.0.0-pr.33655.cdc3e72",
|
|
180
|
+
"@nx/nx-linux-x64-musl": "23.0.0-pr.33655.cdc3e72",
|
|
181
|
+
"@nx/nx-win32-arm64-msvc": "23.0.0-pr.33655.cdc3e72",
|
|
182
|
+
"@nx/nx-win32-x64-msvc": "23.0.0-pr.33655.cdc3e72"
|
|
184
183
|
},
|
|
185
184
|
"nx-migrations": {
|
|
186
185
|
"migrations": "./migrations.json",
|