@depup/nx 23.1.1-depup.3 → 23.1.2-depup.0

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.
Files changed (130) hide show
  1. package/README.md +3 -4
  2. package/changes.json +2 -6
  3. package/dist/release/changelog-renderer/index.js +4 -5
  4. package/dist/release/index.d.ts +1 -1
  5. package/dist/src/command-line/add/add.js +5 -0
  6. package/dist/src/command-line/affected/affected.js +1 -0
  7. package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +2 -2
  8. package/dist/src/command-line/import/import.js +1 -2
  9. package/dist/src/command-line/init/init-v2.js +4 -5
  10. package/dist/src/command-line/migrate/migrate.d.ts +4 -0
  11. package/dist/src/command-line/migrate/migrate.js +89 -26
  12. package/dist/src/command-line/release/changelog.js +5 -0
  13. package/dist/src/command-line/release/index.d.ts +1 -1
  14. package/dist/src/command-line/release/utils/git.js +1 -1
  15. package/dist/src/command-line/release/utils/release-graph.d.ts +17 -0
  16. package/dist/src/command-line/release/utils/release-graph.js +71 -19
  17. package/dist/src/command-line/release/utils/remote-release-clients/github.js +6 -0
  18. package/dist/src/command-line/release/version/release-group-processor.d.ts +24 -0
  19. package/dist/src/command-line/release/version/release-group-processor.js +80 -6
  20. package/dist/src/command-line/release/version/version-actions.d.ts +27 -2
  21. package/dist/src/command-line/release/version/version-actions.js +9 -1
  22. package/dist/src/command-line/release/version.js +9 -5
  23. package/dist/src/command-line/reset/reset.js +6 -1
  24. package/dist/src/command-line/run/run-one.js +1 -0
  25. package/dist/src/command-line/run-many/run-many.js +1 -0
  26. package/dist/src/command-line/watch/watch.js +13 -0
  27. package/dist/src/core/graph/main.js +1 -1
  28. package/dist/src/core/graph/styles.js +1 -1
  29. package/dist/src/daemon/client/client.d.ts +52 -1
  30. package/dist/src/daemon/client/client.js +160 -36
  31. package/dist/src/daemon/client/daemon-environment.d.ts +17 -0
  32. package/dist/src/daemon/client/daemon-environment.js +110 -2
  33. package/dist/src/daemon/client/daemon-socket-messenger.js +4 -0
  34. package/dist/src/daemon/message-types/daemon-message.d.ts +32 -0
  35. package/dist/src/daemon/message-types/daemon-message.js +25 -0
  36. package/dist/src/daemon/server/file-watching/file-watcher-sockets.d.ts +5 -0
  37. package/dist/src/daemon/server/file-watching/file-watcher-sockets.js +16 -0
  38. package/dist/src/daemon/server/latest-nx.js +5 -2
  39. package/dist/src/daemon/server/server.js +24 -0
  40. package/dist/src/daemon/server/shutdown-utils.d.ts +5 -0
  41. package/dist/src/daemon/server/shutdown-utils.js +11 -4
  42. package/dist/src/daemon/socket-utils.d.ts +1 -0
  43. package/dist/src/daemon/socket-utils.js +24 -3
  44. package/dist/src/daemon/tmp-dir.d.ts +43 -3
  45. package/dist/src/daemon/tmp-dir.js +437 -15
  46. package/dist/src/devkit-internals.d.ts +93 -3
  47. package/dist/src/devkit-internals.js +192 -5
  48. package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.d.ts +5 -0
  49. package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.js +9 -2
  50. package/dist/src/generators/tree.d.ts +4 -2
  51. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.d.ts +12 -0
  52. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.js +250 -0
  53. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.md +50 -0
  54. package/dist/src/native/index.d.ts +10 -0
  55. package/dist/src/native/index.js +71 -28
  56. package/dist/src/native/native-bindings.js +1 -0
  57. package/dist/src/native/native-file-cache-location.d.ts +17 -1
  58. package/dist/src/native/native-file-cache-location.js +86 -12
  59. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  60. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  61. package/dist/src/nx-cloud/utilities/get-cloud-options.js +5 -2
  62. package/dist/src/nx-cloud/utilities/onboarding.js +5 -2
  63. package/dist/src/plugins/js/lock-file/bun-parser.js +43 -10
  64. package/dist/src/plugins/js/lock-file/pnpm-parser.js +60 -0
  65. package/dist/src/plugins/js/lock-file/project-graph-pruning.js +14 -8
  66. package/dist/src/plugins/js/project-graph/affected/npm-packages.js +51 -20
  67. package/dist/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +2 -0
  68. package/dist/src/project-graph/affected/affected-project-graph-models.d.ts +1 -1
  69. package/dist/src/project-graph/affected/affected-project-graph.d.ts +1 -1
  70. package/dist/src/project-graph/affected/affected-project-graph.js +2 -2
  71. package/dist/src/project-graph/affected/locators/project-glob-changes.js +5 -2
  72. package/dist/src/project-graph/error-types.d.ts +12 -1
  73. package/dist/src/project-graph/error-types.js +27 -2
  74. package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +1 -0
  75. package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +18 -1
  76. package/dist/src/project-graph/plugins/isolation/messaging.d.ts +16 -3
  77. package/dist/src/project-graph/plugins/isolation/messaging.js +3 -0
  78. package/dist/src/project-graph/plugins/isolation/plugin-worker.js +58 -8
  79. package/dist/src/project-graph/project-graph.js +20 -0
  80. package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.js +5 -1
  81. package/dist/src/project-graph/utils/project-configuration/target-normalization.js +133 -3
  82. package/dist/src/tasks-runner/task-env.js +5 -2
  83. package/dist/src/tasks-runner/utils.js +2 -6
  84. package/dist/src/utils/assert-workspace-validity.js +7 -2
  85. package/dist/src/utils/fileutils.d.ts +5 -0
  86. package/dist/src/utils/fileutils.js +7 -2
  87. package/dist/src/utils/git-worktrees.d.ts +30 -0
  88. package/dist/src/utils/git-worktrees.js +212 -0
  89. package/dist/src/utils/ignore.d.ts +128 -1
  90. package/dist/src/utils/ignore.js +182 -12
  91. package/dist/src/utils/long-running-target.d.ts +10 -0
  92. package/dist/src/utils/long-running-target.js +19 -0
  93. package/dist/src/utils/min-release-age/behavior/bun.js +7 -11
  94. package/dist/src/utils/min-release-age/behavior/npm.js +5 -2
  95. package/dist/src/utils/min-release-age/packument.js +1 -1
  96. package/dist/src/utils/nx-tmp-dir.d.ts +18 -0
  97. package/dist/src/utils/nx-tmp-dir.js +40 -0
  98. package/dist/src/utils/owned-private-dir.d.ts +132 -0
  99. package/dist/src/utils/owned-private-dir.js +323 -0
  100. package/dist/src/utils/package-manager-config/bunfig.d.ts +14 -0
  101. package/dist/src/utils/package-manager-config/bunfig.js +49 -0
  102. package/dist/src/utils/package-manager-config/npmrc.d.ts +23 -0
  103. package/dist/src/utils/package-manager-config/npmrc.js +124 -0
  104. package/dist/src/utils/package-manager-config/pnpm-config.d.ts +17 -0
  105. package/dist/src/utils/package-manager-config/pnpm-config.js +60 -0
  106. package/dist/src/utils/package-manager.d.ts +21 -2
  107. package/dist/src/utils/package-manager.js +244 -47
  108. package/dist/src/utils/provenance.js +6 -14
  109. package/dist/src/utils/registry-config/bun.d.ts +2 -0
  110. package/dist/src/utils/registry-config/bun.js +257 -0
  111. package/dist/src/utils/registry-config/index.d.ts +13 -0
  112. package/dist/src/utils/registry-config/index.js +102 -0
  113. package/dist/src/utils/registry-config/pnpm.d.ts +2 -0
  114. package/dist/src/utils/registry-config/pnpm.js +1551 -0
  115. package/dist/src/utils/registry-config/utils.d.ts +195 -0
  116. package/dist/src/utils/registry-config/utils.js +496 -0
  117. package/dist/src/utils/registry-config/yarn-berry.d.ts +2 -0
  118. package/dist/src/utils/registry-config/yarn-berry.js +612 -0
  119. package/dist/src/utils/registry-config/yarn-classic.d.ts +2 -0
  120. package/dist/src/utils/registry-config/yarn-classic.js +1001 -0
  121. package/dist/src/utils/safe-spawn.d.ts +24 -0
  122. package/dist/src/utils/safe-spawn.js +104 -0
  123. package/dist/src/utils/shell-quoting.d.ts +15 -0
  124. package/dist/src/utils/shell-quoting.js +35 -0
  125. package/dist/src/utils/wait-for-socket-connection.d.ts +11 -0
  126. package/dist/src/utils/wait-for-socket-connection.js +14 -8
  127. package/migrations.json +6 -0
  128. package/package.json +15 -19
  129. package/dist/src/utils/min-release-age/npmrc.d.ts +0 -15
  130. package/dist/src/utils/min-release-age/npmrc.js +0 -45
