nx 19.7.0-canary.20240903-9039e5e → 19.7.0-canary.20240905-ccda7f9

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nx",
3
- "version": "19.7.0-canary.20240903-9039e5e",
3
+ "version": "19.7.0-canary.20240905-ccda7f9",
4
4
  "private": false,
5
5
  "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.",
6
6
  "repository": {
@@ -71,7 +71,7 @@
71
71
  "yargs-parser": "21.1.1",
72
72
  "node-machine-id": "1.1.12",
73
73
  "ora": "5.3.0",
74
- "@nrwl/tao": "19.7.0-canary.20240903-9039e5e"
74
+ "@nrwl/tao": "19.7.0-canary.20240905-ccda7f9"
75
75
  },
76
76
  "peerDependencies": {
77
77
  "@swc-node/register": "^1.8.0",
@@ -86,16 +86,16 @@
86
86
  }
87
87
  },
88
88
  "optionalDependencies": {
89
- "@nx/nx-darwin-x64": "19.7.0-canary.20240903-9039e5e",
90
- "@nx/nx-darwin-arm64": "19.7.0-canary.20240903-9039e5e",
91
- "@nx/nx-linux-x64-gnu": "19.7.0-canary.20240903-9039e5e",
92
- "@nx/nx-linux-x64-musl": "19.7.0-canary.20240903-9039e5e",
93
- "@nx/nx-win32-x64-msvc": "19.7.0-canary.20240903-9039e5e",
94
- "@nx/nx-linux-arm64-gnu": "19.7.0-canary.20240903-9039e5e",
95
- "@nx/nx-linux-arm64-musl": "19.7.0-canary.20240903-9039e5e",
96
- "@nx/nx-linux-arm-gnueabihf": "19.7.0-canary.20240903-9039e5e",
97
- "@nx/nx-win32-arm64-msvc": "19.7.0-canary.20240903-9039e5e",
98
- "@nx/nx-freebsd-x64": "19.7.0-canary.20240903-9039e5e"
89
+ "@nx/nx-darwin-x64": "19.7.0-canary.20240905-ccda7f9",
90
+ "@nx/nx-darwin-arm64": "19.7.0-canary.20240905-ccda7f9",
91
+ "@nx/nx-linux-x64-gnu": "19.7.0-canary.20240905-ccda7f9",
92
+ "@nx/nx-linux-x64-musl": "19.7.0-canary.20240905-ccda7f9",
93
+ "@nx/nx-win32-x64-msvc": "19.7.0-canary.20240905-ccda7f9",
94
+ "@nx/nx-linux-arm64-gnu": "19.7.0-canary.20240905-ccda7f9",
95
+ "@nx/nx-linux-arm64-musl": "19.7.0-canary.20240905-ccda7f9",
96
+ "@nx/nx-linux-arm-gnueabihf": "19.7.0-canary.20240905-ccda7f9",
97
+ "@nx/nx-win32-arm64-msvc": "19.7.0-canary.20240905-ccda7f9",
98
+ "@nx/nx-freebsd-x64": "19.7.0-canary.20240905-ccda7f9"
99
99
  },
100
100
  "nx-migrations": {
101
101
  "migrations": "./migrations.json",
@@ -41,7 +41,7 @@ export type ChangelogRenderer = (config: {
41
41
  changelogRenderOptions: DefaultChangelogRenderOptions;
42
42
  dependencyBumps?: DependencyBump[];
43
43
  repoSlug?: RepoSlug;
44
- conventionalCommitsConfig: NxReleaseConfig['conventionalCommits'];
44
+ conventionalCommitsConfig: NxReleaseConfig['conventionalCommits'] | null;
45
45
  }) => Promise<string> | string;
46
46
  /**
47
47
  * The specific options available to the default implementation of the ChangelogRenderer that nx exports
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const semver_1 = require("semver");
4
+ const conventional_commits_1 = require("../../src/command-line/release/config/conventional-commits");
4
5
  const github_1 = require("../../src/command-line/release/utils/github");
5
6
  // axios types and values don't seem to match
6
7
  const _axios = require("axios");
@@ -10,9 +11,7 @@ const axios = _axios;
10
11
  * from the given commits and other metadata.
11
12
  */
12
13
  const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion, project, entryWhenNoChanges, changelogRenderOptions, dependencyBumps, repoSlug, conventionalCommitsConfig, }) => {
13
- const changeTypes = conventionalCommitsConfig.types;
14
14
  const markdownLines = [];
15
- const breakingChanges = [];
16
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.
17
16
  for (const change of changes) {
18
17
  if (change.type === 'revert' && change.revertedHashes) {
@@ -26,10 +25,38 @@ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion,
26
25
  }
27
26
  }
28
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, repoSlug);
50
+ breakingChanges.push(line);
51
+ relevantChanges.splice(i, 1);
52
+ }
53
+ }
54
+ }
55
+ const changeTypes = conventionalCommitsConfig.types;
29
56
  // workspace root level changelog
