nx 19.8.0-canary.20240919-7f4a877 → 19.8.0

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nx",
3
- "version": "19.8.0-canary.20240919-7f4a877",
3
+ "version": "19.8.0",
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.20240919-7f4a877"
71
+ "@nrwl/tao": "19.8.0"
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.20240919-7f4a877",
87
- "@nx/nx-darwin-arm64": "19.8.0-canary.20240919-7f4a877",
88
- "@nx/nx-linux-x64-gnu": "19.8.0-canary.20240919-7f4a877",
89
- "@nx/nx-linux-x64-musl": "19.8.0-canary.20240919-7f4a877",
90
- "@nx/nx-win32-x64-msvc": "19.8.0-canary.20240919-7f4a877",
91
- "@nx/nx-linux-arm64-gnu": "19.8.0-canary.20240919-7f4a877",
92
- "@nx/nx-linux-arm64-musl": "19.8.0-canary.20240919-7f4a877",
93
- "@nx/nx-linux-arm-gnueabihf": "19.8.0-canary.20240919-7f4a877",
94
- "@nx/nx-win32-arm64-msvc": "19.8.0-canary.20240919-7f4a877",
95
- "@nx/nx-freebsd-x64": "19.8.0-canary.20240919-7f4a877"
86
+ "@nx/nx-darwin-x64": "19.8.0",
87
+ "@nx/nx-darwin-arm64": "19.8.0",
88
+ "@nx/nx-linux-x64-gnu": "19.8.0",
89
+ "@nx/nx-linux-x64-musl": "19.8.0",
90
+ "@nx/nx-win32-x64-msvc": "19.8.0",
91
+ "@nx/nx-linux-arm64-gnu": "19.8.0",
92
+ "@nx/nx-linux-arm64-musl": "19.8.0",
93
+ "@nx/nx-linux-arm-gnueabihf": "19.8.0",
94
+ "@nx/nx-win32-arm64-msvc": "19.8.0",
95
+ "@nx/nx-freebsd-x64": "19.8.0"
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": {
@@ -24,6 +24,7 @@ export interface ProjectGraphClientResponse {
24
24
  isPartial: boolean;
25
25
  errors?: GraphError[];
26
26
  connectedToCloud?: boolean;
27
+ disabledTaskSyncGenerators?: string[];
27
28
  }
28
29
  export interface TaskGraphClientResponse {
29
30
  taskGraphs: Record<string, TaskGraph>;
@@ -499,11 +499,14 @@ async function createProjectGraphAndSourceMapClientResponse(affected = []) {
499
499
  let isPartial = false;
500
500
  let errors;
501
501
  let connectedToCloud;
502
+ let disabledTaskSyncGenerators;
502
503
  try {
503
504
  const projectGraphAndSourceMaps = await (0, project_graph_1.createProjectGraphAndSourceMapsAsync)({ exitOnError: false });
504
505
  projectGraph = projectGraphAndSourceMaps.projectGraph;
505
506
  sourceMaps = projectGraphAndSourceMaps.sourceMaps;
506
- connectedToCloud = (0, nx_cloud_utils_1.isNxCloudUsed)((0, configuration_1.readNxJson)());
507
+ const nxJson = (0, configuration_1.readNxJson)();
508
+ connectedToCloud = (0, nx_cloud_utils_1.isNxCloudUsed)(nxJson);
509
+ disabledTaskSyncGenerators = nxJson.sync?.disabledTaskSyncGenerators;
507
510
  }
508
511
  catch (e) {
509
512
  if (e instanceof error_types_1.ProjectGraphError) {
@@ -538,6 +541,7 @@ async function createProjectGraphAndSourceMapClientResponse(affected = []) {
538
541
  sourceMaps,
539
542
  errors,
540
543
  connectedToCloud,
544
+ disabledTaskSyncGenerators,
541
545
  }));
542
546
  const hash = hasher.digest('hex');
543
547
  perf_hooks_1.performance.mark('project graph response generation:end');
@@ -555,6 +559,7 @@ async function createProjectGraphAndSourceMapClientResponse(affected = []) {
555
559
  isPartial,
556
560
  errors,
557
561
  connectedToCloud,
562
+ disabledTaskSyncGenerators,
558
563
  },
559
564
  sourceMapResponse: sourceMaps,
560
565
  };
@@ -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 {};