tegami 0.1.4 → 0.1.6

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.
@@ -0,0 +1,109 @@
1
+ import { r as handlePluginError } from "./error-DNy8R5ue.js";
2
+ import { n as jsonCodec, t as bumpTypeSchema } from "./schemas-CurBAaW5.js";
3
+ import z$1 from "zod";
4
+ import { dump } from "js-yaml";
5
+ import { readFile } from "fs/promises";
6
+ //#region src/changelog/shared.ts
7
+ const changelogPackageConfigSchema = z$1.object({
8
+ type: bumpTypeSchema.optional(),
9
+ replay: z$1.array(z$1.string().min(1)).optional()
10
+ });
11
+ const changelogFrontmatterSchema = z$1.object({
12
+ subject: z$1.string().optional(),
13
+ packages: z$1.union([z$1.array(z$1.string()), z$1.record(z$1.string(), z$1.union([
14
+ bumpTypeSchema,
15
+ z$1.null(),
16
+ changelogPackageConfigSchema
17
+ ]))]).optional()
18
+ });
19
+ function renderChangelog(frontmatter, body) {
20
+ return [
21
+ "---",
22
+ dump(frontmatter).trim(),
23
+ "---",
24
+ "",
25
+ body.trim(),
26
+ ""
27
+ ].join("\n");
28
+ }
29
+ //#endregion
30
+ //#region src/plans/store.ts
31
+ const packagePlanStoreSchema = z$1.object({
32
+ type: bumpTypeSchema.optional(),
33
+ changelogIds: z$1.array(z$1.string()).optional(),
34
+ bumpReasons: z$1.array(z$1.string()).optional(),
35
+ npm: z$1.object({ distTag: z$1.string().optional() }).optional(),
36
+ publish: z$1.boolean()
37
+ });
38
+ /** the persisted plan data for actual publishing */
39
+ const planStoreSchema = jsonCodec(z$1.object({
40
+ id: z$1.string(),
41
+ createdAt: z$1.iso.datetime(),
42
+ version: z$1.literal("0.0.0").default("0.0.0"),
43
+ /** release note entries */
44
+ changelogs: z$1.record(z$1.string(), z$1.object({
45
+ filename: z$1.string(),
46
+ content: z$1.string()
47
+ })),
48
+ /** package id -> package info */
49
+ packages: z$1.record(z$1.string(), packagePlanStoreSchema)
50
+ }));
51
+ function createPlanStore(draft, context) {
52
+ const store = {
53
+ version: "0.0.0",
54
+ id: `tegami-${Date.now().toString(36)}`,
55
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
56
+ changelogs: {},
57
+ packages: {}
58
+ };
59
+ for (const entry of draft.getChangelogs()) store.changelogs[entry.id] = {
60
+ filename: entry.filename,
61
+ content: entry.getRawContent()
62
+ };
63
+ for (const pkg of context.graph.getPackages()) {
64
+ const plan = draft.getPackagePlan(pkg.id);
65
+ if (plan) store.packages[pkg.id] = {
66
+ publish: plan.publish ?? false,
67
+ type: plan.type,
68
+ npm: plan.npm,
69
+ changelogIds: plan.changelogs?.map((entry) => entry.id),
70
+ bumpReasons: plan.bumpReasons ? Array.from(plan.bumpReasons) : void 0
71
+ };
72
+ }
73
+ return planStoreSchema.encode(store);
74
+ }
75
+ async function readPlanStore(context) {
76
+ try {
77
+ return planStoreSchema.decode(await readFile(context.planPath, "utf8"));
78
+ } catch {}
79
+ }
80
+ //#endregion
81
+ //#region src/plans/checks.ts
82
+ async function publishPlanStatus(store, context) {
83
+ async function defaultStatus() {
84
+ try {
85
+ await Promise.all(Object.entries(store.packages).map(async ([id, plan]) => {
86
+ const pkg = context.graph.get(id);
87
+ if (!pkg || !plan.publish) return;
88
+ if (!await context.getRegistryClient(pkg).isPackagePublished(pkg)) throw "pending";
89
+ }));
90
+ return { state: "success" };
91
+ } catch (err) {
92
+ if (err === "pending") return { state: "pending" };
93
+ throw err;
94
+ }
95
+ }
96
+ let status = await defaultStatus();
97
+ for (const plugin of context.plugins) {
98
+ const resolved = await handlePluginError(plugin, "resolvePlanStatus", () => plugin.resolvePlanStatus?.call(context, status, { plan: store }));
99
+ if (resolved) status = resolved;
100
+ }
101
+ return status;
102
+ }
103
+ async function assertPublishPlanFinished(context) {
104
+ const store = await readPlanStore(context);
105
+ if (!store) return;
106
+ if ((await publishPlanStatus(store, context)).state === "pending") throw new Error(`Publish plan already exists at ${context.planPath} and is pending. Publish it before applying a new plan.`);
107
+ }
108
+ //#endregion
109
+ export { changelogFrontmatterSchema as a, readPlanStore as i, publishPlanStatus as n, renderChangelog as o, createPlanStore as r, assertPublishPlanFinished as t };
@@ -1,4 +1,4 @@
1
- import { k as DraftPlan, t as Awaitable, v as Tegami, w as PublishResult } from "../types-BXk2fMqa.js";
1
+ import { k as DraftPlan, t as Awaitable, v as Tegami, w as PublishResult } from "../types-DexeJdl7.js";
2
2
  import { Command } from "commander";
3
3
 
4
4
  //#region src/cli/index.d.ts
package/dist/cli/index.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import { r as formatNpmDistTag } from "../semver-C4vJ4SK8.js";
2
- import { a as changelogFilename, l as renderChangelog, s as generateReplays, t as assertPublishPlanFinished } from "../checks-Cwz-Ezkq.js";
2
+ import { r as generateReplays, t as changelogFilename } from "../generate-B3bcuKLY.js";
3
3
  import { a as isCI, n as execFailure, r as handlePluginError, t as CancelledError } from "../error-DNy8R5ue.js";
4
+ import { o as renderChangelog, t as assertPublishPlanFinished } from "../checks-azjuIFt7.js";
4
5
  import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
5
6
  import path, { basename, isAbsolute, join, normalize, relative } from "node:path";
6
7
  import { x } from "tinyexec";
8
+ import z$1 from "zod";
7
9
  import { resolveCommand } from "package-manager-detector";
8
10
  import { autocompleteMultiselect, confirm, intro, isCancel, multiline, note, outro, select, spinner } from "@clack/prompts";
9
11
  import { Command, InvalidArgumentError } from "commander";
@@ -318,12 +320,19 @@ async function buildPrPreview(context, draft, options = {}) {
318
320
  }
