nx 19.8.0-canary.20240920-999abe9 → 19.9.0-canary.20240921-a510b36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nx",
3
- "version": "19.8.0-canary.20240920-999abe9",
3
+ "version": "19.9.0-canary.20240921-a510b36",
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": {
@@ -68,7 +68,7 @@
68
68
  "yargs-parser": "21.1.1",
69
69
  "node-machine-id": "1.1.12",
70
70
  "ora": "5.3.0",
71
- "@nrwl/tao": "19.8.0-canary.20240920-999abe9"
71
+ "@nrwl/tao": "19.9.0-canary.20240921-a510b36"
72
72
  },
73
73
  "peerDependencies": {
74
74
  "@swc-node/register": "^1.8.0",
@@ -83,16 +83,16 @@
83
83
  }
84
84
  },
85
85
  "optionalDependencies": {
86
- "@nx/nx-darwin-x64": "19.8.0-canary.20240920-999abe9",
87
- "@nx/nx-darwin-arm64": "19.8.0-canary.20240920-999abe9",
88
- "@nx/nx-linux-x64-gnu": "19.8.0-canary.20240920-999abe9",
89
- "@nx/nx-linux-x64-musl": "19.8.0-canary.20240920-999abe9",
90
- "@nx/nx-win32-x64-msvc": "19.8.0-canary.20240920-999abe9",
91
- "@nx/nx-linux-arm64-gnu": "19.8.0-canary.20240920-999abe9",
92
- "@nx/nx-linux-arm64-musl": "19.8.0-canary.20240920-999abe9",
93
- "@nx/nx-linux-arm-gnueabihf": "19.8.0-canary.20240920-999abe9",
94
- "@nx/nx-win32-arm64-msvc": "19.8.0-canary.20240920-999abe9",
95
- "@nx/nx-freebsd-x64": "19.8.0-canary.20240920-999abe9"
86
+ "@nx/nx-darwin-x64": "19.9.0-canary.20240921-a510b36",
87
+ "@nx/nx-darwin-arm64": "19.9.0-canary.20240921-a510b36",
88
+ "@nx/nx-linux-x64-gnu": "19.9.0-canary.20240921-a510b36",
89
+ "@nx/nx-linux-x64-musl": "19.9.0-canary.20240921-a510b36",
90
+ "@nx/nx-win32-x64-msvc": "19.9.0-canary.20240921-a510b36",
91
+ "@nx/nx-linux-arm64-gnu": "19.9.0-canary.20240921-a510b36",
92
+ "@nx/nx-linux-arm64-musl": "19.9.0-canary.20240921-a510b36",
93
+ "@nx/nx-linux-arm-gnueabihf": "19.9.0-canary.20240921-a510b36",
94
+ "@nx/nx-win32-arm64-msvc": "19.9.0-canary.20240921-a510b36",
95
+ "@nx/nx-freebsd-x64": "19.9.0-canary.20240921-a510b36"
96
96
  },
