nx 19.6.0-canary.20240806-a3869a8 → 19.6.0-canary.20240809-d3747e0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. package/package.json +12 -12
  2. package/release/changelog-renderer/index.js +16 -1
  3. package/release/index.d.ts +1 -1
  4. package/release/index.js +2 -1
  5. package/schemas/nx-schema.json +3 -0
  6. package/src/adapter/compat.d.ts +1 -1
  7. package/src/adapter/compat.js +1 -0
  8. package/src/command-line/connect/connect-to-nx-cloud.js +7 -3
  9. package/src/command-line/release/changelog.d.ts +2 -7
  10. package/src/command-line/release/changelog.js +415 -363
  11. package/src/command-line/release/command-object.d.ts +1 -0
  12. package/src/command-line/release/command-object.js +14 -0
  13. package/src/command-line/release/config/deep-merge-json.d.ts +1 -0
  14. package/src/command-line/release/config/deep-merge-json.js +28 -0
  15. package/src/command-line/release/config/version-plans.d.ts +5 -0
  16. package/src/command-line/release/config/version-plans.js +9 -5
  17. package/src/command-line/release/index.d.ts +16 -4
  18. package/src/command-line/release/index.js +23 -9
  19. package/src/command-line/release/plan.d.ts +2 -1
  20. package/src/command-line/release/plan.js +93 -100
  21. package/src/command-line/release/publish.d.ts +2 -6
  22. package/src/command-line/release/publish.js +67 -54
  23. package/src/command-line/release/release.d.ts +2 -1
  24. package/src/command-line/release/release.js +181 -165
  25. package/src/command-line/release/utils/generate-version-plan-content.js +2 -3
  26. package/src/command-line/release/utils/print-config.d.ts +7 -0
  27. package/src/command-line/release/utils/print-config.js +36 -0
  28. package/src/command-line/release/version.d.ts +7 -6
  29. package/src/command-line/release/version.js +179 -165
  30. package/src/config/nx-json.d.ts +6 -1
  31. package/src/core/graph/styles.css +1 -1
  32. package/src/devkit-internals.d.ts +2 -2
  33. package/src/devkit-internals.js +2 -2
  34. package/src/native/nx.wasm32-wasi.wasm +0 -0
  35. package/src/nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud.d.ts +2 -1
  36. package/src/nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud.js +49 -10
  37. package/src/nx-cloud/nx-cloud-tasks-runner-shell.d.ts +1 -0
  38. package/src/nx-cloud/utilities/axios.js +9 -2
  39. package/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +7 -2
  40. package/src/plugins/package-json/create-nodes.js +9 -1
  41. package/src/project-graph/plugins/isolation/plugin-pool.js +32 -10
  42. package/src/tasks-runner/run-command.js +6 -1
  43. package/src/tasks-runner/utils.js +14 -10
  44. package/src/utils/nx-cloud-utils.js +3 -1
  45. package/src/utils/package-manager.js +12 -3
@@ -6,6 +6,7 @@ export interface NxReleaseArgs {
6
6
  projects?: string[];
7
7
  dryRun?: boolean;
8
8
  verbose?: boolean;
9
+ printConfig?: boolean | 'debug';
9
10
  }
