nx 21.0.0-canary.20250429-cf4a1f3 → 21.0.0-canary.20250501-8f50358

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.
Files changed (63) hide show
  1. package/migrations.json +16 -1
  2. package/package.json +11 -11
  3. package/release/changelog-renderer/index.d.ts +7 -7
  4. package/release/changelog-renderer/index.js +12 -31
  5. package/schemas/nx-schema.json +8 -3
  6. package/src/command-line/migrate/migrate-ui-api.d.ts +2 -1
  7. package/src/command-line/migrate/migrate-ui-api.js +4 -3
  8. package/src/command-line/migrate/migrate.d.ts +12 -6
  9. package/src/command-line/migrate/migrate.js +31 -9
  10. package/src/command-line/release/changelog.d.ts +3 -2
  11. package/src/command-line/release/changelog.js +57 -70
  12. package/src/command-line/release/command-object.d.ts +1 -1
  13. package/src/command-line/release/config/config.d.ts +8 -1
  14. package/src/command-line/release/config/config.js +18 -11
  15. package/src/command-line/release/release.js +30 -18
  16. package/src/command-line/release/utils/git.d.ts +1 -0
  17. package/src/command-line/release/utils/git.js +27 -8
  18. package/src/command-line/release/utils/remote-release-clients/github.d.ts +57 -0
  19. package/src/command-line/release/utils/remote-release-clients/github.js +309 -0
  20. package/src/command-line/release/utils/remote-release-clients/gitlab.d.ts +62 -0
  21. package/src/command-line/release/utils/remote-release-clients/gitlab.js +271 -0
  22. package/src/command-line/release/utils/remote-release-clients/remote-release-client.d.ts +111 -0
  23. package/src/command-line/release/utils/remote-release-clients/remote-release-client.js +136 -0
  24. package/src/command-line/repair/repair.js +8 -2
  25. package/src/command-line/report/report.js +1 -1
  26. package/src/command-line/yargs-utils/shared-options.d.ts +1 -1
  27. package/src/command-line/yargs-utils/shared-options.js +22 -3
  28. package/src/config/misc-interfaces.d.ts +9 -1
  29. package/src/config/nx-json.d.ts +8 -5
  30. package/src/core/graph/main.js +1 -1
  31. package/src/core/graph/styles.css +1 -1
  32. package/src/devkit-exports.d.ts +1 -1
  33. package/src/migrations/update-21-0-0/release-changelog-config-changes.d.ts +2 -0
  34. package/src/migrations/update-21-0-0/release-changelog-config-changes.js +38 -0
  35. package/src/migrations/update-21-0-0/remove-custom-tasks-runner.d.ts +2 -0
  36. package/src/migrations/update-21-0-0/remove-custom-tasks-runner.js +38 -0
  37. package/src/migrations/update-21-0-0/remove-legacy-cache.d.ts +2 -0
  38. package/src/migrations/update-21-0-0/remove-legacy-cache.js +17 -0
  39. package/src/native/index.d.ts +6 -1
  40. package/src/native/native-bindings.js +1 -0
  41. package/src/native/native-file-cache-location.js +2 -1
  42. package/src/native/nx.wasm32-wasi.wasm +0 -0
  43. package/src/project-graph/plugins/get-plugins.js +19 -14
  44. package/src/tasks-runner/batch/run-batch.js +1 -1
  45. package/src/tasks-runner/cache.d.ts +1 -2
  46. package/src/tasks-runner/cache.js +2 -18
  47. package/src/tasks-runner/is-tui-enabled.d.ts +16 -1
  48. package/src/tasks-runner/is-tui-enabled.js +40 -28
  49. package/src/tasks-runner/life-cycles/tui-summary-life-cycle.js +8 -7
  50. package/src/tasks-runner/pseudo-terminal.d.ts +1 -0
  51. package/src/tasks-runner/pseudo-terminal.js +11 -1
  52. package/src/tasks-runner/run-command.js +5 -27
  53. package/src/tasks-runner/running-tasks/node-child-process.d.ts +1 -0
  54. package/src/tasks-runner/running-tasks/node-child-process.js +7 -0
  55. package/src/tasks-runner/task-graph-utils.d.ts +3 -0
  56. package/src/tasks-runner/task-graph-utils.js +31 -2
  57. package/src/tasks-runner/task-orchestrator.js +16 -4
  58. package/src/utils/is-ci.d.ts +1 -1
  59. package/src/utils/is-ci.js +4 -1
  60. package/src/utils/package-manager.d.ts +1 -0
  61. package/src/utils/package-manager.js +29 -16
  62. package/src/command-line/release/utils/github.d.ts +0 -32
  63. package/src/command-line/release/utils/github.js +0 -326
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.releaseChangelogCLIHandler = void 0;
4
4
  exports.createAPI = createAPI;
5
- exports.shouldCreateGitHubRelease = shouldCreateGitHubRelease;
6
5
  const chalk = require("chalk");
7
6
  const enquirer_1 = require("enquirer");
8
7
  const node_fs_1 = require("node:fs");
