nx 22.0.0-beta.3 → 22.0.0-beta.5

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 (85) hide show
  1. package/migrations.json +5 -0
  2. package/package.json +11 -11
  3. package/release/changelog-renderer/index.d.ts +1 -0
  4. package/release/changelog-renderer/index.d.ts.map +1 -1
  5. package/release/changelog-renderer/index.js +46 -15
  6. package/schemas/nx-schema.json +254 -86
  7. package/src/command-line/configure-ai-agents/command-object.d.ts +1 -1
  8. package/src/command-line/configure-ai-agents/command-object.d.ts.map +1 -1
  9. package/src/command-line/configure-ai-agents/command-object.js +18 -4
  10. package/src/command-line/configure-ai-agents/configure-ai-agents.d.ts.map +1 -1
  11. package/src/command-line/configure-ai-agents/configure-ai-agents.js +58 -31
  12. package/src/command-line/migrate/migrate.d.ts.map +1 -1
  13. package/src/command-line/migrate/migrate.js +0 -4
  14. package/src/command-line/nx-cloud/login/command-object.d.ts.map +1 -1
  15. package/src/command-line/nx-cloud/login/command-object.js +2 -2
  16. package/src/command-line/nx-cloud/logout/command-object.js +1 -1
  17. package/src/command-line/nx-commands.js +1 -1
  18. package/src/command-line/release/changelog.d.ts.map +1 -1
  19. package/src/command-line/release/changelog.js +58 -47
  20. package/src/command-line/release/command-object.d.ts +7 -3
  21. package/src/command-line/release/command-object.d.ts.map +1 -1
  22. package/src/command-line/release/config/config.d.ts +6 -2
  23. package/src/command-line/release/config/config.d.ts.map +1 -1
  24. package/src/command-line/release/config/config.js +124 -61
  25. package/src/command-line/release/config/version-plans.d.ts.map +1 -1
  26. package/src/command-line/release/config/version-plans.js +4 -1
  27. package/src/command-line/release/publish.d.ts.map +1 -1
  28. package/src/command-line/release/publish.js +35 -11
  29. package/src/command-line/release/release.d.ts.map +1 -1
  30. package/src/command-line/release/release.js +31 -30
  31. package/src/command-line/release/utils/git.d.ts +2 -2
  32. package/src/command-line/release/utils/git.d.ts.map +1 -1
  33. package/src/command-line/release/utils/git.js +5 -5
  34. package/src/command-line/release/utils/release-graph.d.ts +219 -0
  35. package/src/command-line/release/utils/release-graph.d.ts.map +1 -0
  36. package/src/command-line/release/utils/release-graph.js +658 -0
  37. package/src/command-line/release/utils/semver.d.ts +1 -2
  38. package/src/command-line/release/utils/semver.d.ts.map +1 -1
  39. package/src/command-line/release/utils/semver.js +3 -5
  40. package/src/command-line/release/utils/shared.d.ts +1 -1
  41. package/src/command-line/release/utils/shared.d.ts.map +1 -1
  42. package/src/command-line/release/utils/shared.js +53 -19
  43. package/src/command-line/release/version/release-group-processor.d.ts +3 -152
  44. package/src/command-line/release/version/release-group-processor.d.ts.map +1 -1
  45. package/src/command-line/release/version/release-group-processor.js +58 -569
  46. package/src/command-line/release/version/resolve-current-version.d.ts +1 -1
  47. package/src/command-line/release/version/resolve-current-version.d.ts.map +1 -1
  48. package/src/command-line/release/version/resolve-current-version.js +1 -1
  49. package/src/command-line/release/version/test-utils.d.ts +13 -4
  50. package/src/command-line/release/version/test-utils.d.ts.map +1 -1
  51. package/src/command-line/release/version/test-utils.js +26 -11
  52. package/src/command-line/release/version/version-actions.d.ts +12 -5
  53. package/src/command-line/release/version/version-actions.d.ts.map +1 -1
  54. package/src/command-line/release/version/version-actions.js +36 -19
  55. package/src/command-line/release/version.d.ts +6 -1
  56. package/src/command-line/release/version.d.ts.map +1 -1
  57. package/src/command-line/release/version.js +57 -28
  58. package/src/config/nx-json.d.ts +139 -58
  59. package/src/config/nx-json.d.ts.map +1 -1
  60. package/src/config/nx-json.js +8 -8
  61. package/src/core/graph/main.js +1 -1
  62. package/src/daemon/client/client.d.ts +4 -0
  63. package/src/daemon/client/client.d.ts.map +1 -1
  64. package/src/daemon/client/client.js +23 -0
  65. package/src/daemon/message-types/register-project-graph-listener.d.ts +6 -0
  66. package/src/daemon/message-types/register-project-graph-listener.d.ts.map +1 -0
  67. package/src/daemon/message-types/register-project-graph-listener.js +11 -0
  68. package/src/daemon/server/project-graph-incremental-recomputation.d.ts +3 -1
  69. package/src/daemon/server/project-graph-incremental-recomputation.d.ts.map +1 -1
  70. package/src/daemon/server/project-graph-incremental-recomputation.js +13 -5
  71. package/src/daemon/server/project-graph-listener-sockets.d.ts +8 -0
  72. package/src/daemon/server/project-graph-listener-sockets.d.ts.map +1 -0
  73. package/src/daemon/server/project-graph-listener-sockets.js +24 -0
  74. package/src/daemon/server/server.d.ts.map +1 -1
  75. package/src/daemon/server/server.js +9 -2
  76. package/src/migrations/update-22-0-0/consolidate-release-tag-config.d.ts +3 -0
  77. package/src/migrations/update-22-0-0/consolidate-release-tag-config.d.ts.map +1 -0
  78. package/src/migrations/update-22-0-0/consolidate-release-tag-config.js +100 -0
  79. package/src/native/nx.wasm32-wasi.wasm +0 -0
  80. package/src/tasks-runner/is-tui-enabled.d.ts.map +1 -1
  81. package/src/tasks-runner/is-tui-enabled.js +0 -1
  82. package/src/tasks-runner/run-command.d.ts.map +1 -1
  83. package/src/tasks-runner/run-command.js +5 -2
  84. package/src/utils/package-manager.d.ts.map +1 -1
  85. package/src/utils/package-manager.js +1 -3