package/README.md CHANGED
@@ -13,10 +13,10 @@ npm install @depup/nx
13
13
 
14
14
  | Field | Value |
15
15
  |-------|-------|
16
- | Original | [nx](https://www.npmjs.com/package/nx) @ 23.1.1 |
17
- | Processed | 2026-08-26 |
16
+ | Original | [nx](https://www.npmjs.com/package/nx) @ 23.1.2 |
17
+ | Processed | 2026-08-27 |
18
18
  | Smoke test | failed |
19
- | Deps updated | 71 |
19
+ | Deps updated | 70 |
20
20
 
21
21
  ## Dependency Changes
22
22
 
@@ -37,7 +37,6 @@ npm install @depup/nx
37
37
  | axios | 1.18.1 | ^1.20.0 |
38
38
  | balanced-match | 4.0.3 | ^4.0.4 |
39
39
  | bl | 4.1.0 | ^7.0.12 |
40
- | brace-expansion | 5.0.8 | ^5.0.9 |
41
40
  | buffer | 5.7.1 | ^6.0.3 |
42
41
  | chalk | 4.1.2 | ^6.0.0 |
43
42
  | cli-cursor | 3.1.0 | ^5.0.0 |
package/changes.json CHANGED
@@ -60,10 +60,6 @@
60
60
  "from": "4.1.0",
61
61
  "to": "^7.0.12"
62
62
  },
63
- "brace-expansion": {
64
- "from": "5.0.8",
65
- "to": "^5.0.9"
66
- },
67
63
  "buffer": {
68
64
  "from": "5.7.1",
69
65
  "to": "^6.0.3"
@@ -285,6 +281,6 @@
285
281
  "to": "^22.0.0"
286
282
  }
287
283
  },
