tegami 1.2.2 → 1.2.4

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.
Files changed (31) hide show
  1. package/dist/{_accessExpressionAsString-QhbUZzwv.js → _accessExpressionAsString-DW_6Xqcp.js} +1 -1
  2. package/dist/{_assertGuard-BBn2NbSz.js → _assertGuard-CFFC1Up9.js} +2 -2
  3. package/dist/{_createStandardSchema-BGQyz-uA.js → _createStandardSchema-CrRqJgaE.js} +2 -2
  4. package/dist/cli/index.d.ts +1 -1
  5. package/dist/cli/index.js +10 -8
  6. package/dist/{generate-Cnd8RiKO.js → generate-Cgl2G5ea.js} +2 -2
  7. package/dist/generators/simple.d.ts +1 -1
  8. package/dist/generators/simple.js +1 -1
  9. package/dist/{graph-BmXTJZxx.js → graph-DaJ28Y4f.js} +1 -1
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.js +14 -8
  12. package/dist/{npm-cS-D2xGI.js → npm-CyC2Rk11.js} +221 -133
  13. package/dist/plugins/cargo.d.ts +1 -1
  14. package/dist/plugins/cargo.js +37 -34
  15. package/dist/plugins/git.d.ts +1 -1
  16. package/dist/plugins/git.js +2 -4
  17. package/dist/plugins/github.d.ts +7 -7
  18. package/dist/plugins/github.js +113 -241
  19. package/dist/plugins/gitlab.d.ts +6 -6
  20. package/dist/plugins/gitlab.js +118 -245
  21. package/dist/plugins/go.d.ts +1 -1
  22. package/dist/plugins/go.js +10 -10
  23. package/dist/providers/npm.d.ts +1 -1
  24. package/dist/providers/npm.js +1 -1
  25. package/dist/{publish-Bt3e1RPs.js → publish-DAMkayLs.js} +11 -15
  26. package/dist/{semver-EKJ8yK5U.js → semver-DrtaCCZK.js} +15 -3
  27. package/dist/{shared-C_iSTp_s.js → shared-pTOZU5UZ.js} +11 -3
  28. package/dist/{types-C_vz41r2.d.ts → types-BMYzG4dR.d.ts} +42 -26
  29. package/dist/{version-request-DXk_B7O_.d.ts → version-request-BorZZ98V.d.ts} +1 -1
  30. package/dist/{version-request-DvWVAYj2.js → version-request-CQ4cJHtP.js} +203 -67
  31. package/package.json +5 -4
@@ -1,5 +1,3 @@
1
- import { Agent, AgentName } from "package-manager-detector";
2
-
3
1
  //#region src/utils/semver.d.ts
4
2
  type BumpType = "major" | "minor" | "patch";
5
3
  //#endregion
@@ -183,7 +181,7 @@ interface PackageDraft {
183
181
  /** npm dist-tag used when publishing. */distTag?: string;
184
182
  };
185
183
  /** get the bumped version of a package, return `undefined` if the package doesn't have a `version` field */
186
- bumpVersion: (pkg: WorkspacePackage) => string | undefined;
184
+ bumpVersion: (pkg: WorkspacePackage$1) => string | undefined;
187
185
  }
188
186
  /** a draft describes all operations to perform before the actual publishing, such as version bumps. */
