nx 21.0.0-canary.20250429-cf4a1f3 → 21.0.0-canary.20250501-8f50358
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/migrations.json +16 -1
- package/package.json +11 -11
- package/release/changelog-renderer/index.d.ts +7 -7
- package/release/changelog-renderer/index.js +12 -31
- package/schemas/nx-schema.json +8 -3
- package/src/command-line/migrate/migrate-ui-api.d.ts +2 -1
- package/src/command-line/migrate/migrate-ui-api.js +4 -3
- package/src/command-line/migrate/migrate.d.ts +12 -6
- package/src/command-line/migrate/migrate.js +31 -9
- package/src/command-line/release/changelog.d.ts +3 -2
- package/src/command-line/release/changelog.js +57 -70
- package/src/command-line/release/command-object.d.ts +1 -1
- package/src/command-line/release/config/config.d.ts +8 -1
- package/src/command-line/release/config/config.js +18 -11
- package/src/command-line/release/release.js +30 -18
- package/src/command-line/release/utils/git.d.ts +1 -0
- package/src/command-line/release/utils/git.js +27 -8
- package/src/command-line/release/utils/remote-release-clients/github.d.ts +57 -0
- package/src/command-line/release/utils/remote-release-clients/github.js +309 -0
- package/src/command-line/release/utils/remote-release-clients/gitlab.d.ts +62 -0
- package/src/command-line/release/utils/remote-release-clients/gitlab.js +271 -0
- package/src/command-line/release/utils/remote-release-clients/remote-release-client.d.ts +111 -0
- package/src/command-line/release/utils/remote-release-clients/remote-release-client.js +136 -0
- package/src/command-line/repair/repair.js +8 -2
- package/src/command-line/report/report.js +1 -1
- package/src/command-line/yargs-utils/shared-options.d.ts +1 -1
- package/src/command-line/yargs-utils/shared-options.js +22 -3
- package/src/config/misc-interfaces.d.ts +9 -1
- package/src/config/nx-json.d.ts +8 -5
- package/src/core/graph/main.js +1 -1
- package/src/core/graph/styles.css +1 -1
- package/src/devkit-exports.d.ts +1 -1
- package/src/migrations/update-21-0-0/release-changelog-config-changes.d.ts +2 -0
- package/src/migrations/update-21-0-0/release-changelog-config-changes.js +38 -0
- package/src/migrations/update-21-0-0/remove-custom-tasks-runner.d.ts +2 -0
- package/src/migrations/update-21-0-0/remove-custom-tasks-runner.js +38 -0
- package/src/migrations/update-21-0-0/remove-legacy-cache.d.ts +2 -0
- package/src/migrations/update-21-0-0/remove-legacy-cache.js +17 -0
- package/src/native/index.d.ts +6 -1
- package/src/native/native-bindings.js +1 -0
- package/src/native/native-file-cache-location.js +2 -1
- package/src/native/nx.wasm32-wasi.wasm +0 -0
- package/src/project-graph/plugins/get-plugins.js +19 -14
- package/src/tasks-runner/batch/run-batch.js +1 -1
- package/src/tasks-runner/cache.d.ts +1 -2
- package/src/tasks-runner/cache.js +2 -18
- package/src/tasks-runner/is-tui-enabled.d.ts +16 -1
- package/src/tasks-runner/is-tui-enabled.js +40 -28
- package/src/tasks-runner/life-cycles/tui-summary-life-cycle.js +8 -7
- package/src/tasks-runner/pseudo-terminal.d.ts +1 -0
- package/src/tasks-runner/pseudo-terminal.js +11 -1
- package/src/tasks-runner/run-command.js +5 -27
- package/src/tasks-runner/running-tasks/node-child-process.d.ts +1 -0
- package/src/tasks-runner/running-tasks/node-child-process.js +7 -0
- package/src/tasks-runner/task-graph-utils.d.ts +3 -0
- package/src/tasks-runner/task-graph-utils.js +31 -2
- package/src/tasks-runner/task-orchestrator.js +16 -4
- package/src/utils/is-ci.d.ts +1 -1
- package/src/utils/is-ci.js +4 -1
- package/src/utils/package-manager.d.ts +1 -0
- package/src/utils/package-manager.js +29 -16
- package/src/command-line/release/utils/github.d.ts +0 -32
- package/src/command-line/release/utils/github.js +0 -326
@@ -1,48 +1,60 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
exports.isTuiEnabled = isTuiEnabled;
|
4
|
-
|
4
|
+
exports.shouldUseTui = shouldUseTui;
|
5
|
+
const native_1 = require("../native");
|
5
6
|
const is_ci_1 = require("../utils/is-ci");
|
6
7
|
let tuiEnabled = undefined;
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
/**
|
9
|
+
* @returns If tui is enabled
|
10
|
+
*/
|
11
|
+
function isTuiEnabled() {
|
12
|
+
return process.env.NX_TUI === 'true';
|
13
|
+
}
|
14
|
+
/**
|
15
|
+
* Determines if the TUI should be enabled for the current environment.
|
16
|
+
*
|
17
|
+
* **Note:** This function should almost never be called directly. Instead, use the `isTuiEnabled` function.
|
18
|
+
*
|
19
|
+
* @param nxJson `nx.json`
|
20
|
+
* @param nxArgs CLI Flags passed into Nx
|
21
|
+
* @param skipCapabilityCheck Mainly used for unit tests.
|
22
|
+
* @returns `true` if the TUI should be enabled, `false` otherwise.
|
23
|
+
*/
|
24
|
+
function shouldUseTui(nxJson, nxArgs, skipCapabilityCheck = process.env.NX_TUI_SKIP_CAPABILITY_CHECK === 'true') {
|
11
25
|
// If the current terminal/environment is not capable of displaying the TUI, we don't run it
|
12
26
|
const isWindows = process.platform === 'win32';
|
13
|
-
const isCapable =
|
27
|
+
const isCapable = skipCapabilityCheck || (process.stderr.isTTY && isUnicodeSupported());
|
14
28
|
if (!isCapable) {
|
15
|
-
|
16
|
-
process.env.NX_TUI = 'false';
|
17
|
-
return tuiEnabled;
|
29
|
+
return false;
|
18
30
|
}
|
19
31
|
// The environment variable takes precedence over the nx.json config
|
20
32
|
if (typeof process.env.NX_TUI === 'string') {
|
21
|
-
|
22
|
-
return tuiEnabled;
|
33
|
+
return process.env.NX_TUI === 'true';
|
23
34
|
}
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
tuiEnabled = false;
|
28
|
-
process.env.NX_TUI = 'false';
|
29
|
-
return tuiEnabled;
|
35
|
+
if (['static', 'stream', 'dynamic-legacy'].includes(nxArgs.outputStyle)) {
|
36
|
+
// If the user has specified a non-TUI output style, we disable the TUI
|
37
|
+
return false;
|
30
38
|
}
|
31
|
-
|
32
|
-
|
33
|
-
|
39
|
+
if (
|
40
|
+
// Interactive TUI doesn't make sense on CI
|
41
|
+
(0, is_ci_1.isCI)() ||
|
42
|
+
// TODO(@JamesHenry): Remove this check once Windows issues are fixed.
|
43
|
+
// Windows is not working well right now, temporarily disable it on Windows even if it has been specified as enabled
|
44
|
+
isWindows ||
|
45
|
+
// WASM needs further testing
|
46
|
+
native_1.IS_WASM) {
|
47
|
+
return false;
|
48
|
+
}
|
49
|
+
if (nxArgs.outputStyle === 'dynamic' || nxArgs.outputStyle === 'tui') {
|
50
|
+
return true;
|
34
51
|
}
|
35
52
|
// Respect user config
|
36
53
|
if (typeof nxJson.tui?.enabled === 'boolean') {
|
37
|
-
|
38
|
-
}
|
39
|
-
else {
|
40
|
-
// Default to enabling the TUI if the system is capable of displaying it
|
41
|
-
tuiEnabled = true;
|
54
|
+
return Boolean(nxJson.tui?.enabled);
|
42
55
|
}
|
43
|
-
//
|
44
|
-
|
45
|
-
return tuiEnabled;
|
56
|
+
// Default to enabling the TUI if the system is capable of displaying it
|
57
|
+
return true;
|
46
58
|
}
|
47
59
|
// Credit to https://github.com/sindresorhus/is-unicode-supported/blob/e0373335038856c63034c8eef6ac43ee3827a601/index.js
|
48
60
|
function isUnicodeSupported() {
|
@@ -20,10 +20,10 @@ function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, args, overrides,
|
|
20
20
|
let totalSuccessfulTasks = 0;
|
21
21
|
let totalFailedTasks = 0;
|
22
22
|
let totalCompletedTasks = 0;
|
23
|
-
let totalStoppedTasks = 0;
|
24
23
|
let timeTakenText;
|
25
24
|
const failedTasks = new Set();
|
26
25
|
const inProgressTasks = new Set();
|
26
|
+
const stoppedTasks = new Set();
|
27
27
|
const tasksToTerminalOutputs = {};
|
28
28
|
const taskIdsInOrderOfCompletion = [];
|
29
29
|
lifeCycle.startTasks = (tasks) => {
|
@@ -37,7 +37,8 @@ function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, args, overrides,
|
|
37
37
|
};
|
38
38
|
lifeCycle.setTaskStatus = (taskId, taskStatus) => {
|
39
39
|
if (taskStatus === 9 /* NativeTaskStatus.Stopped */) {
|
40
|
-
|
40
|
+
stoppedTasks.add(taskId);
|
41
|
+
inProgressTasks.delete(taskId);
|
41
42
|
}
|
42
43
|
};
|
43
44
|
lifeCycle.endTasks = (taskResults) => {
|
@@ -83,7 +84,7 @@ function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, args, overrides,
|
|
83
84
|
};
|
84
85
|
const printRunOneSummary = () => {
|
85
86
|
let lines = [];
|
86
|
-
const failure = totalSuccessfulTasks +
|
87
|
+
const failure = totalSuccessfulTasks + stoppedTasks.size !== totalTasks;
|
87
88
|
// Prints task outputs in the order they were completed
|
88
89
|
// above the summary, since run-one should print all task results.
|
89
90
|
for (const taskId of taskIdsInOrderOfCompletion) {
|
@@ -107,7 +108,7 @@ function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, args, overrides,
|
|
107
108
|
}
|
108
109
|
lines = [output_1.output.colors.green(lines.join(node_os_1.EOL))];
|
109
110
|
}
|
110
|
-
else if (totalCompletedTasks +
|
111
|
+
else if (totalCompletedTasks + stoppedTasks.size === totalTasks) {
|
111
112
|
let text = `Ran target ${output_1.output.bold(targets[0])} for project ${output_1.output.bold(initiatingProject)}`;
|
112
113
|
if (tasks.length > 1) {
|
113
114
|
text += ` and ${output_1.output.bold(tasks.length - 1)} task(s) they depend on`;
|
@@ -129,7 +130,7 @@ function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, args, overrides,
|
|
129
130
|
`${LEFT_PAD}${output_1.output.colors.red(figures.cross)}${SPACER}${totalFailedTasks}${`/${totalCompletedTasks}`} failed`,
|
130
131
|
`${LEFT_PAD}${output_1.output.dim(figures.tick)}${SPACER}${totalSuccessfulTasks}${`/${totalCompletedTasks}`} succeeded ${output_1.output.dim(`[${totalCachedTasks} read from cache]`)}`,
|
131
132
|
...viewLogs,
|
132
|
-
]),
|
133
|
+
].join(node_os_1.EOL)),
|
133
134
|
];
|
134
135
|
}
|
135
136
|
else {
|
@@ -145,7 +146,7 @@ function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, args, overrides,
|
|
145
146
|
const printRunManySummary = () => {
|
146
147
|
console.log('');
|
147
148
|
const lines = [];
|
148
|
-
const failure = totalSuccessfulTasks +
|
149
|
+
const failure = totalSuccessfulTasks + stoppedTasks.size !== totalTasks;
|
149
150
|
for (const taskId of taskIdsInOrderOfCompletion) {
|
150
151
|
const { terminalOutput, taskStatus } = tasksToTerminalOutputs[taskId];
|
151
152
|
if (taskStatus === 'failure') {
|
@@ -157,7 +158,7 @@ function getTuiTerminalSummaryLifeCycle({ projectNames, tasks, args, overrides,
|
|
157
158
|
}
|
158
159
|
}
|
159
160
|
lines.push(...output_1.output.getVerticalSeparatorLines(failure ? 'red' : 'green'));
|
160
|
-
if (totalSuccessfulTasks +
|
161
|
+
if (totalSuccessfulTasks + stoppedTasks.size === totalTasks) {
|
161
162
|
const successSummaryRows = [];
|
162
163
|
const text = `Successfully ran ${(0, formatting_utils_1.formatTargetsAndProjects)(projectNames, targets, tasks)}`;
|
163
164
|
const taskOverridesRows = [];
|
@@ -38,6 +38,7 @@ class PseudoTerminal {
|
|
38
38
|
this.pseudoIPCPath = (0, socket_utils_1.getForkedProcessOsSocketPath)(process.pid.toString() + '-' + id++);
|
39
39
|
this.pseudoIPC = new pseudo_ipc_1.PseudoIPCServer(this.pseudoIPCPath);
|
40
40
|
this.initialized = false;
|
41
|
+
this.childProcesses = new Set();
|
41
42
|
}
|
42
43
|
async init() {
|
43
44
|
if (this.initialized) {
|
@@ -47,18 +48,27 @@ class PseudoTerminal {
|
|
47
48
|
this.initialized = true;
|
48
49
|
}
|
49
50
|
shutdown() {
|
51
|
+
for (const cp of this.childProcesses) {
|
52
|
+
try {
|
53
|
+
cp.kill();
|
54
|
+
}
|
55
|
+
catch { }
|
56
|
+
}
|
50
57
|
if (this.initialized) {
|
51
58
|
this.pseudoIPC.close();
|
52
59
|
}
|
53
60
|
}
|
54
61
|
runCommand(command, { cwd, execArgv, jsEnv, quiet, tty, } = {}) {
|
55
|
-
|
62
|
+
const cp = new PseudoTtyProcess(this.rustPseudoTerminal, this.rustPseudoTerminal.runCommand(command, cwd, jsEnv, execArgv, quiet, tty));
|
63
|
+
this.childProcesses.add(cp);
|
64
|
+
return cp;
|
56
65
|
}
|
57
66
|
async fork(id, script, { cwd, execArgv, jsEnv, quiet, }) {
|
58
67
|
if (!this.initialized) {
|
59
68
|
throw new Error('Call init() before forking processes');
|
60
69
|
}
|
61
70
|
const cp = new PseudoTtyProcessWithSend(this.rustPseudoTerminal, this.rustPseudoTerminal.fork(id, script, this.pseudoIPCPath, cwd, jsEnv, execArgv, quiet), id, this.pseudoIPC);
|
71
|
+
this.childProcesses.add(cp);
|
62
72
|
await this.pseudoIPC.waitForChildReady(id);
|
63
73
|
return cp;
|
64
74
|
}
|
@@ -17,7 +17,6 @@ const create_task_hasher_1 = require("../hasher/create-task-hasher");
|
|
17
17
|
const hash_task_1 = require("../hasher/hash-task");
|
18
18
|
const tasks_execution_hooks_1 = require("../project-graph/plugins/tasks-execution-hooks");
|
19
19
|
const project_graph_1 = require("../project-graph/project-graph");
|
20
|
-
const fileutils_1 = require("../utils/fileutils");
|
21
20
|
const handle_errors_1 = require("../utils/handle-errors");
|
22
21
|
const is_ci_1 = require("../utils/is-ci");
|
23
22
|
const nx_cloud_utils_1 = require("../utils/nx-cloud-utils");
|
@@ -48,7 +47,8 @@ const originalConsoleError = console.error.bind(console);
|
|
48
47
|
async function getTerminalOutputLifeCycle(initiatingProject, initiatingTasks, projectNames, tasks, taskGraph, nxArgs, nxJson, overrides) {
|
49
48
|
const overridesWithoutHidden = { ...overrides };
|
50
49
|
delete overridesWithoutHidden['__overrides_unparsed__'];
|
51
|
-
|
50
|
+
const isRunOne = initiatingProject != null;
|
51
|
+
if ((0, is_tui_enabled_1.isTuiEnabled)()) {
|
52
52
|
const interceptedNxCloudLogs = [];
|
53
53
|
const createPatchedConsoleMethod = (originalMethod) => {
|
54
54
|
return (...args) => {
|
@@ -125,7 +125,7 @@ async function getTerminalOutputLifeCycle(initiatingProject, initiatingTasks, pr
|
|
125
125
|
const lifeCycles = [tsLifeCycle];
|
126
126
|
// Only run the TUI if there are tasks to run
|
127
127
|
if (tasks.length > 0) {
|
128
|
-
appLifeCycle = new AppLifeCycle(tasks, pinnedTasks, nxArgs ?? {}, nxJson.tui ?? {}, titleText);
|
128
|
+
appLifeCycle = new AppLifeCycle(tasks, initiatingTasks.map((t) => t.id), isRunOne ? 0 /* RunMode.RunOne */ : 1 /* RunMode.RunMany */, pinnedTasks, nxArgs ?? {}, nxJson.tui ?? {}, titleText);
|
129
129
|
lifeCycles.unshift(appLifeCycle);
|
130
130
|
/**
|
131
131
|
* Patch stdout.write and stderr.write methods to pass Nx Cloud client logs to the TUI via the lifecycle
|
@@ -206,7 +206,6 @@ async function getTerminalOutputLifeCycle(initiatingProject, initiatingTasks, pr
|
|
206
206
|
};
|
207
207
|
}
|
208
208
|
const { runnerOptions } = getRunner(nxArgs, nxJson);
|
209
|
-
const isRunOne = initiatingProject != null;
|
210
209
|
const useDynamicOutput = shouldUseDynamicLifeCycle(tasks, runnerOptions, nxArgs.outputStyle);
|
211
210
|
if (isRunOne) {
|
212
211
|
if (useDynamicOutput) {
|
@@ -241,6 +240,7 @@ async function getTerminalOutputLifeCycle(initiatingProject, initiatingTasks, pr
|
|
241
240
|
}
|
242
241
|
function createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies, projectNames, nxArgs, overrides, extraOptions) {
|
243
242
|
const taskGraph = (0, create_task_graph_1.createTaskGraph)(projectGraph, extraTargetDependencies, projectNames, nxArgs.targets, nxArgs.configuration, overrides, extraOptions.excludeTaskDependencies);
|
243
|
+
(0, task_graph_utils_1.assertTaskGraphDoesNotContainInvalidTargets)(taskGraph);
|
244
244
|
const cycle = (0, task_graph_utils_1.findCycle)(taskGraph);
|
245
245
|
if (cycle) {
|
246
246
|
if (process.env.NX_IGNORE_CYCLES === 'true' || nxArgs.nxIgnoreCycles) {
|
@@ -712,14 +712,6 @@ function getRunner(nxArgs, nxJson) {
|
|
712
712
|
}
|
713
713
|
const modulePath = getTasksRunnerPath(runner, nxJson);
|
714
714
|
try {
|
715
|
-
if (isCustomRunnerPath(modulePath)) {
|
716
|
-
output_1.output.warn({
|
717
|
-
title: `Custom task runners will be replaced by a new API starting with Nx 21.`,
|
718
|
-
bodyLines: [
|
719
|
-
`For more information, see https://nx.dev/deprecated/custom-tasks-runner`,
|
720
|
-
],
|
721
|
-
});
|
722
|
-
}
|
723
715
|
const tasksRunner = loadTasksRunner(modulePath);
|
724
716
|
return {
|
725
717
|
tasksRunner,
|
@@ -732,18 +724,12 @@ function getRunner(nxArgs, nxJson) {
|
|
732
724
|
}
|
733
725
|
const defaultTasksRunnerPath = require.resolve('./default-tasks-runner');
|
734
726
|
function getTasksRunnerPath(runner, nxJson) {
|
735
|
-
let modulePath = nxJson.tasksRunnerOptions?.[runner]?.runner;
|
736
|
-
if (modulePath) {
|
737
|
-
if ((0, fileutils_1.isRelativePath)(modulePath)) {
|
738
|
-
return (0, node_path_1.join)(workspace_root_1.workspaceRoot, modulePath);
|
739
|
-
}
|
740
|
-
return modulePath;
|
741
|
-
}
|
742
727
|
const isCloudRunner =
|
743
728
|
// No tasksRunnerOptions for given --runner
|
744
729
|
nxJson.nxCloudAccessToken ||
|
745
730
|
// No runner prop in tasks runner options, check if access token is set.
|
746
731
|
nxJson.tasksRunnerOptions?.[runner]?.options?.accessToken ||
|
732
|
+
['nx-cloud', '@nrwl/nx-cloud'].includes(nxJson.tasksRunnerOptions?.[runner]?.runner) ||
|
747
733
|
// Cloud access token specified in env var.
|
748
734
|
process.env.NX_CLOUD_ACCESS_TOKEN ||
|
749
735
|
// Nx Cloud ID specified in nxJson
|
@@ -792,11 +778,3 @@ function getRunnerOptions(runner, nxJson, nxArgs, isCloudDefault) {
|
|
792
778
|
}
|
793
779
|
return result;
|
794
780
|
}
|
795
|
-
function isCustomRunnerPath(modulePath) {
|
796
|
-
return ![
|
797
|
-
'nx-cloud',
|
798
|
-
'@nrwl/nx-cloud',
|
799
|
-
'nx/tasks-runners/default',
|
800
|
-
defaultTasksRunnerPath,
|
801
|
-
].includes(modulePath);
|
802
|
-
}
|
@@ -4,6 +4,7 @@ export declare class NodeChildProcessWithNonDirectOutput implements RunningTask
|
|
4
4
|
private childProcess;
|
5
5
|
private terminalOutput;
|
6
6
|
private exitCallbacks;
|
7
|
+
private exitCode;
|
7
8
|
constructor(childProcess: ChildProcess, { streamOutput, prefix }: {
|
8
9
|
streamOutput: boolean;
|
9
10
|
prefix: string;
|
@@ -35,6 +35,7 @@ class NodeChildProcessWithNonDirectOutput {
|
|
35
35
|
this.childProcess.on('exit', (code, signal) => {
|
36
36
|
if (code === null)
|
37
37
|
code = (0, exit_codes_1.signalToCode)(signal);
|
38
|
+
this.exitCode = code;
|
38
39
|
for (const cb of this.exitCallbacks) {
|
39
40
|
cb(code, this.terminalOutput);
|
40
41
|
}
|
@@ -56,6 +57,12 @@ class NodeChildProcessWithNonDirectOutput {
|
|
56
57
|
this.exitCallbacks.push(cb);
|
57
58
|
}
|
58
59
|
async getResults() {
|
60
|
+
if (typeof this.exitCode === 'number') {
|
61
|
+
return {
|
62
|
+
code: this.exitCode,
|
63
|
+
terminalOutput: this.terminalOutput,
|
64
|
+
};
|
65
|
+
}
|
59
66
|
return new Promise((res) => {
|
60
67
|
this.onExit((code, terminalOutput) => {
|
61
68
|
res({ code, terminalOutput });
|
@@ -6,6 +6,7 @@ import { TaskGraph } from '../config/task-graph';
|
|
6
6
|
*/
|
7
7
|
export declare function findCycle(graph: {
|
8
8
|
dependencies: Record<string, string[]>;
|
9
|
+
continuousDependencies?: Record<string, string[]>;
|
9
10
|
}): string[] | null;
|
10
11
|
/**
|
11
12
|
* This function finds all cycles in the graph.
|
@@ -13,9 +14,11 @@ export declare function findCycle(graph: {
|
|
13
14
|
*/
|
14
15
|
export declare function findCycles(graph: {
|
15
16
|
dependencies: Record<string, string[]>;
|
17
|
+
continuousDependencies?: Record<string, string[]>;
|
16
18
|
}): Set<string> | null;
|
17
19
|
export declare function makeAcyclic(graph: {
|
18
20
|
roots: string[];
|
19
21
|
dependencies: Record<string, string[]>;
|
20
22
|
}): void;
|
21
23
|
export declare function validateNoAtomizedTasks(taskGraph: TaskGraph, projectGraph: ProjectGraph): void;
|
24
|
+
export declare function assertTaskGraphDoesNotContainInvalidTargets(taskGraph: TaskGraph): void;
|
@@ -4,12 +4,16 @@ exports.findCycle = findCycle;
|
|
4
4
|
exports.findCycles = findCycles;
|
5
5
|
exports.makeAcyclic = makeAcyclic;
|
6
6
|
exports.validateNoAtomizedTasks = validateNoAtomizedTasks;
|
7
|
+
exports.assertTaskGraphDoesNotContainInvalidTargets = assertTaskGraphDoesNotContainInvalidTargets;
|
7
8
|
const output_1 = require("../utils/output");
|
8
9
|
function _findCycle(graph, id, visited, path) {
|
9
10
|
if (visited[id])
|
10
11
|
return null;
|
11
12
|
visited[id] = true;
|
12
|
-
for (const d of
|
13
|
+
for (const d of [
|
14
|
+
...graph.dependencies[id],
|
15
|
+
...(graph.continuousDependencies?.[id] ?? []),
|
16
|
+
]) {
|
13
17
|
if (path.includes(d))
|
14
18
|
return [...path, d];
|
15
19
|
const cycle = _findCycle(graph, d, visited, [...path, d]);
|
@@ -57,9 +61,11 @@ function _makeAcyclic(graph, id, visited, path) {
|
|
57
61
|
return;
|
58
62
|
visited[id] = true;
|
59
63
|
const deps = graph.dependencies[id];
|
60
|
-
|
64
|
+
const continuousDeps = graph.continuousDependencies?.[id] ?? [];
|
65
|
+
for (const d of [...deps, ...continuousDeps]) {
|
61
66
|
if (path.includes(d)) {
|
62
67
|
deps.splice(deps.indexOf(d), 1);
|
68
|
+
continuousDeps.splice(continuousDeps.indexOf(d), 1);
|
63
69
|
}
|
64
70
|
else {
|
65
71
|
_makeAcyclic(graph, d, visited, [...path, d]);
|
@@ -109,3 +115,26 @@ function validateNoAtomizedTasks(taskGraph, projectGraph) {
|
|
109
115
|
}
|
110
116
|
process.exit(1);
|
111
117
|
}
|
118
|
+
function assertTaskGraphDoesNotContainInvalidTargets(taskGraph) {
|
119
|
+
const invalidTasks = [];
|
120
|
+
for (const task of Object.values(taskGraph.tasks)) {
|
121
|
+
if (task.parallelism === false &&
|
122
|
+
taskGraph.continuousDependencies[task.id].length > 0) {
|
123
|
+
invalidTasks.push(task);
|
124
|
+
}
|
125
|
+
}
|
126
|
+
if (invalidTasks.length > 0) {
|
127
|
+
throw new NonParallelTaskDependsOnContinuousTasksError(invalidTasks, taskGraph);
|
128
|
+
}
|
129
|
+
}
|
130
|
+
class NonParallelTaskDependsOnContinuousTasksError extends Error {
|
131
|
+
constructor(invalidTasks, taskGraph) {
|
132
|
+
let message = 'The following tasks do not support parallelism but depend on continuous tasks:';
|
133
|
+
for (const task of invalidTasks) {
|
134
|
+
message += `\n - ${task.id} -> ${taskGraph.continuousDependencies[task.id].join(', ')}`;
|
135
|
+
}
|
136
|
+
super(message);
|
137
|
+
this.invalidTasks = invalidTasks;
|
138
|
+
this.name = 'NonParallelTaskDependsOnContinuousTasksError';
|
139
|
+
}
|
140
|
+
}
|
@@ -38,9 +38,11 @@ class TaskOrchestrator {
|
|
38
38
|
this.taskGraphForHashing = taskGraphForHashing;
|
39
39
|
this.taskDetails = (0, hash_task_1.getTaskDetails)();
|
40
40
|
this.cache = (0, cache_1.getCache)(this.options);
|
41
|
-
this.tuiEnabled = (0, is_tui_enabled_1.isTuiEnabled)(
|
41
|
+
this.tuiEnabled = (0, is_tui_enabled_1.isTuiEnabled)();
|
42
42
|
this.forkedProcessTaskRunner = new forked_process_task_runner_1.ForkedProcessTaskRunner(this.options, this.tuiEnabled);
|
43
|
-
this.runningTasksService =
|
43
|
+
this.runningTasksService = !native_1.IS_WASM
|
44
|
+
? new native_1.RunningTasksService((0, db_connection_1.getDbConnection)())
|
45
|
+
: null;
|
44
46
|
this.tasksSchedule = new tasks_schedule_1.TasksSchedule(this.projectGraph, this.taskGraph, this.options);
|
45
47
|
// region internal state
|
46
48
|
this.batchEnv = (0, task_env_1.getEnvVariablesForBatchProcess)(this.options.skipNxCache, this.options.captureStderr);
|
@@ -173,7 +175,7 @@ class TaskOrchestrator {
|
|
173
175
|
// No output files to restore
|
174
176
|
!!outputs.length &&
|
175
177
|
// Remote caches are restored to output dirs when applied and using db cache
|
176
|
-
(!cachedResult.remote || !(0, cache_1.dbCacheEnabled)(
|
178
|
+
(!cachedResult.remote || !(0, cache_1.dbCacheEnabled)()) &&
|
177
179
|
// Output files have not been touched since last run
|
178
180
|
(await this.shouldCopyOutputsFromCache(outputs, task.hash));
|
179
181
|
if (shouldCopyOutputsFromCache) {
|
@@ -194,6 +196,7 @@ class TaskOrchestrator {
|
|
194
196
|
// endregion Applying Cache
|
195
197
|
// region Batch
|
196
198
|
async applyFromCacheOrRunBatch(doNotSkipCache, batch, groupId) {
|
199
|
+
const applyFromCacheOrRunBatchStart = perf_hooks_1.performance.mark('TaskOrchestrator-apply-from-cache-or-run-batch:start');
|
197
200
|
const taskEntries = Object.entries(batch.taskGraph.tasks);
|
198
201
|
const tasks = taskEntries.map(([, task]) => task);
|
199
202
|
// Wait for batch to be processed
|
@@ -219,8 +222,12 @@ class TaskOrchestrator {
|
|
219
222
|
taskGraph: (0, utils_1.removeTasksFromTaskGraph)(batch.taskGraph, tasksCompleted.map(([taskId]) => taskId)),
|
220
223
|
}, groupId);
|
221
224
|
}
|
225
|
+
// Batch is done, mark it as completed
|
226
|
+
const applyFromCacheOrRunBatchEnd = perf_hooks_1.performance.mark('TaskOrchestrator-apply-from-cache-or-run-batch:end');
|
227
|
+
perf_hooks_1.performance.measure('TaskOrchestrator-apply-from-cache-or-run-batch', applyFromCacheOrRunBatchStart.name, applyFromCacheOrRunBatchEnd.name);
|
222
228
|
}
|
223
229
|
async runBatch(batch, env) {
|
230
|
+
const runBatchStart = perf_hooks_1.performance.mark('TaskOrchestrator-run-batch:start');
|
224
231
|
try {
|
225
232
|
const batchProcess = await this.forkedProcessTaskRunner.forkProcessForBatch(batch, this.projectGraph, this.taskGraph, env);
|
226
233
|
const results = await batchProcess.getResults();
|
@@ -242,6 +249,10 @@ class TaskOrchestrator {
|
|
242
249
|
status: 'failure',
|
243
250
|
}));
|
244
251
|
}
|
252
|
+
finally {
|
253
|
+
const runBatchEnd = perf_hooks_1.performance.mark('TaskOrchestrator-run-batch:end');
|
254
|
+
perf_hooks_1.performance.measure('TaskOrchestrator-run-batch', runBatchStart.name, runBatchEnd.name);
|
255
|
+
}
|
245
256
|
}
|
246
257
|
// endregion Batch
|
247
258
|
// region Single Task
|
@@ -413,7 +424,8 @@ class TaskOrchestrator {
|
|
413
424
|
}
|
414
425
|
}
|
415
426
|
async startContinuousTask(task, groupId) {
|
416
|
-
if (this.runningTasksService
|
427
|
+
if (this.runningTasksService &&
|
428
|
+
this.runningTasksService.getRunningTasks([task.id]).length) {
|
417
429
|
await this.preRunSteps([task], { groupId });
|
418
430
|
if (this.tuiEnabled) {
|
419
431
|
this.options.lifeCycle.setTaskStatus(task.id, 8 /* NativeTaskStatus.Shared */);
|
package/src/utils/is-ci.d.ts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export declare function isCI(): boolean;
|
1
|
+
export declare function isCI(): string | boolean;
|
package/src/utils/is-ci.js
CHANGED
@@ -2,7 +2,10 @@
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
exports.isCI = isCI;
|
4
4
|
function isCI() {
|
5
|
-
|
5
|
+
if (process.env.CI === 'false') {
|
6
|
+
return false;
|
7
|
+
}
|
8
|
+
return (process.env.CI ||
|
6
9
|
process.env.TF_BUILD === 'true' ||
|
7
10
|
process.env.GITHUB_ACTIONS === 'true' ||
|
8
11
|
process.env.BUILDKITE === 'true' ||
|
@@ -44,6 +44,7 @@ export declare function getPackageManagerCommand(packageManager?: PackageManager
|
|
44
44
|
* but it can also be passed in explicitly.
|
45
45
|
*/
|
46
46
|
export declare function getPackageManagerVersion(packageManager?: PackageManager, cwd?: string): string;
|
47
|
+
export declare function parseVersionFromPackageManagerField(requestedPackageManager: string, packageManagerFieldValue: string | undefined): null | string;
|
47
48
|
/**
|
48
49
|
* Checks for a project level npmrc file by crawling up the file tree until
|
49
50
|
* hitting a package.json file, as this is how npm finds them as well.
|
@@ -4,6 +4,7 @@ exports.detectPackageManager = detectPackageManager;
|
|
4
4
|
exports.isWorkspacesEnabled = isWorkspacesEnabled;
|
5
5
|
exports.getPackageManagerCommand = getPackageManagerCommand;
|
6
6
|
exports.getPackageManagerVersion = getPackageManagerVersion;
|
7
|
+
exports.parseVersionFromPackageManagerField = parseVersionFromPackageManagerField;
|
7
8
|
exports.findFileInPackageJsonDirectory = findFileInPackageJsonDirectory;
|
8
9
|
exports.modifyYarnRcYmlToFitNewDirectory = modifyYarnRcYmlToFitNewDirectory;
|
9
10
|
exports.modifyYarnRcToFitNewDirectory = modifyYarnRcToFitNewDirectory;
|
@@ -175,30 +176,42 @@ function getPackageManagerCommand(packageManager = detectPackageManager(), root
|
|
175
176
|
*/
|
176
177
|
function getPackageManagerVersion(packageManager = detectPackageManager(), cwd = process.cwd()) {
|
177
178
|
let version;
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
encoding: 'utf-8',
|
182
|
-
windowsHide: true,
|
183
|
-
}).trim();
|
179
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(cwd, 'package.json'))) {
|
180
|
+
const packageManagerEntry = (0, fileutils_1.readJsonFile)((0, path_1.join)(cwd, 'package.json'))?.packageManager;
|
181
|
+
version = parseVersionFromPackageManagerField(packageManager, packageManagerEntry);
|
184
182
|
}
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
version = versionFromPackageJson;
|
193
|
-
}
|
194
|
-
}
|
183
|
+
if (!version) {
|
184
|
+
try {
|
185
|
+
version = (0, child_process_1.execSync)(`${packageManager} --version`, {
|
186
|
+
cwd,
|
187
|
+
encoding: 'utf-8',
|
188
|
+
windowsHide: true,
|
189
|
+
}).trim();
|
195
190
|
}
|
191
|
+
catch { }
|
196
192
|
}
|
197
193
|
if (!version) {
|
198
194
|
throw new Error(`Cannot determine the version of ${packageManager}.`);
|
199
195
|
}
|
200
196
|
return version;
|
201
197
|
}
|
198
|
+
function parseVersionFromPackageManagerField(requestedPackageManager, packageManagerFieldValue) {
|
199
|
+
if (!packageManagerFieldValue)
|
200
|
+
return null;
|
201
|
+
const [packageManagerFromPackageJson, versionFromPackageJson] = packageManagerFieldValue.split('@');
|
202
|
+
if (versionFromPackageJson &&
|
203
|
+
// If it's a URL, it's not a valid range by default, unless users set `COREPACK_ENABLE_UNSAFE_CUSTOM_URLS=1`.
|
204
|
+
// In the unsafe case, there's no way to reliably pare out the version since it could be anything, e.g. http://mydomain.com/bin/yarn.js.
|
205
|
+
// See: https://github.com/nodejs/corepack/blob/2b43f26/sources/corepackUtils.ts#L110-L112
|
206
|
+
!URL.canParse(versionFromPackageJson) &&
|
207
|
+
packageManagerFromPackageJson === requestedPackageManager &&
|
208
|
+
versionFromPackageJson) {
|
209
|
+
// The range could have a validation hash attached, like "3.2.3+sha224.953c8233f7a92884eee2de69a1b92d1f2ec1655e66d08071ba9a02fa".
|
210
|
+
// We just want to parse out the "<major>.<minor>.<patch>". Semver treats "+" as a build, which is not included in the resulting version.
|
211
|
+
return (0, semver_1.parse)(versionFromPackageJson)?.version ?? null;
|
212
|
+
}
|
213
|
+
return null;
|
214
|
+
}
|
202
215
|
/**
|
203
216
|
* Checks for a project level npmrc file by crawling up the file tree until
|
204
217
|
* hitting a package.json file, as this is how npm finds them as well.
|
@@ -1,32 +0,0 @@
|
|
1
|
-
import { NxReleaseChangelogConfiguration } from '../../../config/nx-json';
|
2
|
-
import { Reference } from './git';
|
3
|
-
import { ReleaseVersion } from './shared';
|
4
|
-
export type RepoSlug = `${string}/${string}`;
|
5
|
-
interface GithubRequestConfig {
|
6
|
-
repo: string;
|
7
|
-
hostname: string;
|
8
|
-
apiBaseUrl: string;
|
9
|
-
token: string | null;
|
10
|
-
}
|
11
|
-
interface GithubRelease {
|
12
|
-
id?: string;
|
13
|
-
tag_name: string;
|
14
|
-
target_commitish?: string;
|
15
|
-
name?: string;
|
16
|
-
body?: string;
|
17
|
-
draft?: boolean;
|
18
|
-
prerelease?: boolean;
|
19
|
-
make_latest?: 'legacy' | boolean;
|
20
|
-
}
|
21
|
-
export interface GithubRepoData {
|
22
|
-
hostname: string;
|
23
|
-
slug: RepoSlug;
|
24
|
-
apiBaseUrl: string;
|
25
|
-
}
|
26
|
-
export declare function getGitHubRepoData(remoteName: string, createReleaseConfig: NxReleaseChangelogConfiguration['createRelease']): GithubRepoData | null;
|
27
|
-
export declare function createOrUpdateGithubRelease(createReleaseConfig: NxReleaseChangelogConfiguration['createRelease'], releaseVersion: ReleaseVersion, changelogContents: string, latestCommit: string, { dryRun }: {
|
28
|
-
dryRun: boolean;
|
29
|
-
}): Promise<void>;
|
30
|
-
export declare function getGithubReleaseByTag(config: GithubRequestConfig, tag: string): Promise<GithubRelease>;
|
31
|
-
export declare function formatReferences(references: Reference[], repoData: GithubRepoData): string;
|
32
|
-
export {};
|