nx 19.8.0-canary.20240920-999abe9 → 19.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. package/.eslintrc.json +2 -1
  2. package/bin/nx.js +10 -2
  3. package/package.json +12 -12
  4. package/release/changelog-renderer/index.d.ts +3 -1
  5. package/release/changelog-renderer/index.js +8 -8
  6. package/schemas/nx-schema.json +47 -21
  7. package/src/adapter/compat.d.ts +1 -1
  8. package/src/adapter/compat.js +1 -0
  9. package/src/command-line/activate-powerpack/activate-powerpack.js +3 -1
  10. package/src/command-line/add/add.js +4 -2
  11. package/src/command-line/connect/view-logs.js +1 -0
  12. package/src/command-line/exec/exec.js +6 -1
  13. package/src/command-line/format/format.js +3 -1
  14. package/src/command-line/graph/graph.js +1 -0
  15. package/src/command-line/init/implementation/angular/integrated-workspace.js +4 -1
  16. package/src/command-line/init/implementation/angular/legacy-angular-versions.js +5 -2
  17. package/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +3 -1
  18. package/src/command-line/init/implementation/dot-nx/nxw.js +1 -0
  19. package/src/command-line/init/implementation/react/check-for-uncommitted-changes.js +3 -1
  20. package/src/command-line/init/implementation/react/index.js +17 -5
  21. package/src/command-line/init/implementation/utils.js +5 -1
  22. package/src/command-line/init/init-v1.js +1 -0
  23. package/src/command-line/init/init-v2.js +2 -1
  24. package/src/command-line/migrate/command-object.js +4 -0
  25. package/src/command-line/migrate/migrate.js +1 -1
  26. package/src/command-line/release/changelog.js +16 -10
  27. package/src/command-line/release/config/config.d.ts +2 -1
  28. package/src/command-line/release/config/config.js +165 -20
  29. package/src/command-line/release/config/version-plans.js +3 -1
  30. package/src/command-line/release/release.js +6 -2
  31. package/src/command-line/release/utils/exec-command.js +1 -0
  32. package/src/command-line/release/utils/github.d.ts +14 -6
  33. package/src/command-line/release/utils/github.js +50 -24
  34. package/src/command-line/release/utils/launch-editor.js +6 -1
  35. package/src/command-line/release/version.js +6 -3
  36. package/src/command-line/report/report.d.ts +3 -1
  37. package/src/command-line/report/report.js +17 -2
  38. package/src/command-line/run/run.js +1 -0
  39. package/src/command-line/sync/sync.js +5 -4
  40. package/src/command-line/watch/watch.js +1 -0
  41. package/src/config/nx-json.d.ts +12 -1
  42. package/src/core/graph/main.js +1 -1
  43. package/src/core/graph/styles.js +1 -1
  44. package/src/daemon/client/client.d.ts +4 -1
  45. package/src/daemon/client/generate-help-output.js +1 -0
  46. package/src/daemon/server/sync-generators.d.ts +4 -1
  47. package/src/daemon/server/sync-generators.js +33 -15
  48. package/src/executors/run-commands/run-commands.impl.js +1 -0
  49. package/src/executors/run-script/run-script.impl.js +1 -0
  50. package/src/native/index.d.ts +1 -1
  51. package/src/native/nx.wasm32-wasi.wasm +0 -0
  52. package/src/nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud.js +1 -1
  53. package/src/project-graph/file-utils.js +1 -0
  54. package/src/tasks-runner/cache.d.ts +3 -1
  55. package/src/tasks-runner/cache.js +12 -13
  56. package/src/tasks-runner/default-tasks-runner.js +1 -1
  57. package/src/tasks-runner/life-cycles/formatting-utils.d.ts +1 -1
  58. package/src/tasks-runner/life-cycles/formatting-utils.js +27 -15
  59. package/src/tasks-runner/life-cycles/task-history-life-cycle.js +3 -0
  60. package/src/tasks-runner/task-orchestrator.d.ts +3 -1
  61. package/src/tasks-runner/task-orchestrator.js +3 -2
  62. package/src/tasks-runner/tasks-schedule.js +1 -1
  63. package/src/utils/ab-testing.js +4 -1
  64. package/src/utils/child-process.js +5 -3
  65. package/src/utils/command-line-utils.js +7 -1
  66. package/src/utils/default-base.js +5 -2
  67. package/src/utils/git-utils.index-filter.js +2 -1
  68. package/src/utils/git-utils.js +4 -0
  69. package/src/utils/git-utils.tree-filter.js +3 -1
  70. package/src/utils/powerpack.d.ts +1 -1
  71. package/src/utils/powerpack.js +3 -8
  72. package/src/utils/sync-generators.d.ts +13 -3
  73. package/src/utils/sync-generators.js +99 -25
  74. package/src/utils/task-history.d.ts +2 -2
  75. package/src/utils/task-history.js +4 -1