@@ -0,0 +1,658 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ReleaseGraph = exports.validReleaseVersionPrefixes = void 0;
4
+ exports.createReleaseGraph = createReleaseGraph;
5
+ const config_1 = require("../config/config");
6
+ const project_logger_1 = require("../version/project-logger");
7
+ const resolve_current_version_1 = require("../version/resolve-current-version");
8
+ const topological_sort_1 = require("../version/topological-sort");
9
+ const version_actions_1 = require("../version/version-actions");
10
+ const git_1 = require("./git");
11
+ const shared_1 = require("./shared");
12
+ exports.validReleaseVersionPrefixes = ['auto', '', '~', '^', '='];
13
+ /**
14
+ * The complete release graph containing all relationships, caches, and computed data
15
+ * necessary for efficient release operations across versioning, changelog, and publishing.
16
+ *
17
+ * This class encapsulates the complex dependency graph between projects and release groups,
18
+ * providing convenient methods for querying relationships and accessing cached data.
19
+ */
20
+ class ReleaseGraph {
21
+ constructor(releaseGroups, filters) {
22
+ this.releaseGroups = releaseGroups;
23
+ this.filters = filters;
24
+ this.projectToReleaseGroup = new Map();
25
+ this.projectToDependents = new Map();
26
+ this.projectToDependencies = new Map();
27
+ this.projectToUpdateDependentsSetting = new Map();
28
+ this.groupGraph = new Map();
29
+ this.sortedReleaseGroups = [];
30
+ this.sortedProjects = new Map();
31
+ this.allProjectsConfiguredForNxRelease = new Set();
32
+ this.allProjectsToProcess = new Set();
33
+ this.finalConfigsByProject = new Map();
34
+ this.projectsToVersionActions = new Map();
35
+ this.uniqueAfterAllProjectsVersioned = new Map();
36
+ this.projectLoggers = new Map();
37
+ this.cachedCurrentVersions = new Map();
38
+ this.cachedLatestMatchingGitTag = new Map();
39
+ this.currentVersionsPerFixedReleaseGroup = new Map();
40
+ this.originalDependentProjectsPerProject = new Map();
41
+ this.releaseGroupToFilteredProjects = new Map();
42
+ this.originalFilteredProjects = new Set();
43
+ /**
44
+ * User-friendly log describing what the filter matched.
45
+ * Null if no filters were applied.
46
+ */
47
+ this.filterLog = null;
48
+ }
49
+ /**
50
+ * Initialize the graph by building all relationships and caches
51
+ * @internal - Called by createReleaseGraph(), not meant for external use
52
+ */
53
+ async init(options) {
54
+ // Step 1: Setup project to release group mapping
55
+ this.setupProjectReleaseGroupMapping();
56
+ // Step 2: Apply initial filtering to determine base set of projects and groups to process
57
+ this.applyInitialFiltering();
58
+ // Step 3: Setup projects to process and resolve version actions
59
+ await this.setupProjectsToProcess(options);
60
+ // Step 4: Precompute dependency relationships
61
+ await this.precomputeDependencyRelationships(options.tree, options.projectGraph);
62
+ // Step 5: Apply dependency-aware filtering based on updateDependents
63
+ this.applyDependencyAwareFiltering();
64
+ // Step 5: Build the group graph structure
65
+ this.buildGroupGraphStructure();
66
+ // Step 6: Resolve current versions for all projects to process (unless explicitly skipped)
67
+ if (!options.skipVersionResolution) {
68
+ await this.resolveCurrentVersionsForProjects(options.tree, options.projectGraph, options.preid ?? '');
69
+ }
70
+ // Step 7: Build dependency relationships between groups
71
+ this.buildGroupDependencyGraph();
72
+ // Step 8: Topologically sort groups and projects
73
+ this.sortedReleaseGroups = this.topologicallySortReleaseGroups();
74
+ for (const group of this.releaseGroups) {
75
+ this.sortedProjects.set(group.name, this.topologicallySortProjects(group));
76
+ }
77
+ // Step 9: Populate dependent projects data
78
+ await this.populateDependentProjectsData(options.tree, options.projectGraph);
79
+ }
80
+ /**
81
+ * Setup mapping from project to release group and cache updateDependents settings
82
+ */
83
+ setupProjectReleaseGroupMapping() {
84
+ for (const group of this.releaseGroups) {
85
+ for (const project of group.projects) {
86
+ this.projectToReleaseGroup.set(project, group);
87
+ const updateDependents = group.version?.updateDependents ||
88
+ 'always';
89
+ this.projectToUpdateDependentsSetting.set(project, updateDependents);
90
+ }
91
+ }
92
+ }
93
+ /**
94
+ * Apply initial filtering to construct releaseGroupToFilteredProjects based on filters.
95
+ * This determines the base set of projects and groups before considering dependencies.
96
+ */
97
+ applyInitialFiltering() {
98
+ const matchedReleaseGroups = [];
99
+ for (const releaseGroup of this.releaseGroups) {
100
+ // If group filter is applied and this group doesn't match, skip it entirely
101
+ if (this.filters.groups?.length &&
102
+ !this.filters.groups.includes(releaseGroup.name)) {
103
+ continue;
104
+ }
105
+ // If filtering by groups (not projects), include ALL projects in the matched group
106
+ if (this.filters.groups?.length && !this.filters.projects?.length) {
107
+ this.releaseGroupToFilteredProjects.set(releaseGroup, new Set(releaseGroup.projects));
108
+ matchedReleaseGroups.push(releaseGroup);
109
+ continue;
110
+ }
111
+ // If filtering by projects, filter down to matching projects
112
+ const filteredProjects = new Set();
113
+ for (const project of releaseGroup.projects) {
114
+ if (this.filters.projects?.length &&
115
+ !this.filters.projects.includes(project)) {
116
+ continue;
117
+ }
118
+ filteredProjects.add(project);
119
+ }
120
+ // If no filters applied or group has matching projects, include it
121
+ if (filteredProjects.size > 0 || !this.hasAnyFilters()) {
122
+ const projectsToInclude = filteredProjects.size > 0
123
+ ? filteredProjects
124
+ : new Set(releaseGroup.projects);
125
+ this.releaseGroupToFilteredProjects.set(releaseGroup, projectsToInclude);
126
+ matchedReleaseGroups.push(releaseGroup);
127
+ }
128
+ }
129
+ // Update this.releaseGroups to only include matched groups
130
+ if (this.hasAnyFilters()) {
131
+ this.releaseGroups = matchedReleaseGroups;
132
+ }
133
+ }
134
+ /**
135
+ * Check if any filters are applied
136
+ */
137
+ hasAnyFilters() {
138
+ return !!(this.filters.projects?.length || this.filters.groups?.length);
139
+ }
140
+ /**
141
+ * Setup projects to process and resolve version actions
142
+ */
143
+ async setupProjectsToProcess(options) {
144
+ const { tree, projectGraph, nxReleaseConfig, filters, firstRelease, versionActionsOptionsOverrides, } = options;
145
+ let projectsToProcess = new Set();
146
+ const resolveVersionActionsForProjectCallbacks = [];
147
+ // Precompute all projects in nx release config
148
+ for (const [groupName, group] of Object.entries(nxReleaseConfig.groups)) {
149
+ for (const project of group.projects) {
150
+ this.allProjectsConfiguredForNxRelease.add(project);
151
+ this.projectLoggers.set(project, new project_logger_1.ProjectLogger(project));
152
+ if (filters.groups?.includes(groupName)) {
153
+ projectsToProcess.add(project);
154
+ }
155
+ else if (filters.projects?.includes(project)) {
156
+ projectsToProcess.add(project);
157
+ }
158
+ const projectGraphNode = projectGraph.nodes[project];
159
+ const releaseGroup = this.projectToReleaseGroup.get(project);
160
+ const finalConfigForProject = ReleaseGraph.resolveFinalConfigForProject(releaseGroup, projectGraphNode, firstRelease, versionActionsOptionsOverrides);
161
+ this.finalConfigsByProject.set(project, finalConfigForProject);
162
+ resolveVersionActionsForProjectCallbacks.push(async () => {
163
+ const { versionActionsPath, versionActions, afterAllProjectsVersioned, } = await (0, version_actions_1.resolveVersionActionsForProject)(tree, releaseGroup, projectGraphNode, finalConfigForProject);
164
+ if (!this.uniqueAfterAllProjectsVersioned.has(versionActionsPath)) {
165
+ this.uniqueAfterAllProjectsVersioned.set(versionActionsPath, afterAllProjectsVersioned);
166
+ }
167
+ let versionActionsToUse = versionActions;
168
+ const shouldSkip = (0, shared_1.shouldSkipVersionActions)(finalConfigForProject.dockerOptions, project);
169
+ if (shouldSkip) {
170
+ versionActionsToUse = new version_actions_1.NOOP_VERSION_ACTIONS(releaseGroup, projectGraphNode, finalConfigForProject);
171
+ }
172
+ this.projectsToVersionActions.set(project, versionActionsToUse);
173
+ });
174
+ }
175
+ }
176
+ if (!filters.groups?.length && !filters.projects?.length) {
177
+ projectsToProcess = this.allProjectsConfiguredForNxRelease;
178
+ }
179
+ if (projectsToProcess.size === 0) {
180
+ throw new Error('No projects are set to be processed, please report this as a bug on https://github.com/nrwl/nx/issues');
181
+ }
182
+ this.allProjectsToProcess = new Set(projectsToProcess);
183
+ for (const cb of resolveVersionActionsForProjectCallbacks) {
184
+ await cb();
185
+ }
186
+ }
187
+ /**
188
+ * Precompute dependency relationships between all projects
189
+ */
190
+ async precomputeDependencyRelationships(tree, projectGraph) {
191
+ for (const projectName of this.allProjectsConfiguredForNxRelease) {
192
+ const versionActions = this.projectsToVersionActions.get(projectName);
193
+ if (!this.projectToDependencies.has(projectName)) {
194
+ this.projectToDependencies.set(projectName, new Set());
195
+ }
196
+ const deps = await versionActions.readDependencies(tree, projectGraph);
197
+ for (const dep of deps) {
198
+ if (!this.allProjectsConfiguredForNxRelease.has(dep.target)) {
199
+ continue;
200
+ }
201
+ this.projectToDependencies.get(projectName).add(dep.target);
202
+ if (!this.projectToDependents.has(dep.target)) {
203
+ this.projectToDependents.set(dep.target, new Set());
204
+ }
205
+ this.projectToDependents.get(dep.target).add(projectName);
206
+ }
207
+ }
208
+ }
209
+ /**
210
+ * Apply dependency-aware filtering that considers updateDependents configuration.
211
+ * This includes transitive dependents based on updateDependents setting ('always' by default, or 'auto').
212
+ */
213
+ applyDependencyAwareFiltering() {
214
+ // Track the original filtered projects before adding dependents
215
+ this.originalFilteredProjects = new Set(this.allProjectsToProcess);
216
+ if (!this.hasAnyFilters()) {
217
+ // No filtering applied, nothing to do
218
+ return;
219
+ }
220
+ // Validate filtering against fixed release groups
221
+ this.validateFilterAgainstFixedGroups();
222
+ // Find all dependents that need to be included based on updateDependents setting
223
+ this.findDependentsToProcess();
224
+ // Generate user-friendly filter log
225
+ this.generateFilterLog();
226
+ }
227
+ /**
228
+ * Validate that the filter doesn't try to isolate projects in fixed release groups
229
+ */
230
+ validateFilterAgainstFixedGroups() {
231
+ if (!this.filters.projects?.length) {
232
+ // Group filtering doesn't have this issue
233
+ return;
234
+ }
235
+ for (const releaseGroup of this.releaseGroups) {
236
+ if (releaseGroup.projectsRelationship !== 'fixed') {
237
+ continue;
238
+ }
239
+ const filteredProjectsInGroup = releaseGroup.projects.filter((p) => this.releaseGroupToFilteredProjects.get(releaseGroup)?.has(p));
240
+ if (filteredProjectsInGroup.length > 0 &&
241
+ filteredProjectsInGroup.length < releaseGroup.projects.length) {
242
+ throw new Error(`Cannot filter to a subset of projects within fixed release group "${releaseGroup.name}". ` +
243
+ `Filtered projects: [${filteredProjectsInGroup.join(', ')}], ` +
244
+ `All projects in group: [${releaseGroup.projects.join(', ')}]. ` +
245
+ `Either filter to all projects in the group, use --groups to filter by group, or change the group to "independent".`);
246
+ }
247
+ }
248
+ }
249
+ /**
250
+ * Find dependents that should be included in processing based on updateDependents configuration
251
+ */
252
+ findDependentsToProcess() {
253
+ const projectsToProcess = Array.from(this.allProjectsToProcess);
254
+ const allTrackedDependents = new Set();
255
+ const dependentsToProcess = new Set();
256
+ const additionalGroups = new Map();
257
+ // BFS traversal to find all transitive dependents
258
+ let currentLevel = [...projectsToProcess];
259
+ while (currentLevel.length > 0) {
260
+ const nextLevel = [];
261
+ const dependents = this.getAllNonImplicitDependents(currentLevel);
262
+ for (const dep of dependents) {
263
+ if (allTrackedDependents.has(dep) ||
264
+ this.allProjectsToProcess.has(dep)) {
265
+ continue;
266
+ }
267
+ allTrackedDependents.add(dep);
268
+ // Check if this dependent should be included based on updateDependents settings
269
+ const depUpdateDependentsSetting = this.projectToUpdateDependentsSetting.get(dep);
270
+ // Only include if dependent has 'always' or 'auto' (not 'never')
271
+ if (depUpdateDependentsSetting !== 'never') {
272
+ // Find which project(s) in currentLevel this dependent depends on
273
+ const shouldIncludeDependent = currentLevel.some((proj) => {
274
+ const projUpdateSetting = this.projectToUpdateDependentsSetting.get(proj);
275
+ const projDependents = this.getProjectDependents(proj);
276
+ if (!projDependents.has(dep)) {
277
+ return false;
278
+ }
279
+ // Always include if updateDependents is 'always'
280
+ if (projUpdateSetting === 'always') {
281
+ return true;
282
+ }
283
+ // For 'auto', include if in the same release group to match historical behavior
284
+ if (projUpdateSetting === 'auto') {
285
+ const projGroup = this.getReleaseGroupForProject(proj);
286
+ const depGroup = this.getReleaseGroupForProject(dep);
287
+ return projGroup && depGroup && projGroup.name === depGroup.name;
288
+ }
289
+ return false;
290
+ });
291
+ if (shouldIncludeDependent) {
292
+ dependentsToProcess.add(dep);
293
+ // Track the release group of this dependent
294
+ const depGroup = this.getReleaseGroupForProject(dep);
295
+ if (depGroup) {
296
+ // Check if this group is already in our list by name
297
+ const groupAlreadyExists = this.releaseGroups.some((g) => g.name === depGroup.name);
298
+ if (!groupAlreadyExists) {
299
+ additionalGroups.set(depGroup.name, depGroup);
300
+ }
301
+ }
302
+ }
303
+ }
304
+ nextLevel.push(dep);
305
+ }
306
+ currentLevel = nextLevel;
307
+ }
308
+ dependentsToProcess.forEach((dep) => this.allProjectsToProcess.add(dep));
309
+ // Add any additional groups and their filtered projects
310
+ additionalGroups.forEach((group) => {
311
+ // When adding groups due to dependents, clear version plans to avoid duplication
312
+ // Version plans should only be processed for groups that were explicitly included
313
+ const groupForDependents = {
314
+ ...group,
315
+ versionPlans: false,
316
+ resolvedVersionPlans: false,
317
+ };
318
+ this.releaseGroups.push(groupForDependents);
319
+ // Add the projects from this group that are actually being processed
320
+ const projectsInGroup = new Set(group.projects.filter((p) => dependentsToProcess.has(p)));
321
+ this.releaseGroupToFilteredProjects.set(groupForDependents, projectsInGroup);
322
+ });
323
+ }
324
+ /**
325
+ * Generate user-friendly log describing what the filter matched
326
+ */
327
+ generateFilterLog() {
328
+ if (this.filters.projects?.length) {
329
+ // Projects filter - only show the originally filtered projects to match old behavior
330
+ const matchedProjects = Array.from(this.originalFilteredProjects);
331
+ this.filterLog = {
332
+ title: `Your filter "${this.filters.projects.join(',')}" matched the following projects:`,
333
+ bodyLines: matchedProjects.map((p) => {
334
+ const releaseGroupForProject = this.projectToReleaseGroup.get(p);
335
+ if (!releaseGroupForProject ||
336
+ releaseGroupForProject.name === config_1.IMPLICIT_DEFAULT_RELEASE_GROUP) {
337
+ return `- ${p}`;
338
+ }
339
+ return `- ${p} (release group "${releaseGroupForProject.name}")`;
340
+ }),
341
+ };
342
+ }
343
+ // TODO: add groups filter log
344
+ }
345
+ /**
346
+ * Build the group graph structure
347
+ */
348
+ buildGroupGraphStructure() {
349
+ for (const group of this.releaseGroups) {
350
+ // Don't overwrite if already exists (may have been added during filtering)
351
+ if (!this.groupGraph.has(group.name)) {
352
+ this.groupGraph.set(group.name, {
353
+ group,
354
+ dependencies: new Set(),
355
+ dependents: new Set(),
356
+ });
357
+ }
358
+ }
359
+ }
360
+ /**
361
+ * Resolve current versions for all projects that will be processed
362
+ */
363
+ async resolveCurrentVersionsForProjects(tree, projectGraph, preid) {
364
+ for (const [, releaseGroupNode] of this.groupGraph) {
365
+ for (const projectName of releaseGroupNode.group.projects) {
366
+ const projectGraphNode = projectGraph.nodes[projectName];
367
+ if (!this.allProjectsToProcess.has(projectName)) {
368
+ continue;
369
+ }
370
+ const versionActions = this.projectsToVersionActions.get(projectName);
371
+ const finalConfigForProject = this.finalConfigsByProject.get(projectName);
372
+ let latestMatchingGitTag;
373
+ const releaseTagPattern = releaseGroupNode.group.releaseTag.pattern;
374
+ if (finalConfigForProject.currentVersionResolver === 'git-tag') {
375
+ latestMatchingGitTag = await (0, git_1.getLatestGitTagForPattern)(releaseTagPattern, {
376
+ projectName: projectGraphNode.name,
377
+ }, {
378
+ checkAllBranchesWhen: releaseGroupNode.group.releaseTag.checkAllBranchesWhen,
379
+ preid: preid,
380
+ requireSemver: releaseGroupNode.group.releaseTag.requireSemver,
381
+ strictPreid: releaseGroupNode.group.releaseTag.strictPreid,
382
+ });
383
+ this.cachedLatestMatchingGitTag.set(projectName, latestMatchingGitTag);
384
+ }
385
+ const currentVersion = await (0, resolve_current_version_1.resolveCurrentVersion)(tree, projectGraphNode, releaseGroupNode.group, versionActions, this.projectLoggers.get(projectName), this.currentVersionsPerFixedReleaseGroup, finalConfigForProject, releaseTagPattern, latestMatchingGitTag);
386
+ this.cachedCurrentVersions.set(projectName, currentVersion);
387
+ }
388
+ }
389
+ }
390
+ /**
391
+ * Build dependency relationships between release groups
392
+ */
393
+ buildGroupDependencyGraph() {
394
+ for (const [releaseGroupName, releaseGroupNode] of this.groupGraph) {
395
+ for (const projectName of releaseGroupNode.group.projects) {
396
+ const projectDeps = this.getProjectDependencies(projectName);
397
+ for (const dep of projectDeps) {
398
+ const dependencyGroup = this.getReleaseGroupNameForProject(dep);
399
+ if (dependencyGroup && dependencyGroup !== releaseGroupName) {
400
+ releaseGroupNode.dependencies.add(dependencyGroup);
401
+ // Only add to dependents if the dependency group exists in the graph
402
+ // (it may have been filtered out due to user filters)
403
+ const dependencyGroupNode = this.groupGraph.get(dependencyGroup);
404
+ if (dependencyGroupNode) {
405
+ dependencyGroupNode.dependents.add(releaseGroupName);
406
+ }
407
+ }
408
+ }
409
+ }
410
+ }
411
+ }
412
+ /**
413
+ * Topologically sort release groups
414
+ */
415
+ topologicallySortReleaseGroups() {
416
+ const groupNames = Array.from(this.groupGraph.keys());
417
+ const getGroupDependencies = (groupName) => {
418
+ const groupNode = this.groupGraph.get(groupName);
419
+ if (!groupNode) {
420
+ return [];
421
+ }
422
+ return Array.from(groupNode.dependencies);
423
+ };
424
+ return (0, topological_sort_1.topologicalSort)(groupNames, getGroupDependencies);
425
+ }
426
+ /**
427
+ * Topologically sort projects within a release group
428
+ */
429
+ topologicallySortProjects(releaseGroup) {
430
+ const projects = releaseGroup.projects.filter((p) => this.allProjectsToProcess.has(p));
431
+ const getProjectDependenciesInSameGroup = (project) => {
432
+ const deps = this.getProjectDependencies(project);
433
+ return Array.from(deps).filter((dep) => this.getReleaseGroupNameForProject(dep) === releaseGroup.name &&
434
+ this.allProjectsToProcess.has(dep));
435
+ };
436
+ return (0, topological_sort_1.topologicalSort)(projects, getProjectDependenciesInSameGroup);
437
+ }
438
+ async populateDependentProjectsData(tree, projectGraph) {
439
+ // Populate detailed dependent projects data for all projects being processed
440
+ for (const projectName of this.allProjectsToProcess) {
441
+ const dependentProjectNames = Array.from(this.getProjectDependents(projectName)).filter((dep) => this.allProjectsConfiguredForNxRelease.has(dep));
442
+ const dependentProjectsData = [];
443
+ for (const dependentProjectName of dependentProjectNames) {
444
+ const versionActions = this.projectsToVersionActions.get(dependentProjectName);
445
+ const { currentVersion, dependencyCollection } = await versionActions.readCurrentVersionOfDependency(tree, projectGraph, projectName);
446
+ dependentProjectsData.push({
447
+ source: dependentProjectName,
448
+ target: projectName,
449
+ type: 'static',
450
+ dependencyCollection,
451
+ rawVersionSpec: currentVersion,
452
+ });
453
+ }
454
+ this.originalDependentProjectsPerProject.set(projectName, dependentProjectsData);
455
+ }
456
+ }
457
+ /**
458
+ * Get all non-implicit dependents for a set of projects
459
+ */
460
+ getAllNonImplicitDependents(projects) {
461
+ return projects
462
+ .flatMap((project) => Array.from(this.getProjectDependents(project)))
463
+ .filter((dep) => !this.allProjectsToProcess.has(dep));
464
+ }
465
+ /**
466
+ * Resolve final configuration for a project
467
+ *
468
+ * NOTE: We are providing ultimate fallback values via ?? here mainly just to keep TypeScript happy.
469
+ * All default values should have been applied by this point by config.ts but the types can't know
470
+ * that for sure at this point.
471
+ */
472
+ static resolveFinalConfigForProject(releaseGroup, projectGraphNode, firstRelease, versionActionsOptionsOverrides) {
473
+ const releaseGroupVersionConfig = releaseGroup.version;
474
+ const projectVersionConfig = projectGraphNode.data.release?.version;
475
+ const projectDockerConfig = projectGraphNode.data.release?.docker;
476
+ /**
477
+ * specifierSource
478
+ *
479
+ * If the user has provided a specifier, it always takes precedence,
480
+ * so the effective specifier source is 'prompt', regardless of what
481
+ * the project or release group config says.
482
+ */
483
+ const specifierSource = projectVersionConfig?.specifierSource ??
484
+ releaseGroupVersionConfig?.specifierSource ??
485
+ 'prompt';
486
+ /**
487
+ * versionPrefix, defaults to auto
488
+ */
489
+ const versionPrefix = projectVersionConfig?.versionPrefix ??
490
+ releaseGroupVersionConfig?.versionPrefix ??
491
+ 'auto';
492
+ if (versionPrefix && !exports.validReleaseVersionPrefixes.includes(versionPrefix)) {
493
+ throw new Error(`Invalid value for versionPrefix: "${versionPrefix}"
494
+
495
+ Valid values are: ${exports.validReleaseVersionPrefixes
496
+ .map((s) => `"${s}"`)
497
+ .join(', ')}`);
498
+ }
499
+ /**
500
+ * Merge docker options configured in project with release group config,
501
+ * project level configuration should take precedence
502
+ */
503
+ const dockerOptions = Object.assign({}, releaseGroup.docker || {}, projectDockerConfig || {});
504
+ /**
505
+ * currentVersionResolver, defaults to disk
506
+ */
507
+ let currentVersionResolver = projectVersionConfig?.currentVersionResolver ??
508
+ releaseGroupVersionConfig?.currentVersionResolver ??
509
+ 'disk';
510
+ // Check if this project should skip version actions based on docker configuration
511
+ const shouldSkip = (0, shared_1.shouldSkipVersionActions)(dockerOptions, projectGraphNode.name);
512
+ if (shouldSkip) {
513
+ // If the project skips version actions, it doesn't need to resolve a current version
514
+ currentVersionResolver = 'none';
515
+ }
516
+ else if (specifierSource === 'conventional-commits' &&
517
+ currentVersionResolver !== 'git-tag') {
518
+ throw new Error(`Invalid currentVersionResolver "${currentVersionResolver}" provided for project "${projectGraphNode.name}". Must be "git-tag" when "specifierSource" is "conventional-commits"`);
519
+ }
520
+ /**
521
+ * currentVersionResolverMetadata, defaults to {}
522
+ */
523
+ const currentVersionResolverMetadata = projectVersionConfig?.currentVersionResolverMetadata ??
524
+ releaseGroupVersionConfig?.currentVersionResolverMetadata ??
525
+ {};
526
+ /**
527
+ * preserveLocalDependencyProtocols
528
+ *
529
+ * This was false by default in legacy versioning, but is true by default now.
530
+ */
531
+ const preserveLocalDependencyProtocols = projectVersionConfig?.preserveLocalDependencyProtocols ??
532
+ releaseGroupVersionConfig?.preserveLocalDependencyProtocols ??
533
+ true;
534
+ /**
535
+ * preserveMatchingDependencyRanges
536
+ *
537
+ * This was false by default until v22, but is true by default now.
538
+ */
539
+ const preserveMatchingDependencyRanges = projectVersionConfig?.preserveMatchingDependencyRanges ??
540
+ releaseGroupVersionConfig?.preserveMatchingDependencyRanges ??
541
+ true;
542
+ /**
543
+ * fallbackCurrentVersionResolver, defaults to disk when performing a first release, otherwise undefined
544
+ */
545
+ const fallbackCurrentVersionResolver = projectVersionConfig?.fallbackCurrentVersionResolver ??
546
+ releaseGroupVersionConfig?.fallbackCurrentVersionResolver ??
547
+ (firstRelease ? 'disk' : undefined);
548
+ /**
549
+ * versionActionsOptions, defaults to {}
550
+ */
551
+ let versionActionsOptions = projectVersionConfig?.versionActionsOptions ??
552
+ releaseGroupVersionConfig?.versionActionsOptions ??
553
+ {};
554
+ // Apply any optional overrides that may be passed in from the programmatic API
555
+ versionActionsOptions = {
556
+ ...versionActionsOptions,
557
+ ...(versionActionsOptionsOverrides ?? {}),
558
+ };
559
+ const manifestRootsToUpdate = (projectVersionConfig?.manifestRootsToUpdate ??
560
+ releaseGroupVersionConfig?.manifestRootsToUpdate ??
561
+ []).map((manifestRoot) => {
562
+ if (typeof manifestRoot === 'string') {
563
+ return {
564
+ path: manifestRoot,
565
+ // Apply the project level preserveLocalDependencyProtocols setting that was already resolved
566
+ preserveLocalDependencyProtocols,
567
+ };
568
+ }
569
+ return manifestRoot;
570
+ });
571
+ return {
572
+ specifierSource,
573
+ currentVersionResolver,
574
+ currentVersionResolverMetadata,
575
+ fallbackCurrentVersionResolver,
576
+ versionPrefix,
577
+ preserveLocalDependencyProtocols,
578
+ preserveMatchingDependencyRanges,
579
+ versionActionsOptions,
580
+ manifestRootsToUpdate,
581
+ dockerOptions,
582
+ };
583
+ }
584
+ /**
585
+ * Get the release group for a given project
586
+ */
587
+ getReleaseGroupForProject(projectName) {
588
+ return this.projectToReleaseGroup.get(projectName);
589
+ }
590
+ /**
591
+ * Get the release group name for a given project
592
+ */
593
+ getReleaseGroupNameForProject(projectName) {
594
+ const group = this.projectToReleaseGroup.get(projectName);
595
+ return group ? group.name : null;
596
+ }
597
+ /**
598
+ * Get the dependencies of a project
599
+ */
600
+ getProjectDependencies(projectName) {
601
+ return this.projectToDependencies.get(projectName) || new Set();
602
+ }
603
+ /**
604
+ * Get the dependents of a project (projects that depend on it)
605
+ */
606
+ getProjectDependents(projectName) {
607
+ return this.projectToDependents.get(projectName) || new Set();
608
+ }
609
+ /**
610
+ * Get the version actions for a project
611
+ */
612
+ getVersionActionsForProject(projectName) {
613
+ return this.projectsToVersionActions.get(projectName);
614
+ }
615
+ /**
616
+ * Check if a project will be processed
617
+ */
618
+ isProjectToProcess(projectName) {
619
+ return this.allProjectsToProcess.has(projectName);
620
+ }
621
+ /**
622
+ * Runs validation on resolved VersionActions instances. E.g. check that manifest files exist for all projects that will be processed.
623
+ * This should be called after preVersionCommand has run, as those commands may create manifest files that are needed for versioning.
624
+ */
625
+ async validate(tree) {
626
+ const validationPromises = [];
627
+ for (const projectName of this.allProjectsToProcess) {
628
+ const versionActions = this.projectsToVersionActions.get(projectName);
629
+ if (versionActions) {
630
+ validationPromises.push(versionActions.validate(tree));
631
+ }
632
+ }
633
+ // Validate in parallel
634
+ await Promise.all(validationPromises);
635
+ }
636
+ }
637
+ exports.ReleaseGraph = ReleaseGraph;
638
+ /**
639
+ * Creates a complete release graph by analyzing all release groups, projects, and their relationships.
640
+ *
641
+ * This function builds the graph structure, applies filtering logic that considers dependencies
642
+ * and updateDependents configuration, and caches all necessary data.
643
+ *
644
+ * The returned graph can be reused across versioning, changelog, and publishing operations.
645
+ */
646
+ async function createReleaseGraph(options) {
647
+ // Construct ReleaseGroupWithName objects from nxReleaseConfig
648
+ const releaseGroups = Object.entries(options.nxReleaseConfig.groups).map(([name, group]) => {
649
+ return {
650
+ ...group,
651
+ name,
652
+ resolvedVersionPlans: group.versionPlans ? [] : false,
653
+ };
654
+ });
655
+ const graph = new ReleaseGraph(releaseGroups, options.filters);
656
+ await graph.init(options);
657
+ return graph;
658
+ }
@@ -20,7 +20,6 @@ export declare function isValidSemverSpecifier(specifier: string): boolean;
20
20
  export declare function determineSemverChange(relevantCommits: Map<string, {
21
21
  commit: GitCommit;
22
22
  isProjectScopedCommit: boolean;
23
- }[]>, // <projectName, commits>
24
- config: NxReleaseConfig['conventionalCommits']): Map<string, SemverSpecifier | null>;
23
+ }[]>, config: NxReleaseConfig['conventionalCommits']): Map<string, SemverSpecifier | null>;
25
24
  export declare function deriveNewSemverVersion(currentSemverVersion: string, semverSpecifier: string, preid?: string): string;
