tegami 1.1.3 → 1.2.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.
@@ -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 { c as somePromise, r as handlePluginError } from "./error-BhMYq9iW.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;
@@ -0,0 +1,39 @@
1
+ import { b as TegamiContext, j as Draft, 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
+ }
31
+ interface VersionRequestContext {
32
+ draft: Draft;
33
+ /** predicted publish plan (after preflight) */
34
+ plan: PublishPlan | undefined;
35
+ getPreviousVersion(packageId: string): string | undefined;
36
+ }
37
+ /** adapter over the version request API of a git provider */
38
+ //#endregion
39
+ export { VersionRequestOptions as t };