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,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/gitlab.d.ts
5
6
  interface GitlabRelease {
@@ -8,51 +9,6 @@ interface GitlabRelease {
8
9
  /** Release notes */
9
10
  notes?: string;
10
11
  }
11
- interface VersionMergeRequest {
12
- /** Merge request title. */
13
- title?: string;
14
- /** Merge request body. */
15
- body?: string;
16
- }
17
- interface VersionMergeRequestOptions {
18
- /**
19
- * Create the MR even outside of CI.
20
- *
21
- * @default false
22
- */
23
- forceCreate?: boolean;
24
- /**
25
- * Merge request branch. Publish group MRs are created under `<branch>/`.
26
- *
27
- * @default "tegami/version-packages"
28
- */
29
- branch?: string;
30
- /**
31
- * Merge request base branch.
32
- *
33
- * @default "main"
34
- */
35
- base?: string;
36
- /**
37
- * Publish groups to split into separate version MRs, each entry is a package (or a list of
38
- * packages) to version & publish together. Packages not covered by any group are collected
39
- * into an extra "unlisted packages" MR.
40
- *
41
- * Merging a group MR publishes only its members, the remaining MRs are re-synced on every
42
- * publish run until all of them are merged & published.
43
- */
44
- groups?: (string | string[])[];
45
- /**
46
- * Override details for a version MR.
47
- *
48
- * Only called at version-time: publish group MRs re-synced at publish-time keep the stored
49
- * title and use a default body.
50
- */
51
- create?: (this: TegamiContext, opts: {
52
- draft: Draft;
53
- publishGroup?: string[];
54
- }) => Awaitable<VersionMergeRequest>;
55
- }
56
12
  /** Options for creating GitLab releases after a successful publish. */
57
13
  interface GitLabPluginOptions extends GitPluginOptions {
58
14
  /** GitLab repository. */
@@ -91,7 +47,7 @@ interface GitLabPluginOptions extends GitPluginOptions {
91
47
  *
92
48
  * Defaults to enabled in CI and disabled locally.
93
49
  */
94
- versionMr?: VersionMergeRequestOptions | false;
50
+ versionMr?: VersionRequestOptions | false;
95
51
  }
96
52
  /** Create GitLab releases for successfully published packages after the whole plan succeeds. */
97
53
  declare function gitlab(options?: GitLabPluginOptions): 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, s as joinPath } 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 { c as joinPath, 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";
@@ -31,12 +31,12 @@ async function releaseExistsByTag(repo, tag, options = {}) {
31
31
  const { encodedProjectPath } = parseGitLabRepo(repo);
32
32
  const response = await gitlabRequest(options, `/projects/${encodedProjectPath}/releases/${encodeURIComponent(tag)}`, { method: "HEAD" });
33
33
  if (response.status === 404) return false;
34
- if (!response.ok) throw new Error(`Failed to get GitLab release for ${tag}.`);
34
+ if (!response.ok) throw await fetchFailure(`Failed to get GitLab release for ${tag}`, response);
35
35
  return true;
36
36
  }
37
37
  async function createRelease(repo, options) {
38
38
  const { encodedProjectPath } = parseGitLabRepo(repo);
39
- if (!(await gitlabRequest(options, `/projects/${encodedProjectPath}/releases`, {
39
+ const response = await gitlabRequest(options, `/projects/${encodedProjectPath}/releases`, {
40
40
  method: "POST",
41
41
  headers: { "Content-Type": "application/json" },
42
42
  body: JSON.stringify({
@@ -44,7 +44,8 @@ async function createRelease(repo, options) {
44
44
  name: options.title,
45
45
  description: options.notes
46
46
  })
47
- })).ok) throw new Error(`Failed to create GitLab release for ${options.tag}.`);
47
+ });
48
+ if (!response.ok) throw await fetchFailure(`Failed to create GitLab release for ${options.tag}`, response);
48
49
  }
49
50
  async function findOpenMergeRequest(repo, options) {
50
51
  const { encodedProjectPath } = parseGitLabRepo(repo);
@@ -54,12 +55,12 @@ async function findOpenMergeRequest(repo, options) {
54
55
  });
55
56
  if (options.base) params.set("target_branch", options.base);
56
57
  const response = await gitlabRequest(options, `/projects/${encodedProjectPath}/merge_requests?${params}`);
57
- if (!response.ok) throw new Error("Failed to check for an existing version merge request.");
58
+ if (!response.ok) throw await fetchFailure("Failed to check for an existing version merge request", response);
58
59
  return (await response.json())[0]?.iid;
59
60
  }
60
61
  async function updateMergeRequest(repo, number, options) {
61
62
  const { encodedProjectPath } = parseGitLabRepo(repo);
62
- if (!(await gitlabRequest(options, `/projects/${encodedProjectPath}/merge_requests/${number}`, {
63
+ const response = await gitlabRequest(options, `/projects/${encodedProjectPath}/merge_requests/${number}`, {
63
64
  method: "PUT",
64
65
  headers: { "Content-Type": "application/json" },
65
66
  body: JSON.stringify({
@@ -67,11 +68,12 @@ async function updateMergeRequest(repo, number, options) {
67
68
  description: options.body,
68
69
  target_branch: options.base
69
70
  })
70
- })).ok) throw new Error("Failed to update the version merge request.");
71
+ });
72
+ if (!response.ok) throw await fetchFailure("Failed to update the version merge request", response);
71
73
  }
72
74
  async function createMergeRequest(repo, options) {
73
75
  const { encodedProjectPath } = parseGitLabRepo(repo);
74
- if (!(await gitlabRequest(options, `/projects/${encodedProjectPath}/merge_requests`, {
76
+ const response = await gitlabRequest(options, `/projects/${encodedProjectPath}/merge_requests`, {
75
77
  method: "POST",
76
78
  headers: { "Content-Type": "application/json" },
77
79
  body: JSON.stringify({
@@ -80,12 +82,13 @@ async function createMergeRequest(repo, options) {
80
82
  source_branch: options.head,
81
83
  target_branch: options.base
82
84
  })
83
- })).ok) throw new Error("Failed to create the version merge request.");
85
+ });
86
+ if (!response.ok) throw await fetchFailure("Failed to create the version merge request", response);
84
87
  }
85
88
  async function getMergeRequest(repo, number, options = {}) {
86
89
  const { encodedProjectPath } = parseGitLabRepo(repo);
87
90
  const response = await gitlabRequest(options, `/projects/${encodedProjectPath}/merge_requests/${number}`);
88
- if (!response.ok) throw new Error(`Failed to resolve merge request !${number}.`);
91
+ if (!response.ok) throw await fetchFailure(`Failed to resolve merge request !${number}`, response);
89
92
  const data = await response.json();
90
93
  let sourceProjectPath;
91
94
  if (data.source_project_id !== void 0) {
@@ -102,7 +105,7 @@ async function getMergeRequest(repo, number, options = {}) {
102
105
  async function listMergeRequestsForCommit(repo, commitSha, options = {}) {
103
106
  const { encodedProjectPath } = parseGitLabRepo(repo);
104
107
  const response = await gitlabRequest(options, `/projects/${encodedProjectPath}/repository/commits/${commitSha}/merge_requests`);
105
- if (!response.ok) throw new Error(`Failed to list merge requests for commit ${commitSha.slice(0, 7)}.`);
108
+ if (!response.ok) throw await fetchFailure(`Failed to list merge requests for commit ${commitSha.slice(0, 7)}`, response);
106
109
  return (await response.json()).map((mergeRequest) => ({
107
110
  number: mergeRequest.iid,
108
111
  title: mergeRequest.title,
@@ -114,7 +117,7 @@ async function findMergeRequestCommentByPrefix(repo, mergeRequestNumber, prefix,
114
117
  let page = 1;
115
118
  while (true) {
116
119
  const response = await gitlabRequest(options, `/projects/${encodedProjectPath}/merge_requests/${mergeRequestNumber}/notes?per_page=100&page=${page}`);
117
- if (!response.ok) throw new Error("Failed to list merge request comments.");
120
+ if (!response.ok) throw await fetchFailure("Failed to list merge request comments", response);
118
121
  const batch = await response.json();
119
122
  if (batch.length === 0) break;
120
123
  const comment = batch.find((comment) => comment.body.startsWith(prefix));
@@ -125,19 +128,21 @@ async function findMergeRequestCommentByPrefix(repo, mergeRequestNumber, prefix,
125
128
  }
126
129
  async function updateMergeRequestComment(repo, mergeRequestNumber, commentId, body, options = {}) {
127
130
  const { encodedProjectPath } = parseGitLabRepo(repo);
128
- if (!(await gitlabRequest(options, `/projects/${encodedProjectPath}/merge_requests/${mergeRequestNumber}/notes/${commentId}`, {
131
+ const response = await gitlabRequest(options, `/projects/${encodedProjectPath}/merge_requests/${mergeRequestNumber}/notes/${commentId}`, {
129
132
  method: "PUT",
130
133
  headers: { "Content-Type": "application/json" },
131
134
  body: JSON.stringify({ body })
132
- })).ok) throw new Error("Failed to update merge request comment.");
135
+ });
136
+ if (!response.ok) throw await fetchFailure("Failed to update merge request comment", response);
133
137
  }
134
138
  async function createMergeRequestComment(repo, mergeRequestNumber, body, options = {}) {
135
139
  const { encodedProjectPath } = parseGitLabRepo(repo);
136
- if (!(await gitlabRequest(options, `/projects/${encodedProjectPath}/merge_requests/${mergeRequestNumber}/notes`, {
140
+ const response = await gitlabRequest(options, `/projects/${encodedProjectPath}/merge_requests/${mergeRequestNumber}/notes`, {
137
141
  method: "POST",
138
142
  headers: { "Content-Type": "application/json" },
139
143
  body: JSON.stringify({ body })
140
- })).ok) throw new Error("Failed to create merge request comment.");
144
+ });
145
+ if (!response.ok) throw await fetchFailure("Failed to create merge request comment", response);
141
146
  }
142
147
  //#endregion
143
148
  //#region src/plugins/gitlab/cli.ts
@@ -311,38 +316,36 @@ function gitlab(options = {}) {
311
316
  }
312
317
  const versionRequests = onVersionRequest({
313
318
  name: "gitlab",
314
- summary: "Merge this MR to publish the versioned packages.",
315
319
  options: options.versionMr,
316
- enabled(context) {
320
+ canCreate(context) {
317
321
  const { repo, token } = context.gitlab ?? {};
318
322
  return Boolean(repo && token);
319
323
  },
320
- find(context, { head, base }) {
321
- return findOpenMergeRequest(context.gitlab.repo, {
322
- head,
323
- base,
324
- ...gitLabApiOptions(context.gitlab)
324
+ async upsert(context, request, update) {
325
+ const repo = context.gitlab.repo;
326
+ const api = gitLabApiOptions(context.gitlab);
327
+ const openMr = await findOpenMergeRequest(repo, {
328
+ head: request.head,
329
+ base: request.base,
330
+ ...api
325
331
  });
326
- },
327
- create(context, request) {
328
- return createMergeRequest(context.gitlab.repo, {
332
+ if (openMr === void 0) await createMergeRequest(repo, {
329
333
  title: request.title,
330
334
  body: request.body,
331
335
  head: request.head,
332
336
  base: request.base,
333
- ...gitLabApiOptions(context.gitlab)
337
+ ...api
334
338
  });
335
- },
336
- update(context, number, request) {
337
- return updateMergeRequest(context.gitlab.repo, number, {
339
+ else if (update) await updateMergeRequest(repo, openMr, {
338
340
  title: request.title,
339
341
  body: request.body,
340
342
  base: request.base,
341
- ...gitLabApiOptions(context.gitlab)
343
+ ...api
342
344
  });
343
345
  }
344
346
  });
345
- return [git(options), {
347
+ const plugin = {
348
+ ...versionRequests,
346
349
  name: "gitlab",
347
350
  init() {
348
351
  this.gitlab = {
@@ -353,7 +356,7 @@ function gitlab(options = {}) {
353
356
  };
354
357
  },
355
358
  async resolvePlanStatus({ plan }) {
356
- if (versionRequests.resolvePlanStatus() === "pending") return "pending";
359
+ if (versionRequests.resolvePlanStatus.call(this, { plan }) === "pending") return "pending";
357
360
  const { repo, token } = this.gitlab;
358
361
  if (!repo || !token || releaseOptions === false) return;
359
362
  const requiredTags = /* @__PURE__ */ new Set();
@@ -425,20 +428,9 @@ function gitlab(options = {}) {
425
428
  gitlabRemoteUrl(repo, token, webUrl)
426
429
  ], { nodeOptions: { cwd: this.cwd } });
427
430
  if (result.exitCode !== 0) throw execFailure("Failed to configure git remote for GitLab CI.", result);
428
- },
429
- initCliDraft() {
430
- versionRequests.initCliDraft.call(this);
431
- },
432
- applyCliDraft(draft) {
433
- return versionRequests.applyCliDraft.call(this, draft);
434
- },
435
- initPublishPlan(opts) {
436
- versionRequests.initPublishPlan.call(this, opts);
437
- },
438
- beforePublishAll(opts) {
439
- return versionRequests.beforePublishAll.call(this, opts);
440
431
  }
441
- }];
432
+ };
433
+ return [git(options), plugin];
442
434
  }
443
435
  function createChangelogRenderer(context) {
444
436
  const { repo, webUrl } = context.gitlab;
@@ -1,4 +1,4 @@
1
- import { A as WorkspacePackage, P as BumpType, s as TegamiPlugin } from "../types-DEyZ2r-2.js";
1
+ import { A as WorkspacePackage, P as BumpType, s as TegamiPlugin } from "../types-BbwOrNZ2.js";
2
2
 
3
3
  //#region src/plugins/go.d.ts
4
4
  interface GoModFile {
@@ -1,4 +1,4 @@
1
- import { i as isNodeError, n as execFailure } from "../error-BhMYq9iW.js";
1
+ import { a as isNodeError, n as execFailure, r as fetchFailure } from "../error-CAsrGb6e.js";
2
2
  import { n as _validateReport, t as _createStandardSchema } from "../_createStandardSchema-BGQyz-uA.js";
3
3
  import { n as WorkspacePackage } from "../graph-BmXTJZxx.js";
4
4
  import { relative, resolve } from "node:path";
@@ -524,7 +524,7 @@ async function isModulePublished(module, version) {
524
524
  const response = await fetch(`https://proxy.golang.org/${encodeURIComponent(module)}/@v/${formatted}.info`);
525
525
  if (response.status === 200) return true;
526
526
  if (response.status === 404) return false;
527
- throw new Error(`Unable to validate ${module}@${formatted} against proxy.golang.org: ${await response.text()}`);
527
+ throw await fetchFailure(`Unable to validate ${module}@${formatted} against proxy.golang.org`, response);
528
528
  }
529
529
  //#endregion
530
530
  export { GoPackage, go };
@@ -1,2 +1,2 @@
1
- import { C as NpmPackage, S as NpmGraph, l as NpmPluginOptions, u as npm, x as DependencySpec } from "../types-DEyZ2r-2.js";
1
+ import { C as NpmPackage, S as NpmGraph, l as NpmPluginOptions, u as npm, x as DependencySpec } from "../types-BbwOrNZ2.js";
2
2
  export { type DependencySpec, type NpmGraph, NpmPackage, NpmPluginOptions, npm };
@@ -1,2 +1,2 @@
1
- import { n as NpmPackage, t as npm } from "../npm-CaBYeOeV.js";
1
+ import { n as NpmPackage, t as npm } from "../npm-4iA03RvC.js";
2
2
  export { NpmPackage, npm };
@@ -1,11 +1,11 @@
1
1
  import { a as maxBump } from "./semver-EKJ8yK5U.js";
2
- import { r as handlePluginError } from "./error-BhMYq9iW.js";
2
+ import { i as handlePluginError, l as somePromise } from "./error-CAsrGb6e.js";
3
3
  import { t as _accessExpressionAsString } from "./_accessExpressionAsString-QhbUZzwv.js";
4
4
  import { n as _validateReport, t as _createStandardSchema } from "./_createStandardSchema-BGQyz-uA.js";
5
5
  import { n as validateChangelogFrontmatter, t as renderChangelog } from "./shared-C_iSTp_s.js";
6
6
  import { simpleGenerator } from "./generators/simple.js";
7
7
  import { t as _assertGuard } from "./_assertGuard-BBn2NbSz.js";
8
- import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
8
+ import fs, { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
9
9
  import path, { basename, dirname, join } from "node:path";
10
10
  import * as semver$1 from "semver";
11
11
  import { parse as parse$1, stringify } from "yaml";
@@ -178,10 +178,14 @@ function headingToBump(depth) {
178
178
  /**
179
179
  * the data structure of `publish-lock.yaml` file.
180
180
  */
181
- var PublishLock = class {
181
+ var PublishLock = class PublishLock {
182
+ /** namespace -> data array */
182
183
  data;
183
- constructor(data = /* @__PURE__ */ new Map()) {
184
- this.data = data;
184
+ constructor(input = /* @__PURE__ */ new Map()) {
185
+ if (input instanceof PublishLock) {
186
+ this.data = /* @__PURE__ */ new Map();
187
+ for (const [k, v] of input.data) this.data.set(k, [...v]);
188
+ } else this.data = input;
185
189
  }
186
190
  /** write data to namespace, note that the `data` must be serializable in yaml */
187
191
  write(namespace, data) {
@@ -618,4 +622,182 @@ function attachChangelog(draft, entry) {
618
622
  draft.changelogs.push(entry);
619
623
  }
620
624
  //#endregion
621
- export { parseChangelogFile as a, parsePublishLock as i, validateChangelogStore as n, readChangelogEntries as o, validatePackageStore as r, createDraft as t };
625
+ //#region src/plans/publish.ts
626
+ async function initPublishPlan(context, options) {
627
+ let lock;
628
+ try {
629
+ lock = parsePublishLock(await fs.readFile(context.lockPath, "utf8"));
630
+ } catch {
631
+ return;
632
+ }
633
+ let data;
634
+ const packages = /* @__PURE__ */ new Map();
635
+ const changelogs = /* @__PURE__ */ new Map();
636
+ while (data = lock.read("core:changelogs")) {
637
+ const validated = validateChangelogStore(data);
638
+ if (!validated.success) continue;
639
+ const entry = validated.data;
640
+ const parsed = parseChangelogFile(entry.filename, entry.content);
641
+ if (!parsed) continue;
642
+ changelogs.set(parsed.id, parsed);
643
+ }
644
+ while (data = lock.read("core:packages")) {
645
+ const validated = validatePackageStore(data);
646
+ if (!validated.success) continue;
647
+ const parsed = validated.data;
648
+ if (!context.graph.get(parsed.id)) continue;
649
+ const pkgChangelogs = [];
650
+ for (const id of parsed.changelogIds ?? []) {
651
+ const entry = changelogs.get(id);
652
+ if (entry) pkgChangelogs.push(entry);
653
+ }
654
+ packages.set(parsed.id, {
655
+ changelogs: pkgChangelogs,
656
+ updated: parsed.updated
657
+ });
658
+ }
659
+ const plan = {
660
+ options,
661
+ changelogs,
662
+ packages
663
+ };
664
+ for (const plugin of context.plugins) await handlePluginError(plugin, "initPublishPlan", () => plugin.initPublishPlan?.call(context, {
665
+ lock,
666
+ plan
667
+ }));
668
+ return plan;
669
+ }
670
+ function resolvePublishTargets(plan) {
671
+ /** the iteration order = publish order */
672
+ const orderedMap = /* @__PURE__ */ new Map();
673
+ let lastSplitIndex = -1;
674
+ /** package id -> true while scanning hard wait, false while scanning optional wait */
675
+ const stack = /* @__PURE__ */ new Map();
676
+ function scan(id) {
677
+ const preflight = plan.packages.get(id)?.preflight;
678
+ if (!preflight || !preflight.shouldPublish) return;
679
+ switch (stack.get(id)) {
680
+ case true: throw new Error(`circular reference of deps: ${[...stack.keys(), id].join(" -> ")}`);
681
+ case false: return;
682
+ }
683
+ let ordered = orderedMap.get(id);
684
+ if (ordered) return ordered;
685
+ let split = false;
686
+ if (preflight.wait) {
687
+ stack.set(id, true);
688
+ for (const dep of preflight.wait) {
689
+ const ordered = scan(dep);
690
+ split ||= ordered !== void 0 && ordered.index >= lastSplitIndex;
691
+ }
692
+ }
693
+ if (preflight.optionalWait) {
694
+ stack.set(id, false);
695
+ for (const dep of preflight.optionalWait) {
696
+ const ordered = scan(dep);
697
+ split ||= ordered !== void 0 && ordered.index >= lastSplitIndex;
698
+ }
699
+ }
700
+ stack.delete(id);
701
+ ordered = {
702
+ split,
703
+ index: orderedMap.size
704
+ };
705
+ if (split) lastSplitIndex = ordered.index;
706
+ orderedMap.set(id, ordered);
707
+ return ordered;
708
+ }
709
+ for (const id of plan.packages.keys()) scan(id);
710
+ return orderedMap;
711
+ }
712
+ async function runPublishPlan(context, plan) {
713
+ const { dryRun = false, unstable_maxChunk = 5 } = plan.options;
714
+ for (const plugin of context.plugins) await handlePluginError(plugin, "beforePublishAll", () => plugin.beforePublishAll?.call(context, { plan }));
715
+ async function publish(pkg) {
716
+ if (dryRun) return { type: "published" };
717
+ try {
718
+ for (const plugin of context.plugins) if (await handlePluginError(plugin, "willPublish", () => plugin.willPublish?.call(context, { pkg })) === false) return { type: "skipped" };
719
+ for (const plugin of context.plugins) {
720
+ const publishResult = await handlePluginError(plugin, "publish", () => plugin.publish?.call(context, {
721
+ pkg,
722
+ plan
723
+ }));
724
+ if (publishResult) return publishResult;
725
+ }
726
+ } catch (e) {
727
+ return {
728
+ type: "failed",
729
+ error: e instanceof Error ? e.message : String(e)
730
+ };
731
+ }
732
+ return {
733
+ type: "failed",
734
+ error: `There is no plugin to publish package "${pkg.id}", please make sure the package has a supported provider plugin.`
735
+ };
736
+ }
737
+ let promises = [];
738
+ for (const [id, { split }] of resolvePublishTargets(plan)) {
739
+ const pkg = context.graph.get(id);
740
+ const packagePlan = plan.packages.get(pkg.id);
741
+ if (!pkg || !packagePlan) continue;
742
+ if (split || promises.length >= unstable_maxChunk) {
743
+ await Promise.all(promises);
744
+ promises = [];
745
+ }
746
+ promises.push(publish(pkg).then(async (result) => {
747
+ packagePlan.publishResult = result;
748
+ if (result.type === "skipped") return;
749
+ for (const plugin of context.plugins) await handlePluginError(plugin, "afterPublish", () => plugin.afterPublish?.call(context, {
750
+ pkg,
751
+ plan
752
+ }));
753
+ }));
754
+ }
755
+ await Promise.all(promises);
756
+ for (const packagePlan of plan.packages.values()) packagePlan.publishResult ??= { type: "skipped" };
757
+ for (const plugin of context.plugins) await handlePluginError(plugin, "afterPublishAll", () => plugin.afterPublishAll?.call(context, { plan }));
758
+ }
759
+ async function runPreflights(context, plan) {
760
+ const { graph } = context;
761
+ await Promise.all(Array.from(plan.packages, async ([id, packagePlan]) => {
762
+ const pkg = graph.get(id);
763
+ packagePlan.preflight = { shouldPublish: false };
764
+ if (!packagePlan.updated) return;
765
+ for (const plugin of context.plugins) {
766
+ const res = await handlePluginError(plugin, "publishPreflight", () => plugin.publishPreflight?.call(context, {
767
+ pkg,
768
+ plan
769
+ }));
770
+ if (res) {
771
+ packagePlan.preflight = res;
772
+ break;
773
+ }
774
+ }
775
+ }));
776
+ if (plan.options.packages) {
777
+ const only = /* @__PURE__ */ new Set();
778
+ function addOnly(id) {
779
+ if (only.has(id)) return;
780
+ const preflight = plan.packages.get(id)?.preflight;
781
+ if (!preflight) return;
782
+ only.add(id);
783
+ if (preflight.wait) for (const dep of preflight.wait) addOnly(dep);
784
+ if (preflight.optionalWait) for (const dep of preflight.optionalWait) addOnly(dep);
785
+ }
786
+ for (const name of plan.options.packages) for (const pkg of graph.getByName(name)) addOnly(pkg.id);
787
+ for (const [id, packagePlan] of plan.packages) {
788
+ if (only.has(id)) continue;
789
+ packagePlan.preflight.shouldPublish = false;
790
+ }
791
+ }
792
+ for (const plugin of context.plugins) await handlePluginError(plugin, "afterPreflight", () => plugin.afterPreflight?.call(context, { plan }));
793
+ }
794
+ async function publishPlanStatus(plan, context) {
795
+ for (const plugin of context.plugins) {
796
+ const status = await handlePluginError(plugin, "resolvePlanStatus", () => plugin.resolvePlanStatus?.call(context, { plan }));
797
+ if (Array.isArray(status) && await somePromise(status, (v) => v === "pending")) return "pending";
798
+ if (status === "pending") return "pending";
799
+ }
800
+ return "success";
801
+ }
802
+ //#endregion
803
+ export { createDraft as a, parseChangelogFile as c, runPublishPlan as i, readChangelogEntries as l, publishPlanStatus as n, PublishLock as o, runPreflights as r, parsePublishLock as s, initPublishPlan as t };
@@ -560,6 +560,10 @@ interface PublishPlan {
560
560
  changelogs: Map<string, ChangelogEntry>;
561
561
  /** id -> package data. The package id will always exist in package graph, stale items will be pruned at init-time */
562
562
  packages: Map<string, PackagePublishPlan>;
563
+ /** generated by GitHub/GitLab plugin (internal) */
564
+ $versionRequest?: {
565
+ publishGroups: Map<string, "active" | "pending">;
566
+ };
563
567
  }
564
568
  interface PackagePublishPlan {
565
569
  changelogs: ChangelogEntry[];
@@ -586,6 +590,8 @@ interface PublishOptions {
586
590
  * Publish only the given packages and their dependencies.
587
591
  *
588
592
  * Each entry can be a package id, package name, or `group:name`.
593
+ *
594
+ * When empty, no packages will be published.
589
595
  */
590
596
  packages?: string[];
591
597
  /**
@@ -609,9 +615,8 @@ type PackagePublishResult = {
609
615
  declare class PublishLock {
610
616
  /** namespace -> data array */
611
617
  private readonly data;
612
- constructor(/** namespace -> data array */
613
-
614
- data?: Map<string, unknown[]>);
618
+ constructor(lock: PublishLock);
619
+ constructor(data?: Map<string, unknown[]>);
615
620
  /** write data to namespace, note that the `data` must be serializable in yaml */
616
621
  write(namespace: string, data: unknown): void;
617
622
  read(namespace: string): unknown | undefined;
@@ -2,9 +2,10 @@ import { Result } from "tinyexec";
2
2
 
3
3
  //#region src/utils/error.d.ts
4
4
  declare function execFailure(context: string, result: Awaited<Result>): Error;
5
+ declare function fetchFailure(context: string, response: Response): Promise<Error>;
5
6
  //#endregion
6
7
  //#region src/utils/common.d.ts
7
8
  declare const isCI: () => boolean;
8
9
  declare function joinPath(...paths: string[]): string;
9
10
  //#endregion
10
- export { execFailure, isCI, joinPath };
11
+ export { execFailure, fetchFailure, isCI, joinPath };
@@ -1,2 +1,2 @@
1
- import { n as execFailure, o as isCI, s as joinPath } from "../error-BhMYq9iW.js";
2
- export { execFailure, isCI, joinPath };
1
+ import { c as joinPath, n as execFailure, r as fetchFailure, s as isCI } from "../error-CAsrGb6e.js";
2
+ export { execFailure, fetchFailure, isCI, joinPath };
@@ -0,0 +1,57 @@
1
+ import { b as TegamiContext, j as Draft, m as PublishLock, t as Awaitable, v as PublishPlan } from "./types-BbwOrNZ2.js";
2
+
3
+ //#region src/utils/version-request.d.ts
4
+ interface VersionRequestOptions {
5
+ /**
6
+ * Create the pull/merge request even outside of CI.
7
+ *
8
+ * @default false
9
+ */
10
+ forceCreate?: boolean;
11
+ /**
12
+ * Pull/merge request branch. Publish group PRs are created under `<branch>/`.
13
+ *
14
+ * @default "tegami/version-packages"
15
+ */
16
+ branch?: string;
17
+ /**
18
+ * Pull/merge request base branch.
19
+ *
20
+ * @default "main"
21
+ */
22
+ base?: string;
23
+ /** Publish groups to split into separate version requests. */
24
+ groups?: (string | string[])[];
25
+ /** Override details of a version request at version-time. */
26
+ create?: (this: TegamiContext, opts: VersionRequestContext) => Awaitable<{
27
+ title?: string;
28
+ body?: string;
29
+ }>;
30
+ /** Override commit summary & message. */
31
+ commit?: (this: TegamiContext, opts: {
32
+ type: "version-packages";
33
+ } | {
34
+ type: "update-lock";
35
+ store: PublishGroupStore;
36
+ updatedLock: PublishLock;
37
+ }) => Awaitable<{
38
+ title?: string;
39
+ body?: string;
40
+ } | undefined>;
41
+ }
42
+ interface VersionRequestContext {
43
+ draft: Draft;
44
+ /** predicted publish plan (after preflight) */
45
+ plan: PublishPlan | undefined;
46
+ getPreviousVersion(packageId: string): string | undefined;
47
+ }
48
+ /** adapter over the version request API of a git provider */
49
+ interface PublishGroupStore {
50
+ /**
51
+ * - active: groups whose version request was merged, they stay listed until the lock is removed
52
+ * - pending: groups still waiting for their version request to be merged
53
+ */
54
+ groups: Record<string, "pending" | "active">;
55
+ }
56
+ //#endregion
57
+ export { VersionRequestOptions as t };