288
- "timestamp": "2026-08-26T08:22:34.168Z",
289
- "totalUpdated": 71
284
+ "timestamp": "2026-08-27T01:41:10.145Z",
285
+ "totalUpdated": 70
290
286
  }
@@ -215,12 +215,11 @@ class DefaultChangelogRenderer {
215
215
  if (!name || name.includes('[bot]')) {
216
216
  continue;
217
217
  }
218
- if (_authors.has(name)) {
219
- const entry = _authors.get(name);
220
- entry.email.add(author.email);
218
+ if (!_authors.has(name)) {
219
+ _authors.set(name, { email: new Set() });
221
220
  }
222
- else {
223
- _authors.set(name, { email: new Set([author.email]) });
221
+ if (author.email) {
222
+ _authors.get(name).email.add(author.email);
224
223
  }
225
224
  }
226
225
  }
@@ -1,4 +1,4 @@
1
1
  /**
2
2
  * @public Programmatic API for nx release
3
3
  */
4
- export { ReleaseClient, release, releaseChangelog, releasePublish, releaseVersion, VersionActions, AfterAllProjectsVersioned, } from '../src/command-line/release';
4
+ export { ReleaseClient, release, releaseChangelog, releasePublish, releaseVersion, VersionActions, AfterAllProjectsVersioned, ResolveVersionForDependency, } from '../src/command-line/release';
@@ -18,9 +18,14 @@ const semver_1 = require("semver");
18
18
  const configure_plugins_1 = require("../init/configure-plugins");
19
19
  const spinner_1 = require("../../utils/spinner");
20
20
  const analytics_1 = require("../../analytics");
21
+ const client_1 = require("../../daemon/client/client");
21
22
  function addHandler(options) {
22
23
  return (0, handle_errors_1.handleErrors)(options.verbose, async () => {
23
24
  output_1.output.addNewline();
25
+ // Package managers write the lock file before node_modules is fully linked,
26
+ // so a live daemon restarts mid-install and caches a graph whose plugins,
27
+ // still being relinked, no longer resolve.
28
+ await client_1.daemonClient.stop();
24
29
  const [pkgName, version] = parsePackageSpecifier(options.packageSpecifier);
25
30
  (0, analytics_1.reportNxAddCommand)(pkgName, version);
26
31
  const nxJson = (0, nx_json_1.readNxJson)();
@@ -49,6 +49,7 @@ async function affected(command, args, extraTargetDependencies = {}, extraOption
49
49
  }
50
50
  else {
51
51
  const status = await (0, run_command_1.runCommand)(projectsWithTarget, projectGraph, { nxJson }, nxArgs, overrides, null, extraTargetDependencies, extraOptions);
52
+ await output_1.output.drain();
52
53
  process.exit(status);
53
54
  }
54
55
  break;
@@ -11,7 +11,7 @@ const constants_1 = require("../../ai/constants");
11
11
  const detect_ai_agent_1 = require("../../ai/detect-ai-agent");
12
12
  const utils_1 = require("../../ai/utils");
13
13
  const client_1 = require("../../daemon/client/client");
14
- const devkit_internals_1 = require("../../devkit-internals");
14
+ const package_json_1 = require("../../utils/package-json");
15
15
  const output_1 = require("../../utils/output");
16
16
  const package_manager_1 = require("../../utils/package-manager");
17
17
  const provenance_1 = require("../../utils/provenance");
@@ -44,7 +44,7 @@ async function configureAiAgentsHandler(args, inner = false) {
44
44
  let cleanup;
45
45
  try {
46
46
  await (0, provenance_1.ensurePackageHasProvenance)('nx', 'latest');
47
- const packageInstallResults = (0, devkit_internals_1.installPackageToTmp)('nx', 'latest', (0, package_manager_1.detectPackageManager)(workspace_root_1.workspaceRoot));
47
+ const packageInstallResults = (0, package_json_1.installPackageToTmp)('nx', 'latest', (0, package_manager_1.detectPackageManager)(workspace_root_1.workspaceRoot));
48
48
  cleanup = packageInstallResults.cleanup;
49
49
  let modulePath = require.resolve('nx/src/command-line/configure-ai-agents/configure-ai-agents.js', { paths: [packageInstallResults.tempDir] });
50
50
  const module = await (0, handle_import_1.handleImport)(modulePath);
@@ -26,7 +26,6 @@ const configure_plugins_1 = require("../init/configure-plugins");
26
26
  const check_compatible_with_plugins_1 = require("../init/implementation/check-compatible-with-plugins");
27
27
  const native_1 = require("../../native");
28
28
  const ai_output_1 = require("./utils/ai-output");
29
- const init_v2_2 = require("../init/init-v2");
30
29
  const importRemoteName = '__tmp_nx_import__';
31
30
  async function importHandler(options) {
32
31
  process.env.NX_RUNNING_NX_IMPORT = 'true';
@@ -361,7 +360,7 @@ async function importHandler(options) {
361
360
  (0, ai_output_1.writeAiOutput)((0, ai_output_1.buildImportNeedsPluginSelectionResult)({
362
361
  detectedPlugins: detectedButNotInstalled.map((name) => ({
363
362
  name,
364
- reason: (0, init_v2_2.getPluginReason)(name),
363
+ reason: (0, init_v2_1.getPluginReason)(name),
365
364
  })),
366
365
  sourceRepository,
367
366
  ref,
@@ -11,6 +11,7 @@ const nx_json_1 = require("../../config/nx-json");
11
11
  const fileutils_1 = require("../../utils/fileutils");
12
12
  const get_package_name_from_import_path_1 = require("../../utils/get-package-name-from-import-path");
13
13
  const output_1 = require("../../utils/output");
14
+ const package_json_1 = require("../../utils/package-json");
14
15
  const package_manager_1 = require("../../utils/package-manager");
15
16
  const versions_1 = require("../../utils/versions");
16
17
  const workspace_context_1 = require("../../utils/workspace-context");
@@ -26,14 +27,12 @@ const angular_1 = require("./implementation/angular");
26
27
  const add_nx_scripts_1 = require("./implementation/dot-nx/add-nx-scripts");
27
28
  const utils_1 = require("./implementation/utils");
28
29
  const provenance_1 = require("../../utils/provenance");
29
- const devkit_internals_1 = require("../../devkit-internals");
30
30
  const handle_import_1 = require("../../utils/handle-import");
31
31
  const native_1 = require("../../native");
32
32
  const detect_ai_agent_1 = require("../../ai/detect-ai-agent");
33
33
  const ab_testing_1 = require("../../utils/ab-testing");
34
34
  const analytics_prompt_1 = require("../../utils/analytics-prompt");
35
35
  const is_ci_1 = require("../../utils/is-ci");
36
- const package_manager_2 = require("../../utils/package-manager");
37
36
  const ai_output_1 = require("./utils/ai-output");
38
37
  async function initHandler(options, inner = false) {
39
38
  // Use environment variable to force local execution
@@ -43,7 +42,7 @@ async function initHandler(options, inner = false) {
43
42
  let cleanup;
44
43
  try {
45
44
  await (0, provenance_1.ensurePackageHasProvenance)('nx', 'latest');
46
- const packageInstallResults = (0, devkit_internals_1.installPackageToTmp)('nx', 'latest', (0, package_manager_2.detectPackageManager)(process.cwd()));
45
+ const packageInstallResults = (0, package_json_1.installPackageToTmp)('nx', 'latest', (0, package_manager_1.detectPackageManager)(process.cwd()));
47
46
  cleanup = packageInstallResults.cleanup;
48
47
  let modulePath = require.resolve('nx/src/command-line/init/init-v2.js', {
49
48
  paths: [packageInstallResults.tempDir],
@@ -95,7 +94,7 @@ async function initHandlerImpl(options) {
95
94
  const baseMeta = {
96
95
  nodeVersion: process.versions.node,
97
96
  os: process.platform,
98
- packageManager: (0, package_manager_2.detectPackageManager)(),
97
+ packageManager: (0, package_manager_1.detectPackageManager)(),
99
98
  aiAgent: (0, native_1.isAiAgent)(),
100
99
  isCI: (0, is_ci_1.isCI)(),
101
100
  };
@@ -368,7 +367,7 @@ async function runInit(options, baseMeta) {
368
367
  analyticsPrompt,
369
368
  nodeVersion: process.versions.node,
370
369
  os: process.platform,
371
- packageManager: (0, package_manager_2.detectPackageManager)(),
370
+ packageManager: (0, package_manager_1.detectPackageManager)(),
372
371
  aiAgent: aiMode,
373
372
  isCI: (0, is_ci_1.isCI)(),
374
373
  pluginsInstalled: pluginsToInstall.join(','),
@@ -63,6 +63,8 @@ export declare class Migrator {
63
63
  private readonly packageUpdates;
64
64
  private readonly collectedVersions;
65
65
  private readonly promptAnswers;
66
+ private readonly pendingPackageJsonUpdates;
67
+ private readonly appliedPackageJsonUpdates;
66
68
  private readonly nxInstallation;
67
69
  private minVersionWithSkippedUpdates;
68
70
  constructor(opts: MigratorOptions);
@@ -85,6 +87,8 @@ export declare class Migrator {
85
87
  }>;
86
88
  private createMigrateJson;
87
89
  private buildPackageJsonUpdates;
90
+ private applyPackageJsonUpdate;
91
+ private applyPendingPackageJsonUpdates;
88
92
  private resolveVersionForCascade;
89
93
  private populatePackageJsonUpdatesAndGetPackagesToCheck;
90
94
  private getPackageJsonUpdatesFromMigrationConfig;
@@ -110,6 +110,8 @@ class Migrator {
110
110
  this.packageUpdates = {};
111
111
  this.collectedVersions = {};
112
112
  this.promptAnswers = {};
113
+ this.pendingPackageJsonUpdates = new Map();
114
+ this.appliedPackageJsonUpdates = new Set();
113
115
  if ((opts.include === 'required' || opts.include === 'optional') &&
114
116
  !opts.requiredPackages) {
115
117
  throw new Error(`Error: 'requiredPackages' is required when 'include' is '${opts.include}'.`);
@@ -137,6 +139,7 @@ class Migrator {
137
139
  version: targetVersion,
138
140
  addToPackageJson: false,
139
141
  });
142
+ await this.applyPendingPackageJsonUpdates();
140
143
  this.applyIncludeFilter();
141
144
  const { migrations, promptContents } = await this.createMigrateJson();
142
145
  return {
@@ -182,29 +185,66 @@ class Migrator {
182
185
  for (const packageToCheck of packagesToCheck) {
183
186
  const filteredUpdates = {};
184
187
  for (const [packageUpdateKey, packageUpdate] of Object.entries(packageToCheck.updates)) {
185
- if (this.areRequirementsMet(packageUpdate.requires) &&
186
- !this.areIncompatiblePackagesPresent(packageUpdate.incompatibleWith) &&
187
- (!this.interactive ||
188
- (await this.runPackageJsonUpdatesConfirmationPrompt(packageUpdate, packageUpdateKey, packageToCheck.package)))) {
189
- const updateEntries = Object.entries(packageUpdate.packages);
190
- // Validate all up front so invalid metadata fails fast, before any
191
- // resolution does I/O.
192
- for (const [name, update] of updateEntries) {
193
- this.validatePackageUpdateVersion(packageToCheck.package, name, update);
194
- }
195
- // Resolve serially: resolution can prompt (pnpm strict cooldown) and
196
- // append to minimumReleaseAgeExclude, so a serial loop avoids
197
- // overlapping prompts and keeps packageUpdates ordering stable.
198
- for (const [name, update] of updateEntries) {
199
- const resolvedUpdate = {
200
- ...update,
201
- version: await this.resolveVersionForCascade(name, update.version),
202
- };
203
- filteredUpdates[name] = resolvedUpdate;
204
- this.packageUpdates[name] = resolvedUpdate;
205
- }
188
+ Object.assign(filteredUpdates, await this.applyPackageJsonUpdate(packageToCheck.package, packageUpdateKey, packageUpdate));
189
+ }
190
+ await Promise.all(Object.entries(filteredUpdates).map(([name, update]) => this.buildPackageJsonUpdates(name, update)));
191
+ }
192
+ }
193
+ async applyPackageJsonUpdate(sourcePackage, packageUpdateKey, packageUpdate) {
194
+ const appliedKey = JSON.stringify([sourcePackage, packageUpdateKey]);
195
+ if (this.appliedPackageJsonUpdates.has(appliedKey)) {
196
+ this.pendingPackageJsonUpdates.delete(appliedKey);
197
+ return {};
198
+ }
199
+ if (!this.areRequirementsMet(packageUpdate.requires) ||
200
+ this.areIncompatiblePackagesPresent(packageUpdate.incompatibleWith)) {
201
+ this.pendingPackageJsonUpdates.set(appliedKey, {
202
+ package: sourcePackage,
203
+ key: packageUpdateKey,
204
+ update: packageUpdate,
205
+ });
206
+ return {};
207
+ }
208
+ this.pendingPackageJsonUpdates.delete(appliedKey);
209
+ if (this.interactive &&
210
+ !(await this.runPackageJsonUpdatesConfirmationPrompt(packageUpdate, packageUpdateKey, sourcePackage))) {
211
+ return {};
212
+ }
213
+ this.appliedPackageJsonUpdates.add(appliedKey);
214
+ const updateEntries = Object.entries(packageUpdate.packages);
215
+ // Validate all up front so invalid metadata fails fast, before any
216
+ // resolution does I/O.
217
+ for (const [name, update] of updateEntries) {
218
+ this.validatePackageUpdateVersion(sourcePackage, name, update);
219
+ }
220
+ const filteredUpdates = {};
221
+ // Resolve serially: resolution can prompt (pnpm strict cooldown) and append
222
+ // to minimumReleaseAgeExclude, so a serial loop avoids overlapping prompts
223
+ // and keeps packageUpdates ordering stable.
224
+ for (const [name, update] of updateEntries) {
225
+ const resolvedUpdate = {
226
+ ...update,
227
+ version: await this.resolveVersionForCascade(name, update.version),
228
+ };
229
+ this.addPackageUpdate(name, resolvedUpdate);
230
+ filteredUpdates[name] = this.packageUpdates[name];
231
+ }
232
+ return filteredUpdates;
233
+ }
234
+ async applyPendingPackageJsonUpdates() {
235
+ while (this.pendingPackageJsonUpdates.size) {
236
+ let applied = false;
237
+ const filteredUpdates = {};
238
+ for (const pending of [...this.pendingPackageJsonUpdates.values()]) {
239
+ const updates = await this.applyPackageJsonUpdate(pending.package, pending.key, pending.update);
240
+ if (Object.keys(updates).length) {
241
+ applied = true;
242
+ Object.assign(filteredUpdates, updates);
206
243
  }
207
244
  }
245
+ if (!applied) {
246
+ return;
247
+ }
208
248
  await Promise.all(Object.entries(filteredUpdates).map(([name, update]) => this.buildPackageJsonUpdates(name, update)));
209
249
  }
210
250
  }
@@ -408,7 +448,7 @@ class Migrator {
408
448
  }
409
449
  addPackageUpdate(name, packageUpdate) {
410
450
  if (!this.packageUpdates[name] ||
411
- this.gt(packageUpdate.version, this.packageUpdates[name].version)) {
451
+ !this.lt(packageUpdate.version, this.packageUpdates[name].version)) {
412
452
  this.packageUpdates[name] = packageUpdate;
413
453
  }
414
454
  }
@@ -1093,8 +1133,30 @@ async function getPackageMigrationsUsingRegistry(packageName, packageVersion) {
1093
1133
  // try to obtain the migrations from the registry directly
1094
1134
  return await downloadPackageMigrationsFromRegistry(packageName, packageVersion, migrationsConfig);
1095
1135
  }
1136
+ // Matched exactly: a hostname that merely contains one of these is a different
1137
+ // registry. registry.yarnpkg.com is npmjs' CNAME, so it serves the same
1138
+ // metadata; the two loopback literals are the spellings of a local registry
1139
+ // that the substring below cannot reach, since neither contains "localhost".
1140
+ const FULL_METADATA_REGISTRIES = [
1141
+ 'registry.npmjs.org',
1142
+ 'registry.yarnpkg.com',
1143
+ '127.0.0.1',
1144
+ '[::1]',
1145
+ ];
1146
+ // Matched as substrings, since neither names a single host: a local registry
1147
+ // can sit on a subdomain of localhost, and an Artifactory instance is
1148
+ // identified only by that word appearing somewhere in its hostname.
1149
+ const FULL_METADATA_REGISTRY_MARKERS = [
1150
+ 'localhost',
1151
+ 'artifactory',
1152
+ ];
1096
1153
  async function getPackageMigrationsConfigFromRegistry(packageName, packageVersion) {
1097
- const result = await (0, package_manager_1.packageRegistryView)(packageName, packageVersion, 'nx-migrations ng-update dist --json');
1154
+ const result = await (0, package_manager_1.packageRegistryView)(packageName, packageVersion, [
1155
+ 'nx-migrations',
1156
+ 'ng-update',
1157
+ 'dist',
1158
+ '--json',
1159
+ ]);
1098
1160
  if (!result) {
1099
1161
  return null;
1100
1162
  }
@@ -1102,9 +1164,10 @@ async function getPackageMigrationsConfigFromRegistry(packageName, packageVersio
1102
1164
  if (!json['nx-migrations'] && !json['ng-update']) {
1103
1165
  const registry = new node_url_1.URL('dist' in json ? json.dist.tarball : json.tarball)
1104
1166
  .hostname;
1105
- // Registries other than npmjs and the local registry may not support full metadata via npm view
1106
- // so throw error so that fetcher falls back to getting config via install
1107
- if (!['registry.npmjs.org', 'localhost', 'artifactory'].some((v) => registry.includes(v))) {
1167
+ // Other registries may not support full metadata via npm view; throw to
1168
+ // trigger the install fallback.
1169
+ if (!FULL_METADATA_REGISTRIES.includes(registry) &&
1170
+ !FULL_METADATA_REGISTRY_MARKERS.some((v) => registry.includes(v))) {
1108
1171
  throw new Error(`Getting migration config from registry is not supported from ${registry}`);
1109
1172
  }
1110
1173
  }
@@ -305,6 +305,11 @@ function createAPI(overrideReleaseConfig, ignoreNxJsonConfig) {
305
305
  const projectNodes = projects.map((name) => projectGraph.nodes[name]);
306
306
  if (releaseGroup.projectsRelationship === 'independent') {
307
307
  for (const project of projectNodes) {
308
+ if (!projectsVersionData[project.name] ||
309
+ (projectsVersionData[project.name].newVersion === null &&
310
+ !projectsVersionData[project.name].dockerVersion)) {
311
+ continue;
312
+ }
308
313
  let changes = null;
309
314
  if (releaseGroup.resolvedVersionPlans) {
310
315
  changes = (0, version_plan_utils_1.createChangesFromProjectsVersionPlans)(releaseGroup.resolvedVersionPlans, project.name);
@@ -46,4 +46,4 @@ export declare const release: typeof defaultClient.release;
46
46
  /**
47
47
  * @public
48
48
  */
49
- export { AfterAllProjectsVersioned, VersionActions, } from './version/version-actions';
49
+ export { AfterAllProjectsVersioned, ResolveVersionForDependency, VersionActions, } from './version/version-actions';
@@ -468,7 +468,7 @@ function getAllAuthorsForCommit(commit) {
468
468
  }
469
469
  // https://www.conventionalcommits.org/en/v1.0.0/
470
470
  // https://regex101.com/r/FSfNvA/1
471
- const ConventionalCommitRegex = /(?<type>[a-z]+)(\((?<scope>.+)\))?(?<breaking>!)?: (?<description>.+)/i;
471
+ const ConventionalCommitRegex = /^(?<type>[^\s():!]+)(?:\s*\((?<scope>.+)\))?(?<breaking>!)?: (?<description>.+)$/u;
472
472
  const CoAuthoredByRegex = /co-authored-by:\s*(?<name>.+)(<(?<email>.+)>)/gim;
473
473
  // GitHub style PR references
474
474
  const PullRequestRE = /\([ a-z]*(#\d+)\s*\)/gm;
@@ -161,6 +161,23 @@ export declare class ReleaseGraph {
161
161
  * Resolve current versions for all projects that will be processed
162
162
  */
163
163
  private resolveCurrentVersionsForProjects;
164
+ /**
165
+ * Resolve the current version of a single project via its configured
166
+ * `currentVersionResolver` (honoring `fallbackCurrentVersionResolver`),
167
+ * performing the git-tag lookup when applicable.
168
+ *
169
+ * Extracted from `resolveCurrentVersionsForProjects` so it can also be
170
+ * invoked on-demand for projects that are NOT part of `allProjectsToProcess`.
171
+ */
172
+ private resolveCurrentVersionForProject;
173
+ /**
174
+ * Resolve and cache the current version of a dependency that is not already
175
+ * being versioned. Ecosystem-specific VersionActions call this lazily when
176
+ * they need a concrete version that is absent from `dependenciesToUpdate`.
177
+ *
178
+ * @internal
179
+ */
180
+ resolveCurrentVersionForDependency(tree: Tree, projectGraph: ProjectGraph, projectName: string, preid: string): Promise<string>;
164
181
  /**
165
182
  * Build dependency relationships between release groups
166
183
  */
@@ -373,31 +373,79 @@ class ReleaseGraph {
373
373
  async resolveCurrentVersionsForProjects(tree, projectGraph, preid) {
374
374
  for (const [, releaseGroupNode] of this.groupGraph) {
375
375
  for (const projectName of releaseGroupNode.group.projects) {
376
- const projectGraphNode = projectGraph.nodes[projectName];
377
376
  if (!this.allProjectsToProcess.has(projectName)) {
378
377
  continue;
379
378
  }
380
- const versionActions = this.projectsToVersionActions.get(projectName);
381
- const finalConfigForProject = this.finalConfigsByProject.get(projectName);
382
- let latestMatchingGitTag;
383
- const releaseTagPattern = releaseGroupNode.group.releaseTag.pattern;
384
- if (finalConfigForProject.currentVersionResolver === 'git-tag') {
385
- latestMatchingGitTag = await (0, git_1.getLatestGitTagForPattern)(releaseTagPattern, {
386
- projectName: (0, git_1.sanitizeProjectNameForGitTag)(projectGraphNode.name),
387
- releaseGroupName: releaseGroupNode.group.name,
388
- }, this.resolveRepositoryTags.bind(this), {
389
- checkAllBranchesWhen: releaseGroupNode.group.releaseTag.checkAllBranchesWhen,
390
- preid: preid,
391
- requireSemver: releaseGroupNode.group.releaseTag.requireSemver,
392
- strictPreid: releaseGroupNode.group.releaseTag.strictPreid,
393
- });
394
- this.cachedLatestMatchingGitTag.set(projectName, latestMatchingGitTag);
395
- }
396
- const currentVersion = await (0, resolve_current_version_1.resolveCurrentVersion)(tree, projectGraphNode, releaseGroupNode.group, versionActions, this.projectLoggers.get(projectName), this.currentVersionsPerFixedReleaseGroup, finalConfigForProject, releaseTagPattern, latestMatchingGitTag);
379
+ const currentVersion = await this.resolveCurrentVersionForProject(tree, projectGraph, releaseGroupNode.group, projectName, preid);
397
380
  this.cachedCurrentVersions.set(projectName, currentVersion);
398
381
  }
399
382
  }
400
383
  }
384
+ /**
385
+ * Resolve the current version of a single project via its configured
386
+ * `currentVersionResolver` (honoring `fallbackCurrentVersionResolver`),
387
+ * performing the git-tag lookup when applicable.
388
+ *
389
+ * Extracted from `resolveCurrentVersionsForProjects` so it can also be
390
+ * invoked on-demand for projects that are NOT part of `allProjectsToProcess`.
391
+ */
392
+ async resolveCurrentVersionForProject(tree, projectGraph, releaseGroup, projectName, preid) {
393
+ const projectGraphNode = projectGraph.nodes[projectName];
394
+ const versionActions = this.projectsToVersionActions.get(projectName);
395
+ const finalConfigForProject = this.finalConfigsByProject.get(projectName);
396
+ let latestMatchingGitTag;
397
+ const releaseTagPattern = releaseGroup.releaseTag.pattern;
398
+ if (finalConfigForProject.currentVersionResolver === 'git-tag') {
399
+ latestMatchingGitTag = await (0, git_1.getLatestGitTagForPattern)(releaseTagPattern, {
400
+ projectName: (0, git_1.sanitizeProjectNameForGitTag)(projectGraphNode.name),
401
+ releaseGroupName: releaseGroup.name,
402
+ }, this.resolveRepositoryTags.bind(this), {
403
+ checkAllBranchesWhen: releaseGroup.releaseTag.checkAllBranchesWhen,
404
+ preid: preid,
405
+ requireSemver: releaseGroup.releaseTag.requireSemver,
406
+ strictPreid: releaseGroup.releaseTag.strictPreid,
407
+ });
408
+ this.cachedLatestMatchingGitTag.set(projectName, latestMatchingGitTag);
409
+ }
410
+ return (0, resolve_current_version_1.resolveCurrentVersion)(tree, projectGraphNode, releaseGroup, versionActions, this.projectLoggers.get(projectName), this.currentVersionsPerFixedReleaseGroup, finalConfigForProject, releaseTagPattern, latestMatchingGitTag);
411
+ }
412
+ /**
413
+ * Resolve and cache the current version of a dependency that is not already
414
+ * being versioned. Ecosystem-specific VersionActions call this lazily when
415
+ * they need a concrete version that is absent from `dependenciesToUpdate`.
416
+ *
417
+ * @internal
418
+ */
419
+ async resolveCurrentVersionForDependency(tree, projectGraph, projectName, preid) {
420
+ if (this.cachedCurrentVersions.has(projectName)) {
421
+ const currentVersion = this.cachedCurrentVersions.get(projectName);
422
+ if (currentVersion) {
423
+ return currentVersion;
424
+ }
425
+ const currentVersionResolver = this.finalConfigsByProject.get(projectName)?.currentVersionResolver;
426
+ throw new Error(`Cannot resolve a concrete current version for dependency project "${projectName}" because its "currentVersionResolver" is set to "${currentVersionResolver}" and did not resolve a version. Configure a resolver that can determine the current version.`);
427
+ }
428
+ const releaseGroup = this.projectToReleaseGroup.get(projectName);
429
+ if (!releaseGroup ||
430
+ !this.projectsToVersionActions.has(projectName) ||
431
+ !this.finalConfigsByProject.has(projectName)) {
432
+ throw new Error(`Cannot resolve a concrete current version for dependency project "${projectName}" because it is not configured for Nx Release. Include the project in an Nx Release group so that its current version resolver can be configured.`);
433
+ }
434
+ let currentVersion;
435
+ try {
436
+ currentVersion = await this.resolveCurrentVersionForProject(tree, projectGraph, releaseGroup, projectName, preid);
437
+ }
438
+ catch (err) {
439
+ const errorMessage = err instanceof Error ? err.message : String(err);
440
+ throw new Error(`Cannot resolve a concrete current version for dependency project "${projectName}". ${errorMessage}`);
441
+ }
442
+ if (!currentVersion) {
443
+ const finalConfigForProject = this.finalConfigsByProject.get(projectName);
444
+ throw new Error(`Cannot resolve a concrete current version for dependency project "${projectName}" because its "currentVersionResolver" is set to "${finalConfigForProject.currentVersionResolver}" and did not resolve a version. Configure a resolver that can determine the current version.`);
445
+ }
446
+ this.cachedCurrentVersions.set(projectName, currentVersion);
447
+ return currentVersion;
448
+ }
401
449
  /**
402
450
  * Build dependency relationships between release groups
403
451
  */
@@ -662,7 +710,11 @@ Valid values are: ${exports.validReleaseVersionPrefixes
662
710
  head: commit.shortHash,
663
711
  });
664
712
  // Use the same affected detection logic as `nx affected`
665
- affectedGraph = await (0, affected_project_graph_1.filterAffected)(projectGraph, touchedFiles);
713
+ affectedGraph = await (0, affected_project_graph_1.filterAffected)(projectGraph, touchedFiles, undefined, undefined,
714
+ // Release evaluates historical commits against the current project
715
+ // graph. A project configuration which no longer exists must not make
716
+ // every surviving release project relevant to that commit.
717
+ false);
666
718
  this.affectedGraphPerCommit.set(shortHash, affectedGraph);
667
719
  return affectedGraph;
668
720
  }
@@ -104,6 +104,12 @@ class GithubRemoteReleaseClient extends remote_release_client_1.RemoteReleaseCli
104
104
  await Promise.all([...authors.keys()].map(async (authorName) => {
105
105
  const meta = authors.get(authorName);
106
106
  for (const email of meta.email) {
107
+ // An empty email makes the URL `/users/find/`, so ungh attributes
108
+ // the commit to the "find" user rather than the real author.
109
+ // Non-emails just 404, but skip those too to avoid a wasted lookup.
110
+ if (!email || !email.includes('@')) {
111
+ continue;
112
+ }
107
113
  if (email.endsWith('@users.noreply.github.com')) {
108
114
  const match = email.match(/^(\d+\+)?([^@]+)@users\.noreply\.github\.com$/);
109
115
  if (match && match[2]) {
@@ -42,6 +42,21 @@ export declare class ReleaseGroupProcessor {
42
42
  * processing them multiple times. Used during the group traversal.
43
43
  */
44
44
  private processedGroups;
45
+ /**
46
+ * Tracks release groups that have completed all version decisions. A group
47
+ * can reach this state before its dependency manifests are updated.
48
+ */
49
+ private groupsWithFinalizedVersionDecisions;
50
+ /**
51
+ * Tracks projects whose dependency manifests must wait until all release
52
+ * groups have completed their version decisions.
53
+ */
54
+ private projectsWithDeferredDependencyUpdates;
55
+ /**
56
+ * Indicates that every release group has completed its version decisions,
57
+ * so dependency manifests can use final versions safely.
58
+ */
59
+ private allVersionDecisionsFinalized;
45
60
  /**
46
61
  * Keeps track of which projects have already had their versions bumped.
47
62
  * This is used to avoid redundant version bumping and to determine which
@@ -96,6 +111,15 @@ export declare class ReleaseGroupProcessor {
96
111
  private getCachedFinalConfigForProject;
97
112
  private calculateNewVersion;
98
113
  private updateDependenciesForProject;
114
+ private finalizeVersionDecisionsForGroup;
115
+ private finalizeAllVersionDecisions;
116
+ /**
117
+ * Resolve a dependency version when `dependenciesToUpdate` does not contain
118
+ * a concrete version for a manifest entry.
119
+ *
120
+ * @internal
121
+ */
122
+ resolveVersionForDependency(dependencyProjectName: string): Promise<string>;
99
123
  private bumpVersionForProject;
100
124
  private updateDependenciesForDependents;
101
125
  private getOriginalDependentProjects;