@releasekit/publish 0.2.0-next.9 → 0.3.0-next.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Sam Maister
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -82,13 +82,21 @@ releasekit-publish --input version-output.json
82
82
  ### In CI (GitHub Actions)
83
83
 
84
84
  ```yaml
85
+ - name: Configure permissions (OIDC + git pushes)
86
+ # at job level:
87
+ # permissions:
88
+ # id-token: write
89
+ # contents: write
90
+
85
91
  - name: Version
86
92
  run: releasekit-version --json > version-output.json
87
93
 
88
94
  - name: Publish
89
95
  run: releasekit-publish --input version-output.json
96
+ # For OIDC trusted publishing: no npm token needed (recommended).
97
+ # For token-based publishing: set NPM_TOKEN (or NODE_AUTH_TOKEN).
90
98
  env:
91
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
99
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
92
100
  ```
93
101
 
94
102
  ## Configuration
@@ -105,6 +113,10 @@ Configure via `releasekit.config.json`:
105
113
  "access": "public",
106
114
  "copyFiles": ["LICENSE"]
107
115
  },
116
+ "git": {
117
+ "pushMethod": "auto",
118
+ "httpsTokenEnv": "GITHUB_TOKEN"
119
+ },
108
120
  "cargo": {
109
121
  "enabled": false,
110
122
  "noVerify": false
@@ -23,14 +23,16 @@ function getDefaultConfig() {
23
23
  push: true,
24
24
  pushMethod: "auto",
25
25
  remote: "origin",
26
- branch: "main"
26
+ branch: "main",
27
+ httpsTokenEnv: void 0,
28
+ skipHooks: false
27
29
  },
28
30
  githubRelease: {
29
31
  enabled: true,
30
32
  draft: true,
31
- generateNotes: true,
32
- perPackage: false,
33
- prerelease: "auto"
33
+ perPackage: true,
34
+ prerelease: "auto",
35
+ releaseNotes: "auto"
34
36
  },
35
37
  verify: {
36
38
  npm: {
@@ -71,15 +73,16 @@ function toPublishConfig(config) {
71
73
  push: config.git.push ?? defaults.git.push,
72
74
  pushMethod: config.git.pushMethod ?? defaults.git.pushMethod,
73
75
  remote: config.git.remote ?? defaults.git.remote,
74
- branch: config.git.branch ?? defaults.git.branch
76
+ branch: config.git.branch ?? defaults.git.branch,
77
+ httpsTokenEnv: config.git.httpsTokenEnv ?? defaults.git.httpsTokenEnv,
78
+ skipHooks: config.git.skipHooks ?? defaults.git.skipHooks
75
79
  } : defaults.git,
76
80
  githubRelease: {
77
81
  enabled: config.githubRelease?.enabled ?? defaults.githubRelease.enabled,
78
82
  draft: config.githubRelease?.draft ?? defaults.githubRelease.draft,
79
- generateNotes: config.githubRelease?.generateNotes ?? defaults.githubRelease.generateNotes,
80
83
  perPackage: config.githubRelease?.perPackage ?? defaults.githubRelease.perPackage,
81
84
  prerelease: config.githubRelease?.prerelease ?? defaults.githubRelease.prerelease,
82
- notesFile: config.githubRelease?.notesFile
85
+ releaseNotes: config.githubRelease?.releaseNotes ?? defaults.githubRelease.releaseNotes
83
86
  },
84
87
  verify: {
85
88
  npm: {
@@ -248,8 +251,20 @@ function createPublishError(code, details) {
248
251
  // src/utils/exec.ts
249
252
  import { execFile } from "child_process";
250
253
  import { debug, info } from "@releasekit/core";
254
+ function redactArg(arg) {
255
+ try {
256
+ const url = new URL(arg);
257
+ if (url.username || url.password) {
258
+ url.username = url.username ? "***" : "";
259
+ url.password = url.password ? "***" : "";
260
+ return url.toString();
261
+ }
262
+ } catch {
263
+ }
264
+ return arg;
265
+ }
251
266
  async function execCommand(file, args, options = {}) {
252
- const displayCommand = options.label ?? [file, ...args].join(" ");
267
+ const displayCommand = options.label ?? [file, ...args.map(redactArg)].join(" ");
253
268
  if (options.dryRun) {
254
269
  info(`[DRY RUN] Would execute: ${displayCommand}`);
255
270
  return { stdout: "", stderr: "", exitCode: 0 };
@@ -305,7 +320,7 @@ function detectNpmAuth() {
305
320
  if (process.env.ACTIONS_ID_TOKEN_REQUEST_URL) {
306
321
  return "oidc";
307
322
  }
308
- if (process.env.NPM_TOKEN) {
323
+ if (process.env.NPM_TOKEN || process.env.NODE_AUTH_TOKEN) {
309
324
  return "token";
310
325
  }
311
326
  return null;
@@ -560,13 +575,17 @@ function topologicalSort(crates) {
560
575
  import * as path3 from "path";
561
576
  import { info as info2, success as success2 } from "@releasekit/core";
562
577
  async function runGitCommitStage(ctx) {
563
- const { input, cliOptions, cwd } = ctx;
578
+ const { input, config, cliOptions, cwd } = ctx;
564
579
  const dryRun = cliOptions.dryRun;
580
+ const skipHooks = config.git.skipHooks ?? false;
565
581
  if (!input.commitMessage) {
566
582
  info2("No commit message provided, skipping git commit");
567
583
  return;
568
584
  }
569
585
  const filePaths = input.updates.map((u) => path3.resolve(cwd, u.filePath));
586
+ if (ctx.additionalFiles) {
587
+ filePaths.push(...ctx.additionalFiles.map((f) => path3.resolve(cwd, f)));
588
+ }
570
589
  if (filePaths.length === 0) {
571
590
  info2("No files to commit");
572
591
  return;
@@ -583,8 +602,13 @@ async function runGitCommitStage(ctx) {
583
602
  `git add failed: ${error instanceof Error ? error.message : String(error)}`
584
603
  );
585
604
  }
605
+ const commitArgs = ["commit"];
606
+ if (skipHooks) {
607
+ commitArgs.push("--no-verify");
608
+ }
609
+ commitArgs.push("-m", input.commitMessage);
586
610
  try {
587
- await execCommand("git", ["commit", "-m", input.commitMessage], {
611
+ await execCommand("git", commitArgs, {
588
612
  cwd,
589
613
  dryRun,
590
614
  label: `git commit -m "${input.commitMessage}"`
@@ -622,6 +646,18 @@ async function runGitCommitStage(ctx) {
622
646
 
623
647
  // src/stages/git-push.ts
624
648
  import { info as info3, success as success3 } from "@releasekit/core";
649
+ function toGithubAuthedUrl(remoteUrl, token) {
650
+ try {
651
+ const url = new URL(remoteUrl);
652
+ if (url.protocol !== "https:") return void 0;
653
+ if (url.host !== "github.com") return void 0;
654
+ url.username = "x-access-token";
655
+ url.password = token;
656
+ return url.toString();
657
+ } catch {
658
+ return void 0;
659
+ }
660
+ }
625
661
  async function runGitPushStage(ctx) {
626
662
  const { config, cliOptions, cwd, output } = ctx;
627
663
  const dryRun = cliOptions.dryRun;
@@ -642,16 +678,26 @@ async function runGitPushStage(ctx) {
642
678
  pushMethod = "https";
643
679
  }
644
680
  }
681
+ const httpsTokenEnv = config.git.httpsTokenEnv;
682
+ const httpsToken = httpsTokenEnv ? process.env[httpsTokenEnv] : void 0;
645
683
  try {
684
+ let pushRemote = remote;
685
+ if (pushMethod === "https" && httpsToken) {
686
+ const remoteUrlResult = await execCommand("git", ["remote", "get-url", remote], { cwd, dryRun: false });
687
+ const authed = toGithubAuthedUrl(remoteUrlResult.stdout.trim(), httpsToken);
688
+ if (authed) {
689
+ pushRemote = authed;
690
+ }
691
+ }
646
692
  if (output.git.committed) {
647
- await execCommand("git", ["push", remote, branch], {
693
+ await execCommand("git", ["push", pushRemote, branch], {
648
694
  cwd,
649
695
  dryRun,
650
696
  label: `git push ${remote} ${branch}`
651
697
  });
652
698
  }
653
699
  if (output.git.tags.length > 0) {
654
- await execCommand("git", ["push", remote, "--tags"], {
700
+ await execCommand("git", ["push", pushRemote, "--tags"], {
655
701
  cwd,
656
702
  dryRun,
657
703
  label: `git push ${remote} --tags`
@@ -672,6 +718,62 @@ async function runGitPushStage(ctx) {
672
718
  // src/stages/github-release.ts
673
719
  import * as fs4 from "fs";
674
720
  import { debug as debug3, info as info4, success as success4, warn as warn2 } from "@releasekit/core";
721
+ function resolveNotes(notesSetting, tag, changelogs, pipelineNotes) {
722
+ if (notesSetting === "none") {
723
+ return { useGithubNotes: false };
724
+ }
725
+ if (notesSetting === "github") {
726
+ return { useGithubNotes: true };
727
+ }
728
+ if (notesSetting !== "auto") {
729
+ const body = readFileIfExists(notesSetting);
730
+ if (body) return { body, useGithubNotes: false };
731
+ debug3(`Notes file not found: ${notesSetting}, falling back to GitHub auto-notes`);
732
+ return { useGithubNotes: true };
733
+ }
734
+ if (pipelineNotes) {
735
+ const body = findNotesForTag(tag, pipelineNotes);
736
+ if (body) return { body, useGithubNotes: false };
737
+ }
738
+ const packageBody = formatChangelogForTag(tag, changelogs);
739
+ if (packageBody) {
740
+ return { body: packageBody, useGithubNotes: false };
741
+ }
742
+ return { useGithubNotes: true };
743
+ }
744
+ function isVersionOnlyTag(tag) {
745
+ return /^v?\d+\.\d+\.\d+/.test(tag);
746
+ }
747
+ function findNotesForTag(tag, notes) {
748
+ for (const [packageName, body] of Object.entries(notes)) {
749
+ if (tag.startsWith(`${packageName}@`) && body.trim()) {
750
+ return body;
751
+ }
752
+ }
753
+ const entries = Object.values(notes).filter((b) => b.trim());
754
+ if (entries.length === 1 && isVersionOnlyTag(tag)) return entries[0];
755
+ return void 0;
756
+ }
757
+ function readFileIfExists(filePath) {
758
+ try {
759
+ const content = fs4.readFileSync(filePath, "utf-8").trim();
760
+ return content || void 0;
761
+ } catch {
762
+ return void 0;
763
+ }
764
+ }
765
+ function formatChangelogForTag(tag, changelogs) {
766
+ if (changelogs.length === 0) return void 0;
767
+ const changelog = changelogs.find((c) => tag.startsWith(`${c.packageName}@`));
768
+ const target = changelog ?? (changelogs.length === 1 && isVersionOnlyTag(tag) ? changelogs[0] : void 0);
769
+ if (!target || target.entries.length === 0) return void 0;
770
+ const lines = [];
771
+ for (const entry of target.entries) {
772
+ const scope = entry.scope ? `**${entry.scope}:** ` : "";
773
+ lines.push(`- ${scope}${entry.description}`);
774
+ }
775
+ return lines.join("\n");
776
+ }
675
777
  async function runGithubReleaseStage(ctx) {
676
778
  const { config, cliOptions, output } = ctx;
677
779
  const dryRun = cliOptions.dryRun;
@@ -684,19 +786,13 @@ async function runGithubReleaseStage(ctx) {
684
786
  info4("No tags available for GitHub release");
685
787
  return;
686
788
  }
687
- let notesBody;
688
- if (config.githubRelease.notesFile) {
689
- try {
690
- notesBody = fs4.readFileSync(config.githubRelease.notesFile, "utf-8");
691
- } catch {
692
- debug3(`Could not read notes file: ${config.githubRelease.notesFile}`);
693
- }
694
- }
695
789
  const firstTag = tags[0];
696
790
  if (!firstTag) return;
697
791
  const tagsToRelease = config.githubRelease.perPackage ? tags : [firstTag];
698
792
  for (const tag of tagsToRelease) {
699
- const versionMatch = tag.match(/(\d+\.\d+\.\d+.*)$/);
793
+ const MAX_TAG_LENGTH = 1e3;
794
+ const truncatedTag = tag.length > MAX_TAG_LENGTH ? tag.slice(0, MAX_TAG_LENGTH) : tag;
795
+ const versionMatch = truncatedTag.match(/(\d{1,20}\.\d{1,20}\.\d{1,20}(?:[-+.]?[a-zA-Z0-9.-]{0,100})?)$/);
700
796
  const version = versionMatch?.[1] ?? "";
701
797
  const isPreRel = config.githubRelease.prerelease === "auto" ? version ? isPrerelease(version) : false : config.githubRelease.prerelease;
702
798
  const result = {
@@ -712,9 +808,15 @@ async function runGithubReleaseStage(ctx) {
712
808
  if (isPreRel) {
713
809
  ghArgs.push("--prerelease");
714
810
  }
715
- if (notesBody) {
716
- ghArgs.push("--notes", notesBody);
717
- } else if (config.githubRelease.generateNotes) {
811
+ const { body, useGithubNotes } = resolveNotes(
812
+ config.githubRelease.releaseNotes,
813
+ tag,
814
+ ctx.input.changelogs,
815
+ ctx.releaseNotes
816
+ );
817
+ if (body) {
818
+ ghArgs.push("--notes", body);
819
+ } else if (useGithubNotes) {
718
820
  ghArgs.push("--generate-notes");
719
821
  }
720
822
  try {
@@ -738,9 +840,77 @@ async function runGithubReleaseStage(ctx) {
738
840
  }
739
841
 
740
842
  // src/stages/npm-publish.ts
843
+ import * as fs6 from "fs";
844
+ import * as path5 from "path";
845
+ import { debug as debug5, info as info5, success as success5, warn as warn3 } from "@releasekit/core";
846
+
847
+ // src/utils/npm-env.ts
741
848
  import * as fs5 from "fs";
849
+ import * as os from "os";
742
850
  import * as path4 from "path";
743
- import { debug as debug4, info as info5, success as success5, warn as warn3 } from "@releasekit/core";
851
+ import { debug as debug4 } from "@releasekit/core";
852
+ function writeTempNpmrc(contents) {
853
+ const dir = fs5.mkdtempSync(path4.join(os.tmpdir(), "releasekit-npmrc-"));
854
+ const npmrcPath = path4.join(dir, ".npmrc");
855
+ fs5.writeFileSync(npmrcPath, contents, "utf-8");
856
+ return {
857
+ npmrcPath,
858
+ cleanup: () => {
859
+ try {
860
+ fs5.rmSync(dir, { recursive: true, force: true });
861
+ } catch {
862
+ }
863
+ }
864
+ };
865
+ }
866
+ function createNpmSubprocessIsolation(options) {
867
+ const { authMethod, registryUrl } = options;
868
+ const baseEnv = {};
869
+ if (!authMethod) return { env: baseEnv, cleanup: () => {
870
+ } };
871
+ const token = process.env.NPM_TOKEN ?? process.env.NODE_AUTH_TOKEN;
872
+ const registryHost = (() => {
873
+ try {
874
+ return new URL(registryUrl).host;
875
+ } catch {
876
+ return "registry.npmjs.org";
877
+ }
878
+ })();
879
+ const lines = [`registry=${registryUrl}`];
880
+ if (authMethod === "oidc") {
881
+ lines.push("always-auth=false");
882
+ }
883
+ if (authMethod === "token" && token) {
884
+ lines.push(`//${registryHost}/:_authToken=${token}`);
885
+ }
886
+ lines.push("");
887
+ const { npmrcPath, cleanup } = writeTempNpmrc(lines.join("\n"));
888
+ debug4(`Using isolated npm userconfig: ${npmrcPath}`);
889
+ const isOidc = authMethod === "oidc";
890
+ return {
891
+ env: {
892
+ ...baseEnv,
893
+ // Ensure npm and tools that read npm_config_* pick up our temp file
894
+ NPM_CONFIG_USERCONFIG: npmrcPath,
895
+ npm_config_userconfig: npmrcPath,
896
+ // Auth-specific hardening
897
+ ...isOidc ? {
898
+ // Prevent setup-node's always-auth from forcing token lookups
899
+ NPM_CONFIG_ALWAYS_AUTH: "false",
900
+ npm_config_always_auth: "false",
901
+ // Explicitly prevent token-based publishing from being selected implicitly
902
+ NODE_AUTH_TOKEN: void 0,
903
+ NPM_TOKEN: void 0
904
+ } : {
905
+ // Ensure CLIs that expect NODE_AUTH_TOKEN can still work
906
+ NODE_AUTH_TOKEN: token
907
+ }
908
+ },
909
+ cleanup
910
+ };
911
+ }
912
+
913
+ // src/stages/npm-publish.ts
744
914
  async function runNpmPublishStage(ctx) {
745
915
  const { input, config, cliOptions, cwd } = ctx;
746
916
  const dryRun = cliOptions.dryRun;
@@ -753,98 +923,108 @@ async function runNpmPublishStage(ctx) {
753
923
  throw createPublishError("NPM_AUTH_ERROR" /* NPM_AUTH_ERROR */, "No NPM authentication method detected");
754
924
  }
755
925
  const useProvenance = config.npm.provenance && authMethod === "oidc";
756
- for (const update of input.updates) {
757
- const result = {
758
- packageName: update.packageName,
759
- version: update.newVersion,
760
- registry: "npm",
761
- success: false,
762
- skipped: false
763
- };
764
- const pkgJsonPath = path4.resolve(cwd, update.filePath);
765
- try {
766
- const pkgContent = fs5.readFileSync(pkgJsonPath, "utf-8");
767
- const pkgJson = JSON.parse(pkgContent);
768
- if (pkgJson.private) {
769
- result.skipped = true;
770
- result.success = true;
771
- result.reason = "Package is private";
772
- ctx.output.npm.push(result);
773
- debug4(`Skipping private package: ${update.packageName}`);
774
- continue;
926
+ const npmIsolation = createNpmSubprocessIsolation({
927
+ authMethod,
928
+ registryUrl: config.npm.registry
929
+ });
930
+ try {
931
+ for (const update of input.updates) {
932
+ const result = {
933
+ packageName: update.packageName,
934
+ version: update.newVersion,
935
+ registry: "npm",
936
+ success: false,
937
+ skipped: false
938
+ };
939
+ const pkgJsonPath = path5.resolve(cwd, update.filePath);
940
+ try {
941
+ const pkgContent = fs6.readFileSync(pkgJsonPath, "utf-8");
942
+ const pkgJson = JSON.parse(pkgContent);
943
+ if (pkgJson.private) {
944
+ result.skipped = true;
945
+ result.success = true;
946
+ result.reason = "Package is private";
947
+ ctx.output.npm.push(result);
948
+ debug5(`Skipping private package: ${update.packageName}`);
949
+ continue;
950
+ }
951
+ } catch {
952
+ if (update.filePath.endsWith("Cargo.toml")) {
953
+ result.skipped = true;
954
+ result.success = true;
955
+ result.reason = "Not an npm package";
956
+ ctx.output.npm.push(result);
957
+ continue;
958
+ }
775
959
  }
776
- } catch {
777
- if (update.filePath.endsWith("Cargo.toml")) {
960
+ const { file: viewFile, args: viewArgs } = buildViewCommand(
961
+ ctx.packageManager,
962
+ update.packageName,
963
+ update.newVersion
964
+ );
965
+ const viewResult = await execCommandSafe(viewFile, viewArgs, {
966
+ cwd,
967
+ dryRun: false,
968
+ // Always check, even in dry-run
969
+ env: npmIsolation.env
970
+ });
971
+ if (viewResult.exitCode === 0 && viewResult.stdout.trim()) {
972
+ result.alreadyPublished = true;
778
973
  result.skipped = true;
779
974
  result.success = true;
780
- result.reason = "Not an npm package";
975
+ result.reason = "Already published";
781
976
  ctx.output.npm.push(result);
977
+ warn3(`${update.packageName}@${update.newVersion} is already published, skipping`);
782
978
  continue;
783
979
  }
784
- }
785
- const { file: viewFile, args: viewArgs } = buildViewCommand(
786
- ctx.packageManager,
787
- update.packageName,
788
- update.newVersion
789
- );
790
- const viewResult = await execCommandSafe(viewFile, viewArgs, {
791
- cwd,
792
- dryRun: false
793
- // Always check, even in dry-run
794
- });
795
- if (viewResult.exitCode === 0 && viewResult.stdout.trim()) {
796
- result.alreadyPublished = true;
797
- result.skipped = true;
798
- result.success = true;
799
- result.reason = "Already published";
800
- ctx.output.npm.push(result);
801
- warn3(`${update.packageName}@${update.newVersion} is already published, skipping`);
802
- continue;
803
- }
804
- const distTag = getDistTag(update.newVersion, config.npm.tag);
805
- const pkgDir = path4.dirname(path4.resolve(cwd, update.filePath));
806
- const { file: pubFile, args: pubArgs } = buildPublishCommand(ctx.packageManager, update.packageName, pkgDir, {
807
- access: config.npm.access,
808
- tag: distTag,
809
- provenance: useProvenance,
810
- noGitChecks: true
811
- });
812
- try {
813
- await execCommand(pubFile, pubArgs, {
814
- cwd,
815
- dryRun,
816
- label: `npm publish ${update.packageName}@${update.newVersion}`
980
+ const distTag = getDistTag(update.newVersion, config.npm.tag);
981
+ const pkgDir = path5.dirname(path5.resolve(cwd, update.filePath));
982
+ const { file: pubFile, args: pubArgs } = buildPublishCommand(ctx.packageManager, update.packageName, pkgDir, {
983
+ access: config.npm.access,
984
+ tag: distTag,
985
+ provenance: useProvenance,
986
+ noGitChecks: true
817
987
  });
818
- result.success = true;
819
- if (!dryRun) {
820
- success5(`Published ${update.packageName}@${update.newVersion} to npm`);
988
+ try {
989
+ await execCommand(pubFile, pubArgs, {
990
+ cwd,
991
+ dryRun,
992
+ label: `npm publish ${update.packageName}@${update.newVersion}`,
993
+ env: npmIsolation.env
994
+ });
995
+ result.success = true;
996
+ if (!dryRun) {
997
+ success5(`Published ${update.packageName}@${update.newVersion} to npm`);
998
+ }
999
+ } catch (error) {
1000
+ result.reason = error instanceof Error ? error.message : String(error);
1001
+ warn3(`Failed to publish ${update.packageName}: ${result.reason}`);
821
1002
  }
822
- } catch (error) {
823
- result.reason = error instanceof Error ? error.message : String(error);
824
- warn3(`Failed to publish ${update.packageName}: ${result.reason}`);
1003
+ ctx.output.npm.push(result);
825
1004
  }
826
- ctx.output.npm.push(result);
1005
+ } finally {
1006
+ npmIsolation.cleanup();
827
1007
  }
828
1008
  }
829
1009
 
830
1010
  // src/stages/prepare.ts
831
- import * as fs6 from "fs";
832
- import * as path5 from "path";
833
- import { debug as debug5, info as info6 } from "@releasekit/core";
1011
+ import * as fs7 from "fs";
1012
+ import * as path6 from "path";
1013
+ import { debug as debug6, info as info6 } from "@releasekit/core";
834
1014
  async function runPrepareStage(ctx) {
835
1015
  const { input, config, cliOptions, cwd } = ctx;
836
1016
  if (config.npm.enabled && config.npm.copyFiles.length > 0) {
837
1017
  for (const update of input.updates) {
838
- const pkgDir = path5.dirname(path5.resolve(cwd, update.filePath));
1018
+ const pkgDir = path6.dirname(path6.resolve(cwd, update.filePath));
839
1019
  for (const file of config.npm.copyFiles) {
840
- const src = path5.resolve(cwd, file);
841
- const dest = path5.join(pkgDir, file);
842
- if (!fs6.existsSync(src)) {
843
- debug5(`Source file not found, skipping copy: ${src}`);
1020
+ const src = path6.resolve(cwd, file);
1021
+ const dest = path6.join(pkgDir, file);
1022
+ if (!fs7.existsSync(src)) {
1023
+ debug6(`Source file not found, skipping copy: ${src}`);
844
1024
  continue;
845
1025
  }
846
- if (path5.resolve(path5.dirname(src)) === path5.resolve(pkgDir)) {
847
- debug5(`Skipping copy of ${file} - same directory as source`);
1026
+ if (path6.resolve(path6.dirname(src)) === path6.resolve(pkgDir)) {
1027
+ debug6(`Skipping copy of ${file} - same directory as source`);
848
1028
  continue;
849
1029
  }
850
1030
  if (cliOptions.dryRun) {
@@ -852,8 +1032,8 @@ async function runPrepareStage(ctx) {
852
1032
  continue;
853
1033
  }
854
1034
  try {
855
- fs6.copyFileSync(src, dest);
856
- debug5(`Copied ${file} \u2192 ${pkgDir}`);
1035
+ fs7.copyFileSync(src, dest);
1036
+ debug6(`Copied ${file} \u2192 ${pkgDir}`);
857
1037
  } catch (error) {
858
1038
  throw createPublishError(
859
1039
  "FILE_COPY_ERROR" /* FILE_COPY_ERROR */,
@@ -865,9 +1045,9 @@ async function runPrepareStage(ctx) {
865
1045
  }
866
1046
  if (config.cargo.enabled) {
867
1047
  for (const update of input.updates) {
868
- const pkgDir = path5.dirname(path5.resolve(cwd, update.filePath));
869
- const cargoPath = path5.join(pkgDir, "Cargo.toml");
870
- if (!fs6.existsSync(cargoPath)) {
1048
+ const pkgDir = path6.dirname(path6.resolve(cwd, update.filePath));
1049
+ const cargoPath = path6.join(pkgDir, "Cargo.toml");
1050
+ if (!fs7.existsSync(cargoPath)) {
871
1051
  continue;
872
1052
  }
873
1053
  if (cliOptions.dryRun) {
@@ -875,16 +1055,16 @@ async function runPrepareStage(ctx) {
875
1055
  continue;
876
1056
  }
877
1057
  updateCargoVersion(cargoPath, update.newVersion);
878
- debug5(`Updated ${cargoPath} to version ${update.newVersion}`);
1058
+ debug6(`Updated ${cargoPath} to version ${update.newVersion}`);
879
1059
  }
880
1060
  }
881
1061
  }
882
1062
 
883
1063
  // src/stages/verify.ts
884
- import { debug as debug7, info as info7, success as success6, warn as warn4 } from "@releasekit/core";
1064
+ import { debug as debug8, info as info7, success as success6, warn as warn4 } from "@releasekit/core";
885
1065
 
886
1066
  // src/utils/retry.ts
887
- import { debug as debug6 } from "@releasekit/core";
1067
+ import { debug as debug7 } from "@releasekit/core";
888
1068
  async function withRetry(fn, options, shouldRetry) {
889
1069
  let lastError;
890
1070
  let delay = options.initialDelay;
@@ -897,7 +1077,7 @@ async function withRetry(fn, options, shouldRetry) {
897
1077
  throw error;
898
1078
  }
899
1079
  if (attempt < options.maxAttempts) {
900
- debug6(`Attempt ${attempt}/${options.maxAttempts} failed, retrying in ${delay}ms...`);
1080
+ debug7(`Attempt ${attempt}/${options.maxAttempts} failed, retrying in ${delay}ms...`);
901
1081
  await sleep(delay);
902
1082
  delay = Math.floor(delay * options.backoffMultiplier);
903
1083
  }
@@ -939,7 +1119,7 @@ async function runVerifyStage(ctx) {
939
1119
  if (viewResult.exitCode !== 0 || !viewResult.stdout.trim()) {
940
1120
  throw new Error(`${pkg.packageName}@${pkg.version} not yet available on npm`);
941
1121
  }
942
- debug7(`Verified ${pkg.packageName}@${pkg.version} on npm`);
1122
+ debug8(`Verified ${pkg.packageName}@${pkg.version} on npm`);
943
1123
  }, config.verify.npm);
944
1124
  result.verified = true;
945
1125
  success6(`Verified ${pkg.packageName}@${pkg.version} on npm`);
@@ -972,7 +1152,7 @@ async function runVerifyStage(ctx) {
972
1152
  if (!response.ok) {
973
1153
  throw new Error(`${crate.packageName}@${crate.version} not yet available on crates.io`);
974
1154
  }
975
- debug7(`Verified ${crate.packageName}@${crate.version} on crates.io`);
1155
+ debug8(`Verified ${crate.packageName}@${crate.version} on crates.io`);
976
1156
  }, config.verify.cargo);
977
1157
  result.verified = true;
978
1158
  success6(`Verified ${crate.packageName}@${crate.version} on crates.io`);
@@ -1012,6 +1192,8 @@ async function runPipeline(input, config, options) {
1012
1192
  cliOptions: options,
1013
1193
  packageManager: detectPackageManager(cwd),
1014
1194
  cwd,
1195
+ releaseNotes: options.releaseNotes,
1196
+ additionalFiles: options.additionalFiles,
1015
1197
  output: {
1016
1198
  dryRun: options.dryRun,
1017
1199
  git: { committed: false, tags: [], pushed: false },
@@ -1023,7 +1205,10 @@ async function runPipeline(input, config, options) {
1023
1205
  };
1024
1206
  try {
1025
1207
  await runPrepareStage(ctx);
1026
- if (!options.skipGit) {
1208
+ if (options.skipGitCommit && !options.skipGit) {
1209
+ ctx.output.git.committed = !!input.commitMessage;
1210
+ ctx.output.git.tags = [...input.tags];
1211
+ } else if (!options.skipGit) {
1027
1212
  await runGitCommitStage(ctx);
1028
1213
  }
1029
1214
  if (!options.skipPublish) {
@@ -1052,7 +1237,7 @@ async function runPipeline(input, config, options) {
1052
1237
  }
1053
1238
 
1054
1239
  // src/stages/input.ts
1055
- import * as fs7 from "fs";
1240
+ import * as fs8 from "fs";
1056
1241
  import { info as info8 } from "@releasekit/core";
1057
1242
  import { z } from "zod";
1058
1243
  var VersionChangelogEntrySchema = z.object({
@@ -1086,7 +1271,7 @@ async function parseInput(inputPath) {
1086
1271
  let raw;
1087
1272
  if (inputPath) {
1088
1273
  try {
1089
- raw = fs7.readFileSync(inputPath, "utf-8");
1274
+ raw = fs8.readFileSync(inputPath, "utf-8");
1090
1275
  } catch {
1091
1276
  throw createPublishError("INPUT_PARSE_ERROR" /* INPUT_PARSE_ERROR */, `Could not read file: ${inputPath}`);
1092
1277
  }