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.
- package/dist/checks-azjuIFt7.js +109 -0
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +41 -18
- package/dist/{checks-Cwz-Ezkq.js → generate-B3bcuKLY.js} +3 -109
- package/dist/generators/simple.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -271
- package/dist/plugins/git.d.ts +1 -1
- package/dist/plugins/git.js +35 -27
- package/dist/plugins/github.d.ts +1 -1
- package/dist/plugins/github.js +44 -28
- package/dist/providers/cargo.d.ts +1 -1
- package/dist/providers/npm.d.ts +1 -1
- package/dist/providers/npm.js +3 -3
- package/dist/publish-DkRT0yh6.js +282 -0
- package/dist/{types-BXk2fMqa.d.ts → types-DexeJdl7.d.ts} +5 -2
- package/package.json +1 -1
|
@@ -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 };
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { k as DraftPlan, t as Awaitable, v as Tegami, w as PublishResult } from "../types-
|
|
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 {
|
|
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)
|
|
322
|
-
|
|
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
|
-
|
|
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)
|
|
369
|
-
|
|
382
|
+
if (!eventPath) return {
|
|
383
|
+
found: false,
|
|
384
|
+
reason: "GITHUB_EVENT_PATH is required."
|
|
385
|
+
};
|
|
386
|
+
let raw;
|
|
370
387
|
try {
|
|
371
|
-
|
|
388
|
+
raw = JSON.parse(await readFile(eventPath, "utf8"));
|
|
372
389
|
} catch {
|
|
373
|
-
|
|
390
|
+
return {
|
|
391
|
+
found: false,
|
|
392
|
+
reason: "Failed to read workflow_run event."
|
|
393
|
+
};
|
|
374
394
|
}
|
|
375
|
-
const
|
|
376
|
-
if (
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
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
|
-
|
|
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
|
|
3
|
-
import {
|
|
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
|
-
|
|
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 };
|
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-
|
|
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 {
|
|
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 {
|
|
9
|
-
import
|
|
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 = {}) {
|
package/dist/plugins/git.d.ts
CHANGED
package/dist/plugins/git.js
CHANGED
|
@@ -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
|
|
41
|
-
const
|
|
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
|
-
|
|
44
|
-
pkg.
|
|
45
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
await
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
}
|
package/dist/plugins/github.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as PackagePublishResult, T as TegamiContext, c as TegamiPlugin, k as DraftPlan, t as Awaitable } from "../types-
|
|
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
|
package/dist/plugins/github.js
CHANGED
|
@@ -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 (
|
|
13
|
+
if (pkg.state === "failed") return;
|
|
28
14
|
const release = await onCreateRelease?.call(context, pkg) ?? {};
|
|
29
15
|
if (release === false) return;
|
|
30
|
-
|
|
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
|
-
|
|
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
|
-
|
|
174
|
-
|
|
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.
|
|
201
|
-
const group = groups.get(pkg.
|
|
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.
|
|
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
|
-
|
|
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].
|
|
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-
|
|
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 };
|
package/dist/providers/npm.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as npm, g as NpmRegistryClient, h as NpmPluginOptions, m as NpmPackage } from "../types-
|
|
1
|
+
import { _ as npm, g as NpmRegistryClient, h as NpmPluginOptions, m as NpmPackage } from "../types-DexeJdl7.js";
|
|
2
2
|
export { NpmPackage, NpmPluginOptions, NpmRegistryClient, npm };
|
package/dist/providers/npm.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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",
|
|
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
|
-
};
|
|
232
|
-
|
|
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
|