319
321
  async function postPrComment(body) {
320
322
  const repo = process.env.GITHUB_REPOSITORY;
321
- if (!repo) throw new Error("GITHUB_REPOSITORY is required.");
322
- const number = await readPullRequestNumberFromWorkflowRunEvent();
323
+ if (!repo) {
324
+ outro("GITHUB_REPOSITORY is required.");
325
+ return;
326
+ }
327
+ const pr = await readPullRequestFromWorkflowRunEvent();
328
+ if (!pr.found) {
329
+ outro(pr.reason);
330
+ return;
331
+ }
323
332
  const markedBody = `${COMMENT_MARKER}\n${body}`;
324
333
  const listResult = await x("gh", [
325
334
  "api",
326
- `repos/${repo}/issues/${number}/comments`,
335
+ `repos/${repo}/issues/${pr.number}/comments`,
327
336
  "--paginate",
328
337
  "--jq",
329
338
  `[.[] | select(.body | startswith("${COMMENT_MARKER}")) | .id][0] // empty`
@@ -355,7 +364,7 @@ async function postPrComment(body) {
355
364
  const createResult = await x("gh", [
356
365
  "pr",
357
366
  "comment",
358
- String(number),
367
+ String(pr.number),
359
368
  "--body",
360
369
  markedBody,
361
370
  "--repo",
@@ -363,22 +372,35 @@ async function postPrComment(body) {
363
372
  ]);
364
373
  if (createResult.exitCode !== 0) throw execFailure("Failed to create pull request comment.", createResult);
365
374
  }
366
- async function readPullRequestNumberFromWorkflowRunEvent() {
375
+ const eventSchema = z$1.looseObject({ workflow_run: z$1.looseObject({
376
+ event: z$1.literal("pull_request", { error: "The preview workflow was not triggered by a pull request." }),
377
+ conclusion: z$1.literal("success", { error: "The preview workflow did not complete successfully." }),
378
+ pull_requests: z$1.array(z$1.looseObject({ number: z$1.int() }), { error: "The preview workflow is not associated with a pull request." }).min(1)
379
+ }, { error: "A workflow_run event is required." }) });
380
+ async function readPullRequestFromWorkflowRunEvent() {
367
381
  const eventPath = process.env.GITHUB_EVENT_PATH;
368
- if (!eventPath) throw new Error("GITHUB_EVENT_PATH is required.");
369
- let event;
382
+ if (!eventPath) return {
383
+ found: false,
384
+ reason: "GITHUB_EVENT_PATH is required."
385
+ };
386
+ let raw;
370
387
  try {
371
- event = JSON.parse(await readFile(eventPath, "utf8"));
388
+ raw = JSON.parse(await readFile(eventPath, "utf8"));
372
389
  } catch {
373
- throw new Error("Failed to read workflow_run event.");
390
+ return {
391
+ found: false,
392
+ reason: "Failed to read workflow_run event."
393
+ };
374
394
  }
375
- const workflowRun = event.workflow_run;
376
- if (!workflowRun) throw new Error("A workflow_run event is required.");
377
- if (workflowRun.event !== "pull_request") throw new Error("The preview workflow was not triggered by a pull request.");
378
- if (workflowRun.conclusion !== "success") throw new Error("The preview workflow did not complete successfully.");
379
- const number = workflowRun.pull_requests?.[0]?.number;
380
- if (!Number.isInteger(number) || !number || number <= 0) throw new Error("The preview workflow is not associated with a pull request.");
381
- return number;
395
+ const { error, data } = eventSchema.safeParse(raw);
396
+ if (error) return {
397
+ found: false,
398
+ reason: z$1.prettifyError(error)
399
+ };
400
+ return {
401
+ found: true,
402
+ number: data.workflow_run.pull_requests[0].number
403
+ };
382
404
  }
383
405
  async function resolvePullRequest(context, options) {
384
406
  const repo = context.github?.repo ?? process.env.GITHUB_REPOSITORY;
@@ -564,7 +586,8 @@ async function publishPackages(tegami, options) {
564
586
  }).join("\n"), dryRun ? "Publish dry run" : "Publish result");
565
587
  if (result.state === "failed") {
566
588
  process.exitCode = 1;
567
- outro("Some packages failed to publish.");
589
+ if (result.error) note(result.error, "Error when publishing");
590
+ outro("Failed to publish.");
568
591
  return false;
569
592
  }
570
593
  outro(dryRun ? "Publish plan is valid." : "Packages published.");
@@ -1,13 +1,10 @@
1
1
  import { a as maxBump, t as bumpDepth } from "./semver-C4vJ4SK8.js";
2
- import { n as execFailure, r as handlePluginError } from "./error-DNy8R5ue.js";
3
- import { n as jsonCodec, t as bumpTypeSchema } from "./schemas-CurBAaW5.js";
2
+ import { n as execFailure } from "./error-DNy8R5ue.js";
3
+ import { o as renderChangelog } from "./checks-azjuIFt7.js";
4
4
  import { mkdir, writeFile } from "node:fs/promises";
5
5
  import { join } from "node:path";
6
6
  import { x } from "tinyexec";
7
7
  import * as semver from "semver";
8
- import z$1 from "zod";
9
- import { dump } from "js-yaml";
10
- import { readFile as readFile$1 } from "fs/promises";
11
8
  //#region src/utils/conventional-commit.ts
12
9
  /**
13
10
  * Conventional commit header per conventionalcommits.org and semantic-release defaults.
@@ -73,30 +70,6 @@ function conventionalCommitToBump(type, breaking) {
73
70
  }
74
71
  }
75
72
  //#endregion
76
- //#region src/changelog/shared.ts
77
- const changelogPackageConfigSchema = z$1.object({
78
- type: bumpTypeSchema.optional(),
79
- replay: z$1.array(z$1.string().min(1)).optional()
80
- });
81
- const changelogFrontmatterSchema = z$1.object({
82
- subject: z$1.string().optional(),
83
- packages: z$1.union([z$1.array(z$1.string()), z$1.record(z$1.string(), z$1.union([
84
- bumpTypeSchema,
85
- z$1.null(),
86
- changelogPackageConfigSchema
87
- ]))]).optional()
88
- });
89
- function renderChangelog(frontmatter, body) {
90
- return [
91
- "---",
92
- dump(frontmatter).trim(),
93
- "---",
94
- "",
95
- body.trim(),
96
- ""
97
- ].join("\n");
98
- }
99
- //#endregion
100
73
  //#region src/changelog/generate.ts
101
74
  async function generateChangelog(context, options = {}) {
102
75
  const write = options.write ?? true;
@@ -195,83 +168,4 @@ function changelogFilename(disambiguator = 0) {
195
168
  return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}-${(Date.now() + disambiguator).toString(36)}.md`;
196
169
  }
197
170
  //#endregion
198
- //#region src/plans/store.ts
199
- const packagePlanStoreSchema = z$1.object({
200
- type: bumpTypeSchema.optional(),
201
- changelogIds: z$1.array(z$1.string()).optional(),
202
- bumpReasons: z$1.array(z$1.string()).optional(),
203
- npm: z$1.object({ distTag: z$1.string().optional() }).optional(),
204
- publish: z$1.boolean()
205
- });
206
- /** the persisted plan data for actual publishing */
207
- const planStoreSchema = jsonCodec(z$1.object({
208
- id: z$1.string(),
209
- createdAt: z$1.iso.datetime(),
210
- version: z$1.literal("0.0.0").default("0.0.0"),
211
- /** release note entries */
212
- changelogs: z$1.record(z$1.string(), z$1.object({
213
- filename: z$1.string(),
214
- content: z$1.string()
215
- })),
216
- /** package id -> package info */
217
- packages: z$1.record(z$1.string(), packagePlanStoreSchema)
218
- }));
219
- function createPlanStore(draft, context) {
220
- const store = {
221
- version: "0.0.0",
222
- id: `tegami-${Date.now().toString(36)}`,
223
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
224
- changelogs: {},
225
- packages: {}
226
- };
227
- for (const entry of draft.getChangelogs()) store.changelogs[entry.id] = {
228
- filename: entry.filename,
229
- content: entry.getRawContent()
230
- };
231
- for (const pkg of context.graph.getPackages()) {
232
- const plan = draft.getPackagePlan(pkg.id);
233
- if (plan) store.packages[pkg.id] = {
234
- publish: plan.publish ?? false,
235
- type: plan.type,
236
- npm: plan.npm,
237
- changelogIds: plan.changelogs?.map((entry) => entry.id),
238
- bumpReasons: plan.bumpReasons ? Array.from(plan.bumpReasons) : void 0
239
- };
240
- }
241
- return planStoreSchema.encode(store);
242
- }
243
- async function readPlanStore(context) {
244
- try {
245
- return planStoreSchema.decode(await readFile$1(context.planPath, "utf8"));
246
- } catch {}
247
- }
248
- //#endregion
249
- //#region src/plans/checks.ts
250
- async function publishPlanStatus(store, context) {
251
- async function defaultStatus() {
252
- try {
253
- await Promise.all(Object.entries(store.packages).map(async ([id, plan]) => {
254
- const pkg = context.graph.get(id);
255
- if (!pkg || !plan.publish) return;
256
- if (!await context.getRegistryClient(pkg).isPackagePublished(pkg)) throw "pending";
257
- }));
258
- return { state: "success" };
259
- } catch (err) {
260
- if (err === "pending") return { state: "pending" };
261
- throw err;
262
- }
263
- }
264
- let status = await defaultStatus();
265
- for (const plugin of context.plugins) {
266
- const resolved = await handlePluginError(plugin, "resolvePlanStatus", () => plugin.resolvePlanStatus?.call(context, status, { plan: store }));
267
- if (resolved) status = resolved;
268
- }
269
- return status;
270
- }
271
- async function assertPublishPlanFinished(context) {
272
- const store = await readPlanStore(context);
273
- if (!store) return;
274
- if ((await publishPlanStatus(store, context)).state === "pending") throw new Error(`Publish plan already exists at ${context.planPath} and is pending. Publish it before applying a new plan.`);
275
- }
276
- //#endregion
277
- export { changelogFilename as a, changelogFrontmatterSchema as c, readPlanStore as i, renderChangelog as l, publishPlanStatus as n, generateChangelog as o, createPlanStore as r, generateReplays as s, assertPublishPlanFinished as t };
171
+ export { generateChangelog as n, generateReplays as r, changelogFilename as t };
@@ -1,4 +1,4 @@
1
- import { r as LogGenerator } from "../types-BXk2fMqa.js";
1
+ import { r as LogGenerator } from "../types-DexeJdl7.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 PackagePlan, C as PublishOptions, D as PackageGroup, E as PackageGraph, O as WorkspacePackage, S as PackagePublishResult, a as PublishPreflight, b as GenerateChangelogOptions, c as TegamiPlugin, i as PackageOptions, k as DraftPlan, l as TegamiPluginOption, n as GroupOptions, o as RegistryClient, r as LogGenerator, s as TegamiOptions, v as Tegami, w as PublishResult, x as GeneratedChangelog, y as tegami } from "./types-BXk2fMqa.js";
1
+ import { A as PackagePlan, C as PublishOptions, D as PackageGroup, E as PackageGraph, O as WorkspacePackage, S as PackagePublishResult, a as PublishPreflight, b as GenerateChangelogOptions, c as TegamiPlugin, i as PackageOptions, k as DraftPlan, l as TegamiPluginOption, n as GroupOptions, o as RegistryClient, r as LogGenerator, s as TegamiOptions, v as Tegami, w as PublishResult, x as GeneratedChangelog, y as tegami } from "./types-DexeJdl7.js";
2
2
  export { type DraftPlan, type GenerateChangelogOptions, type GeneratedChangelog, type GroupOptions, type LogGenerator, type PackageGraph, type PackageGroup, type PackageOptions, type PackagePlan, type PackagePublishResult, type PublishOptions, type PublishPreflight, type PublishResult, type RegistryClient, Tegami, type TegamiOptions, type TegamiPlugin, type TegamiPluginOption, type WorkspacePackage, tegami };
package/dist/index.js CHANGED
@@ -1,16 +1,15 @@
1
1
  import { a as maxBump } from "./semver-C4vJ4SK8.js";
2
- import { c as changelogFrontmatterSchema, i as readPlanStore, n as publishPlanStatus, o as generateChangelog, r as createPlanStore, t as assertPublishPlanFinished } from "./checks-Cwz-Ezkq.js";
2
+ import { n as generateChangelog } from "./generate-B3bcuKLY.js";
3
3
  import { r as handlePluginError } from "./error-DNy8R5ue.js";
4
+ import { i as readPlanStore, n as publishPlanStatus, r as createPlanStore, t as assertPublishPlanFinished } from "./checks-azjuIFt7.js";
4
5
  import { t as PackageGraph } from "./graph-DLKPUXSD.js";
5
6
  import { cargo } from "./providers/cargo.js";
6
7
  import { npm } from "./providers/npm.js";
7
8
  import { simpleGenerator } from "./generators/simple.js";
8
- import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
9
- import path, { basename, dirname, join } from "node:path";
9
+ import { a as readChangelogEntries, i as parseReplayCondition, r as publishFromPlan } from "./publish-DkRT0yh6.js";
10
+ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
11
+ import path, { dirname, join } from "node:path";
10
12
  import * as semver from "semver";
11
- import { dump, load } from "js-yaml";
12
- import { fromMarkdown } from "mdast-util-from-markdown";
13
- import { toMarkdown } from "mdast-util-to-markdown";
14
13
  //#region src/context.ts
15
14
  async function createTegamiContext(options = {}) {
16
15
  const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd();
@@ -75,141 +74,6 @@ function resolvePlugins(plugins = []) {
75
74
  return plugins.flat(Infinity).sort((a, b) => PLUGIN_ORDER[a.enforce ?? "default"] - PLUGIN_ORDER[b.enforce ?? "default"]);
76
75
  }
77
76
  //#endregion
78
- //#region src/utils/frontmatter.ts
79
- /**
80
- * Inspired by https://github.com/jonschlinkert/gray-matter
81
- */
82
- const regex = /^---\r?\n(.+?)\r?\n---\r?\n?/s;
83
- /**
84
- * parse frontmatter, it supports only yaml format
85
- */
86
- function frontmatter(input) {
87
- const output = {
88
- matter: "",
89
- data: {},
90
- content: input
91
- };
92
- const match = regex.exec(input);
93
- if (!match) return output;
94
- output.matter = match[0];
95
- output.content = input.slice(match[0].length);
96
- output.data = load(match[1]) ?? {};
97
- return output;
98
- }
99
- //#endregion
100
- //#region src/changelog/parse.ts
101
- async function getChangelogFiles(context) {
102
- return (await readdir(context.changelogDir).catch(() => [])).filter((file) => file.endsWith(".md"));
103
- }
104
- async function readChangelogEntries(context) {
105
- const dir = context.changelogDir;
106
- const files = await getChangelogFiles(context);
107
- return (await Promise.all(files.map(async (file) => {
108
- const filePath = join(dir, file);
109
- const content = await readFile(filePath, "utf8");
110
- return parseChangelogFile(basename(filePath), content);
111
- }))).filter((v) => v !== void 0);
112
- }
113
- /** Parse one changelog markdown file into release entries. */
114
- function parseChangelogFile(filename, content) {
115
- const parsed = frontmatter(content);
116
- const { success, data } = changelogFrontmatterSchema.safeParse(parsed.data);
117
- if (!success || !data.packages) return;
118
- const tree = fromMarkdown(parsed.content);
119
- let headingBump;
120
- const packages = /* @__PURE__ */ new Map();
121
- const sections = [];
122
- for (const section of getHeadingSections(tree)) {
123
- const sectionBumpType = headingToBump(section.heading.depth);
124
- if (sectionBumpType) headingBump = headingBump ? maxBump(headingBump, sectionBumpType) : sectionBumpType;
125
- sections.push({
126
- depth: section.heading.depth,
127
- title: sectionToMarkdown(section.heading.children),
128
- content: sectionToMarkdown(section.children)
129
- });
130
- }
131
- if (sections.length === 0) return;
132
- if (Array.isArray(data.packages)) {
133
- if (!headingBump) return;
134
- for (const pkg of data.packages) packages.set(pkg, { type: headingBump });
135
- } else for (const [k, v] of Object.entries(data.packages)) {
136
- let config;
137
- if (typeof v === "string") config = { type: v };
138
- else if (v === null) config = { type: headingBump };
139
- else config = v;
140
- if (config.type || config.replay?.length) packages.set(k, config);
141
- }
142
- if (packages.size === 0) return;
143
- const entry = {
144
- id: filename,
145
- filename,
146
- subject: data.subject,
147
- packages,
148
- sections,
149
- _raw_body: parsed.content,
150
- getRawContent() {
151
- return [
152
- "---",
153
- dump({
154
- subject: this.subject,
155
- packages: Object.fromEntries(this.packages.entries())
156
- }).trim(),
157
- "---",
158
- "",
159
- entry._raw_body.trim(),
160
- ""
161
- ].join("\n");
162
- }
163
- };
164
- return entry;
165
- }
166
- function parseReplayCondition(condition) {
167
- if (condition.startsWith("exit prerelease:")) return {
168
- type: "on-exit-prerelease",
169
- name: condition.slice(16).trimStart()
170
- };
171
- const idx = condition.lastIndexOf("@");
172
- if (idx <= 0) return null;
173
- return {
174
- type: "on-version",
175
- name: condition.slice(0, idx),
176
- version: condition.slice(idx + 1)
177
- };
178
- }
179
- function getHeadingSections(tree) {
180
- const sections = [];
181
- let current;
182
- for (const child of tree.children) {
183
- if (child.type === "heading") {
184
- current = {
185
- heading: child,
186
- children: []
187
- };
188
- sections.push(current);
189
- continue;
190
- }
191
- current?.children.push(child);
192
- }
193
- return sections;
194
- }
195
- function sectionToMarkdown(children) {
196
- if (children.length === 0) return "";
197
- return toMarkdown({
198
- type: "root",
199
- children
200
- }, {
201
- bullet: "-",
202
- fence: "`"
203
- }).trim();
204
- }
205
- function headingToBump(depth) {
206
- switch (depth) {
207
- case 1: return "major";
208
- case 2: return "minor";
209
- case 3: return "patch";
210
- }
211
- }
212
- //#endregion
213
77
  //#region src/plans/policy.ts
214
78
  function groupPolicy({ graph }) {
215
79
  return {
@@ -427,136 +291,6 @@ function attachChangelog(plan, entry) {
427
291
  plan.changelogs.push(entry);
428
292
  }
429
293
  //#endregion
430
- //#region src/publish.ts
431
- async function resolvePublishTargets(context, store) {
432
- const targets = [];
433
- const preflightPromises = [];
434
- for (const [id, plan] of Object.entries(store.packages)) {
435
- if (!plan.publish) continue;
436
- const pkg = context.graph.get(id);
437
- if (!pkg) continue;
438
- targets.push(pkg.id);
439
- preflightPromises.push(context.getRegistryClient(pkg).publishPreflight?.(pkg, {
440
- store,
441
- packageStore: plan
442
- }));
443
- }
444
- const preflights = await Promise.all(preflightPromises);
445
- const children = /* @__PURE__ */ new Map();
446
- for (let i = 0; i < targets.length; i++) {
447
- const id = targets[i];
448
- children.set(id, preflights[i]?.wait);
449
- }
450
- const ordered = [];
451
- function scan(id, stack = /* @__PURE__ */ new Set()) {
452
- if (stack.has(id)) throw new Error(`circular reference of deps: ${[...stack, id].join(" -> ")}`);
453
- if (ordered.includes(id)) return;
454
- const deps = children.get(id);
455
- if (deps) {
456
- stack.add(id);
457
- for (const dep of deps) scan(dep, stack);
458
- stack.delete(id);
459
- }
460
- ordered.push(id);
461
- }
462
- for (const id of targets) scan(id);
463
- return ordered;
464
- }
465
- async function publishFromPlan(context, store, options) {
466
- const { dryRun = false } = options;
467
- const packages = [];
468
- if ((await publishPlanStatus(store, context)).state !== "pending") return { state: "skipped" };
469
- const orderedIds = await resolvePublishTargets(context, store);
470
- const parsedChangelogs = /* @__PURE__ */ new Map();
471
- for (const [id, entry] of Object.entries(store.changelogs)) {
472
- const parsed = parseChangelogFile(entry.filename, entry.content);
473
- if (!parsed) continue;
474
- parsedChangelogs.set(id, parsed);
475
- }
476
- for (const id of orderedIds) {
477
- const plan = store.packages[id];
478
- const pkg = context.graph.get(id);
479
- const registryClient = context.getRegistryClient(pkg);
480
- const changelogs = [];
481
- for (const id of plan.changelogIds ?? []) {
482
- const entry = parsedChangelogs.get(id);
483
- if (entry) changelogs.push(entry);
484
- }
485
- if (!dryRun) {
486
- if (await registryClient.isPackagePublished(pkg)) {
487
- packages.push({
488
- id: pkg.id,
489
- name: pkg.name,
490
- version: pkg.version,
491
- npm: plan.npm,
492
- state: "success",
493
- changelogs
494
- });
495
- continue;
496
- }
497
- } else {
498
- packages.push({
499
- id: pkg.id,
500
- name: pkg.name,
501
- version: pkg.version,
502
- npm: plan.npm,
503
- state: "success",
504
- changelogs
505
- });
506
- continue;
507
- }
508
- try {
509
- let result;
510
- for (const plugin of context.plugins) {
511
- const next = await handlePluginError(plugin, "willPublish", () => plugin.willPublish?.call(context, { pkg }));
512
- if (next !== void 0) {
513
- result = next;
514
- break;
515
- }
516
- }
517
- if (result === void 0) {
518
- await registryClient.publish(pkg, {
519
- packageStore: plan,
520
- store
521
- });
522
- result = {
523
- id: pkg.id,
524
- name: pkg.name,
525
- version: pkg.version,
526
- npm: plan.npm,
527
- state: "success",
528
- changelogs
529
- };
530
- }
531
- if (result === false) continue;
532
- for (const plugin of context.plugins) {
533
- const next = await handlePluginError(plugin, "afterPublish", () => plugin.afterPublish?.call(context, {
534
- pkg,
535
- result
536
- }));
537
- if (next) result = next;
538
- }
539
- packages.push(result);
540
- } catch (error) {
541
- packages.push({
542
- id: pkg.id,
543
- name: pkg.name,
544
- version: pkg.version,
545
- npm: plan.npm,
546
- changelogs,
547
- state: "failed",
548
- error: error instanceof Error ? error.message : String(error)
549
- });
550
- }
551
- }
552
- if (packages.length === 0) return { state: "skipped" };
553
- return {
554
- state: packages.some((pkg) => pkg.state === "failed") ? "failed" : "created",
555
- packages,
556
- _rawPlan: store
557
- };
558
- }
559
- //#endregion
560
294
  //#region src/index.ts
561
295
  /** Create a Tegami project handle. */
562
296
  function tegami(options = {}) {
@@ -1,4 +1,4 @@
1
- import { c as TegamiPlugin } from "../types-BXk2fMqa.js";
1
+ import { c as TegamiPlugin } from "../types-DexeJdl7.js";
2
2
 
3
3
  //#region src/plugins/git.d.ts
4
4
  interface GitPluginOptions {
@@ -1,4 +1,5 @@
1
1
  import { a as isCI, n as execFailure } from "../error-DNy8R5ue.js";
2
+ import { n as publishError, t as packagePublishError } from "../publish-DkRT0yh6.js";
2
3
  import { x } from "tinyexec";
3
4
  //#region src/plugins/git.ts
4
5
  /**
@@ -37,37 +38,44 @@ function git(options = {}) {
37
38
  } },
38
39
  async afterPublishAll(result) {
39
40
  const { cwd, publishOptions: { dryRun = false } } = this;
40
- if (dryRun || !createTags || result.state === "skipped") return result;
41
- const pendingTags = /* @__PURE__ */ new Set();
41
+ if (dryRun || !createTags || result.state === "skipped") return;
42
+ const createdTags = [];
43
+ const pendingTags = /* @__PURE__ */ new Map();
42
44
  for (const pkg of result.packages) {
43
- if (pkg.state !== "success") continue;
44
- pkg.gitTag = resolveGitTag(this, pkg);
45
- pendingTags.add(pkg.gitTag);
45
+ const tag = resolveGitTag(this, pkg);
46
+ pkg.git = {
47
+ tag,
48
+ tagState: "skipped"
49
+ };
50
+ if (pkg.state === "success") pendingTags.set(tag, null);
46
51
  }
47
- try {
48
- const createdTags = [];
49
- await Promise.all(Array.from(pendingTags).map(async (tag) => {
50
- if (await gitTagExists(cwd, tag)) return;
51
- const gitOut = await x("git", ["tag", tag], { nodeOptions: { cwd } });
52
- if (gitOut.exitCode !== 0) throw execFailure(`Failed to create Git tag "${tag}" for release`, gitOut);
53
- createdTags.push(tag);
54
- }));
55
- if (pushTags && createdTags.length > 0) {
56
- const gitOut = await x("git", [
57
- "push",
58
- "origin",
59
- ...createdTags
60
- ], { nodeOptions: { cwd } });
61
- if (gitOut.exitCode !== 0) throw execFailure(`Failed to push Git tags to origin: ${createdTags.join(", ")}`, gitOut);
52
+ await Promise.all(Array.from(pendingTags.keys(), async (tag) => {
53
+ if (await gitTagExists(cwd, tag)) return;
54
+ const gitOut = await x("git", ["tag", tag], { nodeOptions: { cwd } });
55
+ if (gitOut.exitCode !== 0) {
56
+ pendingTags.set(tag, execFailure(`Failed to create Git tag "${tag}" for release`, gitOut));
57
+ return;
62
58
  }
63
- } catch (error) {
64
- return {
65
- ...result,
66
- state: "failed",
67
- error: error instanceof Error ? error.message : String(error)
68
- };
59
+ createdTags.push(tag);
60
+ pendingTags.set(tag, true);
61
+ }));
62
+ for (const pkg of result.packages) {
63
+ if (!pkg.git?.tag) continue;
64
+ const state = pendingTags.get(pkg.git.tag);
65
+ if (state === true) pkg.git.tagState = "created";
66
+ else if (state instanceof Error) {
67
+ pkg.git.tagState = "failed";
68
+ packagePublishError(result, pkg, state.message);
69
+ }
70
+ }
71
+ if (pushTags && createdTags.length > 0) {
72
+ const gitOut = await x("git", [
73
+ "push",
74
+ "origin",
75
+ ...createdTags
76
+ ], { nodeOptions: { cwd } });
77
+ if (gitOut.exitCode !== 0) publishError(result, execFailure(`Failed to push Git tags to origin: ${createdTags.join(", ")}`, gitOut).message);
69
78
  }
70
- return result;
71
79
  }
72
80
  };
73
81
  }
@@ -1,4 +1,4 @@
1
- import { S as PackagePublishResult, T as TegamiContext, c as TegamiPlugin, k as DraftPlan, t as Awaitable } from "../types-BXk2fMqa.js";
1
+ import { S as PackagePublishResult, T as TegamiContext, c as TegamiPlugin, k as DraftPlan, t as Awaitable } from "../types-DexeJdl7.js";
2
2
  import { GitPluginOptions } from "./git.js";
3
3
 
4
4
  //#region src/plugins/github.d.ts
@@ -1,5 +1,6 @@
1
1
  import { i as formatPackageVersion, r as formatNpmDistTag } from "../semver-C4vJ4SK8.js";
2
2
  import { a as isCI, n as execFailure } from "../error-DNy8R5ue.js";
3
+ import { n as publishError } from "../publish-DkRT0yh6.js";
3
4
  import { git } from "./git.js";
4
5
  import { join, relative } from "node:path";
5
6
  import { x } from "tinyexec";
@@ -8,34 +9,25 @@ import { prerelease } from "semver";
8
9
  /** Create GitHub releases for successfully published packages after the whole plan succeeds. */
9
10
  function github(options = {}) {
10
11
  const { eagerRelease = false, onCreateGroupedRelease, onCreateRelease, onCreateVersionPullRequest, cli: cliOptions = {} } = options;
11
- async function runGithubRelease(gitTag, title, notes, prerelease, repo) {
12
- const args = [
13
- "release",
14
- "create",
15
- gitTag,
16
- "--title",
17
- title,
18
- "--notes",
19
- notes
20
- ];
21
- if (repo) args.push("--repo", repo);
22
- if (prerelease) args.push("--prerelease");
23
- const result = await x("gh", args);
24
- if (result.exitCode !== 0) throw execFailure(`Failed to create GitHub release for ${gitTag}.`, result);
25
- }
26
12
  async function createRelease(context, pkg) {
27
- if (!pkg.gitTag || pkg.state === "failed") return;
13
+ if (pkg.state === "failed") return;
28
14
  const release = await onCreateRelease?.call(context, pkg) ?? {};
29
15
  if (release === false) return;
30
- await runGithubRelease(pkg.gitTag, release.title ?? defaultTitle(pkg), release.notes ?? await defaultNotes(context, pkg), release.prerelease ?? prerelease(pkg.version) !== null, context.github?.repo);
16
+ return {
17
+ title: release.title ?? defaultTitle(pkg),
18
+ notes: release.notes ?? await defaultNotes(context, pkg),
19
+ prerelease: release.prerelease ?? prerelease(pkg.version) !== null
20
+ };
31
21
  }
32
22
  async function createGroupedRelease(context, packages) {
33
- const primary = packages[0];
34
- if (!primary?.gitTag) return;
35
23
  if (packages.some((member) => member.state === "failed")) return;
36
24
  const release = await onCreateGroupedRelease?.call(context, packages) ?? {};
37
25
  if (release === false) return;
38
- await runGithubRelease(primary.gitTag, release.title ?? defaultGroupedTitle(packages), release.notes ?? await defaultGroupedNotes(context, packages), release.prerelease ?? packages.some((pkg) => prerelease(pkg.version) !== null), context.github?.repo);
26
+ return {
27
+ title: release.title ?? defaultGroupedTitle(packages),
28
+ notes: release.notes ?? await defaultGroupedNotes(context, packages),
29
+ prerelease: release.prerelease ?? packages.some((pkg) => prerelease(pkg.version) !== null)
30
+ };
39
31
  }
40
32
  function resolvePROptions() {
41
33
  const setting = cliOptions.versionPr ?? isCI();
@@ -168,10 +160,33 @@ function github(options = {}) {
168
160
  }
169
161
  },
170
162
  async afterPublishAll(result) {
171
- if (!eagerRelease && result.state === "failed") return;
172
163
  if (result.state === "skipped") return;
173
- for (const packages of groupPackagesByGitTag(result.packages).values()) if (packages.length > 1) await createGroupedRelease(this, packages);
174
- else await createRelease(this, packages[0]);
164
+ if (!eagerRelease && result.state === "failed") return;
165
+ const repo = this.github?.repo;
166
+ await Promise.all(Array.from(groupPackagesByGitTag(result.packages), async ([tag, packages]) => {
167
+ const release = packages.length > 1 ? await createGroupedRelease(this, packages) : await createRelease(this, packages[0]);
168
+ if (!release) return;
169
+ const viewArgs = [
170
+ "release",
171
+ "view",
172
+ tag
173
+ ];
174
+ if (repo) viewArgs.push("--repo", repo);
175
+ if ((await x("gh", viewArgs)).exitCode === 0) return;
176
+ const args = [
177
+ "release",
178
+ "create",
179
+ tag,
180
+ "--title",
181
+ release.title,
182
+ "--notes",
183
+ release.notes
184
+ ];
185
+ if (repo) args.push("--repo", repo);
186
+ if (release.prerelease) args.push("--prerelease");
187
+ const ghOut = await x("gh", args);
188
+ if (ghOut.exitCode !== 0) publishError(result, execFailure(`Failed to create GitHub release for ${tag}.`, ghOut).message);
189
+ }));
175
190
  }
176
191
  }];
177
192
  }
@@ -197,10 +212,10 @@ async function findOpenPullRequest(branch, repo) {
197
212
  function groupPackagesByGitTag(packages) {
198
213
  const groups = /* @__PURE__ */ new Map();
199
214
  for (const pkg of packages) {
200
- if (!pkg.gitTag) continue;
201
- const group = groups.get(pkg.gitTag);
215
+ if (!pkg.git?.tag) continue;
216
+ const group = groups.get(pkg.git.tag);
202
217
  if (group) group.push(pkg);
203
- else groups.set(pkg.gitTag, [pkg]);
218
+ else groups.set(pkg.git.tag, [pkg]);
204
219
  }
205
220
  return groups;
206
221
  }
@@ -210,7 +225,8 @@ function defaultTitle(pkg) {
210
225
  function defaultGroupedTitle(packages) {
211
226
  const primary = packages[0];
212
227
  const distTag = packages.every((pkg) => pkg.npm?.distTag === primary.npm?.distTag) ? primary.npm?.distTag : void 0;
213
- return formatPackageVersion(primary.gitTag.slice(0, primary.gitTag.lastIndexOf("@")), primary.version, distTag);
228
+ const tag = primary.git.tag;
229
+ return formatPackageVersion(tag.slice(0, tag.lastIndexOf("@")), primary.version, distTag);
214
230
  }
215
231
  function formatCommitLink(commit, repo) {
216
232
  const short = commit.slice(0, 7);
@@ -251,7 +267,7 @@ async function defaultGroupedNotes(context, packages) {
251
267
  if (changelogs.size > 0) {
252
268
  const notes = await Promise.all(Array.from(changelogs.values()).map((entry) => renderChangelogEntryNotes(context, entry)));
253
269
  sections.push("", notes.join("\n\n"));
254
- } else sections.push("", `Published ${packages[0].gitTag}.`);
270
+ } else sections.push("", `Published ${packages[0].git.tag}.`);
255
271
  return sections.join("\n");
256
272
  }
257
273
  //#endregion
@@ -1,2 +1,2 @@
1
- import { d as CargoPluginOptions, f as CargoRegistryClient, p as cargo, u as CargoPackage } from "../types-BXk2fMqa.js";
1
+ import { d as CargoPluginOptions, f as CargoRegistryClient, p as cargo, u as CargoPackage } from "../types-DexeJdl7.js";
2
2
  export { CargoPackage, CargoPluginOptions, CargoRegistryClient, cargo };
@@ -1,2 +1,2 @@
1
- import { _ as npm, g as NpmRegistryClient, h as NpmPluginOptions, m as NpmPackage } from "../types-BXk2fMqa.js";
1
+ import { _ as npm, g as NpmRegistryClient, h as NpmPluginOptions, m as NpmPackage } from "../types-DexeJdl7.js";
2
2
  export { NpmPackage, NpmPluginOptions, NpmRegistryClient, npm };
@@ -81,15 +81,15 @@ var NpmRegistryClient = class {
81
81
  async publish(pkg, { packageStore }) {
82
82
  const distTag = packageStore.npm?.distTag;
83
83
  if (this.client === "bun") {
84
- const tarball = "pkg.tgz";
84
+ const tarballPath = path.resolve(pkg.path, "pkg.tgz");
85
85
  const packResult = await x("bun", [
86
86
  "pm",
87
87
  "pack",
88
88
  "--filename",
89
- tarball
89
+ tarballPath
90
90
  ], { nodeOptions: { cwd: pkg.path } });
91
91
  if (packResult.exitCode !== 0) throw execFailure(`Failed to pack ${pkg.name}@${pkg.version}.`, packResult);
92
- const publishArgs = ["publish", tarball];
92
+ const publishArgs = ["publish", tarballPath];
93
93
  if (distTag) publishArgs.push("--tag", distTag);
94
94
  const publishResult = await x("npm", publishArgs, { nodeOptions: { cwd: pkg.path } });
95
95
  if (publishResult.exitCode !== 0) throw execFailure(`Failed to publish ${pkg.name}@${pkg.version}${distTag ? ` with dist-tag "${distTag}"` : ""}.`, publishResult);
@@ -0,0 +1,282 @@
1
+ import { a as maxBump } from "./semver-C4vJ4SK8.js";
2
+ import { r as handlePluginError } from "./error-DNy8R5ue.js";
3
+ import { a as changelogFrontmatterSchema, n as publishPlanStatus } from "./checks-azjuIFt7.js";
4
+ import { readFile, readdir } from "node:fs/promises";
5
+ import { basename, join } from "node:path";
6
+ import { dump, load } from "js-yaml";
7
+ import { fromMarkdown } from "mdast-util-from-markdown";
8
+ import { toMarkdown } from "mdast-util-to-markdown";
9
+ //#region src/utils/frontmatter.ts
10
+ /**
11
+ * Inspired by https://github.com/jonschlinkert/gray-matter
12
+ */
13
+ const regex = /^---\r?\n(.+?)\r?\n---\r?\n?/s;
14
+ /**
15
+ * parse frontmatter, it supports only yaml format
16
+ */
17
+ function frontmatter(input) {
18
+ const output = {
19
+ matter: "",
20
+ data: {},
21
+ content: input
22
+ };
23
+ const match = regex.exec(input);
24
+ if (!match) return output;
25
+ output.matter = match[0];
26
+ output.content = input.slice(match[0].length);
27
+ output.data = load(match[1]) ?? {};
28
+ return output;
29
+ }
30
+ //#endregion
31
+ //#region src/changelog/parse.ts
32
+ async function getChangelogFiles(context) {
33
+ return (await readdir(context.changelogDir).catch(() => [])).filter((file) => file.endsWith(".md"));
34
+ }
35
+ async function readChangelogEntries(context) {
36
+ const dir = context.changelogDir;
37
+ const files = await getChangelogFiles(context);
38
+ return (await Promise.all(files.map(async (file) => {
39
+ const filePath = join(dir, file);
40
+ const content = await readFile(filePath, "utf8");
41
+ return parseChangelogFile(basename(filePath), content);
42
+ }))).filter((v) => v !== void 0);
43
+ }
44
+ /** Parse one changelog markdown file into release entries. */
45
+ function parseChangelogFile(filename, content) {
46
+ const parsed = frontmatter(content);
47
+ const { success, data } = changelogFrontmatterSchema.safeParse(parsed.data);
48
+ if (!success || !data.packages) return;
49
+ const tree = fromMarkdown(parsed.content);
50
+ let headingBump;
51
+ const packages = /* @__PURE__ */ new Map();
52
+ const sections = [];
53
+ for (const section of getHeadingSections(tree)) {
54
+ const sectionBumpType = headingToBump(section.heading.depth);
55
+ if (sectionBumpType) headingBump = headingBump ? maxBump(headingBump, sectionBumpType) : sectionBumpType;
56
+ sections.push({
57
+ depth: section.heading.depth,
58
+ title: sectionToMarkdown(section.heading.children),
59
+ content: sectionToMarkdown(section.children)
60
+ });
61
+ }
62
+ if (sections.length === 0) return;
63
+ if (Array.isArray(data.packages)) {
64
+ if (!headingBump) return;
65
+ for (const pkg of data.packages) packages.set(pkg, { type: headingBump });
66
+ } else for (const [k, v] of Object.entries(data.packages)) {
67
+ let config;
68
+ if (typeof v === "string") config = { type: v };
69
+ else if (v === null) config = { type: headingBump };
70
+ else config = v;
71
+ if (config.type || config.replay?.length) packages.set(k, config);
72
+ }
73
+ if (packages.size === 0) return;
74
+ const entry = {
75
+ id: filename,
76
+ filename,
77
+ subject: data.subject,
78
+ packages,
79
+ sections,
80
+ _raw_body: parsed.content,
81
+ getRawContent() {
82
+ return [
83
+ "---",
84
+ dump({
85
+ subject: this.subject,
86
+ packages: Object.fromEntries(this.packages.entries())
87
+ }).trim(),
88
+ "---",
89
+ "",
90
+ entry._raw_body.trim(),
91
+ ""
92
+ ].join("\n");
93
+ }
94
+ };
95
+ return entry;
96
+ }
97
+ function parseReplayCondition(condition) {
98
+ if (condition.startsWith("exit prerelease:")) return {
99
+ type: "on-exit-prerelease",
100
+ name: condition.slice(16).trimStart()
101
+ };
102
+ const idx = condition.lastIndexOf("@");
103
+ if (idx <= 0) return null;
104
+ return {
105
+ type: "on-version",
106
+ name: condition.slice(0, idx),
107
+ version: condition.slice(idx + 1)
108
+ };
109
+ }
110
+ function getHeadingSections(tree) {
111
+ const sections = [];
112
+ let current;
113
+ for (const child of tree.children) {
114
+ if (child.type === "heading") {
115
+ current = {
116
+ heading: child,
117
+ children: []
118
+ };
119
+ sections.push(current);
120
+ continue;
121
+ }
122
+ current?.children.push(child);
123
+ }
124
+ return sections;
125
+ }
126
+ function sectionToMarkdown(children) {
127
+ if (children.length === 0) return "";
128
+ return toMarkdown({
129
+ type: "root",
130
+ children
131
+ }, {
132
+ bullet: "-",
133
+ fence: "`"
134
+ }).trim();
135
+ }
136
+ function headingToBump(depth) {
137
+ switch (depth) {
138
+ case 1: return "major";
139
+ case 2: return "minor";
140
+ case 3: return "patch";
141
+ }
142
+ }
143
+ //#endregion
144
+ //#region src/publish.ts
145
+ async function resolvePublishTargets(context, store) {
146
+ const targets = [];
147
+ const preflightPromises = [];
148
+ for (const [id, plan] of Object.entries(store.packages)) {
149
+ if (!plan.publish) continue;
150
+ const pkg = context.graph.get(id);
151
+ if (!pkg) continue;
152
+ targets.push(pkg.id);
153
+ preflightPromises.push(context.getRegistryClient(pkg).publishPreflight?.(pkg, {
154
+ store,
155
+ packageStore: plan
156
+ }));
157
+ }
158
+ const preflights = await Promise.all(preflightPromises);
159
+ const children = /* @__PURE__ */ new Map();
160
+ for (let i = 0; i < targets.length; i++) {
161
+ const id = targets[i];
162
+ children.set(id, preflights[i]?.wait);
163
+ }
164
+ const ordered = [];
165
+ function scan(id, stack = /* @__PURE__ */ new Set()) {
166
+ if (stack.has(id)) throw new Error(`circular reference of deps: ${[...stack, id].join(" -> ")}`);
167
+ if (ordered.includes(id)) return;
168
+ const deps = children.get(id);
169
+ if (deps) {
170
+ stack.add(id);
171
+ for (const dep of deps) scan(dep, stack);
172
+ stack.delete(id);
173
+ }
174
+ ordered.push(id);
175
+ }
176
+ for (const id of targets) scan(id);
177
+ return ordered;
178
+ }
179
+ async function publishFromPlan(context, store, options) {
180
+ const { dryRun = false } = options;
181
+ const packages = [];
182
+ if ((await publishPlanStatus(store, context)).state !== "pending") return { state: "skipped" };
183
+ const orderedIds = await resolvePublishTargets(context, store);
184
+ const parsedChangelogs = /* @__PURE__ */ new Map();
185
+ for (const [id, entry] of Object.entries(store.changelogs)) {
186
+ const parsed = parseChangelogFile(entry.filename, entry.content);
187
+ if (!parsed) continue;
188
+ parsedChangelogs.set(id, parsed);
189
+ }
190
+ for (const id of orderedIds) {
191
+ const plan = store.packages[id];
192
+ const pkg = context.graph.get(id);
193
+ const registryClient = context.getRegistryClient(pkg);
194
+ const changelogs = [];
195
+ for (const id of plan.changelogIds ?? []) {
196
+ const entry = parsedChangelogs.get(id);
197
+ if (entry) changelogs.push(entry);
198
+ }
199
+ if (dryRun) {
200
+ packages.push({
201
+ id: pkg.id,
202
+ name: pkg.name,
203
+ version: pkg.version,
204
+ npm: plan.npm,
205
+ state: "success",
206
+ changelogs
207
+ });
208
+ continue;
209
+ }
210
+ if (await registryClient.isPackagePublished(pkg)) {
211
+ packages.push({
212
+ id: pkg.id,
213
+ name: pkg.name,
214
+ version: pkg.version,
215
+ npm: plan.npm,
216
+ state: "success",
217
+ changelogs
218
+ });
219
+ continue;
220
+ }
221
+ try {
222
+ let result;
223
+ for (const plugin of context.plugins) {
224
+ const next = await handlePluginError(plugin, "willPublish", () => plugin.willPublish?.call(context, { pkg }));
225
+ if (next !== void 0) {
226
+ result = next;
227
+ break;
228
+ }
229
+ }
230
+ if (result === void 0) {
231
+ await registryClient.publish(pkg, {
232
+ packageStore: plan,
233
+ store
234
+ });
235
+ result = {
236
+ id: pkg.id,
237
+ name: pkg.name,
238
+ version: pkg.version,
239
+ npm: plan.npm,
240
+ state: "success",
241
+ changelogs
242
+ };
243
+ }
244
+ if (result === false) continue;
245
+ for (const plugin of context.plugins) {
246
+ const next = await handlePluginError(plugin, "afterPublish", () => plugin.afterPublish?.call(context, {
247
+ pkg,
248
+ result
249
+ }));
250
+ if (next) result = next;
251
+ }
252
+ packages.push(result);
253
+ } catch (error) {
254
+ packages.push({
255
+ id: pkg.id,
256
+ name: pkg.name,
257
+ version: pkg.version,
258
+ npm: plan.npm,
259
+ changelogs,
260
+ state: "failed",
261
+ error: error instanceof Error ? error.message : String(error)
262
+ });
263
+ }
264
+ }
265
+ if (packages.length === 0) return { state: "skipped" };
266
+ return {
267
+ state: packages.some((pkg) => pkg.state === "failed") ? "failed" : "created",
268
+ packages,
269
+ _rawPlan: store
270
+ };
271
+ }
272
+ function publishError(result, error) {
273
+ result.state = "failed";
274
+ if (result.state === "failed" && error) result.error = result.error ? `${result.error}\n${error}` : error;
275
+ }
276
+ function packagePublishError(result, packageResult, error) {
277
+ result.state = "failed";
278
+ packageResult.state = "failed";
279
+ if (packageResult.state === "failed" && error) packageResult.error = packageResult.error ? `${packageResult.error}\n${error}` : error;
280
+ }
281
+ //#endregion
282
+ export { readChangelogEntries as a, parseReplayCondition as i, publishError as n, publishFromPlan as r, packagePublishError as t };
@@ -228,8 +228,11 @@ type PackagePublishResult = ({
228
228
  version: string;
229
229
  npm?: {
230
230
  distTag?: string;
231
- }; /** added by the `git` plugin */
232
- gitTag?: string;
231
+ };
232
+ git?: {
233
+ /** will be defined even if publishing fails */tag: string;
234
+ tagState: "created" | "skipped" | "failed";
235
+ };
233
236
  changelogs: ChangelogEntry[];
234
237
  };
235
238
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tegami",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Utility for package versioning & publish",
5
5
  "license": "MIT",
6
6
  "author": "Fuma Nama",