tegami 1.2.3 → 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.
@@ -1,13 +1,13 @@
1
- import { j as WorkspacePackage, s as TegamiPlugin, t as Awaitable, x as TegamiContext, y as PublishPlan } from "../types-Kj7Nxbjz.js";
1
+ import { j as WorkspacePackage, s as TegamiPlugin, t as Awaitable, x as TegamiContext, y as PublishPlan } from "../types-BMYzG4dR.js";
2
2
  import { GitPluginOptions } from "./git.js";
3
- import { t as VersionRequestOptions } from "../version-request-C5vtakPE.js";
3
+ import { t as VersionRequestOptions } from "../version-request-BorZZ98V.js";
4
4
 
5
5
  //#region src/plugins/gitlab.d.ts
6
6
  interface GitlabRelease {
7
7
  /** Release title */
8
- title?: string;
8
+ title: string;
9
9
  /** Release notes */
10
- notes?: string;
10
+ notes: string;
11
11
  }
12
12
  /** Options for creating GitLab releases after a successful publish. */
13
13
  interface GitLabPluginOptions extends GitPluginOptions {
@@ -35,12 +35,12 @@ interface GitLabPluginOptions extends GitPluginOptions {
35
35
  tag: string;
36
36
  pkg: WorkspacePackage;
37
37
  plan: PublishPlan;
38
- }) => Awaitable<GitlabRelease>; /** Override release details when multiple packages share a git tag. */
38
+ }) => Awaitable<Partial<GitlabRelease>>; /** Override release details when multiple packages share a git tag. */
39
39
  createGrouped?: (this: TegamiContext, opts: {
40
40
  tag: string;
41
41
  packages: WorkspacePackage[];
42
42
  plan: PublishPlan;
43
- }) => Awaitable<GitlabRelease>;
43
+ }) => Awaitable<Partial<GitlabRelease>>;
44
44
  };
45
45
  /**
46
46
  * (CLI only) Open a version merge request after versioning.
@@ -1,9 +1,8 @@
1
- import { a as formatPackageVersion } from "../semver-DrtaCCZK.js";
2
1
  import { t as changelogFilename } from "../generate-Cgl2G5ea.js";
3
2
  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-BEYIILK5.js";
3
+ import { a as createDraft, l as readChangelogEntries } from "../publish-DAMkayLs.js";
5
4
  import { git } from "./git.js";
6
- import { n as onVersionRequest, t as formatPreview } from "../version-request-C89RO85i.js";
5
+ import { i as versionRequestPlugin, n as formatPreview, r as resolveFileCommit, t as createAutoRelease } from "../version-request-CQ4cJHtP.js";
7
6
  import { readFile, writeFile } from "node:fs/promises";
8
7
  import { basename, join, relative, resolve } from "node:path";
9
8
  import { x } from "tinyexec";
@@ -273,209 +272,120 @@ function parsePositiveInt(value, option) {
273
272
  /** Create GitLab releases for successfully published packages after the whole plan succeeds. */