26
25
  //# sourceMappingURL=semver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"semver.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nx/src/command-line/release/utils/semver.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAiB,WAAW,EAAc,MAAM,QAAQ,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,0BAAkB,eAAe;IAC/B,KAAK,IAAI;IACT,KAAK,IAAI;IACT,KAAK,IAAI;CACV;AAED,eAAO,MAAM,mBAAmB;;;;CAI/B,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,IAAI,WAAW,CAExE;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAIjE;AAGD,wBAAgB,qBAAqB,CACnC,eAAe,EAAE,GAAG,CAClB,MAAM,EACN;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,qBAAqB,EAAE,OAAO,CAAA;CAAE,EAAE,CACxD,EAAE,yBAAyB;AAC5B,MAAM,EAAE,eAAe,CAAC,qBAAqB,CAAC,GAC7C,GAAG,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC,CA0BrC;AAED,wBAAgB,sBAAsB,CACpC,oBAAoB,EAAE,MAAM,EAC5B,eAAe,EAAE,MAAM,EACvB,KAAK,CAAC,EAAE,MAAM,UA2Bf"}
1
+ {"version":3,"file":"semver.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nx/src/command-line/release/utils/semver.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAiB,WAAW,EAAc,MAAM,QAAQ,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,0BAAkB,eAAe;IAC/B,KAAK,IAAI;IACT,KAAK,IAAI;IACT,KAAK,IAAI;CACV;AAED,eAAO,MAAM,mBAAmB;;;;CAI/B,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,IAAI,WAAW,CAExE;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAIjE;AAED,wBAAgB,qBAAqB,CACnC,eAAe,EAAE,GAAG,CAClB,MAAM,EACN;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,qBAAqB,EAAE,OAAO,CAAA;CAAE,EAAE,CACxD,EACD,MAAM,EAAE,eAAe,CAAC,qBAAqB,CAAC,GAC7C,GAAG,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC,CA0BrC;AAED,wBAAgB,sBAAsB,CACpC,oBAAoB,EAAE,MAAM,EAC5B,eAAe,EAAE,MAAM,EACvB,KAAK,CAAC,EAAE,MAAM,UA2Bf"}