nx 22.7.0 → 22.7.1
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/ai/set-up-ai-agents/set-up-ai-agents.js +15 -23
- package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +13 -1
- package/dist/src/command-line/init/implementation/dot-nx/nxw.js +2 -1
- package/dist/src/command-line/migrate/command-object.js +5 -0
- package/dist/src/command-line/migrate/migrate.d.ts +10 -2
- package/dist/src/command-line/migrate/migrate.js +157 -30
- package/dist/src/command-line/release/utils/shared.js +22 -12
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/daemon/client/client.js +1 -1
- package/dist/src/daemon/client/daemon-environment.js +2 -0
- package/dist/src/daemon/is-nx-version-mismatch.d.ts +0 -1
- package/dist/src/daemon/is-nx-version-mismatch.js +2 -18
- package/dist/src/daemon/server/server.js +2 -1
- 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/run-command.js +2 -3
- package/dist/src/tasks-runner/task-orchestrator.js +6 -1
- package/dist/src/tasks-runner/utils.d.ts +11 -0
- package/dist/src/tasks-runner/utils.js +37 -0
- package/dist/src/utils/installed-nx-version.d.ts +8 -0
- package/dist/src/utils/installed-nx-version.js +67 -0
- package/dist/src/utils/workspace-context.js +1 -1
- package/package.json +11 -11
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,38 +15,30 @@ const package_json_1 = require("../../utils/package-json");
|
|
|
15
15
|
const ignore_1 = require("../../utils/ignore");
|
|
16
16
|
const provenance_1 = require("../../utils/provenance");
|
|
17
17
|
const workspace_root_1 = require("../../utils/workspace-root");
|
|
18
|
+
const installed_nx_version_1 = require("../../utils/installed-nx-version");
|
|
18
19
|
const constants_1 = require("../constants");
|
|
19
20
|
const clone_ai_config_repo_1 = require("../clone-ai-config-repo");
|
|
20
21
|
const utils_1 = require("../utils");
|
|
21
22
|
const handle_import_1 = require("../../utils/handle-import");
|
|
22
23
|
/**
|
|
23
|
-
*
|
|
24
|
+
* Best-effort fallback when `getInstalledNxVersion()` can't find an
|
|
25
|
+
* installed nx — read the version declared in the workspace's
|
|
26
|
+
* `package.json` (devDependencies/dependencies), stripping any semver
|
|
27
|
+
* range prefix, and finally a sane default.
|
|
24
28
|
*/
|
|
25
|
-
function
|
|
29
|
+
function getDeclaredNxVersionOrDefault() {
|
|
26
30
|
try {
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
31
|
+
const workspacePackageJson = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(workspace_root_1.workspaceRoot, 'package.json'), 'utf-8'));
|
|
32
|
+
const declared = workspacePackageJson.devDependencies?.nx ||
|
|
33
|
+
workspacePackageJson.dependencies?.nx;
|
|
34
|
+
if (declared) {
|
|
35
|
+
return declared.replace(/^[\^~>=<]+/, '');
|
|
36
|
+
}
|
|
30
37
|
}
|
|
31
38
|
catch {
|
|
32
|
-
|
|
33
|
-
// Fallback: try to read from workspace package.json
|
|
34
|
-
const workspacePackageJson = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(workspace_root_1.workspaceRoot, 'package.json'), 'utf-8'));
|
|
35
|
-
// Check devDependencies first, then dependencies
|
|
36
|
-
const nxVersion = workspacePackageJson.devDependencies?.nx ||
|
|
37
|
-
workspacePackageJson.dependencies?.nx;
|
|
38
|
-
if (nxVersion) {
|
|
39
|
-
// Remove any semver range characters (^, ~, >=, etc.)
|
|
40
|
-
return nxVersion.replace(/^[\^~>=<]+/, '');
|
|
41
|
-
}
|
|
42
|
-
throw new Error('Nx not found in package.json');
|
|
43
|
-
}
|
|
44
|
-
catch {
|
|
45
|
-
// If we can't determine the version, default to the newer format
|
|
46
|
-
// This handles cases where nx might not be installed or is globally installed
|
|
47
|
-
return '22.0.0';
|
|
48
|
-
}
|
|
39
|
+
// fall through to default
|
|
49
40
|
}
|
|
41
|
+
return '22.0.0';
|
|
50
42
|
}
|
|
51
43
|
async function setupAiAgentsGenerator(tree, options, inner = false) {
|
|
52
44
|
const normalizedOptions = normalizeOptions(options);
|
|
@@ -77,7 +69,7 @@ function normalizeOptions(options) {
|
|
|
77
69
|
}
|
|
78
70
|
async function setupAiAgentsGeneratorImpl(tree, options) {
|
|
79
71
|
const hasAgent = (agent) => options.agents.includes(agent);
|
|
80
|
-
const nxVersion =
|
|
72
|
+
const nxVersion = (0, installed_nx_version_1.getInstalledNxVersion)() ?? getDeclaredNxVersionOrDefault();
|
|
81
73
|
const agentsMd = (0, constants_1.agentsMdPath)(options.directory);
|
|
82
74
|
// write AGENTS.md for most agents
|
|
83
75
|
if (hasAgent('cursor') ||
|
|
@@ -64,7 +64,19 @@ function generateDotNxSetup(version) {
|
|
|
64
64
|
(0, tree_1.flushChanges)(host.root, changes);
|
|
65
65
|
// Ensure that the dot-nx installation is available.
|
|
66
66
|
// This is needed when using a global nx with dot-nx, otherwise running any nx command using global command will fail due to missing modules.
|
|
67
|
-
|
|
67
|
+
// Pipe stderr so failures surface in telemetry instead of bare "Command failed: ./nx --version".
|
|
68
|
+
try {
|
|
69
|
+
(0, child_process_1.execSync)('./nx --version', {
|
|
70
|
+
stdio: ['ignore', 'ignore', 'pipe'],
|
|
71
|
+
encoding: 'utf8',
|
|
72
|
+
windowsHide: true,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
if (e?.stderr)
|
|
77
|
+
process.stderr.write(e.stderr);
|
|
78
|
+
throw e;
|
|
79
|
+
}
|
|
68
80
|
}
|
|
69
81
|
function normalizeVersionForNxJson(pkg, version) {
|
|
70
82
|
if (!(0, semver_1.valid)(version)) {
|
|
@@ -60,7 +60,8 @@ function performInstallation(currentInstallation, nxJson) {
|
|
|
60
60
|
},
|
|
61
61
|
}));
|
|
62
62
|
try {
|
|
63
|
-
|
|
63
|
+
// --include=dev forces install even if consumer env sets NODE_ENV=production / omit=dev.
|
|
64
|
+
cp.execSync('npm i --include=dev', {
|
|
64
65
|
cwd: path.dirname(installationPath),
|
|
65
66
|
stdio: 'inherit',
|
|
66
67
|
windowsHide: true,
|
|
@@ -61,6 +61,11 @@ function withMigrationOptions(yargs) {
|
|
|
61
61
|
describe: 'Exclude migrations that should have been applied on previous updates. To be used with --from.',
|
|
62
62
|
type: 'boolean',
|
|
63
63
|
default: false,
|
|
64
|
+
})
|
|
65
|
+
.option('skipInstall', {
|
|
66
|
+
describe: 'Skip installing packages before running migrations. Useful when the installation needs to be performed manually (e.g., to resolve peer dependency conflicts).',
|
|
67
|
+
type: 'boolean',
|
|
68
|
+
default: false,
|
|
64
69
|
})
|
|
65
70
|
.check(({ createCommits, commitPrefix, from, excludeAppliedMigrations }) => {
|
|
66
71
|
if (!createCommits && commitPrefix !== defaultCommitPrefix) {
|
|
@@ -104,12 +104,20 @@ type RunMigrations = {
|
|
|
104
104
|
export declare function parseMigrationsOptions(options: {
|
|
105
105
|
[k: string]: any;
|
|
106
106
|
}): Promise<GenerateMigrations | RunMigrations>;
|
|
107
|
+
/**
|
|
108
|
+
* Detects npm peer-dependency resolution failures. Keyed on the `ERESOLVE`
|
|
109
|
+
* error code, which npm consistently emits for this class of failure across
|
|
110
|
+
* v7+ (`npm ERR! code ERESOLVE` / `npm error code ERESOLVE`). Falls back to a
|
|
111
|
+
* small set of stable phrases in case the code line is missing from the
|
|
112
|
+
* captured output.
|
|
113
|
+
*/
|
|
114
|
+
export declare function isNpmPeerDepsError(stderr: string): boolean;
|
|
107
115
|
export declare function executeMigrations(root: string, migrations: {
|
|
108
116
|
package: string;
|
|
109
117
|
name: string;
|
|
110
118
|
description?: string;
|
|
111
119
|
version: string;
|
|
112
|
-
}[], isVerbose: boolean, shouldCreateCommits: boolean, commitPrefix: string): Promise<{
|
|
120
|
+
}[], isVerbose: boolean, shouldCreateCommits: boolean, commitPrefix: string, shouldSkipInstall?: boolean): Promise<{
|
|
113
121
|
migrationsWithNoChanges: {
|
|
114
122
|
package: string;
|
|
115
123
|
name: string;
|
|
@@ -123,7 +131,7 @@ export declare function runNxOrAngularMigration(root: string, migration: {
|
|
|
123
131
|
name: string;
|
|
124
132
|
description?: string;
|
|
125
133
|
version: string;
|
|
126
|
-
}, isVerbose: boolean, shouldCreateCommits: boolean, commitPrefix: string, installDepsIfChanged?: () => void
|
|
134
|
+
}, isVerbose: boolean, shouldCreateCommits: boolean, commitPrefix: string, installDepsIfChanged?: () => Promise<void>, handleInstallDeps?: boolean): Promise<{
|
|
127
135
|
changes: FileChange[];
|
|
128
136
|
nextSteps: string[];
|
|
129
137
|
}>;
|
|
@@ -4,6 +4,7 @@ exports.Migrator = void 0;
|
|
|
4
4
|
exports.formatCommandFailure = formatCommandFailure;
|
|
5
5
|
exports.normalizeVersion = normalizeVersion;
|
|
6
6
|
exports.parseMigrationsOptions = parseMigrationsOptions;
|
|
7
|
+
exports.isNpmPeerDepsError = isNpmPeerDepsError;
|
|
7
8
|
exports.executeMigrations = executeMigrations;
|
|
8
9
|
exports.runNxOrAngularMigration = runNxOrAngularMigration;
|
|
9
10
|
exports.migrate = migrate;
|
|
@@ -1064,28 +1065,120 @@ function showConnectToCloudMessage() {
|
|
|
1064
1065
|
return false;
|
|
1065
1066
|
}
|
|
1066
1067
|
}
|
|
1067
|
-
function runInstall(nxWorkspaceRoot) {
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
packageManager = (0, package_manager_1.detectPackageManager)(nxWorkspaceRoot);
|
|
1072
|
-
pmCommands = (0, package_manager_1.getPackageManagerCommand)(packageManager, nxWorkspaceRoot);
|
|
1073
|
-
}
|
|
1074
|
-
else {
|
|
1075
|
-
pmCommands = (0, package_manager_1.getPackageManagerCommand)();
|
|
1076
|
-
}
|
|
1068
|
+
function runInstall(nxWorkspaceRoot, phase = 'pre-migration') {
|
|
1069
|
+
const cwd = nxWorkspaceRoot ?? process.cwd();
|
|
1070
|
+
const packageManager = (0, package_manager_1.detectPackageManager)(cwd);
|
|
1071
|
+
const pmCommands = (0, package_manager_1.getPackageManagerCommand)(packageManager, cwd);
|
|
1077
1072
|
const installCommand = `${pmCommands.install} ${pmCommands.ignoreScriptsFlag ?? ''}`;
|
|
1078
1073
|
output_1.output.log({
|
|
1079
1074
|
title: `Running '${installCommand}' to make sure necessary packages are installed`,
|
|
1080
1075
|
});
|
|
1081
|
-
(
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1076
|
+
return new Promise((resolve, reject) => {
|
|
1077
|
+
// For npm, pipe stderr so we can detect peer dependency errors while still
|
|
1078
|
+
// mirroring it live to the user's terminal. Other package managers inherit
|
|
1079
|
+
// stderr directly since we don't need to inspect their output.
|
|
1080
|
+
const shouldCaptureStderr = packageManager === 'npm';
|
|
1081
|
+
const child = (0, child_process_1.spawn)(installCommand, {
|
|
1082
|
+
shell: true,
|
|
1083
|
+
stdio: ['inherit', 'inherit', shouldCaptureStderr ? 'pipe' : 'inherit'],
|
|
1084
|
+
windowsHide: true,
|
|
1085
|
+
cwd,
|
|
1086
|
+
});
|
|
1087
|
+
const stderrChunks = [];
|
|
1088
|
+
child.stderr?.on('data', (chunk) => {
|
|
1089
|
+
process.stderr.write(chunk);
|
|
1090
|
+
stderrChunks.push(chunk);
|
|
1091
|
+
});
|
|
1092
|
+
child.on('error', reject);
|
|
1093
|
+
child.on('close', (code) => {
|
|
1094
|
+
if (code === 0) {
|
|
1095
|
+
resolve();
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
if (shouldCaptureStderr) {
|
|
1099
|
+
const stderr = Buffer.concat(stderrChunks).toString().trim();
|
|
1100
|
+
if (isNpmPeerDepsError(stderr)) {
|
|
1101
|
+
// Log the remediation guidance here so every caller of `runInstall`
|
|
1102
|
+
// (CLI migrate, `nx repair`, single-migration runner, etc.) surfaces
|
|
1103
|
+
// it consistently. Top-level callers catch `NpmPeerDepsInstallError`
|
|
1104
|
+
// and return a non-zero exit code without re-logging.
|
|
1105
|
+
logNpmPeerDepsError(phase);
|
|
1106
|
+
reject(new NpmPeerDepsInstallError());
|
|
1107
|
+
return;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
reject(new Error(`Command failed: ${installCommand}`));
|
|
1111
|
+
});
|
|
1085
1112
|
});
|
|
1086
1113
|
}
|
|
1087
|
-
|
|
1088
|
-
|
|
1114
|
+
class NpmPeerDepsInstallError extends Error {
|
|
1115
|
+
constructor() {
|
|
1116
|
+
super('npm install failed due to peer dependency conflicts.');
|
|
1117
|
+
this.name = 'NpmPeerDepsInstallError';
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
* Detects npm peer-dependency resolution failures. Keyed on the `ERESOLVE`
|
|
1122
|
+
* error code, which npm consistently emits for this class of failure across
|
|
1123
|
+
* v7+ (`npm ERR! code ERESOLVE` / `npm error code ERESOLVE`). Falls back to a
|
|
1124
|
+
* small set of stable phrases in case the code line is missing from the
|
|
1125
|
+
* captured output.
|
|
1126
|
+
*/
|
|
1127
|
+
function isNpmPeerDepsError(stderr) {
|
|
1128
|
+
if (/\bERESOLVE\b/.test(stderr)) {
|
|
1129
|
+
return true;
|
|
1130
|
+
}
|
|
1131
|
+
const lowerStderr = stderr.toLowerCase();
|
|
1132
|
+
return (lowerStderr.includes('unable to resolve dependency tree') ||
|
|
1133
|
+
lowerStderr.includes('could not resolve dependency') ||
|
|
1134
|
+
lowerStderr.includes('conflicting peer dependency'));
|
|
1135
|
+
}
|
|
1136
|
+
function logNpmPeerDepsError(phase) {
|
|
1137
|
+
const peerDepsResolutionSteps = [
|
|
1138
|
+
'Recommended approaches (in order of preference):',
|
|
1139
|
+
'',
|
|
1140
|
+
'1. Use "overrides" in package.json to force compatible versions across the dependency tree.',
|
|
1141
|
+
' See https://docs.npmjs.com/cli/configuring-npm/package-json#overrides',
|
|
1142
|
+
'2. Persist legacy peer deps resolution in the project ".npmrc":',
|
|
1143
|
+
' npm config set legacy-peer-deps=true --location=project',
|
|
1144
|
+
' (bypasses peer dependency resolution; use with caution)',
|
|
1145
|
+
'3. As a last resort, force the installation by running "npm install --force".',
|
|
1146
|
+
' (does not persist and may produce broken installs)',
|
|
1147
|
+
];
|
|
1148
|
+
const manualInstallHint = [
|
|
1149
|
+
'If you installed the dependencies manually, pass "--skip-install" to avoid re-installing them:',
|
|
1150
|
+
' nx migrate --run-migrations --skip-install',
|
|
1151
|
+
];
|
|
1152
|
+
if (phase === 'pre-migration') {
|
|
1153
|
+
output_1.output.error({
|
|
1154
|
+
title: 'You need to resolve the peer dependency conflicts before the migration can continue',
|
|
1155
|
+
bodyLines: [
|
|
1156
|
+
...peerDepsResolutionSteps,
|
|
1157
|
+
'',
|
|
1158
|
+
'Once the conflicts are resolved, re-run the migrations:',
|
|
1159
|
+
' nx migrate --run-migrations',
|
|
1160
|
+
'',
|
|
1161
|
+
...manualInstallHint,
|
|
1162
|
+
],
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
1165
|
+
else {
|
|
1166
|
+
output_1.output.error({
|
|
1167
|
+
title: 'Some migrations have been applied, but installing the updated dependencies failed',
|
|
1168
|
+
bodyLines: [
|
|
1169
|
+
...peerDepsResolutionSteps,
|
|
1170
|
+
'',
|
|
1171
|
+
'Once the conflicts are resolved, run "npm install" to install the updated dependencies.',
|
|
1172
|
+
'If the migration was interrupted before completing, re-run the remaining migrations:',
|
|
1173
|
+
' nx migrate --run-migrations',
|
|
1174
|
+
'',
|
|
1175
|
+
...manualInstallHint,
|
|
1176
|
+
],
|
|
1177
|
+
});
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
async function executeMigrations(root, migrations, isVerbose, shouldCreateCommits, commitPrefix, shouldSkipInstall = false) {
|
|
1181
|
+
const changedDepInstaller = new ChangedDepInstaller(root, shouldSkipInstall);
|
|
1089
1182
|
const migrationsWithNoChanges = [];
|
|
1090
1183
|
const sortedMigrations = migrations.sort((a, b) => {
|
|
1091
1184
|
// special case for the split configuration migration to run first
|
|
@@ -1114,30 +1207,53 @@ async function executeMigrations(root, migrations, isVerbose, shouldCreateCommit
|
|
|
1114
1207
|
logger_1.logger.info(`---------------------------------------------------------`);
|
|
1115
1208
|
}
|
|
1116
1209
|
catch (e) {
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1210
|
+
if (!(e instanceof NpmPeerDepsInstallError)) {
|
|
1211
|
+
output_1.output.error({
|
|
1212
|
+
title: `Failed to run ${m.name} from ${m.package}. This workspace is NOT up to date!`,
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1120
1215
|
throw e;
|
|
1121
1216
|
}
|
|
1122
1217
|
}
|
|
1123
1218
|
if (!shouldCreateCommits) {
|
|
1124
|
-
changedDepInstaller.installDepsIfChanged();
|
|
1219
|
+
await changedDepInstaller.installDepsIfChanged();
|
|
1220
|
+
}
|
|
1221
|
+
if (changedDepInstaller.skippedInstall) {
|
|
1222
|
+
logSkippedPostMigrationInstall(root);
|
|
1125
1223
|
}
|
|
1126
1224
|
return { migrationsWithNoChanges, nextSteps: allNextSteps };
|
|
1127
1225
|
}
|
|
1128
1226
|
class ChangedDepInstaller {
|
|
1129
|
-
constructor(root) {
|
|
1227
|
+
constructor(root, shouldSkipInstall = false) {
|
|
1130
1228
|
this.root = root;
|
|
1229
|
+
this.shouldSkipInstall = shouldSkipInstall;
|
|
1230
|
+
this._skippedInstall = false;
|
|
1131
1231
|
this.initialDeps = getStringifiedPackageJsonDeps(root);
|
|
1132
1232
|
}
|
|
1133
|
-
|
|
1233
|
+
get skippedInstall() {
|
|
1234
|
+
return this._skippedInstall;
|
|
1235
|
+
}
|
|
1236
|
+
async installDepsIfChanged() {
|
|
1134
1237
|
const currentDeps = getStringifiedPackageJsonDeps(this.root);
|
|
1135
1238
|
if (this.initialDeps !== currentDeps) {
|
|
1136
|
-
|
|
1239
|
+
if (this.shouldSkipInstall) {
|
|
1240
|
+
this._skippedInstall = true;
|
|
1241
|
+
}
|
|
1242
|
+
else {
|
|
1243
|
+
await runInstall(this.root, 'post-migration');
|
|
1244
|
+
}
|
|
1137
1245
|
}
|
|
1138
1246
|
this.initialDeps = currentDeps;
|
|
1139
1247
|
}
|
|
1140
1248
|
}
|
|
1249
|
+
function logSkippedPostMigrationInstall(root) {
|
|
1250
|
+
const packageManager = (0, package_manager_1.detectPackageManager)(root);
|
|
1251
|
+
const installCommand = (0, package_manager_1.getPackageManagerCommand)(packageManager, root).install;
|
|
1252
|
+
output_1.output.warn({
|
|
1253
|
+
title: 'Migrations updated your dependencies, but the install was skipped',
|
|
1254
|
+
bodyLines: [`Run "${installCommand}" to install the updated dependencies.`],
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1141
1257
|
async function runNxOrAngularMigration(root, migration, isVerbose, shouldCreateCommits, commitPrefix, installDepsIfChanged, handleInstallDeps = false) {
|
|
1142
1258
|
if (!installDepsIfChanged) {
|
|
1143
1259
|
const changedDepInstaller = new ChangedDepInstaller(root);
|
|
@@ -1173,7 +1289,7 @@ async function runNxOrAngularMigration(root, migration, isVerbose, shouldCreateC
|
|
|
1173
1289
|
logger_1.logger.info('');
|
|
1174
1290
|
}
|
|
1175
1291
|
if (shouldCreateCommits) {
|
|
1176
|
-
installDepsIfChanged();
|
|
1292
|
+
await installDepsIfChanged();
|
|
1177
1293
|
const commitMessage = `${commitPrefix}${migration.name}`;
|
|
1178
1294
|
try {
|
|
1179
1295
|
const committedSha = (0, git_utils_1.commitChanges)(commitMessage, root);
|
|
@@ -1190,13 +1306,13 @@ async function runNxOrAngularMigration(root, migration, isVerbose, shouldCreateC
|
|
|
1190
1306
|
// if we are running this function alone, we need to install deps internally
|
|
1191
1307
|
}
|
|
1192
1308
|
else if (handleInstallDeps) {
|
|
1193
|
-
installDepsIfChanged();
|
|
1309
|
+
await installDepsIfChanged();
|
|
1194
1310
|
}
|
|
1195
1311
|
return { changes, nextSteps };
|
|
1196
1312
|
}
|
|
1197
|
-
async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits = false, commitPrefix) {
|
|
1198
|
-
if (!process.env.NX_MIGRATE_SKIP_INSTALL) {
|
|
1199
|
-
runInstall();
|
|
1313
|
+
async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits = false, commitPrefix, shouldSkipInstall = false) {
|
|
1314
|
+
if (!shouldSkipInstall && !process.env.NX_MIGRATE_SKIP_INSTALL) {
|
|
1315
|
+
await runInstall();
|
|
1200
1316
|
}
|
|
1201
1317
|
if (!__dirname.startsWith(workspace_root_1.workspaceRoot)) {
|
|
1202
1318
|
// we are running from a temp installation with nx latest, switch to running
|
|
@@ -1229,7 +1345,7 @@ async function runMigrations(root, opts, args, isVerbose, shouldCreateCommits =
|
|
|
1229
1345
|
(shouldCreateCommits ? ', with each applied in a dedicated commit' : ''),
|
|
1230
1346
|
});
|
|
1231
1347
|
const migrations = (0, fileutils_1.readJsonFile)((0, path_1.join)(root, opts.runMigrations)).migrations;
|
|
1232
|
-
const { migrationsWithNoChanges, nextSteps } = await executeMigrations(root, migrations, isVerbose, shouldCreateCommits, commitPrefix);
|
|
1348
|
+
const { migrationsWithNoChanges, nextSteps } = await executeMigrations(root, migrations, isVerbose, shouldCreateCommits, commitPrefix, shouldSkipInstall);
|
|
1233
1349
|
if (migrationsWithNoChanges.length < migrations.length) {
|
|
1234
1350
|
output_1.output.success({
|
|
1235
1351
|
title: `Successfully finished running migrations from '${opts.runMigrations}'. This workspace is up to date!`,
|
|
@@ -1283,7 +1399,18 @@ async function migrate(root, args, rawArgs) {
|
|
|
1283
1399
|
await generateMigrationsJsonAndUpdatePackageJson(root, opts);
|
|
1284
1400
|
}
|
|
1285
1401
|
else {
|
|
1286
|
-
|
|
1402
|
+
try {
|
|
1403
|
+
return await runMigrations(root, opts, rawArgs, args['verbose'], args['createCommits'], args['commitPrefix'], args['skipInstall']);
|
|
1404
|
+
}
|
|
1405
|
+
catch (e) {
|
|
1406
|
+
// The remediation guidance is already logged by `runInstall`; swallow
|
|
1407
|
+
// the error here so `handleErrors` doesn't print a noisy stack after
|
|
1408
|
+
// the friendly output.
|
|
1409
|
+
if (e instanceof NpmPeerDepsInstallError) {
|
|
1410
|
+
return 1;
|
|
1411
|
+
}
|
|
1412
|
+
throw e;
|
|
1413
|
+
}
|
|
1287
1414
|
}
|
|
1288
1415
|
});
|
|
1289
1416
|
}
|
|
@@ -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
|
}
|