30
57
  if (project === null) {
31
58
  // No changes for the workspace
32
- if (relevantChanges.length === 0) {
59
+ if (relevantChanges.length === 0 && breakingChanges.length === 0) {
33
60
  if (dependencyBumps?.length) {
34
61
  applyAdditionalDependencyBumps({
35
62
  markdownLines,
@@ -62,7 +89,7 @@ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion,
62
89
  for (const scope of scopesSortedAlphabetically) {
63
90
  const changes = changesGroupedByScope[scope];
64
91
  for (const change of changes) {
65
- const line = formatChange(change, changelogRenderOptions, repoSlug);
92
+ const line = formatChange(change, changelogRenderOptions, isVersionPlans, repoSlug);
66
93
  markdownLines.push(line);
67
94
  if (change.isBreaking) {
68
95
  const breakingChangeExplanation = extractBreakingChangeExplanation(change.body);
@@ -79,7 +106,7 @@ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion,
79
106
  relevantChanges = relevantChanges.filter((c) => c.affectedProjects &&
80
107
  (c.affectedProjects === '*' || c.affectedProjects.includes(project)));
81
108
  // Generating for a named project, but that project has no relevant changes in the current set of commits, exit early
82
- if (relevantChanges.length === 0) {
109
+ if (relevantChanges.length === 0 && breakingChanges.length === 0) {
83
110
  if (dependencyBumps?.length) {
84
111
  applyAdditionalDependencyBumps({
85
112
  markdownLines,
@@ -105,7 +132,7 @@ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion,
105
132
  markdownLines.push('', `### ${changeTypes[type].changelog.title}`, '');
106
133
  const changesInChronologicalOrder = group.reverse();
107
134
  for (const change of changesInChronologicalOrder) {
108
- const line = formatChange(change, changelogRenderOptions, repoSlug);
135
+ const line = formatChange(change, changelogRenderOptions, isVersionPlans, repoSlug);
109
136
  markdownLines.push(line + '\n');
110
137
  if (change.isBreaking) {
111
138
  const breakingChangeExplanation = extractBreakingChangeExplanation(change.body);
@@ -117,7 +144,7 @@ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion,
117
144
  }
118
145
  }
119
146
  if (breakingChanges.length > 0) {
120
- markdownLines.push('', '#### ⚠️ Breaking Changes', '', ...breakingChanges);
147
+ markdownLines.push('', '### ⚠️ Breaking Changes', '', ...breakingChanges);
121
148
  }
122
149
  if (dependencyBumps?.length) {
123
150
  applyAdditionalDependencyBumps({
@@ -129,7 +156,10 @@ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion,
129
156
  }
130
157
  if (changelogRenderOptions.authors) {
131
158
  const _authors = new Map();
132
- for (const change of relevantChanges) {
159
+ for (const change of [
160
+ ...relevantChanges,
161
+ ...additionalChangesForAuthorsSection,
162
+ ]) {
133
163
  if (!change.author) {
134
164
  continue;
135
165
  }
@@ -215,7 +245,7 @@ function groupBy(items, key) {
215
245
  }
216
246
  return groups;
217
247
  }
218
- function formatChange(change, changelogRenderOptions, repoSlug) {
248
+ function formatChange(change, changelogRenderOptions, isVersionPlans, repoSlug) {
219
249
  let description = change.description;
220
250
  let extraLines = [];
221
251
  let extraLinesStr = '';
@@ -228,9 +258,14 @@ function formatChange(change, changelogRenderOptions, repoSlug) {
228
258
  .map((l) => `${indentation}${l}`)
229
259
  .join('\n');
230
260
  }
261
+ /**
262
+ * In version plans changelogs:
263
+ * - don't repeat the breaking change icon
264
+ * - don't render the scope
265
+ */
231
266
  let changeLine = '- ' +
232
- (change.isBreaking ? '⚠️ ' : '') +
233
- (change.scope ? `**${change.scope.trim()}:** ` : '') +
267
+ (!isVersionPlans && change.isBreaking ? '⚠️ ' : '') +
268
+ (!isVersionPlans && change.scope ? `**${change.scope.trim()}:** ` : '') +
234
269
  description;
235
270
  if (repoSlug && changelogRenderOptions.commitReferences) {
236
271
  changeLine += (0, github_1.formatReferences)(change.githubReferences, repoSlug);
@@ -4,7 +4,7 @@ exports.yargsLoginCommand = void 0;
4
4
  const shared_options_1 = require("../../command-line/yargs-utils/shared-options");
5
5
  exports.yargsLoginCommand = {
6
6
  command: 'login [nxCloudUrl]',
7
- describe: 'Login to Nx Cloud',
7
+ describe: false,
8
8
  builder: (yargs) => (0, shared_options_1.withVerbose)(yargs.positional('nxCloudUrl', {
9
9
  describe: 'The Nx Cloud URL of the instance you are trying to connect to. If no positional argument is provided, this command will connect to https://cloud.nx.app.',
10
10
  type: 'string',
@@ -4,7 +4,7 @@ exports.yargsLogoutCommand = void 0;
4
4
  const shared_options_1 = require("../../command-line/yargs-utils/shared-options");
5
5
  exports.yargsLogoutCommand = {
6
6
  command: 'logout',
7
- describe: 'Logout from Nx Cloud',
7
+ describe: false,
8
8
  builder: (yargs) => (0, shared_options_1.withVerbose)(yargs),
9
9
  handler: async (args) => {
10
10
  process.exit(await (await Promise.resolve().then(() => require('./logout'))).logoutHandler(args));
@@ -81,7 +81,7 @@ function createAPI(overrideReleaseConfig) {
81
81
  process.exit(1);
82
82
  }
83
83
  const rawVersionPlans = await (0, version_plans_1.readRawVersionPlans)();
84
- (0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
84
+ await (0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes), args.verbose);
85
85
  if (args.deleteVersionPlans === undefined) {
86
86
  // default to deleting version plans in this command instead of after versioning
87
87
  args.deleteVersionPlans = true;
@@ -146,6 +146,15 @@ function createAPI(overrideReleaseConfig) {
146
146
  workspaceChangelogChanges = versionPlans
147
147
  .flatMap((vp) => {
148
148
  const releaseType = versionPlanSemverReleaseTypeToChangelogType(vp.groupVersionBump);
149
+ let githubReferences = [];
150
+ let author = undefined;
151
+ const parsedCommit = vp.commit
152
+ ? (0, git_1.parseGitCommit)(vp.commit, true)
153
+ : null;
154
+ if (parsedCommit) {
155
+ githubReferences = parsedCommit.references;
156
+ author = parsedCommit.author;
157
+ }
149
158
  const changes = !vp.triggeredByProjects
150
159
  ? {
151
160
  type: releaseType.type,
@@ -153,7 +162,8 @@ function createAPI(overrideReleaseConfig) {
153
162
  description: vp.message,
154
163
  body: '',
155
164
  isBreaking: releaseType.isBreaking,
156
- githubReferences: [],
165
+ githubReferences,
166
+ author,
157
167
  affectedProjects: '*',
158
168
  }
159
169
  : vp.triggeredByProjects.map((project) => {
@@ -162,9 +172,9 @@ function createAPI(overrideReleaseConfig) {
162
172
  scope: project,
163
173
  description: vp.message,
164
174
  body: '',
165
- // TODO: what about github references?
166
175
  isBreaking: releaseType.isBreaking,
167
- githubReferences: [],
176
+ githubReferences,
177
+ author,
168
178
  affectedProjects: [project],
169
179
  };
170
180
  });
@@ -301,6 +311,15 @@ function createAPI(overrideReleaseConfig) {
301
311
  return null;
302
312
  }
303
313
  const releaseType = versionPlanSemverReleaseTypeToChangelogType(bumpForProject);
314
+ let githubReferences = [];
315
+ let author = undefined;
316
+ const parsedCommit = vp.commit
317
+ ? (0, git_1.parseGitCommit)(vp.commit, true)
318
+ : null;
319
+ if (parsedCommit) {
320
+ githubReferences = parsedCommit.references;
321
+ author = parsedCommit.author;
322
+ }
304
323
  return {
305
324
  type: releaseType.type,
306
325
  scope: project.name,
@@ -308,8 +327,8 @@ function createAPI(overrideReleaseConfig) {
308
327
  body: '',
309
328
  isBreaking: releaseType.isBreaking,
310
329
  affectedProjects: Object.keys(vp.projectVersionBumps),
311
- // TODO: can we include github references when using version plans?
312
- githubReferences: [],
330
+ githubReferences,
331
+ author,
313
332
  };
314
333
  })
315
334
  .filter(Boolean);
@@ -397,6 +416,15 @@ function createAPI(overrideReleaseConfig) {
397
416
  changes = releaseGroup.resolvedVersionPlans
398
417
  .flatMap((vp) => {
399
418
  const releaseType = versionPlanSemverReleaseTypeToChangelogType(vp.groupVersionBump);
419
+ let githubReferences = [];
420
+ let author = undefined;
421
+ const parsedCommit = vp.commit
422
+ ? (0, git_1.parseGitCommit)(vp.commit, true)
423
+ : null;
424
+ if (parsedCommit) {
425
+ githubReferences = parsedCommit.references;
426
+ author = parsedCommit.author;
427
+ }
400
428
  const changes = !vp.triggeredByProjects
401
429
  ? {
402
430
  type: releaseType.type,
@@ -404,7 +432,8 @@ function createAPI(overrideReleaseConfig) {
404
432
  description: vp.message,
405
433
  body: '',
406
434
  isBreaking: releaseType.isBreaking,
407
- githubReferences: [],
435
+ githubReferences,
436
+ author,
408
437
  affectedProjects: '*',
409
438
  }
410
439
  : vp.triggeredByProjects.map((project) => {
@@ -413,9 +442,9 @@ function createAPI(overrideReleaseConfig) {
413
442
  scope: project,
414
443
  description: vp.message,
415
444
  body: '',
416
- // TODO: what about github references?
417
445
  isBreaking: releaseType.isBreaking,
418
- githubReferences: [],
446
+ githubReferences,
447
+ author,
419
448
  affectedProjects: [project],
420
449
  };
421
450
  });
@@ -579,7 +608,7 @@ async function applyChangesAndExit(args, nxReleaseConfig, tree, toSHA, postGitTa
579
608
  }
580
609
  const changedFiles = changes.map((f) => f.path);
581
610
  let deletedFiles = [];
582
- if (args.deleteVersionPlans && !args.dryRun) {
611
+ if (args.deleteVersionPlans) {
583
612
  const planFiles = new Set();
584
613
  releaseGroups.forEach((group) => {
585
614
  if (group.resolvedVersionPlans) {
@@ -811,7 +840,9 @@ async function generateChangelogForProjects({ tree, args, projectGraph, changes,
811
840
  })
812
841
  : false,
813
842
  changelogRenderOptions: config.renderOptions,
814
- conventionalCommitsConfig: nxReleaseConfig.conventionalCommits,
843
+ conventionalCommitsConfig: releaseGroup.versionPlans
844
+ ? null
845
+ : nxReleaseConfig.conventionalCommits,
815
846
  dependencyBumps: projectToAdditionalDependencyBumps.get(project.name),
816
847
  });
817
848
  /**
@@ -39,6 +39,7 @@ export type PublishOptions = NxReleaseArgs & Partial<RunManyOptions> & {
39
39
  } & FirstReleaseArgs & {
40
40
  registry?: string;
41
41
  tag?: string;
42
+ access?: string;
42
43
  otp?: number;
43
44
  };
44
45
  export type PlanOptions = NxReleaseArgs & {
@@ -187,6 +187,11 @@ const publishCommand = {
187
187
  .option('tag', {
188
188
  type: 'string',
189
189
  description: 'The distribution tag to apply to the published package',
190
+ })
191
+ .option('access', {
192
+ type: 'string',
193
+ choices: ['public', 'restricted'],
194
+ description: 'Overrides the access level of the published package. Unscoped packages cannot be set to restricted. See the npm publish documentation for more information.',
190
195
  })
191
196
  .option('otp', {
192
197
  type: 'number',
@@ -203,10 +208,7 @@ const publishCommand = {
203
208
  const planCommand = {
204
209
  command: 'plan [bump]',
205
210
  aliases: ['pl'],
206
- // TODO: Remove this when docs are added
207
- // Create a plan to pick a new version and generate a changelog entry.
208
- // Hidden for now until the feature is more stable
209
- describe: false,
211
+ describe: 'Create a version plan file to specify the desired semver bump for one or more projects or groups, as well as the relevant changelog entry',
210
212
  builder: (yargs) => (0, shared_options_1.withAffectedOptions)(yargs)
211
213
  .positional('bump', {
212
214
  type: 'string',
@@ -242,10 +244,7 @@ const planCommand = {
242
244
  };
243
245
  const planCheckCommand = {
244
246
  command: 'plan:check',
245
- // TODO: Remove this when docs are added
246
- // Create a plan to pick a new version and generate a changelog entry.
247
- // Hidden for now until the feature is more stable
248
- describe: false,
247
+ describe: 'Ensure that all touched projects have an applicable version plan created for them',
249
248
  builder: (yargs) => (0, shared_options_1.withAffectedOptions)(yargs),
250
249
  handler: async (args) => {
251
250
  const release = await Promise.resolve().then(() => require('./plan-check'));
@@ -1,4 +1,5 @@
1
1
  import { ReleaseType } from 'semver';
2
+ import { RawGitCommit } from '../utils/git';
2
3
  import { ReleaseGroupWithName } from './filter-release-groups';
3
4
  export interface VersionPlanFile {
4
5
  absolutePath: string;
@@ -12,9 +13,21 @@ export interface RawVersionPlan extends VersionPlanFile {
12
13
  }
13
14
  export interface VersionPlan extends VersionPlanFile {
14
15
  message: string;
16
+ /**
17
+ * The commit that added the version plan file, will be null if the file was never committed.
18
+ * For optimal performance, we don't apply it at the time of reading the raw contents, because
19
+ * it hasn't yet passed further validation at that point.
20
+ */
21
+ commit: RawGitCommit | null;
15
22
  }
16
23
  export interface GroupVersionPlan extends VersionPlan {
17
24
  groupVersionBump: ReleaseType;
25
+ /**
26
+ * The commit that added the version plan file, will be null if the file was never committed.
27
+ * For optimal performance, we don't apply it at the time of reading the raw contents, because.
28
+ * it hasn't yet passed validation.
29
+ */
30
+ commit: RawGitCommit | null;
18
31
  /**
19
32
  * Will not be set if the group name was the trigger, otherwise will be a list of
20
33
  * all the individual project names explicitly found in the version plan file.
@@ -25,5 +38,5 @@ export interface ProjectsVersionPlan extends VersionPlan {
25
38
  projectVersionBumps: Record<string, ReleaseType>;
26
39
  }
27
40
  export declare function readRawVersionPlans(): Promise<RawVersionPlan[]>;
28
- export declare function setResolvedVersionPlansOnGroups(rawVersionPlans: RawVersionPlan[], releaseGroups: ReleaseGroupWithName[], allProjectNamesInWorkspace: string[]): ReleaseGroupWithName[];
41
+ export declare function setResolvedVersionPlansOnGroups(rawVersionPlans: RawVersionPlan[], releaseGroups: ReleaseGroupWithName[], allProjectNamesInWorkspace: string[], isVerbose: boolean): Promise<ReleaseGroupWithName[]>;
29
42
  export declare function getVersionPlansAbsolutePath(): string;
@@ -5,6 +5,7 @@ exports.setResolvedVersionPlansOnGroups = setResolvedVersionPlansOnGroups;
5
5
  exports.getVersionPlansAbsolutePath = getVersionPlansAbsolutePath;
6
6
  const fs_1 = require("fs");
7
7
  const fs_extra_1 = require("fs-extra");
8
+ const node_child_process_1 = require("node:child_process");
8
9
  const path_1 = require("path");
9
10
  const semver_1 = require("semver");
10
11
  const workspace_root_1 = require("../../../utils/workspace-root");
@@ -35,7 +36,7 @@ async function readRawVersionPlans() {
35
36
  }
36
37
  return versionPlans;
37
38
  }
38
- function setResolvedVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNamesInWorkspace) {
39
+ async function setResolvedVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNamesInWorkspace, isVerbose) {
39
40
  const groupsByName = releaseGroups.reduce((acc, group) => acc.set(group.name, group), new Map());
40
41
  const isDefaultGroup = isDefault(releaseGroups);
41
42
  for (const rawVersionPlan of rawVersionPlans) {
@@ -88,6 +89,7 @@ function setResolvedVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProj
88
89
  createdOnMs: rawVersionPlan.createdOnMs,
89
90
  message: rawVersionPlan.message,
90
91
  groupVersionBump: value,
92
+ commit: await getCommitForVersionPlanFile(rawVersionPlan, isVerbose),
91
93
  });
92
94
  }
93
95
  }
@@ -130,6 +132,7 @@ function setResolvedVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProj
130
132
  projectVersionBumps: {
131
133
  [key]: value,
132
134
  },
135
+ commit: await getCommitForVersionPlanFile(rawVersionPlan, isVerbose),
133
136
  });
134
137
  }
135
138
  }
@@ -161,6 +164,7 @@ function setResolvedVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProj
161
164
  // but we track the projects that triggered the version bump so that we can accurately produce changelog entries.
162
165
  groupVersionBump: value,
163
166
  triggeredByProjects: [key],
167
+ commit: await getCommitForVersionPlanFile(rawVersionPlan, isVerbose),
164
168
  });
165
169
  }
166
170
  }
@@ -185,3 +189,31 @@ function getVersionPlansAbsolutePath() {
185
189
  function isReleaseType(value) {
186
190
  return semver_1.RELEASE_TYPES.includes(value);
187
191
  }
192
+ async function getCommitForVersionPlanFile(rawVersionPlan, isVerbose) {
193
+ return new Promise((resolve) => {
194
+ (0, node_child_process_1.exec)(`git log --diff-filter=A --pretty=format:"%s|%h|%an|%ae|%b" -n 1 -- ${rawVersionPlan.absolutePath}`, (error, stdout, stderr) => {
195
+ if (error) {
196
+ if (isVerbose) {
197
+ console.error(`Error executing git command for ${rawVersionPlan.relativePath}: ${error.message}`);
198
+ }
199
+ return resolve(null);
200
+ }
201
+ if (stderr) {
202
+ if (isVerbose) {
203
+ console.error(`Git command stderr for ${rawVersionPlan.relativePath}: ${stderr}`);
204
+ }
205
+ return resolve(null);
206
+ }
207
+ const [message, shortHash, authorName, authorEmail, ...body] = stdout
208
+ .trim()
209
+ .split('|');
210
+ const commitDetails = {
211
+ message: message || '',
212
+ shortHash: shortHash || '',
213
+ author: { name: authorName || '', email: authorEmail || '' },
214
+ body: body.join('|') || '', // Handle case where body might be empty or contain multiple '|'
215
+ };
216
+ return resolve(commitDetails);
217
+ });
218
+ });
219
+ }
@@ -53,7 +53,7 @@ function createAPI(overrideReleaseConfig) {
53
53
  return 1;
54
54
  }
55
55
  const rawVersionPlans = await (0, version_plans_1.readRawVersionPlans)();
56
- (0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
56
+ await (0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes), args.verbose);
57
57
  // Resolve the final values for base, head etc to use when resolving the changes to consider
58
58
  const { nxArgs } = (0, command_line_utils_1.splitArgsIntoNxArgsAndOverrides)(args, 'affected', {
59
59
  printWarnings: args.verbose,
@@ -103,6 +103,9 @@ async function runPublishOnProjects(args, projectGraph, nxJson, projectNames, is
103
103
  if (args.otp) {
104
104
  overrides.otp = args.otp;
105
105
  }
106
+ if (args.access) {
107
+ overrides.access = args.access;
108
+ }
106
109
  if (args.dryRun) {
107
110
  overrides.dryRun = args.dryRun;
108
111
  /**
@@ -94,7 +94,7 @@ function createAPI(overrideReleaseConfig) {
94
94
  output_1.output.error(filterError);
95
95
  process.exit(1);
96
96
  }
97
- (0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
97
+ await (0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes), args.verbose);
98
98
  const planFiles = new Set();
99
99
  releaseGroups.forEach((group) => {
100
100
  if (group.resolvedVersionPlans) {
@@ -62,6 +62,6 @@ export declare function parseConventionalCommitsMessage(message: string): {
62
62
  description: string;
63
63
  breaking: boolean;
64
64
  } | null;
65
- export declare function parseGitCommit(commit: RawGitCommit): GitCommit | null;
65
+ export declare function parseGitCommit(commit: RawGitCommit, isVersionPlanCommit?: boolean): GitCommit | null;
66
66
  export declare function getCommitHash(ref: string): Promise<string>;
67
67
  export declare function getFirstGitCommit(): Promise<string>;
@@ -136,7 +136,7 @@ async function gitAdd({ changedFiles, deletedFiles, dryRun, verbose, logFn, cwd,
136
136
  ignoredFiles.push(f);
137
137
  // git add will fail if trying to add an untracked file that doesn't exist
138
138
  }
139
- else if (changedTrackedFiles.has(f)) {
139
+ else if (changedTrackedFiles.has(f) || dryRun) {
140
140
  filesToAdd.push(f);
141
141
  }
142
142
  }
@@ -281,6 +281,30 @@ function parseConventionalCommitsMessage(message) {
281
281
  breaking: Boolean(match.groups.breaking),
282
282
  };
283
283
  }
284
+ function extractReferencesFromCommitMessage(message, shortHash) {
285
+ const references = [];
286
+ for (const m of message.matchAll(PullRequestRE)) {
287
+ references.push({ type: 'pull-request', value: m[1] });
288
+ }
289
+ for (const m of message.matchAll(IssueRE)) {
290
+ if (!references.some((i) => i.value === m[1])) {
291
+ references.push({ type: 'issue', value: m[1] });
292
+ }
293
+ }
294
+ references.push({ value: shortHash, type: 'hash' });
295
+ return references;
296
+ }
297
+ function getAllAuthorsForCommit(commit) {
298
+ const authors = [commit.author];
299
+ // Additional authors can be specified in the commit body (depending on the VCS provider)
300
+ for (const match of commit.body.matchAll(CoAuthoredByRegex)) {
301
+ authors.push({
302
+ name: (match.groups.name || '').trim(),
303
+ email: (match.groups.email || '').trim(),
304
+ });
305
+ }
306
+ return authors;
307
+ }
284
308
  // https://www.conventionalcommits.org/en/v1.0.0/
285
309
  // https://regex101.com/r/FSfNvA/1
286
310
  const ConventionalCommitRegex = /(?<type>[a-z]+)(\((?<scope>.+)\))?(?<breaking>!)?: (?<description>.+)/i;
@@ -289,7 +313,25 @@ const PullRequestRE = /\([ a-z]*(#\d+)\s*\)/gm;
289
313
  const IssueRE = /(#\d+)/gm;
290
314
  const ChangedFileRegex = /(A|M|D|R\d*|C\d*)\t([^\t\n]*)\t?(.*)?/gm;
291
315
  const RevertHashRE = /This reverts commit (?<hash>[\da-f]{40})./gm;
292
- function parseGitCommit(commit) {
316
+ function parseGitCommit(commit, isVersionPlanCommit = false) {
317
+ // For version plans, we do not require conventional commits and therefore cannot extract data based on that format
318
+ if (isVersionPlanCommit) {
319
+ return {
320
+ ...commit,
321
+ description: commit.message,
322
+ type: '',
323
+ scope: '',
324
+ references: extractReferencesFromCommitMessage(commit.message, commit.shortHash),
325
+ // The commit message is not the source of truth for a breaking (major) change in version plans, so the value is not relevant
326
+ // TODO(v20): Make the current GitCommit interface more clearly tied to conventional commits
327
+ isBreaking: false,
328
+ authors: getAllAuthorsForCommit(commit),
329
+ // Not applicable to version plans
330
+ affectedFiles: [],
331
+ // Not applicable, a version plan cannot have been added in a commit that also reverts another commit
332
+ revertedHashes: [],
333
+ };
334
+ }
293
335
  const parsedMessage = parseConventionalCommitsMessage(commit.message);
294
336
  if (!parsedMessage) {
295
337
  return null;
@@ -298,16 +340,7 @@ function parseGitCommit(commit) {
298
340
  const isBreaking = parsedMessage.breaking || commit.body.includes('BREAKING CHANGE:');
299
341
  let description = parsedMessage.description;
300
342
  // Extract references from message
301
- const references = [];
302
- for (const m of description.matchAll(PullRequestRE)) {
303
- references.push({ type: 'pull-request', value: m[1] });
304
- }
305
- for (const m of description.matchAll(IssueRE)) {
306
- if (!references.some((i) => i.value === m[1])) {
307
- references.push({ type: 'issue', value: m[1] });
308
- }
309
- }
310
- references.push({ value: commit.shortHash, type: 'hash' });
343
+ const references = extractReferencesFromCommitMessage(description, commit.shortHash);
311
344
  // Remove references and normalize
312
345
  description = description.replace(PullRequestRE, '').trim();
313
346
  let type = parsedMessage.type;
@@ -322,13 +355,7 @@ function parseGitCommit(commit) {
322
355
  description = commit.message;
323
356
  }
324
357
  // Find all authors
325
- const authors = [commit.author];
326
- for (const match of commit.body.matchAll(CoAuthoredByRegex)) {
327
- authors.push({
328
- name: (match.groups.name || '').trim(),
329
- email: (match.groups.email || '').trim(),
330
- });
331
- }
358
+ const authors = getAllAuthorsForCommit(commit);
332
359
  // Extract file changes from commit body
333
360
  const affectedFiles = Array.from(commit.body.matchAll(ChangedFileRegex)).reduce((prev, [fullLine, changeType, file1, file2]) =>
334
361
  // file2 only exists for some change types, such as renames
@@ -82,7 +82,7 @@ function createAPI(overrideReleaseConfig) {
82
82
  }
83
83
  if (!args.specifier) {
84
84
  const rawVersionPlans = await (0, version_plans_1.readRawVersionPlans)();
85
- (0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
85
+ await (0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes), args.verbose);
86
86
  }
87
87
  else {
88
88
  if (args.verbose && releaseGroups.some((g) => !!g.versionPlans)) {
@@ -3,7 +3,7 @@ interface ExcludeOptions {
3
3
  exclude: string[];
4
4
  }
5
5
  export declare const defaultYargsParserConfiguration: Partial<ParserConfigurationOptions>;
6
- export declare function withExcludeOption(yargs: Argv): Argv<ExcludeOptions>;
6
+ export declare function withExcludeOption<T>(yargs: Argv<T>): Argv<T & ExcludeOptions>;
7
7
  export interface RunOptions {
8
8
  exclude: string;
9
9
  parallel: string;
@@ -20,6 +20,7 @@ export interface RunOptions {
20
20
  batch: boolean;
21
21
  useAgents: boolean;
22
22
  excludeTaskDependencies: boolean;
23
+ skipSync: boolean;
23
24
  }
24
25
  export declare function withRunOptions<T>(yargs: Argv<T>): Argv<T & RunOptions>;
25
26
  export declare function withTargetAndConfigurationOption(yargs: Argv, demandOption?: boolean): Argv<{