nx 19.6.0-beta.2 → 19.6.0-beta.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. package/package.json +12 -12
  2. package/schemas/nx-schema.json +30 -4
  3. package/src/command-line/import/command-object.d.ts +2 -0
  4. package/src/command-line/import/command-object.js +38 -0
  5. package/src/command-line/import/import.d.ts +21 -0
  6. package/src/command-line/import/import.js +173 -0
  7. package/src/command-line/import/utils/merge-remote-source.d.ts +2 -0
  8. package/src/command-line/import/utils/merge-remote-source.js +14 -0
  9. package/src/command-line/import/utils/needs-install.d.ts +3 -0
  10. package/src/command-line/import/utils/needs-install.js +31 -0
  11. package/src/command-line/import/utils/prepare-source-repo.d.ts +2 -0
  12. package/src/command-line/import/utils/prepare-source-repo.js +104 -0
  13. package/src/command-line/init/init-v2.d.ts +7 -0
  14. package/src/command-line/init/init-v2.js +48 -15
  15. package/src/command-line/nx-commands.js +33 -31
  16. package/src/command-line/release/changelog.js +9 -9
  17. package/src/command-line/release/command-object.d.ts +12 -3
  18. package/src/command-line/release/command-object.js +16 -1
  19. package/src/command-line/release/config/config.js +4 -2
  20. package/src/command-line/release/config/filter-release-groups.d.ts +2 -2
  21. package/src/command-line/release/config/filter-release-groups.js +1 -1
  22. package/src/command-line/release/config/version-plans.d.ts +1 -1
  23. package/src/command-line/release/config/version-plans.js +12 -12
  24. package/src/command-line/release/plan-check.d.ts +4 -0
  25. package/src/command-line/release/plan-check.js +225 -0
  26. package/src/command-line/release/plan.js +1 -1
  27. package/src/command-line/release/release.js +3 -3
  28. package/src/command-line/release/version.js +1 -1
  29. package/src/command-line/yargs-utils/shared-options.d.ts +1 -1
  30. package/src/config/nx-json.d.ts +9 -2
  31. package/src/native/nx.wasm32-wasi.wasm +0 -0
  32. package/src/utils/command-line-utils.d.ts +1 -0
  33. package/src/utils/command-line-utils.js +6 -3
  34. package/src/utils/git-utils.d.ts +35 -0
  35. package/src/utils/git-utils.js +111 -0
  36. package/src/utils/package-manager.js +1 -1
  37. package/src/utils/squash.d.ts +1 -0
  38. package/src/utils/squash.js +12 -0
@@ -10,21 +10,22 @@ const command_object_4 = require("./graph/command-object");
10
10
  const command_object_5 = require("./exec/command-object");
11
11
  const command_object_6 = require("./format/command-object");
12
12
  const command_object_7 = require("./generate/command-object");
13
- const command_object_8 = require("./init/command-object");
14
- const command_object_9 = require("./list/command-object");
15
- const command_object_10 = require("./migrate/command-object");
16
- const command_object_11 = require("./new/command-object");
17
- const command_object_12 = require("./repair/command-object");
18
- const command_object_13 = require("./report/command-object");
19
- const command_object_14 = require("./run/command-object");
20
- const command_object_15 = require("./run-many/command-object");
21
- const command_object_16 = require("./show/command-object");
22
- const command_object_17 = require("./watch/command-object");
23
- const command_object_18 = require("./reset/command-object");
24
- const command_object_19 = require("./release/command-object");
25
- const command_object_20 = require("./add/command-object");
13
+ const command_object_8 = require("./import/command-object");
14
+ const command_object_9 = require("./init/command-object");
15
+ const command_object_10 = require("./list/command-object");
16
+ const command_object_11 = require("./migrate/command-object");
17
+ const command_object_12 = require("./new/command-object");
18
+ const command_object_13 = require("./repair/command-object");
19
+ const command_object_14 = require("./report/command-object");
20
+ const command_object_15 = require("./run/command-object");
21
+ const command_object_16 = require("./run-many/command-object");
22
+ const command_object_17 = require("./show/command-object");
23
+ const command_object_18 = require("./watch/command-object");
24
+ const command_object_19 = require("./reset/command-object");
25
+ const command_object_20 = require("./release/command-object");
26
+ const command_object_21 = require("./add/command-object");
26
27
  const command_objects_1 = require("./deprecated/command-objects");
27
- const command_object_21 = require("./sync/command-object");
28
+ const command_object_22 = require("./sync/command-object");
28
29
  // Ensure that the output takes up the available width of the terminal.
29
30
  yargs.wrap(yargs.terminalWidth());