10
11
  interface GitCommitAndTagOptions {
11
12
  stageChanges?: boolean;
@@ -39,6 +39,20 @@ exports.yargsReleaseCommand = {
39
39
  .option('verbose', {
40
40
  type: 'boolean',
41
41
  describe: 'Prints additional information about the commands (e.g., stack traces)',
42
+ })
43
+ // NOTE: The camel case format is required for the coerce() function to be called correctly. It still supports --print-config casing.
44
+ .option('printConfig', {
45
+ type: 'string',
46
+ describe: 'Print the resolved nx release configuration that would be used for the current command and then exit',
47
+ coerce: (val) => {
48
+ if (val === '') {
49
+ return true;
50
+ }
51
+ if (val === 'false') {
52
+ return false;
53
+ }
54
+ return val;
55
+ },
42
56
  })
43
57
  .check((argv) => {
44
58
  if (argv.groups && argv.projects) {
@@ -0,0 +1 @@
1
+ export declare function deepMergeJson<T extends Record<string, any>>(target: T, source: T): T;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deepMergeJson = deepMergeJson;
4
+ function isObject(obj) {
5
+ return obj && typeof obj === 'object' && !Array.isArray(obj);
6
+ }
7
+ function deepMergeJson(target, source) {
8
+ try {
9
+ // Ensure both objects are valid JSON before attempting to merge values
10
+ JSON.parse(JSON.stringify(source));
11
+ JSON.parse(JSON.stringify(target));
12
+ for (const key in source) {
13
+ if (isObject(source[key])) {
14
+ if (!target[key]) {
15
+ Object.assign(target, { [key]: {} });
16
+ }
17
+ deepMergeJson(target[key], source[key]);
18
+ }
19
+ else {
20
+ Object.assign(target, { [key]: source[key] });
21
+ }
22
+ }
23
+ return target;
24
+ }
25
+ catch {
26
+ throw new Error('Invalid JSON was provided');
27
+ }
28
+ }
@@ -15,6 +15,11 @@ export interface VersionPlan extends VersionPlanFile {
15
15
  }
16
16
  export interface GroupVersionPlan extends VersionPlan {
17
17
  groupVersionBump: ReleaseType;
18
+ /**
19
+ * Will not be set if the group name was the trigger, otherwise will be a list of
20
+ * all the individual project names explicitly found in the version plan file.
21
+ */
22
+ triggeredByProjects?: string[];
18
23
  }
19
24
  export interface ProjectsVersionPlan extends VersionPlan {
20
25
  projectVersionBumps: Record<string, ReleaseType>;
@@ -29,7 +29,7 @@ async function readRawVersionPlans() {
29
29
  relativePath: (0, path_1.join)(versionPlansDirectory, versionPlanFile),
30
30
  fileName: versionPlanFile,
31
31
  content: parsedContent.attributes,
32
- message: getSingleLineMessage(parsedContent.body),
32
+ message: parsedContent.body,
33
33
  createdOnMs: versionPlanStats.birthtimeMs,
34
34
  });
35
35
  }
@@ -39,6 +39,9 @@ function setVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNames
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) {
42
+ if (!rawVersionPlan.message) {
43
+ throw new Error(`Please add a changelog message to version plan: '${rawVersionPlan.fileName}'`);
44
+ }
42
45
  for (const [key, value] of Object.entries(rawVersionPlan.content)) {
43
46
  if (groupsByName.has(key)) {
44
47
  const group = groupsByName.get(key);
@@ -143,6 +146,9 @@ function setVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNames
143
146
  throw new Error(`Found a version bump for project '${key}' in '${rawVersionPlan.fileName}' that conflicts with another project's version bump in the same release group '${groupForProject.name}'. When the group is in fixed versioning mode, all projects' version bumps within the same group must match.`);
144
147
  }
145
148
  }
149
+ else {
150
+ existingPlan.triggeredByProjects.push(key);
151
+ }
146
152
  }
147
153
  else {
148
154
  groupForProject.versionPlans.push({
@@ -152,7 +158,9 @@ function setVersionPlansOnGroups(rawVersionPlans, releaseGroups, allProjectNames
152
158
  createdOnMs: rawVersionPlan.createdOnMs,
153
159
  message: rawVersionPlan.message,
154
160
  // This is a fixed group, so the version bump is for the group, even if a project within it was specified
161
+ // but we track the projects that triggered the version bump so that we can accurately produce changelog entries.
155
162
  groupVersionBump: value,
163
+ triggeredByProjects: [key],
156
164
  });
157
165
  }
158
166
  }
@@ -177,7 +185,3 @@ function getVersionPlansAbsolutePath() {
177
185
  function isReleaseType(value) {
178
186
  return semver_1.RELEASE_TYPES.includes(value);
179
187
  }
180
- // changelog messages may only be a single line long, so ignore anything else
181
- function getSingleLineMessage(message) {
182
- return message.trim().split('\n')[0];
183
- }
@@ -1,16 +1,28 @@
1
+ import type { NxReleaseConfiguration } from '../../config/nx-json';
1
2
  /**
2
3
  * @public
3
4
  */
4
- export { releaseChangelog } from './changelog';
5
+ export declare class ReleaseClient {
6
+ private overrideReleaseConfig;
7
+ releaseChangelog: (args: import("./command-object").ChangelogOptions) => Promise<import("./changelog").NxReleaseChangelogResult>;
8
+ releasePublish: (args: import("./command-object").PublishOptions, isCLI?: boolean) => Promise<number>;
9
+ releaseVersion: (args: import("./command-object").VersionOptions) => Promise<import("./version").NxReleaseVersionResult>;
10
+ release: (args: import("./command-object").ReleaseOptions) => Promise<import("./version").NxReleaseVersionResult | number>;
11
+ constructor(overrideReleaseConfig: NxReleaseConfiguration);
12
+ }
5
13
  /**
6
14
  * @public
7
15
  */
8
- export { releasePublish } from './publish';
16
+ export declare const releaseChangelog: any;
9
17
  /**
10
18
  * @public
11
19
  */
12
- export { releaseVersion } from './version';
20
+ export declare const releasePublish: any;
13
21
  /**
14
22
  * @public
15
23
  */
16
- export { release } from './release';
24
+ export declare const releaseVersion: any;
25
+ /**
26
+ * @public
27
+ */
28
+ export declare const release: any;
@@ -1,23 +1,37 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.release = exports.releaseVersion = exports.releasePublish = exports.releaseChangelog = void 0;
3
+ exports.release = exports.releaseVersion = exports.releasePublish = exports.releaseChangelog = exports.ReleaseClient = void 0;
4
+ const changelog_1 = require("./changelog");
5
+ const publish_1 = require("./publish");
6
+ const release_1 = require("./release");
7
+ const version_1 = require("./version");
4
8
  /**
5
9
  * @public
6
10
  */
7
- var changelog_1 = require("./changelog");
8
- Object.defineProperty(exports, "releaseChangelog", { enumerable: true, get: function () { return changelog_1.releaseChangelog; } });
11
+ class ReleaseClient {
12
+ constructor(overrideReleaseConfig) {
13
+ this.overrideReleaseConfig = overrideReleaseConfig;
14
+ this.releaseChangelog = (0, changelog_1.createAPI)(this.overrideReleaseConfig);
15
+ this.releasePublish = (0, publish_1.createAPI)(this.overrideReleaseConfig);
16
+ this.releaseVersion = (0, version_1.createAPI)(this.overrideReleaseConfig);
17
+ this.release = (0, release_1.createAPI)(this.overrideReleaseConfig);
18
+ }
19
+ }
20
+ exports.ReleaseClient = ReleaseClient;
21
+ const defaultClient = new ReleaseClient({});
9
22
  /**
10
23
  * @public
11
24
  */
12
- var publish_1 = require("./publish");
13
- Object.defineProperty(exports, "releasePublish", { enumerable: true, get: function () { return publish_1.releasePublish; } });
25
+ exports.releaseChangelog = defaultClient.releaseChangelog.bind(defaultClient);
14
26
  /**
15
27
  * @public
16
28
  */
17
- var version_1 = require("./version");
18
- Object.defineProperty(exports, "releaseVersion", { enumerable: true, get: function () { return version_1.releaseVersion; } });
29
+ exports.releasePublish = defaultClient.releasePublish.bind(defaultClient);
19
30
  /**
20
31
  * @public
21
32
  */
22
- var release_1 = require("./release");
23
- Object.defineProperty(exports, "release", { enumerable: true, get: function () { return release_1.release; } });
33
+ exports.releaseVersion = defaultClient.releaseVersion.bind(defaultClient);
34
+ /**
35
+ * @public
36
+ */
37
+ exports.release = defaultClient.release.bind(defaultClient);
@@ -1,3 +1,4 @@
1
+ import { NxReleaseConfiguration } from '../../config/nx-json';
1
2
  import { PlanOptions } from './command-object';
2
3
  export declare const releasePlanCLIHandler: (args: PlanOptions) => Promise<number>;
3
- export declare function releasePlan(args: PlanOptions): Promise<string | number>;
4
+ export declare function createAPI(overrideReleaseConfig: NxReleaseConfiguration): (args: PlanOptions) => Promise<string | number>;
@@ -1,114 +1,110 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.releasePlanCLIHandler = void 0;
4
- exports.releasePlan = releasePlan;
4
+ exports.createAPI = createAPI;
5
5
  const enquirer_1 = require("enquirer");
6
6
  const fs_extra_1 = require("fs-extra");
7
- const path_1 = require("path");
7
+ const node_path_1 = require("node:path");
8
8
  const semver_1 = require("semver");
9
+ const tmp_1 = require("tmp");
9
10
  const nx_json_1 = require("../../config/nx-json");
10
11
  const file_map_utils_1 = require("../../project-graph/file-map-utils");
11
12
  const project_graph_1 = require("../../project-graph/project-graph");
12
13
  const output_1 = require("../../utils/output");
13
14
  const params_1 = require("../../utils/params");
14
15
  const config_1 = require("./config/config");
16
+ const deep_merge_json_1 = require("./config/deep-merge-json");
15
17
  const filter_release_groups_1 = require("./config/filter-release-groups");
16
18
  const version_plans_1 = require("./config/version-plans");
17
19
  const generate_version_plan_content_1 = require("./utils/generate-version-plan-content");
18
- const git_1 = require("./utils/git");
20
+ const launch_editor_1 = require("./utils/launch-editor");
19
21
  const print_changes_1 = require("./utils/print-changes");
20
- const releasePlanCLIHandler = (args) => (0, params_1.handleErrors)(args.verbose, () => releasePlan(args));
22
+ const print_config_1 = require("./utils/print-config");
23
+ const releasePlanCLIHandler = (args) => (0, params_1.handleErrors)(args.verbose, () => createAPI({})(args));
21
24
  exports.releasePlanCLIHandler = releasePlanCLIHandler;
22
- async function releasePlan(args) {
23
- const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });
24
- const nxJson = (0, nx_json_1.readNxJson)();
25
- if (args.verbose) {
26
- process.env.NX_VERBOSE_LOGGING = 'true';
27
- }
28
- // Apply default configuration to any optional user configuration
29
- const { error: configError, nxReleaseConfig } = await (0, config_1.createNxReleaseConfig)(projectGraph, await (0, file_map_utils_1.createProjectFileMapUsingProjectGraph)(projectGraph), nxJson.release);
30
- if (configError) {
31
- return await (0, config_1.handleNxReleaseConfigError)(configError);
32
- }
33
- const { error: filterError, releaseGroups, releaseGroupToFilteredProjects, } = (0, filter_release_groups_1.filterReleaseGroups)(projectGraph, nxReleaseConfig, args.projects, args.groups);
34
- if (filterError) {
35
- output_1.output.error(filterError);
36
- process.exit(1);
37
- }
38
- const versionPlanBumps = {};
39
- const setBumpIfNotNone = (projectOrGroup, version) => {
40
- if (version !== 'none') {
41
- versionPlanBumps[projectOrGroup] = version;
25
+ function createAPI(overrideReleaseConfig) {
26
+ return async function releasePlan(args) {
27
+ const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });
28
+ const nxJson = (0, nx_json_1.readNxJson)();
29
+ const userProvidedReleaseConfig = (0, deep_merge_json_1.deepMergeJson)(nxJson.release ?? {}, overrideReleaseConfig ?? {});
30
+ if (args.verbose) {
31
+ process.env.NX_VERBOSE_LOGGING = 'true';
42
32
  }
43
- };
44
- if (args.message) {
45
- const message = (0, git_1.parseConventionalCommitsMessage)(args.message);
46
- if (!message) {
47
- output_1.output.error({
48
- title: 'Changelog message is not in conventional commits format.',
49
- bodyLines: [
50
- 'Please ensure your message is in the form of:',
51
- ' type(optional scope): description',
52
- '',
53
- 'For example:',
54
- ' feat(pkg-b): add new feature',
55
- ' fix(pkg-a): correct a bug',
56
- ' chore: update build process',
57
- ' fix(core)!: breaking change in core package',
58
- ],
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);
35
+ if (configError) {
36
+ return await (0, config_1.handleNxReleaseConfigError)(configError);
37
+ }
38
+ // --print-config exits directly as it is not designed to be combined with any other programmatic operations
39
+ if (args.printConfig) {
40
+ return (0, print_config_1.printConfigAndExit)({
41
+ userProvidedReleaseConfig,
42
+ nxReleaseConfig,
43
+ isDebug: args.printConfig === 'debug',
59
44
  });
45
+ }
46
+ const { error: filterError, releaseGroups, releaseGroupToFilteredProjects, } = (0, filter_release_groups_1.filterReleaseGroups)(projectGraph, nxReleaseConfig, args.projects, args.groups);
47
+ if (filterError) {
48
+ output_1.output.error(filterError);
60
49
  process.exit(1);
61
50
  }
62
- }
63
- if (releaseGroups[0].name === config_1.IMPLICIT_DEFAULT_RELEASE_GROUP) {
64
- const group = releaseGroups[0];
65
- if (group.projectsRelationship === 'independent') {
66
- for (const project of group.projects) {
67
- setBumpIfNotNone(project, args.bump ||
68
- (await promptForVersion(`How do you want to bump the version of the project "${project}"?`)));
51
+ const versionPlanBumps = {};
52
+ const setBumpIfNotNone = (projectOrGroup, version) => {
53
+ if (version !== 'none') {
54
+ versionPlanBumps[projectOrGroup] = version;
69
55
  }
70
- }
71
- else {
72
- // TODO: use project names instead of the implicit default release group name? (though this might be confusing, as users might think they can just delete one of the project bumps to change the behavior to independent versioning)
73
- setBumpIfNotNone(group.name, args.bump ||
74
- (await promptForVersion(`How do you want to bump the versions of all projects?`)));
75
- }
76
- }
77
- else {
78
- for (const group of releaseGroups) {
56
+ };
57
+ if (releaseGroups[0].name === config_1.IMPLICIT_DEFAULT_RELEASE_GROUP) {
58
+ const group = releaseGroups[0];
79
59
  if (group.projectsRelationship === 'independent') {
80
- for (const project of releaseGroupToFilteredProjects.get(group)) {
60
+ for (const project of group.projects) {
81
61
  setBumpIfNotNone(project, args.bump ||
82
- (await promptForVersion(`How do you want to bump the version of the project "${project}" within group "${group.name}"?`)));
62
+ (await promptForVersion(`How do you want to bump the version of the project "${project}"?`)));
83
63
  }
84
64
  }
85
65
  else {
66
+ // TODO: use project names instead of the implicit default release group name? (though this might be confusing, as users might think they can just delete one of the project bumps to change the behavior to independent versioning)
86
67
  setBumpIfNotNone(group.name, args.bump ||
87
- (await promptForVersion(`How do you want to bump the versions of the projects in the group "${group.name}"?`)));
68
+ (await promptForVersion(`How do you want to bump the versions of all projects?`)));
88
69
  }
89
70
  }
90
- }
91
- if (!Object.keys(versionPlanBumps).length) {
92
- output_1.output.warn({
93
- title: 'No version bumps were selected so no version plan file was created.',
94
- });
71
+ else {
72
+ for (const group of releaseGroups) {
73
+ if (group.projectsRelationship === 'independent') {
74
+ for (const project of releaseGroupToFilteredProjects.get(group)) {
75
+ setBumpIfNotNone(project, args.bump ||
76
+ (await promptForVersion(`How do you want to bump the version of the project "${project}" within group "${group.name}"?`)));
77
+ }
78
+ }
79
+ else {
80
+ setBumpIfNotNone(group.name, args.bump ||
81
+ (await promptForVersion(`How do you want to bump the versions of the projects in the group "${group.name}"?`)));
82
+ }
83
+ }
84
+ }
85
+ if (!Object.keys(versionPlanBumps).length) {
86
+ output_1.output.warn({
87
+ title: 'No version bumps were selected so no version plan file was created.',
88
+ });
89
+ return 0;
90
+ }
91
+ const versionPlanName = `version-plan-${new Date().getTime()}`;
92
+ const versionPlanMessage = args.message || (await promptForMessage(versionPlanName));
93
+ const versionPlanFileContent = (0, generate_version_plan_content_1.generateVersionPlanContent)(versionPlanBumps, versionPlanMessage);
94
+ const versionPlanFileName = `${versionPlanName}.md`;
95
+ if (args.dryRun) {
96
+ output_1.output.logSingleLine(`Would create version plan file "${versionPlanFileName}", but --dry-run was set.`);
97
+ (0, print_changes_1.printDiff)('', versionPlanFileContent, 1);
98
+ }
99
+ else {
100
+ output_1.output.logSingleLine(`Creating version plan file "${versionPlanFileName}"`);
101
+ (0, print_changes_1.printDiff)('', versionPlanFileContent, 1);
102
+ const versionPlansAbsolutePath = (0, version_plans_1.getVersionPlansAbsolutePath)();
103
+ await (0, fs_extra_1.ensureDir)(versionPlansAbsolutePath);
104
+ await (0, fs_extra_1.writeFile)((0, node_path_1.join)(versionPlansAbsolutePath, versionPlanFileName), versionPlanFileContent);
105
+ }
95
106
  return 0;
96
- }
97
- const versionPlanMessage = args.message || (await promptForMessage());
98
- const versionPlanFileContent = (0, generate_version_plan_content_1.generateVersionPlanContent)(versionPlanBumps, versionPlanMessage);
99
- const versionPlanFileName = `version-plan-${new Date().getTime()}.md`;
100
- if (args.dryRun) {
101
- output_1.output.logSingleLine(`Would create version plan file "${versionPlanFileName}", but --dry-run was set.`);
102
- (0, print_changes_1.printDiff)('', versionPlanFileContent, 1);
103
- }
104
- else {
105
- output_1.output.logSingleLine(`Creating version plan file "${versionPlanFileName}"`);
106
- (0, print_changes_1.printDiff)('', versionPlanFileContent, 1);
107
- const versionPlansAbsolutePath = (0, version_plans_1.getVersionPlansAbsolutePath)();
108
- await (0, fs_extra_1.ensureDir)(versionPlansAbsolutePath);
109
- await (0, fs_extra_1.writeFile)((0, path_1.join)(versionPlansAbsolutePath, versionPlanFileName), versionPlanFileContent);
110
- }
111
- return 0;
107
+ };
112
108
  }
113
109
  async function promptForVersion(message) {
114
110
  try {
@@ -129,41 +125,38 @@ async function promptForVersion(message) {
129
125
  process.exit(0);
130
126
  }
131
127
  }
132
- async function promptForMessage() {
128
+ async function promptForMessage(versionPlanName) {
133
129
  let message;
134
130
  do {
135
- message = await _promptForMessage();
131
+ message = await _promptForMessage(versionPlanName);
136
132
  } while (!message);
137
133
  return message;
138
134
  }
139
- // TODO: support non-conventional commits messages (will require significant changelog renderer changes)
140
- async function _promptForMessage() {
135
+ async function _promptForMessage(versionPlanName) {
141
136
  try {
142
137
  const reply = await (0, enquirer_1.prompt)([
143
138
  {
144
139
  name: 'message',
145
- message: 'What changelog message would you like associated with this change?',
140
+ message: 'What changelog message would you like associated with this change? (Leave blank to open an external editor for multi-line messages/easier editing)',
146
141
  type: 'input',
147
142
  },
148
143
  ]);
149
- const conventionalCommitsMessage = (0, git_1.parseConventionalCommitsMessage)(reply.message);
150
- if (!conventionalCommitsMessage) {
144
+ let message = reply.message.trim();
145
+ if (!message.length) {
146
+ const tmpDir = (0, tmp_1.dirSync)().name;
147
+ const messageFilePath = (0, node_path_1.join)(tmpDir, `DRAFT_MESSAGE__${versionPlanName}.md`);
148
+ (0, fs_extra_1.writeFileSync)(messageFilePath, '');
149
+ await (0, launch_editor_1.launchEditor)(messageFilePath);
150
+ message = (0, fs_extra_1.readFileSync)(messageFilePath, 'utf-8');
151
+ }
152
+ message = message.trim();
153
+ if (!message) {
151
154
  output_1.output.warn({
152
- title: 'Changelog message is not in conventional commits format.',
153
- bodyLines: [
154
- 'Please ensure your message is in the form of:',
155
- ' type(optional scope): description',
156
- '',
157
- 'For example:',
158
- ' feat(pkg-b): add new feature',
159
- ' fix(pkg-a): correct a bug',
160
- ' chore: update build process',
161
- ' fix(core)!: breaking change in core package',
162
- ],
155
+ title: 'A changelog message is required in order to create the version plan file',
156
+ bodyLines: [],
163
157
  });
164
- return null;
165
158
  }
166
- return reply.message;
159
+ return message;
167
160
  }
168
161
  catch (e) {
169
162
  output_1.output.log({
@@ -1,8 +1,4 @@
1
+ import { NxReleaseConfiguration } from '../../config/nx-json';
1
2
  import { PublishOptions } from './command-object';
2
3
  export declare const releasePublishCLIHandler: (args: PublishOptions) => Promise<number>;
3
- /**
4
- * NOTE: This function is also exported for programmatic usage and forms part of the public API
5
- * of Nx. We intentionally do not wrap the implementation with handleErrors because users need
6
- * to have control over their own error handling when using the API.
7
- */
8
- export declare function releasePublish(args: PublishOptions, isCLI?: boolean): Promise<number>;
4
+ export declare function createAPI(overrideReleaseConfig: NxReleaseConfiguration): (args: PublishOptions, isCLI?: boolean) => Promise<number>;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.releasePublishCLIHandler = void 0;
4
- exports.releasePublish = releasePublish;
4
+ exports.createAPI = createAPI;
5
5
  const nx_json_1 = require("../../config/nx-json");
6
6
  const file_map_utils_1 = require("../../project-graph/file-map-utils");
7
7
  const project_graph_1 = require("../../project-graph/project-graph");
@@ -12,52 +12,78 @@ const params_1 = require("../../utils/params");
12
12
  const project_graph_utils_1 = require("../../utils/project-graph-utils");
13
13
  const graph_1 = require("../graph/graph");
14
14
  const config_1 = require("./config/config");
15
+ const deep_merge_json_1 = require("./config/deep-merge-json");
15
16
  const filter_release_groups_1 = require("./config/filter-release-groups");
16
- const releasePublishCLIHandler = (args) => (0, params_1.handleErrors)(args.verbose, () => releasePublish(args, true));
17
+ const print_config_1 = require("./utils/print-config");
18
+ const releasePublishCLIHandler = (args) => (0, params_1.handleErrors)(args.verbose, () => createAPI({})(args, true));
17
19
  exports.releasePublishCLIHandler = releasePublishCLIHandler;
18
- /**
19
- * NOTE: This function is also exported for programmatic usage and forms part of the public API
20
- * of Nx. We intentionally do not wrap the implementation with handleErrors because users need
21
- * to have control over their own error handling when using the API.
22
- */
23
- async function releasePublish(args, isCLI = false) {
20
+ function createAPI(overrideReleaseConfig) {
24
21
  /**
25
- * When used via the CLI, the args object will contain a __overrides_unparsed__ property that is
26
- * important for invoking the relevant executor behind the scenes.
27
- *
28
- * We intentionally do not include that in the function signature, however, so as not to cause
29
- * confusing errors for programmatic consumers of this function.
22
+ * NOTE: This function is also exported for programmatic usage and forms part of the public API
23
+ * of Nx. We intentionally do not wrap the implementation with handleErrors because users need
24
+ * to have control over their own error handling when using the API.
30
25
  */
31
- const _args = args;
32
- const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });
33
- const nxJson = (0, nx_json_1.readNxJson)();
34
- if (_args.verbose) {
35
- process.env.NX_VERBOSE_LOGGING = 'true';
36
- }
37
- // Apply default configuration to any optional user configuration
38
- const { error: configError, nxReleaseConfig } = await (0, config_1.createNxReleaseConfig)(projectGraph, await (0, file_map_utils_1.createProjectFileMapUsingProjectGraph)(projectGraph), nxJson.release);
39
- if (configError) {
40
- return await (0, config_1.handleNxReleaseConfigError)(configError);
41
- }
42
- const { error: filterError, releaseGroups, releaseGroupToFilteredProjects, } = (0, filter_release_groups_1.filterReleaseGroups)(projectGraph, nxReleaseConfig, _args.projects, _args.groups);
43
- if (filterError) {
44
- output_1.output.error(filterError);
45
- process.exit(1);
46
- }
47
- /**
48
- * If the user is filtering to a subset of projects or groups, we should not run the publish task
49
- * for dependencies, because that could cause projects outset of the filtered set to be published.
50
- */
51
- const shouldExcludeTaskDependencies = _args.projects?.length > 0 ||
52
- _args.groups?.length > 0 ||
53
- args.excludeTaskDependencies;
54
- let overallExitStatus = 0;
55
- if (args.projects?.length) {
26
+ return async function releasePublish(args, isCLI = false) {
27
+ /**
28
+ * When used via the CLI, the args object will contain a __overrides_unparsed__ property that is
29
+ * important for invoking the relevant executor behind the scenes.
30
+ *
31
+ * We intentionally do not include that in the function signature, however, so as not to cause
32
+ * confusing errors for programmatic consumers of this function.
33
+ */
34
+ const _args = args;
35
+ const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });
36
+ const nxJson = (0, nx_json_1.readNxJson)();
37
+ const userProvidedReleaseConfig = (0, deep_merge_json_1.deepMergeJson)(nxJson.release ?? {}, overrideReleaseConfig ?? {});
38
+ if (_args.verbose) {
39
+ process.env.NX_VERBOSE_LOGGING = 'true';
40
+ }
41
+ // Apply default configuration to any optional user configuration
42
+ const { error: configError, nxReleaseConfig } = await (0, config_1.createNxReleaseConfig)(projectGraph, await (0, file_map_utils_1.createProjectFileMapUsingProjectGraph)(projectGraph), userProvidedReleaseConfig);
43
+ if (configError) {
44
+ return await (0, config_1.handleNxReleaseConfigError)(configError);
45
+ }
46
+ // --print-config exits directly as it is not designed to be combined with any other programmatic operations
47
+ if (args.printConfig) {
48
+ return (0, print_config_1.printConfigAndExit)({
49
+ userProvidedReleaseConfig,
50
+ nxReleaseConfig,
51
+ isDebug: args.printConfig === 'debug',
52
+ });
53
+ }
54
+ const { error: filterError, releaseGroups, releaseGroupToFilteredProjects, } = (0, filter_release_groups_1.filterReleaseGroups)(projectGraph, nxReleaseConfig, _args.projects, _args.groups);
55
+ if (filterError) {
56
+ output_1.output.error(filterError);
57
+ process.exit(1);
58
+ }
59
+ /**
60
+ * If the user is filtering to a subset of projects or groups, we should not run the publish task
61
+ * for dependencies, because that could cause projects outset of the filtered set to be published.
62
+ */
63
+ const shouldExcludeTaskDependencies = _args.projects?.length > 0 ||
64
+ _args.groups?.length > 0 ||
65
+ args.excludeTaskDependencies;
66
+ let overallExitStatus = 0;
67
+ if (args.projects?.length) {
68
+ /**
69
+ * Run publishing for all remaining release groups and filtered projects within them
70
+ */
71
+ for (const releaseGroup of releaseGroups) {
72
+ const status = await runPublishOnProjects(_args, projectGraph, nxJson, Array.from(releaseGroupToFilteredProjects.get(releaseGroup)), isCLI, {
73
+ excludeTaskDependencies: shouldExcludeTaskDependencies,
74
+ loadDotEnvFiles: process.env.NX_LOAD_DOT_ENV_FILES !== 'false',
75
+ });
76
+ if (status !== 0) {
77
+ overallExitStatus = status || 1;
78
+ }
79
+ }
80
+ return overallExitStatus;
81
+ }
56
82
  /**
57
- * Run publishing for all remaining release groups and filtered projects within them
83
+ * Run publishing for all remaining release groups
58
84
  */
59
85
  for (const releaseGroup of releaseGroups) {
60
- const status = await runPublishOnProjects(_args, projectGraph, nxJson, Array.from(releaseGroupToFilteredProjects.get(releaseGroup)), isCLI, {
86
+ const status = await runPublishOnProjects(_args, projectGraph, nxJson, releaseGroup.projects, isCLI, {
61
87
  excludeTaskDependencies: shouldExcludeTaskDependencies,
62
88
  loadDotEnvFiles: process.env.NX_LOAD_DOT_ENV_FILES !== 'false',
63
89
  });
@@ -66,20 +92,7 @@ async function releasePublish(args, isCLI = false) {
66
92
  }
67
93
  }
68
94
  return overallExitStatus;
69
- }
70
- /**
71
- * Run publishing for all remaining release groups
72
- */
73
- for (const releaseGroup of releaseGroups) {
74
- const status = await runPublishOnProjects(_args, projectGraph, nxJson, releaseGroup.projects, isCLI, {
75
- excludeTaskDependencies: shouldExcludeTaskDependencies,
76
- loadDotEnvFiles: process.env.NX_LOAD_DOT_ENV_FILES !== 'false',
77
- });
78
- if (status !== 0) {
79
- overallExitStatus = status || 1;
80
- }
81
- }
82
- return overallExitStatus;
95
+ };
83
96
  }
84
97
  async function runPublishOnProjects(args, projectGraph, nxJson, projectNames, isCLI, extraOptions) {
85
98
  const projectsToRun = projectNames.map((projectName) => projectGraph.nodes[projectName]);
@@ -1,4 +1,5 @@
1
+ import { NxReleaseConfiguration } from '../../config/nx-json';
1
2
  import { ReleaseOptions, VersionOptions } from './command-object';
2
3
  import { NxReleaseVersionResult } from './version';
3
4
  export declare const releaseCLIHandler: (args: VersionOptions) => Promise<number>;
4
- export declare function release(args: ReleaseOptions): Promise<NxReleaseVersionResult | number>;
5
+ export declare function createAPI(overrideReleaseConfig: NxReleaseConfiguration): (args: ReleaseOptions) => Promise<NxReleaseVersionResult | number>;