nx 20.0.0-beta.5 → 20.0.0-beta.7

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 (47) hide show
  1. package/.eslintrc.json +12 -2
  2. package/migrations.json +0 -37
  3. package/package.json +11 -11
  4. package/release/changelog-renderer/index.d.ts +60 -38
  5. package/release/changelog-renderer/index.js +260 -236
  6. package/src/command-line/add/add.js +2 -2
  7. package/src/command-line/nx-commands.js +31 -10
  8. package/src/command-line/release/changelog.d.ts +2 -2
  9. package/src/command-line/release/changelog.js +28 -29
  10. package/src/command-line/release/index.d.ts +5 -2
  11. package/src/command-line/release/publish.d.ts +6 -1
  12. package/src/command-line/release/publish.js +31 -25
  13. package/src/command-line/release/utils/print-changes.js +6 -4
  14. package/src/command-line/release/utils/resolve-changelog-renderer.d.ts +2 -2
  15. package/src/command-line/release/utils/resolve-changelog-renderer.js +3 -3
  16. package/src/command-line/release/utils/resolve-nx-json-error-message.js +4 -3
  17. package/src/command-line/release/version.d.ts +3 -3
  18. package/src/command-line/yargs-utils/shared-options.js +2 -2
  19. package/src/config/nx-json.d.ts +2 -1
  20. package/src/config/workspace-json-project-json.d.ts +14 -0
  21. package/src/core/graph/main.js +1 -1
  22. package/src/native/nx.wasm32-wasi.wasm +0 -0
  23. package/src/nx-cloud/utilities/axios.js +1 -2
  24. package/src/nx-cloud/utilities/onboarding.js +2 -2
  25. package/src/nx-cloud/utilities/url-shorten.js +5 -5
  26. package/src/project-graph/file-utils.d.ts +2 -2
  27. package/src/project-graph/file-utils.js +2 -2
  28. package/src/tasks-runner/cache.d.ts +2 -1
  29. package/src/tasks-runner/cache.js +10 -6
  30. package/src/tasks-runner/create-task-graph.d.ts +2 -0
  31. package/src/tasks-runner/create-task-graph.js +39 -5
  32. package/src/tasks-runner/run-command.js +15 -2
  33. package/src/tasks-runner/task-orchestrator.js +1 -1
  34. package/src/utils/command-line-utils.d.ts +3 -0
  35. package/src/utils/git-utils.js +2 -2
  36. package/src/migrations/update-15-0-0/prefix-outputs.d.ts +0 -2
  37. package/src/migrations/update-15-0-0/prefix-outputs.js +0 -49
  38. package/src/migrations/update-16-0-0/remove-nrwl-cli.d.ts +0 -2
  39. package/src/migrations/update-16-0-0/remove-nrwl-cli.js +0 -16
  40. package/src/migrations/update-16-0-0/update-depends-on-to-tokens.d.ts +0 -2
  41. package/src/migrations/update-16-0-0/update-depends-on-to-tokens.js +0 -97
  42. package/src/migrations/update-16-0-0/update-nx-cloud-runner.d.ts +0 -2
  43. package/src/migrations/update-16-0-0/update-nx-cloud-runner.js +0 -29
  44. package/src/migrations/update-16-2-0/remove-run-commands-output-path.d.ts +0 -2
  45. package/src/migrations/update-16-2-0/remove-run-commands-output-path.js +0 -45
  46. package/src/migrations/update-16-8-0/escape-dollar-sign-env-variables.d.ts +0 -12
  47. package/src/migrations/update-16-8-0/escape-dollar-sign-env-variables.js +0 -67
@@ -6,182 +6,239 @@ const github_1 = require("../../src/command-line/release/utils/github");
6
6
  // axios types and values don't seem to match
7
7
  const _axios = require("axios");
8
8
  const axios = _axios;