30
31
  exports.parserConfiguration = {
@@ -41,7 +42,7 @@ exports.commandsObject = yargs
41
42
  .parserConfiguration(exports.parserConfiguration)
42
43
  .usage(chalk.bold('Smart Monorepos · Fast CI'))
43
44
  .demandCommand(1, '')
44
- .command(command_object_20.yargsAddCommand)
45
+ .command(command_object_21.yargsAddCommand)
45
46
  .command(command_object_1.yargsAffectedBuildCommand)
46
47
  .command(command_object_1.yargsAffectedCommand)
47
48
  .command(command_object_1.yargsAffectedE2ECommand)
@@ -55,24 +56,25 @@ exports.commandsObject = yargs
55
56
  .command(command_object_6.yargsFormatCheckCommand)
56
57
  .command(command_object_6.yargsFormatWriteCommand)
57
58
  .command(command_object_7.yargsGenerateCommand)
58
- .command(command_object_8.yargsInitCommand)
59
- .command(command_object_10.yargsInternalMigrateCommand)
60
- .command(command_object_9.yargsListCommand)
61
- .command(command_object_10.yargsMigrateCommand)
62
- .command(command_object_11.yargsNewCommand)
59
+ .command(command_object_8.yargsImportCommand)
60
+ .command(command_object_9.yargsInitCommand)
61
+ .command(command_object_11.yargsInternalMigrateCommand)
62
+ .command(command_object_10.yargsListCommand)
63
+ .command(command_object_11.yargsMigrateCommand)
64
+ .command(command_object_12.yargsNewCommand)
63
65
  .command(command_objects_1.yargsPrintAffectedCommand)
64
- .command(command_object_19.yargsReleaseCommand)
65
- .command(command_object_12.yargsRepairCommand)
66
- .command(command_object_13.yargsReportCommand)
67
- .command(command_object_18.yargsResetCommand)
68
- .command(command_object_14.yargsRunCommand)
69
- .command(command_object_15.yargsRunManyCommand)
70
- .command(command_object_16.yargsShowCommand)
71
- .command(command_object_21.yargsSyncCommand)
72
- .command(command_object_21.yargsSyncCheckCommand)
66
+ .command(command_object_20.yargsReleaseCommand)
67
+ .command(command_object_13.yargsRepairCommand)
68
+ .command(command_object_14.yargsReportCommand)
69
+ .command(command_object_19.yargsResetCommand)
70
+ .command(command_object_15.yargsRunCommand)
71
+ .command(command_object_16.yargsRunManyCommand)
72
+ .command(command_object_17.yargsShowCommand)
73
+ .command(command_object_22.yargsSyncCommand)
74
+ .command(command_object_22.yargsSyncCheckCommand)
73
75
  .command(command_object_2.yargsViewLogsCommand)
74
- .command(command_object_17.yargsWatchCommand)
75
- .command(command_object_14.yargsNxInfixCommand)
76
+ .command(command_object_18.yargsWatchCommand)
77
+ .command(command_object_15.yargsNxInfixCommand)
76
78
  .scriptName('nx')
77
79
  .help()
78
80
  // NOTE: we handle --version in nx.ts, this just tells yargs that the option exists
@@ -84,7 +84,7 @@ function createAPI(overrideReleaseConfig) {
84
84
  process.exit(1);
85
85
  }
86
86
  const rawVersionPlans = await (0, version_plans_1.readRawVersionPlans)();
87
- (0, version_plans_1.setVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
87
+ (0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
88
88
  if (args.deleteVersionPlans === undefined) {
89
89
  // default to deleting version plans in this command instead of after versioning
90
90
  args.deleteVersionPlans = true;
@@ -140,12 +140,12 @@ function createAPI(overrideReleaseConfig) {
140
140
  // TODO: remove this after the changelog renderer is refactored to remove coupling with git commits
141
141
  let workspaceChangelogCommits = [];
142
142
  // If there are multiple release groups, we'll just skip the workspace changelog anyway.
143
- const versionPlansEnabledForWorkspaceChangelog = releaseGroups[0].versionPlans;
143
+ const versionPlansEnabledForWorkspaceChangelog = releaseGroups[0].resolvedVersionPlans;
144
144
  if (versionPlansEnabledForWorkspaceChangelog) {
145
145
  if (releaseGroups.length === 1) {
146
146
  const releaseGroup = releaseGroups[0];
147
147
  if (releaseGroup.projectsRelationship === 'fixed') {
148
- const versionPlans = releaseGroup.versionPlans;
148
+ const versionPlans = releaseGroup.resolvedVersionPlans;
149
149
  workspaceChangelogChanges = versionPlans
150
150
  .flatMap((vp) => {
151
151
  const releaseType = versionPlanSemverReleaseTypeToChangelogType(vp.groupVersionBump);
@@ -296,8 +296,8 @@ function createAPI(overrideReleaseConfig) {
296
296
  let changes = null;
297
297
  // TODO: remove this after the changelog renderer is refactored to remove coupling with git commits
298
298
  let commits;
299
- if (releaseGroup.versionPlans) {
300
- changes = releaseGroup.versionPlans
299
+ if (releaseGroup.resolvedVersionPlans) {
300
+ changes = releaseGroup.resolvedVersionPlans
301
301
  .map((vp) => {
302
302
  const bumpForProject = vp.projectVersionBumps[project.name];
303
303
  if (!bumpForProject) {
@@ -396,8 +396,8 @@ function createAPI(overrideReleaseConfig) {
396
396
  let changes = [];
397
397
  // TODO: remove this after the changelog renderer is refactored to remove coupling with git commits
398
398
  let commits = [];
399
- if (releaseGroup.versionPlans) {
400
- changes = releaseGroup.versionPlans
399
+ if (releaseGroup.resolvedVersionPlans) {
400
+ changes = releaseGroup.resolvedVersionPlans
401
401
  .flatMap((vp) => {
402
402
  const releaseType = versionPlanSemverReleaseTypeToChangelogType(vp.groupVersionBump);
403
403
  const changes = !vp.triggeredByProjects
@@ -585,8 +585,8 @@ async function applyChangesAndExit(args, nxReleaseConfig, tree, toSHA, postGitTa
585
585
  if (args.deleteVersionPlans && !args.dryRun) {
586
586
  const planFiles = new Set();
587
587
  releaseGroups.forEach((group) => {
588
- if (group.versionPlans) {
589
- group.versionPlans.forEach((plan) => {
588
+ if (group.resolvedVersionPlans) {
589
+ group.resolvedVersionPlans.forEach((plan) => {
590
590
  (0, fs_extra_1.removeSync)(plan.absolutePath);
591
591
  planFiles.add(plan.relativePath);
592
592
  });
@@ -1,12 +1,14 @@
1
1
  import { CommandModule } from 'yargs';
2
2
  import { OutputStyle, RunManyOptions } from '../yargs-utils/shared-options';
3
3
  import { VersionData } from './utils/shared';
4
- export interface NxReleaseArgs {
4
+ export interface BaseNxReleaseArgs {
5
+ verbose?: boolean;
6
+ printConfig?: boolean | 'debug';
7
+ }
8
+ export interface NxReleaseArgs extends BaseNxReleaseArgs {
5
9
  groups?: string[];
6
10
  projects?: string[];
7
11
  dryRun?: boolean;
8
- verbose?: boolean;
9
- printConfig?: boolean | 'debug';
10
12
  }
11
13
  interface GitCommitAndTagOptions {
12
14
  stageChanges?: boolean;
@@ -43,6 +45,13 @@ export type PlanOptions = NxReleaseArgs & {
43
45
  bump?: string;
44
46
  message?: string;
45
47
  };
48
+ export type PlanCheckOptions = BaseNxReleaseArgs & {
49
+ base?: string;
50
+ head?: string;
51
+ files?: string;
52
+ uncommitted?: boolean;
53
+ untracked?: boolean;
54
+ };
46
55
  export type ReleaseOptions = NxReleaseArgs & FirstReleaseArgs & {
47
56
  yes?: boolean;
48
57
  skipPublish?: boolean;
@@ -3,9 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.yargsReleaseCommand = void 0;
4
4
  const yargs_1 = require("yargs");
5
5
  const nx_json_1 = require("../../config/nx-json");
6
+ const command_line_utils_1 = require("../../utils/command-line-utils");
6
7
  const logger_1 = require("../../utils/logger");
7
8
  const shared_options_1 = require("../yargs-utils/shared-options");
8
- const command_line_utils_1 = require("../../utils/command-line-utils");
9
9
  exports.yargsReleaseCommand = {
10
10
  command: 'release',
11
11
  describe: 'Orchestrate versioning and publishing of applications and libraries',
@@ -15,6 +15,7 @@ exports.yargsReleaseCommand = {
15
15
  .command(changelogCommand)
16
16
  .command(publishCommand)
17
17
  .command(planCommand)
18
+ .command(planCheckCommand)
18
19
  .demandCommand()
19
20
  // Error on typos/mistyped CLI args, there is no reason to support arbitrary unknown args for these commands
20
21
  .strictOptions()
@@ -206,6 +207,7 @@ const publishCommand = {
206
207
  const planCommand = {
207
208
  command: 'plan [bump]',
208
209
  aliases: ['pl'],
210
+ // TODO: Remove this when docs are added
209
211
  // Create a plan to pick a new version and generate a changelog entry.
210
212
  // Hidden for now until the feature is more stable
211
213
  describe: false,
@@ -237,6 +239,19 @@ const planCommand = {
237
239
  process.exit(result);
238
240
  },
239
241
  };
242
+ const planCheckCommand = {
243
+ command: 'plan:check',
244
+ // TODO: Remove this when docs are added
245
+ // Create a plan to pick a new version and generate a changelog entry.
246
+ // Hidden for now until the feature is more stable
247
+ describe: false,
248
+ builder: (yargs) => (0, shared_options_1.withAffectedOptions)(yargs),
249
+ handler: async (args) => {
250
+ const release = await Promise.resolve().then(() => require('./plan-check'));
251
+ const result = await release.releasePlanCheckCLIHandler(args);
252
+ process.exit(result);
253
+ },
254
+ };
240
255
  function coerceParallelOption(args) {
241
256
  return {
242
257
  ...args,
@@ -144,7 +144,8 @@ async function createNxReleaseConfig(projectGraph, projectFileMap, userConfig =
144
144
  ? defaultIndependentReleaseTagPattern
145
145
  : defaultFixedReleaseTagPattern),
146
146
  conventionalCommits: conventional_commits_1.DEFAULT_CONVENTIONAL_COMMITS_CONFIG,
147
- versionPlans: false,
147
+ versionPlans: (userConfig.versionPlans ||
148
+ false),
148
149
  };
149
150
  const groupProjectsRelationship = userConfig.projectsRelationship || WORKSPACE_DEFAULTS.projectsRelationship;
150
151
  const GROUP_DEFAULTS = {
@@ -200,7 +201,8 @@ async function createNxReleaseConfig(projectGraph, projectFileMap, userConfig =
200
201
  git: userConfig.git,
201
202
  },
202
203
  ], normalizeTrueToEmptyObject(userConfig.changelog));
203
- const rootVersionPlansConfig = userConfig.versionPlans ?? WORKSPACE_DEFAULTS.versionPlans;
204
+ const rootVersionPlansConfig = (userConfig.versionPlans ??
205
+ WORKSPACE_DEFAULTS.versionPlans);
204
206
  const rootConventionalCommitsConfig = deepMergeDefaults([WORKSPACE_DEFAULTS.conventionalCommits], fillUnspecifiedConventionalCommitsProperties(normalizeConventionalCommitsConfig(userConfig.conventionalCommits)));
205
207
  // these options are not supported at the group level, only the root/command level
206
208
  const rootVersionWithoutGlobalOptions = { ...rootVersionConfig };
@@ -1,9 +1,9 @@
1
1
  import { ProjectGraph } from '../../../config/project-graph';
2
2
  import { NxReleaseConfig } from './config';
3
3
  import { GroupVersionPlan, ProjectsVersionPlan } from './version-plans';
4
- export type ReleaseGroupWithName = Omit<NxReleaseConfig['groups'][string], 'versionPlans'> & {
4
+ export type ReleaseGroupWithName = NxReleaseConfig['groups'][string] & {
5
5
  name: string;
6
- versionPlans: (ProjectsVersionPlan | GroupVersionPlan)[] | false;
6
+ resolvedVersionPlans: (ProjectsVersionPlan | GroupVersionPlan)[] | false;
7
7
  };
8
8
  export declare function filterReleaseGroups(projectGraph: ProjectGraph, nxReleaseConfig: NxReleaseConfig, projectsFilter?: string[], groupsFilter?: string[]): {
9
9
  error: null | {
@@ -9,7 +9,7 @@ function filterReleaseGroups(projectGraph, nxReleaseConfig, projectsFilter, grou
9
9
  return {
10
10
  ...group,
11
11
  name,
12
- versionPlans: group.versionPlans ? [] : false,
12
+ resolvedVersionPlans: group.versionPlans ? [] : false,
13
13
  };
14
14
  });
15
15
  const filteredProjectToReleaseGroup = new Map();
@@ -25,5 +25,5 @@ export interface ProjectsVersionPlan extends VersionPlan {
25
25
  projectVersionBumps: Record<string, ReleaseType>;
26
26
  }
27
27
  export declare function readRawVersionPlans(): Promise<RawVersionPlan[]>;
28
- export declare function setVersionPlansOnGroups(rawVersionPlans: RawVersionPlan[], releaseGroups: ReleaseGroupWithName[], allProjectNamesInWorkspace: string[]): ReleaseGroupWithName[];
28
+ export declare function setResolvedVersionPlansOnGroups(rawVersionPlans: RawVersionPlan[], releaseGroups: ReleaseGroupWithName[], allProjectNamesInWorkspace: string[]): ReleaseGroupWithName[];
29
29
  export declare function getVersionPlansAbsolutePath(): string;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.readRawVersionPlans = readRawVersionPlans;
4
- exports.setVersionPlansOnGroups = setVersionPlansOnGroups;
4
+ exports.setResolvedVersionPlansOnGroups = setResolvedVersionPlansOnGroups;
5
5
  exports.getVersionPlansAbsolutePath = getVersionPlansAbsolutePath;
6
6
  const fs_1 = require("fs");
7
7
  const fs_extra_1 = require("fs-extra");
@@ -35,7 +35,7 @@ async function readRawVersionPlans() {
35
35
  }
36
36
  return versionPlans;
37
37
  }
38
- function setVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNamesInWorkspace) {
38
+ function setResolvedVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNamesInWorkspace) {
39
39
  const groupsByName = releaseGroups.reduce((acc, group) => acc.set(group.name, group), new Map());
40
40
  const isDefaultGroup = isDefault(releaseGroups);
41
41
  for (const rawVersionPlan of rawVersionPlans) {
@@ -45,7 +45,7 @@ function setVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNames
45
45
  for (const [key, value] of Object.entries(rawVersionPlan.content)) {
46
46
  if (groupsByName.has(key)) {
47
47
  const group = groupsByName.get(key);
48
- if (!group.versionPlans) {
48
+ if (!group.resolvedVersionPlans) {
49
49
  if (isDefaultGroup) {
50
50
  throw new Error(`Found a version bump in '${rawVersionPlan.fileName}' but version plans are not enabled.`);
51
51
  }
@@ -69,7 +69,7 @@ function setVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNames
69
69
  throw new Error(`Found a version bump for group '${key}' in '${rawVersionPlan.fileName}' with an invalid release type. Please specify one of ${semver_1.RELEASE_TYPES.join(', ')}.`);
70
70
  }
71
71
  }
72
- const existingPlan = (group.versionPlans.find((plan) => plan.fileName === rawVersionPlan.fileName));
72
+ const existingPlan = (group.resolvedVersionPlans.find((plan) => plan.fileName === rawVersionPlan.fileName));
73
73
  if (existingPlan) {
74
74
  if (existingPlan.groupVersionBump !== value) {
75
75
  if (isDefaultGroup) {
@@ -81,7 +81,7 @@ function setVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNames
81
81
  }
82
82
  }
83
83
  else {
84
- group.versionPlans.push({
84
+ group.resolvedVersionPlans.push({
85
85
  absolutePath: rawVersionPlan.absolutePath,
86
86
  relativePath: rawVersionPlan.relativePath,
87
87
  fileName: rawVersionPlan.fileName,
@@ -104,7 +104,7 @@ function setVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNames
104
104
  throw new Error(`Found a version bump for project '${key}' in '${rawVersionPlan.fileName}' but the project is not in any configured release groups.`);
105
105
  }
106
106
  }
107
- if (!groupForProject.versionPlans) {
107
+ if (!groupForProject.resolvedVersionPlans) {
108
108
  if (isDefaultGroup) {
109
109
  throw new Error(`Found a version bump for project '${key}' in '${rawVersionPlan.fileName}' but version plans are not enabled.`);
110
110
  }
@@ -116,12 +116,12 @@ function setVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNames
116
116
  throw new Error(`Found a version bump for project '${key}' in '${rawVersionPlan.fileName}' with an invalid release type. Please specify one of ${semver_1.RELEASE_TYPES.join(', ')}.`);
117
117
  }
118
118
  if (groupForProject.projectsRelationship === 'independent') {
119
- const existingPlan = (groupForProject.versionPlans.find((plan) => plan.fileName === rawVersionPlan.fileName));
119
+ const existingPlan = (groupForProject.resolvedVersionPlans.find((plan) => plan.fileName === rawVersionPlan.fileName));
120
120
  if (existingPlan) {
121
121
  existingPlan.projectVersionBumps[key] = value;
122
122
  }
123
123
  else {
124
- groupForProject.versionPlans.push({
124
+ groupForProject.resolvedVersionPlans.push({
125
125
  absolutePath: rawVersionPlan.absolutePath,
126
126
  relativePath: rawVersionPlan.relativePath,
127
127
  fileName: rawVersionPlan.fileName,
@@ -134,7 +134,7 @@ function setVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNames
134
134
  }
135
135
  }
136
136
  else {
137
- const existingPlan = (groupForProject.versionPlans.find((plan) => plan.fileName === rawVersionPlan.fileName));
137
+ const existingPlan = (groupForProject.resolvedVersionPlans.find((plan) => plan.fileName === rawVersionPlan.fileName));
138
138
  // This can occur if the same fixed release group has multiple entries for different projects within
139
139
  // the same version plan file. This will be the case when users are using the default release group.
140
140
  if (existingPlan) {
@@ -151,7 +151,7 @@ function setVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNames
151
151
  }
152
152
  }
153
153
  else {
154
- groupForProject.versionPlans.push({
154
+ groupForProject.resolvedVersionPlans.push({
155
155
  absolutePath: rawVersionPlan.absolutePath,
156
156
  relativePath: rawVersionPlan.relativePath,
157
157
  fileName: rawVersionPlan.fileName,
@@ -169,8 +169,8 @@ function setVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNames
169
169
  }
170
170
  // Order the plans from newest to oldest
171
171
  releaseGroups.forEach((group) => {
172
- if (group.versionPlans) {
173
- group.versionPlans.sort((a, b) => b.createdOnMs - a.createdOnMs);
172
+ if (group.resolvedVersionPlans) {
173
+ group.resolvedVersionPlans.sort((a, b) => b.createdOnMs - a.createdOnMs);
174
174
  }
175
175
  });
176
176
  return releaseGroups;
@@ -0,0 +1,4 @@
1
+ import { NxReleaseConfiguration } from '../../config/nx-json';
2
+ import { PlanCheckOptions, PlanOptions } from './command-object';
3
+ export declare const releasePlanCheckCLIHandler: (args: PlanCheckOptions) => Promise<number>;
4
+ export declare function createAPI(overrideReleaseConfig: NxReleaseConfiguration): (args: PlanOptions) => Promise<number>;
@@ -0,0 +1,225 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.releasePlanCheckCLIHandler = void 0;
4
+ exports.createAPI = createAPI;
5
+ const nx_json_1 = require("../../config/nx-json");
6
+ const workspace_projects_1 = require("../../project-graph/affected/locators/workspace-projects");
7
+ const file_map_utils_1 = require("../../project-graph/file-map-utils");
8
+ const file_utils_1 = require("../../project-graph/file-utils");
9
+ const project_graph_1 = require("../../project-graph/project-graph");
10
+ const all_file_data_1 = require("../../utils/all-file-data");
11
+ const command_line_utils_1 = require("../../utils/command-line-utils");
12
+ const ignore_1 = require("../../utils/ignore");
13
+ const output_1 = require("../../utils/output");
14
+ const params_1 = require("../../utils/params");
15
+ const config_1 = require("./config/config");
16
+ const deep_merge_json_1 = require("./config/deep-merge-json");
17
+ const filter_release_groups_1 = require("./config/filter-release-groups");
18
+ const version_plans_1 = require("./config/version-plans");
19
+ const print_config_1 = require("./utils/print-config");
20
+ const releasePlanCheckCLIHandler = (args) => (0, params_1.handleErrors)(args.verbose, () => createAPI({})(args));
21
+ exports.releasePlanCheckCLIHandler = releasePlanCheckCLIHandler;
22
+ function createAPI(overrideReleaseConfig) {
23
+ return async function releasePlanCheck(args) {
24
+ const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });
25
+ const nxJson = (0, nx_json_1.readNxJson)();
26
+ const userProvidedReleaseConfig = (0, deep_merge_json_1.deepMergeJson)(nxJson.release ?? {}, overrideReleaseConfig ?? {});
27
+ if (args.verbose) {
28
+ process.env.NX_VERBOSE_LOGGING = 'true';
29
+ }
30
+ // Apply default configuration to any optional user configuration
31
+ const { error: configError, nxReleaseConfig } = await (0, config_1.createNxReleaseConfig)(projectGraph, await (0, file_map_utils_1.createProjectFileMapUsingProjectGraph)(projectGraph), userProvidedReleaseConfig);
32
+ if (configError) {
33
+ return await (0, config_1.handleNxReleaseConfigError)(configError);
34
+ }
35
+ // --print-config exits directly as it is not designed to be combined with any other programmatic operations
36
+ if (args.printConfig) {
37
+ return (0, print_config_1.printConfigAndExit)({
38
+ userProvidedReleaseConfig,
39
+ nxReleaseConfig,
40
+ isDebug: args.printConfig === 'debug',
41
+ });
42
+ }
43
+ const { error: filterError, releaseGroups, releaseGroupToFilteredProjects, } = (0, filter_release_groups_1.filterReleaseGroups)(projectGraph, nxReleaseConfig, args.projects, args.groups);
44
+ if (filterError) {
45
+ output_1.output.error(filterError);
46
+ process.exit(1);
47
+ }
48
+ // If no release groups have version plans enabled, provide an explicit error
49
+ if (!releaseGroups.some((group) => group.versionPlans)) {
50
+ output_1.output.error({
51
+ title: 'Version plans are not enabled',
52
+ bodyLines: [
53
+ 'Please ensure at least one release group has version plans enabled in your Nx release configuration if you want to use this command.',
54
+ // TODO: Add docs link here once it is available
55
+ ],
56
+ });
57
+ return 1;
58
+ }
59
+ const rawVersionPlans = await (0, version_plans_1.readRawVersionPlans)();
60
+ (0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
61
+ // Resolve the final values for base, head etc to use when resolving the changes to consider
62
+ const { nxArgs } = (0, command_line_utils_1.splitArgsIntoNxArgsAndOverrides)(args, 'affected', {
63
+ printWarnings: args.verbose,
64
+ }, nxJson);
65
+ const changedFiles = (0, command_line_utils_1.parseFiles)(nxArgs).files;
66
+ if (nxArgs.verbose) {
67
+ if (changedFiles.length) {
68
+ output_1.output.log({
69
+ title: `Changed files based on resolved "base" (${nxArgs.base}) and "head" (${nxArgs.head ?? 'HEAD'})`,
70
+ bodyLines: changedFiles.map((file) => ` - ${file}`),
71
+ });
72
+ }
73
+ else {
74
+ output_1.output.warn({
75
+ title: 'No changed files found based on resolved "base" and "head"',
76
+ });
77
+ }
78
+ }
79
+ const resolvedAllFileData = await (0, all_file_data_1.allFileData)();
80
+ /**
81
+ * Create a minimal subset of touched projects based on the configured ignore patterns, we only need
82
+ * to recompute when the ignorePatternsForPlanCheck differs between release groups.
83
+ */
84
+ const serializedIgnorePatternsToTouchedProjects = new Map();
85
+ const NOTE_ABOUT_VERBOSE_LOGGING = 'Run with --verbose to see the full list of changed files used for the touched projects logic.';
86
+ let hasErrors = false;
87
+ for (const releaseGroup of releaseGroups) {
88
+ // The current release group doesn't leverage version plans
89
+ if (!releaseGroup.versionPlans) {
90
+ continue;
91
+ }
92
+ const resolvedVersionPlans = releaseGroup.resolvedVersionPlans || [];
93
+ // Check upfront if the release group as a whole is featured in any version plan files
94
+ const matchingVersionPlanFiles = resolvedVersionPlans.filter((plan) => 'groupVersionBump' in plan);
95
+ if (matchingVersionPlanFiles.length) {
96
+ output_1.output.log({
97
+ title: `${releaseGroup.name === config_1.IMPLICIT_DEFAULT_RELEASE_GROUP
98
+ ? `There are`
99
+ : `Release group "${releaseGroup.name}" has`} pending bumps in version plan(s)`,
100
+ bodyLines: [
101
+ ...matchingVersionPlanFiles.map((plan) => ` - "${plan.groupVersionBump}" in ${plan.fileName}`),
102
+ ],
103
+ });
104
+ continue;
105
+ }
106
+ // Exclude patterns from .nxignore, .gitignore and explicit version plan config
107
+ let serializedIgnorePatterns = '[]';
108
+ const ignore = (0, ignore_1.getIgnoreObject)();
109
+ if (typeof releaseGroup.versionPlans !== 'boolean' &&
110
+ Array.isArray(releaseGroup.versionPlans.ignorePatternsForPlanCheck) &&
111
+ releaseGroup.versionPlans.ignorePatternsForPlanCheck.length) {
112
+ output_1.output.note({
113
+ title: `Applying configured ignore patterns to changed files${releaseGroup.name !== config_1.IMPLICIT_DEFAULT_RELEASE_GROUP
114
+ ? ` for release group "${releaseGroup.name}"`
115
+ : ''}`,
116
+ bodyLines: [
117
+ ...releaseGroup.versionPlans.ignorePatternsForPlanCheck.map((pattern) => ` - ${pattern}`),
118
+ ],
119
+ });
120
+ ignore.add(releaseGroup.versionPlans.ignorePatternsForPlanCheck);
121
+ serializedIgnorePatterns = JSON.stringify(releaseGroup.versionPlans.ignorePatternsForPlanCheck);
122
+ }
123
+ let touchedProjects = {};
124
+ if (serializedIgnorePatternsToTouchedProjects.has(serializedIgnorePatterns)) {
125
+ touchedProjects = serializedIgnorePatternsToTouchedProjects.get(serializedIgnorePatterns);
126
+ }
127
+ else {
128
+ // We only care about directly touched projects, not implicitly affected ones etc
129
+ const touchedProjectsArr = await (0, workspace_projects_1.getTouchedProjects)((0, file_utils_1.calculateFileChanges)(changedFiles, resolvedAllFileData, nxArgs, undefined, ignore), projectGraph.nodes);
130
+ touchedProjects = touchedProjectsArr.reduce((acc, project) => ({ ...acc, [project]: true }), {});
131
+ serializedIgnorePatternsToTouchedProjects.set(serializedIgnorePatterns, touchedProjects);
132
+ }
133
+ const touchedProjectsUnderReleaseGroup = releaseGroup.projects.filter((project) => touchedProjects[project]);
134
+ if (touchedProjectsUnderReleaseGroup.length) {
135
+ output_1.output.log({
136
+ title: `Touched projects based on changed files${releaseGroup.name !== config_1.IMPLICIT_DEFAULT_RELEASE_GROUP
137
+ ? ` under release group "${releaseGroup.name}"`
138
+ : ''}`,
139
+ bodyLines: [
140
+ ...touchedProjectsUnderReleaseGroup.map((project) => ` - ${project}`),
141
+ '',
142
+ 'NOTE: You can adjust your "versionPlans.ignorePatternsForPlanCheck" config to stop certain files from resulting in projects being classed as touched for the purposes of this command.',
143
+ ],
144
+ });
145
+ }
146
+ else {
147
+ output_1.output.log({
148
+ title: `No touched projects found based on changed files${typeof releaseGroup.versionPlans !== 'boolean' &&
149
+ Array.isArray(releaseGroup.versionPlans.ignorePatternsForPlanCheck) &&
150
+ releaseGroup.versionPlans.ignorePatternsForPlanCheck.length
151
+ ? ' combined with configured ignore patterns'
152
+ : ''}${releaseGroup.name !== config_1.IMPLICIT_DEFAULT_RELEASE_GROUP
153
+ ? ` under release group "${releaseGroup.name}"`
154
+ : ''}`,
155
+ });
156
+ }
157
+ const projectsInResolvedVersionPlans = resolvedVersionPlans.reduce((acc, plan) => {
158
+ if ('projectVersionBumps' in plan) {
159
+ for (const project in plan.projectVersionBumps) {
160
+ acc[project] = acc[project] || [];
161
+ acc[project].push({
162
+ bump: plan.projectVersionBumps[project],
163
+ fileName: plan.fileName,
164
+ });
165
+ }
166
+ }
167
+ return acc;
168
+ }, {});
169
+ // Ensure each touched project under this release group features in at least one version plan file
170
+ let touchedProjectsNotFoundInVersionPlans = [];
171
+ for (const touchedProject of touchedProjectsUnderReleaseGroup) {
172
+ if (!resolvedVersionPlans.length) {
173
+ touchedProjectsNotFoundInVersionPlans.push(touchedProject);
174
+ continue;
175
+ }
176
+ const matchingVersionPlanFileEntries = projectsInResolvedVersionPlans[touchedProject];
177
+ if (!matchingVersionPlanFileEntries?.length) {
178
+ touchedProjectsNotFoundInVersionPlans.push(touchedProject);
179
+ continue;
180
+ }
181
+ }
182
+ // Log any resolved pending bumps, regardless of whether the projects were directly touched or not
183
+ for (const [projectName, entries] of Object.entries(projectsInResolvedVersionPlans)) {
184
+ output_1.output.log({
185
+ title: `Project "${projectName}" has pending bumps in version plan(s)`,
186
+ bodyLines: [
187
+ ...entries.map(({ bump, fileName }) => ` - "${bump}" in ${fileName}`),
188
+ ],
189
+ });
190
+ }
191
+ if (touchedProjectsNotFoundInVersionPlans.length) {
192
+ const bodyLines = [
193
+ `The following touched projects${releaseGroup.name !== config_1.IMPLICIT_DEFAULT_RELEASE_GROUP
194
+ ? ` under release group "${releaseGroup.name}"`
195
+ : ''} do not feature in any version plan files:`,
196
+ ...touchedProjectsNotFoundInVersionPlans.map((project) => ` - ${project}`),
197
+ '',
198
+ 'Please use `nx release plan` to generate missing version plans, or adjust your "versionPlans.ignorePatternsForPlanCheck" config stop certain files from affecting the projects for the purposes of this command.',
199
+ ];
200
+ if (!nxArgs.verbose) {
201
+ bodyLines.push('', NOTE_ABOUT_VERBOSE_LOGGING);
202
+ }
203
+ output_1.output.error({
204
+ title: 'Touched projects missing version plans',
205
+ bodyLines,
206
+ });
207
+ // At least one project in one release group has an issue
208
+ hasErrors = true;
209
+ }
210
+ }
211
+ // Do not print success message if any projects are missing version plans
212
+ if (hasErrors) {
213
+ return 1;
214
+ }
215
+ const bodyLines = [];
216
+ if (!nxArgs.verbose) {
217
+ bodyLines.push(NOTE_ABOUT_VERBOSE_LOGGING);
218
+ }
219
+ output_1.output.success({
220
+ title: 'All touched projects have, or do not require, version plans.',
221
+ bodyLines,
222
+ });
223
+ return 0;
224
+ };
225
+ }
@@ -31,7 +31,7 @@ function createAPI(overrideReleaseConfig) {
31
31
  process.env.NX_VERBOSE_LOGGING = 'true';
32
32
  }
33
33
  // Apply default configuration to any optional user configuration
34
- const { error: configError, nxReleaseConfig } = await (0, config_1.createNxReleaseConfig)(projectGraph, await (0, file_map_utils_1.createProjectFileMapUsingProjectGraph)(projectGraph), nxJson.release);
34
+ const { error: configError, nxReleaseConfig } = await (0, config_1.createNxReleaseConfig)(projectGraph, await (0, file_map_utils_1.createProjectFileMapUsingProjectGraph)(projectGraph), userProvidedReleaseConfig);
35
35
  if (configError) {
36
36
  return await (0, config_1.handleNxReleaseConfigError)(configError);
37
37
  }
@@ -88,17 +88,17 @@ function createAPI(overrideReleaseConfig) {
88
88
  process.exit(1);
89
89
  }
90
90
  const rawVersionPlans = await (0, version_plans_1.readRawVersionPlans)();
91
- (0, version_plans_1.setVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
91
+ (0, version_plans_1.setResolvedVersionPlansOnGroups)(rawVersionPlans, releaseGroups, Object.keys(projectGraph.nodes));
92
92
  const planFiles = new Set();
93
93
  releaseGroups.forEach((group) => {
94
- if (group.versionPlans) {
94
+ if (group.resolvedVersionPlans) {
95
95
  if (group.name === config_1.IMPLICIT_DEFAULT_RELEASE_GROUP) {
96
96
  output_1.output.logSingleLine(`Removing version plan files`);
97
97
  }
98
98
  else {
99
99
  output_1.output.logSingleLine(`Removing version plan files for group ${group.name}`);
100
100
  }
101
- group.versionPlans.forEach((plan) => {
101
+ group.resolvedVersionPlans.forEach((plan) => {
102
102
  if (!args.dryRun) {
103
103
  (0, fs_extra_1.removeSync)(plan.absolutePath);
104
104
  if (args.verbose) {