tegami 1.1.3 → 1.2.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.
@@ -1,4 +1,4 @@
1
- import { f as Tegami, j as Draft, t as Awaitable, v as PublishPlan } from "../types-DEyZ2r-2.js";
1
+ import { f as Tegami, j as Draft, t as Awaitable, v as PublishPlan } from "../types-BbwOrNZ2.js";
2
2
 
3
3
  //#region src/cli/index.d.ts
4
4
  interface TegamiCLIOptions {
package/dist/cli/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { n as generateFromCommits, t as changelogFilename } from "../generate-Bg86OJP4.js";
2
- import { o as isCI, r as handlePluginError, t as CancelledError } from "../error-BhMYq9iW.js";
1
+ import { n as generateFromCommits, t as changelogFilename } from "../generate-Cnd8RiKO.js";
2
+ import { i as handlePluginError, s as isCI, t as CancelledError } from "../error-CAsrGb6e.js";
3
3
  import { t as renderChangelog } from "../shared-C_iSTp_s.js";
4
4
  import { mkdir, readFile, writeFile } from "node:fs/promises";
5
5
  import path, { join, relative } from "node:path";
@@ -561,7 +561,7 @@ async function publishPackages(tegami, options) {
561
561
  s.start(dryRun ? "Validating publish lock" : "Publishing packages");
562
562
  const plan = customPublish ? await customPublish() : await tegami.publish({
563
563
  dryRun,
564
- packages: options.packages
564
+ packages: options.packages && options.packages.length > 0 ? options.packages : void 0
565
565
  });
566
566
  if (plan === "skipped") {
567
567
  s.stop(dryRun ? "No publish lock to validate" : "Nothing to publish");
@@ -59,6 +59,11 @@ function execFailure(context, result) {
59
59
  if (err) lines.push(err);
60
60
  return new Error(redactSensitiveTokens(lines.join("\n")));
61
61
  }
62
+ async function fetchFailure(context, response) {
63
+ const body = (await response.text()).trim();
64
+ const message = body ? `${context}: ${body}` : context;
65
+ return new Error(redactSensitiveTokens(message));
66
+ }
62
67
  function isNodeError(error) {
63
68
  return error instanceof Error && "code" in error;
64
69
  }
@@ -86,4 +91,4 @@ async function handlePluginError(plugin, hookName, callback) {
86
91
  }
87
92
  }
88
93
  //#endregion
89
- export { cached as a, somePromise as c, isNodeError as i, execFailure as n, isCI as o, handlePluginError as r, joinPath as s, CancelledError as t };
94
+ export { isNodeError as a, joinPath as c, handlePluginError as i, somePromise as l, execFailure as n, cached as o, fetchFailure as r, isCI as s, CancelledError as t };
@@ -1,5 +1,5 @@
1
1
  import { a as maxBump, t as bumpDepth } from "./semver-EKJ8yK5U.js";
2
- import { n as execFailure } from "./error-BhMYq9iW.js";
2
+ import { n as execFailure } from "./error-CAsrGb6e.js";
3
3
  import { t as renderChangelog } from "./shared-C_iSTp_s.js";
4
4
  import { x } from "tinyexec";
5
5
  //#region src/utils/conventional-commit.ts
@@ -1,4 +1,4 @@
1
- import { r as LogGenerator } from "../types-DEyZ2r-2.js";
1
+ import { r as LogGenerator } from "../types-BbwOrNZ2.js";
2
2
 
3
3
  //#region src/generators/simple.d.ts
4
4
  declare function simpleGenerator(): LogGenerator;
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { A as WorkspacePackage, M as DraftPolicy, N as PackageDraft, O as PackageGraph, P as BumpType, _ as PublishOptions, a as PublishPreflight, b as TegamiContext, c as TegamiPluginOption, d as GenerateChangelogOptions, f as Tegami, g as PackagePublishResult, h as PackagePublishPlan, i as PackageOptions, j as Draft, k as PackageGroup, m as PublishLock, n as GroupOptions, o as TegamiOptions, p as tegami, r as LogGenerator, s as TegamiPlugin, v as PublishPlan, y as CommitChangelog } from "./types-DEyZ2r-2.js";
1
+ import { A as WorkspacePackage, M as DraftPolicy, N as PackageDraft, O as PackageGraph, P as BumpType, _ as PublishOptions, a as PublishPreflight, b as TegamiContext, c as TegamiPluginOption, d as GenerateChangelogOptions, f as Tegami, g as PackagePublishResult, h as PackagePublishPlan, i as PackageOptions, j as Draft, k as PackageGroup, m as PublishLock, n as GroupOptions, o as TegamiOptions, p as tegami, r as LogGenerator, s as TegamiPlugin, v as PublishPlan, y as CommitChangelog } from "./types-BbwOrNZ2.js";
2
2
  export { type BumpType, type CommitChangelog, type Draft, type DraftPolicy, GenerateChangelogOptions, type GroupOptions, type LogGenerator, type PackageDraft, PackageGraph, type PackageGroup, type PackageOptions, type PackagePublishPlan, type PackagePublishResult, type PublishLock, type PublishOptions, type PublishPlan, type PublishPreflight, Tegami, type TegamiContext, type TegamiOptions, type TegamiPlugin, type TegamiPluginOption, WorkspacePackage, tegami };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { n as generateFromCommits } from "./generate-Bg86OJP4.js";
2
- import { r as handlePluginError } from "./error-BhMYq9iW.js";
3
- import { a as parseChangelogFile, o as readChangelogEntries, t as createDraft } from "./draft-CzUiQasJ.js";
4
- import { a as runPreflights, i as publishPlanStatus, o as runPublishPlan, r as initPublishPlan, t as npm } from "./npm-CaBYeOeV.js";
1
+ import { n as generateFromCommits } from "./generate-Cnd8RiKO.js";
2
+ import { i as handlePluginError } from "./error-CAsrGb6e.js";
3
+ import { a as createDraft, c as parseChangelogFile, i as runPublishPlan, l as readChangelogEntries, n as publishPlanStatus, r as runPreflights, t as initPublishPlan } from "./publish-Bt3e1RPs.js";
4
+ import { t as npm } from "./npm-4iA03RvC.js";
5
5
  import { n as WorkspacePackage, t as PackageGraph } from "./graph-BmXTJZxx.js";
6
6
  import { mkdir, rm, writeFile } from "node:fs/promises";
7
7
  import path, { join } from "node:path";
@@ -1,7 +1,7 @@
1
- import { c as somePromise, i as isNodeError, n as execFailure, r as handlePluginError, s as joinPath } from "./error-BhMYq9iW.js";
1
+ import { a as isNodeError, c as joinPath, n as execFailure, r as fetchFailure } from "./error-CAsrGb6e.js";
2
2
  import { t as _accessExpressionAsString } from "./_accessExpressionAsString-QhbUZzwv.js";
3
3
  import { n as _validateReport, t as _createStandardSchema } from "./_createStandardSchema-BGQyz-uA.js";
4
- import { a as parseChangelogFile, i as parsePublishLock, n as validateChangelogStore, r as validatePackageStore } from "./draft-CzUiQasJ.js";
4
+ import { r as runPreflights, s as parsePublishLock, t as initPublishPlan } from "./publish-Bt3e1RPs.js";
5
5
  import { t as _assertGuard } from "./_assertGuard-BBn2NbSz.js";
6
6
  import { n as WorkspacePackage } from "./graph-BmXTJZxx.js";
7
7
  import fs, { readFile, writeFile } from "node:fs/promises";
@@ -13,172 +13,6 @@ import { detect } from "package-manager-detector";
13
13
  import { tmpdir } from "node:os";
14
14
  import { intro, note, outro } from "@clack/prompts";
15
15
  import { glob } from "tinyglobby";
16
- //#region src/plans/publish.ts
17
- async function initPublishPlan(context, options) {
18
- let lock;
19
- try {
20
- lock = parsePublishLock(await fs.readFile(context.lockPath, "utf8"));
21
- } catch {
22
- return;
23
- }
24
- let data;
25
- const packages = /* @__PURE__ */ new Map();
26
- const changelogs = /* @__PURE__ */ new Map();
27
- while (data = lock.read("core:changelogs")) {
28
- const validated = validateChangelogStore(data);
29
- if (!validated.success) continue;
30
- const entry = validated.data;
31
- const parsed = parseChangelogFile(entry.filename, entry.content);
32
- if (!parsed) continue;
33
- changelogs.set(parsed.id, parsed);
34
- }
35
- while (data = lock.read("core:packages")) {
36
- const validated = validatePackageStore(data);
37
- if (!validated.success) continue;
38
- const parsed = validated.data;
39
- if (!context.graph.get(parsed.id)) continue;
40
- const pkgChangelogs = [];
41
- for (const id of parsed.changelogIds ?? []) {
42
- const entry = changelogs.get(id);
43
- if (entry) pkgChangelogs.push(entry);
44
- }
45
- packages.set(parsed.id, {
46
- changelogs: pkgChangelogs,
47
- updated: parsed.updated
48
- });
49
- }
50
- const plan = {
51
- options,
52
- changelogs,
53
- packages
54
- };
55
- for (const plugin of context.plugins) await handlePluginError(plugin, "initPublishPlan", () => plugin.initPublishPlan?.call(context, {
56
- lock,
57
- plan
58
- }));
59
- return plan;
60
- }
61
- function resolvePublishTargets(plan) {
62
- /** the iteration order = publish order */
63
- const orderedMap = /* @__PURE__ */ new Map();
64
- /** package id -> true while scanning hard wait, false while scanning optional wait */
65
- const stack = /* @__PURE__ */ new Map();
66
- function scan(id) {
67
- const preflight = plan.packages.get(id)?.preflight;
68
- if (!preflight || !preflight.shouldPublish) return;
69
- switch (stack.get(id)) {
70
- case true: throw new Error(`circular reference of deps: ${[...stack.keys(), id].join(" -> ")}`);
71
- case false: return;
72
- }
73
- if (orderedMap.has(id)) return;
74
- let split = false;
75
- if (preflight.wait) {
76
- stack.set(id, true);
77
- split ||= preflight.wait.length > 0;
78
- for (const dep of preflight.wait) scan(dep);
79
- }
80
- if (preflight.optionalWait) {
81
- stack.set(id, false);
82
- split ||= preflight.optionalWait.length > 0;
83
- for (const dep of preflight.optionalWait) scan(dep);
84
- }
85
- stack.delete(id);
86
- orderedMap.set(id, { split });
87
- }
88
- for (const id of plan.packages.keys()) scan(id);
89
- return orderedMap;
90
- }
91
- async function runPublishPlan(context, plan) {
92
- const { dryRun = false, unstable_maxChunk = 5 } = plan.options;
93
- for (const plugin of context.plugins) await handlePluginError(plugin, "beforePublishAll", () => plugin.beforePublishAll?.call(context, { plan }));
94
- async function publish(pkg) {
95
- if (dryRun) return { type: "published" };
96
- try {
97
- for (const plugin of context.plugins) if (await handlePluginError(plugin, "willPublish", () => plugin.willPublish?.call(context, { pkg })) === false) return { type: "skipped" };
98
- for (const plugin of context.plugins) {
99
- const publishResult = await handlePluginError(plugin, "publish", () => plugin.publish?.call(context, {
100
- pkg,
101
- plan
102
- }));
103
- if (publishResult) return publishResult;
104
- }
105
- } catch (e) {
106
- return {
107
- type: "failed",
108
- error: e instanceof Error ? e.message : String(e)
109
- };
110
- }
111
- return {
112
- type: "failed",
113
- error: `There is no plugin to publish package "${pkg.id}", please make sure the package has a supported provider plugin.`
114
- };
115
- }
116
- let promises = [];
117
- for (const [id, { split }] of resolvePublishTargets(plan)) {
118
- const pkg = context.graph.get(id);
119
- const packagePlan = plan.packages.get(pkg.id);
120
- if (!pkg || !packagePlan) continue;
121
- if (split || promises.length >= unstable_maxChunk) {
122
- await Promise.all(promises);
123
- promises = [];
124
- }
125
- promises.push(publish(pkg).then(async (result) => {
126
- packagePlan.publishResult = result;
127
- if (result.type === "skipped") return;
128
- for (const plugin of context.plugins) await handlePluginError(plugin, "afterPublish", () => plugin.afterPublish?.call(context, {
129
- pkg,
130
- plan
131
- }));
132
- }));
133
- }
134
- await Promise.all(promises);
135
- for (const packagePlan of plan.packages.values()) packagePlan.publishResult ??= { type: "skipped" };
136
- for (const plugin of context.plugins) await handlePluginError(plugin, "afterPublishAll", () => plugin.afterPublishAll?.call(context, { plan }));
137
- }
138
- async function runPreflights(context, plan) {
139
- const { graph } = context;
140
- await Promise.all(Array.from(plan.packages, async ([id, packagePlan]) => {
141
- const pkg = graph.get(id);
142
- packagePlan.preflight = { shouldPublish: false };
143
- if (!packagePlan.updated) return;
144
- for (const plugin of context.plugins) {
145
- const res = await handlePluginError(plugin, "publishPreflight", () => plugin.publishPreflight?.call(context, {
146
- pkg,
147
- plan
148
- }));
149
- if (res) {
150
- packagePlan.preflight = res;
151
- break;
152
- }
153
- }
154
- }));
155
- if (plan.options.packages?.length) {
156
- const only = /* @__PURE__ */ new Set();
157
- function addOnly(id) {
158
- if (only.has(id)) return;
159
- const preflight = plan.packages.get(id)?.preflight;
160
- if (!preflight) return;
161
- only.add(id);
162
- if (preflight.wait) for (const dep of preflight.wait) addOnly(dep);
163
- if (preflight.optionalWait) for (const dep of preflight.optionalWait) addOnly(dep);
164
- }
165
- for (const name of plan.options.packages) for (const pkg of graph.getByName(name)) addOnly(pkg.id);
166
- for (const [id, packagePlan] of plan.packages) {
167
- if (only.has(id)) continue;
168
- packagePlan.preflight.shouldPublish = false;
169
- }
170
- }
171
- for (const plugin of context.plugins) await handlePluginError(plugin, "afterPreflight", () => plugin.afterPreflight?.call(context, { plan }));
172
- }
173
- async function publishPlanStatus(plan, context) {
174
- for (const plugin of context.plugins) {
175
- const status = await handlePluginError(plugin, "resolvePlanStatus", () => plugin.resolvePlanStatus?.call(context, { plan }));
176
- if (Array.isArray(status) && await somePromise(status, (v) => v === "pending")) return "pending";
177
- if (status === "pending") return "pending";
178
- }
179
- return "success";
180
- }
181
- //#endregion
182
16
  //#region src/providers/npm/cli.ts
183
17
  const PLACEHOLDER_VERSION = "0.0.0-tegami-trusted-publish-setup";
184
18
  const PLACEHOLDER_DIST_TAG = "temp";
@@ -245,7 +79,7 @@ async function resolvePretrustTargets(context) {
245
79
  async function isPackageOnRegistry(name, registry = "https://registry.npmjs.org") {
246
80
  const response = await fetch(joinPath(registry, name), { headers: { Accept: "application/json" } });
247
81
  if (response.status === 404) return false;
248
- if (!response.ok) throw new Error(`Unable to check whether ${name} exists on the npm registry${registry ? ` "${registry}"` : ""}.`);
82
+ if (!response.ok) throw await fetchFailure(`Unable to check whether ${name} exists on the npm registry${registry ? ` "${registry}"` : ""}`, response);
249
83
  return true;
250
84
  }
251
85
  async function publishPlaceholder(pkg) {
@@ -1151,8 +985,8 @@ function npm({ client: defaultClient, onBreakPeerDep = "set", updateLockFile = t
1151
985
  }
1152
986
  for (const pkg of npmGraph.packages.values()) {
1153
987
  for (const dep of pkg.listDependencies(npmGraph)) {
1154
- if (!dep.linked || !dep.range || !dep.setRange) continue;
1155
- if (!dep.linked.version || semver$1.satisfies(dep.linked.version, dep.range)) continue;
988
+ if (!dep.linked?.version || !dep.range || !dep.setRange) continue;
989
+ if (semver$1.satisfies(dep.linked.version, dep.range, { includePrerelease: dep.spec.protocol === "workspace" })) continue;
1156
990
  const isPeer = dep.field === "peerDependencies";
1157
991
  if (isPeer && onBreakPeerDep === "ignore") continue;
1158
992
  let updatedRange;
@@ -1205,7 +1039,7 @@ function depsPolicy(context, getBumpDepType) {
1205
1039
  case "":
1206
1040
  case "*": return true;
1207
1041
  case "^":
1208
- case "~": return !semver$1.satisfies(target, `${resolved.spec.range}${resolved.linked.version ?? "0.0.0"}`);
1042
+ case "~": return !semver$1.satisfies(target, `${resolved.spec.range}${resolved.linked.version ?? "0.0.0"}`, { includePrerelease: true });
1209
1043
  }
1210
1044
  }
1211
1045
  if (!resolved.range || !semver$1.validRange(resolved.range)) return false;
@@ -1286,8 +1120,8 @@ async function publish(client, pkg, distTag) {
1286
1120
  async function isPackagePublished(name, version, registry) {
1287
1121
  const response = await fetch(joinPath(registry, name, version), { headers: { Accept: "application/json" } });
1288
1122
  if (response.status === 404) return false;
1289
- if (!response.ok) throw new Error(`Unable to validate ${name}@${version} against the npm registry${registry ? ` "${registry}"` : ""}.`);
1123
+ if (!response.ok) throw await fetchFailure(`Unable to validate ${name}@${version} against the npm registry${registry ? ` "${registry}"` : ""}`, response);
1290
1124
  return true;
1291
1125
  }
1292
1126
  //#endregion
1293
- export { runPreflights as a, publishPlanStatus as i, NpmPackage as n, runPublishPlan as o, initPublishPlan as r, npm as t };
1127
+ export { NpmPackage as n, npm as t };
@@ -1,2 +1,2 @@
1
- import { D as cargo, E as CargoPluginOptions, T as CargoPackage, w as CargoGraph } from "../types-DEyZ2r-2.js";
1
+ import { D as cargo, E as CargoPluginOptions, T as CargoPackage, w as CargoGraph } from "../types-BbwOrNZ2.js";
2
2
  export { CargoGraph, CargoPackage, CargoPluginOptions, cargo };
@@ -1,4 +1,4 @@
1
- import { n as execFailure } from "../error-BhMYq9iW.js";
1
+ import { n as execFailure, r as fetchFailure } from "../error-CAsrGb6e.js";
2
2
  import { t as _accessExpressionAsString } from "../_accessExpressionAsString-QhbUZzwv.js";
3
3
  import { t as _assertGuard } from "../_assertGuard-BBn2NbSz.js";
4
4
  import { n as WorkspacePackage } from "../graph-BmXTJZxx.js";
@@ -686,7 +686,7 @@ async function isPackagePublished(name, version) {
686
686
  const response = await fetch(`https://crates.io/api/v1/crates/${encodeURIComponent(name)}/${version}`);
687
687
  if (response.status === 200) return true;
688
688
  if (response.status === 404) return false;
689
- throw new Error(`Unable to validate ${name}@${version} against crates.io: ${await response.text()}`);
689
+ throw await fetchFailure(`Unable to validate ${name}@${version} against crates.io`, response);
690
690
  }
691
691
  async function buildEntry(dir) {
692
692
  try {
@@ -1,4 +1,4 @@
1
- import { s as TegamiPlugin } from "../types-DEyZ2r-2.js";
1
+ import { s as TegamiPlugin } from "../types-BbwOrNZ2.js";
2
2
 
3
3
  //#region src/plugins/git.d.ts
4
4
  interface GitPluginOptions {
@@ -1,4 +1,4 @@
1
- import { n as execFailure, o as isCI } from "../error-BhMYq9iW.js";
1
+ import { n as execFailure, s as isCI } from "../error-CAsrGb6e.js";
2
2
  import { x } from "tinyexec";
3
3
  //#region src/plugins/git.ts
4
4
  /**
@@ -1,5 +1,6 @@
1
- import { A as WorkspacePackage, b as TegamiContext, j as Draft, s as TegamiPlugin, t as Awaitable, v as PublishPlan } from "../types-DEyZ2r-2.js";
1
+ import { A as WorkspacePackage, b as TegamiContext, s as TegamiPlugin, t as Awaitable, v as PublishPlan } from "../types-BbwOrNZ2.js";
2
2
  import { GitPluginOptions } from "./git.js";
3
+ import { t as VersionRequestOptions } from "../version-request-BQwP7EWa.js";
3
4
 
4
5
  //#region src/plugins/github.d.ts
5
6
  interface GithubRelease {
@@ -10,51 +11,6 @@ interface GithubRelease {
10
11
  /** Whether to mark release as prerelease */
11
12
  prerelease?: boolean;
12
13
  }
13
- interface VersionPullRequest {
14
- /** Pull request title. */
15
- title?: string;
16
- /** Pull request body. */
17
- body?: string;
18
- }
19
- interface VersionPullRequestOptions {
20
- /**
21
- * Create the PR even outside of CI.
22
- *
23
- * @default false
24
- */
25
- forceCreate?: boolean;
26
- /**
27
- * Pull request branch. Publish group PRs are created under `<branch>/`.
28
- *
29
- * @default "tegami/version-packages"
30
- */
31
- branch?: string;
32
- /**
33
- * Pull request base branch.
34
- *
35
- * @default "main"
36
- */
37
- base?: string;
38
- /**
39
- * Publish groups to split into separate version PRs, each entry is a package (or a list of
40
- * packages) to version & publish together. Packages not covered by any group are collected
41
- * into an extra "unlisted packages" PR.
42
- *
43
- * Merging a group PR publishes only its members, the remaining PRs are re-synced on every
44
- * publish run until all of them are merged & published.
45
- */
46
- groups?: (string | string[])[];
47
- /**
48
- * Override details for a version PR.
49
- *
50
- * Only called at version-time: publish group PRs re-synced at publish-time keep the stored
51
- * title and use a default body.
52
- */
53
- create?: (this: TegamiContext, opts: {
54
- draft: Draft;
55
- publishGroup?: string[];
56
- }) => Awaitable<VersionPullRequest>;
57
- }
58
14
  /** Options for creating GitHub releases after a successful publish. */
59
15
  interface GitHubPluginOptions extends GitPluginOptions {
60
16
  /** GitHub repository. */
@@ -89,7 +45,7 @@ interface GitHubPluginOptions extends GitPluginOptions {
89
45
  *
90
46
  * Defaults to enabled in CI and disabled locally.
91
47
  */
92
- versionPr?: VersionPullRequestOptions | false;
48
+ versionPr?: VersionRequestOptions | false;
93
49
  }
94
50
  /** Create GitHub releases for successfully published packages after the whole plan succeeds. */
95
51
  declare function github(options?: GitHubPluginOptions): TegamiPlugin[];
@@ -1,9 +1,9 @@
1
1
  import { i as formatPackageVersion, r as formatNpmDistTag } from "../semver-EKJ8yK5U.js";
2
- import { t as changelogFilename } from "../generate-Bg86OJP4.js";
3
- import { a as cached, n as execFailure, o as isCI } from "../error-BhMYq9iW.js";
4
- import { o as readChangelogEntries, t as createDraft } from "../draft-CzUiQasJ.js";
2
+ import { t as changelogFilename } from "../generate-Cnd8RiKO.js";
3
+ import { n as execFailure, o as cached, r as fetchFailure, s as isCI } from "../error-CAsrGb6e.js";
4
+ import { a as createDraft, l as readChangelogEntries } from "../publish-Bt3e1RPs.js";
5
5
  import { git } from "./git.js";
6
- import { t as onVersionRequest } from "../version-request-DlLpLLK3.js";
6
+ import { t as onVersionRequest } from "../version-request-DvWVAYj2.js";
7
7
  import { readFile, writeFile } from "node:fs/promises";
8
8
  import { basename, join, relative, resolve } from "node:path";
9
9
  import { x } from "tinyexec";
@@ -33,12 +33,12 @@ async function releaseExistsByTag(repo, tag, token) {
33
33
  const { owner, repo: name } = parseGitHubRepo(repo);
34
34
  const response = await githubRequest(`/repos/${owner}/${name}/releases/tags/${encodeURIComponent(tag)}`, token, { method: "HEAD" });
35
35
  if (response.status === 404) return false;
36
- if (!response.ok) throw new Error(`Failed to get GitHub release for ${tag}.`);
36
+ if (!response.ok) throw await fetchFailure(`Failed to get GitHub release for ${tag}`, response);
37
37
  return true;
38
38
  }
39
39
  async function createRelease(repo, options) {
40
40
  const { owner, repo: name } = parseGitHubRepo(repo);
41
- if (!(await githubRequest(`/repos/${owner}/${name}/releases`, options.token, {
41
+ const response = await githubRequest(`/repos/${owner}/${name}/releases`, options.token, {
42
42
  method: "POST",
43
43
  headers: { "Content-Type": "application/json" },
44
44
  body: JSON.stringify({
@@ -47,7 +47,8 @@ async function createRelease(repo, options) {
47
47
  body: options.notes,
48
48
  prerelease: options.prerelease ?? false
49
49
  })
50
- })).ok) throw new Error(`Failed to create GitHub release for ${options.tag}.`);
50
+ });
51
+ if (!response.ok) throw await fetchFailure(`Failed to create GitHub release for ${options.tag}`, response);
51
52
  }
52
53
  async function findOpenPullRequest(repo, headBranch, token) {
53
54
  const { owner, repo: name } = parseGitHubRepo(repo);
@@ -55,23 +56,24 @@ async function findOpenPullRequest(repo, headBranch, token) {
55
56
  head: `${owner}:${headBranch}`,
56
57
  state: "open"
57
58
  })}`, token);
58
- if (!response.ok) throw new Error("Failed to check for an existing version pull request.");
59
+ if (!response.ok) throw await fetchFailure("Failed to check for an existing version pull request", response);
59
60
  return (await response.json())[0]?.number;
60
61
  }
61
62
  async function updatePullRequest(repo, number, options) {
62
63
  const { owner, repo: name } = parseGitHubRepo(repo);
63
- if (!(await githubRequest(`/repos/${owner}/${name}/pulls/${number}`, options.token, {
64
+ const response = await githubRequest(`/repos/${owner}/${name}/pulls/${number}`, options.token, {
64
65
  method: "PATCH",
65
66
  headers: { "Content-Type": "application/json" },
66
67
  body: JSON.stringify({
67
68
  title: options.title,
68
69
  body: options.body
69
70
  })
70
- })).ok) throw new Error("Failed to update the version pull request.");
71
+ });
72
+ if (!response.ok) throw await fetchFailure("Failed to update the version pull request", response);
71
73
  }
72
74
  async function createPullRequest(repo, options) {
73
75
  const { owner, repo: name } = parseGitHubRepo(repo);
74
- if (!(await githubRequest(`/repos/${owner}/${name}/pulls`, options.token, {
76
+ const response = await githubRequest(`/repos/${owner}/${name}/pulls`, options.token, {
75
77
  method: "POST",
76
78
  headers: { "Content-Type": "application/json" },
77
79
  body: JSON.stringify({
@@ -80,18 +82,19 @@ async function createPullRequest(repo, options) {
80
82
  head: options.head,
81
83
  base: options.base
82
84
  })
83
- })).ok) throw new Error("Failed to create the version pull request.");
85
+ });
86
+ if (!response.ok) throw await fetchFailure("Failed to create the version pull request", response);
84
87
  }
85
88
  async function listPullRequestsForCommit(repo, commitSha, token) {
86
89
  const { owner, repo: name } = parseGitHubRepo(repo);
87
90
  const response = await githubRequest(`/repos/${owner}/${name}/commits/${commitSha}/pulls`, token);
88
- if (!response.ok) throw new Error(`Failed to list pull requests for commit ${commitSha.slice(0, 7)}.`);
91
+ if (!response.ok) throw await fetchFailure(`Failed to list pull requests for commit ${commitSha.slice(0, 7)}`, response);
89
92
  return await response.json();
90
93
  }
91
94
  async function getPullRequest(repo, number, token) {
92
95
  const { owner, repo: name } = parseGitHubRepo(repo);
93
96
  const response = await githubRequest(`/repos/${owner}/${name}/pulls/${number}`, token);
94
- if (!response.ok) throw new Error(`Failed to resolve pull request #${number}.`);
97
+ if (!response.ok) throw await fetchFailure(`Failed to resolve pull request #${number}`, response);
95
98
  const data = await response.json();
96
99
  return {
97
100
  headRefName: data.head.ref,
@@ -105,7 +108,7 @@ async function findIssueCommentByPrefix(repo, issueNumber, prefix, token) {
105
108
  let page = 1;
106
109
  while (true) {
107
110
  const response = await githubRequest(`/repos/${owner}/${name}/issues/${issueNumber}/comments?per_page=100&page=${page}`, token);
108
- if (!response.ok) throw new Error("Failed to list pull request comments.");
111
+ if (!response.ok) throw await fetchFailure("Failed to list pull request comments", response);
109
112
  const batch = await response.json();
110
113
  if (batch.length === 0) break;
111
114
  const comment = batch.find((comment) => comment.body.startsWith(prefix));
@@ -116,19 +119,21 @@ async function findIssueCommentByPrefix(repo, issueNumber, prefix, token) {
116
119
  }
117
120
  async function updateIssueComment(repo, commentId, body, token) {
118
121
  const { owner, repo: name } = parseGitHubRepo(repo);
119
- if (!(await githubRequest(`/repos/${owner}/${name}/issues/comments/${commentId}`, token, {
122
+ const response = await githubRequest(`/repos/${owner}/${name}/issues/comments/${commentId}`, token, {
120
123
  method: "PATCH",
121
124
  headers: { "Content-Type": "application/json" },
122
125
  body: JSON.stringify({ body })
123
- })).ok) throw new Error("Failed to update pull request comment.");
126
+ });
127
+ if (!response.ok) throw await fetchFailure("Failed to update pull request comment", response);
124
128
  }
125
129
  async function createIssueComment(repo, issueNumber, body, token) {
126
130
  const { owner, repo: name } = parseGitHubRepo(repo);
127
- if (!(await githubRequest(`/repos/${owner}/${name}/issues/${issueNumber}/comments`, token, {
131
+ const response = await githubRequest(`/repos/${owner}/${name}/issues/${issueNumber}/comments`, token, {
128
132
  method: "POST",
129
133
  headers: { "Content-Type": "application/json" },
130
134
  body: JSON.stringify({ body })
131
- })).ok) throw new Error("Failed to create pull request comment.");
135
+ });
136
+ if (!response.ok) throw await fetchFailure("Failed to create pull request comment", response);
132
137
  }
133
138
  //#endregion
134
139
  //#region src/plugins/github/cli.ts
@@ -348,36 +353,30 @@ function github(options = {}) {
348
353
  }
349
354
  const versionRequests = onVersionRequest({
350
355
  name: "github",
351
- summary: "Merge this PR to publish the versioned packages.",
352
356
  options: options.versionPr,
353
- enabled(context) {
357
+ canCreate(context) {
354
358
  const { repo, token } = context.github ?? {};
355
359
  return Boolean(repo && token);
356
360
  },
357
- find(context, { head }) {
358
- const { repo, token } = context.github;
359
- return findOpenPullRequest(repo, head, token);
360
- },
361
- create(context, request) {
361
+ async upsert(context, request, update) {
362
362
  const { repo, token } = context.github;
363
- return createPullRequest(repo, {
363
+ const openPr = await findOpenPullRequest(repo, request.head, token);
364
+ if (openPr === void 0) await createPullRequest(repo, {
364
365
  title: request.title,
365
366
  body: request.body,
366
367
  head: request.head,
367
368
  base: request.base,
368
369
  token
369
370
  });
370
- },
371
- update(context, number, request) {
372
- const { repo, token } = context.github;
373
- return updatePullRequest(repo, number, {
371
+ else if (update) await updatePullRequest(repo, openPr, {
374
372
  title: request.title,
375
373
  body: request.body,
376
374
  token
377
375
  });
378
376
  }
379
377
  });
380
- return [git(options), {
378
+ const plugin = {
379
+ ...versionRequests,
381
380
  name: "github",
382
381
  init() {
383
382
  this.github = {
@@ -386,7 +385,7 @@ function github(options = {}) {
386
385
  };
387
386
  },
388
387
  async resolvePlanStatus({ plan }) {
389
- if (versionRequests.resolvePlanStatus() === "pending") return "pending";
388
+ if (versionRequests.resolvePlanStatus.call(this, { plan }) === "pending") return "pending";
390
389
  const { repo, token } = this.github;
391
390
  if (!repo || !token || releaseOptions === false) return;
392
391
  const requiredTags = /* @__PURE__ */ new Set();
@@ -459,20 +458,9 @@ function github(options = {}) {
459
458
  `https://x-access-token:${token}@github.com/${repo}.git`
460
459
  ], { nodeOptions: { cwd: this.cwd } });
461
460
  if (result.exitCode !== 0) throw execFailure("Failed to configure git remote for GitHub Actions.", result);
462
- },
463
- initCliDraft() {
464
- versionRequests.initCliDraft.call(this);
465
- },
466
- applyCliDraft(draft) {
467
- return versionRequests.applyCliDraft.call(this, draft);
468
- },
469
- initPublishPlan(opts) {
470
- versionRequests.initPublishPlan.call(this, opts);
471
- },
472
- beforePublishAll(opts) {
473
- return versionRequests.beforePublishAll.call(this, opts);
474
461
  }
475
- }];
462
+ };
463
+ return [git(options), plugin];
476
464
  }
477
465
  function createChangelogRenderer(context) {
478
466
  const { repo, token } = context.github;