@storm-software/git-tools 2.124.0 → 2.124.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/git.cjs CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
+ require('./chunk-AU5PZKTN.cjs');
4
5
  var chunkFH5OSXAJ_cjs = require('./chunk-FH5OSXAJ.cjs');
5
6
  var chunkEHPPIARR_cjs = require('./chunk-EHPPIARR.cjs');
6
7
  var TOML = require('@ltd/j-toml');
@@ -26,22 +27,21 @@ var _ = require('underscore');
26
27
  var updateSection = require('update-section');
27
28
  var devkit = require('@nx/devkit');
28
29
  var axios = require('axios');
29
- require('enquirer');
30
30
  var os = require('os');
31
- var printChanges = require('nx/src/command-line/release/utils/print-changes');
32
31
  var github = require('nx/src/command-line/release/utils/remote-release-clients/github');
33
- var shared = require('nx/src/command-line/release/utils/shared');
34
32
  var yaml = require('yaml');
35
33
  var chalk = require('chalk');
34
+ var printChanges = require('nx/src/command-line/release/utils/print-changes');
35
+ var shared = require('nx/src/command-line/release/utils/shared');
36
36
  var utils = require('nx/src/tasks-runner/utils');
37
37
  var prettier = require('prettier');
38
- var release = require('nx/release');
38
+ var execCommand_js = require('nx/src/command-line/release/utils/exec-command.js');
39
39
  var git = require('nx/src/command-line/release/utils/git');
40
+ var semver = require('semver');
41
+ var release = require('nx/release');
40
42
  var nxJson = require('nx/src/config/nx-json');
41
43
  var tree = require('nx/src/generators/tree');
42
44
  var fileMapUtils = require('nx/src/project-graph/file-map-utils');
43
- var execCommand_js = require('nx/src/command-line/release/utils/exec-command.js');
44
- var semver = require('semver');
45
45
  var DefaultChangelogRenderer = require('nx/release/changelog-renderer');
46
46
  var conventionalCommits = require('nx/src/command-line/release/config/conventional-commits');
47
47
 