@@ -24,11 +23,11 @@ const filter_release_groups_1 = require("./config/filter-release-groups");
24
23
  const use_legacy_versioning_1 = require("./config/use-legacy-versioning");
25
24
  const version_plans_1 = require("./config/version-plans");
26
25
  const git_1 = require("./utils/git");
27
- const github_1 = require("./utils/github");
28
26
  const launch_editor_1 = require("./utils/launch-editor");
29
27
  const markdown_1 = require("./utils/markdown");
30
28
  const print_changes_1 = require("./utils/print-changes");
31
29
  const print_config_1 = require("./utils/print-config");
30
+ const remote_release_client_1 = require("./utils/remote-release-clients/remote-release-client");
32
31
  const resolve_changelog_renderer_1 = require("./utils/resolve-changelog-renderer");
33
32
  const resolve_nx_json_error_message_1 = require("./utils/resolve-nx-json-error-message");
34
33
  const shared_1 = require("./utils/shared");
@@ -226,21 +225,13 @@ function createAPI(overrideReleaseConfig) {
226
225
  const workspaceChangelog = await generateChangelogForWorkspace({
227
226
  tree,
228
227
  args,
229
- projectGraph,
230
228
  nxReleaseConfig,
231
229
  workspaceChangelogVersion,
232
230
  changes: workspaceChangelogChanges,
233
- // TODO(v22): remove this after the changelog renderer is refactored to remove coupling with git commits
234
- commits: filterHiddenCommits(workspaceChangelogCommits, nxReleaseConfig.conventionalCommits),
235
231
  });
236
- if (workspaceChangelog &&
237
- shouldCreateGitHubRelease(nxReleaseConfig.changelog.workspaceChangelog, args.createRelease)) {
238
- postGitTasks.push(async (latestCommit) => {
239
- output_1.output.logSingleLine(`Creating GitHub Release`);
240
- await (0, github_1.createOrUpdateGithubRelease)(nxReleaseConfig.changelog.workspaceChangelog
241
- ? nxReleaseConfig.changelog.workspaceChangelog.createRelease
242
- : config_1.defaultCreateReleaseProvider, workspaceChangelog.releaseVersion, workspaceChangelog.contents, latestCommit, { dryRun: args.dryRun });
243
- });
232
+ // Add the post git task (e.g. create a remote release) for the workspace changelog, if applicable
233
+ if (workspaceChangelog && workspaceChangelog.postGitTask) {
234
+ postGitTasks.push(workspaceChangelog.postGitTask);
244
235
  }
245
236
  /**
246
237
  * Compute any additional dependency bumps up front because there could be cases of circular dependencies,
@@ -381,17 +372,14 @@ function createAPI(overrideReleaseConfig) {
381
372
  nxReleaseConfig,
382
373
  projectToAdditionalDependencyBumps,
383
374
  });
384
- for (const [projectName, projectChangelog] of Object.entries(projectChangelogs)) {
385
- if (projectChangelogs &&
386
- shouldCreateGitHubRelease(releaseGroup.changelog, args.createRelease)) {
387
- postGitTasks.push(async (latestCommit) => {
388
- output_1.output.logSingleLine(`Creating GitHub Release`);
389
- await (0, github_1.createOrUpdateGithubRelease)(releaseGroup.changelog
390
- ? releaseGroup.changelog.createRelease
391
- : config_1.defaultCreateReleaseProvider, projectChangelog.releaseVersion, projectChangelog.contents, latestCommit, { dryRun: args.dryRun });
392
- });
375
+ if (projectChangelogs) {
376
+ for (const [projectName, projectChangelog] of Object.entries(projectChangelogs)) {
377
+ // Add the post git task (e.g. create a remote release) for the project changelog, if applicable
378
+ if (projectChangelog.postGitTask) {
379
+ postGitTasks.push(projectChangelog.postGitTask);
380
+ }
381
+ allProjectChangelogs[projectName] = projectChangelog;
393
382
  }
394
- allProjectChangelogs[projectName] = projectChangelog;
395
383
  }
396
384
  }
397
385
  }
@@ -486,17 +474,14 @@ function createAPI(overrideReleaseConfig) {
486
474
  nxReleaseConfig,
487
475
  projectToAdditionalDependencyBumps,
488
476
  });
489
- for (const [projectName, projectChangelog] of Object.entries(projectChangelogs)) {
490
- if (projectChangelogs &&
491
- shouldCreateGitHubRelease(releaseGroup.changelog, args.createRelease)) {
492
- postGitTasks.push(async (latestCommit) => {
493
- output_1.output.logSingleLine(`Creating GitHub Release`);
494
- await (0, github_1.createOrUpdateGithubRelease)(releaseGroup.changelog
495
- ? releaseGroup.changelog.createRelease
496
- : config_1.defaultCreateReleaseProvider, projectChangelog.releaseVersion, projectChangelog.contents, latestCommit, { dryRun: args.dryRun });
497
- });
477
+ if (projectChangelogs) {
478
+ for (const [projectName, projectChangelog] of Object.entries(projectChangelogs)) {
479
+ // Add the post git task (e.g. create a remote release) for the project changelog, if applicable
480
+ if (projectChangelog.postGitTask) {
481
+ postGitTasks.push(projectChangelog.postGitTask);
482
+ }
483
+ allProjectChangelogs[projectName] = projectChangelog;
498
484
  }
499
- allProjectChangelogs[projectName] = projectChangelog;
500
485
  }
501
486
  }
502
487
  }
@@ -546,6 +531,19 @@ function resolveChangelogVersions(args, releaseGroups, releaseGroupToFilteredPro
546
531
  projectsVersionData: versionData,
547
532
  };
548
533
  }
534
+ // Can be overridden to something more specific as we resolve the remote release client within nested logic
535
+ let remoteReleaseProviderName;
536
+ // If already set, and not the same as the remote release client, append
537
+ function applyRemoteReleaseProviderName(newRemoteReleaseProviderName) {
538
+ if (remoteReleaseProviderName) {
539
+ if (remoteReleaseProviderName !== newRemoteReleaseProviderName) {
540
+ remoteReleaseProviderName = `${remoteReleaseProviderName}/${newRemoteReleaseProviderName}`;
541
+ }
542
+ }
543
+ else {
544
+ remoteReleaseProviderName = newRemoteReleaseProviderName;
545
+ }
546
+ }
549
547
  async function applyChangesAndExit(args, nxReleaseConfig, tree, toSHA, postGitTasks, commitMessageValues, gitTagValues, releaseGroups) {
550
548
  let latestCommit = toSHA;
551
549
  const changes = tree.listChanges();
@@ -563,19 +561,21 @@ async function applyChangesAndExit(args, nxReleaseConfig, tree, toSHA, postGitTa
563
561
  ],
564
562
  });
565
563
  if (!postGitTasks.length) {
566
- // no GitHub releases to create so we can just exit
564
+ // No post git tasks (e.g. remote release creation) to perform so we can just exit
567
565
  return;
568
566
  }
569
567
  if ((0, is_ci_1.isCI)()) {
570
568
  output_1.output.warn({
571
- title: `Skipped GitHub release creation because no changes were detected for any changelog files.`,
569
+ title: `Skipped ${remoteReleaseProviderName ?? 'remote'} release creation because no changes were detected for any changelog files.`,
572
570
  });
573
571
  return;
574
572
  }
575
- // prompt the user to see if they want to create a GitHub release anyway
576
- // we know that the user has configured GitHub releases because we have postGitTasks
577
- const shouldCreateGitHubReleaseAnyway = await promptForGitHubRelease();
578
- if (!shouldCreateGitHubReleaseAnyway) {
573
+ /**
574
+ * Prompt the user to see if they want to create a remote release anyway.
575
+ * We know that the user has configured remote releases because we have postGitTasks.
576
+ */
577
+ const shouldCreateRemoteReleaseAnyway = await promptForRemoteRelease();
578
+ if (!shouldCreateRemoteReleaseAnyway) {
579
579
  return;
580
580
  }
581
581
  for (const postGitTask of postGitTasks) {
@@ -658,7 +658,7 @@ async function applyChangesAndExit(args, nxReleaseConfig, tree, toSHA, postGitTa
658
658
  }
659
659
  return;
660
660
  }
661
- async function generateChangelogForWorkspace({ tree, args, projectGraph, nxReleaseConfig, workspaceChangelogVersion, changes, commits, }) {
661
+ async function generateChangelogForWorkspace({ tree, args, nxReleaseConfig, workspaceChangelogVersion, changes, }) {
662
662
  const config = nxReleaseConfig.changelog.workspaceChangelog;
663
663
  // The entire feature is disabled at the workspace level, exit early
664
664
  if (config === false) {
@@ -716,16 +716,17 @@ async function generateChangelogForWorkspace({ tree, args, projectGraph, nxRelea
716
716
  title: `${prefix} an entry in ${interpolatedTreePath} for ${chalk.white(releaseVersion.gitTag)}`,
717
717
  });
718
718
  }
719
- const githubRepoData = (0, github_1.getGitHubRepoData)(gitRemote, config.createRelease);
719
+ const remoteReleaseClient = await (0, remote_release_client_1.createRemoteReleaseClient)(config.createRelease, gitRemote);
720
+ applyRemoteReleaseProviderName(remoteReleaseClient.remoteReleaseProviderName);
720
721
  const changelogRenderer = new ChangelogRendererClass({
721
722
  changes,
722
723
  changelogEntryVersion: releaseVersion.rawVersion,
723
724
  project: null,
724
725
  isVersionPlans: false,
725
- repoData: githubRepoData,
726
726
  entryWhenNoChanges: config.entryWhenNoChanges,
727
727
  changelogRenderOptions: config.renderOptions,
728
728
  conventionalCommitsConfig: nxReleaseConfig.conventionalCommits,
729
+ remoteReleaseClient,
729
730
  });
730
731
  let contents = await changelogRenderer.render();
731
732
  /**
@@ -764,9 +765,13 @@ async function generateChangelogForWorkspace({ tree, args, projectGraph, nxRelea
764
765
  tree.write(interpolatedTreePath, rootChangelogContents);
765
766
  (0, print_changes_1.printAndFlushChanges)(tree, !!dryRun, 3, false, shared_1.noDiffInChangelogMessage);
766
767
  }
768
+ const postGitTask = args.createRelease !== false && config.createRelease
769
+ ? remoteReleaseClient.createPostGitTask(releaseVersion, contents, dryRun)
770
+ : null;
767
771
  return {
768
772
  releaseVersion,
769
773
  contents,
774
+ postGitTask,
770
775
  };
771
776
  }
772
777
  async function generateChangelogForProjects({ tree, args, changes, projectsVersionData, releaseGroup, projects, nxReleaseConfig, projectToAdditionalDependencyBumps, }) {
@@ -780,6 +785,9 @@ async function generateChangelogForProjects({ tree, args, changes, projectsVersi
780
785
  const dryRun = !!args.dryRun;
781
786
  const gitRemote = args.gitRemote;
782
787
  const ChangelogRendererClass = (0, resolve_changelog_renderer_1.resolveChangelogRenderer)(config.renderer);
788
+ // Maximum of one remote release client per release group
789
+ const remoteReleaseClient = await (0, remote_release_client_1.createRemoteReleaseClient)(config.createRelease, gitRemote);
790
+ applyRemoteReleaseProviderName(remoteReleaseClient.remoteReleaseProviderName);
783
791
  const projectChangelogs = {};
784
792
  for (const project of projects) {
785
793
  let interpolatedTreePath = config.file || '';
@@ -809,12 +817,10 @@ async function generateChangelogForProjects({ tree, args, changes, projectsVersi
809
817
  title: `${prefix} an entry in ${interpolatedTreePath} for ${chalk.white(releaseVersion.gitTag)}`,
810
818
  });
811
819
  }
812
- const githubRepoData = (0, github_1.getGitHubRepoData)(gitRemote, config.createRelease);
813
820
  const changelogRenderer = new ChangelogRendererClass({
814
821
  changes,
815
822
  changelogEntryVersion: releaseVersion.rawVersion,
816
823
  project: project.name,
817
- repoData: githubRepoData,
818
824
  entryWhenNoChanges: typeof config.entryWhenNoChanges === 'string'
819
825
  ? (0, utils_1.interpolate)(config.entryWhenNoChanges, {
820
826
  projectName: project.name,
@@ -828,6 +834,7 @@ async function generateChangelogForProjects({ tree, args, changes, projectsVersi
828
834
  ? null
829
835
  : nxReleaseConfig.conventionalCommits,
830
836
  dependencyBumps: projectToAdditionalDependencyBumps.get(project.name),
837
+ remoteReleaseClient,
831
838
  });
832
839
  let contents = await changelogRenderer.render();
833
840
  /**
@@ -868,9 +875,13 @@ async function generateChangelogForProjects({ tree, args, changes, projectsVersi
868
875
  // Only print the change for the current changelog file at this point
869
876
  (f) => f.path === interpolatedTreePath);
870
877
  }
878
+ const postGitTask = args.createRelease !== false && config.createRelease
879
+ ? remoteReleaseClient.createPostGitTask(releaseVersion, contents, dryRun)
880
+ : null;
871
881
  projectChangelogs[project.name] = {
872
882
  releaseVersion,
873
883
  contents,
884
+ postGitTask,
874
885
  };
875
886
  }
876
887
  return projectChangelogs;
@@ -903,36 +914,12 @@ function filterHiddenChanges(changes, conventionalCommitsConfig) {
903
914
  return !typeConfig.changelog.hidden;
904
915
  });
905
916
  }
906
- // TODO(v22): remove this after the changelog renderer is refactored to remove coupling with git commits
907
- function filterHiddenCommits(commits, conventionalCommitsConfig) {
908
- if (!commits) {
909
- return [];
910
- }
911
- return commits.filter((commit) => {
912
- const type = commit.type;
913
- const typeConfig = conventionalCommitsConfig.types[type];
914
- if (!typeConfig) {
915
- // don't include commits with unknown types
916
- return false;
917
- }
918
- return !typeConfig.changelog.hidden;
919
- });
920
- }
921
- function shouldCreateGitHubRelease(changelogConfig, createReleaseArg = undefined) {
922
- if (createReleaseArg !== undefined) {
923
- return createReleaseArg === 'github';
924
- }
925
- if (changelogConfig === false) {
926
- return false;
927
- }
928
- return changelogConfig.createRelease !== false;
929
- }
930
- async function promptForGitHubRelease() {
917
+ async function promptForRemoteRelease() {
931
918
  try {
932
919
  const result = await (0, enquirer_1.prompt)([
933
920
  {
934
921
  name: 'confirmation',
935
- message: 'Do you want to create a GitHub release anyway?',
922
+ message: `Do you want to create a ${remoteReleaseProviderName ?? 'remote'} release anyway?`,
936
923
  type: 'confirm',
937
924
  },
938
925
  ]);
@@ -40,7 +40,7 @@ export type ChangelogOptions = NxReleaseArgs & GitOptions & VersionPlanArgs & Fi
40
40
  to?: string;
41
41
  from?: string;
42
42
  interactive?: string;
43
- createRelease?: false | 'github';
43
+ createRelease?: false | 'github' | 'gitlab';
44
44
  };
45
45
  export type PublishOptions = NxReleaseArgs & Partial<RunManyOptions> & {
46
46
  outputStyle?: OutputStyle;
@@ -51,5 +51,12 @@ export declare function createNxReleaseConfig(projectGraph: ProjectGraph, projec
51
51
  nxReleaseConfig: NxReleaseConfig | null;
52
52
  }>;
53
53
  export declare function handleNxReleaseConfigError(error: CreateNxReleaseConfigError, useLegacyVersioning: boolean): Promise<never>;
54
- export declare const defaultCreateReleaseProvider: any;
54
+ /**
55
+ * Full form of the createRelease config, with the provider, hostname, and apiBaseUrl resolved.
56
+ */
57
+ export interface ResolvedCreateRemoteReleaseProvider {
58
+ provider: string;
59
+ hostname: string;
60
+ apiBaseUrl: string;
61
+ }
55
62
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.defaultCreateReleaseProvider = exports.DEFAULT_VERSION_ACTIONS_PATH = exports.IMPLICIT_DEFAULT_RELEASE_GROUP = void 0;
3
+ exports.DEFAULT_VERSION_ACTIONS_PATH = exports.IMPLICIT_DEFAULT_RELEASE_GROUP = void 0;
4
4
  exports.createNxReleaseConfig = createNxReleaseConfig;
5
5
  exports.handleNxReleaseConfigError = handleNxReleaseConfigError;
6
6
  /**
@@ -23,6 +23,8 @@ const find_matching_projects_1 = require("../../../utils/find-matching-projects"
23
23
  const output_1 = require("../../../utils/output");
24
24
  const path_1 = require("../../../utils/path");
25
25
  const workspace_root_1 = require("../../../utils/workspace-root");
26
+ const github_1 = require("../utils/remote-release-clients/github");
27
+ const gitlab_1 = require("../utils/remote-release-clients/gitlab");
26
28
  const resolve_changelog_renderer_1 = require("../utils/resolve-changelog-renderer");
27
29
  const resolve_nx_json_error_message_1 = require("../utils/resolve-nx-json-error-message");
28
30
  const conventional_commits_1 = require("./conventional-commits");
@@ -170,7 +172,7 @@ async function createNxReleaseConfig(projectGraph, projectFileMap, userConfig =
170
172
  renderer: defaultRendererPath,
171
173
  renderOptions: {
172
174
  authors: true,
173
- mapAuthorsToGitHubUsernames: true,
175
+ applyUsernameToAuthors: true,
174
176
  commitReferences: true,
175
177
  versionTitleDate: true,
176
178
  },
@@ -184,7 +186,7 @@ async function createNxReleaseConfig(projectGraph, projectFileMap, userConfig =
184
186
  renderer: defaultRendererPath,
185
187
  renderOptions: {
186
188
  authors: true,
187
- mapAuthorsToGitHubUsernames: true,
189
+ applyUsernameToAuthors: true,
188
190
  commitReferences: true,
189
191
  versionTitleDate: true,
190
192
  },
@@ -225,7 +227,7 @@ async function createNxReleaseConfig(projectGraph, projectFileMap, userConfig =
225
227
  renderer: defaultRendererPath,
226
228
  renderOptions: {
227
229
  authors: true,
228
- mapAuthorsToGitHubUsernames: true,
230
+ applyUsernameToAuthors: true,
229
231
  commitReferences: true,
230
232
  versionTitleDate: true,
231
233
  },
@@ -930,13 +932,11 @@ const supportedCreateReleaseProviders = [
930
932
  name: 'github-enterprise-server',
931
933
  defaultApiBaseUrl: 'https://__hostname__/api/v3',
932
934
  },
935
+ {
936
+ name: 'gitlab',
937
+ defaultApiBaseUrl: 'https://__hostname__/api/v4',
938
+ },
933
939
  ];
934
- // User opts into the default by specifying the string value 'github'
935
- exports.defaultCreateReleaseProvider = {
936
- provider: 'github',
937
- hostname: 'github.com',
938
- apiBaseUrl: 'https://api.github.com',
939
- };
940
940
  function validateCreateReleaseConfig(changelogConfig) {
941
941
  const createRelease = changelogConfig.createRelease;
942
942
  // Disabled: valid
@@ -945,7 +945,14 @@ function validateCreateReleaseConfig(changelogConfig) {
945
945
  }
946
946
  // GitHub shorthand, expand to full object form, mark as valid
947
947
  if (createRelease === 'github') {
948
- changelogConfig.createRelease = exports.defaultCreateReleaseProvider;
948
+ changelogConfig.createRelease =
949
+ github_1.defaultCreateReleaseProvider;
950
+ return null;
951
+ }
952
+ // Gitlab shorthand, expand to full object form, mark as valid
953
+ if (createRelease === 'gitlab') {
954
+ changelogConfig.createRelease =
955
+ gitlab_1.defaultCreateReleaseProvider;
949
956
  return null;
950
957
  }
951
958
  // Object config, ensure that properties are valid
@@ -17,8 +17,8 @@ const use_legacy_versioning_1 = require("./config/use-legacy-versioning");
17
17
  const version_plans_1 = require("./config/version-plans");
18
18
  const publish_1 = require("./publish");
19
19
  const git_1 = require("./utils/git");
20
- const github_1 = require("./utils/github");
21
20
  const print_config_1 = require("./utils/print-config");
21
+ const remote_release_client_1 = require("./utils/remote-release-clients/remote-release-client");
22
22
  const resolve_nx_json_error_message_1 = require("./utils/resolve-nx-json-error-message");
23
23
  const shared_1 = require("./utils/shared");
24
24
  const version_1 = require("./version");
@@ -84,10 +84,10 @@ function createAPI(overrideReleaseConfig) {
84
84
  const shouldCommit = userProvidedReleaseConfig.git?.commit ?? true;
85
85
  const shouldStage = (shouldCommit || userProvidedReleaseConfig.git?.stageChanges) ?? false;
86
86
  const shouldTag = userProvidedReleaseConfig.git?.tag ?? true;
87
- const shouldCreateWorkspaceRelease = (0, changelog_1.shouldCreateGitHubRelease)(nxReleaseConfig.changelog.workspaceChangelog);
88
- // If the workspace or any of the release groups specify that a github release should be created, we need to push the changes to the remote
89
- const shouldPush = (shouldCreateWorkspaceRelease ||
90
- releaseGroups.some((group) => (0, changelog_1.shouldCreateGitHubRelease)(group.changelog))) ??
87
+ const shouldCreateWorkspaceRemoteRelease = shouldCreateRemoteRelease(nxReleaseConfig.changelog.workspaceChangelog);
88
+ // If the workspace or any of the release groups specify that a remote release should be created, we need to push the changes to the remote
89
+ const shouldPush = (shouldCreateWorkspaceRemoteRelease ||
90
+ releaseGroups.some((group) => shouldCreateRemoteRelease(group.changelog))) ??
91
91
  false;
92
92
  const versionResult = await releaseVersion({
93
93
  ...args,
@@ -179,19 +179,27 @@ function createAPI(overrideReleaseConfig) {
179
179
  hasPushedChanges = true;
180
180
  }
181
181
  let latestCommit;
182
- if (shouldCreateWorkspaceRelease && changelogResult.workspaceChangelog) {
182
+ if (shouldCreateWorkspaceRemoteRelease &&
183
+ changelogResult.workspaceChangelog) {
184
+ const remoteReleaseClient = await (0, remote_release_client_1.createRemoteReleaseClient)(
185
+ // shouldCreateWorkspaceRemoteRelease() ensures that the createRelease property exists and is not false
186
+ nxReleaseConfig.changelog.workspaceChangelog
187
+ .createRelease);
183
188
  if (!hasPushedChanges) {
184
- throw new Error('It is not possible to create a github release for the workspace without pushing the changes to the remote, please ensure that you have not disabled git push in your nx release config');
189
+ throw new Error(`It is not possible to create a ${remoteReleaseClient.remoteReleaseProviderName} release for the workspace without pushing the changes to the remote, please ensure that you have not disabled git push in your nx release config`);
185
190
  }
186
- output_1.output.logSingleLine(`Creating GitHub Release`);
191
+ output_1.output.logSingleLine(`Creating ${remoteReleaseClient.remoteReleaseProviderName} Release`);
187
192
  latestCommit = await (0, git_1.getCommitHash)('HEAD');
188
- await (0, github_1.createOrUpdateGithubRelease)(nxReleaseConfig.changelog.workspaceChangelog
189
- ? nxReleaseConfig.changelog.workspaceChangelog.createRelease
190
- : false, changelogResult.workspaceChangelog.releaseVersion, changelogResult.workspaceChangelog.contents, latestCommit, { dryRun: args.dryRun });
193
+ await remoteReleaseClient.createOrUpdateRelease(changelogResult.workspaceChangelog.releaseVersion, changelogResult.workspaceChangelog.contents, latestCommit, { dryRun: args.dryRun });
191
194
  }
192
195
  for (const releaseGroup of releaseGroups) {
193
- const shouldCreateProjectReleases = (0, changelog_1.shouldCreateGitHubRelease)(releaseGroup.changelog);
194
- if (shouldCreateProjectReleases && changelogResult.projectChangelogs) {
196
+ const shouldCreateProjectRemoteReleases = shouldCreateRemoteRelease(releaseGroup.changelog);
197
+ if (shouldCreateProjectRemoteReleases &&
198
+ changelogResult.projectChangelogs) {
199
+ const remoteReleaseClient = await (0, remote_release_client_1.createRemoteReleaseClient)(
200
+ // shouldCreateProjectRemoteReleases() ensures that the createRelease property exists and is not false
201
+ releaseGroup.changelog
202
+ .createRelease);
195
203
  const projects = args.projects?.length
196
204
  ? // If the user has passed a list of projects, we need to use the filtered list of projects within the release group
197
205
  Array.from(releaseGroupToFilteredProjects.get(releaseGroup))
@@ -204,15 +212,13 @@ function createAPI(overrideReleaseConfig) {
204
212
  continue;
205
213
  }
206
214
  if (!hasPushedChanges) {
207
- throw new Error('It is not possible to create a github release for the project without pushing the changes to the remote, please ensure that you have not disabled git push in your nx release config');
215
+ throw new Error(`It is not possible to create a ${remoteReleaseClient.remoteReleaseProviderName} release for the project without pushing the changes to the remote, please ensure that you have not disabled git push in your nx release config`);
208
216
  }
209
- output_1.output.logSingleLine(`Creating GitHub Release`);
217
+ output_1.output.logSingleLine(`Creating ${remoteReleaseClient.remoteReleaseProviderName} Release`);
210
218
  if (!latestCommit) {
211
219
  latestCommit = await (0, git_1.getCommitHash)('HEAD');
212
220
  }
213
- await (0, github_1.createOrUpdateGithubRelease)(releaseGroup.changelog
214
- ? releaseGroup.changelog.createRelease
215
- : false, changelog.releaseVersion, changelog.contents, latestCommit, { dryRun: args.dryRun });
221
+ await remoteReleaseClient.createOrUpdateRelease(changelog.releaseVersion, changelog.contents, latestCommit, { dryRun: args.dryRun });
216
222
  }
217
223
  }
218
224
  }
@@ -253,3 +259,9 @@ async function promptForPublish() {
253
259
  return false;
254
260
  }
255
261
  }
262
+ function shouldCreateRemoteRelease(changelogConfig) {
263
+ if (changelogConfig === false) {
264
+ return false;
265
+ }
266
+ return changelogConfig.createRelease !== false;
267
+ }
@@ -63,6 +63,7 @@ export declare function parseConventionalCommitsMessage(message: string): {
63
63
  description: string;
64
64
  breaking: boolean;
65
65
  } | null;
66
+ export declare function extractReferencesFromCommit(commit: RawGitCommit): Reference[];
66
67
  export declare function parseGitCommit(commit: RawGitCommit, isVersionPlanCommit?: boolean): GitCommit | null;
67
68
  export declare function getCommitHash(ref: string): Promise<string>;
68
69
  export declare function getFirstGitCommit(): Promise<string>;
@@ -8,6 +8,7 @@ exports.gitTag = gitTag;
8
8
  exports.gitPush = gitPush;
9
9
  exports.parseCommits = parseCommits;
10
10
  exports.parseConventionalCommitsMessage = parseConventionalCommitsMessage;
11
+ exports.extractReferencesFromCommit = extractReferencesFromCommit;
11
12
  exports.parseGitCommit = parseGitCommit;
12
13
  exports.getCommitHash = getCommitHash;
13
14
  exports.getFirstGitCommit = getFirstGitCommit;
@@ -362,17 +363,32 @@ function parseConventionalCommitsMessage(message) {
362
363
  breaking: Boolean(match.groups.breaking),
363
364
  };
364
365
  }
365
- function extractReferencesFromCommitMessage(message, shortHash) {
366
+ function extractReferencesFromCommit(commit) {
366
367
  const references = [];
367
- for (const m of message.matchAll(PullRequestRE)) {
368
+ // Extract GitHub style PR references from commit message
369
+ for (const m of commit.message.matchAll(PullRequestRE)) {
368
370
  references.push({ type: 'pull-request', value: m[1] });
369
371
  }
370
- for (const m of message.matchAll(IssueRE)) {
372
+ // Extract GitLab style merge request references from commit body
373
+ for (const m of commit.body.matchAll(GitLabMergeRequestRE)) {
374
+ if (m[1]) {
375
+ references.push({ type: 'pull-request', value: m[1] });
376
+ }
377
+ }
378
+ // Extract issue references from commit message
379
+ for (const m of commit.message.matchAll(IssueRE)) {
380
+ if (!references.some((i) => i.value === m[1])) {
381
+ references.push({ type: 'issue', value: m[1] });
382
+ }
383
+ }
384
+ // Extract issue references from commit body
385
+ for (const m of commit.body.matchAll(IssueRE)) {
371
386
  if (!references.some((i) => i.value === m[1])) {
372
387
  references.push({ type: 'issue', value: m[1] });
373
388
  }
374
389
  }
375
- references.push({ value: shortHash, type: 'hash' });
390
+ // Add commit hash reference
391
+ references.push({ value: commit.shortHash, type: 'hash' });
376
392
  return references;
377
393
  }
378
394
  function getAllAuthorsForCommit(commit) {
@@ -390,7 +406,10 @@ function getAllAuthorsForCommit(commit) {
390
406
  // https://regex101.com/r/FSfNvA/1
391
407
  const ConventionalCommitRegex = /(?<type>[a-z]+)(\((?<scope>.+)\))?(?<breaking>!)?: (?<description>.+)/i;
392
408
  const CoAuthoredByRegex = /co-authored-by:\s*(?<name>.+)(<(?<email>.+)>)/gim;
409
+ // GitHub style PR references
393
410
  const PullRequestRE = /\([ a-z]*(#\d+)\s*\)/gm;
411
+ // GitLab style merge request references
412
+ const GitLabMergeRequestRE = /See merge request (?:[a-z0-9/-]+)?(![\d]+)/gim;
394
413
  const IssueRE = /(#\d+)/gm;
395
414
  const ChangedFileRegex = /(A|M|D|R\d*|C\d*)\t([^\t\n]*)\t?(.*)?/gm;
396
415
  const RevertHashRE = /This reverts commit (?<hash>[\da-f]{40})./gm;
@@ -402,7 +421,7 @@ function parseGitCommit(commit, isVersionPlanCommit = false) {
402
421
  description: commit.message,
403
422
  type: '',
404
423
  scope: '',
405
- references: extractReferencesFromCommitMessage(commit.message, commit.shortHash),
424
+ references: extractReferencesFromCommit(commit),
406
425
  // The commit message is not the source of truth for a breaking (major) change in version plans, so the value is not relevant
407
426
  // TODO(v22): Make the current GitCommit interface more clearly tied to conventional commits
408
427
  isBreaking: false,
@@ -420,9 +439,9 @@ function parseGitCommit(commit, isVersionPlanCommit = false) {
420
439
  const scope = parsedMessage.scope;
421
440
  const isBreaking = parsedMessage.breaking || commit.body.includes('BREAKING CHANGE:');
422
441
  let description = parsedMessage.description;
423
- // Extract references from message
424
- const references = extractReferencesFromCommitMessage(description, commit.shortHash);
425
- // Remove references and normalize
442
+ // Extract issue and PR references from the commit
443
+ const references = extractReferencesFromCommit(commit);
444
+ // Remove GitHub style references from description (NOTE: GitLab style references only seem to appear in the body, so we don't need to remove them here)
426
445
  description = description.replace(PullRequestRE, '').trim();
427
446
  let type = parsedMessage.type;
428
447
  // Extract any reverted hashes, if applicable
@@ -0,0 +1,57 @@
1
+ import type { PostGitTask } from '../../changelog';
2
+ import { type ResolvedCreateRemoteReleaseProvider } from '../../config/config';
3
+ import { Reference } from '../git';
4
+ import { ReleaseVersion } from '../shared';
5
+ import { RemoteReleaseClient, RemoteReleaseOptions, RemoteReleaseResult, RemoteRepoData } from './remote-release-client';
6
+ export interface GithubRepoData extends RemoteRepoData {
7
+ }
8
+ export interface GithubRemoteRelease {
9
+ id?: string;
10
+ body: string;
11
+ tag_name: string;
12
+ target_commitish?: string;
13
+ name?: string;
14
+ draft?: boolean;
15
+ prerelease?: boolean;
16
+ make_latest?: 'legacy' | boolean;
17
+ }
18
+ export declare const defaultCreateReleaseProvider: ResolvedCreateRemoteReleaseProvider;
19
+ export declare class GithubRemoteReleaseClient extends RemoteReleaseClient<GithubRemoteRelease> {
20
+ remoteReleaseProviderName: string;
21
+ /**
22
+ * Get GitHub repository data from git remote
23
+ */
24
+ static resolveRepoData(createReleaseConfig: false | ResolvedCreateRemoteReleaseProvider, remoteName?: string): GithubRepoData | null;
25
+ /**
26
+ * Resolve a GitHub token from environment variables or gh CLI
27
+ */
28
+ static resolveTokenData(hostname: string): Promise<{
29
+ token: string;
30
+ headerName: string;
31
+ } | null>;
32
+ createPostGitTask(releaseVersion: ReleaseVersion, changelogContents: string, dryRun: boolean): PostGitTask;
33
+ applyUsernameToAuthors(authors: Map<string, {
34
+ email: Set<string>;
35
+ username?: string;
36
+ }>): Promise<void>;
37
+ /**
38
+ * Get a release by tag
39
+ */
40
+ protected getReleaseByTag(tag: string): Promise<GithubRemoteRelease>;
41
+ /**
42
+ * Create a new release
43
+ */
44
+ protected createRelease(remoteRelease: GithubRemoteRelease): Promise<any>;
45
+ protected updateRelease(id: string, remoteRelease: GithubRemoteRelease): Promise<any>;
46
+ protected getManualRemoteReleaseURL(remoteReleaseOptions: RemoteReleaseOptions): string;
47
+ protected handleAuthError(): void;
48
+ protected logReleaseAction(existingRelease: GithubRemoteRelease | undefined, gitTag: string, dryRun: boolean): void;
49
+ protected handleError(error: any, result: RemoteReleaseResult): Promise<void>;
50
+ private promptForContinueInGitHub;
51
+ /**
52
+ * Format references for the release (e.g., PRs, issues)
53
+ */
54
+ formatReferences(references: Reference[]): string;
55
+ protected syncRelease(remoteReleaseOptions: RemoteReleaseOptions, existingRelease?: GithubRemoteRelease): Promise<RemoteReleaseResult>;
56
+ private getRequiredRemoteRepoData;
57
+ }