@@ -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
  }
@@ -191,7 +191,9 @@ function isReleaseType(value) {
191
191
  }
192
192
  async function getCommitForVersionPlanFile(rawVersionPlan, isVerbose) {
193
193
  return new Promise((resolve) => {
194
- (0, node_child_process_1.exec)(`git log --diff-filter=A --pretty=format:"%s|%h|%an|%ae|%b" -n 1 -- ${rawVersionPlan.absolutePath}`, (error, stdout, stderr) => {
194
+ (0, node_child_process_1.exec)(`git log --diff-filter=A --pretty=format:"%s|%h|%an|%ae|%b" -n 1 -- ${rawVersionPlan.absolutePath}`, {
195
+ windowsHide: true,
196
+ }, (error, stdout, stderr) => {
195
197
  if (error) {
196
198
  if (isVerbose) {
197
199
  console.error(`Error executing git command for ${rawVersionPlan.relativePath}: ${error.message}`);
@@ -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
  }
@@ -8,6 +8,7 @@ async function execCommand(cmd, args, options) {
8
8
  ...options,
9
9
  stdio: ['pipe', 'pipe', 'pipe'], // stdin, stdout, stderr
10
10
  encoding: 'utf-8',
11
+ windowsHide: true,
11
12
  });
12
13
  let stdout = '';
13
14
  let stderr = '';
@@ -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 {};
@@ -1,8 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getGitHubRepoSlug = getGitHubRepoSlug;
3
+ exports.getGitHubRepoData = getGitHubRepoData;
4
4
  exports.createOrUpdateGithubRelease = createOrUpdateGithubRelease;
5
- exports.resolveGithubToken = resolveGithubToken;
6
5
  exports.getGithubReleaseByTag = getGithubReleaseByTag;
7
6
  exports.formatReferences = formatReferences;
8
7
  const chalk = require("chalk");
@@ -12,22 +11,38 @@ const node_fs_1 = require("node:fs");
12
11
  const node_os_1 = require("node:os");
13
12
  const output_1 = require("../../../utils/output");
14
13
  const path_1 = require("../../../utils/path");
14
+ const config_1 = require("../config/config");
15
15
  const print_changes_1 = require("./print-changes");
16
16
  const shared_1 = require("./shared");
17
17
  // axios types and values don't seem to match
18
18
  const _axios = require("axios");
19
19
  const axios = _axios;
20
- function getGitHubRepoSlug(remoteName = 'origin') {
20
+ function getGitHubRepoData(remoteName = 'origin', createReleaseConfig) {
21
21
  try {
22
22
  const remoteUrl = (0, node_child_process_1.execSync)(`git remote get-url ${remoteName}`, {
23
23
  encoding: 'utf8',
24
24
  stdio: 'pipe',
25
25
  }).trim();
26
+ // Use the default provider (github.com) if custom one is not specified or releases are disabled
27
+ let hostname = config_1.defaultCreateReleaseProvider.hostname;
28
+ let apiBaseUrl = config_1.defaultCreateReleaseProvider.apiBaseUrl;
29
+ if (createReleaseConfig !== false &&
30
+ typeof createReleaseConfig !== 'string') {
31
+ hostname = createReleaseConfig.hostname;
32
+ apiBaseUrl = createReleaseConfig.apiBaseUrl;
33
+ }
26
34
  // Extract the 'user/repo' part from the URL
27
- const regex = /github\.com[/:]([\w-]+\/[\w-]+)/;
35
+ const escapedHostname = hostname.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
36
+ const regexString = `${escapedHostname}[/:]([\\w.-]+/[\\w.-]+)(\\.git)?`;
37
+ const regex = new RegExp(regexString);
28
38
  const match = remoteUrl.match(regex);
29
39
  if (match && match[1]) {
30
- return match[1];
40
+ return {
41
+ hostname,
42
+ apiBaseUrl,
43
+ // Ensure any trailing .git is stripped
44
+ slug: match[1].replace(/\.git$/, ''),
45
+ };
31
46
  }
32
47
  else {
33
48
  throw new Error(`Could not extract "user/repo" data from the resolved remote URL: ${remoteUrl}`);
@@ -37,9 +52,9 @@ function getGitHubRepoSlug(remoteName = 'origin') {
37
52
  return null;
38
53
  }
39
54
  }
40
- async function createOrUpdateGithubRelease(releaseVersion, changelogContents, latestCommit, { dryRun }) {
41
- const githubRepoSlug = getGitHubRepoSlug();
42
- if (!githubRepoSlug) {
55
+ async function createOrUpdateGithubRelease(createReleaseConfig, releaseVersion, changelogContents, latestCommit, { dryRun }) {
56
+ const githubRepoData = getGitHubRepoData(undefined, createReleaseConfig);
57
+ if (!githubRepoData) {
43
58
  output_1.output.error({
44
59
  title: `Unable to create a GitHub release because the GitHub repo slug could not be determined.`,
45
60
  bodyLines: [
@@ -48,9 +63,11 @@ async function createOrUpdateGithubRelease(releaseVersion, changelogContents, la
48
63
  });
49
64
  process.exit(1);
50
65
  }
51
- const token = await resolveGithubToken();
66
+ const token = await resolveGithubToken(githubRepoData.hostname);
52
67
  const githubRequestConfig = {
53
- repo: githubRepoSlug,
68
+ repo: githubRepoData.slug,
69
+ hostname: githubRepoData.hostname,
70
+ apiBaseUrl: githubRepoData.apiBaseUrl,
54
71
  token,
55
72
  };
56
73
  let existingGithubReleaseForVersion;
@@ -76,7 +93,7 @@ async function createOrUpdateGithubRelease(releaseVersion, changelogContents, la
76
93
  throw err;
77
94
  }
78
95
  }
79
- const logTitle = `https://github.com/${githubRepoSlug}/releases/tag/${releaseVersion.gitTag}`;
96
+ const logTitle = `https://${githubRepoData.hostname}/${githubRepoData.slug}/releases/tag/${releaseVersion.gitTag}`;
80
97
  if (existingGithubReleaseForVersion) {
81
98
  console.error(`${chalk.white('UPDATE')} ${logTitle}${dryRun ? chalk.keyword('orange')(' [dry-run]') : ''}`);
82
99
  }
@@ -215,7 +232,7 @@ async function syncGithubRelease(githubRequestConfig, release, existingGithubRel
215
232
  };
216
233
  }
217
234
  }
218
- async function resolveGithubToken() {
235
+ async function resolveGithubToken(hostname) {
219
236
  // Try and resolve from the environment
220
237
  const tokenFromEnv = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
221
238
  if (tokenFromEnv) {
@@ -227,21 +244,25 @@ async function resolveGithubToken() {
227
244
  const yamlContents = await node_fs_1.promises.readFile(ghCLIPath, 'utf8');
228
245
  const { load } = require('@zkochan/js-yaml');
229
246
  const ghCLIConfig = load(yamlContents);
230
- if (ghCLIConfig['github.com']) {
247
+ if (ghCLIConfig[hostname]) {
231
248
  // Web based session (the token is already embedded in the config)
232
- if (ghCLIConfig['github.com'].oauth_token) {
233
- return ghCLIConfig['github.com'].oauth_token;
249
+ if (ghCLIConfig[hostname].oauth_token) {
250
+ return ghCLIConfig[hostname].oauth_token;
234
251
  }
235
252
  // SSH based session (we need to dynamically resolve a token using the CLI)
236
- if (ghCLIConfig['github.com'].user &&
237
- ghCLIConfig['github.com'].git_protocol === 'ssh') {
253
+ if (ghCLIConfig[hostname].user &&
254
+ ghCLIConfig[hostname].git_protocol === 'ssh') {
238
255
  return (0, node_child_process_1.execSync)(`gh auth token`, {
239
256
  encoding: 'utf8',
240
257
  stdio: 'pipe',
258
+ windowsHide: true,
241
259
  }).trim();
242
260
  }
243
261
  }
244
262
  }
263
+ if (hostname !== 'github.com') {
264
+ console.log(`Warning: It was not possible to automatically resolve a GitHub token from your environment for hostname ${hostname}. If you set the GITHUB_TOKEN or GH_TOKEN environment variable, that will be used for GitHub API requests.`);
265
+ }
245
266
  return null;
246
267
  }
247
268
  async function getGithubReleaseByTag(config, tag) {
@@ -250,7 +271,7 @@ async function getGithubReleaseByTag(config, tag) {
250
271
  async function makeGithubRequest(config, url, opts = {}) {
251
272
  return (await axios(url, {
252
273
  ...opts,
253
- baseURL: 'https://api.github.com',
274
+ baseURL: config.apiBaseUrl,
254
275
  headers: {
255
276
  ...opts.headers,
256
277
  Authorization: config.token ? `Bearer ${config.token}` : undefined,
@@ -270,27 +291,32 @@ async function updateGithubRelease(config, id, body) {
270
291
  });
271
292
  }
272
293
  function githubNewReleaseURL(config, release) {
273
- return `https://github.com/${config.repo}/releases/new?tag=${release.version}&title=${release.version}&body=${encodeURIComponent(release.body)}`;
294
+ // Parameters taken from https://github.com/isaacs/github/issues/1410#issuecomment-442240267
295
+ let url = `https://${config.hostname}/${config.repo}/releases/new?tag=${release.version}&title=${release.version}&body=${encodeURIComponent(release.body)}&target=${release.commit}`;
296
+ if (release.prerelease) {
297
+ url += '&prerelease=true';
298
+ }
299
+ return url;
274
300
  }
275
301
  const providerToRefSpec = {
276
302
  github: { 'pull-request': 'pull', hash: 'commit', issue: 'issues' },
277
303
  };
278
- function formatReference(ref, repoSlug) {
304
+ function formatReference(ref, repoData) {
279
305
  const refSpec = providerToRefSpec['github'];
280
- return `[${ref.value}](https://github.com/${repoSlug}/${refSpec[ref.type]}/${ref.value.replace(/^#/, '')})`;
306
+ return `[${ref.value}](https://${repoData.hostname}/${repoData.slug}/${refSpec[ref.type]}/${ref.value.replace(/^#/, '')})`;
281
307
  }
282
- function formatReferences(references, repoSlug) {
308
+ function formatReferences(references, repoData) {
283
309
  const pr = references.filter((ref) => ref.type === 'pull-request');
284
310
  const issue = references.filter((ref) => ref.type === 'issue');
285
311
  if (pr.length > 0 || issue.length > 0) {
286
312
  return (' (' +
287
313
  [...pr, ...issue]
288
- .map((ref) => formatReference(ref, repoSlug))
314
+ .map((ref) => formatReference(ref, repoData))
289
315
  .join(', ') +
290
316
  ')');
291
317
  }
292
318
  if (references.length > 0) {
293
- return ' (' + formatReference(references[0], repoSlug) + ')';
319
+ return ' (' + formatReference(references[0], repoData) + ')';
294
320
  }
295
321
  return '';
296
322
  }
@@ -13,6 +13,7 @@ async function launchEditor(filePath) {
13
13
  return new Promise((resolve, reject) => {
14
14
  const editorProcess = (0, node_child_process_1.spawn)(cmd, [...args, filePath], {
15
15
  stdio: 'inherit', // This will ensure the editor uses the current terminal
16
+ windowsHide: true,
16
17
  });
17
18
  editorProcess.on('exit', (code) => {
18
19
  if (code === 0) {
@@ -26,7 +27,11 @@ async function launchEditor(filePath) {
26
27
  }
27
28
  function getGitConfig(key) {
28
29
  try {
29
- return (0, node_child_process_1.execSync)(`git config --get ${key}`).toString().trim();
30
+ return (0, node_child_process_1.execSync)(`git config --get ${key}`, {
31
+ windowsHide: true,
32
+ })
33
+ .toString()
34
+ .trim();
30
35
  }
31
36
  catch {
32
37
  return null;
@@ -210,7 +210,7 @@ function createAPI(overrideReleaseConfig) {
210
210
  runPreVersionCommand(releaseGroup.version.groupPreVersionCommand, {
211
211
  dryRun: args.dryRun,
212
212
  verbose: args.verbose,
213
- });
213
+ }, releaseGroup);
214
214
  const projectBatches = (0, batch_projects_by_generator_config_1.batchProjectsByGeneratorConfig)(projectGraph, releaseGroup,
215
215
  // Batch based on all projects within the release group
216
216
  releaseGroup.projects);
@@ -412,11 +412,13 @@ function resolveGeneratorData({ collectionName, generatorName, configGeneratorOp
412
412
  throw err;
413
413
  }
414
414
  }
415
- function runPreVersionCommand(preVersionCommand, { dryRun, verbose }) {
415
+ function runPreVersionCommand(preVersionCommand, { dryRun, verbose }, releaseGroup) {
416
416
  if (!preVersionCommand) {
417
417
  return;
418
418
  }
419
- output_1.output.logSingleLine(`Executing pre-version command`);
419
+ output_1.output.logSingleLine(releaseGroup
420
+ ? `Executing release group pre-version command for "${releaseGroup.name}"`
421
+ : `Executing pre-version command`);
420
422
  if (verbose) {
421
423
  console.log(`Executing the following pre-version command:`);
422
424
  console.log(preVersionCommand);
@@ -434,6 +436,7 @@ function runPreVersionCommand(preVersionCommand, { dryRun, verbose }) {
434
436
  maxBuffer: LARGE_BUFFER,
435
437
  stdio,
436
438
  env,
439
+ windowsHide: true,
437
440
  });
438
441
  }
439
442
  catch (e) {
@@ -1,6 +1,7 @@
1
1
  import { PackageManager } from '../../utils/package-manager';
2
2
  import { PackageJson } from '../../utils/package-json';
3
3
  import { NxJsonConfiguration } from '../../config/nx-json';
4
+ import type { PowerpackLicense } from '@nx/powerpack-license';
4
5
  export declare const packagesWeCareAbout: string[];
5
6
  export declare const patternsWeIgnoreInCommunityReport: Array<string | RegExp>;
6
7
  /**
@@ -15,7 +16,8 @@ export declare function reportHandler(): Promise<void>;
15
16
  export interface ReportData {
16
17
  pm: PackageManager;
17
18
  pmVersion: string;
18
- powerpackLicense: any | null;
19
+ powerpackLicense: PowerpackLicense | null;
20
+ powerpackError: Error | null;
19
21
  powerpackPlugins: PackageJson[];
20
22
  localPlugins: string[];
21
23
  communityPlugins: PackageJson[];