9
- /**
10
- * The default ChangelogRenderer implementation that nx exports for the common case of generating markdown
11
- * from the given commits and other metadata.
12
- */
13
- const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion, project, entryWhenNoChanges, changelogRenderOptions, dependencyBumps, repoSlug, conventionalCommitsConfig, repoData, }) => {
14
- const markdownLines = [];
15
- // If the current range of changes contains both a commit and its revert, we strip them both from the final list. Changes from version plans are unaffected, as they have no hashes.
16
- for (const change of changes) {
17
- if (change.type === 'revert' && change.revertedHashes) {
18
- for (const revertedHash of change.revertedHashes) {
19
- const revertedCommit = changes.find((c) => c.shortHash && revertedHash.startsWith(c.shortHash));
20
- if (revertedCommit) {
21
- changes.splice(changes.indexOf(revertedCommit), 1);
22
- changes.splice(changes.indexOf(change), 1);
23
- }
24
- }
9
+ class DefaultChangelogRenderer {
10
+ /**
11
+ * A ChangelogRenderer class takes in the determined changes and other relevant metadata
12
+ * and returns a string, or a Promise of a string of changelog contents (usually markdown).
13
+ *
14
+ * @param {Object} config The configuration object for the ChangelogRenderer
15
+ * @param {ChangelogChange[]} config.changes The collection of changes to show in the changelog
16
+ * @param {string} config.changelogEntryVersion The version for which we are rendering the current changelog entry
17
+ * @param {string | null} config.project The name of specific project to generate a changelog entry for, or `null` if the overall workspace changelog
18
+ * @param {string | false} config.entryWhenNoChanges The (already interpolated) string to use as the changelog entry when there are no changes, or `false` if no entry should be generated
19
+ * @param {boolean} config.isVersionPlans Whether or not Nx release version plans are the source of truth for the changelog entry
20
+ * @param {ChangelogRenderOptions} config.changelogRenderOptions The options specific to the ChangelogRenderer implementation
21
+ * @param {DependencyBump[]} config.dependencyBumps Optional list of additional dependency bumps that occurred as part of the release, outside of the change data
22
+ * @param {GithubRepoData} config.repoData Resolved data for the current GitHub repository
23
+ * @param {NxReleaseConfig['conventionalCommits'] | null} config.conventionalCommitsConfig The configuration for conventional commits, or null if version plans are being used
24
+ */
25
+ constructor(config) {
26
+ this.changes = this.filterChanges(config.changes, config.project);
27
+ this.changelogEntryVersion = config.changelogEntryVersion;
28
+ this.project = config.project;
29
+ this.entryWhenNoChanges = config.entryWhenNoChanges;
30
+ this.isVersionPlans = config.isVersionPlans;
31
+ this.changelogRenderOptions = config.changelogRenderOptions;
32
+ this.dependencyBumps = config.dependencyBumps;
33
+ this.repoData = config.repoData;
34
+ this.conventionalCommitsConfig = config.conventionalCommitsConfig;
35
+ this.relevantChanges = [];
36
+ this.breakingChanges = [];
37
+ this.additionalChangesForAuthorsSection = [];
38
+ }
39
+ filterChanges(changes, project) {
40
+ if (project === null) {
41
+ return changes;
25
42
  }
43
+ return changes.filter((c) => c.affectedProjects &&
44
+ (c.affectedProjects === '*' || c.affectedProjects.includes(project)));
26
45
  }
27
- let relevantChanges = changes;
28
- const breakingChanges = [];
29
- // For now to keep the interface of the changelog renderer non-breaking for v19 releases we have a somewhat indirect check for whether or not we are generating a changelog for version plans
30
- const isVersionPlans = !conventionalCommitsConfig;
31
- // Only applicable for version plans
32
- const additionalChangesForAuthorsSection = [];
33
- // Provide a default configuration for version plans to allow most of the subsequent logic to work in the same way it would for conventional commits
34
- // NOTE: The one exception is breaking/major changes, where we do not follow the same structure and instead only show the changes once
35
- if (isVersionPlans) {
36
- conventionalCommitsConfig = {
37
- types: {
38
- feat: conventional_commits_1.DEFAULT_CONVENTIONAL_COMMITS_CONFIG.types.feat,
39
- fix: conventional_commits_1.DEFAULT_CONVENTIONAL_COMMITS_CONFIG.types.fix,
40
- },
41
- };
42
- // Trim down "relevant changes" to only include non-breaking ones so that we can render them differently under version plans,
43
- // but keep track of the changes for the purposes of the authors section
44
- // TODO(v20): Clean this abstraction up as part of the larger overall refactor of changelog rendering
45
- for (let i = 0; i < relevantChanges.length; i++) {
46
- if (relevantChanges[i].isBreaking) {
47
- const change = relevantChanges[i];
48
- additionalChangesForAuthorsSection.push(change);
49
- const line = formatChange(change, changelogRenderOptions, isVersionPlans, repoData);
50
- breakingChanges.push(line);
51
- relevantChanges.splice(i, 1);
52
- }
46
+ async render() {
47
+ const sections = [];
48
+ this.preprocessChanges();
49
+ if (this.shouldRenderEmptyEntry()) {
50
+ return this.renderEmptyEntry();
51
+ }
52
+ sections.push([this.renderVersionTitle()]);
53
+ const changesByType = this.renderChangesByType();
54
+ if (changesByType.length > 0) {
55
+ sections.push(changesByType);
56
+ }
57
+ if (this.hasBreakingChanges()) {
58
+ sections.push(this.renderBreakingChanges());
59
+ }
60
+ if (this.hasDependencyBumps()) {
61
+ sections.push(this.renderDependencyBumps());
53
62
  }
63
+ if (this.shouldRenderAuthors()) {
64
+ sections.push(await this.renderAuthors());
65
+ }
66
+ // Join sections with double newlines, and trim any extra whitespace
67
+ return sections
68
+ .filter((section) => section.length > 0)
69
+ .map((section) => section.join('\n').trim())
70
+ .join('\n\n')
71
+ .trim();
54
72
  }
55
- const changeTypes = conventionalCommitsConfig.types;
56
- // workspace root level changelog
57
- if (project === null) {
58
- // No changes for the workspace
59
- if (relevantChanges.length === 0 && breakingChanges.length === 0) {
60
- if (dependencyBumps?.length) {
61
- applyAdditionalDependencyBumps({
62
- markdownLines,
63
- dependencyBumps,
64
- releaseVersion,
65
- changelogRenderOptions,
66
- });
67
- }
68
- else if (entryWhenNoChanges) {
69
- markdownLines.push('', `${createVersionTitle(releaseVersion, changelogRenderOptions)}\n\n${entryWhenNoChanges}`, '');
73
+ preprocessChanges() {
74
+ this.relevantChanges = [...this.changes];
75
+ this.breakingChanges = [];
76
+ this.additionalChangesForAuthorsSection = [];
77
+ // Filter out reverted changes
78
+ for (let i = this.relevantChanges.length - 1; i >= 0; i--) {
79
+ const change = this.relevantChanges[i];
80
+ if (change.type === 'revert' && change.revertedHashes) {
81
+ for (const revertedHash of change.revertedHashes) {
82
+ const revertedCommitIndex = this.relevantChanges.findIndex((c) => c.shortHash && revertedHash.startsWith(c.shortHash));
83
+ if (revertedCommitIndex !== -1) {
84
+ this.relevantChanges.splice(revertedCommitIndex, 1);
85
+ this.relevantChanges.splice(i, 1);
86
+ i--;
87
+ break;
88
+ }
89
+ }
70
90
  }
71
- return markdownLines.join('\n').trim();
72
91
  }
73
- const typeGroups = groupBy(relevantChanges, 'type');
74
- markdownLines.push('', createVersionTitle(releaseVersion, changelogRenderOptions), '');
75
- for (const type of Object.keys(changeTypes)) {
76
- const group = typeGroups[type];
77
- if (!group || group.length === 0) {
78
- continue;
92
+ if (this.isVersionPlans) {
93
+ this.conventionalCommitsConfig = {
94
+ types: {
95
+ feat: conventional_commits_1.DEFAULT_CONVENTIONAL_COMMITS_CONFIG.types.feat,
96
+ fix: conventional_commits_1.DEFAULT_CONVENTIONAL_COMMITS_CONFIG.types.fix,
97
+ },
98
+ };
99
+ for (let i = this.relevantChanges.length - 1; i >= 0; i--) {
100
+ if (this.relevantChanges[i].isBreaking) {
101
+ const change = this.relevantChanges[i];
102
+ this.additionalChangesForAuthorsSection.push(change);
103
+ const line = this.formatChange(change);
104
+ this.breakingChanges.push(line);
105
+ this.relevantChanges.splice(i, 1);
106
+ }
79
107
  }
80
- markdownLines.push('', '### ' + changeTypes[type].changelog.title, '');
81
- /**
82
- * In order to make the final changelog most readable, we organize changes as follows:
83
- * - By scope, where scopes are in alphabetical order (changes with no scope are listed first)
84
- * - Within a particular scope grouping, we list changes in chronological order
85
- */
86
- const changesInChronologicalOrder = group.reverse();
87
- const changesGroupedByScope = groupBy(changesInChronologicalOrder, 'scope');
88
- const scopesSortedAlphabetically = Object.keys(changesGroupedByScope).sort();
89
- for (const scope of scopesSortedAlphabetically) {
90
- const changes = changesGroupedByScope[scope];
91
- for (const change of changes) {
92
- const line = formatChange(change, changelogRenderOptions, isVersionPlans, repoData);
93
- markdownLines.push(line);
94
- if (change.isBreaking) {
95
- const breakingChangeExplanation = extractBreakingChangeExplanation(change.body);
96
- breakingChanges.push(breakingChangeExplanation
97
- ? `- ${change.scope ? `**${change.scope.trim()}:** ` : ''}${breakingChangeExplanation}`
98
- : line);
99
- }
108
+ }
109
+ else {
110
+ for (const change of this.relevantChanges) {
111
+ if (change.isBreaking) {
112
+ const breakingChangeExplanation = this.extractBreakingChangeExplanation(change.body);
113
+ this.breakingChanges.push(breakingChangeExplanation
114
+ ? `- ${change.scope ? `**${change.scope.trim()}:** ` : ''}${breakingChangeExplanation}`
115
+ : this.formatChange(change));
100
116
  }
101
117
  }
102
118
  }
103
119
  }
104
- else {
105
- // project level changelog
106
- relevantChanges = relevantChanges.filter((c) => c.affectedProjects &&
107
- (c.affectedProjects === '*' || c.affectedProjects.includes(project)));
108
- // Generating for a named project, but that project has no relevant changes in the current set of commits, exit early
109
- if (relevantChanges.length === 0 && breakingChanges.length === 0) {
110
- if (dependencyBumps?.length) {
111
- applyAdditionalDependencyBumps({
112
- markdownLines,
113
- dependencyBumps,
114
- releaseVersion,
115
- changelogRenderOptions,
116
- });
117
- }
118
- else if (entryWhenNoChanges) {
119
- markdownLines.push('', `${createVersionTitle(releaseVersion, changelogRenderOptions)}\n\n${entryWhenNoChanges}`, '');
120
- }
121
- return markdownLines.join('\n').trim();
120
+ shouldRenderEmptyEntry() {
121
+ return (this.relevantChanges.length === 0 &&
122
+ this.breakingChanges.length === 0 &&
123
+ !this.hasDependencyBumps());
124
+ }
125
+ renderEmptyEntry() {
126
+ if (this.hasDependencyBumps()) {
127
+ return [
128
+ this.renderVersionTitle(),
129
+ '',
130
+ ...this.renderDependencyBumps(),
131
+ ].join('\n');
132
+ }
133
+ else if (this.entryWhenNoChanges) {
134
+ return `${this.renderVersionTitle()}\n\n${this.entryWhenNoChanges}`;
122
135
  }
123
- markdownLines.push('', createVersionTitle(releaseVersion, changelogRenderOptions), '');
124
- const typeGroups = groupBy(
125
- // Sort the relevant changes to have the unscoped changes first, before grouping by type
126
- relevantChanges.sort((a, b) => (b.scope ? 1 : 0) - (a.scope ? 1 : 0)), 'type');
136
+ return '';
137
+ }
138
+ renderVersionTitle() {
139
+ const isMajorVersion = `${(0, semver_1.major)(this.changelogEntryVersion)}.0.0` ===
140
+ this.changelogEntryVersion.replace(/^v/, '');
141
+ let maybeDateStr = '';
142
+ if (this.changelogRenderOptions.versionTitleDate) {
143
+ const dateStr = new Date().toISOString().slice(0, 10);
144
+ maybeDateStr = ` (${dateStr})`;
145
+ }
146
+ return isMajorVersion
147
+ ? `# ${this.changelogEntryVersion}${maybeDateStr}`
148
+ : `## ${this.changelogEntryVersion}${maybeDateStr}`;
149
+ }
150
+ renderChangesByType() {
151
+ const markdownLines = [];
152
+ const typeGroups = this.groupChangesByType();
153
+ const changeTypes = this.conventionalCommitsConfig.types;
127
154
  for (const type of Object.keys(changeTypes)) {
128
155
  const group = typeGroups[type];
129
156
  if (!group || group.length === 0) {
130
157
  continue;
131
158
  }
132
159
  markdownLines.push('', `### ${changeTypes[type].changelog.title}`, '');
133
- const changesInChronologicalOrder = group.reverse();
134
- for (const change of changesInChronologicalOrder) {
135
- const line = formatChange(change, changelogRenderOptions, isVersionPlans, repoData);
136
- markdownLines.push(line + '\n');
137
- if (change.isBreaking) {
138
- const breakingChangeExplanation = extractBreakingChangeExplanation(change.body);
139
- breakingChanges.push(breakingChangeExplanation
140
- ? `- ${change.scope ? `**${change.scope.trim()}:** ` : ''}${breakingChangeExplanation}`
141
- : line);
160
+ if (this.project === null) {
161
+ const changesGroupedByScope = this.groupChangesByScope(group);
162
+ const scopesSortedAlphabetically = Object.keys(changesGroupedByScope).sort();
163
+ for (const scope of scopesSortedAlphabetically) {
164
+ const changes = changesGroupedByScope[scope];
165
+ for (const change of changes.reverse()) {
166
+ const line = this.formatChange(change);
167
+ markdownLines.push(line);
168
+ if (change.isBreaking && !this.isVersionPlans) {
169
+ const breakingChangeExplanation = this.extractBreakingChangeExplanation(change.body);
170
+ this.breakingChanges.push(breakingChangeExplanation
171
+ ? `- ${change.scope ? `**${change.scope.trim()}:** ` : ''}${breakingChangeExplanation}`
172
+ : line);
173
+ }
174
+ }
175
+ }
176
+ }
177
+ else {
178
+ // For project-specific changelogs, maintain the original order
179
+ for (const change of group) {
180
+ const line = this.formatChange(change);
181
+ markdownLines.push(line);
182
+ if (change.isBreaking && !this.isVersionPlans) {
183
+ const breakingChangeExplanation = this.extractBreakingChangeExplanation(change.body);
184
+ this.breakingChanges.push(breakingChangeExplanation
185
+ ? `- ${change.scope ? `**${change.scope.trim()}:** ` : ''}${breakingChangeExplanation}`
186
+ : line);
187
+ }
142
188
  }
143
189
  }
144
190
  }
191
+ return markdownLines;
192
+ }
193
+ hasBreakingChanges() {
194
+ return this.breakingChanges.length > 0;
145
195
  }
146
- if (breakingChanges.length > 0) {
147
- markdownLines.push('', '### ⚠️ Breaking Changes', '', ...breakingChanges);
196
+ renderBreakingChanges() {
197
+ const uniqueBreakingChanges = Array.from(new Set(this.breakingChanges));
198
+ return ['### ⚠️ Breaking Changes', '', ...uniqueBreakingChanges];
148
199
  }
149
- if (dependencyBumps?.length) {
150
- applyAdditionalDependencyBumps({
151
- markdownLines,
152
- dependencyBumps,
153
- releaseVersion,
154
- changelogRenderOptions,
200
+ hasDependencyBumps() {
201
+ return this.dependencyBumps && this.dependencyBumps.length > 0;
202
+ }
203
+ renderDependencyBumps() {
204
+ const markdownLines = ['', '### 🧱 Updated Dependencies', ''];
205
+ this.dependencyBumps.forEach(({ dependencyName, newVersion }) => {
206
+ markdownLines.push(`- Updated ${dependencyName} to ${newVersion}`);
155
207
  });
208
+ return markdownLines;
209
+ }
210
+ shouldRenderAuthors() {
211
+ return this.changelogRenderOptions.authors;
156
212
  }
157
- if (changelogRenderOptions.authors) {
213
+ async renderAuthors() {
214
+ const markdownLines = [];
158
215
  const _authors = new Map();
159
216
  for (const change of [
160
- ...relevantChanges,
161
- ...additionalChangesForAuthorsSection,
217
+ ...this.relevantChanges,
218
+ ...this.additionalChangesForAuthorsSection,
162
219
  ]) {
163
- if (!change.author) {
220
+ if (!change.authors) {
164
221
  continue;
165
222
  }
166
- const name = formatName(change.author.name);
167
- if (!name || name.includes('[bot]')) {
168
- continue;
169
- }
170
- if (_authors.has(name)) {
171
- const entry = _authors.get(name);
172
- entry.email.add(change.author.email);
173
- }
174
- else {
175
- _authors.set(name, { email: new Set([change.author.email]) });
223
+ for (const author of change.authors) {
224
+ const name = this.formatName(author.name);
225
+ if (!name || name.includes('[bot]')) {
226
+ continue;
227
+ }
228
+ if (_authors.has(name)) {
229
+ const entry = _authors.get(name);
230
+ entry.email.add(author.email);
231
+ }
232
+ else {
233
+ _authors.set(name, { email: new Set([author.email]) });
234
+ }
176
235
  }
177
236
  }
178
- // Try to map authors to github usernames
179
- if (repoData && changelogRenderOptions.mapAuthorsToGitHubUsernames) {
237
+ if (this.repoData &&
238
+ this.changelogRenderOptions.mapAuthorsToGitHubUsernames) {
180
239
  await Promise.all([..._authors.keys()].map(async (authorName) => {
181
240
  const meta = _authors.get(authorName);
182
241
  for (const email of meta.email) {
183
- // For these pseudo-anonymized emails we can just extract the Github username from before the @
184
- // It could either be in the format: username@ or github_id+username@
185
242
  if (email.endsWith('@users.noreply.github.com')) {
186
243
  const match = email.match(/^(\d+\+)?([^@]+)@users\.noreply\.github\.com$/);
187
244
  if (match && match[2]) {
@@ -189,7 +246,6 @@ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion,
189
246
  break;
190
247
  }
191
248
  }
192
- // Look up any other emails against the ungh.cc API
193
249
  const { data } = await axios
194
250
  .get(`https://ungh.cc/users/find/${email}`)
195
251
  .catch(() => ({ data: { user: null } }));
@@ -206,110 +262,78 @@ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion,
206
262
  }));
207
263
  if (authors.length > 0) {
208
264
  markdownLines.push('', '### ' + '❤️ Thank You', '', ...authors
209
- // Sort the contributors by name
210
265
  .sort((a, b) => a.name.localeCompare(b.name))
211
266
  .map((i) => {
212
- // Tag the author's Github username if we were able to resolve it so that Github adds them as a contributor
213
267
  const github = i.github ? ` @${i.github}` : '';
214
268
  return `- ${i.name}${github}`;
215
269
  }));
216
270
  }
271
+ return markdownLines;
217
272
  }
218
- return markdownLines.join('\n').trim();
219
- };
220
- exports.default = defaultChangelogRenderer;
221
- function applyAdditionalDependencyBumps({ markdownLines, dependencyBumps, releaseVersion, changelogRenderOptions, }) {
222
- if (markdownLines.length === 0) {
223
- markdownLines.push('', `${createVersionTitle(releaseVersion, changelogRenderOptions)}\n`, '');
224
- }
225
- else {
226
- markdownLines.push('');
227
- }
228
- markdownLines.push('### 🧱 Updated Dependencies\n');
229
- dependencyBumps.forEach(({ dependencyName, newVersion }) => {
230
- markdownLines.push(`- Updated ${dependencyName} to ${newVersion}`);
231
- });
232
- markdownLines.push('');
233
- }
234
- function formatName(name = '') {
235
- return name
236
- .split(' ')
237
- .map((p) => p.trim())
238
- .join(' ');
239
- }
240
- function groupBy(items, key) {
241
- const groups = {};
242
- for (const item of items) {
243
- groups[item[key]] = groups[item[key]] || [];
244
- groups[item[key]].push(item);
245
- }
246
- return groups;
247
- }
248
- function formatChange(change, changelogRenderOptions, isVersionPlans, repoData) {
249
- let description = change.description;
250
- let extraLines = [];
251
- let extraLinesStr = '';
252
- if (description.includes('\n')) {
253
- [description, ...extraLines] = description.split('\n');
254
- // Align the extra lines with the start of the description for better readability
255
- const indentation = ' ';
256
- extraLinesStr = extraLines
257
- .filter((l) => l.trim().length > 0)
258
- .map((l) => `${indentation}${l}`)
259
- .join('\n');
260
- }
261
- /**
262
- * In version plans changelogs:
263
- * - don't repeat the breaking change icon
264
- * - don't render the scope
265
- */
266
- let changeLine = '- ' +
267
- (!isVersionPlans && change.isBreaking ? '⚠️ ' : '') +
268
- (!isVersionPlans && change.scope ? `**${change.scope.trim()}:** ` : '') +
269
- description;
270
- if (repoData && changelogRenderOptions.commitReferences) {
271
- changeLine += (0, github_1.formatReferences)(change.githubReferences, repoData);
272
- }
273
- if (extraLinesStr) {
274
- changeLine += '\n\n' + extraLinesStr;
275
- }
276
- return changeLine;
277
- }
278
- /**
279
- * It is common to add further information about a breaking change in the commit body,
280
- * and it is naturally that information that should be included in the BREAKING CHANGES
281
- * section of changelog, rather than repeating the commit title/description.
282
- */
283
- function extractBreakingChangeExplanation(message) {
284
- if (!message) {
285
- return null;
273
+ formatChange(change) {
274
+ let description = change.description;
275
+ let extraLines = [];
276
+ let extraLinesStr = '';
277
+ if (description.includes('\n')) {
278
+ [description, ...extraLines] = description.split('\n');
279
+ const indentation = ' ';
280
+ extraLinesStr = extraLines
281
+ .filter((l) => l.trim().length > 0)
282
+ .map((l) => `${indentation}${l}`)
283
+ .join('\n');
284
+ }
285
+ let changeLine = '- ' +
286
+ (!this.isVersionPlans && change.isBreaking ? '⚠️ ' : '') +
287
+ (!this.isVersionPlans && change.scope
288
+ ? `**${change.scope.trim()}:** `
289
+ : '') +
290
+ description;
291
+ if (this.repoData && this.changelogRenderOptions.commitReferences) {
292
+ changeLine += (0, github_1.formatReferences)(change.githubReferences, this.repoData);
293
+ }
294
+ if (extraLinesStr) {
295
+ changeLine += '\n\n' + extraLinesStr;
296
+ }
297
+ return changeLine;
286
298
  }
287
- const breakingChangeIdentifier = 'BREAKING CHANGE:';
288
- const startIndex = message.indexOf(breakingChangeIdentifier);
289
- if (startIndex === -1) {
290
- // "BREAKING CHANGE:" not found in the message
291
- return null;
299
+ groupChangesByType() {
300
+ const typeGroups = {};
301
+ for (const change of this.relevantChanges) {
302
+ typeGroups[change.type] = typeGroups[change.type] || [];
303
+ typeGroups[change.type].push(change);
304
+ }
305
+ return typeGroups;
292
306
  }
293
- const startOfBreakingChange = startIndex + breakingChangeIdentifier.length;
294
- const endOfBreakingChange = message.indexOf('\n', startOfBreakingChange);
295
- if (endOfBreakingChange === -1) {
296
- // No newline character found, extract till the end of the message
297
- return message.substring(startOfBreakingChange).trim();
307
+ groupChangesByScope(changes) {
308
+ const scopeGroups = {};
309
+ for (const change of changes) {
310
+ const scope = change.scope || '';
311
+ scopeGroups[scope] = scopeGroups[scope] || [];
312
+ scopeGroups[scope].push(change);
313
+ }
314
+ return scopeGroups;
298
315
  }
299
- // Extract and return the breaking change message
300
- return message.substring(startOfBreakingChange, endOfBreakingChange).trim();
301
- }
302
- function createVersionTitle(version, changelogRenderOptions) {
303
- // Normalize by removing any leading `v` during comparison
304
- const isMajorVersion = `${(0, semver_1.major)(version)}.0.0` === version.replace(/^v/, '');
305
- let maybeDateStr = '';
306
- if (changelogRenderOptions.versionTitleDate) {
307
- // YYYY-MM-DD
308
- const dateStr = new Date().toISOString().slice(0, 10);
309
- maybeDateStr = ` (${dateStr})`;
316
+ extractBreakingChangeExplanation(message) {
317
+ if (!message) {
318
+ return null;
319
+ }
320
+ const breakingChangeIdentifier = 'BREAKING CHANGE:';
321
+ const startIndex = message.indexOf(breakingChangeIdentifier);
322
+ if (startIndex === -1) {
323
+ return null;
324
+ }
325
+ const startOfBreakingChange = startIndex + breakingChangeIdentifier.length;
326
+ const endOfBreakingChange = message.indexOf('\n', startOfBreakingChange);
327
+ if (endOfBreakingChange === -1) {
328
+ return message.substring(startOfBreakingChange).trim();
329
+ }
330
+ return message.substring(startOfBreakingChange, endOfBreakingChange).trim();
310
331
  }
311
- if (isMajorVersion) {
312
- return `# ${version}${maybeDateStr}`;
332
+ formatName(name = '') {
333
+ return name
334
+ .split(' ')
335
+ .map((p) => p.trim())
336
+ .join(' ');
313
337
  }
314
- return `## ${version}${maybeDateStr}`;
315
338
  }
339
+ exports.default = DefaultChangelogRenderer;
@@ -103,8 +103,8 @@ async function initializePlugin(pkgName, options, nxJson) {
103
103
  if (options.__overrides_unparsed__.length) {
104
104
  args.push(...options.__overrides_unparsed__);
105
105
  }
106
- await (0, child_process_2.runNxAsync)(`g ${pkgName}:${initGenerator} ${args.join(' ')}`, {
107
- silent: !options.verbose,
106
+ (0, child_process_2.runNxSync)(`g ${pkgName}:${initGenerator} ${args.join(' ')}`, {
107
+ stdio: [0, 1, 2],
108
108
  });
109
109
  }
110
110
  catch (e) {
@@ -29,6 +29,7 @@ const command_object_23 = require("./login/command-object");
29
29
  const command_object_24 = require("./logout/command-object");
30
30
  const command_objects_1 = require("./deprecated/command-objects");
31
31
  const command_object_25 = require("./sync/command-object");
32
+ const output_1 = require("../utils/output");
32
33
  // Ensure that the output takes up the available width of the terminal.
33
34
  yargs.wrap(yargs.terminalWidth());
34
35
  exports.parserConfiguration = {
@@ -82,26 +83,46 @@ exports.commandsObject = yargs
82
83
  .command(command_object_23.yargsLoginCommand)
83
84
  .command(command_object_24.yargsLogoutCommand)
84
85
  .command(resolveConformanceCommandObject())
86
+ .command(resolveConformanceCheckCommandObject())
85
87
  .scriptName('nx')
86
88
  .help()
87
89
  // NOTE: we handle --version in nx.ts, this just tells yargs that the option exists
88
90
  // so that it shows up in help. The default yargs implementation of --version is not
89
91
  // hit, as the implementation in nx.ts is hit first and calls process.exit(0).
90
92
  .version();
93
+ function createMissingConformanceCommand(command) {
94
+ return {
95
+ command,
96
+ // Hide from --help output in the common case of not having the plugin installed
97
+ describe: false,
98
+ handler: () => {
99
+ output_1.output.error({
100
+ title: `${command} is not available`,
101
+ bodyLines: [
102
+ `In order to use the \`nx ${command}\` command you must have an active Powerpack license and the \`@nx/powerpack-conformance\` plugin installed.`,
103
+ '',
104
+ 'To learn more, visit https://nx.dev/features/powerpack/conformance',
105
+ ],
106
+ });
107
+ process.exit(1);
108
+ },
109
+ };
110
+ }
91
111
  function resolveConformanceCommandObject() {
92
112
  try {
93
113
  const { yargsConformanceCommand } = require('@nx/powerpack-conformance');
94
114
  return yargsConformanceCommand;
95
115
  }
96
- catch (e) {
97
- return {
98
- command: 'conformance',
99
- // Hide from --help output in the common case of not having the plugin installed
100
- describe: false,
101
- handler: () => {
102
- // TODO: Add messaging to help with learning more about powerpack and conformance
103
- process.exit(1);
104
- },
105
- };
116
+ catch {
117
+ return createMissingConformanceCommand('conformance');
118
+ }
119
+ }
120
+ function resolveConformanceCheckCommandObject() {
121
+ try {
122
+ const { yargsConformanceCheckCommand, } = require('@nx/powerpack-conformance');
123
+ return yargsConformanceCheckCommand;
124
+ }
125
+ catch {
126
+ return createMissingConformanceCommand('conformance:check');
106
127
  }
107
128
  }