97
97
  "nx-migrations": {
98
98
  "migrations": "./migrations.json",
@@ -1,7 +1,7 @@
1
1
  import { ChangelogChange } from '../../src/command-line/release/changelog';
2
2
  import { NxReleaseConfig } from '../../src/command-line/release/config/config';
3
3
  import { GitCommit } from '../../src/command-line/release/utils/git';
4
- import { RepoSlug } from '../../src/command-line/release/utils/github';
4
+ import { GithubRepoData, RepoSlug } from '../../src/command-line/release/utils/github';
5
5
  import type { ProjectGraph } from '../../src/config/project-graph';
6
6
  /**
7
7
  * The ChangelogRenderOptions are specific to each ChangelogRenderer implementation, and are taken
@@ -30,6 +30,7 @@ export type DependencyBump = {
30
30
  * @param {string | false} config.entryWhenNoChanges The (already interpolated) string to use as the changelog entry when there are no changes, or `false` if no entry should be generated
31
31
  * @param {ChangelogRenderOptions} config.changelogRenderOptions The options specific to the ChangelogRenderer implementation
32
32
  * @param {DependencyBump[]} config.dependencyBumps Optional list of additional dependency bumps that occurred as part of the release, outside of the commit data
33
+ * @param {GithubRepoData} config.repoData Resolved data for the current GitHub repository
33
34
  */
34
35
  export type ChangelogRenderer = (config: {
35
36
  projectGraph: ProjectGraph;
@@ -41,6 +42,7 @@ export type ChangelogRenderer = (config: {
41
42
  changelogRenderOptions: DefaultChangelogRenderOptions;
42
43
  dependencyBumps?: DependencyBump[];
43
44
  repoSlug?: RepoSlug;
45
+ repoData?: GithubRepoData;
44
46
  conventionalCommitsConfig: NxReleaseConfig['conventionalCommits'] | null;
45
47
  }) => Promise<string> | string;
46
48
  /**
@@ -10,7 +10,7 @@ const axios = _axios;
10
10
  * The default ChangelogRenderer implementation that nx exports for the common case of generating markdown
11
11
  * from the given commits and other metadata.
12
12
  */
13
- const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion, project, entryWhenNoChanges, changelogRenderOptions, dependencyBumps, repoSlug, conventionalCommitsConfig, }) => {
13
+ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion, project, entryWhenNoChanges, changelogRenderOptions, dependencyBumps, repoSlug, conventionalCommitsConfig, repoData, }) => {
14
14
  const markdownLines = [];
15
15
  // If the current range of changes contains both a commit and its revert, we strip them both from the final list. Changes from version plans are unaffected, as they have no hashes.
16
16
  for (const change of changes) {
@@ -46,7 +46,7 @@ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion,
46
46
  if (relevantChanges[i].isBreaking) {
47
47
  const change = relevantChanges[i];
48
48
  additionalChangesForAuthorsSection.push(change);
49
- const line = formatChange(change, changelogRenderOptions, isVersionPlans, repoSlug);
49
+ const line = formatChange(change, changelogRenderOptions, isVersionPlans, repoData);
50
50
  breakingChanges.push(line);
51
51
  relevantChanges.splice(i, 1);
52
52
  }
@@ -89,7 +89,7 @@ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion,
89
89
  for (const scope of scopesSortedAlphabetically) {
90
90
  const changes = changesGroupedByScope[scope];
91
91
  for (const change of changes) {
92
- const line = formatChange(change, changelogRenderOptions, isVersionPlans, repoSlug);
92
+ const line = formatChange(change, changelogRenderOptions, isVersionPlans, repoData);
93
93
  markdownLines.push(line);
94
94
  if (change.isBreaking) {
95
95
  const breakingChangeExplanation = extractBreakingChangeExplanation(change.body);
@@ -132,7 +132,7 @@ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion,
132
132
  markdownLines.push('', `### ${changeTypes[type].changelog.title}`, '');
133
133
  const changesInChronologicalOrder = group.reverse();
134
134
  for (const change of changesInChronologicalOrder) {
135
- const line = formatChange(change, changelogRenderOptions, isVersionPlans, repoSlug);
135
+ const line = formatChange(change, changelogRenderOptions, isVersionPlans, repoData);
136
136
  markdownLines.push(line + '\n');
137
137
  if (change.isBreaking) {
138
138
  const breakingChangeExplanation = extractBreakingChangeExplanation(change.body);
@@ -176,7 +176,7 @@ const defaultChangelogRenderer = async ({ projectGraph, changes, releaseVersion,
176
176
  }
177
177
  }
178
178
  // Try to map authors to github usernames
179
- if (repoSlug && changelogRenderOptions.mapAuthorsToGitHubUsernames) {
179
+ if (repoData && changelogRenderOptions.mapAuthorsToGitHubUsernames) {
180
180
  await Promise.all([..._authors.keys()].map(async (authorName) => {
181
181
  const meta = _authors.get(authorName);
182
182
  for (const email of meta.email) {
@@ -245,7 +245,7 @@ function groupBy(items, key) {
245
245
  }
246
246
  return groups;
247
247
  }
248
- function formatChange(change, changelogRenderOptions, isVersionPlans, repoSlug) {
248
+ function formatChange(change, changelogRenderOptions, isVersionPlans, repoData) {
249
249
  let description = change.description;
250
250
  let extraLines = [];
251
251
  let extraLinesStr = '';
@@ -267,8 +267,8 @@ function formatChange(change, changelogRenderOptions, isVersionPlans, repoSlug)
267
267
  (!isVersionPlans && change.isBreaking ? '⚠️ ' : '') +
268
268
  (!isVersionPlans && change.scope ? `**${change.scope.trim()}:** ` : '') +
269
269
  description;
270
- if (repoSlug && changelogRenderOptions.commitReferences) {
271
- changeLine += (0, github_1.formatReferences)(change.githubReferences, repoSlug);
270
+ if (repoData && changelogRenderOptions.commitReferences) {
271
+ changeLine += (0, github_1.formatReferences)(change.githubReferences, repoData);
272
272
  }
273
273
  if (extraLinesStr) {
274
274
  changeLine += '\n\n' + extraLinesStr;
@@ -691,6 +691,9 @@
691
691
  {
692
692
  "type": "boolean",
693
693
  "enum": [false]
694
+ },
695
+ {
696
+ "$ref": "#/definitions/CreateReleaseProviderConfiguration"
694
697
  }
695
698
  ]
696
699
  },
@@ -724,6 +727,24 @@
724
727
  }
725
728
  }
726
729
  },
730
+ "CreateReleaseProviderConfiguration": {
731
+ "type": "object",
732
+ "properties": {
733
+ "provider": {
734
+ "type": "string",
735
+ "enum": ["github-enterprise-server"]
736
+ },
737
+ "hostname": {
738
+ "type": "string",
739
+ "description": "The hostname of the VCS provider instance, e.g. github.example.com"
740
+ },
741
+ "apiBaseUrl": {
742
+ "type": "string",
743
+ "description": "The base URL for the relevant VCS provider API. If not set, this will default to `https://${hostname}/api/v3`"
744
+ }
745
+ },
746
+ "required": ["provider", "hostname"]
747
+ },
727
748
  "NxReleaseVersionPlansConfiguration": {
728
749
  "type": "object",
729
750
  "properties": {
@@ -242,7 +242,9 @@ function createAPI(overrideReleaseConfig) {
242
242
  hasPushed = true;
243
243
  }
244
244
  output_1.output.logSingleLine(`Creating GitHub Release`);
245
- await (0, github_1.createOrUpdateGithubRelease)(workspaceChangelog.releaseVersion, workspaceChangelog.contents, latestCommit, { dryRun: args.dryRun });
245
+ await (0, github_1.createOrUpdateGithubRelease)(nxReleaseConfig.changelog.workspaceChangelog
246
+ ? nxReleaseConfig.changelog.workspaceChangelog.createRelease
247
+ : config_1.defaultCreateReleaseProvider, workspaceChangelog.releaseVersion, workspaceChangelog.contents, latestCommit, { dryRun: args.dryRun });
246
248
  });
247
249
  }
248
250
  /**
@@ -401,7 +403,9 @@ function createAPI(overrideReleaseConfig) {
401
403
  hasPushed = true;
402
404
  }
403
405
  output_1.output.logSingleLine(`Creating GitHub Release`);
404
- await (0, github_1.createOrUpdateGithubRelease)(projectChangelog.releaseVersion, projectChangelog.contents, latestCommit, { dryRun: args.dryRun });
406
+ await (0, github_1.createOrUpdateGithubRelease)(releaseGroup.changelog
407
+ ? releaseGroup.changelog.createRelease
408
+ : config_1.defaultCreateReleaseProvider, projectChangelog.releaseVersion, projectChangelog.contents, latestCommit, { dryRun: args.dryRun });
405
409
  });
406
410
  }
407
411
  allProjectChangelogs[projectName] = projectChangelog;
@@ -516,7 +520,9 @@ function createAPI(overrideReleaseConfig) {
516
520
  hasPushed = true;
517
521
  }
518
522
  output_1.output.logSingleLine(`Creating GitHub Release`);
519
- await (0, github_1.createOrUpdateGithubRelease)(projectChangelog.releaseVersion, projectChangelog.contents, latestCommit, { dryRun: args.dryRun });
523
+ await (0, github_1.createOrUpdateGithubRelease)(releaseGroup.changelog
524
+ ? releaseGroup.changelog.createRelease
525
+ : config_1.defaultCreateReleaseProvider, projectChangelog.releaseVersion, projectChangelog.contents, latestCommit, { dryRun: args.dryRun });
520
526
  });
521
527
  }
522
528
  allProjectChangelogs[projectName] = projectChangelog;
@@ -730,14 +736,15 @@ async function generateChangelogForWorkspace({ tree, args, projectGraph, nxRelea
730
736
  title: `${prefix} an entry in ${interpolatedTreePath} for ${chalk.white(releaseVersion.gitTag)}`,
731
737
  });
732
738
  }
733
- const githubRepoSlug = (0, github_1.getGitHubRepoSlug)(gitRemote);
739
+ const githubRepoData = (0, github_1.getGitHubRepoData)(gitRemote, config.createRelease);
734
740
  let contents = await changelogRenderer({
735
741
  projectGraph,
736
742
  changes,
737
743
  commits,
738
744
  releaseVersion: releaseVersion.rawVersion,
739
745
  project: null,
740
- repoSlug: githubRepoSlug,
746
+ repoSlug: githubRepoData?.slug,
747
+ repoData: githubRepoData,
741
748
  entryWhenNoChanges: config.entryWhenNoChanges,
742
749
  changelogRenderOptions: config.renderOptions,
743
750
  conventionalCommitsConfig: nxReleaseConfig.conventionalCommits,
@@ -822,16 +829,15 @@ async function generateChangelogForProjects({ tree, args, projectGraph, changes,
822
829
  title: `${prefix} an entry in ${interpolatedTreePath} for ${chalk.white(releaseVersion.gitTag)}`,
823
830
  });
824
831
  }
825
- const githubRepoSlug = config.createRelease === 'github'
826
- ? (0, github_1.getGitHubRepoSlug)(gitRemote)
827
- : undefined;
832
+ const githubRepoData = (0, github_1.getGitHubRepoData)(gitRemote, config.createRelease);
828
833
  let contents = await changelogRenderer({
829
834
  projectGraph,
830
835
  changes,
831
836
  commits,
832
837
  releaseVersion: releaseVersion.rawVersion,
833
838
  project: project.name,
834
- repoSlug: githubRepoSlug,
839
+ repoSlug: githubRepoData?.slug,
840
+ repoData: githubRepoData,
835
841
  entryWhenNoChanges: typeof config.entryWhenNoChanges === 'string'
836
842
  ? (0, utils_1.interpolate)(config.entryWhenNoChanges, {
837
843
  projectName: project.name,
@@ -937,7 +943,7 @@ function shouldCreateGitHubRelease(changelogConfig, createReleaseArg = undefined
937
943
  if (createReleaseArg !== undefined) {
938
944
  return createReleaseArg === 'github';
939
945
  }
940
- return (changelogConfig || {}).createRelease === 'github';
946
+ return (changelogConfig || {}).createRelease !== false;
941
947
  }
942
948
  async function promptForGitHubRelease() {
943
949
  try {
@@ -42,7 +42,7 @@ export type NxReleaseConfig = Omit<DeepRequired<NxJsonConfiguration['release'] &
42
42
  };
43
43
  }>, 'projects'>;
44
44
  export interface CreateNxReleaseConfigError {
45
- code: 'PROJECTS_AND_GROUPS_DEFINED' | 'RELEASE_GROUP_MATCHES_NO_PROJECTS' | 'RELEASE_GROUP_RELEASE_TAG_PATTERN_VERSION_PLACEHOLDER_MISSING_OR_EXCESSIVE' | 'PROJECT_MATCHES_MULTIPLE_GROUPS' | 'CONVENTIONAL_COMMITS_SHORTHAND_MIXED_WITH_OVERLAPPING_GENERATOR_OPTIONS' | 'GLOBAL_GIT_CONFIG_MIXED_WITH_GRANULAR_GIT_CONFIG';
45
+ code: 'PROJECTS_AND_GROUPS_DEFINED' | 'RELEASE_GROUP_MATCHES_NO_PROJECTS' | 'RELEASE_GROUP_RELEASE_TAG_PATTERN_VERSION_PLACEHOLDER_MISSING_OR_EXCESSIVE' | 'PROJECT_MATCHES_MULTIPLE_GROUPS' | 'CONVENTIONAL_COMMITS_SHORTHAND_MIXED_WITH_OVERLAPPING_GENERATOR_OPTIONS' | 'GLOBAL_GIT_CONFIG_MIXED_WITH_GRANULAR_GIT_CONFIG' | 'CANNOT_RESOLVE_CHANGELOG_RENDERER' | 'INVALID_CHANGELOG_CREATE_RELEASE_PROVIDER' | 'INVALID_CHANGELOG_CREATE_RELEASE_HOSTNAME' | 'INVALID_CHANGELOG_CREATE_RELEASE_API_BASE_URL';
46
46
  data: Record<string, string | string[]>;
47
47
  }
48
48
  export declare function createNxReleaseConfig(projectGraph: ProjectGraph, projectFileMap: ProjectFileMap, userConfig?: NxJsonConfiguration['release']): Promise<{
@@ -50,4 +50,5 @@ export declare function createNxReleaseConfig(projectGraph: ProjectGraph, projec
50
50
  nxReleaseConfig: NxReleaseConfig | null;
51
51
  }>;
52
52
  export declare function handleNxReleaseConfigError(error: CreateNxReleaseConfigError): Promise<never>;
53
+ export declare const defaultCreateReleaseProvider: any;
53
54
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.IMPLICIT_DEFAULT_RELEASE_GROUP = void 0;
3
+ exports.defaultCreateReleaseProvider = exports.IMPLICIT_DEFAULT_RELEASE_GROUP = void 0;
4
4
  exports.createNxReleaseConfig = createNxReleaseConfig;
5
5
  exports.handleNxReleaseConfigError = handleNxReleaseConfigError;
6
6
  /**
@@ -17,6 +17,7 @@ exports.handleNxReleaseConfigError = handleNxReleaseConfigError;
17
17
  * and easy to consume config object for all the `nx release` command implementations.
18
18
  */
19
19
  const node_path_1 = require("node:path");
20
+ const node_url_1 = require("node:url");
20
21
  const fileutils_1 = require("../../../utils/fileutils");
21
22
  const find_matching_projects_1 = require("../../../utils/find-matching-projects");
22
23
  const output_1 = require("../../../utils/output");
@@ -368,7 +369,13 @@ async function createNxReleaseConfig(projectGraph, projectFileMap, userConfig =
368
369
  }
369
370
  releaseGroups[releaseGroupName] = finalReleaseGroup;
370
371
  }
371
- ensureChangelogRenderersAreResolvable(releaseGroups, rootChangelogConfig);
372
+ const configError = validateChangelogConfig(releaseGroups, rootChangelogConfig);
373
+ if (configError) {
374
+ return {
375
+ error: configError,
376
+ nxReleaseConfig: null,
377
+ };
378
+ }
372
379
  return {
373
380
  error: null,
374
381
  nxReleaseConfig: {
@@ -547,6 +554,48 @@ async function handleNxReleaseConfigError(error) {
547
554
  });
548
555
  }
549
556
  break;
557
+ case 'CANNOT_RESOLVE_CHANGELOG_RENDERER': {
558
+ const nxJsonMessage = await (0, resolve_nx_json_error_message_1.resolveNxJsonConfigErrorMessage)(['release']);
559
+ output_1.output.error({
560
+ title: `There was an error when resolving the configured changelog renderer at path: ${error.data.workspaceRelativePath}`,
561
+ bodyLines: [nxJsonMessage],
562
+ });
563
+ }
564
+ case 'INVALID_CHANGELOG_CREATE_RELEASE_PROVIDER':
565
+ {
566
+ const nxJsonMessage = await (0, resolve_nx_json_error_message_1.resolveNxJsonConfigErrorMessage)([
567
+ 'release',
568
+ ]);
569
+ output_1.output.error({
570
+ title: `Your "changelog.createRelease" config specifies an unsupported provider "${error.data.provider}". The supported providers are ${error.data.supportedProviders
571
+ .map((p) => `"${p}"`)
572
+ .join(', ')}`,
573
+ bodyLines: [nxJsonMessage],
574
+ });
575
+ }
576
+ break;
577
+ case 'INVALID_CHANGELOG_CREATE_RELEASE_HOSTNAME':
578
+ {
579
+ const nxJsonMessage = await (0, resolve_nx_json_error_message_1.resolveNxJsonConfigErrorMessage)([
580
+ 'release',
581
+ ]);
582
+ output_1.output.error({
583
+ title: `Your "changelog.createRelease" config specifies an invalid hostname "${error.data.hostname}". Please ensure you provide a valid hostname value, such as "example.com"`,
584
+ bodyLines: [nxJsonMessage],
585
+ });
586
+ }
587
+ break;
588
+ case 'INVALID_CHANGELOG_CREATE_RELEASE_API_BASE_URL':
589
+ {
590
+ const nxJsonMessage = await (0, resolve_nx_json_error_message_1.resolveNxJsonConfigErrorMessage)([
591
+ 'release',
592
+ ]);
593
+ output_1.output.error({
594
+ title: `Your "changelog.createRelease" config specifies an invalid apiBaseUrl "${error.data.apiBaseUrl}". Please ensure you provide a valid URL value, such as "https://example.com"`,
595
+ bodyLines: [nxJsonMessage],
596
+ });
597
+ }
598
+ break;
550
599
  default:
551
600
  throw new Error(`Unhandled error code: ${error.code}`);
552
601
  }
@@ -678,42 +727,138 @@ function isProjectPublic(project, projectGraph, projectFileMap) {
678
727
  return false;
679
728
  }
680
729
  }
681
- function ensureChangelogRenderersAreResolvable(releaseGroups, rootChangelogConfig) {
730
+ /**
731
+ * We need to ensure that changelog renderers are resolvable up front so that we do not end up erroring after performing
732
+ * actions later, and we also make sure that any configured createRelease options are valid.
733
+ *
734
+ * For the createRelease config, we also set a default apiBaseUrl if applicable.
735
+ */
736
+ function validateChangelogConfig(releaseGroups, rootChangelogConfig) {
682
737
  /**
683
738
  * If any form of changelog config is enabled, ensure that any provided changelog renderers are resolvable
684
739
  * up front so that we do not end up erroring only after the versioning step has been completed.
685
740
  */
686
741
  const uniqueRendererPaths = new Set();
687
742
  if (rootChangelogConfig.workspaceChangelog &&
688
- typeof rootChangelogConfig.workspaceChangelog !== 'boolean' &&
689
- rootChangelogConfig.workspaceChangelog.renderer?.length) {
690
- uniqueRendererPaths.add(rootChangelogConfig.workspaceChangelog.renderer);
743
+ typeof rootChangelogConfig.workspaceChangelog !== 'boolean') {
744
+ if (rootChangelogConfig.workspaceChangelog.renderer?.length) {
745
+ uniqueRendererPaths.add(rootChangelogConfig.workspaceChangelog.renderer);
746
+ }
747
+ const createReleaseError = validateCreateReleaseConfig(rootChangelogConfig.workspaceChangelog);
748
+ if (createReleaseError) {
749
+ return createReleaseError;
750
+ }
691
751
  }
692
752
  if (rootChangelogConfig.projectChangelogs &&
693
- typeof rootChangelogConfig.projectChangelogs !== 'boolean' &&
694
- rootChangelogConfig.projectChangelogs.renderer?.length) {
695
- uniqueRendererPaths.add(rootChangelogConfig.projectChangelogs.renderer);
753
+ typeof rootChangelogConfig.projectChangelogs !== 'boolean') {
754
+ if (rootChangelogConfig.projectChangelogs.renderer?.length) {
755
+ uniqueRendererPaths.add(rootChangelogConfig.projectChangelogs.renderer);
756
+ }
757
+ const createReleaseError = validateCreateReleaseConfig(rootChangelogConfig.projectChangelogs);
758
+ if (createReleaseError) {
759
+ return createReleaseError;
760
+ }
696
761
  }
697
762
  for (const group of Object.values(releaseGroups)) {
698
- if (group.changelog &&
699
- typeof group.changelog !== 'boolean' &&
700
- group.changelog.renderer?.length) {
701
- uniqueRendererPaths.add(group.changelog.renderer);
763
+ if (group.changelog && typeof group.changelog !== 'boolean') {
764
+ if (group.changelog.renderer?.length) {
765
+ uniqueRendererPaths.add(group.changelog.renderer);
766
+ }
767
+ const createReleaseError = validateCreateReleaseConfig(group.changelog);
768
+ if (createReleaseError) {
769
+ return createReleaseError;
770
+ }
702
771
  }
703
772
  }
704
773
  if (!uniqueRendererPaths.size) {
705
- return;
774
+ return null;
706
775
  }
707
776
  for (const rendererPath of uniqueRendererPaths) {
708
777
  try {
709
778
  (0, resolve_changelog_renderer_1.resolveChangelogRenderer)(rendererPath);
710
779
  }
711
- catch (e) {
712
- const workspaceRelativePath = (0, node_path_1.relative)(workspace_root_1.workspaceRoot, rendererPath);
713
- output_1.output.error({
714
- title: `There was an error when resolving the configured changelog renderer at path: ${workspaceRelativePath}`,
715
- });
716
- throw e;
780
+ catch {
781
+ return {
782
+ code: 'CANNOT_RESOLVE_CHANGELOG_RENDERER',
783
+ data: {
784
+ workspaceRelativePath: (0, node_path_1.relative)(workspace_root_1.workspaceRoot, rendererPath),
785
+ },
786
+ };
717
787
  }
718
788
  }
789
+ return null;
790
+ }
791
+ const supportedCreateReleaseProviders = [
792
+ {
793
+ name: 'github-enterprise-server',
794
+ defaultApiBaseUrl: 'https://__hostname__/api/v3',
795
+ },
796
+ ];
797
+ // User opts into the default by specifying the string value 'github'
798
+ exports.defaultCreateReleaseProvider = {
799
+ provider: 'github',
800
+ hostname: 'github.com',
801
+ apiBaseUrl: 'https://api.github.com',
802
+ };
803
+ function validateCreateReleaseConfig(changelogConfig) {
804
+ const createRelease = changelogConfig.createRelease;
805
+ // Disabled: valid
806
+ if (!createRelease) {
807
+ return null;
808
+ }
809
+ // GitHub shorthand, expand to full object form, mark as valid
810
+ if (createRelease === 'github') {
811
+ changelogConfig.createRelease = exports.defaultCreateReleaseProvider;
812
+ return null;
813
+ }
814
+ // Object config, ensure that properties are valid
815
+ const supportedProvider = supportedCreateReleaseProviders.find((p) => p.name === createRelease.provider);
816
+ if (!supportedProvider) {
817
+ return {
818
+ code: 'INVALID_CHANGELOG_CREATE_RELEASE_PROVIDER',
819
+ data: {
820
+ provider: createRelease.provider,
821
+ supportedProviders: supportedCreateReleaseProviders.map((p) => p.name),
822
+ },
823
+ };
824
+ }
825
+ if (!isValidHostname(createRelease.hostname)) {
826
+ return {
827
+ code: 'INVALID_CHANGELOG_CREATE_RELEASE_HOSTNAME',
828
+ data: {
829
+ hostname: createRelease.hostname,
830
+ },
831
+ };
832
+ }
833
+ // user provided a custom apiBaseUrl, ensure it is valid (accounting for empty string case)
834
+ if (createRelease.apiBaseUrl ||
835
+ typeof createRelease.apiBaseUrl === 'string') {
836
+ if (!isValidUrl(createRelease.apiBaseUrl)) {
837
+ return {
838
+ code: 'INVALID_CHANGELOG_CREATE_RELEASE_API_BASE_URL',
839
+ data: {
840
+ apiBaseUrl: createRelease.apiBaseUrl,
841
+ },
842
+ };
843
+ }
844
+ }
845
+ else {
846
+ // Set default apiBaseUrl when not provided by the user
847
+ createRelease.apiBaseUrl = supportedProvider.defaultApiBaseUrl.replace('__hostname__', createRelease.hostname);
848
+ }
849
+ return null;
850
+ }
851
+ function isValidHostname(hostname) {
852
+ // Regular expression to match a valid hostname
853
+ const hostnameRegex = /^(?!:\/\/)(?=.{1,255}$)(?!.*\.$)(?!.*?\.\.)(?!.*?-$)(?!^-)([a-zA-Z0-9-]{1,63}\.?)+[a-zA-Z]{2,}$/;
854
+ return hostnameRegex.test(hostname);
855
+ }
856
+ function isValidUrl(str) {
857
+ try {
858
+ new node_url_1.URL(str);
859
+ return true;
860
+ }
861
+ catch {
862
+ return false;
863
+ }
719
864
  }
@@ -168,7 +168,9 @@ function createAPI(overrideReleaseConfig) {
168
168
  hasPushedChanges = true;
169
169
  output_1.output.logSingleLine(`Creating GitHub Release`);
170
170
  latestCommit = await (0, git_1.getCommitHash)('HEAD');
171
- await (0, github_1.createOrUpdateGithubRelease)(changelogResult.workspaceChangelog.releaseVersion, changelogResult.workspaceChangelog.contents, latestCommit, { dryRun: args.dryRun });
171
+ await (0, github_1.createOrUpdateGithubRelease)(nxReleaseConfig.changelog.workspaceChangelog
172
+ ? nxReleaseConfig.changelog.workspaceChangelog.createRelease
173
+ : false, changelogResult.workspaceChangelog.releaseVersion, changelogResult.workspaceChangelog.contents, latestCommit, { dryRun: args.dryRun });
172
174
  }
173
175
  for (const releaseGroup of releaseGroups) {
174
176
  const shouldCreateProjectReleases = (0, changelog_1.shouldCreateGitHubRelease)(releaseGroup.changelog);
@@ -197,7 +199,9 @@ function createAPI(overrideReleaseConfig) {
197
199
  if (!latestCommit) {
198
200
  latestCommit = await (0, git_1.getCommitHash)('HEAD');
199
201
  }
200
- await (0, github_1.createOrUpdateGithubRelease)(changelog.releaseVersion, changelog.contents, latestCommit, { dryRun: args.dryRun });
202
+ await (0, github_1.createOrUpdateGithubRelease)(releaseGroup.changelog
203
+ ? releaseGroup.changelog.createRelease
204
+ : false, changelog.releaseVersion, changelog.contents, latestCommit, { dryRun: args.dryRun });
201
205
  }
202
206
  }
203
207
  }
@@ -1,11 +1,14 @@
1
+ import { NxReleaseChangelogConfiguration } from '../../../config/nx-json';
1
2
  import { Reference } from './git';
2
3
  import { ReleaseVersion } from './shared';
3
4
  export type RepoSlug = `${string}/${string}`;
4
- export interface GithubRequestConfig {
5
+ interface GithubRequestConfig {
5
6
  repo: string;
7
+ hostname: string;
8
+ apiBaseUrl: string;
6
9
  token: string | null;
7
10
  }
8
- export interface GithubRelease {
11
+ interface GithubRelease {
9
12
  id?: string;
10
13
  tag_name: string;
11
14
  target_commitish?: string;
@@ -14,10 +17,15 @@ export interface GithubRelease {
14
17
  draft?: boolean;
15
18
  prerelease?: boolean;
16
19
  }
17
- export declare function getGitHubRepoSlug(remoteName?: string): RepoSlug;
18
- export declare function createOrUpdateGithubRelease(releaseVersion: ReleaseVersion, changelogContents: string, latestCommit: string, { dryRun }: {
20
+ export interface GithubRepoData {
21
+ hostname: string;
22
+ slug: RepoSlug;
23
+ apiBaseUrl: string;
24
+ }
25
+ export declare function getGitHubRepoData(remoteName: string, createReleaseConfig: NxReleaseChangelogConfiguration['createRelease']): GithubRepoData | null;
26
+ export declare function createOrUpdateGithubRelease(createReleaseConfig: NxReleaseChangelogConfiguration['createRelease'], releaseVersion: ReleaseVersion, changelogContents: string, latestCommit: string, { dryRun }: {
19
27
  dryRun: boolean;
20
28
  }): Promise<void>;
21
- export declare function resolveGithubToken(): Promise<string | null>;
22
29
  export declare function getGithubReleaseByTag(config: GithubRequestConfig, tag: string): Promise<GithubRelease>;
23
- export declare function formatReferences(references: Reference[], repoSlug: RepoSlug): string;
30
+ export declare function formatReferences(references: Reference[], repoData: GithubRepoData): string;
31
+ export {};