@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/dist/index.cjs CHANGED
@@ -75,14 +75,16 @@ function getDefaultConfig() {
75
75
  push: true,
76
76
  pushMethod: "auto",
77
77
  remote: "origin",
78
- branch: "main"
78
+ branch: "main",
79
+ httpsTokenEnv: void 0,
80
+ skipHooks: false
79
81
  },
80
82
  githubRelease: {
81
83
  enabled: true,
82
84
  draft: true,
83
- generateNotes: true,
84
- perPackage: false,
85
- prerelease: "auto"
85
+ perPackage: true,
86
+ prerelease: "auto",
87
+ releaseNotes: "auto"
86
88
  },
87
89
  verify: {
88
90
  npm: {
@@ -123,15 +125,16 @@ function toPublishConfig(config) {
123
125
  push: config.git.push ?? defaults.git.push,
124
126
  pushMethod: config.git.pushMethod ?? defaults.git.pushMethod,
125
127
  remote: config.git.remote ?? defaults.git.remote,
126
- branch: config.git.branch ?? defaults.git.branch
128
+ branch: config.git.branch ?? defaults.git.branch,
129
+ httpsTokenEnv: config.git.httpsTokenEnv ?? defaults.git.httpsTokenEnv,
130
+ skipHooks: config.git.skipHooks ?? defaults.git.skipHooks
127
131
  } : defaults.git,
128
132
  githubRelease: {
129
133
  enabled: config.githubRelease?.enabled ?? defaults.githubRelease.enabled,
130
134
  draft: config.githubRelease?.draft ?? defaults.githubRelease.draft,
131
- generateNotes: config.githubRelease?.generateNotes ?? defaults.githubRelease.generateNotes,
132
135
  perPackage: config.githubRelease?.perPackage ?? defaults.githubRelease.perPackage,
133
136
  prerelease: config.githubRelease?.prerelease ?? defaults.githubRelease.prerelease,
134
- notesFile: config.githubRelease?.notesFile
137
+ releaseNotes: config.githubRelease?.releaseNotes ?? defaults.githubRelease.releaseNotes
135
138
  },
136
139
  verify: {
137
140
  npm: {
@@ -305,8 +308,20 @@ var import_core3 = require("@releasekit/core");
305
308
  // src/utils/exec.ts
306
309
  var import_node_child_process = require("child_process");
307
310
  var import_core2 = require("@releasekit/core");
311
+ function redactArg(arg) {
312
+ try {
313
+ const url = new URL(arg);
314
+ if (url.username || url.password) {
315
+ url.username = url.username ? "***" : "";
316
+ url.password = url.password ? "***" : "";
317
+ return url.toString();
318
+ }
319
+ } catch {
320
+ }
321
+ return arg;
322
+ }
308
323
  async function execCommand(file, args, options = {}) {
309
- const displayCommand = options.label ?? [file, ...args].join(" ");
324
+ const displayCommand = options.label ?? [file, ...args.map(redactArg)].join(" ");
310
325
  if (options.dryRun) {
311
326
  (0, import_core2.info)(`[DRY RUN] Would execute: ${displayCommand}`);
312
327
  return { stdout: "", stderr: "", exitCode: 0 };
@@ -362,7 +377,7 @@ function detectNpmAuth() {
362
377
  if (process.env.ACTIONS_ID_TOKEN_REQUEST_URL) {
363
378
  return "oidc";
364
379
  }
365
- if (process.env.NPM_TOKEN) {
380
+ if (process.env.NPM_TOKEN || process.env.NODE_AUTH_TOKEN) {
366
381
  return "token";
367
382
  }
368
383
  return null;
@@ -571,13 +586,17 @@ function topologicalSort(crates) {
571
586
  var path2 = __toESM(require("path"), 1);
572
587
  var import_core4 = require("@releasekit/core");
573
588
  async function runGitCommitStage(ctx) {
574
- const { input, cliOptions, cwd } = ctx;
589
+ const { input, config, cliOptions, cwd } = ctx;
575
590
  const dryRun = cliOptions.dryRun;
591
+ const skipHooks = config.git.skipHooks ?? false;
576
592
  if (!input.commitMessage) {
577
593
  (0, import_core4.info)("No commit message provided, skipping git commit");
578
594
  return;
579
595
  }
580
596
  const filePaths = input.updates.map((u) => path2.resolve(cwd, u.filePath));
597
+ if (ctx.additionalFiles) {
598
+ filePaths.push(...ctx.additionalFiles.map((f) => path2.resolve(cwd, f)));
599
+ }
581
600
  if (filePaths.length === 0) {
582
601
  (0, import_core4.info)("No files to commit");
583
602
  return;
@@ -594,8 +613,13 @@ async function runGitCommitStage(ctx) {
594
613
  `git add failed: ${error instanceof Error ? error.message : String(error)}`
595
614
  );
596
615
  }
616
+ const commitArgs = ["commit"];
617
+ if (skipHooks) {
618
+ commitArgs.push("--no-verify");
619
+ }
620
+ commitArgs.push("-m", input.commitMessage);
597
621
  try {
598
- await execCommand("git", ["commit", "-m", input.commitMessage], {
622
+ await execCommand("git", commitArgs, {
599
623
  cwd,
600
624
  dryRun,
601
625
  label: `git commit -m "${input.commitMessage}"`
@@ -633,6 +657,18 @@ async function runGitCommitStage(ctx) {
633
657
 
634
658
  // src/stages/git-push.ts
635
659
  var import_core5 = require("@releasekit/core");
660
+ function toGithubAuthedUrl(remoteUrl, token) {
661
+ try {
662
+ const url = new URL(remoteUrl);
663
+ if (url.protocol !== "https:") return void 0;
664
+ if (url.host !== "github.com") return void 0;
665
+ url.username = "x-access-token";
666
+ url.password = token;
667
+ return url.toString();
668
+ } catch {
669
+ return void 0;
670
+ }
671
+ }
636
672
  async function runGitPushStage(ctx) {
637
673
  const { config, cliOptions, cwd, output } = ctx;
638
674
  const dryRun = cliOptions.dryRun;
@@ -653,16 +689,26 @@ async function runGitPushStage(ctx) {
653
689
  pushMethod = "https";
654
690
  }
655
691
  }
692
+ const httpsTokenEnv = config.git.httpsTokenEnv;
693
+ const httpsToken = httpsTokenEnv ? process.env[httpsTokenEnv] : void 0;
656
694
  try {
695
+ let pushRemote = remote;
696
+ if (pushMethod === "https" && httpsToken) {
697
+ const remoteUrlResult = await execCommand("git", ["remote", "get-url", remote], { cwd, dryRun: false });
698
+ const authed = toGithubAuthedUrl(remoteUrlResult.stdout.trim(), httpsToken);
699
+ if (authed) {
700
+ pushRemote = authed;
701
+ }
702
+ }
657
703
  if (output.git.committed) {
658
- await execCommand("git", ["push", remote, branch], {
704
+ await execCommand("git", ["push", pushRemote, branch], {
659
705
  cwd,
660
706
  dryRun,
661
707
  label: `git push ${remote} ${branch}`
662
708
  });
663
709
  }
664
710
  if (output.git.tags.length > 0) {
665
- await execCommand("git", ["push", remote, "--tags"], {
711
+ await execCommand("git", ["push", pushRemote, "--tags"], {
666
712
  cwd,
667
713
  dryRun,
668
714
  label: `git push ${remote} --tags`
@@ -699,6 +745,62 @@ function getDistTag(version, defaultTag = "latest") {
699
745
  }
700
746
 
701
747
  // src/stages/github-release.ts
748
+ function resolveNotes(notesSetting, tag, changelogs, pipelineNotes) {
749
+ if (notesSetting === "none") {
750
+ return { useGithubNotes: false };
751
+ }
752
+ if (notesSetting === "github") {
753
+ return { useGithubNotes: true };
754
+ }
755
+ if (notesSetting !== "auto") {
756
+ const body = readFileIfExists(notesSetting);
757
+ if (body) return { body, useGithubNotes: false };
758
+ (0, import_core6.debug)(`Notes file not found: ${notesSetting}, falling back to GitHub auto-notes`);
759
+ return { useGithubNotes: true };
760
+ }
761
+ if (pipelineNotes) {
762
+ const body = findNotesForTag(tag, pipelineNotes);
763
+ if (body) return { body, useGithubNotes: false };
764
+ }
765
+ const packageBody = formatChangelogForTag(tag, changelogs);
766
+ if (packageBody) {
767
+ return { body: packageBody, useGithubNotes: false };
768
+ }
769
+ return { useGithubNotes: true };
770
+ }
771
+ function isVersionOnlyTag(tag) {
772
+ return /^v?\d+\.\d+\.\d+/.test(tag);
773
+ }
774
+ function findNotesForTag(tag, notes) {
775
+ for (const [packageName, body] of Object.entries(notes)) {
776
+ if (tag.startsWith(`${packageName}@`) && body.trim()) {
777
+ return body;
778
+ }
779
+ }
780
+ const entries = Object.values(notes).filter((b) => b.trim());
781
+ if (entries.length === 1 && isVersionOnlyTag(tag)) return entries[0];
782
+ return void 0;
783
+ }
784
+ function readFileIfExists(filePath) {
785
+ try {
786
+ const content = fs3.readFileSync(filePath, "utf-8").trim();
787
+ return content || void 0;
788
+ } catch {
789
+ return void 0;
790
+ }
791
+ }
792
+ function formatChangelogForTag(tag, changelogs) {
793
+ if (changelogs.length === 0) return void 0;
794
+ const changelog = changelogs.find((c) => tag.startsWith(`${c.packageName}@`));
795
+ const target = changelog ?? (changelogs.length === 1 && isVersionOnlyTag(tag) ? changelogs[0] : void 0);
796
+ if (!target || target.entries.length === 0) return void 0;
797
+ const lines = [];
798
+ for (const entry of target.entries) {
799
+ const scope = entry.scope ? `**${entry.scope}:** ` : "";
800
+ lines.push(`- ${scope}${entry.description}`);
801
+ }
802
+ return lines.join("\n");
803
+ }
702
804
  async function runGithubReleaseStage(ctx) {
703
805
  const { config, cliOptions, output } = ctx;
704
806
  const dryRun = cliOptions.dryRun;
@@ -711,19 +813,13 @@ async function runGithubReleaseStage(ctx) {
711
813
  (0, import_core6.info)("No tags available for GitHub release");
712
814
  return;
713
815
  }
714
- let notesBody;
715
- if (config.githubRelease.notesFile) {
716
- try {
717
- notesBody = fs3.readFileSync(config.githubRelease.notesFile, "utf-8");
718
- } catch {
719
- (0, import_core6.debug)(`Could not read notes file: ${config.githubRelease.notesFile}`);
720
- }
721
- }
722
816
  const firstTag = tags[0];
723
817
  if (!firstTag) return;
724
818
  const tagsToRelease = config.githubRelease.perPackage ? tags : [firstTag];
725
819
  for (const tag of tagsToRelease) {
726
- const versionMatch = tag.match(/(\d+\.\d+\.\d+.*)$/);
820
+ const MAX_TAG_LENGTH = 1e3;
821
+ const truncatedTag = tag.length > MAX_TAG_LENGTH ? tag.slice(0, MAX_TAG_LENGTH) : tag;
822
+ const versionMatch = truncatedTag.match(/(\d{1,20}\.\d{1,20}\.\d{1,20}(?:[-+.]?[a-zA-Z0-9.-]{0,100})?)$/);
727
823
  const version = versionMatch?.[1] ?? "";
728
824
  const isPreRel = config.githubRelease.prerelease === "auto" ? version ? isPrerelease(version) : false : config.githubRelease.prerelease;
729
825
  const result = {
@@ -739,9 +835,15 @@ async function runGithubReleaseStage(ctx) {
739
835
  if (isPreRel) {
740
836
  ghArgs.push("--prerelease");
741
837
  }
742
- if (notesBody) {
743
- ghArgs.push("--notes", notesBody);
744
- } else if (config.githubRelease.generateNotes) {
838
+ const { body, useGithubNotes } = resolveNotes(
839
+ config.githubRelease.releaseNotes,
840
+ tag,
841
+ ctx.input.changelogs,
842
+ ctx.releaseNotes
843
+ );
844
+ if (body) {
845
+ ghArgs.push("--notes", body);
846
+ } else if (useGithubNotes) {
745
847
  ghArgs.push("--generate-notes");
746
848
  }
747
849
  try {
@@ -765,16 +867,82 @@ async function runGithubReleaseStage(ctx) {
765
867
  }
766
868
 
767
869
  // src/stages/npm-publish.ts
768
- var fs5 = __toESM(require("fs"), 1);
769
- var path4 = __toESM(require("path"), 1);
770
- var import_core7 = require("@releasekit/core");
870
+ var fs6 = __toESM(require("fs"), 1);
871
+ var path5 = __toESM(require("path"), 1);
872
+ var import_core8 = require("@releasekit/core");
771
873
 
772
- // src/utils/package-manager.ts
874
+ // src/utils/npm-env.ts
773
875
  var fs4 = __toESM(require("fs"), 1);
876
+ var os = __toESM(require("os"), 1);
774
877
  var path3 = __toESM(require("path"), 1);
878
+ var import_core7 = require("@releasekit/core");
879
+ function writeTempNpmrc(contents) {
880
+ const dir = fs4.mkdtempSync(path3.join(os.tmpdir(), "releasekit-npmrc-"));
881
+ const npmrcPath = path3.join(dir, ".npmrc");
882
+ fs4.writeFileSync(npmrcPath, contents, "utf-8");
883
+ return {
884
+ npmrcPath,
885
+ cleanup: () => {
886
+ try {
887
+ fs4.rmSync(dir, { recursive: true, force: true });
888
+ } catch {
889
+ }
890
+ }
891
+ };
892
+ }
893
+ function createNpmSubprocessIsolation(options) {
894
+ const { authMethod, registryUrl } = options;
895
+ const baseEnv = {};
896
+ if (!authMethod) return { env: baseEnv, cleanup: () => {
897
+ } };
898
+ const token = process.env.NPM_TOKEN ?? process.env.NODE_AUTH_TOKEN;
899
+ const registryHost = (() => {
900
+ try {
901
+ return new URL(registryUrl).host;
902
+ } catch {
903
+ return "registry.npmjs.org";
904
+ }
905
+ })();
906
+ const lines = [`registry=${registryUrl}`];
907
+ if (authMethod === "oidc") {
908
+ lines.push("always-auth=false");
909
+ }
910
+ if (authMethod === "token" && token) {
911
+ lines.push(`//${registryHost}/:_authToken=${token}`);
912
+ }
913
+ lines.push("");
914
+ const { npmrcPath, cleanup } = writeTempNpmrc(lines.join("\n"));
915
+ (0, import_core7.debug)(`Using isolated npm userconfig: ${npmrcPath}`);
916
+ const isOidc = authMethod === "oidc";
917
+ return {
918
+ env: {
919
+ ...baseEnv,
920
+ // Ensure npm and tools that read npm_config_* pick up our temp file
921
+ NPM_CONFIG_USERCONFIG: npmrcPath,
922
+ npm_config_userconfig: npmrcPath,
923
+ // Auth-specific hardening
924
+ ...isOidc ? {
925
+ // Prevent setup-node's always-auth from forcing token lookups
926
+ NPM_CONFIG_ALWAYS_AUTH: "false",
927
+ npm_config_always_auth: "false",
928
+ // Explicitly prevent token-based publishing from being selected implicitly
929
+ NODE_AUTH_TOKEN: void 0,
930
+ NPM_TOKEN: void 0
931
+ } : {
932
+ // Ensure CLIs that expect NODE_AUTH_TOKEN can still work
933
+ NODE_AUTH_TOKEN: token
934
+ }
935
+ },
936
+ cleanup
937
+ };
938
+ }
939
+
940
+ // src/utils/package-manager.ts
941
+ var fs5 = __toESM(require("fs"), 1);
942
+ var path4 = __toESM(require("path"), 1);
775
943
  function detectPackageManager(cwd) {
776
- if (fs4.existsSync(path3.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
777
- if (fs4.existsSync(path3.join(cwd, "yarn.lock"))) return "yarn";
944
+ if (fs5.existsSync(path4.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
945
+ if (fs5.existsSync(path4.join(cwd, "yarn.lock"))) return "yarn";
778
946
  return "npm";
779
947
  }
780
948
  function buildPublishCommand(pm, packageName, _packageDir, options) {
@@ -803,7 +971,7 @@ async function runNpmPublishStage(ctx) {
803
971
  const { input, config, cliOptions, cwd } = ctx;
804
972
  const dryRun = cliOptions.dryRun;
805
973
  if (!config.npm.enabled) {
806
- (0, import_core7.info)("NPM publishing disabled in config");
974
+ (0, import_core8.info)("NPM publishing disabled in config");
807
975
  return;
808
976
  }
809
977
  const authMethod = config.npm.auth === "auto" ? detectNpmAuth() : config.npm.auth;
@@ -811,107 +979,117 @@ async function runNpmPublishStage(ctx) {
811
979
  throw createPublishError("NPM_AUTH_ERROR" /* NPM_AUTH_ERROR */, "No NPM authentication method detected");
812
980
  }
813
981
  const useProvenance = config.npm.provenance && authMethod === "oidc";
814
- for (const update of input.updates) {
815
- const result = {
816
- packageName: update.packageName,
817
- version: update.newVersion,
818
- registry: "npm",
819
- success: false,
820
- skipped: false
821
- };
822
- const pkgJsonPath = path4.resolve(cwd, update.filePath);
823
- try {
824
- const pkgContent = fs5.readFileSync(pkgJsonPath, "utf-8");
825
- const pkgJson = JSON.parse(pkgContent);
826
- if (pkgJson.private) {
827
- result.skipped = true;
828
- result.success = true;
829
- result.reason = "Package is private";
830
- ctx.output.npm.push(result);
831
- (0, import_core7.debug)(`Skipping private package: ${update.packageName}`);
832
- continue;
982
+ const npmIsolation = createNpmSubprocessIsolation({
983
+ authMethod,
984
+ registryUrl: config.npm.registry
985
+ });
986
+ try {
987
+ for (const update of input.updates) {
988
+ const result = {
989
+ packageName: update.packageName,
990
+ version: update.newVersion,
991
+ registry: "npm",
992
+ success: false,
993
+ skipped: false
994
+ };
995
+ const pkgJsonPath = path5.resolve(cwd, update.filePath);
996
+ try {
997
+ const pkgContent = fs6.readFileSync(pkgJsonPath, "utf-8");
998
+ const pkgJson = JSON.parse(pkgContent);
999
+ if (pkgJson.private) {
1000
+ result.skipped = true;
1001
+ result.success = true;
1002
+ result.reason = "Package is private";
1003
+ ctx.output.npm.push(result);
1004
+ (0, import_core8.debug)(`Skipping private package: ${update.packageName}`);
1005
+ continue;
1006
+ }
1007
+ } catch {
1008
+ if (update.filePath.endsWith("Cargo.toml")) {
1009
+ result.skipped = true;
1010
+ result.success = true;
1011
+ result.reason = "Not an npm package";
1012
+ ctx.output.npm.push(result);
1013
+ continue;
1014
+ }
833
1015
  }
834
- } catch {
835
- if (update.filePath.endsWith("Cargo.toml")) {
1016
+ const { file: viewFile, args: viewArgs } = buildViewCommand(
1017
+ ctx.packageManager,
1018
+ update.packageName,
1019
+ update.newVersion
1020
+ );
1021
+ const viewResult = await execCommandSafe(viewFile, viewArgs, {
1022
+ cwd,
1023
+ dryRun: false,
1024
+ // Always check, even in dry-run
1025
+ env: npmIsolation.env
1026
+ });
1027
+ if (viewResult.exitCode === 0 && viewResult.stdout.trim()) {
1028
+ result.alreadyPublished = true;
836
1029
  result.skipped = true;
837
1030
  result.success = true;
838
- result.reason = "Not an npm package";
1031
+ result.reason = "Already published";
839
1032
  ctx.output.npm.push(result);
1033
+ (0, import_core8.warn)(`${update.packageName}@${update.newVersion} is already published, skipping`);
840
1034
  continue;
841
1035
  }
842
- }
843
- const { file: viewFile, args: viewArgs } = buildViewCommand(
844
- ctx.packageManager,
845
- update.packageName,
846
- update.newVersion
847
- );
848
- const viewResult = await execCommandSafe(viewFile, viewArgs, {
849
- cwd,
850
- dryRun: false
851
- // Always check, even in dry-run
852
- });
853
- if (viewResult.exitCode === 0 && viewResult.stdout.trim()) {
854
- result.alreadyPublished = true;
855
- result.skipped = true;
856
- result.success = true;
857
- result.reason = "Already published";
858
- ctx.output.npm.push(result);
859
- (0, import_core7.warn)(`${update.packageName}@${update.newVersion} is already published, skipping`);
860
- continue;
861
- }
862
- const distTag = getDistTag(update.newVersion, config.npm.tag);
863
- const pkgDir = path4.dirname(path4.resolve(cwd, update.filePath));
864
- const { file: pubFile, args: pubArgs } = buildPublishCommand(ctx.packageManager, update.packageName, pkgDir, {
865
- access: config.npm.access,
866
- tag: distTag,
867
- provenance: useProvenance,
868
- noGitChecks: true
869
- });
870
- try {
871
- await execCommand(pubFile, pubArgs, {
872
- cwd,
873
- dryRun,
874
- label: `npm publish ${update.packageName}@${update.newVersion}`
1036
+ const distTag = getDistTag(update.newVersion, config.npm.tag);
1037
+ const pkgDir = path5.dirname(path5.resolve(cwd, update.filePath));
1038
+ const { file: pubFile, args: pubArgs } = buildPublishCommand(ctx.packageManager, update.packageName, pkgDir, {
1039
+ access: config.npm.access,
1040
+ tag: distTag,
1041
+ provenance: useProvenance,
1042
+ noGitChecks: true
875
1043
  });
876
- result.success = true;
877
- if (!dryRun) {
878
- (0, import_core7.success)(`Published ${update.packageName}@${update.newVersion} to npm`);
1044
+ try {
1045
+ await execCommand(pubFile, pubArgs, {
1046
+ cwd,
1047
+ dryRun,
1048
+ label: `npm publish ${update.packageName}@${update.newVersion}`,
1049
+ env: npmIsolation.env
1050
+ });
1051
+ result.success = true;
1052
+ if (!dryRun) {
1053
+ (0, import_core8.success)(`Published ${update.packageName}@${update.newVersion} to npm`);
1054
+ }
1055
+ } catch (error) {
1056
+ result.reason = error instanceof Error ? error.message : String(error);
1057
+ (0, import_core8.warn)(`Failed to publish ${update.packageName}: ${result.reason}`);
879
1058
  }
880
- } catch (error) {
881
- result.reason = error instanceof Error ? error.message : String(error);
882
- (0, import_core7.warn)(`Failed to publish ${update.packageName}: ${result.reason}`);
1059
+ ctx.output.npm.push(result);
883
1060
  }
884
- ctx.output.npm.push(result);
1061
+ } finally {
1062
+ npmIsolation.cleanup();
885
1063
  }
886
1064
  }
887
1065
 
888
1066
  // src/stages/prepare.ts
889
- var fs6 = __toESM(require("fs"), 1);
890
- var path5 = __toESM(require("path"), 1);
891
- var import_core8 = require("@releasekit/core");
1067
+ var fs7 = __toESM(require("fs"), 1);
1068
+ var path6 = __toESM(require("path"), 1);
1069
+ var import_core9 = require("@releasekit/core");
892
1070
  async function runPrepareStage(ctx) {
893
1071
  const { input, config, cliOptions, cwd } = ctx;
894
1072
  if (config.npm.enabled && config.npm.copyFiles.length > 0) {
895
1073
  for (const update of input.updates) {
896
- const pkgDir = path5.dirname(path5.resolve(cwd, update.filePath));
1074
+ const pkgDir = path6.dirname(path6.resolve(cwd, update.filePath));
897
1075
  for (const file of config.npm.copyFiles) {
898
- const src = path5.resolve(cwd, file);
899
- const dest = path5.join(pkgDir, file);
900
- if (!fs6.existsSync(src)) {
901
- (0, import_core8.debug)(`Source file not found, skipping copy: ${src}`);
1076
+ const src = path6.resolve(cwd, file);
1077
+ const dest = path6.join(pkgDir, file);
1078
+ if (!fs7.existsSync(src)) {
1079
+ (0, import_core9.debug)(`Source file not found, skipping copy: ${src}`);
902
1080
  continue;
903
1081
  }
904
- if (path5.resolve(path5.dirname(src)) === path5.resolve(pkgDir)) {
905
- (0, import_core8.debug)(`Skipping copy of ${file} - same directory as source`);
1082
+ if (path6.resolve(path6.dirname(src)) === path6.resolve(pkgDir)) {
1083
+ (0, import_core9.debug)(`Skipping copy of ${file} - same directory as source`);
906
1084
  continue;
907
1085
  }
908
1086
  if (cliOptions.dryRun) {
909
- (0, import_core8.info)(`[DRY RUN] Would copy ${src} \u2192 ${dest}`);
1087
+ (0, import_core9.info)(`[DRY RUN] Would copy ${src} \u2192 ${dest}`);
910
1088
  continue;
911
1089
  }
912
1090
  try {
913
- fs6.copyFileSync(src, dest);
914
- (0, import_core8.debug)(`Copied ${file} \u2192 ${pkgDir}`);
1091
+ fs7.copyFileSync(src, dest);
1092
+ (0, import_core9.debug)(`Copied ${file} \u2192 ${pkgDir}`);
915
1093
  } catch (error) {
916
1094
  throw createPublishError(
917
1095
  "FILE_COPY_ERROR" /* FILE_COPY_ERROR */,
@@ -923,26 +1101,26 @@ async function runPrepareStage(ctx) {
923
1101
  }
924
1102
  if (config.cargo.enabled) {
925
1103
  for (const update of input.updates) {
926
- const pkgDir = path5.dirname(path5.resolve(cwd, update.filePath));
927
- const cargoPath = path5.join(pkgDir, "Cargo.toml");
928
- if (!fs6.existsSync(cargoPath)) {
1104
+ const pkgDir = path6.dirname(path6.resolve(cwd, update.filePath));
1105
+ const cargoPath = path6.join(pkgDir, "Cargo.toml");
1106
+ if (!fs7.existsSync(cargoPath)) {
929
1107
  continue;
930
1108
  }
931
1109
  if (cliOptions.dryRun) {
932
- (0, import_core8.info)(`[DRY RUN] Would update ${cargoPath} to version ${update.newVersion}`);
1110
+ (0, import_core9.info)(`[DRY RUN] Would update ${cargoPath} to version ${update.newVersion}`);
933
1111
  continue;
934
1112
  }
935
1113
  updateCargoVersion(cargoPath, update.newVersion);
936
- (0, import_core8.debug)(`Updated ${cargoPath} to version ${update.newVersion}`);
1114
+ (0, import_core9.debug)(`Updated ${cargoPath} to version ${update.newVersion}`);
937
1115
  }
938
1116
  }
939
1117
  }
940
1118
 
941
1119
  // src/stages/verify.ts
942
- var import_core10 = require("@releasekit/core");
1120
+ var import_core11 = require("@releasekit/core");
943
1121
 
944
1122
  // src/utils/retry.ts
945
- var import_core9 = require("@releasekit/core");
1123
+ var import_core10 = require("@releasekit/core");
946
1124
  async function withRetry(fn, options, shouldRetry) {
947
1125
  let lastError;
948
1126
  let delay = options.initialDelay;
@@ -955,7 +1133,7 @@ async function withRetry(fn, options, shouldRetry) {
955
1133
  throw error;
956
1134
  }
957
1135
  if (attempt < options.maxAttempts) {
958
- (0, import_core9.debug)(`Attempt ${attempt}/${options.maxAttempts} failed, retrying in ${delay}ms...`);
1136
+ (0, import_core10.debug)(`Attempt ${attempt}/${options.maxAttempts} failed, retrying in ${delay}ms...`);
959
1137
  await sleep(delay);
960
1138
  delay = Math.floor(delay * options.backoffMultiplier);
961
1139
  }
@@ -981,7 +1159,7 @@ async function runVerifyStage(ctx) {
981
1159
  attempts: 0
982
1160
  };
983
1161
  if (cliOptions.dryRun) {
984
- (0, import_core10.info)(`[DRY RUN] Would verify ${pkg.packageName}@${pkg.version} on npm`);
1162
+ (0, import_core11.info)(`[DRY RUN] Would verify ${pkg.packageName}@${pkg.version} on npm`);
985
1163
  result.verified = true;
986
1164
  ctx.output.verification.push(result);
987
1165
  continue;
@@ -997,12 +1175,12 @@ async function runVerifyStage(ctx) {
997
1175
  if (viewResult.exitCode !== 0 || !viewResult.stdout.trim()) {
998
1176
  throw new Error(`${pkg.packageName}@${pkg.version} not yet available on npm`);
999
1177
  }
1000
- (0, import_core10.debug)(`Verified ${pkg.packageName}@${pkg.version} on npm`);
1178
+ (0, import_core11.debug)(`Verified ${pkg.packageName}@${pkg.version} on npm`);
1001
1179
  }, config.verify.npm);
1002
1180
  result.verified = true;
1003
- (0, import_core10.success)(`Verified ${pkg.packageName}@${pkg.version} on npm`);
1181
+ (0, import_core11.success)(`Verified ${pkg.packageName}@${pkg.version} on npm`);
1004
1182
  } catch {
1005
- (0, import_core10.warn)(`Failed to verify ${pkg.packageName}@${pkg.version} on npm after ${result.attempts} attempts`);
1183
+ (0, import_core11.warn)(`Failed to verify ${pkg.packageName}@${pkg.version} on npm after ${result.attempts} attempts`);
1006
1184
  }
1007
1185
  ctx.output.verification.push(result);
1008
1186
  }
@@ -1018,7 +1196,7 @@ async function runVerifyStage(ctx) {
1018
1196
  attempts: 0
1019
1197
  };
1020
1198
  if (cliOptions.dryRun) {
1021
- (0, import_core10.info)(`[DRY RUN] Would verify ${crate.packageName}@${crate.version} on crates.io`);
1199
+ (0, import_core11.info)(`[DRY RUN] Would verify ${crate.packageName}@${crate.version} on crates.io`);
1022
1200
  result.verified = true;
1023
1201
  ctx.output.verification.push(result);
1024
1202
  continue;
@@ -1030,12 +1208,12 @@ async function runVerifyStage(ctx) {
1030
1208
  if (!response.ok) {
1031
1209
  throw new Error(`${crate.packageName}@${crate.version} not yet available on crates.io`);
1032
1210
  }
1033
- (0, import_core10.debug)(`Verified ${crate.packageName}@${crate.version} on crates.io`);
1211
+ (0, import_core11.debug)(`Verified ${crate.packageName}@${crate.version} on crates.io`);
1034
1212
  }, config.verify.cargo);
1035
1213
  result.verified = true;
1036
- (0, import_core10.success)(`Verified ${crate.packageName}@${crate.version} on crates.io`);
1214
+ (0, import_core11.success)(`Verified ${crate.packageName}@${crate.version} on crates.io`);
1037
1215
  } catch {
1038
- (0, import_core10.warn)(`Failed to verify ${crate.packageName}@${crate.version} on crates.io after ${result.attempts} attempts`);
1216
+ (0, import_core11.warn)(`Failed to verify ${crate.packageName}@${crate.version} on crates.io after ${result.attempts} attempts`);
1039
1217
  }
1040
1218
  ctx.output.verification.push(result);
1041
1219
  }
@@ -1070,6 +1248,8 @@ async function runPipeline(input, config, options) {
1070
1248
  cliOptions: options,
1071
1249
  packageManager: detectPackageManager(cwd),
1072
1250
  cwd,
1251
+ releaseNotes: options.releaseNotes,
1252
+ additionalFiles: options.additionalFiles,
1073
1253
  output: {
1074
1254
  dryRun: options.dryRun,
1075
1255
  git: { committed: false, tags: [], pushed: false },
@@ -1081,7 +1261,10 @@ async function runPipeline(input, config, options) {
1081
1261
  };
1082
1262
  try {
1083
1263
  await runPrepareStage(ctx);
1084
- if (!options.skipGit) {
1264
+ if (options.skipGitCommit && !options.skipGit) {
1265
+ ctx.output.git.committed = !!input.commitMessage;
1266
+ ctx.output.git.tags = [...input.tags];
1267
+ } else if (!options.skipGit) {
1085
1268
  await runGitCommitStage(ctx);
1086
1269
  }
1087
1270
  if (!options.skipPublish) {
@@ -1110,8 +1293,8 @@ async function runPipeline(input, config, options) {
1110
1293
  }
1111
1294
 
1112
1295
  // src/stages/input.ts
1113
- var fs7 = __toESM(require("fs"), 1);
1114
- var import_core11 = require("@releasekit/core");
1296
+ var fs8 = __toESM(require("fs"), 1);
1297
+ var import_core12 = require("@releasekit/core");
1115
1298
  var import_zod = require("zod");
1116
1299
  var VersionChangelogEntrySchema = import_zod.z.object({
1117
1300
  type: import_zod.z.string(),
@@ -1144,7 +1327,7 @@ async function parseInput(inputPath) {
1144
1327
  let raw;
1145
1328
  if (inputPath) {
1146
1329
  try {
1147
- raw = fs7.readFileSync(inputPath, "utf-8");
1330
+ raw = fs8.readFileSync(inputPath, "utf-8");
1148
1331
  } catch {
1149
1332
  throw createPublishError("INPUT_PARSE_ERROR" /* INPUT_PARSE_ERROR */, `Could not read file: ${inputPath}`);
1150
1333
  }
@@ -1164,7 +1347,7 @@ async function parseInput(inputPath) {
1164
1347
  ${issues}`);
1165
1348
  }
1166
1349
  if (result.data.updates.length === 0) {
1167
- (0, import_core11.info)("No package updates in version output \u2014 pipeline will be a no-op");
1350
+ (0, import_core12.info)("No package updates in version output \u2014 pipeline will be a no-op");
1168
1351
  }
1169
1352
  return result.data;
1170
1353
  }