nx 23.0.0-beta.21 → 23.0.0-beta.23

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 (82) hide show
  1. package/dist/plugins/package-json.js +1 -1
  2. package/dist/src/adapter/angular-json.d.ts +2 -2
  3. package/dist/src/adapter/angular-json.js +0 -1
  4. package/dist/src/adapter/compat.d.ts +1 -1
  5. package/dist/src/adapter/compat.js +1 -0
  6. package/dist/src/ai/set-up-ai-agents/set-up-ai-agents.js +2 -1
  7. package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +1 -1
  8. package/dist/src/command-line/examples.js +4 -4
  9. package/dist/src/command-line/graph/graph.js +1 -1
  10. package/dist/src/command-line/init/init-v2.js +1 -1
  11. package/dist/src/command-line/migrate/agentic/prompts/generic-validation.d.ts +5 -0
  12. package/dist/src/command-line/migrate/agentic/prompts/generic-validation.js +1 -0
  13. package/dist/src/command-line/migrate/agentic/prompts/hybrid-prompt-migration.d.ts +5 -0
  14. package/dist/src/command-line/migrate/agentic/prompts/hybrid-prompt-migration.js +1 -0
  15. package/dist/src/command-line/migrate/agentic/prompts/prompt-migration.d.ts +5 -0
  16. package/dist/src/command-line/migrate/agentic/prompts/prompt-migration.js +1 -0
  17. package/dist/src/command-line/migrate/agentic/prompts/shared-rendering.d.ts +1 -0
  18. package/dist/src/command-line/migrate/agentic/prompts/shared-rendering.js +15 -0
  19. package/dist/src/command-line/migrate/agentic/run-step.d.ts +7 -0
  20. package/dist/src/command-line/migrate/agentic/run-step.js +3 -1
  21. package/dist/src/command-line/migrate/agentic/select.js +120 -32
  22. package/dist/src/command-line/migrate/command-object.d.ts +42 -0
  23. package/dist/src/command-line/migrate/command-object.js +38 -8
  24. package/dist/src/command-line/migrate/migrate-config.d.ts +27 -0
  25. package/dist/src/command-line/migrate/migrate-config.js +103 -0
  26. package/dist/src/command-line/migrate/migrate.d.ts +39 -2
  27. package/dist/src/command-line/migrate/migrate.js +203 -41
  28. package/dist/src/command-line/migrate/multi-major.js +5 -2
  29. package/dist/src/command-line/release/changelog/version-plan-filtering.d.ts +3 -1
  30. package/dist/src/command-line/release/changelog/version-plan-filtering.js +7 -3
  31. package/dist/src/command-line/release/changelog.d.ts +7 -0
  32. package/dist/src/command-line/release/changelog.js +22 -9
  33. package/dist/src/command-line/release/release.js +65 -55
  34. package/dist/src/command-line/release/utils/git.d.ts +6 -0
  35. package/dist/src/command-line/release/utils/git.js +33 -0
  36. package/dist/src/command-line/release/version/derive-specifier-from-conventional-commits.js +3 -2
  37. package/dist/src/command-line/release/version.d.ts +3 -0
  38. package/dist/src/command-line/release/version.js +13 -3
  39. package/dist/src/config/misc-interfaces.d.ts +8 -0
  40. package/dist/src/config/nx-json.d.ts +49 -0
  41. package/dist/src/core/graph/main.js +1 -1
  42. package/dist/src/daemon/server/latest-nx.js +3 -1
  43. package/dist/src/devkit-exports.d.ts +11 -11
  44. package/dist/src/devkit-exports.js +7 -4
  45. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  46. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  47. package/dist/src/plugins/js/index.d.ts +2 -2
  48. package/dist/src/plugins/js/index.js +4 -4
  49. package/dist/src/plugins/js/lock-file/lock-file.d.ts +7 -2
  50. package/dist/src/plugins/js/lock-file/lock-file.js +35 -25
  51. package/dist/src/plugins/js/project-graph/affected/lock-file-changes.d.ts +2 -4
  52. package/dist/src/plugins/js/project-graph/affected/lock-file-changes.js +121 -43
  53. package/dist/src/plugins/js/utils/register.d.ts +52 -0
  54. package/dist/src/plugins/js/utils/register.js +195 -0
  55. package/dist/src/plugins/package-json/create-nodes.d.ts +2 -2
  56. package/dist/src/plugins/package-json/create-nodes.js +2 -2
  57. package/dist/src/plugins/project-json/build-nodes/project-json.d.ts +2 -2
  58. package/dist/src/plugins/project-json/build-nodes/project-json.js +1 -1
  59. package/dist/src/project-graph/error-types.d.ts +6 -6
  60. package/dist/src/project-graph/error-types.js +1 -1
  61. package/dist/src/project-graph/file-utils.d.ts +7 -0
  62. package/dist/src/project-graph/file-utils.js +78 -10
  63. package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +2 -2
  64. package/dist/src/project-graph/plugins/isolation/messaging.d.ts +2 -2
  65. package/dist/src/project-graph/plugins/loaded-nx-plugin.d.ts +3 -3
  66. package/dist/src/project-graph/plugins/loaded-nx-plugin.js +6 -4
  67. package/dist/src/project-graph/plugins/public-api.d.ts +31 -12
  68. package/dist/src/project-graph/plugins/transpiler.js +11 -0
  69. package/dist/src/project-graph/plugins/utils.d.ts +3 -3
  70. package/dist/src/project-graph/utils/project-configuration-utils.d.ts +1 -1
  71. package/dist/src/project-graph/utils/project-configuration-utils.js +6 -17
  72. package/dist/src/tasks-runner/init-tasks-runner.d.ts +2 -2
  73. package/dist/src/tasks-runner/init-tasks-runner.js +6 -6
  74. package/dist/src/tasks-runner/task-orchestrator.d.ts +2 -2
  75. package/dist/src/tasks-runner/task-orchestrator.js +6 -6
  76. package/dist/src/utils/package-json.d.ts +3 -3
  77. package/dist/src/utils/package-json.js +9 -11
  78. package/dist/src/utils/package-manager.d.ts +13 -0
  79. package/dist/src/utils/package-manager.js +27 -0
  80. package/migrations.json +18 -9
  81. package/package.json +11 -11
  82. package/schemas/nx-schema.json +41 -0