189
187
  declare class Draft {
@@ -197,15 +195,15 @@ declare class Draft {
197
195
  constructor(context: TegamiContext);
198
196
  getPackageDrafts(): Map<string, PackageDraft>;
199
197
  getPackageDraft(id: string): PackageDraft | undefined;
200
- bumpPackage(pkg: WorkspacePackage, {
198
+ bumpPackage(pkg: WorkspacePackage$1, {
201
199
  type,
202
200
  reason
203
201
  }: {
204
202
  type: BumpType;
205
203
  reason?: string;
206
204
  }): PackageDraft;
207
- dispatchPackage(pkg: WorkspacePackage, dispatch: (draft: PackageDraft) => void, onUpdate?: (draft: PackageDraft) => void): PackageDraft;
208
- getOrInitPackage(pkg: WorkspacePackage): PackageDraft;
205
+ dispatchPackage(pkg: WorkspacePackage$1, dispatch: (draft: PackageDraft) => void, onUpdate?: (draft: PackageDraft) => void): PackageDraft;
206
+ getOrInitPackage(pkg: WorkspacePackage$1): PackageDraft;
209
207
  hasPending(): boolean;
210
208
  /** get all changelogs, note that this includes replay-only changelogs, as long as they are in the `.tegami` folder. */
211
209
  getChangelogs(): ChangelogEntry[];
@@ -229,13 +227,13 @@ interface DraftPolicy {
229
227
  id: string;
230
228
  onUpdate?: (this: Draft, opts: {
231
229
  packageDraft: PackageDraft;
232
- pkg: WorkspacePackage;
230
+ pkg: WorkspacePackage$1;
233
231
  }) => void;
234
232
  }
235
233
  //#endregion
236
234
  //#region src/graph.d.ts
237
235
  /** Package discovered in the workspace. */
238
- declare abstract class WorkspacePackage {
236
+ declare abstract class WorkspacePackage$1 {
239
237
  abstract readonly name: string;
240
238
  /** absolute path */
241
239
  abstract readonly path: string;
@@ -258,7 +256,7 @@ declare abstract class WorkspacePackage {
258
256
  interface PackageGroup {
259
257
  name: string;
260
258
  options: GroupOptions;
261
- packages: WorkspacePackage[];
259
+ packages: WorkspacePackage$1[];
262
260
  }
263
261
  /**
264
262
  * Unified graph for discovered workspace packages.
@@ -269,14 +267,14 @@ interface PackageGroup {
269
267
  declare class PackageGraph {
270
268
  private readonly packages;
271
269
  private readonly groups;
272
- constructor(packages?: WorkspacePackage[]);
273
- getPackages(): WorkspacePackage[];
270
+ constructor(packages?: WorkspacePackage$1[]);
271
+ getPackages(): WorkspacePackage$1[];
274
272
  /** Get a package by exact id. */
275
- get(id: string): WorkspacePackage | undefined;
273
+ get(id: string): WorkspacePackage$1 | undefined;
276
274
  /** Get packages by id, `group:name`, or every package matching a name. */
277
- getByName(nameOrId: string): WorkspacePackage[];
275
+ getByName(nameOrId: string): WorkspacePackage$1[];
278
276
  /** scan package into graph, if the package id already exists, replace the existing one in graph */
279
- add(pkg: WorkspacePackage): void;
277
+ add(pkg: WorkspacePackage$1): void;
280
278
  delete(id: string): void;
281
279
  getPackageGroup(pkgId: string): PackageGroup | undefined;
282
280
  getGroups(): PackageGroup[];
@@ -287,6 +285,10 @@ declare class PackageGraph {
287
285
  unregisterGroup(name: string): void;
288
286
  }
289
287
  //#endregion
288
+ //#region ../../node_modules/.pnpm/package-manager-detector@1.7.0/node_modules/package-manager-detector/dist/shared/package-manager-detector.CqsrLAro.d.mts
289
+ type Agent = 'npm' | 'yarn' | 'yarn@berry' | 'pnpm' | 'pnpm@6' | 'bun' | 'deno' | 'nub' | 'aube';
290
+ type AgentName = 'npm' | 'yarn' | 'pnpm' | 'bun' | 'deno' | 'nub' | 'aube';
291
+ //#endregion
290
292
  //#region src/plugins/gitlab/api.d.ts
291
293
  interface GitLabToken {
292
294
  value: string;
@@ -360,9 +362,11 @@ declare class CargoToml<Data extends CargoManifest = CargoManifest> {
360
362
  data: Data;
361
363
  private dependencies;
362
364
  workspace?: CargoToml<RequireFields<CargoManifest, "workspace">>;
365
+ private readonly originalContent;
363
366
  constructor(path: string, content: string, data: Data);
364
367
  listDependencies(graph: CargoGraph): ResolvedDependency[];
365
368
  patch(path: string, value: unknown): void;
369
+ write(): Promise<void>;
366
370
  }
367
371
  interface ResolvedDependency {
368
372
  path: [...string[], kind: DepKind, key: string];
@@ -371,7 +375,7 @@ interface ResolvedDependency {
371
375
  range?: string;
372
376
  setRange?: (v: string) => void;
373
377
  }
374
- declare class CargoPackage extends WorkspacePackage {
378
+ declare class CargoPackage extends WorkspacePackage$1 {
375
379
  readonly path: string;
376
380
  /** a crate must have `package` field defined, otherwise it is merely a virutal workspace file, and Tegami should not include it. */
377
381
  readonly file: CargoToml<RequireFields<CargoManifest, "package">>;
@@ -415,7 +419,7 @@ interface CargoGraph {
415
419
  }
416
420
  //#endregion
417
421
  //#region src/providers/npm/graph.d.ts
418
- declare class NpmPackage extends WorkspacePackage {
422
+ declare class NpmPackage extends WorkspacePackage$1 {
419
423
  readonly path: string;
420
424
  readonly manifest: PackageManifest;
421
425
  readonly manager = "npm";
@@ -634,6 +638,7 @@ interface GenerateChangelogOptions extends GenerateFromCommitsOptions {
634
638
  */
635
639
  write?: boolean;
636
640
  }
641
+ declare const WorkspacePackage: typeof WorkspacePackage$1;
637
642
  interface Tegami {
638
643
  /** Create pending changelog files from git commit history. */
639
644
  generateChangelog(options?: GenerateChangelogOptions): Promise<CommitChangelog[]>;
@@ -642,11 +647,22 @@ interface Tegami {
642
647
  /** Publish packages from the publish lock. */
643
648
  publish(options?: PublishOptions): Promise<PublishPlan | "skipped">;
644
649
  /**
645
- * Check publish status.
646
- *
647
- * Prefer `publish()` over this if you are publishing packages, it will also check the publish status.
650
+ * @deprecated use `getPublishStatus()` instead
648
651
  */
649
652
  publishStatus(options?: PublishOptions): Promise<"pending" | "success" | "idle">;
653
+ /**
654
+ * Check publish plan status.
655
+ *
656
+ * Prefer `publish()` over this if you are publishing packages, this is check-only and can lead to TOCTOU race.
657
+ */
658
+ getPublishStatus(options?: PublishOptions): Promise<{
659
+ /**
660
+ * - `pending`: has pending tasks.
661
+ * - `success`: all tasks finished.
662
+ * - `none`: there is no existing publish plans. */
663
+ status: "pending" | "success" | "none";
664
+ reason?: string;
665
+ }>;
650
666
  /** Remove the publish lock file after publishing has finished successfully. */
651
667
  cleanup(options?: PublishOptions): Promise<{
652
668
  state: "removed";
@@ -747,7 +763,7 @@ declare function npm({
747
763
  /** Generates changelog content for a package release. */
748
764
  interface LogGenerator {
749
765
  generate(this: TegamiContext, opts: {
750
- pkg: WorkspacePackage;
766
+ pkg: WorkspacePackage$1;
751
767
  packageDraft: PackageDraft;
752
768
  draft: Draft;
753
769
  }): string | Promise<string>;
@@ -762,7 +778,7 @@ interface TegamiOptions<Groups extends string = string> {
762
778
  /** Changelog generator used when applying a draft. */
763
779
  generator?: LogGenerator;
764
780
  /** Per-package options keyed by package name or a function. */
765
- packages?: Record<string, PackageOptions<NoInfer<Groups>>> | ((pkg: WorkspacePackage) => PackageOptions<NoInfer<Groups>> | undefined);
781
+ packages?: Record<string, PackageOptions<NoInfer<Groups>>> | ((pkg: WorkspacePackage$1) => PackageOptions<NoInfer<Groups>> | undefined);
766
782
  plugins?: TegamiPluginOption[];
767
783
  groups?: Record<Groups, GroupOptions>;
768
784
  /** Package names, ids, or regex patterns to exclude from the dependency graph. */
@@ -841,7 +857,7 @@ interface TegamiPlugin {
841
857
  * If multiple plugins return preflight data for the same package, only the first plugin will be considered.
842
858
  */
843
859
  publishPreflight?(this: TegamiContext, opts: {
844
- pkg: WorkspacePackage;
860
+ pkg: WorkspacePackage$1;
845
861
  plan: PublishPlan;
846
862
  }): Awaitable<PublishPreflight | void | undefined>;
847
863
  /** Called when all preflights finished */
@@ -850,7 +866,7 @@ interface TegamiPlugin {
850
866
  }): Awaitable<void>;
851
867
  /** Publish package, return a result object indicating if the package is published, skipped, or failed. Return `undefined` if the package is not handled by this plugin. */
852
868
  publish?(this: TegamiContext, opts: {
853
- pkg: WorkspacePackage;
869
+ pkg: WorkspacePackage$1;
854
870
  plan: PublishPlan;
855
871
  }): Promise<PackagePublishResult | undefined | void>;
856
872
  /**
@@ -867,11 +883,11 @@ interface TegamiPlugin {
867
883
  }): Awaitable<void>;
868
884
  /** Called before a package will be published, return `false` to prevent from publishing. */
869
885
  willPublish?(this: TegamiContext, opts: {
870
- pkg: WorkspacePackage;
886
+ pkg: WorkspacePackage$1;
871
887
  }): Awaitable<false | void | undefined>;
872
888
  /** Called after a package is published successfully, or failed. */
873
889
  afterPublish?(this: TegamiContext, opts: {
874
- pkg: WorkspacePackage;
890
+ pkg: WorkspacePackage$1;
875
891
  plan: PublishPlan;
876
892
  }): Awaitable<void>;
877
893
  /** Called after all publishing finishes. */
@@ -906,4 +922,4 @@ interface PublishPreflight {
906
922
  optionalWait?: string[];
907
923
  }
908
924
  //#endregion
909
- export { WorkspacePackage as A, NpmPackage as C, cargo as D, CargoPluginOptions as E, DraftPolicy as M, PackageDraft as N, PackageGraph as O, BumpType as P, NpmGraph as S, CargoPackage as T, PublishOptions as _, PublishPreflight as a, TegamiContext as b, TegamiPluginOption as c, GenerateChangelogOptions as d, Tegami as f, PackagePublishResult as g, PackagePublishPlan as h, PackageOptions as i, Draft as j, PackageGroup as k, NpmPluginOptions as l, PublishLock as m, GroupOptions as n, TegamiOptions as o, tegami as p, LogGenerator as r, TegamiPlugin as s, Awaitable as t, npm as u, PublishPlan as v, CargoGraph as w, DependencySpec as x, CommitChangelog as y };
925
+ export { type PackageGroup as A, type NpmGraph as C, type CargoPluginOptions as D, CargoPackage as E, BumpType as F, Draft as M, DraftPolicy as N, cargo as O, PackageDraft as P, DependencySpec as S, CargoGraph as T, PackagePublishResult as _, type PublishPreflight as a, type CommitChangelog as b, type TegamiPluginOption as c, type GenerateChangelogOptions as d, Tegami as f, PackagePublishPlan as g, PublishLock as h, PackageOptions as i, WorkspacePackage$1 as j, PackageGraph as k, NpmPluginOptions as l, tegami as m, GroupOptions as n, TegamiOptions as o, WorkspacePackage as p, LogGenerator as r, TegamiPlugin as s, Awaitable as t, npm as u, PublishOptions as v, NpmPackage as w, TegamiContext as x, PublishPlan as y };
@@ -1,4 +1,4 @@
1
- import { b as TegamiContext, j as Draft, m as PublishLock, t as Awaitable, v as PublishPlan } from "./types-C_vz41r2.js";
1
+ import { M as Draft, h as PublishLock, t as Awaitable, x as TegamiContext, y as PublishPlan } from "./types-BMYzG4dR.js";
2
2
 
3
3
  //#region src/utils/version-request.d.ts
4
4
  interface VersionRequestOptions {
@@ -1,8 +1,9 @@
1
- import { r as formatNpmDistTag } from "./semver-EKJ8yK5U.js";
2
- import { n as execFailure, s as isCI } from "./error-CAsrGb6e.js";
3
- import { t as _accessExpressionAsString } from "./_accessExpressionAsString-QhbUZzwv.js";
4
- import { n as _validateReport, t as _createStandardSchema } from "./_createStandardSchema-BGQyz-uA.js";
5
- import { o as PublishLock, r as runPreflights, s as parsePublishLock, t as initPublishPlan } from "./publish-Bt3e1RPs.js";
1
+ import { a as formatPackageVersion, i as formatNpmDistTag, r as diffWeight } from "./semver-DrtaCCZK.js";
2
+ import { l as somePromise, n as execFailure, s as isCI } from "./error-CAsrGb6e.js";
3
+ import { t as _accessExpressionAsString } from "./_accessExpressionAsString-DW_6Xqcp.js";
4
+ import { n as _validateReport, t as _createStandardSchema } from "./_createStandardSchema-CrRqJgaE.js";
5
+ import { t as getPackageBumps } from "./shared-pTOZU5UZ.js";
6
+ import { o as PublishLock, r as runPreflights, s as parsePublishLock, t as initPublishPlan } from "./publish-DAMkayLs.js";
6
7
  import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
7
8
  import { join, relative } from "node:path";
8
9
  import { x } from "tinyexec";
@@ -65,8 +66,8 @@ const validatePublishGroupStore = (() => {
65
66
  };
66
67
  });
67
68
  })();
68
- function onVersionRequest(provider) {
69
- const namespace = `${provider.name}:publish-group`;
69
+ function versionRequestPlugin(provider) {
70
+ const NamespacePublishGroup = `${provider.name}:publish-group`;
70
71
  /** package id -> version before applying the CLI draft */
71
72
  const snapshots = /* @__PURE__ */ new Map();
72
73
  function resolveConfig(graph) {
@@ -93,6 +94,19 @@ function onVersionRequest(provider) {
93
94
  ...rest
94
95
  };
95
96
  }
97
+ /** commit the working tree changes onto a detached HEAD */
98
+ async function createVersionCommit(ctx, config) {
99
+ const { title = "Version Packages", body } = await config.commit?.call(ctx, { type: "version-packages" }) ?? {};
100
+ await run(ctx.cwd, ["checkout", "--detach"], "Failed to detach HEAD for version branches.");
101
+ await run(ctx.cwd, ["add", "-A"], "Failed to stage version changes.");
102
+ const args = [
103
+ "commit",
104
+ "-m",
105
+ title
106
+ ];
107
+ if (body) args.push("-m", body);
108
+ await run(ctx.cwd, args, "Failed to commit version changes.");
109
+ }
96
110
  /**
97
111
  * Commit the group's lock state on top of `parent` and force-push its branch.
98
112
  *
@@ -100,8 +114,8 @@ function onVersionRequest(provider) {
100
114
  */
101
115
  async function syncGroupBranch(context, opts) {
102
116
  const lock = new PublishLock(opts.baseLock);
103
- while (lock.read(namespace));
104
- lock.write(namespace, opts.store);
117
+ while (lock.read(NamespacePublishGroup));
118
+ lock.write(NamespacePublishGroup, opts.store);
105
119
  const commit = await createLockCommit(context, opts.parent, lock.serialize(), await opts.config.commit?.call(context, {
106
120
  type: "update-lock",
107
121
  store: opts.store,
@@ -117,15 +131,16 @@ function onVersionRequest(provider) {
117
131
  return false;
118
132
  }
119
133
  return {
120
- /** snapshot package versions, hook into `initCliDraft` */
134
+ name: `${provider.name}:version-request`,
135
+ /** snapshot package versions */
121
136
  initCliDraft() {
122
137
  for (const pkg of this.graph.getPackages()) snapshots.set(pkg.id, pkg.version);
123
138
  },
124
- /** commit & push version branches, then upsert their requests, hook into `applyCliDraft` */
139
+ /** commit & push version branches, then upsert their requests */
125
140
  async applyCliDraft(draft) {
141
+ if (!provider.canCreate(this)) return;
126
142
  const config = resolveConfig(this.graph);
127
- if (!config || !provider.canCreate(this)) return;
128
- if (!(config.forceCreate || isCI()) || !await hasGitChanges(this.cwd)) return;
143
+ if (!config || !(config.forceCreate || isCI()) || !await hasGitChanges(this.cwd)) return;
129
144
  const requests = [];
130
145
  const updatedPackages = /* @__PURE__ */ new Map();
131
146
  for (const id of draft.getPackageDrafts().keys()) {
@@ -151,7 +166,7 @@ function onVersionRequest(provider) {
151
166
  packages: Array.from(updatedPackages.values())
152
167
  });
153
168
  if (requests.length === 0) return;
154
- await createVersionCommit(this.cwd, await config.commit?.call(this, { type: "version-packages" }));
169
+ await createVersionCommit(this, config);
155
170
  let baseLock;
156
171
  let parent;
157
172
  const tasks = [];
@@ -164,10 +179,15 @@ function onVersionRequest(provider) {
164
179
  getPreviousVersion: (id) => snapshots.get(id)
165
180
  };
166
181
  const custom = await config.create?.call(this, ctx);
167
- const title = custom?.title ?? (publishGroup ? `Release ${packages.map((pkg) => `${pkg.name} (${pkg.manager})`).join(", ")}` : "Version Packages");
182
+ const resolved = {
183
+ title: custom?.title ?? (publishGroup ? `Release ${packages.map((pkg) => `${pkg.name} (${pkg.manager})`).join(", ")}` : "Version Packages"),
184
+ body: custom?.body ?? renderRequestBody(this, ctx),
185
+ head: branch,
186
+ base: config.base
187
+ };
168
188
  if (publishGroup) {
169
189
  parent ??= await resolveHead(this.cwd);
170
- baseLock ??= await parsePublishLock(await readFile(this.lockPath, "utf8"));
190
+ baseLock ??= parsePublishLock(await readFile(this.lockPath, "utf8"));
171
191
  const newGroups = {};
172
192
  for (const req of requests) {
173
193
  if (!req.publishGroup) continue;
@@ -180,32 +200,33 @@ function onVersionRequest(provider) {
180
200
  parent,
181
201
  store: { groups: newGroups }
182
202
  });
183
- tasks.push(provider.upsert(this, {
184
- title,
185
- body: custom?.body ?? renderRequestBody(this, ctx),
186
- head: branch,
187
- base: config.base
188
- }, !inSync));
203
+ tasks.push(provider.upsert(this, resolved, !inSync));
189
204
  continue;
190
205
  }
191
- await pushBranch(this.cwd, branch);
192
- await provider.upsert(this, {
193
- title,
194
- body: custom?.body ?? renderRequestBody(this, ctx),
195
- head: branch,
196
- base: config.base
197
- }, true);
206
+ await run(this.cwd, [
207
+ "checkout",
208
+ "-B",
209
+ branch
210
+ ], "Failed to create the version branch.");
211
+ await run(this.cwd, [
212
+ "push",
213
+ "--force",
214
+ "-u",
215
+ "origin",
216
+ branch
217
+ ], "Failed to push the version branch to origin. Ensure `origin` is configured and you have push access.");
218
+ await provider.upsert(this, resolved, true);
198
219
  }
199
220
  await Promise.all(tasks);
200
221
  },
201
- /** restore publish groups from the lock into the plan, hook into `initPublishPlan` */
222
+ /** restore publish groups from the lock into the plan */
202
223
  initPublishPlan({ lock, plan }) {
203
224
  const config = resolveConfig(this.graph);
204
225
  if (!config) return;
205
226
  let data;
206
227
  const publishGroups = /* @__PURE__ */ new Map();
207
228
  plan.$versionRequest = { publishGroups };
208
- while (data = lock.read(namespace)) {
229
+ while (data = lock.read(NamespacePublishGroup)) {
209
230
  const validated = validatePublishGroupStore(data);
210
231
  if (!validated.success) continue;
211
232
  const store = validated.data;
@@ -232,7 +253,7 @@ function onVersionRequest(provider) {
232
253
  if (!publishGroups) return;
233
254
  for (const s of publishGroups.values()) if (s === "pending") return "pending";
234
255
  },
235
- /** re-sync the version requests of pending publish groups, hook into `beforePublishAll` */
256
+ /** re-sync the version requests of pending publish groups */
236
257
  async beforePublishAll({ plan }) {
237
258
  if (plan.options.dryRun || !provider.canCreate(this)) return;
238
259
  const config = resolveConfig(this.graph);
@@ -261,7 +282,7 @@ function onVersionRequest(provider) {
261
282
  };
262
283
  }
263
284
  function renderRequestBody(ctx, { draft, getPreviousVersion, plan }) {
264
- const packageLines = [];
285
+ const bumpedPackages = [];
265
286
  const changelogLines = [];
266
287
  const publishLines = [];
267
288
  const changesets = /* @__PURE__ */ new Map();
@@ -274,19 +295,31 @@ function renderRequestBody(ctx, { draft, getPreviousVersion, plan }) {
274
295
  else changesets.set(changelog, [pkg]);
275
296
  }
276
297
  const from = getPreviousVersion(id);
277
- if (!from || from === pkg.version) continue;
278
- packageLines.push(`| \`${pkg.name}\` | \`${from}\` | \`${pkg.version}\`${formatNpmDistTag(packageDraft.npm?.distTag)} |`);
298
+ if (!from || !pkg.version || from === pkg.version) continue;
299
+ bumpedPackages.push({
300
+ name: pkg.name,
301
+ from,
302
+ to: pkg.version,
303
+ diff: diffWeight(from, pkg.version)
304
+ });
279
305
  }
306
+ const packageLines = bumpedPackages.sort((a, b) => b.diff - a.diff).map(({ name, from, to }) => `| \`${name}\` | \`${from}\` | \`${to}\` |`);
280
307
  for (const [entry, linkedPackages] of changesets) {
281
- changelogLines.push(`### ${entry.subject ?? `\`${entry.filename}\``}`, "");
282
- changelogLines.push("<details>", `<summary>Show Bumped Packages (${linkedPackages.length})</summary>`, "", ...linkedPackages.map((pkg) => `- \`${pkg.id}\``), "", "</details>", "");
308
+ const bumps = getPackageBumps(ctx.graph, entry);
309
+ changelogLines.push(`### ${entry.subject ?? `\`${entry.filename}\``}`, "", "<details>", `<summary>Show Bumped Packages (${linkedPackages.length})</summary>`, "", "| Package | Bump |", "| --- | --- |");
310
+ for (const pkg of linkedPackages) changelogLines.push(`| \`${pkg.id}\` | ${bumps.get(pkg) ?? ""} |`);
311
+ changelogLines.push("", "</details>", "");
283
312
  for (const section of entry.sections) {
284
313
  changelogLines.push(`#### ${section.title}`, "");
285
314
  if (section.content) changelogLines.push(section.content);
286
315
  }
287
316
  }
288
- if (plan) {
289
- for (const [id, { preflight }] of plan.packages) if (preflight.shouldPublish) publishLines.push(`- ${id}`);
317
+ if (plan) for (const [id, { preflight, npm }] of plan.packages) {
318
+ if (!preflight.shouldPublish) continue;
319
+ const pkg = ctx.graph.get(id);
320
+ let pm = "";
321
+ if (npm?.distTag) pm += ` (dist-tag: ${npm.distTag})`;
322
+ publishLines.push(`| \`${pkg.name}\` | \`${pkg.version}\`${pm} | \`${pkg.manager}\` |`);
290
323
  }
291
324
  const sections = [
292
325
  "## Summary",
@@ -296,7 +329,7 @@ function renderRequestBody(ctx, { draft, getPreviousVersion, plan }) {
296
329
  ];
297
330
  if (packageLines.length > 0) sections.push("| Package | From | To |", "| --- | --- | --- |", ...packageLines);
298
331
  if (changelogLines.length > 0) sections.push("", "## Changelogs", ...changelogLines);
299
- if (publishLines.length > 0) sections.push("", "## Publish", "", "The following packages will be published if merged:", ...publishLines);
332
+ if (publishLines.length > 0) sections.push("", "## Publish", "", "The following packages will be published if merged:", "", "| Package | Version | Registry |", "| --- | --- | --- |", ...publishLines);
300
333
  sections.push("");
301
334
  return sections.join("\n");
302
335
  }
@@ -380,32 +413,6 @@ async function resolveRemoteBranches(cwd, branches) {
380
413
  async function hasGitChanges(cwd) {
381
414
  return (await run(cwd, ["status", "--porcelain"], "Failed to check git status.")).length > 0;
382
415
  }
383
- /** commit the working tree changes onto a detached HEAD */
384
- async function createVersionCommit(cwd, { title = "Version Packages", body } = {}) {
385
- await run(cwd, ["checkout", "--detach"], "Failed to detach HEAD for version branches.");
386
- await run(cwd, ["add", "-A"], "Failed to stage version changes.");
387
- const args = [
388
- "commit",
389
- "-m",
390
- title
391
- ];
392
- if (body) args.push("-m", body);
393
- await run(cwd, args, "Failed to commit version changes.");
394
- }
395
- async function pushBranch(cwd, branch) {
396
- await run(cwd, [
397
- "checkout",
398
- "-B",
399
- branch
400
- ], "Failed to create the version branch.");
401
- await run(cwd, [
402
- "push",
403
- "--force",
404
- "-u",
405
- "origin",
406
- branch
407
- ], "Failed to push the version branch to origin. Ensure `origin` is configured and you have push access.");
408
- }
409
416
  async function run(cwd, args, message, env) {
410
417
  const result = await x("git", args, { nodeOptions: {
411
418
  cwd,
@@ -423,5 +430,134 @@ function publishGroupId(members) {
423
430
  if (slugs.length === 0) slugs.push("group");
424
431
  return slugs.join("-");
425
432
  }
433
+ function formatPreview({ graph, npm }, draft, newChangelogNames, labels) {
434
+ const pendingPackages = [];
435
+ const lines = [
436
+ "### Tegami",
437
+ "",
438
+ `This repository uses [Tegami](https://tegami.fuma-nama.dev) to manage releases. When your changes affect published packages, add a changelog file under \`.tegami/\` before merging.`,
439
+ "",
440
+ `[**Create a changelog →**](${labels["create-a-changelog-href"]}) · [Changelog format](https://tegami.fuma-nama.dev/changelog)`,
441
+ ""
442
+ ];
443
+ for (const pkg of graph.getPackages()) {
444
+ const plan = draft.getPackageDraft(pkg.id);
445
+ if (!plan) continue;
446
+ const bumped = plan.bumpVersion(pkg);
447
+ if (!bumped || !pkg.version || bumped === pkg.version) continue;
448
+ pendingPackages.push({
449
+ name: pkg.name,
450
+ type: plan.type ?? "—",
451
+ from: pkg.version,
452
+ to: bumped,
453
+ distTag: plan.npm?.distTag
454
+ });
455
+ }
456
+ if (pendingPackages.length > 0) {
457
+ lines.push("#### Release preview", "", "| Package | Bump | Version |", "| --- | --- | --- |");
458
+ for (const { name, type, from, to, distTag } of pendingPackages.sort((a, b) => diffWeight(b.from, b.to) - diffWeight(a.from, a.to))) lines.push(`| \`${name}\` | ${type} | \`${from}\` → \`${to}\`${formatNpmDistTag(distTag)} |`);
459
+ lines.push("");
460
+ }
461
+ const newChangelogs = draft.getChangelogs().filter((entry) => newChangelogNames.has(entry.filename));
462
+ if (newChangelogs.length > 0) {
463
+ lines.push(`#### Changelogs in this ${labels.pr}`, "", "| Changelog | Title |", "| --- | --- |");
464
+ for (const entry of newChangelogs) for (const section of entry.sections) lines.push(`| \`${entry.filename}\` | ${section.title} |`);
465
+ lines.push("");
466
+ } else if (pendingPackages.length === 0) lines.push("#### No changelogs yet", "", `This ${labels.pr} has no pending changelog files. If your changes require a release, add a changelog before merging.`, "");
467
+ else if (newChangelogNames.size === 0) lines.push(`This ${labels.pr} does not add changelog files. Pending changelogs from other branches are included in the preview above.`, "");
468
+ lines.push(`Run \`${npm?.client ?? "npm"} run tegami\` locally to create a changelog interactively.`, "", `<sub>Managed by [Tegami](https://tegami.fuma-nama.dev).</sub>`, "");
469
+ return lines.join("\n");
470
+ }
471
+ async function resolveFileCommit(ctx, filename) {
472
+ const result = await x("git", [
473
+ "log",
474
+ "--diff-filter=A",
475
+ "-1",
476
+ "--format=%H",
477
+ "--",
478
+ relative(ctx.cwd, join(ctx.changelogDir, filename))
479
+ ], { nodeOptions: { cwd: ctx.cwd } });
480
+ if (result.exitCode !== 0) return;
481
+ return result.stdout.trim() || void 0;
482
+ }
483
+ function createAutoRelease({ eager, create, override, overrideGroup, releaseExistsByTag, formatChangelog }) {
484
+ async function defaultNotes(ctx, pkg, packagePlan) {
485
+ if (packagePlan && packagePlan.changelogs.length > 0) return (await Promise.all(packagePlan.changelogs.map(formatChangelog.bind(ctx)))).join("\n\n");
486
+ return `Published ${formatPackageVersion(pkg.name, pkg.version, packagePlan?.npm?.distTag)}.`;
487
+ }
488
+ async function defaultGroupedNotes(ctx, plan, packages) {
489
+ const changelogs = /* @__PURE__ */ new Map();
490
+ for (const pkg of packages) {
491
+ const packagePlan = plan.packages.get(pkg.id);
492
+ if (!packagePlan) continue;
493
+ for (const entry of packagePlan.changelogs) changelogs.set(entry.id, entry);
494
+ }
495
+ const sections = [packages.map((pkg) => {
496
+ const packagePlan = plan.packages.get(pkg.id);
497
+ return `- ${formatPackageVersion(pkg.name, pkg.version, packagePlan?.npm?.distTag)}`;
498
+ }).join("\n")];
499
+ if (changelogs.size > 0) {
500
+ const notes = await Promise.all(Array.from(changelogs.values(), formatChangelog.bind(ctx)));
501
+ sections.push("", notes.join("\n\n"));
502
+ }
503
+ return sections.join("\n");
504
+ }
505
+ return {
506
+ async hasPending(plan) {
507
+ const requiredTags = /* @__PURE__ */ new Set();
508
+ for (const pkg of plan.packages.values()) if (pkg.preflight.shouldPublish && pkg.git?.tag) requiredTags.add(pkg.git.tag);
509
+ return somePromise(Array.from(requiredTags, (tag) => releaseExistsByTag.call(this, tag)), (exists) => !exists);
510
+ },
511
+ async create(plan) {
512
+ const groups = /* @__PURE__ */ new Map();
513
+ for (const [id, { preflight, publishResult, git }] of plan.packages) {
514
+ if (!eager && publishResult.type === "failed") return;
515
+ const tag = git?.tag;
516
+ if (!tag || !preflight.shouldPublish) continue;
517
+ const pkg = this.graph.get(id);
518
+ const group = groups.get(tag);
519
+ if (group) group.push(pkg);
520
+ else groups.set(tag, [pkg]);
521
+ }
522
+ await Promise.all(Array.from(groups, async ([tag, packages]) => {
523
+ for (const member of packages) if (plan.packages.get(member.id).publishResult.type === "failed") return;
524
+ if (await releaseExistsByTag.call(this, tag)) return;
525
+ if (packages.length > 1) {
526
+ const { title = tag, notes = await defaultGroupedNotes(this, plan, packages), ...rest } = await overrideGroup?.call(this, {
527
+ tag,
528
+ packages,
529
+ plan
530
+ }) ?? {};
531
+ await create({
532
+ input: {
533
+ title,
534
+ notes,
535
+ ...rest
536
+ },
537
+ tag,
538
+ packages
539
+ });
540
+ return;
541
+ }
542
+ const pkg = packages[0];
543
+ const packagePlan = plan.packages.get(pkg.id);
544
+ const { title = formatPackageVersion(pkg.name, pkg.version, packagePlan?.npm?.distTag), notes = await defaultNotes(this, pkg, packagePlan), ...rest } = await override?.call(this, {
545
+ tag,
546
+ pkg,
547
+ plan
548
+ }) ?? {};
549
+ await create({
550
+ input: {
551
+ title,
552
+ notes,
553
+ ...rest
554
+ },
555
+ tag,
556
+ packages
557
+ });
558
+ }));
559
+ }
560
+ };
561
+ }
426
562
  //#endregion
427
- export { onVersionRequest as t };
563
+ export { versionRequestPlugin as i, formatPreview as n, resolveFileCommit as r, createAutoRelease as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tegami",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "A tool to manage changelogs, versioning, and publishing in monorepo",
5
5
  "license": "MIT",
6
6
  "author": "Fuma Nama",
@@ -29,17 +29,17 @@
29
29
  "access": "public"
30
30
  },
31
31
  "dependencies": {
32
- "@clack/prompts": "^1.6.0",
32
+ "@clack/prompts": "^1.7.0",
33
33
  "@rainbowatcher/toml-edit-js": "^0.6.5",
34
- "package-manager-detector": "^1.6.0",
35
34
  "semver": "^7.8.5",
36
35
  "tinyexec": "^1.2.4",
37
36
  "tinyglobby": "^0.2.17",
38
37
  "yaml": "^2.9.0"
39
38
  },
40
39
  "devDependencies": {
41
- "@types/node": "^26.0.1",
40
+ "@types/node": "^26.1.0",
42
41
  "@types/semver": "^7.7.1",
42
+ "package-manager-detector": "^1.7.0",
43
43
  "tsdown": "^0.22.3",
44
44
  "typescript": "6.0.3",
45
45
  "typia": "^12.1.1",
@@ -47,6 +47,7 @@
47
47
  },
48
48
  "inlinedDependencies": {
49
49
  "@typia/interface": "12.1.1",
50
+ "package-manager-detector": "1.7.0",
50
51
  "typia": "12.1.1"
51
52
  },
52
53
  "scripts": {