274
273
  function gitlab(options = {}) {
275
274
  const { release: releaseOptions = true } = options;
276
- let renderer;
277
- function getRenderer(context) {
278
- return renderer ??= createChangelogRenderer(context);
279
- }
280
- const versionRequests = onVersionRequest({
281
- name: "gitlab",
282
- options: options.versionMr,
283
- canCreate(context) {
284
- const { repo, token } = context.gitlab ?? {};
285
- return Boolean(repo && token);
286
- },
287
- async upsert(context, request, update) {
288
- const repo = context.gitlab.repo;
289
- const api = gitLabApiOptions(context.gitlab);
290
- const openMr = await findOpenMergeRequest(repo, {
291
- head: request.head,
292
- base: request.base,
293
- ...api
294
- });
295
- if (openMr === void 0) await createMergeRequest(repo, {
296
- title: request.title,
297
- body: request.body,
298
- head: request.head,
299
- base: request.base,
300
- ...api
301
- });
302
- else if (update) await updateMergeRequest(repo, openMr, {
303
- title: request.title,
304
- body: request.body,
305
- base: request.base,
306
- ...api
307
- });
308
- }
309
- });
310
- const plugin = {
311
- ...versionRequests,
312
- name: "gitlab",
313
- init() {
314
- this.gitlab = {
315
- repo: options.repo ?? process.env.GITLAB_REPOSITORY ?? process.env.CI_PROJECT_PATH,
316
- token: resolveGitLabToken(options.token),
317
- apiUrl: options.apiUrl ?? process.env.GITLAB_API_URL ?? process.env.CI_API_V4_URL ?? "https://gitlab.com/api/v4",
318
- webUrl: options.webUrl ?? process.env.GITLAB_SERVER_URL ?? process.env.CI_SERVER_URL ?? "https://gitlab.com"
319
- };
320
- },
321
- async resolvePlanStatus({ plan }) {
322
- if (versionRequests.resolvePlanStatus.call(this, { plan }) === "pending") return "pending";
323
- const { repo, token } = this.gitlab;
324
- if (!repo || !token || releaseOptions === false) return;
325
- const requiredTags = /* @__PURE__ */ new Set();
326
- const api = gitLabApiOptions(this.gitlab);
327
- for (const pkg of plan.packages.values()) if (pkg.preflight.shouldPublish && pkg.git?.tag) requiredTags.add(pkg.git.tag);
328
- return Array.from(requiredTags, async (tag) => {
329
- if (!await releaseExistsByTag(repo, tag, api)) return "pending";
330
- });
331
- },
332
- async afterPublishAll({ plan }) {
333
- const { repo, token } = this.gitlab;
334
- if (!repo || !token || releaseOptions === false) return;
335
- const api = gitLabApiOptions(this.gitlab);
336
- const { eager = false, create, createGrouped } = releaseOptions === true ? {} : releaseOptions;
337
- const groups = /* @__PURE__ */ new Map();
338
- for (const [id, { preflight, publishResult, git }] of plan.packages) {
339
- if (!eager && publishResult.type === "failed") return;
340
- const tag = git?.tag;
341
- if (!tag || !preflight.shouldPublish) continue;
342
- const pkg = this.graph.get(id);
343
- const group = groups.get(tag);
344
- if (group) group.push(pkg);
345
- else groups.set(tag, [pkg]);
346
- }
347
- await Promise.all(Array.from(groups, async ([tag, packages]) => {
348
- for (const member of packages) if (plan.packages.get(member.id).publishResult.type === "failed") return;
349
- if (await releaseExistsByTag(repo, tag, api)) return;
350
- let release;
351
- if (packages.length > 1) {
352
- const overrides = await createGrouped?.call(this, {
353
- tag,
354
- packages,
355
- plan
356
- }) ?? {};
357
- release = {
358
- title: overrides.title ?? tag,
359
- notes: overrides.notes ?? await defaultGroupedNotes(getRenderer(this), plan, packages)
360
- };
361
- } else {
362
- const pkg = packages[0];
363
- const overrides = await create?.call(this, {
364
- tag,
365
- pkg,
366
- plan
367
- }) ?? {};
368
- const packagePlan = plan.packages.get(pkg.id);
369
- release = {
370
- title: overrides.title ?? formatPackageVersion(pkg.name, pkg.version, packagePlan?.npm?.distTag),
371
- notes: overrides.notes ?? await defaultNotes(getRenderer(this), pkg, packagePlan)
372
- };
275
+ let autoRelease;
276
+ return [
277
+ git(options),
278
+ {
279
+ name: "gitlab",
280
+ init() {
281
+ const { repo, token, webUrl } = this.gitlab = {
282
+ repo: options.repo ?? process.env.GITLAB_REPOSITORY ?? process.env.CI_PROJECT_PATH,
283
+ token: resolveGitLabToken(options.token),
284
+ apiUrl: options.apiUrl ?? process.env.GITLAB_API_URL ?? process.env.CI_API_V4_URL ?? "https://gitlab.com/api/v4",
285
+ webUrl: options.webUrl ?? process.env.GITLAB_SERVER_URL ?? process.env.CI_SERVER_URL ?? "https://gitlab.com"
286
+ };
287
+ if (repo && token && releaseOptions !== false) {
288
+ const { eager = false, create, createGrouped } = releaseOptions === true ? {} : releaseOptions;
289
+ const api = gitLabApiOptions(this.gitlab);
290
+ const resolveEntryMeta = cached((entry) => entry.id, async (entry) => {
291
+ const commit = await resolveFileCommit(this, entry.filename);
292
+ if (!commit || !repo) return {
293
+ commit,
294
+ mergeRequests: []
295
+ };
296
+ return {
297
+ commit,
298
+ mergeRequests: await listMergeRequestsForCommit(repo, commit, api).catch(() => [])
299
+ };
300
+ });
301
+ autoRelease = createAutoRelease({
302
+ eager,
303
+ override: create,
304
+ overrideGroup: createGrouped,
305
+ async formatChangelog(entry) {
306
+ const meta = await resolveEntryMeta(entry);
307
+ const commitSuffix = meta.commit ? ` ([${meta.commit.slice(0, 7)}](${joinPath(webUrl, repo, "-/commit", meta.commit)}))` : "";
308
+ const lines = [];
309
+ for (const section of entry.sections) {
310
+ lines.push(`### ${section.title}${commitSuffix}`, "");
311
+ if (section.content) lines.push(section.content, "");
312
+ }
313
+ if (meta.mergeRequests.length > 0) {
314
+ lines.push("<details>", "<summary>Merge request & contributors</summary>", "");
315
+ for (const mr of meta.mergeRequests) {
316
+ let line = `- [!${mr.number} ${mr.title}](${joinPath(webUrl, repo, "-/merge_requests", String(mr.number))})`;
317
+ if (mr.user) line += ` by @${mr.user.login}`;
318
+ lines.push(line);
319
+ }
320
+ lines.push("", "</details>");
321
+ }
322
+ return lines.join("\n").trim();
323
+ },
324
+ create({ input, tag }) {
325
+ return createRelease(repo, {
326
+ tag,
327
+ title: input.title,
328
+ notes: input.notes,
329
+ ...api
330
+ });
331
+ },
332
+ releaseExistsByTag(tag) {
333
+ return releaseExistsByTag(repo, tag, api);
334
+ }
335
+ });
373
336
  }
374
- await createRelease(repo, {
375
- tag,
376
- title: release.title,
377
- notes: release.notes,
337
+ },
338
+ async resolvePlanStatus({ plan }) {
339
+ if (await autoRelease?.hasPending.call(this, plan)) return "pending";
340
+ },
341
+ async afterPublishAll({ plan }) {
342
+ await autoRelease?.create.call(this, plan);
343
+ },
344
+ async initCli(cli) {
345
+ registerMrCli(cli);
346
+ if (!isCI()) return;
347
+ const { repo, token, webUrl } = this.gitlab;
348
+ if (!token || !repo) return;
349
+ const result = await x("git", [
350
+ "remote",
351
+ "set-url",
352
+ "origin",
353
+ gitlabRemoteUrl(repo, token, webUrl)
354
+ ], { nodeOptions: { cwd: this.cwd } });
355
+ if (result.exitCode !== 0) throw execFailure("Failed to configure git remote for GitLab CI.", result);
356
+ }
357
+ },
358
+ versionRequestPlugin({
359
+ name: "gitlab",
360
+ options: options.versionMr,
361
+ canCreate(context) {
362
+ const { repo, token } = context.gitlab ?? {};
363
+ return Boolean(repo && token);
364
+ },
365
+ async upsert(context, request, update) {
366
+ const repo = context.gitlab.repo;
367
+ const api = gitLabApiOptions(context.gitlab);
368
+ const openMr = await findOpenMergeRequest(repo, {
369
+ head: request.head,
370
+ base: request.base,
378
371
  ...api
379
372
  });
380
- }));
381
- },
382
- async initCli(cli) {
383
- registerMrCli(cli);
384
- if (!isCI()) return;
385
- const { repo, token, webUrl } = this.gitlab;
386
- if (!token || !repo) return;
387
- const result = await x("git", [
388
- "remote",
389
- "set-url",
390
- "origin",
391
- gitlabRemoteUrl(repo, token, webUrl)
392
- ], { nodeOptions: { cwd: this.cwd } });
393
- if (result.exitCode !== 0) throw execFailure("Failed to configure git remote for GitLab CI.", result);
394
- }
395
- };
396
- return [git(options), plugin];
397
- }
398
- function createChangelogRenderer(context) {
399
- const { repo, webUrl } = context.gitlab;
400
- const api = gitLabApiOptions(context.gitlab);
401
- const resolveFileCommit = cached((filename) => filename, async (filename) => {
402
- const result = await x("git", [
403
- "log",
404
- "--diff-filter=A",
405
- "-1",
406
- "--format=%H",
407
- "--",
408
- relative(context.cwd, join(context.changelogDir, filename))
409
- ], { nodeOptions: { cwd: context.cwd } });
410
- if (result.exitCode !== 0) return;
411
- return result.stdout.trim() || void 0;
412
- });
413
- const resolveEntryMeta = cached((entry) => entry.id, async (entry) => {
414
- const commit = await resolveFileCommit(entry.filename);
415
- if (!commit || !repo) return {
416
- commit,
417
- mergeRequests: []
418
- };
419
- return {
420
- commit,
421
- mergeRequests: await listMergeRequestsForCommit(repo, commit, api).catch(() => [])
422
- };
423
- });
424
- function formatEntryDetails(meta) {
425
- if (meta.mergeRequests.length === 0) return;
426
- const lines = [];
427
- for (const mr of meta.mergeRequests) {
428
- let line = repo ? `- [!${mr.number} ${mr.title}](${joinPath(webUrl, repo, "-/merge_requests", String(mr.number))})` : `- #${mr.number} ${mr.title}`;
429
- if (mr.user) line += ` by @${mr.user.login}`;
430
- lines.push(line);
431
- }
432
- return [
433
- "<details>",
434
- "<summary>Merge request & contributors</summary>",
435
- "",
436
- ...lines,
437
- "",
438
- "</details>"
439
- ].join("\n");
440
- }
441
- return async (entry) => {
442
- const meta = await resolveEntryMeta(entry);
443
- let commitSuffix = "";
444
- if (meta.commit) {
445
- const short = meta.commit.slice(0, 7);
446
- const link = repo ? `[${short}](${joinPath(webUrl, repo, "-/commit", meta.commit)})` : `\`${short}\``;
447
- commitSuffix += ` (${link})`;
448
- }
449
- const lines = [];
450
- for (const section of entry.sections) {
451
- lines.push(`### ${section.title}${commitSuffix}`, "");
452
- if (section.content) lines.push(section.content, "");
453
- }
454
- const details = formatEntryDetails(meta);
455
- if (details) lines.push(details);
456
- return lines.join("\n").trim();
457
- };
458
- }
459
- async function defaultNotes(renderer, pkg, packagePlan) {
460
- if (packagePlan && packagePlan.changelogs.length > 0) return (await Promise.all(packagePlan.changelogs.map(renderer))).join("\n\n");
461
- return `Published ${formatPackageVersion(pkg.name, pkg.version, packagePlan?.npm?.distTag)}.`;
462
- }
463
- async function defaultGroupedNotes(renderer, plan, packages) {
464
- const changelogs = /* @__PURE__ */ new Map();
465
- for (const pkg of packages) {
466
- const packagePlan = plan.packages.get(pkg.id);
467
- if (!packagePlan) continue;
468
- for (const entry of packagePlan.changelogs) changelogs.set(entry.id, entry);
469
- }
470
- const sections = [packages.map((pkg) => {
471
- const packagePlan = plan.packages.get(pkg.id);
472
- return `- ${formatPackageVersion(pkg.name, pkg.version, packagePlan?.npm?.distTag)}`;
473
- }).join("\n")];
474
- if (changelogs.size > 0) {
475
- const notes = await Promise.all(Array.from(changelogs.values(), renderer));
476
- sections.push("", notes.join("\n\n"));
477
- }
478
- return sections.join("\n");
373
+ if (openMr === void 0) await createMergeRequest(repo, {
374
+ title: request.title,
375
+ body: request.body,
376
+ head: request.head,
377
+ base: request.base,
378
+ ...api
379
+ });
380
+ else if (update) await updateMergeRequest(repo, openMr, {
381
+ title: request.title,
382
+ body: request.body,
383
+ base: request.base,
384
+ ...api
385
+ });
386
+ }
387
+ })
388
+ ];
479
389
  }
480
390
  function gitLabApiOptions(gitlab) {
481
391
  const options = {};
@@ -1,4 +1,4 @@
1
- import { F as BumpType, j as WorkspacePackage, s as TegamiPlugin } from "../types-Kj7Nxbjz.js";
1
+ import { F as BumpType, j as WorkspacePackage, s as TegamiPlugin } from "../types-BMYzG4dR.js";
2
2
 
3
3
  //#region src/plugins/go.d.ts
4
4
  interface GoModFile {
@@ -287,7 +287,6 @@ function go({ updateLockFile = true, bumpDep: getBumpDepType } = {}) {
287
287
  let active = false;
288
288
  return {
289
289
  name: "go",
290
- enforce: "post",
291
290
  async resolve() {
292
291
  await discoverGoPackages(this.cwd, (pkg) => this.graph.add(pkg));
293
292
  active = this.graph.getPackages().some((pkg) => pkg instanceof GoPackage);
@@ -320,9 +319,9 @@ function go({ updateLockFile = true, bumpDep: getBumpDepType } = {}) {
320
319
  },
321
320
  initPublishLock({ lock, draft }) {
322
321
  if (!active) return;
323
- for (const [id, packageDraft] of draft.getPackageDrafts()) {
322
+ for (const id of draft.getPackageDrafts().keys()) {
324
323
  const pkg = this.graph.get(id);
325
- if (!(pkg instanceof GoPackage) || !packageDraft.type) continue;
324
+ if (!(pkg instanceof GoPackage)) continue;
326
325
  lock.write("go:packages", {
327
326
  id,
328
327
  version: pkg.version
@@ -331,17 +330,18 @@ function go({ updateLockFile = true, bumpDep: getBumpDepType } = {}) {
331
330
  },
332
331
  initPublishPlan({ lock, plan }) {
333
332
  if (!active) return;
333
+ const lockVersions = /* @__PURE__ */ new Map();
334
334
  let data;
335
335
  while (data = lock.read("go:packages")) {
336
- const validated = validateGoPackageLock(data);
337
- if (!validated.success) continue;
338
- const parsed = validated.data;
339
- const pkg = this.graph.get(parsed.id);
340
- if (pkg instanceof GoPackage) pkg.setVersion(parsed.version);
336
+ const { success, data: parsed } = validateGoPackageLock(data);
337
+ if (!success) continue;
338
+ lockVersions.set(parsed.id, parsed.version);
341
339
  }
342
340
  for (const [id, packagePlan] of plan.packages) {
343
341
  const pkg = this.graph.get(id);
344
342
  if (!(pkg instanceof GoPackage)) continue;
343
+ const version = packagePlan.updated && lockVersions.get(id);
344
+ if (version) pkg.setVersion(version);
345
345
  packagePlan.git ??= {};
346
346
  packagePlan.git.tag = formatGoTag(this.cwd, pkg.path, pkg.version);
347
347
  }
@@ -1,2 +1,2 @@
1
- import { C as NpmGraph, S as DependencySpec, l as NpmPluginOptions, u as npm, w as NpmPackage } from "../types-Kj7Nxbjz.js";
1
+ import { C as NpmGraph, S as DependencySpec, l as NpmPluginOptions, u as npm, w as NpmPackage } from "../types-BMYzG4dR.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-uJA8deYA.js";
1
+ import { n as NpmPackage, t as npm } from "../npm-CyC2Rk11.js";
2
2
  export { NpmPackage, npm };
@@ -788,10 +788,12 @@ async function runPreflights(context, plan) {
788
788
  async function publishPlanStatus(plan, context) {
789
789
  for (const plugin of context.plugins) {
790
790
  const status = await handlePluginError(plugin, "resolvePlanStatus", () => plugin.resolvePlanStatus?.call(context, { plan }));
791
- if (Array.isArray(status) && await somePromise(status, (v) => v === "pending")) return "pending";
792
- if (status === "pending") return "pending";
791
+ if (Array.isArray(status) && await somePromise(status, (v) => v === "pending") || status === "pending") return {
792
+ status: "pending",
793
+ reason: `Plugin "${plugin.name}" has pending tasks`
794
+ };
793
795
  }
794
- return "success";
796
+ return { status: "success" };
795
797
  }
796
798
  //#endregion
797
799
  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 };
@@ -362,9 +362,11 @@ declare class CargoToml<Data extends CargoManifest = CargoManifest> {
362
362
  data: Data;
363
363
  private dependencies;
364
364
  workspace?: CargoToml<RequireFields<CargoManifest, "workspace">>;
365
+ private readonly originalContent;
365
366
  constructor(path: string, content: string, data: Data);
366
367
  listDependencies(graph: CargoGraph): ResolvedDependency[];
367
368
  patch(path: string, value: unknown): void;
369
+ write(): Promise<void>;
368
370
  }
369
371
  interface ResolvedDependency {
370
372
  path: [...string[], kind: DepKind, key: string];
@@ -645,11 +647,22 @@ interface Tegami {
645
647
  /** Publish packages from the publish lock. */
646
648
  publish(options?: PublishOptions): Promise<PublishPlan | "skipped">;
647
649
  /**
648
- * Check publish status.
649
- *
650
- * Prefer `publish()` over this if you are publishing packages, it will also check the publish status.
650
+ * @deprecated use `getPublishStatus()` instead
651
651
  */
652
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
+ }>;
653
666
  /** Remove the publish lock file after publishing has finished successfully. */
654
667
  cleanup(options?: PublishOptions): Promise<{
655
668
  state: "removed";
@@ -1,4 +1,4 @@
1
- import { M as Draft, h as PublishLock, t as Awaitable, x as TegamiContext, y as PublishPlan } from "./types-Kj7Nxbjz.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 {