@@ -1966,7 +1966,7 @@ var createRegExp = (sectionName) => {
1966
1966
  var runReadme = async ({
1967
1967
  templates = "./tools/readme-templates",
1968
1968
  project,
1969
- output: output4,
1969
+ output: output3,
1970
1970
  clean = true,
1971
1971
  prettier = true
1972
1972
  }) => {
@@ -1977,7 +1977,7 @@ var runReadme = async ({
1977
1977
  if (project) {
1978
1978
  await runProjectReadme(project, {
1979
1979
  templates,
1980
- output: output4,
1980
+ output: output3,
1981
1981
  clean,
1982
1982
  prettier
1983
1983
  });
@@ -1985,14 +1985,14 @@ var runReadme = async ({
1985
1985
  for (const projectName of Object.keys(projectConfigs.projects)) {
1986
1986
  await runProjectReadme(projectName, {
1987
1987
  templates,
1988
- output: output4,
1988
+ output: output3,
1989
1989
  clean,
1990
1990
  prettier
1991
1991
  });
1992
1992
  }
1993
1993
  }
1994
1994
  };
1995
- var runProjectReadme = async (projectName, { templates, output: output4, clean = true, prettier = true }) => {
1995
+ var runProjectReadme = async (projectName, { templates, output: output3, clean = true, prettier = true }) => {
1996
1996
  const projectGraph = await projectGraph_js.createProjectGraphAsync({
1997
1997
  exitOnError: true
1998
1998
  });
@@ -2001,7 +2001,7 @@ var runProjectReadme = async (projectName, { templates, output: output4, clean =
2001
2001
  const inputFile = Path.join(project?.root ?? "./", "README.md");
2002
2002
  if (fs$1.existsSync(inputFile)) {
2003
2003
  console.info(`Formatting ${projectName}'s README file at "${inputFile}"`);
2004
- const outputFilePath = output4 ? output4.includes("README.md") ? output4 : Path.join(findFilePath(output4), "README.md") : inputFile;
2004
+ const outputFilePath = output3 ? output3.includes("README.md") ? output3 : Path.join(findFilePath(output3), "README.md") : inputFile;
2005
2005
  if (clean && fs$1.existsSync(outputFilePath)) {
2006
2006
  if (outputFilePath === inputFile) {
2007
2007
  console.warn(
@@ -2410,7 +2410,7 @@ function generateChangelogTitle(version, project, workspaceConfig) {
2410
2410
  if (!workspaceConfig?.name || !project) {
2411
2411
  return version;
2412
2412
  }
2413
- return `[${version}](https://github.com/${typeof workspaceConfig.organization === "string" ? workspaceConfig.organization : workspaceConfig.organization?.name}/${workspaceConfig.name}/releases/tag/${project}%40${version}) (${(/* @__PURE__ */ new Date()).getMonth() + 1}/${(/* @__PURE__ */ new Date()).getDate()}/${(/* @__PURE__ */ new Date()).getFullYear()})`;
2413
+ return `[${version}](https://github.com/${typeof workspaceConfig.organization === "string" ? workspaceConfig.organization : workspaceConfig.organization?.name}/${workspaceConfig.name}/releases/tag/${project}%40${version}) (${(/* @__PURE__ */ new Date()).getMonth() + 1 < 10 ? `0${(/* @__PURE__ */ new Date()).getMonth() + 1}` : (/* @__PURE__ */ new Date()).getMonth() + 1}/${(/* @__PURE__ */ new Date()).getDate() < 10 ? `0${(/* @__PURE__ */ new Date()).getDate()}` : (/* @__PURE__ */ new Date()).getDate()}/${(/* @__PURE__ */ new Date()).getFullYear()})`;
2414
2414
  }
2415
2415
  function parseChangelogMarkdown(contents) {
2416
2416
  const CHANGELOG_RELEASE_HEAD_RE = new RegExp(
@@ -2450,8 +2450,10 @@ function filterHiddenChanges(changes, conventionalCommitsConfig) {
2450
2450
  });
2451
2451
  }
2452
2452
  async function generateChangelogForProjects({
2453
+ tree,
2453
2454
  args,
2454
2455
  changes,
2456
+ projectGraph,
2455
2457
  projectsVersionData,
2456
2458
  releaseGroup,
2457
2459
  projects,
@@ -2465,9 +2467,21 @@ async function generateChangelogForProjects({
2465
2467
  return;
2466
2468
  }
2467
2469
  const dryRun = !!args.dryRun;
2468
- const remoteReleaseClient = await createGithubRemoteReleaseClient(
2469
- workspaceConfig,
2470
- args.gitRemote
2470
+ const repoData = getGitHubRepoData(args.gitRemote, "github");
2471
+ if (!repoData) {
2472
+ throw new Error(
2473
+ `Unable to create a remote release client because the GitHub repo slug could not be determined. Please ensure you have a valid GitHub remote configured.`
2474
+ );
2475
+ }
2476
+ const remoteReleaseClient = new StormGithubRemoteReleaseClient(
2477
+ repoData,
2478
+ {
2479
+ provider: "github",
2480
+ hostname: repoData.hostname,
2481
+ apiBaseUrl: repoData.apiBaseUrl
2482
+ },
2483
+ await resolveTokenData(repoData.hostname),
2484
+ workspaceConfig
2471
2485
  );
2472
2486
  const projectChangelogs = {};
2473
2487
  for (const project of projects) {
@@ -2526,227 +2540,48 @@ async function generateChangelogForProjects({
2526
2540
  postGitTask
2527
2541
  };
2528
2542
  }
2529
- return projectChangelogs;
2530
- }
2531
-
2532
- // src/release/github.ts
2533
- var StormGithubRemoteReleaseClient = class extends github.GithubRemoteReleaseClient {
2534
- #remoteRepoData;
2535
- #workspaceConfig;
2536
- /**
2537
- * Creates an instance of {@link StormGithubRemoteReleaseClient}.
2538
- *
2539
- * @param remoteRepoData - Data about the remote repository
2540
- * @param createReleaseConfig - Configuration for creating releases
2541
- * @param tokenData - Token data for authentication
2542
- * @param workspaceConfig - The Storm workspace configuration object, which is loaded from the storm-workspace.json file.
2543
- */
2544
- constructor(remoteRepoData, createReleaseConfig, tokenData, workspaceConfig) {
2545
- super(remoteRepoData, createReleaseConfig, tokenData);
2546
- this.#remoteRepoData = remoteRepoData;
2547
- this.#workspaceConfig = workspaceConfig;
2548
- }
2549
- createPostGitTask(releaseVersion, changelogContents, dryRun) {
2550
- return async (latestCommit) => {
2551
- if (!this.#workspaceConfig) {
2552
- this.#workspaceConfig = await chunkEHPPIARR_cjs.getWorkspaceConfig();
2553
- }
2554
- devkit.output.logSingleLine(`Creating GitHub Release`);
2555
- const name = releaseVersion.gitTag.includes("@") ? releaseVersion.gitTag.replace(new RegExp(`^@${this.#workspaceConfig.name}/`), "").replace(/@.*$/, "") : releaseVersion.gitTag;
2556
- await this.createOrUpdateRelease(
2557
- releaseVersion,
2558
- `![${(typeof this.#workspaceConfig.release.banner === "string" ? this.#workspaceConfig.organization ? titleCase(
2559
- typeof this.#workspaceConfig.organization === "string" ? this.#workspaceConfig.organization : this.#workspaceConfig.organization.name
2560
- ) : void 0 : this.#workspaceConfig.release.banner.alt) || "Release banner header"}](${typeof this.#workspaceConfig.release.banner === "string" ? this.#workspaceConfig.release.banner : this.#workspaceConfig.release.banner?.url})
2561
- ${this.#workspaceConfig.release.header || ""}
2562
-
2563
- # ${name ? `${titleCase(name)} ` : ""}v${releaseVersion.rawVersion}
2564
-
2565
- We at [${this.#workspaceConfig.organization ? titleCase(
2566
- typeof this.#workspaceConfig.organization === "string" ? this.#workspaceConfig.organization : this.#workspaceConfig.organization.name
2567
- ) : ""}](${this.#workspaceConfig.homepage}) are very excited to announce the v${releaseVersion.rawVersion} release of the ${name ? this.#workspaceConfig.name ? `${titleCase(this.#workspaceConfig.name)} - ${titleCase(name)}` : titleCase(name) : this.#workspaceConfig.name ? titleCase(this.#workspaceConfig.name) : "Storm Software"} project! \u{1F680}
2568
-
2569
- These changes are released under the ${this.#workspaceConfig.license.includes("license") ? this.#workspaceConfig.license : `${this.#workspaceConfig.license} license`}. You can find more details on [our licensing page](${this.#workspaceConfig.licensing}). You can find guides, API references, and other documentation around this release (and much more) on [our documentation site](${this.#workspaceConfig.docs}).
2570
-
2571
- If you have any questions or comments, feel free to reach out to the team on [Discord](${this.#workspaceConfig.socials.discord}) or [our contact page](${this.#workspaceConfig.contact}). Please help us spread the word by giving [this repository](https://github.com/${typeof this.#workspaceConfig.organization === "string" ? this.#workspaceConfig.organization : this.#workspaceConfig.organization?.name}/${this.#workspaceConfig.name}) a star \u2B50 on GitHub or [posting on X (Twitter)](https://x.com/intent/tweet?text=Check%20out%20the%20latest%20@${this.#workspaceConfig.socials.twitter}%20release%20${name ? `${titleCase(name)?.replaceAll(" ", "%20")}%20` : ""}v${releaseVersion.rawVersion}%20%F0%9F%9A%80%0D%0A%0D%0Ahttps://github.com/${typeof this.#workspaceConfig.organization === "string" ? this.#workspaceConfig.organization : this.#workspaceConfig.organization?.name}/${this.#workspaceConfig.name}/releases/tag/${releaseVersion.gitTag}) about this release!
2572
-
2573
- ## Release Notes
2574
-
2575
- ${changelogContents.replaceAll(
2576
- `## ${generateChangelogTitle(
2577
- releaseVersion.rawVersion,
2578
- name,
2579
- this.#workspaceConfig
2580
- )}`,
2581
- ""
2582
- ).replaceAll(
2583
- `# ${generateChangelogTitle(releaseVersion.rawVersion, name, this.#workspaceConfig)}`,
2584
- ""
2585
- )}
2586
-
2587
- ---
2588
-
2589
- ${this.#workspaceConfig.release.footer}
2590
- `,
2591
- latestCommit,
2592
- { dryRun }
2543
+ for (const [projectName, projectChangelog] of Object.entries(
2544
+ projectChangelogs
2545
+ )) {
2546
+ if (!projectGraph.nodes[projectName]?.data.root) {
2547
+ chunkEHPPIARR_cjs.writeWarning(
2548
+ `A changelog was generated for ${projectName}, but it could not be found in the project graph. Skipping writing changelog file.`,
2549
+ workspaceConfig
2593
2550
  );
2594
- };
2595
- }
2596
- /**
2597
- * Get remote repository data, attempting to resolve it if not already set.
2598
- */
2599
- getRemoteRepoData() {
2600
- if (!this.#remoteRepoData) {
2601
- let githubRepoData = super.getRemoteRepoData();
2602
- if (!githubRepoData) {
2603
- githubRepoData = getGitHubRepoData();
2604
- if (!githubRepoData) {
2605
- devkit.output.error({
2606
- title: `Unable to create a GitHub release because the GitHub repo slug could not be determined.`,
2607
- bodyLines: [
2608
- `Please ensure you have a valid GitHub remote configured. You can run \`git remote -v\` to list your current remotes.`
2609
- ]
2610
- });
2611
- process.exit(1);
2612
- }
2613
- }
2614
- this.#remoteRepoData = githubRepoData;
2615
- }
2616
- return this.#remoteRepoData;
2617
- }
2618
- };
2619
- function getGitHubRepoData(remoteName = "origin", createReleaseConfig = "github") {
2620
- try {
2621
- const remoteUrl = childProcess.execSync(`git remote get-url ${remoteName}`, {
2622
- encoding: "utf8",
2623
- stdio: "pipe"
2624
- }).trim();
2625
- let hostname = github.defaultCreateReleaseProvider.hostname;
2626
- let apiBaseUrl = github.defaultCreateReleaseProvider.apiBaseUrl;
2627
- if (createReleaseConfig && typeof createReleaseConfig !== "string") {
2628
- hostname = createReleaseConfig.hostname;
2629
- apiBaseUrl = createReleaseConfig.apiBaseUrl;
2630
- }
2631
- const escapedHostname = hostname.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2632
- const regexString = `${escapedHostname}[/:]([\\w.-]+/[\\w.-]+)(\\.git)?`;
2633
- const regex = new RegExp(regexString);
2634
- const match = remoteUrl?.match(regex);
2635
- if (match && match[1]) {
2636
- return {
2637
- hostname,
2638
- apiBaseUrl,
2639
- // Ensure any trailing .git is stripped
2640
- slug: match[1].replace(/\.git$/, "")
2641
- };
2642
- } else {
2643
- throw new Error(
2644
- `Could not extract "user/repo" data from the resolved remote URL: ${remoteUrl}`
2551
+ } else if (projectChangelog.contents) {
2552
+ const filePath = chunkEHPPIARR_cjs.joinPaths(
2553
+ projectGraph.nodes[projectName].data.root,
2554
+ "CHANGELOG.md"
2645
2555
  );
2646
- }
2647
- } catch (error) {
2648
- devkit.output.error({
2649
- title: `Failed to get GitHub repo data`,
2650
- bodyLines: [error.message]
2651
- });
2652
- return void 0;
2653
- }
2654
- }
2655
- async function resolveTokenData(hostname) {
2656
- const tokenFromEnv = process.env.STORM_BOT_GITHUB_TOKEN || process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
2657
- if (tokenFromEnv) {
2658
- return { token: tokenFromEnv, headerName: "Authorization" };
2659
- }
2660
- const ghCLIPath = devkit.joinPathFragments(
2661
- process.env.XDG_CONFIG_HOME || devkit.joinPathFragments(os.homedir(), ".config"),
2662
- "gh",
2663
- "hosts.yml"
2664
- );
2665
- if (fs$1.existsSync(ghCLIPath)) {
2666
- const yamlContents = await fs$1.promises.readFile(ghCLIPath, "utf8");
2667
- const ghCLIConfig = yaml.parse(yamlContents);
2668
- if (ghCLIConfig[hostname]) {
2669
- if (ghCLIConfig[hostname].oauth_token) {
2670
- return ghCLIConfig[hostname].oauth_token;
2556
+ let currentContent;
2557
+ if (fs$1.existsSync(filePath)) {
2558
+ currentContent = await fs.readFile(filePath, "utf8");
2671
2559
  }
2672
- if (ghCLIConfig[hostname].user && ghCLIConfig[hostname].git_protocol === "ssh") {
2673
- const token = childProcess.execSync(`gh auth token`, {
2674
- encoding: "utf8",
2675
- stdio: "pipe",
2676
- windowsHide: false
2677
- }).trim();
2678
- return { token, headerName: "Authorization" };
2679
- }
2680
- }
2681
- }
2682
- if (hostname !== "github.com") {
2683
- console.log(
2684
- `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.`
2685
- );
2686
- }
2687
- throw new Error(
2688
- `Unable to resolve a GitHub token for hostname ${hostname}. Please set the GITHUB_TOKEN or GH_TOKEN environment variable, or ensure you have an active session via the official gh CLI tool (https://cli.github.com).`
2689
- );
2690
- }
2691
- async function makeGithubRequest(config5, url, opts = {}) {
2692
- return await axios__default.default(url, {
2693
- ...opts,
2694
- baseURL: config5.apiBaseUrl,
2695
- headers: {
2696
- ...opts.headers,
2697
- Authorization: config5.token ? `Bearer ${config5.token}` : void 0
2698
- }
2699
- });
2700
- }
2701
- async function createGithubRemoteReleaseClient(workspaceConfig, remoteName = "origin") {
2702
- const repoData = getGitHubRepoData(remoteName, "github");
2703
- if (!repoData) {
2704
- throw new Error(
2705
- `Unable to create a remote release client because the GitHub repo slug could not be determined. Please ensure you have a valid GitHub remote configured.`
2706
- );
2707
- }
2708
- return new StormGithubRemoteReleaseClient(
2709
- repoData,
2710
- {
2711
- provider: "github",
2712
- hostname: repoData.hostname,
2713
- apiBaseUrl: repoData.apiBaseUrl
2714
- },
2715
- await resolveTokenData(repoData.hostname),
2716
- workspaceConfig
2717
- );
2718
- }
2719
- async function isUserAnOrganizationMember(userId, config5, remoteName = "origin") {
2720
- try {
2721
- const repoData = getGitHubRepoData(remoteName, "github");
2722
- if (!repoData) {
2723
- throw new Error(
2724
- `Unable to validate GitHub actor because the GitHub repo slug could not be determined. Please ensure you have a valid GitHub remote configured.`
2560
+ chunkEHPPIARR_cjs.writeDebug(
2561
+ `\u270D\uFE0F Writing changelog for project ${projectName} to ${filePath}`,
2562
+ workspaceConfig
2725
2563
  );
2726
- }
2727
- const tokenData = await resolveTokenData(repoData.hostname);
2728
- if (!tokenData.token) {
2729
- throw new Error(
2730
- `Unable to validate GitHub actor because no token was provided. Please set the GITHUB_TOKEN or GH_TOKEN environment variable, or ensure you have an active session via the official gh CLI tool (https://cli.github.com).`
2564
+ const content = await generateChangelogContent(
2565
+ projectChangelog.releaseVersion,
2566
+ filePath,
2567
+ projectChangelog.contents,
2568
+ currentContent,
2569
+ projectName,
2570
+ workspaceConfig
2571
+ );
2572
+ tree.write(filePath, content);
2573
+ printChanges.printAndFlushChanges(
2574
+ tree,
2575
+ !!args.dryRun,
2576
+ 3,
2577
+ false,
2578
+ shared.noDiffInChangelogMessage,
2579
+ // Only print the change for the current changelog file at this point
2580
+ (f) => f.path === filePath
2731
2581
  );
2732
2582
  }
2733
- const result = await makeGithubRequest(
2734
- {
2735
- repo: repoData.slug,
2736
- hostname: repoData.hostname,
2737
- apiBaseUrl: repoData.apiBaseUrl,
2738
- token: tokenData?.token || null
2739
- },
2740
- `/orgs/${typeof config5.organization === "string" ? config5.organization : config5.organization?.name}/members/${userId}`,
2741
- {}
2742
- );
2743
- if (result.status !== 204) {
2744
- return false;
2745
- }
2746
- return true;
2747
- } catch {
2748
- return false;
2749
2583
  }
2584
+ return projectChangelogs;
2750
2585
  }
2751
2586
  async function getCommits(fromSHA, toSHA) {
2752
2587
  const rawCommits = await git.getGitDiff(fromSHA, toSHA);
@@ -2790,40 +2625,6 @@ function extractPreid(version) {
2790
2625
  }
2791
2626
  return void 0;
2792
2627
  }
2793
- function createGitTagValues(releaseGroups, releaseGroupToFilteredProjects, versionData) {
2794
- const tags = [];
2795
- for (const releaseGroup of releaseGroups) {
2796
- const releaseGroupProjectNames = Array.from(
2797
- releaseGroupToFilteredProjects.get(releaseGroup) ?? []
2798
- );
2799
- if (releaseGroup.projectsRelationship === "independent") {
2800
- for (const project of releaseGroupProjectNames) {
2801
- const projectVersionData = versionData[project];
2802
- if (projectVersionData?.newVersion) {
2803
- tags.push(
2804
- utils.interpolate(releaseGroup.releaseTagPattern, {
2805
- version: projectVersionData.newVersion,
2806
- projectName: project
2807
- })
2808
- );
2809
- }
2810
- }
2811
- continue;
2812
- }
2813
- if (releaseGroupProjectNames.length > 0 && releaseGroupProjectNames[0]) {
2814
- const projectVersionData = versionData[releaseGroupProjectNames[0]];
2815
- if (projectVersionData?.newVersion) {
2816
- tags.push(
2817
- utils.interpolate(releaseGroup.releaseTagPattern, {
2818
- version: projectVersionData.newVersion,
2819
- releaseGroupName: releaseGroup.name
2820
- })
2821
- );
2822
- }
2823
- }
2824
- }
2825
- return tags;
2826
- }
2827
2628
  async function gitTag({
2828
2629
  tag,
2829
2630
  message,
@@ -2948,6 +2749,216 @@ function omit(obj, keys) {
2948
2749
  }
2949
2750
  return result;
2950
2751
  }
2752
+
2753
+ // src/release/github.ts
2754
+ var StormGithubRemoteReleaseClient = class extends github.GithubRemoteReleaseClient {
2755
+ repoData;
2756
+ workspaceConfig;
2757
+ /**
2758
+ * Creates an instance of {@link StormGithubRemoteReleaseClient}.
2759
+ *
2760
+ * @param remoteRepoData - Data about the remote repository
2761
+ * @param createReleaseConfig - Configuration for creating releases
2762
+ * @param tokenData - Token data for authentication
2763
+ * @param workspaceConfig - The Storm workspace configuration object, which is loaded from the storm-workspace.json file.
2764
+ */
2765
+ constructor(repoData, createReleaseConfig, tokenData, workspaceConfig) {
2766
+ super(repoData, createReleaseConfig, tokenData);
2767
+ this.repoData = repoData;
2768
+ this.workspaceConfig = workspaceConfig;
2769
+ }
2770
+ createPostGitTask(releaseVersion, changelogContents, dryRun) {
2771
+ return async (latestCommit) => {
2772
+ devkit.output.logSingleLine(`Creating GitHub Release`);
2773
+ await this.createOrUpdateRelease(
2774
+ releaseVersion,
2775
+ changelogContents,
2776
+ latestCommit,
2777
+ { dryRun }
2778
+ );
2779
+ };
2780
+ }
2781
+ async createOrUpdateRelease(releaseVersion, changelogContents, latestCommit, { dryRun }) {
2782
+ if (!this.workspaceConfig) {
2783
+ this.workspaceConfig = await chunkEHPPIARR_cjs.getWorkspaceConfig();
2784
+ }
2785
+ const name = releaseVersion.gitTag.includes("@") ? releaseVersion.gitTag.replace(new RegExp(`^@${this.workspaceConfig.name}/`), "").replace(/@.*$/, "") : releaseVersion.gitTag;
2786
+ return super.createOrUpdateRelease(
2787
+ releaseVersion,
2788
+ `![${(typeof this.workspaceConfig.release.banner === "string" ? this.workspaceConfig.organization ? titleCase(
2789
+ typeof this.workspaceConfig.organization === "string" ? this.workspaceConfig.organization : this.workspaceConfig.organization.name
2790
+ ) : void 0 : this.workspaceConfig.release.banner.alt) || "Release banner header"}](${typeof this.workspaceConfig.release.banner === "string" ? this.workspaceConfig.release.banner : this.workspaceConfig.release.banner?.url})
2791
+ ${this.workspaceConfig.release.header || ""}
2792
+
2793
+ # ${name ? `${titleCase(name)} ` : ""}v${releaseVersion.rawVersion}
2794
+
2795
+ We at [${this.workspaceConfig.organization ? titleCase(
2796
+ typeof this.workspaceConfig.organization === "string" ? this.workspaceConfig.organization : this.workspaceConfig.organization.name
2797
+ ) : ""}](${this.workspaceConfig.homepage}) are very excited to announce the v${releaseVersion.rawVersion} release of the ${name ? this.workspaceConfig.name ? `${titleCase(this.workspaceConfig.name)} - ${titleCase(name)}` : titleCase(name) : this.workspaceConfig.name ? titleCase(this.workspaceConfig.name) : "Storm Software"} project! \u{1F680}
2798
+
2799
+ These changes are released under the ${this.workspaceConfig.license.includes("license") ? this.workspaceConfig.license : `${this.workspaceConfig.license} license`}. You can find more details on [our licensing page](${this.workspaceConfig.licensing}). You can find guides, API references, and other documentation around this release (and much more) on [our documentation site](${this.workspaceConfig.docs}).
2800
+
2801
+ If you have any questions or comments, feel free to reach out to the team on [Discord](${this.workspaceConfig.socials.discord}) or [our contact page](${this.workspaceConfig.contact}). Please help us spread the word by giving [this repository](https://github.com/${typeof this.workspaceConfig.organization === "string" ? this.workspaceConfig.organization : this.workspaceConfig.organization?.name}/${this.workspaceConfig.name}) a star \u2B50 on GitHub or [posting on X (Twitter)](https://x.com/intent/tweet?text=Check%20out%20the%20latest%20@${this.workspaceConfig.socials.twitter}%20release%20${name ? `${titleCase(name)?.replaceAll(" ", "%20")}%20` : ""}v${releaseVersion.rawVersion}%20%F0%9F%9A%80%0D%0A%0D%0Ahttps://github.com/${typeof this.workspaceConfig.organization === "string" ? this.workspaceConfig.organization : this.workspaceConfig.organization?.name}/${this.workspaceConfig.name}/releases/tag/${releaseVersion.gitTag}) about this release!
2802
+
2803
+ ## Release Notes
2804
+
2805
+ ${changelogContents.replaceAll(
2806
+ `## ${generateChangelogTitle(
2807
+ releaseVersion.rawVersion,
2808
+ name,
2809
+ this.workspaceConfig
2810
+ )}`,
2811
+ ""
2812
+ ).replaceAll(
2813
+ `# ${generateChangelogTitle(releaseVersion.rawVersion, name, this.workspaceConfig)}`,
2814
+ ""
2815
+ )}
2816
+
2817
+ ---
2818
+
2819
+ ${this.workspaceConfig.release.footer}
2820
+ `,
2821
+ latestCommit,
2822
+ { dryRun }
2823
+ );
2824
+ }
2825
+ /**
2826
+ * Get remote repository data, attempting to resolve it if not already set.
2827
+ */
2828
+ getRemoteRepoData() {
2829
+ if (!this.repoData) {
2830
+ let githubRepoData = super.getRemoteRepoData();
2831
+ if (!githubRepoData) {
2832
+ githubRepoData = getGitHubRepoData();
2833
+ if (!githubRepoData) {
2834
+ devkit.output.error({
2835
+ title: `Unable to create a GitHub release because the GitHub repo slug could not be determined.`,
2836
+ bodyLines: [
2837
+ `Please ensure you have a valid GitHub remote configured. You can run \`git remote -v\` to list your current remotes.`
2838
+ ]
2839
+ });
2840
+ process.exit(1);
2841
+ }
2842
+ }
2843
+ this.repoData = githubRepoData;
2844
+ }
2845
+ return this.repoData;
2846
+ }
2847
+ };
2848
+ function getGitHubRepoData(remoteName = "origin", createReleaseConfig = "github") {
2849
+ try {
2850
+ const remoteUrl = childProcess.execSync(`git remote get-url ${remoteName}`, {
2851
+ encoding: "utf8",
2852
+ stdio: "pipe"
2853
+ }).trim();
2854
+ let hostname = github.defaultCreateReleaseProvider.hostname;
2855
+ let apiBaseUrl = github.defaultCreateReleaseProvider.apiBaseUrl;
2856
+ if (createReleaseConfig && typeof createReleaseConfig !== "string") {
2857
+ hostname = createReleaseConfig.hostname;
2858
+ apiBaseUrl = createReleaseConfig.apiBaseUrl;
2859
+ }
2860
+ const escapedHostname = hostname.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2861
+ const regexString = `${escapedHostname}[/:]([\\w.-]+/[\\w.-]+)(\\.git)?`;
2862
+ const regex = new RegExp(regexString);
2863
+ const match = remoteUrl?.match(regex);
2864
+ if (match && match[1]) {
2865
+ return {
2866
+ hostname,
2867
+ apiBaseUrl,
2868
+ // Ensure any trailing .git is stripped
2869
+ slug: match[1].replace(/\.git$/, "")
2870
+ };
2871
+ } else {
2872
+ throw new Error(
2873
+ `Could not extract "user/repo" data from the resolved remote URL: ${remoteUrl}`
2874
+ );
2875
+ }
2876
+ } catch (error) {
2877
+ devkit.output.error({
2878
+ title: `Failed to get GitHub repo data`,
2879
+ bodyLines: [error.message]
2880
+ });
2881
+ return void 0;
2882
+ }
2883
+ }
2884
+ async function resolveTokenData(hostname) {
2885
+ const tokenFromEnv = process.env.STORM_BOT_GITHUB_TOKEN || process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
2886
+ if (tokenFromEnv) {
2887
+ return { token: tokenFromEnv, headerName: "Authorization" };
2888
+ }
2889
+ const ghCLIPath = devkit.joinPathFragments(
2890
+ process.env.XDG_CONFIG_HOME || devkit.joinPathFragments(os.homedir(), ".config"),
2891
+ "gh",
2892
+ "hosts.yml"
2893
+ );
2894
+ if (fs$1.existsSync(ghCLIPath)) {
2895
+ const yamlContents = await fs$1.promises.readFile(ghCLIPath, "utf8");
2896
+ const ghCLIConfig = yaml.parse(yamlContents);
2897
+ if (ghCLIConfig[hostname]) {
2898
+ if (ghCLIConfig[hostname].oauth_token) {
2899
+ return ghCLIConfig[hostname].oauth_token;
2900
+ }
2901
+ if (ghCLIConfig[hostname].user && ghCLIConfig[hostname].git_protocol === "ssh") {
2902
+ const token = childProcess.execSync(`gh auth token`, {
2903
+ encoding: "utf8",
2904
+ stdio: "pipe",
2905
+ windowsHide: false
2906
+ }).trim();
2907
+ return { token, headerName: "Authorization" };
2908
+ }
2909
+ }
2910
+ }
2911
+ if (hostname !== "github.com") {
2912
+ console.log(
2913
+ `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.`
2914
+ );
2915
+ }
2916
+ throw new Error(
2917
+ `Unable to resolve a GitHub token for hostname ${hostname}. Please set the GITHUB_TOKEN or GH_TOKEN environment variable, or ensure you have an active session via the official gh CLI tool (https://cli.github.com).`
2918
+ );
2919
+ }
2920
+ async function makeGithubRequest(config5, url, opts = {}) {
2921
+ return await axios__default.default(url, {
2922
+ ...opts,
2923
+ baseURL: config5.apiBaseUrl,
2924
+ headers: {
2925
+ ...opts.headers,
2926
+ Authorization: config5.token ? `Bearer ${config5.token}` : void 0
2927
+ }
2928
+ });
2929
+ }
2930
+ async function isUserAnOrganizationMember(userId, config5, remoteName = "origin") {
2931
+ try {
2932
+ const repoData = getGitHubRepoData(remoteName, "github");
2933
+ if (!repoData) {
2934
+ throw new Error(
2935
+ `Unable to validate GitHub actor because the GitHub repo slug could not be determined. Please ensure you have a valid GitHub remote configured.`
2936
+ );
2937
+ }
2938
+ const tokenData = await resolveTokenData(repoData.hostname);
2939
+ if (!tokenData.token) {
2940
+ throw new Error(
2941
+ `Unable to validate GitHub actor because no token was provided. Please set the GITHUB_TOKEN or GH_TOKEN environment variable, or ensure you have an active session via the official gh CLI tool (https://cli.github.com).`
2942
+ );
2943
+ }
2944
+ const result = await makeGithubRequest(
2945
+ {
2946
+ repo: repoData.slug,
2947
+ hostname: repoData.hostname,
2948
+ apiBaseUrl: repoData.apiBaseUrl,
2949
+ token: tokenData?.token || null
2950
+ },
2951
+ `/orgs/${typeof config5.organization === "string" ? config5.organization : config5.organization?.name}/members/${userId}`,
2952
+ {}
2953
+ );
2954
+ if (result.status !== 204) {
2955
+ return false;
2956
+ }
2957
+ return true;
2958
+ } catch {
2959
+ return false;
2960
+ }
2961
+ }
2951
2962
  var StormChangelogRenderer = class extends DefaultChangelogRenderer__default.default {
2952
2963
  /**
2953
2964
  * The Storm workspace configuration object, which is loaded from the storm-workspace.json file.
@@ -3488,10 +3499,15 @@ var StormReleaseClient = class _StormReleaseClient extends release.ReleaseClient
3488
3499
  })),
3489
3500
  this.config.conventionalCommits
3490
3501
  );
3502
+ chunkEHPPIARR_cjs.writeDebug(
3503
+ `Running changelog generation for the ${releaseGroup.name} release group`,
3504
+ this.workspaceConfig
3505
+ );
3491
3506
  projectChangelogs = await generateChangelogForProjects({
3492
3507
  tree: this.tree,
3493
3508
  args: options,
3494
3509
  changes,
3510
+ projectGraph: this.projectGraph,
3495
3511
  projectsVersionData: options.versionData,
3496
3512
  releaseGroup,
3497
3513
  projects: [project],
@@ -3554,10 +3570,15 @@ var StormReleaseClient = class _StormReleaseClient extends release.ReleaseClient
3554
3570
  })),
3555
3571
  this.config.conventionalCommits
3556
3572
  );
3573
+ chunkEHPPIARR_cjs.writeDebug(
3574
+ `Running changelog generation for the ${releaseGroup.name} release group`,
3575
+ this.workspaceConfig
3576
+ );
3557
3577
  projectChangelogs = await generateChangelogForProjects({
3558
3578
  tree: this.tree,
3559
3579
  args: options,
3560
3580
  changes,
3581
+ projectGraph: this.projectGraph,
3561
3582
  projectsVersionData: options.versionData,
3562
3583
  releaseGroup,
3563
3584
  projects: projectNodes,
@@ -3578,80 +3599,26 @@ var StormReleaseClient = class _StormReleaseClient extends release.ReleaseClient
3578
3599
  }
3579
3600
  }
3580
3601
  }
3581
- if (projectChangelogs) {
3582
- await Promise.all(
3583
- Object.entries(projectChangelogs).map(async ([project, changelog]) => {
3584
- if (!this.projectGraph.nodes[project]?.data.root) {
3585
- chunkEHPPIARR_cjs.writeWarning(
3586
- `A changelog was generated for ${project}, but it could not be found in the project graph. Skipping writing changelog file.`,
3587
- this.workspaceConfig
3588
- );
3589
- } else if (changelog.contents) {
3590
- const filePath = chunkEHPPIARR_cjs.joinPaths(
3591
- this.projectGraph.nodes[project].data.root,
3592
- "CHANGELOG.md"
3593
- );
3594
- let currentContent;
3595
- if (fs$1.existsSync(filePath)) {
3596
- currentContent = await fs.readFile(filePath, "utf8");
3597
- }
3598
- chunkEHPPIARR_cjs.writeDebug(
3599
- `\u270D\uFE0F Writing changelog for project ${project} to ${filePath}`,
3600
- this.workspaceConfig
3601
- );
3602
- const content = await generateChangelogContent(
3603
- changelog.releaseVersion,
3604
- filePath,
3605
- changelog.contents,
3606
- currentContent,
3607
- project,
3608
- this.workspaceConfig
3609
- );
3610
- this.tree.write(filePath, content);
3611
- printChanges.printAndFlushChanges(
3612
- this.tree,
3613
- !!options.dryRun,
3614
- 3,
3615
- false,
3616
- shared.noDiffInChangelogMessage,
3617
- // Only print the change for the current changelog file at this point
3618
- (f) => f.path === filePath
3619
- );
3620
- }
3621
- })
3622
- );
3623
- this.applyChangesAndExit(options, postGitTasks);
3624
- }
3602
+ chunkEHPPIARR_cjs.writeDebug(
3603
+ `Generated changelogs for ${Object.keys(allProjectChangelogs).length} projects:
3604
+ ${Object.keys(allProjectChangelogs).map((p) => ` - ${p}`).join("\n")}
3605
+ `,
3606
+ this.workspaceConfig
3607
+ );
3608
+ await this.applyChangesAndExit(options, postGitTasks);
3625
3609
  return {
3626
3610
  workspaceChangelog: void 0,
3627
3611
  projectChangelogs: allProjectChangelogs
3628
3612
  };
3629
3613
  };
3630
- checkChangelogFilesEnabled() {
3631
- if (this.config.changelog?.workspaceChangelog && (this.config.changelog?.workspaceChangelog === true || this.config.changelog?.workspaceChangelog.file)) {
3632
- return true;
3633
- }
3634
- for (const releaseGroup of Object.values(this.config.groups)) {
3635
- if (releaseGroup.changelog && releaseGroup.changelog !== true && releaseGroup.changelog.file) {
3636
- return true;
3637
- }
3638
- }
3639
- return false;
3640
- }
3641
- isCI = () => {
3642
- if (process.env.CI === "false") {
3643
- return false;
3644
- }
3645
- return process.env.CI || process.env.TF_BUILD === "true" || process.env.GITHUB_ACTIONS === "true" || process.env.BUILDKITE === "true" || process.env.CIRCLECI === "true" || process.env.CIRRUS_CI === "true" || process.env.TRAVIS === "true" || !!process.env["bamboo.buildKey"] || !!process.env["bamboo_buildKey"] || !!process.env.CODEBUILD_BUILD_ID || !!process.env.GITLAB_CI || !!process.env.HEROKU_TEST_RUN_ID || !!process.env.BUILD_ID || !!process.env.BUILD_NUMBER || !!process.env.BUILD_BUILDID || !!process.env.TEAMCITY_VERSION || !!process.env.JENKINS_URL || !!process.env.HUDSON_URL;
3646
- };
3647
3614
  applyChangesAndExit = async (options, postGitTasks) => {
3648
3615
  const to = options.to || "HEAD";
3649
3616
  let latestCommit = await git.getCommitHash(to);
3650
- const gitTagValues = options.gitTag ?? this.config.changelog?.git?.tag ? createGitTagValues(
3617
+ const gitTagValues = shared.createGitTagValues(
3651
3618
  options.releaseGraph.releaseGroups,
3652
3619
  options.releaseGraph.releaseGroupToFilteredProjects,
3653
3620
  options.versionData
3654
- ) : [];
3621
+ );
3655
3622
  shared.handleDuplicateGitTags(gitTagValues);
3656
3623
  const commitMessageValues = shared.createCommitMessageValues(
3657
3624
  options.releaseGraph.releaseGroups,
@@ -3660,13 +3627,11 @@ var StormReleaseClient = class _StormReleaseClient extends release.ReleaseClient
3660
3627
  options.gitCommitMessage || this.config.changelog?.git?.commitMessage || "release(monorepo): Publish workspace release updates"
3661
3628
  );
3662
3629
  const changes = this.tree.listChanges();
3663
- if (this.checkChangelogFilesEnabled() && !changes.length) {
3664
- devkit.output.warn({
3665
- title: `No changes detected for changelogs`,
3666
- bodyLines: [
3667
- `No changes were detected for any changelog files, so no changelog entries will be generated.`
3668
- ]
3669
- });
3630
+ if (!changes.length) {
3631
+ chunkEHPPIARR_cjs.writeWarning(
3632
+ "No changes were detected for any changelog files, so no changelog entries will be generated.",
3633
+ this.workspaceConfig
3634
+ );
3670
3635
  if (!postGitTasks.length) {
3671
3636
  return;
3672
3637
  }
@@ -3685,7 +3650,10 @@ var StormReleaseClient = class _StormReleaseClient extends release.ReleaseClient
3685
3650
  gitCommitArgs: options.gitCommitArgs || this.config.changelog?.git?.commitArgs
3686
3651
  });
3687
3652
  latestCommit = await git.getCommitHash("HEAD");
3688
- devkit.output.logSingleLine(`Tagging commit with git`);
3653
+ chunkEHPPIARR_cjs.writeDebug(
3654
+ `Creating git tags: ${gitTagValues.join(", ")}`,
3655
+ this.workspaceConfig
3656
+ );
3689
3657
  for (const tag of gitTagValues) {
3690
3658
  await gitTag({
3691
3659
  tag,
@@ -3695,17 +3663,16 @@ var StormReleaseClient = class _StormReleaseClient extends release.ReleaseClient
3695
3663
  verbose: options.verbose
3696
3664
  });
3697
3665
  }
3698
- if (options.gitPush ?? this.config.changelog?.git?.push) {
3699
- devkit.output.logSingleLine(
3700
- `Pushing to git remote "${options.gitRemote ?? "origin"}"`
3701
- );
3702
- await git.gitPush({
3703
- gitRemote: options.gitRemote,
3704
- dryRun: options.dryRun,
3705
- verbose: options.verbose,
3706
- additionalArgs: options.gitPushArgs || this.config.changelog?.git?.pushArgs
3707
- });
3708
- }
3666
+ chunkEHPPIARR_cjs.writeDebug(
3667
+ `Pushing to git remote "${options.gitRemote ?? "origin"}"`,
3668
+ this.workspaceConfig
3669
+ );
3670
+ await git.gitPush({
3671
+ gitRemote: options.gitRemote,
3672
+ dryRun: options.dryRun,
3673
+ verbose: options.verbose,
3674
+ additionalArgs: options.gitPushArgs || this.config.changelog?.git?.pushArgs
3675
+ });
3709
3676
  for (const postGitTask of postGitTasks) {
3710
3677
  await postGitTask(latestCommit);
3711
3678
  }