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,4 +1,4 @@
1
- import { M as Draft, f as Tegami, t as Awaitable, y as PublishPlan } from "../types-Kj7Nxbjz.js";
1
+ import { M as Draft, f as Tegami, t as Awaitable, y as PublishPlan } from "../types-BMYzG4dR.js";
2
2
 
3
3
  //#region src/cli/index.d.ts
4
4
  interface TegamiCLIOptions {
package/dist/cli/index.js CHANGED
@@ -484,7 +484,7 @@ function registerCoreCommands(cli, tegami, options) {
484
484
  await publishPackages(tegami, { cli: options });
485
485
  });
486
486
  cli.command("check-publish", { description: "exit with code 1 if no publishing needed, otherwise 0" }).action(async () => {
487
- const status = await tegami.publishStatus();
487
+ const { status } = await tegami.getPublishStatus();
488
488
  process.exit(status === "pending" ? 0 : 1);
489
489
  });
490
490
  cli.command("publish", { description: "publish packages from the publish lock" }).option("dry-run", {
@@ -523,10 +523,13 @@ async function versionPackages(tegami, options) {
523
523
  outro("No versions changed.");
524
524
  return false;
525
525
  }
526
- if (!options.noChecks && await tegami.publishStatus() === "pending") {
527
- note(`Publish lock at ${context.lockPath} is still pending. Publish it before applying a new draft.`);
528
- outro("Cannot apply.");
529
- return false;
526
+ if (!options.noChecks) {
527
+ const { status, reason } = await tegami.getPublishStatus();
528
+ if (status === "pending") {
529
+ note(`Publish lock at ${context.lockPath} is still pending. Publish it before applying a new draft.`, "Failed to apply");
530
+ outro(reason ?? "Cannot apply.");
531
+ return false;
532
+ }
530
533
  }
531
534
  const lines = [];
532
535
  for (const pkg of context.graph.getPackages()) {
@@ -1,4 +1,4 @@
1
- import { r as LogGenerator } from "../types-Kj7Nxbjz.js";
1
+ import { r as LogGenerator } from "../types-BMYzG4dR.js";
2
2
 
3
3
  //#region src/generators/simple.d.ts
4
4
  declare function simpleGenerator(): LogGenerator;
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { A as PackageGroup, F as BumpType, M as Draft, N as DraftPolicy, P as PackageDraft, _ as PackagePublishResult, a as PublishPreflight, b as CommitChangelog, c as TegamiPluginOption, d as GenerateChangelogOptions, f as Tegami, g as PackagePublishPlan, h as PublishLock, i as PackageOptions, k as PackageGraph, m as tegami, n as GroupOptions, o as TegamiOptions, p as WorkspacePackage, r as LogGenerator, s as TegamiPlugin, v as PublishOptions, x as TegamiContext, y as PublishPlan } from "./types-Kj7Nxbjz.js";
1
+ import { A as PackageGroup, F as BumpType, M as Draft, N as DraftPolicy, P as PackageDraft, _ as PackagePublishResult, a as PublishPreflight, b as CommitChangelog, c as TegamiPluginOption, d as GenerateChangelogOptions, f as Tegami, g as PackagePublishPlan, h as PublishLock, i as PackageOptions, k as PackageGraph, m as tegami, n as GroupOptions, o as TegamiOptions, p as WorkspacePackage, r as LogGenerator, s as TegamiPlugin, v as PublishOptions, x as TegamiContext, y as PublishPlan } from "./types-BMYzG4dR.js";
2
2
  export { type BumpType, type CommitChangelog, type Draft, type DraftPolicy, GenerateChangelogOptions, type GroupOptions, type LogGenerator, type PackageDraft, PackageGraph, type PackageGroup, type PackageOptions, type PackagePublishPlan, type PackagePublishResult, type PublishLock, type PublishOptions, type PublishPlan, type PublishPreflight, Tegami, type TegamiContext, type TegamiOptions, type TegamiPlugin, type TegamiPluginOption, WorkspacePackage, tegami };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { n as generateFromCommits } from "./generate-Cgl2G5ea.js";
2
2
  import { i as handlePluginError } from "./error-CAsrGb6e.js";
3
- import { t as npm } from "./npm-uJA8deYA.js";
4
- import { a as createDraft, c as parseChangelogFile, i as runPublishPlan, l as readChangelogEntries, n as publishPlanStatus, r as runPreflights, t as initPublishPlan } from "./publish-BEYIILK5.js";
3
+ import { t as npm } from "./npm-CyC2Rk11.js";
4
+ import { a as createDraft, c as parseChangelogFile, i as runPublishPlan, l as readChangelogEntries, n as publishPlanStatus, r as runPreflights, t as initPublishPlan } from "./publish-DAMkayLs.js";
5
5
  import { n as WorkspacePackage$1, t as PackageGraph } from "./graph-DaJ28Y4f.js";
6
6
  import { mkdir, rm, writeFile } from "node:fs/promises";
7
7
  import path, { join } from "node:path";
@@ -99,19 +99,23 @@ function tegami(options = {}) {
99
99
  }
100
100
  return createDraft(changelogs, context);
101
101
  },
102
- async publishStatus(publishOptions = {}) {
102
+ async getPublishStatus(publishOptions = {}) {
103
103
  const context = await getContextResolved();
104
104
  const plan = await initPublishPlan(context, publishOptions);
105
- if (!plan) return "idle";
105
+ if (!plan) return { status: "none" };
106
106
  await runPreflights(context, plan);
107
107
  return publishPlanStatus(plan, context);
108
108
  },
109
+ async publishStatus(publishOptions = {}) {
110
+ const { status } = await this.getPublishStatus(publishOptions);
111
+ return status === "none" ? "idle" : status;
112
+ },
109
113
  async publish(publishOptions = {}) {
110
114
  const context = await getContextResolved();
111
115
  const plan = await initPublishPlan(context, publishOptions);
112
116
  if (!plan) return "skipped";
113
117
  await runPreflights(context, plan);
114
- if (await publishPlanStatus(plan, context) === "success") return "skipped";
118
+ if ((await publishPlanStatus(plan, context)).status === "success") return "skipped";
115
119
  await runPublishPlan(context, plan);
116
120
  if (Array.from(plan.packages.values()).every((pkg) => pkg.publishResult.type === "skipped")) return "skipped";
117
121
  return plan;
@@ -124,7 +128,8 @@ function tegami(options = {}) {
124
128
  reason: "no-plan"
125
129
  };
126
130
  await runPreflights(context, plan);
127
- if (await publishPlanStatus(plan, context) !== "success") return {
131
+ const { status } = await publishPlanStatus(plan, context);
132
+ if (status !== "success") return {
128
133
  state: "skipped",
129
134
  reason: "pending"
130
135
  };
@@ -1,7 +1,7 @@
1
1
  import { a as isNodeError, c as joinPath, n as execFailure, r as fetchFailure } from "./error-CAsrGb6e.js";
2
2
  import { t as _accessExpressionAsString } from "./_accessExpressionAsString-DW_6Xqcp.js";
3
3
  import { n as _validateReport, t as _createStandardSchema } from "./_createStandardSchema-CrRqJgaE.js";
4
- import { r as runPreflights, s as parsePublishLock, t as initPublishPlan } from "./publish-BEYIILK5.js";
4
+ import { r as runPreflights, s as parsePublishLock, t as initPublishPlan } from "./publish-DAMkayLs.js";
5
5
  import { t as _assertGuard } from "./_assertGuard-CFFC1Up9.js";
6
6
  import { n as WorkspacePackage } from "./graph-DaJ28Y4f.js";
7
7
  import fs, { readFile, writeFile } from "node:fs/promises";
@@ -247,17 +247,16 @@ async function publishPlaceholder(pkg) {
247
247
  const access = pkg.manifest.publishConfig?.access;
248
248
  const dir = await fs.mkdtemp(join(tmpdir(), "tegami-npm-placeholder-"));
249
249
  try {
250
- await fs.writeFile(join(dir, "package.json"), `${JSON.stringify({
250
+ await Promise.all([fs.writeFile(join(dir, "package.json"), `${JSON.stringify({
251
251
  name: pkg.name,
252
252
  version: PLACEHOLDER_VERSION,
253
253
  description: "Placeholder published by Tegami for npm trusted publishing setup."
254
- }, null, 2)}\n`);
255
- await fs.writeFile(join(dir, "README.md"), `# Placeholder package
256
-
257
- This empty package was published by [Tegami](https://tegami.fuma-nama.dev) to configure npm trusted publishing.
258
-
259
- The real package contents will be published via CI with OIDC.
260
- `);
254
+ }, null, 2)}\n`), fs.writeFile(join(dir, "README.md"), `# Placeholder package
255
+
256
+ This empty package was published by [Tegami](https://tegami.fuma-nama.dev) to configure npm trusted publishing.
257
+
258
+ The real package contents will be published via CI with OIDC.
259
+ `)]);
261
260
  const args = [
262
261
  "publish",
263
262
  "--tag",
@@ -969,7 +968,6 @@ function npm({ client: defaultClient, onBreakPeerDep = "set", updateLockFile = t
969
968
  } } = {}) {
970
969
  return {
971
970
  name: "npm",
972
- enforce: "pre",
973
971
  async init() {
974
972
  if (defaultClient) this.npm = {
975
973
  client: defaultClient,
@@ -1,2 +1,2 @@
1
- import { D as CargoPluginOptions, E as CargoPackage, O as cargo, T as CargoGraph } from "../types-Kj7Nxbjz.js";
1
+ import { D as CargoPluginOptions, E as CargoPackage, O as cargo, T as CargoGraph } from "../types-BMYzG4dR.js";
2
2
  export { CargoGraph, CargoPackage, CargoPluginOptions, cargo };
@@ -2,7 +2,7 @@ import { n as execFailure, r as fetchFailure } from "../error-CAsrGb6e.js";
2
2
  import { t as _accessExpressionAsString } from "../_accessExpressionAsString-DW_6Xqcp.js";
3
3
  import { t as _assertGuard } from "../_assertGuard-CFFC1Up9.js";
4
4
  import { n as WorkspacePackage } from "../graph-DaJ28Y4f.js";
5
- import { readFile, writeFile } from "node:fs/promises";
5
+ import fs from "node:fs/promises";
6
6
  import path from "node:path";
7
7
  import { x } from "tinyexec";
8
8
  import * as semver$1 from "semver";
@@ -510,17 +510,47 @@ var CargoToml = class {
510
510
  data;
511
511
  dependencies;
512
512
  workspace;
513
+ originalContent;
513
514
  constructor(path, content, data) {
514
515
  this.path = path;
515
516
  this.content = content;
516
517
  this.data = data;
518
+ this.originalContent = content;
517
519
  }
518
520
  listDependencies(graph) {
519
- return this.dependencies ??= listDependencies(graph, this);
521
+ if (this.dependencies) return this.dependencies;
522
+ const out = this.dependencies = [];
523
+ const scan = (obj, prefix = []) => {
524
+ for (const field of DEP_FIELDS) {
525
+ const table = obj[field];
526
+ if (!table) continue;
527
+ const tablePath = [...prefix, field];
528
+ for (const [key, spec] of Object.entries(table)) {
529
+ const { linked, range, setRange } = resolveLinkedDep(this, graph, tablePath, key, spec) ?? {};
530
+ out.push({
531
+ path: [...tablePath, key],
532
+ spec,
533
+ resolved: linked,
534
+ range,
535
+ setRange: setRange && ((v) => {
536
+ table[key] = setRange(v);
537
+ })
538
+ });
539
+ }
540
+ }
541
+ };
542
+ scan(this.data);
543
+ if (this.data.target) for (const [key, config] of Object.entries(this.data.target)) scan(config, ["target", key]);
544
+ if (this.data.workspace) scan(this.data.workspace);
545
+ return out;
520
546
  }
521
547
  patch(path, value) {
522
548
  this.content = edit(this.content, path, value);
523
549
  }
550
+ async write() {
551
+ if (this.content === this.originalContent) return;
552
+ await fs.writeFile(this.path, this.content);
553
+ }
524
554
  };
525
555
  var CargoPackage = class extends WorkspacePackage {
526
556
  path;
@@ -561,7 +591,6 @@ var CargoPackage = class extends WorkspacePackage {
561
591
  function cargo({ updateLockFile = true, bumpDep: getBumpDepType } = {}) {
562
592
  return {
563
593
  name: "cargo",
564
- enforce: "pre",
565
594
  async init() {
566
595
  await initToml();
567
596
  },
@@ -623,7 +652,7 @@ function cargo({ updateLockFile = true, bumpDep: getBumpDepType } = {}) {
623
652
  else updatedRange = resolved.version;
624
653
  setRange(updatedRange);
625
654
  }
626
- await Promise.all(Array.from(graph.files.values(), (file) => writeFile(file.path, file.content + "\n")));
655
+ await Promise.all(Array.from(graph.files.values(), (file) => file.write()));
627
656
  },
628
657
  async applyCliDraft() {
629
658
  if (!this.cargo || !updateLockFile) return;
@@ -691,7 +720,7 @@ async function isPackagePublished(name, version) {
691
720
  async function buildEntry(dir) {
692
721
  try {
693
722
  const filePath = path.join(dir, "Cargo.toml");
694
- const content = await readFile(filePath, "utf8");
723
+ const content = await fs.readFile(filePath, "utf8");
695
724
  return new CargoToml(filePath, content, assertCargoManifest(parse$1(content)));
696
725
  } catch {
697
726
  return;
@@ -736,32 +765,6 @@ async function expandWorkspaceMembers(cwd, members, exclude = []) {
736
765
  return item.endsWith(path.sep) ? item.slice(0, -1) : item;
737
766
  });
738
767
  }
739
- function listDependencies(graph, file) {
740
- const out = [];
741
- function scan(obj, prefix = []) {
742
- for (const field of DEP_FIELDS) {
743
- const table = obj[field];
744
- if (!table) continue;
745
- const tablePath = [...prefix, field];
746
- for (const [key, spec] of Object.entries(table)) {
747
- const { linked, range, setRange } = resolveLinkedDep(file, graph, tablePath, key, spec) ?? {};
748
- out.push({
749
- path: [...tablePath, key],
750
- spec,
751
- resolved: linked,
752
- range,
753
- setRange: setRange && ((v) => {
754
- table[key] = setRange(v);
755
- })
756
- });
757
- }
758
- }
759
- }
760
- scan(file.data);
761
- if (file.data.target) for (const [key, config] of Object.entries(file.data.target)) scan(config, ["target", key]);
762
- if (file.data.workspace) scan(file.data.workspace);
763
- return out;
764
- }
765
768
  function resolveLinkedDep(file, graph, tablePath, key, spec) {
766
769
  if (typeof spec === "string") {
767
770
  const linked = graph.packages.get(key);
@@ -1,4 +1,4 @@
1
- import { s as TegamiPlugin } from "../types-Kj7Nxbjz.js";
1
+ import { s as TegamiPlugin } from "../types-BMYzG4dR.js";
2
2
 
3
3
  //#region src/plugins/git.d.ts
4
4
  interface GitPluginOptions {
@@ -22,7 +22,6 @@ function git(options = {}) {
22
22
  }
23
23
  return {
24
24
  name: "git",
25
- enforce: "pre",
26
25
  async initCli() {
27
26
  if (!isCI()) return;
28
27
  const gitOptions = { nodeOptions: { cwd: this.cwd } };
@@ -43,9 +42,8 @@ function git(options = {}) {
43
42
  const { graph } = this;
44
43
  for (const [id, packagePlan] of plan.packages) {
45
44
  const pkg = graph.get(id);
46
- packagePlan.git ??= {};
47
- if (pkg.group?.options.syncGitTag && pkg.version) packagePlan.git.tag = `${pkg.group.name}@${pkg.version}`;
48
- else if (pkg.version) packagePlan.git.tag = `${pkg.name}@${pkg.version}`;
45
+ const git = packagePlan.git ??= {};
46
+ if (pkg.version) git.tag ??= pkg.group?.options.syncGitTag ? `${pkg.group.name}@${pkg.version}` : `${pkg.name}@${pkg.version}`;
49
47
  }
50
48
  },
51
49
  async resolvePlanStatus({ plan }) {
@@ -1,15 +1,15 @@
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/github.d.ts
6
6
  interface GithubRelease {
7
7
  /** Release title */
8
- title?: string;
8
+ title: string;
9
9
  /** Release notes */
10
- notes?: string;
10
+ notes: string;
11
11
  /** Whether to mark release as prerelease */
12
- prerelease?: boolean;
12
+ prerelease: boolean;
13
13
  }
14
14
  /** Options for creating GitHub releases after a successful publish. */
15
15
  interface GitHubPluginOptions extends GitPluginOptions {
@@ -33,12 +33,12 @@ interface GitHubPluginOptions extends GitPluginOptions {
33
33
  tag: string;
34
34
  pkg: WorkspacePackage;
35
35
  plan: PublishPlan;
36
- }) => Awaitable<GithubRelease>; /** Override release details when multiple packages share a git tag. */
36
+ }) => Awaitable<Partial<GithubRelease>>; /** Override release details when multiple packages share a git tag. */
37
37
  createGrouped?: (this: TegamiContext, opts: {
38
38
  tag: string;
39
39
  packages: WorkspacePackage[];
40
40
  plan: PublishPlan;
41
- }) => Awaitable<GithubRelease>;
41
+ }) => Awaitable<Partial<GithubRelease>>;
42
42
  };
43
43
  /**
44
44
  * (CLI only) Open a version pull 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 { 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";
@@ -35,9 +34,9 @@ async function releaseExistsByTag(repo, tag, token) {
35
34
  if (!response.ok) throw await fetchFailure(`Failed to get GitHub release for ${tag}`, response);
36
35
  return true;
37
36
  }
38
- async function createRelease(repo, options) {
39
- const { owner, repo: name } = parseGitHubRepo(repo);
40
- const response = await githubRequest(`/repos/${owner}/${name}/releases`, options.token, {
37
+ async function createRelease(options) {
38
+ const { owner, repo } = parseGitHubRepo(options.repo);
39
+ const response = await githubRequest(`/repos/${owner}/${repo}/releases`, options.token, {
41
40
  method: "POST",
42
41
  headers: { "Content-Type": "application/json" },
43
42
  body: JSON.stringify({
@@ -309,201 +308,112 @@ function parsePositiveInt(value, option) {
309
308
  /** Create GitHub releases for successfully published packages after the whole plan succeeds. */
310
309
  function github(options = {}) {
311
310
  const { release: releaseOptions = true } = options;
312
- let renderer;
313
- function getRenderer(context) {
314
- return renderer ??= createChangelogRenderer(context);
315
- }
316
- const versionRequests = onVersionRequest({
317
- name: "github",
318
- options: options.versionPr,
319
- canCreate(context) {
320
- const { repo, token } = context.github ?? {};
321
- return Boolean(repo && token);
322
- },
323
- async upsert(context, request, update) {
324
- const { repo, token } = context.github;
325
- const openPr = await findOpenPullRequest(repo, request.head, token);
326
- if (openPr === void 0) await createPullRequest(repo, {
327
- title: request.title,
328
- body: request.body,
329
- head: request.head,
330
- base: request.base,
331
- token
332
- });
333
- else if (update) await updatePullRequest(repo, openPr, {
334
- title: request.title,
335
- body: request.body,
336
- token
337
- });
338
- }
339
- });
340
- const plugin = {
341
- ...versionRequests,
342
- name: "github",
343
- init() {
344
- this.github = {
345
- repo: options.repo ?? process.env.GITHUB_REPOSITORY,
346
- token: options.token ?? process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN
347
- };
348
- },
349
- async resolvePlanStatus({ plan }) {
350
- if (versionRequests.resolvePlanStatus.call(this, { plan }) === "pending") return "pending";
351
- const { repo, token } = this.github;
352
- if (!repo || !token || releaseOptions === false) return;
353
- const requiredTags = /* @__PURE__ */ new Set();
354
- for (const pkg of plan.packages.values()) if (pkg.preflight.shouldPublish && pkg.git?.tag) requiredTags.add(pkg.git.tag);
355
- return Array.from(requiredTags, async (tag) => {
356
- if (!await releaseExistsByTag(repo, tag, token)) return "pending";
357
- });
358
- },
359
- async afterPublishAll({ plan }) {
360
- const { repo, token } = this.github;
361
- if (!repo || !token || releaseOptions === false) return;
362
- const { eager = false, create, createGrouped } = releaseOptions === true ? {} : releaseOptions;
363
- const groups = /* @__PURE__ */ new Map();
364
- for (const [id, { preflight, publishResult, git }] of plan.packages) {
365
- if (!eager && publishResult.type === "failed") return;
366
- const tag = git?.tag;
367
- if (!tag || !preflight.shouldPublish) continue;
368
- const pkg = this.graph.get(id);
369
- const group = groups.get(tag);
370
- if (group) group.push(pkg);
371
- else groups.set(tag, [pkg]);
372
- }
373
- await Promise.all(Array.from(groups, async ([tag, packages]) => {
374
- for (const member of packages) if (plan.packages.get(member.id).publishResult.type === "failed") return;
375
- if (await releaseExistsByTag(repo, tag, token)) return;
376
- let release;
377
- if (packages.length > 1) {
378
- const overrides = await createGrouped?.call(this, {
379
- tag,
380
- packages,
381
- plan
382
- }) ?? {};
383
- release = {
384
- title: overrides.title ?? tag,
385
- notes: overrides.notes ?? await defaultGroupedNotes(getRenderer(this), plan, packages),
386
- prerelease: overrides.prerelease ?? packages.some((pkg) => pkg.version && semver.prerelease(pkg.version))
387
- };
388
- } else {
389
- const pkg = packages[0];
390
- const overrides = await create?.call(this, {
391
- tag,
392
- pkg,
393
- plan
394
- }) ?? {};
395
- const packagePlan = plan.packages.get(pkg.id);
396
- release = {
397
- title: overrides.title ?? formatPackageVersion(pkg.name, pkg.version, packagePlan?.npm?.distTag),
398
- notes: overrides.notes ?? await defaultNotes(getRenderer(this), pkg, packagePlan),
399
- prerelease: overrides.prerelease ?? (pkg.version !== void 0 && semver.prerelease(pkg.version) !== null)
400
- };
311
+ let autoRelease;
312
+ return [
313
+ git(options),
314
+ {
315
+ name: "github",
316
+ init() {
317
+ const { repo, token } = this.github = {
318
+ repo: options.repo ?? process.env.GITHUB_REPOSITORY,
319
+ token: options.token ?? process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN
320
+ };
321
+ if (repo && token && releaseOptions !== false) {
322
+ const { eager = false, create, createGrouped } = releaseOptions === true ? {} : releaseOptions;
323
+ const resolveEntryMeta = cached((entry) => entry.id, async (entry) => {
324
+ const commit = await resolveFileCommit(this, entry.filename);
325
+ if (!commit) return {
326
+ commit,
327
+ pullRequests: []
328
+ };
329
+ return {
330
+ commit,
331
+ pullRequests: await listPullRequestsForCommit(repo, commit, token).catch(() => [])
332
+ };
333
+ });
334
+ autoRelease = createAutoRelease({
335
+ eager,
336
+ override: create,
337
+ overrideGroup: createGrouped,
338
+ async formatChangelog(entry) {
339
+ const meta = await resolveEntryMeta(entry);
340
+ const lines = [];
341
+ const commitSuffix = meta.commit ? ` ([${meta.commit.slice(0, 7)}](https://github.com/${repo}/commit/${meta.commit}))` : "";
342
+ for (const section of entry.sections) {
343
+ lines.push(`### ${section.title}${commitSuffix}`, "");
344
+ if (section.content) lines.push(section.content, "");
345
+ }
346
+ if (meta.pullRequests.length > 0) {
347
+ lines.push("<details>", "<summary>Pull request & contributors</summary>", "");
348
+ for (const pr of meta.pullRequests) {
349
+ let line = `- [#${pr.number} ${pr.title}](https://github.com/${repo}/pull/${pr.number})`;
350
+ if (pr.user) line += ` by @${pr.user.login}`;
351
+ lines.push(line);
352
+ }
353
+ lines.push("", "</details>");
354
+ }
355
+ return lines.join("\n").trim();
356
+ },
357
+ create({ input, packages, tag }) {
358
+ return createRelease({
359
+ ...input,
360
+ repo,
361
+ tag,
362
+ token,
363
+ prerelease: input.prerelease ?? packages.some((pkg) => pkg.version && semver.prerelease(pkg.version))
364
+ });
365
+ },
366
+ releaseExistsByTag(tag) {
367
+ return releaseExistsByTag(repo, tag, token);
368
+ }
369
+ });
401
370
  }
402
- await createRelease(repo, {
403
- tag,
404
- title: release.title,
405
- notes: release.notes,
406
- prerelease: release.prerelease,
371
+ },
372
+ async resolvePlanStatus({ plan }) {
373
+ if (await autoRelease?.hasPending.call(this, plan)) return "pending";
374
+ },
375
+ async afterPublishAll({ plan }) {
376
+ await autoRelease?.create.call(this, plan);
377
+ },
378
+ async initCli(cli) {
379
+ registerPrCli(cli);
380
+ if (!isCI()) return;
381
+ const { repo, token } = this.github ?? {};
382
+ if (!token || !repo) return;
383
+ const result = await x("git", [
384
+ "remote",
385
+ "set-url",
386
+ "origin",
387
+ `https://x-access-token:${token}@github.com/${repo}.git`
388
+ ], { nodeOptions: { cwd: this.cwd } });
389
+ if (result.exitCode !== 0) throw execFailure("Failed to configure git remote for GitHub Actions.", result);
390
+ }
391
+ },
392
+ versionRequestPlugin({
393
+ name: "github",
394
+ options: options.versionPr,
395
+ canCreate(context) {
396
+ const { repo, token } = context.github ?? {};
397
+ return Boolean(repo && token);
398
+ },
399
+ async upsert(context, request, update) {
400
+ const { repo, token } = context.github;
401
+ const openPr = await findOpenPullRequest(repo, request.head, token);
402
+ if (openPr === void 0) await createPullRequest(repo, {
403
+ title: request.title,
404
+ body: request.body,
405
+ head: request.head,
406
+ base: request.base,
407
407
  token
408
408
  });
409
- }));
410
- },
411
- async initCli(cli) {
412
- registerPrCli(cli);
413
- if (!isCI()) return;
414
- const { repo, token } = this.github ?? {};
415
- if (!token || !repo) return;
416
- const result = await x("git", [
417
- "remote",
418
- "set-url",
419
- "origin",
420
- `https://x-access-token:${token}@github.com/${repo}.git`
421
- ], { nodeOptions: { cwd: this.cwd } });
422
- if (result.exitCode !== 0) throw execFailure("Failed to configure git remote for GitHub Actions.", result);
423
- }
424
- };
425
- return [git(options), plugin];
426
- }
427
- function createChangelogRenderer(context) {
428
- const { repo, token } = context.github;
429
- const resolveFileCommit = cached((filename) => filename, async (filename) => {
430
- const result = await x("git", [
431
- "log",
432
- "--diff-filter=A",
433
- "-1",
434
- "--format=%H",
435
- "--",
436
- relative(context.cwd, join(context.changelogDir, filename))
437
- ], { nodeOptions: { cwd: context.cwd } });
438
- if (result.exitCode !== 0) return;
439
- return result.stdout.trim() || void 0;
440
- });
441
- const resolveEntryMeta = cached((entry) => entry.id, async (entry) => {
442
- const commit = await resolveFileCommit(entry.filename);
443
- if (!commit || !repo) return {
444
- commit,
445
- pullRequests: []
446
- };
447
- return {
448
- commit,
449
- pullRequests: await listPullRequestsForCommit(repo, commit, token).catch(() => [])
450
- };
451
- });
452
- function formatEntryDetails(meta) {
453
- if (meta.pullRequests.length === 0) return;
454
- const lines = [];
455
- for (const pr of meta.pullRequests) {
456
- let line = repo ? `- [#${pr.number} ${pr.title}](https://github.com/${repo}/pull/${pr.number})` : `- #${pr.number} ${pr.title}`;
457
- if (pr.user) line += ` by @${pr.user.login}`;
458
- lines.push(line);
459
- }
460
- return [
461
- "<details>",
462
- "<summary>Pull request & contributors</summary>",
463
- "",
464
- ...lines,
465
- "",
466
- "</details>"
467
- ].join("\n");
468
- }
469
- return async (entry) => {
470
- const meta = await resolveEntryMeta(entry);
471
- let commitSuffix = "";
472
- if (meta.commit) {
473
- const short = meta.commit.slice(0, 7);
474
- const link = repo ? `[${short}](https://github.com/${repo}/commit/${meta.commit})` : `\`${short}\``;
475
- commitSuffix += ` (${link})`;
476
- }
477
- const lines = [];
478
- for (const section of entry.sections) {
479
- lines.push(`### ${section.title}${commitSuffix}`, "");
480
- if (section.content) lines.push(section.content, "");
481
- }
482
- const details = formatEntryDetails(meta);
483
- if (details) lines.push(details);
484
- return lines.join("\n").trim();
485
- };
486
- }
487
- async function defaultNotes(renderer, pkg, packagePlan) {
488
- if (packagePlan && packagePlan.changelogs.length > 0) return (await Promise.all(packagePlan.changelogs.map(renderer))).join("\n\n");
489
- return `Published ${formatPackageVersion(pkg.name, pkg.version, packagePlan?.npm?.distTag)}.`;
490
- }
491
- async function defaultGroupedNotes(renderer, plan, packages) {
492
- const changelogs = /* @__PURE__ */ new Map();
493
- for (const pkg of packages) {
494
- const packagePlan = plan.packages.get(pkg.id);
495
- if (!packagePlan) continue;
496
- for (const entry of packagePlan.changelogs) changelogs.set(entry.id, entry);
497
- }
498
- const sections = [packages.map((pkg) => {
499
- const packagePlan = plan.packages.get(pkg.id);
500
- return `- ${formatPackageVersion(pkg.name, pkg.version, packagePlan?.npm?.distTag)}`;
501
- }).join("\n")];
502
- if (changelogs.size > 0) {
503
- const notes = await Promise.all(Array.from(changelogs.values(), renderer));
504
- sections.push("", notes.join("\n\n"));
505
- }
506
- return sections.join("\n");
409
+ else if (update) await updatePullRequest(repo, openPr, {
410
+ title: request.title,
411
+ body: request.body,
412
+ token
413
+ });
414
+ }
415
+ })
416
+ ];
507
417
  }
508
418
  //#endregion
509
419
  export { github };