@@ -89,7 +89,7 @@ async function getFilesAddedInCommitRange(fromSHA, toSHA, isVerbose) {
89
89
  * Resolves the "from SHA" for changelog purposes.
90
90
  * This determines the starting point for changelog generation and optional version plan filtering.
91
91
  */
92
- async function resolveChangelogFromSHA({ fromRef, tagPattern, tagPatternValues, checkAllBranchesWhen, preid, requireSemver, strictPreid, useAutomaticFromRef, resolveRepositoryTags, }) {
92
+ async function resolveChangelogFromSHA({ fromRef, tagPattern, tagPatternValues, checkAllBranchesWhen, preid, requireSemver, strictPreid, useAutomaticFromRef, resolveRepositoryTags, projectRoot, }) {
93
93
  // If user provided a from ref, resolve it to a SHA
94
94
  if (fromRef) {
95
95
  return await (0, git_1.getCommitHash)(fromRef);
@@ -104,9 +104,13 @@ async function resolveChangelogFromSHA({ fromRef, tagPattern, tagPatternValues,
104
104
  if (latestTag?.tag) {
105
105
  return await (0, git_1.getCommitHash)(latestTag.tag);
106
106
  }
107
- // Finally, if automatic from ref is enabled, use the first commit as a fallback
107
+ // Finally, if automatic from ref is enabled, use the first commit as a fallback.
108
+ // When a projectRoot is provided, scope the fallback to the project's first commit
109
+ // to avoid scanning the entire repo history for projects added after the repo was created.
108
110
  if (useAutomaticFromRef) {
109
- return await (0, git_1.getFirstGitCommit)();
111
+ return projectRoot
112
+ ? await (0, git_1.getFirstProjectCommit)(projectRoot)
113
+ : await (0, git_1.getFirstGitCommit)();
110
114
  }
111
115
  return null;
112
116
  }
@@ -1,5 +1,6 @@
1
1
  import { NxReleaseConfiguration } from '../../config/nx-json';
2
2
  import { ChangelogOptions } from './command-object';
3
+ import { NxReleaseConfig } from './config/config';
3
4
  import { ReleaseVersion } from './utils/shared';
4
5
  export interface NxReleaseChangelogResult {
5
6
  workspaceChangelog?: {
@@ -17,5 +18,11 @@ export interface NxReleaseChangelogResult {
17
18
  }
18
19
  export type { ChangelogChange } from './changelog/version-plan-utils';
19
20
  export type PostGitTask = (latestCommit: string) => Promise<void>;
21
+ /**
22
+ * Determines whether a changelog configuration will actually produce any output.
23
+ * A changelog config is effectively enabled when it would produce a changelog file
24
+ * or create a remote release.
25
+ */
26
+ export declare function isChangelogEffectivelyEnabled(config?: NxReleaseConfig['changelog']['workspaceChangelog'] | NxReleaseConfig['groups'][string]['changelog']): boolean | undefined;
20
27
  export declare const releaseChangelogCLIHandler: (args: ChangelogOptions) => Promise<number>;
21
28
  export declare function createAPI(overrideReleaseConfig: NxReleaseConfiguration, ignoreNxJsonConfig: boolean): (args: ChangelogOptions) => Promise<NxReleaseChangelogResult>;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.releaseChangelogCLIHandler = void 0;
4
+ exports.isChangelogEffectivelyEnabled = isChangelogEffectivelyEnabled;
4
5
  exports.createAPI = createAPI;
5
6
  const tslib_1 = require("tslib");
6
7
  const pc = tslib_1.__importStar(require("picocolors"));
@@ -35,6 +36,17 @@ const resolve_changelog_renderer_1 = require("./utils/resolve-changelog-renderer
35
36
  const resolve_nx_json_error_message_1 = require("./utils/resolve-nx-json-error-message");
36
37
  const shared_1 = require("./utils/shared");
37
38
  const version_plan_utils_2 = require("./utils/version-plan-utils");
39
+ /**
40
+ * Determines whether a changelog configuration will actually produce any output.
41
+ * A changelog config is effectively enabled when it would produce a changelog file
42
+ * or create a remote release.
43
+ */
44
+ function isChangelogEffectivelyEnabled(config) {
45
+ if (!config) {
46
+ return false;
47
+ }
48
+ return config.file !== false || config.createRelease !== false;
49
+ }
38
50
  const releaseChangelogCLIHandler = (args) => (0, handle_errors_1.handleErrors)(args.verbose, () => createAPI({}, false)(args));
39
51
  exports.releaseChangelogCLIHandler = releaseChangelogCLIHandler;
40
52
  function createAPI(overrideReleaseConfig, ignoreNxJsonConfig) {
@@ -100,13 +112,8 @@ function createAPI(overrideReleaseConfig, ignoreNxJsonConfig) {
100
112
  process.env.NX_RELEASE_INTERNAL_SUPPRESS_FILTER_LOG !== 'true') {
101
113
  output_1.output.note(releaseGraph.filterLog);
102
114
  }
103
- let rawVersionPlans = await (0, version_plans_1.readRawVersionPlans)();
104
- if (args.deleteVersionPlans === undefined) {
105
- // default to deleting version plans in this command instead of after versioning
106
- args.deleteVersionPlans = true;
107
- }
108
- const changelogGenerationEnabled = !!nxReleaseConfig.changelog.workspaceChangelog ||
109
- Object.values(nxReleaseConfig.groups).some((g) => g.changelog);
115
+ const changelogGenerationEnabled = isChangelogEffectivelyEnabled(nxReleaseConfig.changelog.workspaceChangelog) ||
116
+ Object.values(nxReleaseConfig.groups).some((g) => isChangelogEffectivelyEnabled(g.changelog));
110
117
  if (!changelogGenerationEnabled) {
111
118
  output_1.output.warn({
112
119
  title: `Changelogs are disabled. No changelog entries will be generated`,
@@ -116,6 +123,11 @@ function createAPI(overrideReleaseConfig, ignoreNxJsonConfig) {
116
123
  });
117
124
  return {};
118
125
  }
126
+ let rawVersionPlans = await (0, version_plans_1.readRawVersionPlans)();
127
+ if (args.deleteVersionPlans === undefined) {
128
+ // default to deleting version plans in this command instead of after versioning
129
+ args.deleteVersionPlans = true;
130
+ }
119
131
  const useAutomaticFromRef = nxReleaseConfig.changelog?.automaticFromRef || args.firstRelease;
120
132
  /**
121
133
  * For determining the versions to use within changelog files, there are a few different possibilities:
@@ -214,7 +226,7 @@ function createAPI(overrideReleaseConfig, ignoreNxJsonConfig) {
214
226
  fromSHACache.set('workspace', fromSHA);
215
227
  }
216
228
  // Helper function to get cached from SHA or resolve and cache it
217
- const getCachedFromSHA = async (cacheKey, pattern, templateValues, preid, checkAllBranchesWhen, requireSemver, strictPreid) => {
229
+ const getCachedFromSHA = async (cacheKey, pattern, templateValues, preid, checkAllBranchesWhen, requireSemver, strictPreid, projectRoot) => {
218
230
  if (fromSHACache.has(cacheKey)) {
219
231
  return fromSHACache.get(cacheKey);
220
232
  }
@@ -228,6 +240,7 @@ function createAPI(overrideReleaseConfig, ignoreNxJsonConfig) {
228
240
  requireSemver,
229
241
  strictPreid,
230
242
  useAutomaticFromRef,
243
+ projectRoot,
231
244
  });
232
245
  fromSHACache.set(cacheKey, sha);
233
246
  return sha;
@@ -296,7 +309,7 @@ function createAPI(overrideReleaseConfig, ignoreNxJsonConfig) {
296
309
  const fromSHA = await getCachedFromSHA(projectCacheKey, releaseGroup.releaseTag.pattern, {
297
310
  projectName: project.name,
298
311
  releaseGroupName: releaseGroup.name,
299
- }, projectsPreid[project.name], releaseGroup.releaseTag.checkAllBranchesWhen, releaseGroup.releaseTag.requireSemver, releaseGroup.releaseTag.strictPreid);
312
+ }, projectsPreid[project.name], releaseGroup.releaseTag.checkAllBranchesWhen, releaseGroup.releaseTag.requireSemver, releaseGroup.releaseTag.strictPreid, project.data.root);
300
313
  let commits;
301
314
  let fromRef = fromSHA;
302
315
  if (!fromRef && useAutomaticFromRef) {
@@ -84,19 +84,6 @@ function createAPI(overrideReleaseConfig, ignoreNxJsonConfig) {
84
84
  });
85
85
  // Suppress the filter log for the changelog command as it would have already been printed by the version command
86
86
  process.env.NX_RELEASE_INTERNAL_SUPPRESS_FILTER_LOG = 'true';
87
- const changelogResult = await releaseChangelog({
88
- ...args,
89
- // Re-use existing release graph
90
- releaseGraph,
91
- versionData: projectsVersionData,
92
- version: workspaceVersion,
93
- stageChanges: shouldStage,
94
- gitCommit: false,
95
- gitTag: false,
96
- gitPush: false,
97
- createRelease: false,
98
- deleteVersionPlans: false,
99
- });
100
87
  await (0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGraph.releaseGroups, Object.keys(projectGraph.nodes), args.verbose);
101
88
  // Validate version plans against the filter after resolution
102
89
  const versionPlanValidationError = (0, version_plan_utils_1.validateResolvedVersionPlansAgainstFilter)(releaseGraph.releaseGroups, releaseGraph.releaseGroupToFilteredProjects);
@@ -150,6 +137,27 @@ function createAPI(overrideReleaseConfig, ignoreNxJsonConfig) {
150
137
  verbose: args.verbose,
151
138
  });
152
139
  }
140
+ // Check if any changelog generation is actually enabled before calling releaseChangelog,
141
+ // to avoid expensive operations (project graph recreation, git log, etc.) when changelogs are disabled
142
+ const changelogGenerationEnabled = (0, changelog_1.isChangelogEffectivelyEnabled)(nxReleaseConfig.changelog.workspaceChangelog) ||
143
+ releaseGraph.releaseGroups.some((g) => (0, changelog_1.isChangelogEffectivelyEnabled)(g.changelog));
144
+ // Run changelog generation before git commit/tag so that changelog files are
145
+ // included in the same commit as the version bump
146
+ const changelogResult = changelogGenerationEnabled
147
+ ? await releaseChangelog({
148
+ ...args,
149
+ // Re-use existing release graph
150
+ releaseGraph,
151
+ versionData: projectsVersionData,
152
+ version: workspaceVersion,
153
+ stageChanges: shouldStage,
154
+ gitCommit: false,
155
+ gitTag: false,
156
+ gitPush: false,
157
+ createRelease: false,
158
+ deleteVersionPlans: false,
159
+ })
160
+ : undefined;
153
161
  if (shouldCommit) {
154
162
  output_1.output.logSingleLine(`Committing changes with git`);
155
163
  const commitMessage = nxReleaseConfig.git.commitMessage;
@@ -190,51 +198,53 @@ function createAPI(overrideReleaseConfig, ignoreNxJsonConfig) {
190
198
  });
191
199
  hasPushedChanges = true;
192
200
  }
193
- let latestCommit;
194
- if (shouldCreateWorkspaceRemoteRelease &&
195
- changelogResult.workspaceChangelog) {
196
- const remoteReleaseClient = await (0, remote_release_client_1.createRemoteReleaseClient)(
197
- // shouldCreateWorkspaceRemoteRelease() ensures that the createRelease property exists and is not false
198
- nxReleaseConfig.changelog.workspaceChangelog
199
- .createRelease);
200
- if (!hasPushedChanges) {
201
- throw new Error(`It is not possible to create a ${remoteReleaseClient.remoteReleaseProviderName} release for the workspace without pushing the changes to the remote, please ensure that you have not disabled git push in your nx release config`);
202
- }
203
- output_1.output.logSingleLine(`Creating ${remoteReleaseClient.remoteReleaseProviderName} Release`);
204
- latestCommit = await (0, git_1.getCommitHash)('HEAD');
205
- await remoteReleaseClient.createOrUpdateRelease(changelogResult.workspaceChangelog.releaseVersion, changelogResult.workspaceChangelog.contents, latestCommit, { dryRun: args.dryRun });
206
- }
207
- for (const releaseGroupName of releaseGraph.sortedReleaseGroups) {
208
- const releaseGroup = releaseGraph.releaseGroups.find((g) => g.name === releaseGroupName);
209
- if (!releaseGroup) {
210
- continue;
211
- }
212
- const shouldCreateProjectRemoteReleases = shouldCreateRemoteRelease(releaseGroup.changelog);
213
- if (shouldCreateProjectRemoteReleases &&
214
- changelogResult.projectChangelogs) {
201
+ if (changelogResult) {
202
+ let latestCommit;
203
+ if (shouldCreateWorkspaceRemoteRelease &&
204
+ changelogResult.workspaceChangelog) {
215
205
  const remoteReleaseClient = await (0, remote_release_client_1.createRemoteReleaseClient)(
216
- // shouldCreateProjectRemoteReleases() ensures that the createRelease property exists and is not false
217
- releaseGroup.changelog
206
+ // shouldCreateWorkspaceRemoteRelease() ensures that the createRelease property exists and is not false
207
+ nxReleaseConfig.changelog.workspaceChangelog
218
208
  .createRelease);
219
- const projects = args.projects?.length
220
- ? // If the user has passed a list of projects, we need to use the filtered list of projects within the release group
221
- Array.from(releaseGraph.releaseGroupToFilteredProjects.get(releaseGroup))
222
- : // Otherwise, we use the full list of projects within the release group
223
- releaseGroup.projects;
224
- const projectNodes = projects.map((name) => projectGraph.nodes[name]);
225
- for (const project of projectNodes) {
226
- const changelog = changelogResult.projectChangelogs[project.name];
227
- if (!changelog) {
228
- continue;
229
- }
230
- if (!hasPushedChanges) {
231
- throw new Error(`It is not possible to create a ${remoteReleaseClient.remoteReleaseProviderName} release for the project without pushing the changes to the remote, please ensure that you have not disabled git push in your nx release config`);
232
- }
233
- output_1.output.logSingleLine(`Creating ${remoteReleaseClient.remoteReleaseProviderName} Release`);
234
- if (!latestCommit) {
235
- latestCommit = await (0, git_1.getCommitHash)('HEAD');
209
+ if (!hasPushedChanges) {
210
+ throw new Error(`It is not possible to create a ${remoteReleaseClient.remoteReleaseProviderName} release for the workspace without pushing the changes to the remote, please ensure that you have not disabled git push in your nx release config`);
211
+ }
212
+ output_1.output.logSingleLine(`Creating ${remoteReleaseClient.remoteReleaseProviderName} Release`);
213
+ latestCommit = await (0, git_1.getCommitHash)('HEAD');
214
+ await remoteReleaseClient.createOrUpdateRelease(changelogResult.workspaceChangelog.releaseVersion, changelogResult.workspaceChangelog.contents, latestCommit, { dryRun: args.dryRun });
215
+ }
216
+ for (const releaseGroupName of releaseGraph.sortedReleaseGroups) {
217
+ const releaseGroup = releaseGraph.releaseGroups.find((g) => g.name === releaseGroupName);
218
+ if (!releaseGroup) {
219
+ continue;
220
+ }
221
+ const shouldCreateProjectRemoteReleases = shouldCreateRemoteRelease(releaseGroup.changelog);
222
+ if (shouldCreateProjectRemoteReleases &&
223
+ changelogResult.projectChangelogs) {
224
+ const remoteReleaseClient = await (0, remote_release_client_1.createRemoteReleaseClient)(
225
+ // shouldCreateProjectRemoteReleases() ensures that the createRelease property exists and is not false
226
+ releaseGroup.changelog
227
+ .createRelease);
228
+ const projects = args.projects?.length
229
+ ? // If the user has passed a list of projects, we need to use the filtered list of projects within the release group
230
+ Array.from(releaseGraph.releaseGroupToFilteredProjects.get(releaseGroup))
231
+ : // Otherwise, we use the full list of projects within the release group
232
+ releaseGroup.projects;
233
+ const projectNodes = projects.map((name) => projectGraph.nodes[name]);
234
+ for (const project of projectNodes) {
235
+ const changelog = changelogResult.projectChangelogs[project.name];
236
+ if (!changelog) {
237
+ continue;
238
+ }
239
+ if (!hasPushedChanges) {
240
+ throw new Error(`It is not possible to create a ${remoteReleaseClient.remoteReleaseProviderName} release for the project without pushing the changes to the remote, please ensure that you have not disabled git push in your nx release config`);
241
+ }
242
+ output_1.output.logSingleLine(`Creating ${remoteReleaseClient.remoteReleaseProviderName} Release`);
243
+ if (!latestCommit) {
244
+ latestCommit = await (0, git_1.getCommitHash)('HEAD');
245
+ }
246
+ await remoteReleaseClient.createOrUpdateRelease(changelog.releaseVersion, changelog.contents, latestCommit, { dryRun: args.dryRun });
236
247
  }
237
- await remoteReleaseClient.createOrUpdateRelease(changelog.releaseVersion, changelog.contents, latestCommit, { dryRun: args.dryRun });
238
248
  }
239
249
  }
240
250
  }
@@ -118,3 +118,9 @@ export declare function parseVersionPlanCommit(commit: RawGitCommit): {
118
118
  export declare function parseGitCommit(commit: RawGitCommit): GitCommit | null;
119
119
  export declare function getCommitHash(ref: string): Promise<string>;
120
120
  export declare function getFirstGitCommit(): Promise<string>;
121
+ /**
122
+ * Returns the parent of the first commit that touched the given project root,
123
+ * so that `from..HEAD` ranges include the project's creation commit.
124
+ * Falls back to getFirstGitCommit() if the project history cannot be determined.
125
+ */
126
+ export declare function getFirstProjectCommit(projectRoot: string): Promise<string>;
@@ -15,6 +15,7 @@ exports.parseVersionPlanCommit = parseVersionPlanCommit;
15
15
  exports.parseGitCommit = parseGitCommit;
16
16
  exports.getCommitHash = getCommitHash;
17
17
  exports.getFirstGitCommit = getFirstGitCommit;
18
+ exports.getFirstProjectCommit = getFirstProjectCommit;
18
19
  /**
19
20
  * Special thanks to changelogen for the original inspiration for many of these utilities:
20
21
  * https://github.com/unjs/changelogen
@@ -542,6 +543,38 @@ async function getFirstGitCommit() {
542
543
  throw new Error(`Unable to find first commit in git history`);
543
544
  }
544
545
  }
546
+ /**
547
+ * Returns the parent of the first commit that touched the given project root,
548
+ * so that `from..HEAD` ranges include the project's creation commit.
549
+ * Falls back to getFirstGitCommit() if the project history cannot be determined.
550
+ */
551
+ async function getFirstProjectCommit(projectRoot) {
552
+ try {
553
+ const result = (await (0, exec_command_1.execCommand)('git', [
554
+ 'rev-list',
555
+ '--reverse',
556
+ 'HEAD',
557
+ '--first-parent',
558
+ '--',
559
+ projectRoot,
560
+ ])).trim();
561
+ const firstCommit = result.split('\n')[0];
562
+ if (firstCommit) {
563
+ // Return the parent so the creation commit is included in from..to ranges
564
+ try {
565
+ return (await (0, exec_command_1.execCommand)('git', ['rev-parse', `${firstCommit}~1`])).trim();
566
+ }
567
+ catch {
568
+ // No parent (project was added in the repo's very first commit)
569
+ return firstCommit;
570
+ }
571
+ }
572
+ }
573
+ catch {
574
+ // fall through to fallback
575
+ }
576
+ return getFirstGitCommit();
577
+ }
545
578
  async function getGitRoot() {
546
579
  try {
547
580
  return (await (0, exec_command_1.execCommand)('git', ['rev-parse', '--show-toplevel'])).trim();
@@ -15,11 +15,12 @@ isPrerelease, latestMatchingGitTag, releaseGraph, fallbackCurrentVersionResolver
15
15
  ? [projectGraphNode.name]
16
16
  : releaseGroup.projects;
17
17
  // latestMatchingGitTag will be undefined if the current version was resolved from the disk fallback.
18
- // In this case, we want to use the first commit as the ref to be consistent with the changelog command.
18
+ // In this case, use the first commit that touched this project rather than the repo's first commit,
19
+ // to avoid scanning the entire git history for projects that were added after the repo was created.
19
20
  const previousVersionRef = latestMatchingGitTag
20
21
  ? latestMatchingGitTag.tag
21
22
  : fallbackCurrentVersionResolver === 'disk'
22
- ? await (0, git_1.getFirstGitCommit)()
23
+ ? await (0, git_1.getFirstProjectCommit)(projectGraphNode.data.root)
23
24
  : undefined;
24
25
  if (!previousVersionRef) {
25
26
  // This should never happen since the checks above should catch if the current version couldn't be resolved
@@ -1,5 +1,7 @@
1
1
  import { NxReleaseConfiguration } from '../../config/nx-json';
2
+ import type { ProjectGraph } from '../../config/project-graph';
2
3
  import { VersionOptions } from './command-object';
4
+ import { type NxReleaseConfig } from './config/config';
3
5
  import { ReleaseGraph } from './utils/release-graph';
4
6
  import { VersionData } from './utils/shared';
5
7
  export interface NxReleaseVersionResult {
@@ -23,3 +25,4 @@ export interface NxReleaseVersionResult {
23
25
  }
24
26
  export declare const releaseVersionCLIHandler: (args: VersionOptions) => Promise<number>;
25
27
  export declare function createAPI(overrideReleaseConfig: NxReleaseConfiguration, ignoreNxJsonConfig: boolean): (args: VersionOptions) => Promise<NxReleaseVersionResult>;
28
+ export declare function hasDockerReleaseConfiguration(nxReleaseConfig: NxReleaseConfig, releaseGraph: ReleaseGraph, projectGraph: ProjectGraph): boolean;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.releaseVersionCLIHandler = void 0;
4
4
  exports.createAPI = createAPI;
5
+ exports.hasDockerReleaseConfiguration = hasDockerReleaseConfiguration;
5
6
  const tslib_1 = require("tslib");
6
7
  const pc = tslib_1.__importStar(require("picocolors"));
7
8
  const node_child_process_1 = require("node:child_process");
@@ -212,17 +213,17 @@ function createAPI(overrideReleaseConfig, ignoreNxJsonConfig) {
212
213
  }, releaseGroup, true);
213
214
  }
214
215
  }
216
+ const shouldProcessDockerProjects = hasDockerReleaseConfiguration(nxReleaseConfig, releaseGraph, projectGraph);
215
217
  // TODO(colum): Remove when Docker support is no longer experimental
216
- if (nxReleaseConfig.docker ||
217
- releaseGraph.releaseGroups.some((rg) => rg.docker)) {
218
+ if (shouldProcessDockerProjects) {
218
219
  output_1.output.warn({
219
220
  title: 'Warning',
220
221
  bodyLines: [
221
222
  `Docker support is experimental. Breaking changes may occur and not adhere to semver versioning.`,
222
223
  ],
223
224
  });
225
+ await processor.processDockerProjects(args.dockerVersionScheme, args.dockerVersion);
224
226
  }
225
- await processor.processDockerProjects(args.dockerVersionScheme, args.dockerVersion);
226
227
  const versionData = processor.getVersionData();
227
228
  // Resolve any git tags as early as possible so that we can hard error in case of any duplicates before reaching the actual git command
228
229
  const gitTagValues = (args.gitTag ?? nxReleaseConfig.version.git.tag)
@@ -298,6 +299,15 @@ function createAPI(overrideReleaseConfig, ignoreNxJsonConfig) {
298
299
  };
299
300
  };
300
301
  }
302
+ function hasDockerReleaseConfiguration(nxReleaseConfig, releaseGraph, projectGraph) {
303
+ if (nxReleaseConfig.docker) {
304
+ return true;
305
+ }
306
+ if (releaseGraph.releaseGroups.some((rg) => rg.docker)) {
307
+ return true;
308
+ }
309
+ return Array.from(releaseGraph.allProjectsToProcess).some((projectName) => projectGraph.nodes[projectName]?.data.release?.docker !== undefined);
310
+ }
301
311
  function printAndFlushChanges(tree, isDryRun) {
302
312
  const changes = tree.listChanges();
303
313
  console.log('');
@@ -84,6 +84,13 @@ export interface MigrationsJsonEntry {
84
84
  factory?: string;
85
85
  prompt?: string;
86
86
  requires?: Record<string, string>;
87
+ /**
88
+ * Path to a markdown doc describing the migration, relative to the
89
+ * `migrations.json` and resolved like `implementation`/`factory`. Always
90
+ * supplementary; never stands in for them. Under `--run-migrations
91
+ * --agentic` the resolved path is passed to the agent as extra context.
92
+ */
93
+ documentation?: string;
87
94
  }
88
95
  export type MigrationDetailsWithId = GeneratedMigrationDetails & {
89
96
  id: string;
@@ -95,6 +102,7 @@ export interface GeneratedMigrationDetails {
95
102
  description: string;
96
103
  implementation?: string;
97
104
  prompt?: string;
105
+ documentation?: string;
98
106
  }
99
107
  export interface MigrationsJson {
100
108
  name?: string;
@@ -1,6 +1,8 @@
1
1
  import type ChangelogRenderer from '../../release/changelog-renderer';
2
2
  import type { ChangelogRenderOptions } from '../../release/changelog-renderer';
3
3
  import type { validReleaseVersionPrefixes } from '../command-line/release/utils/release-graph';
4
+ import type { AgentId } from '../command-line/migrate/agentic/cli-args';
5
+ import type { MigrateMode, MultiMajorMode } from '../command-line/migrate/command-object';
4
6
  import type { PackageManager } from '../utils/package-manager';
5
7
  import type { InputDefinition, TargetConfiguration, TargetDependencyConfig } from './workspace-json-project-json';
6
8
  export type ImplicitDependencyEntry<T = '*' | string[]> = {
@@ -651,6 +653,49 @@ export interface NxSyncConfiguration {
651
653
  */
652
654
  disabledTaskSyncGenerators?: string[];
653
655
  }
656
+ export interface NxMigrateConfiguration {
657
+ /**
658
+ * Whether to automatically create a git commit after each migration runs.
659
+ * Equivalent to the `--create-commits` flag. Defaults to `false`.
660
+ */
661
+ createCommits?: boolean;
662
+ /**
663
+ * Commit message prefix applied to each migration commit when commits are
664
+ * enabled (via `createCommits` or `--create-commits`). Equivalent to the
665
+ * `--commit-prefix` flag. Defaults to `"chore: [nx migration] "`.
666
+ */
667
+ commitPrefix?: string;
668
+ /**
669
+ * Restricts which packages to migrate when migrating Nx itself. Equivalent to
670
+ * the `--mode` flag.
671
+ * - `first-party`: only Nx and its plugins.
672
+ * - `third-party`: only the third-party dependencies referenced by Nx.
673
+ * - `all`: everything (default).
674
+ */
675
+ mode?: MigrateMode;
676
+ /**
677
+ * How to handle a migration that crosses more than one major version.
678
+ * Equivalent to the `--multi-major-mode` flag. The `NX_MULTI_MAJOR_MODE`
679
+ * environment variable takes precedence over this setting.
680
+ * - `direct`: migrate straight to the requested target.
681
+ * - `gradual`: migrate to the smallest recommended step.
682
+ */
683
+ multiMajorMode?: MultiMajorMode;
684
+ /**
685
+ * Default for the agentic flow used by `nx migrate --run-migrations`.
686
+ * Equivalent to the `--agentic` flag.
687
+ * - `false`: never use the agentic flow.
688
+ * - `true`: use the agentic flow and resolve the installed agent.
689
+ * - an agent id (`"claude-code"`, `"codex"`, `"opencode"`): always use that agent.
690
+ */
691
+ agentic?: boolean | AgentId;
692
+ /**
693
+ * Whether to run agent-driven validation after generator-only migrations when
694
+ * the agentic flow is enabled. Equivalent to the `--validate` flag. Defaults
695
+ * to `true` when the agentic flow is enabled.
696
+ */
697
+ validate?: boolean;
698
+ }
654
699
  /**
655
700
  * Nx.json configuration
656
701
  *
@@ -810,6 +855,10 @@ export interface NxJsonConfiguration<T = '*' | string[]> {
810
855
  * Configuration for the `nx sync` command.
811
856
  */
812
857
  sync?: NxSyncConfiguration;
858
+ /**
859
+ * Configuration for the `nx migrate` command.
860
+ */
861
+ migrate?: NxMigrateConfiguration;
813
862
  /**
814
863
  * Sets the maximum size of the local cache. Accepts a number followed by a unit (e.g. 100MB). Accepted units are B, KB, MB, and GB.
815
864
  */