tegami 0.1.5 → 0.2.0
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/api-D-jf_8xY.js +116 -0
- package/dist/cli/index.d.ts +4 -4
- package/dist/cli/index.js +124 -133
- package/dist/{checks-Cwz-Ezkq.js → generate-BMlrn-2e.js} +18 -106
- package/dist/generators/simple.d.ts +1 -1
- package/dist/generators/simple.js +3 -3
- package/dist/{graph-DLKPUXSD.js → graph-DrzluXw8.js} +17 -10
- package/dist/index.d.ts +2 -2
- package/dist/index.js +317 -210
- package/dist/plugins/git.d.ts +1 -1
- package/dist/plugins/git.js +47 -35
- package/dist/plugins/github.d.ts +28 -15
- package/dist/plugins/github.js +158 -142
- package/dist/providers/cargo.d.ts +2 -2
- package/dist/providers/cargo.js +86 -100
- package/dist/providers/npm.d.ts +2 -2
- package/dist/providers/npm.js +132 -129
- package/dist/schemas-B7N6EE2k.js +26 -0
- package/dist/{types-BXk2fMqa.d.ts → types-CurHqnWl.d.ts} +199 -226
- package/package.json +6 -7
- package/dist/schemas-CurBAaW5.js +0 -42
package/dist/index.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { a as maxBump } from "./semver-C4vJ4SK8.js";
|
|
2
|
-
import {
|
|
2
|
+
import { i as changelogFrontmatterSchema, n as generateFromCommits } from "./generate-BMlrn-2e.js";
|
|
3
3
|
import { r as handlePluginError } from "./error-DNy8R5ue.js";
|
|
4
|
-
import { t as PackageGraph } from "./graph-
|
|
4
|
+
import { t as PackageGraph } from "./graph-DrzluXw8.js";
|
|
5
5
|
import { cargo } from "./providers/cargo.js";
|
|
6
6
|
import { npm } from "./providers/npm.js";
|
|
7
7
|
import { simpleGenerator } from "./generators/simple.js";
|
|
8
|
-
import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
8
|
+
import fs, { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
9
9
|
import path, { basename, dirname, join } from "node:path";
|
|
10
10
|
import * as semver from "semver";
|
|
11
|
-
import
|
|
11
|
+
import z from "zod";
|
|
12
|
+
import { dump, load, visit } from "js-yaml";
|
|
12
13
|
import { fromMarkdown } from "mdast-util-from-markdown";
|
|
13
14
|
import { toMarkdown } from "mdast-util-to-markdown";
|
|
14
15
|
//#region src/context.ts
|
|
@@ -16,31 +17,17 @@ async function createTegamiContext(options = {}) {
|
|
|
16
17
|
const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd();
|
|
17
18
|
const changelogDir = path.resolve(cwd, options.changelogDir ?? ".tegami");
|
|
18
19
|
const graph = new PackageGraph();
|
|
19
|
-
const registryClients = /* @__PURE__ */ new Map();
|
|
20
20
|
const ctx = {
|
|
21
21
|
cwd,
|
|
22
22
|
changelogDir,
|
|
23
|
-
|
|
23
|
+
lockPath: options.lockPath ? path.resolve(cwd, options.lockPath) : path.join(changelogDir, "publish-lock.yaml"),
|
|
24
24
|
options,
|
|
25
25
|
plugins: resolvePlugins([
|
|
26
26
|
npm(options.npm),
|
|
27
27
|
cargo(options.cargo),
|
|
28
28
|
...options.plugins ?? []
|
|
29
29
|
]),
|
|
30
|
-
graph
|
|
31
|
-
getRegistryClient(pkgOrId) {
|
|
32
|
-
let client;
|
|
33
|
-
if (typeof pkgOrId === "string") client = registryClients.get(pkgOrId);
|
|
34
|
-
else for (const item of registryClients.values()) if (item.supports && item.supports(pkgOrId)) {
|
|
35
|
-
client = item;
|
|
36
|
-
break;
|
|
37
|
-
}
|
|
38
|
-
if (!client) {
|
|
39
|
-
const id = typeof pkgOrId === "string" ? pkgOrId : pkgOrId.manager;
|
|
40
|
-
throw new Error(`No registry client is available for ${id}.`);
|
|
41
|
-
}
|
|
42
|
-
return client;
|
|
43
|
-
}
|
|
30
|
+
graph
|
|
44
31
|
};
|
|
45
32
|
for (const plugin of ctx.plugins) await handlePluginError(plugin, "init", () => plugin.init?.call(ctx));
|
|
46
33
|
for (const plugin of ctx.plugins) await handlePluginError(plugin, "resolve", () => plugin.resolve?.call(ctx));
|
|
@@ -59,11 +46,6 @@ async function createTegamiContext(options = {}) {
|
|
|
59
46
|
pkg.setPackageOptions(packageOptions);
|
|
60
47
|
if (packageOptions.group) graph.addGroupMember(packageOptions.group, pkg.id);
|
|
61
48
|
}
|
|
62
|
-
for (const plugin of ctx.plugins) {
|
|
63
|
-
const clients = await handlePluginError(plugin, "createRegistryClient", () => plugin.createRegistryClient?.call(ctx));
|
|
64
|
-
if (!clients) continue;
|
|
65
|
-
for (const client of Array.isArray(clients) ? clients : [clients]) registryClients.set(client.id, client);
|
|
66
|
-
}
|
|
67
49
|
return ctx;
|
|
68
50
|
}
|
|
69
51
|
const PLUGIN_ORDER = {
|
|
@@ -210,18 +192,68 @@ function headingToBump(depth) {
|
|
|
210
192
|
}
|
|
211
193
|
}
|
|
212
194
|
//#endregion
|
|
195
|
+
//#region src/plans/lock.ts
|
|
196
|
+
function inlineMultilineScalars(documents) {
|
|
197
|
+
visit(documents, (node) => {
|
|
198
|
+
if (node.kind !== "scalar" || !node.value.includes("\n")) return;
|
|
199
|
+
node.style.doubleQuoted = true;
|
|
200
|
+
node.style.literal = false;
|
|
201
|
+
node.style.folded = false;
|
|
202
|
+
node.style.singleQuoted = false;
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
const lockDumpOptions = {
|
|
206
|
+
sortKeys: true,
|
|
207
|
+
lineWidth: -1,
|
|
208
|
+
transform: inlineMultilineScalars
|
|
209
|
+
};
|
|
210
|
+
/**
|
|
211
|
+
* the data structure of `publish-lock.yaml` file.
|
|
212
|
+
*/
|
|
213
|
+
var PublishLock = class {
|
|
214
|
+
data;
|
|
215
|
+
constructor(data = /* @__PURE__ */ new Map()) {
|
|
216
|
+
this.data = data;
|
|
217
|
+
}
|
|
218
|
+
/** write data to namespace, note that the `data` must be serializable in yaml */
|
|
219
|
+
write(namespace, data) {
|
|
220
|
+
let arr = this.data.get(namespace);
|
|
221
|
+
if (!arr) {
|
|
222
|
+
arr = [];
|
|
223
|
+
this.data.set(namespace, arr);
|
|
224
|
+
}
|
|
225
|
+
arr.push(data);
|
|
226
|
+
}
|
|
227
|
+
read(namespace) {
|
|
228
|
+
return this.data.get(namespace)?.shift();
|
|
229
|
+
}
|
|
230
|
+
size(namespace) {
|
|
231
|
+
return this.data.get(namespace)?.length ?? 0;
|
|
232
|
+
}
|
|
233
|
+
serialize() {
|
|
234
|
+
let res = dump(Object.fromEntries(this.data.entries()), lockDumpOptions);
|
|
235
|
+
if (!res.endsWith("\n")) res += "\n";
|
|
236
|
+
return res;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
const baseSchema = z.record(z.string(), z.array(z.unknown()));
|
|
240
|
+
function parsePublishLock(content) {
|
|
241
|
+
const data = baseSchema.parse(load(content));
|
|
242
|
+
return new PublishLock(new Map(Object.entries(data)));
|
|
243
|
+
}
|
|
244
|
+
//#endregion
|
|
213
245
|
//#region src/plans/policy.ts
|
|
214
246
|
function groupPolicy({ graph }) {
|
|
215
247
|
return {
|
|
216
248
|
id: "group",
|
|
217
|
-
onUpdate({ pkg,
|
|
218
|
-
if (!
|
|
249
|
+
onUpdate({ pkg, packageDraft }) {
|
|
250
|
+
if (!packageDraft.type) return;
|
|
219
251
|
const group = graph.getPackageGroup(pkg.id);
|
|
220
252
|
if (!group || !group.options.syncBump) return;
|
|
221
253
|
for (const member of group.packages) {
|
|
222
254
|
if (member === pkg) continue;
|
|
223
255
|
this.bumpPackage(member, {
|
|
224
|
-
type:
|
|
256
|
+
type: packageDraft.type,
|
|
225
257
|
reason: `sync "${group.name}" group package versions`
|
|
226
258
|
});
|
|
227
259
|
}
|
|
@@ -230,57 +262,70 @@ function groupPolicy({ graph }) {
|
|
|
230
262
|
}
|
|
231
263
|
//#endregion
|
|
232
264
|
//#region src/plans/draft.ts
|
|
233
|
-
|
|
265
|
+
const changelogStoreSchema = z.object({
|
|
266
|
+
v: z.literal("0.0.0"),
|
|
267
|
+
filename: z.string(),
|
|
268
|
+
content: z.string()
|
|
269
|
+
});
|
|
270
|
+
const packageStoreSchema = z.object({
|
|
271
|
+
id: z.string(),
|
|
272
|
+
updated: z.boolean(),
|
|
273
|
+
changelogIds: z.array(z.string()).optional()
|
|
274
|
+
});
|
|
275
|
+
/** a draft describes all operations to perform before the actual publishing, such as version bumps. */
|
|
276
|
+
var Draft = class {
|
|
234
277
|
context;
|
|
235
278
|
#applied = false;
|
|
279
|
+
/** package id -> draft */
|
|
236
280
|
packages = /* @__PURE__ */ new Map();
|
|
281
|
+
/** id -> changelog */
|
|
237
282
|
changelogs = /* @__PURE__ */ new Map();
|
|
238
283
|
policies = [];
|
|
239
284
|
constructor(context) {
|
|
240
285
|
this.context = context;
|
|
241
286
|
this.policies.push(groupPolicy(context));
|
|
242
287
|
}
|
|
243
|
-
|
|
288
|
+
getPackageDrafts() {
|
|
244
289
|
return this.packages;
|
|
245
290
|
}
|
|
246
|
-
|
|
291
|
+
getPackageDraft(id) {
|
|
247
292
|
return this.packages.get(id);
|
|
248
293
|
}
|
|
249
294
|
bumpPackage(pkg, { type, reason }) {
|
|
250
|
-
return this.dispatchPackage(pkg, (
|
|
251
|
-
|
|
295
|
+
return this.dispatchPackage(pkg, (draft) => {
|
|
296
|
+
draft.type = draft.type ? maxBump(draft.type, type) : type;
|
|
252
297
|
if (reason) {
|
|
253
|
-
|
|
254
|
-
|
|
298
|
+
draft.bumpReasons ??= /* @__PURE__ */ new Set();
|
|
299
|
+
draft.bumpReasons.add(reason);
|
|
255
300
|
}
|
|
256
301
|
});
|
|
257
302
|
}
|
|
258
303
|
dispatchPackage(pkg, dispatch, onUpdate) {
|
|
259
|
-
const
|
|
260
|
-
const prevVersion =
|
|
261
|
-
dispatch(
|
|
262
|
-
if (prevVersion !==
|
|
263
|
-
onUpdate?.(
|
|
304
|
+
const packageDraft = this.getOrInitPackage(pkg);
|
|
305
|
+
const prevVersion = packageDraft.bumpVersion(pkg);
|
|
306
|
+
dispatch(packageDraft);
|
|
307
|
+
if (prevVersion !== packageDraft.bumpVersion(pkg)) {
|
|
308
|
+
onUpdate?.(packageDraft);
|
|
264
309
|
for (const policy of this.policies) policy.onUpdate?.call(this, {
|
|
265
|
-
|
|
310
|
+
packageDraft,
|
|
266
311
|
pkg
|
|
267
312
|
});
|
|
268
313
|
}
|
|
269
|
-
return
|
|
314
|
+
return packageDraft;
|
|
270
315
|
}
|
|
271
316
|
getOrInitPackage(pkg) {
|
|
272
317
|
const existing = this.packages.get(pkg.id);
|
|
273
318
|
if (existing) return existing;
|
|
274
|
-
this.packages.set(pkg.id, pkg.
|
|
275
|
-
return this.dispatchPackage(pkg, (
|
|
276
|
-
(
|
|
319
|
+
this.packages.set(pkg.id, pkg.initDraft());
|
|
320
|
+
return this.dispatchPackage(pkg, (draft) => pkg.configureDraft(draft, this.context.graph.getPackageGroup(pkg.id)), (draft) => {
|
|
321
|
+
(draft.bumpReasons ??= /* @__PURE__ */ new Set()).add("align with script-level configs");
|
|
277
322
|
});
|
|
278
323
|
}
|
|
279
324
|
hasPending() {
|
|
280
325
|
const { graph } = this.context;
|
|
281
|
-
for (const [id,
|
|
326
|
+
for (const [id, draft] of this.packages) {
|
|
282
327
|
const pkg = graph.get(id);
|
|
283
|
-
if (pkg &&
|
|
328
|
+
if (pkg && draft.bumpVersion(pkg) !== pkg.version) return true;
|
|
284
329
|
}
|
|
285
330
|
return false;
|
|
286
331
|
}
|
|
@@ -303,30 +348,53 @@ var DraftPlan = class {
|
|
|
303
348
|
deleteChangelog(id) {
|
|
304
349
|
return this.changelogs.delete(id);
|
|
305
350
|
}
|
|
306
|
-
/** Apply
|
|
307
|
-
async
|
|
308
|
-
if (this.#applied) throw new Error("This draft has already applied
|
|
309
|
-
await assertPublishPlanFinished(this.context);
|
|
351
|
+
/** Apply version bumps, lock file, and changelog files. */
|
|
352
|
+
async apply() {
|
|
353
|
+
if (this.#applied) throw new Error("This draft has already been applied.");
|
|
310
354
|
const { graph } = this.context;
|
|
311
355
|
this.#applied = true;
|
|
312
356
|
const snapshots = /* @__PURE__ */ new Map();
|
|
313
357
|
for (const pkg of graph.getPackages()) snapshots.set(pkg.id, { version: pkg.version });
|
|
314
|
-
for (const plugin of this.context.plugins) await handlePluginError(plugin, "
|
|
358
|
+
for (const plugin of this.context.plugins) await handlePluginError(plugin, "applyDraft", () => plugin.applyDraft?.call(this.context, this));
|
|
315
359
|
const updatedChangelogs = this.applyReplays(snapshots);
|
|
316
360
|
const writes = [];
|
|
317
|
-
for (const [id,
|
|
361
|
+
for (const [id, packageDraft] of this.packages) {
|
|
318
362
|
const pkg = graph.get(id);
|
|
319
363
|
if (!pkg) continue;
|
|
320
|
-
writes.push(this.appendChangelog(pkg,
|
|
364
|
+
writes.push(this.appendChangelog(pkg, packageDraft));
|
|
321
365
|
}
|
|
322
366
|
for (const entry of this.changelogs.values()) {
|
|
323
367
|
const updated = updatedChangelogs.get(entry.id);
|
|
324
368
|
const filePath = path.join(this.context.changelogDir, entry.filename);
|
|
325
|
-
writes.push(
|
|
369
|
+
if (updated) writes.push(mkdir(this.context.changelogDir, { recursive: true }).then(() => writeFile(filePath, updated.getRawContent())));
|
|
370
|
+
else if (!entry.virtual) writes.push(rm(filePath, { force: true }));
|
|
326
371
|
}
|
|
372
|
+
writes.push(this.writeLockFile(snapshots));
|
|
327
373
|
await Promise.all(writes);
|
|
328
|
-
|
|
329
|
-
|
|
374
|
+
}
|
|
375
|
+
/** write persistent data to publish lock */
|
|
376
|
+
async writeLockFile(snapshots) {
|
|
377
|
+
const lock = new PublishLock();
|
|
378
|
+
for (const entry of this.getChangelogs()) lock.write("core:changelogs", {
|
|
379
|
+
v: "0.0.0",
|
|
380
|
+
filename: entry.filename,
|
|
381
|
+
content: entry.getRawContent()
|
|
382
|
+
});
|
|
383
|
+
for (const pkg of this.context.graph.getPackages()) {
|
|
384
|
+
const draft = this.getPackageDraft(pkg.id);
|
|
385
|
+
const snapshot = snapshots.get(pkg.id);
|
|
386
|
+
lock.write("core:packages", {
|
|
387
|
+
id: pkg.id,
|
|
388
|
+
updated: draft !== void 0 && (snapshot === void 0 || snapshot.version !== pkg.version),
|
|
389
|
+
changelogIds: draft?.changelogs?.map((entry) => entry.id)
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
for (const plugin of this.context.plugins) await handlePluginError(plugin, "initPublishLock", () => plugin.initPublishLock?.call(this.context, {
|
|
393
|
+
lock,
|
|
394
|
+
draft: this
|
|
395
|
+
}));
|
|
396
|
+
await mkdir(dirname(this.context.lockPath), { recursive: true });
|
|
397
|
+
await writeFile(this.context.lockPath, lock.serialize());
|
|
330
398
|
}
|
|
331
399
|
addPolicy(policy) {
|
|
332
400
|
this.policies.push(policy);
|
|
@@ -378,183 +446,191 @@ var DraftPlan = class {
|
|
|
378
446
|
}
|
|
379
447
|
return updated;
|
|
380
448
|
}
|
|
381
|
-
async appendChangelog(pkg,
|
|
382
|
-
if (!
|
|
449
|
+
async appendChangelog(pkg, draft) {
|
|
450
|
+
if (!draft.changelogs || draft.changelogs.length === 0) return;
|
|
383
451
|
const { generator = simpleGenerator() } = this.context.options;
|
|
384
452
|
const generated = await generator.generate.call(this.context, {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
plan,
|
|
389
|
-
changelogs: plan.changelogs,
|
|
390
|
-
unstable_draft: this
|
|
453
|
+
pkg,
|
|
454
|
+
packageDraft: draft,
|
|
455
|
+
draft: this
|
|
391
456
|
});
|
|
392
457
|
const path = join(pkg.path, "CHANGELOG.md");
|
|
393
458
|
const existing = await readFile(path, "utf8").catch(() => "");
|
|
394
459
|
await writeFile(path, `${generated.trim()}\n\n${existing}`.trimEnd() + "\n");
|
|
395
460
|
}
|
|
396
|
-
/** {@link
|
|
461
|
+
/** {@link apply} but for `await using` syntax */
|
|
397
462
|
async [Symbol.asyncDispose]() {
|
|
398
|
-
return this.
|
|
463
|
+
return this.apply();
|
|
399
464
|
}
|
|
400
465
|
};
|
|
401
|
-
async function
|
|
402
|
-
|
|
403
|
-
if (!store) return {
|
|
404
|
-
state: "skipped",
|
|
405
|
-
reason: "missing"
|
|
406
|
-
};
|
|
407
|
-
if ((await publishPlanStatus(store, context)).state !== "success") return {
|
|
408
|
-
state: "skipped",
|
|
409
|
-
reason: "pending"
|
|
410
|
-
};
|
|
411
|
-
await rm(context.planPath, { force: true });
|
|
412
|
-
return { state: "removed" };
|
|
413
|
-
}
|
|
414
|
-
async function createDraftPlan(changelogs, context) {
|
|
415
|
-
let draft = new DraftPlan(context);
|
|
466
|
+
async function createDraft(changelogs, context) {
|
|
467
|
+
let draft = new Draft(context);
|
|
416
468
|
for (const plugin of context.plugins) {
|
|
417
|
-
const result = await handlePluginError(plugin, "
|
|
469
|
+
const result = await handlePluginError(plugin, "initDraft", () => plugin.initDraft?.call(context, draft));
|
|
418
470
|
if (result) draft = result;
|
|
419
471
|
}
|
|
420
472
|
for (const pkg of context.graph.getPackages()) draft.getOrInitPackage(pkg);
|
|
421
473
|
for (const entry of changelogs) draft.addChangelog(entry);
|
|
422
474
|
return draft;
|
|
423
475
|
}
|
|
424
|
-
function attachChangelog(
|
|
425
|
-
if (
|
|
426
|
-
|
|
427
|
-
|
|
476
|
+
function attachChangelog(draft, entry) {
|
|
477
|
+
if (draft.changelogs?.some((item) => item.id === entry.id)) return;
|
|
478
|
+
draft.changelogs ??= [];
|
|
479
|
+
draft.changelogs.push(entry);
|
|
428
480
|
}
|
|
429
481
|
//#endregion
|
|
430
|
-
//#region src/publish.ts
|
|
431
|
-
async function
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
if (!pkg) continue;
|
|
438
|
-
targets.push(pkg.id);
|
|
439
|
-
preflightPromises.push(context.getRegistryClient(pkg).publishPreflight?.(pkg, {
|
|
440
|
-
store,
|
|
441
|
-
packageStore: plan
|
|
442
|
-
}));
|
|
482
|
+
//#region src/plans/publish.ts
|
|
483
|
+
async function initPublishPlan(context, options) {
|
|
484
|
+
let lock;
|
|
485
|
+
try {
|
|
486
|
+
lock = parsePublishLock(await fs.readFile(context.lockPath, "utf8"));
|
|
487
|
+
} catch {
|
|
488
|
+
return;
|
|
443
489
|
}
|
|
444
|
-
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
490
|
+
let data;
|
|
491
|
+
const packages = /* @__PURE__ */ new Map();
|
|
492
|
+
const changelogs = /* @__PURE__ */ new Map();
|
|
493
|
+
while (data = lock.read("core:changelogs")) {
|
|
494
|
+
const entry = changelogStoreSchema.safeParse(data).data;
|
|
495
|
+
if (!entry) continue;
|
|
496
|
+
const parsed = parseChangelogFile(entry.filename, entry.content);
|
|
497
|
+
if (!parsed) continue;
|
|
498
|
+
changelogs.set(parsed.id, parsed);
|
|
449
499
|
}
|
|
500
|
+
while (data = lock.read("core:packages")) {
|
|
501
|
+
const parsed = packageStoreSchema.safeParse(data).data;
|
|
502
|
+
if (!parsed) continue;
|
|
503
|
+
if (!context.graph.get(parsed.id)) continue;
|
|
504
|
+
const pkgChangelogs = [];
|
|
505
|
+
for (const id of parsed.changelogIds ?? []) {
|
|
506
|
+
const entry = changelogs.get(id);
|
|
507
|
+
if (entry) pkgChangelogs.push(entry);
|
|
508
|
+
}
|
|
509
|
+
packages.set(parsed.id, {
|
|
510
|
+
changelogs: pkgChangelogs,
|
|
511
|
+
updated: parsed.updated
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
const plan = {
|
|
515
|
+
options,
|
|
516
|
+
changelogs,
|
|
517
|
+
packages
|
|
518
|
+
};
|
|
519
|
+
for (const plugin of context.plugins) await handlePluginError(plugin, "initPublishPlan", () => plugin.initPublishPlan?.call(context, {
|
|
520
|
+
lock,
|
|
521
|
+
plan
|
|
522
|
+
}));
|
|
523
|
+
return plan;
|
|
524
|
+
}
|
|
525
|
+
function resolvePublishTargets(plan) {
|
|
450
526
|
const ordered = [];
|
|
451
527
|
function scan(id, stack = /* @__PURE__ */ new Set()) {
|
|
528
|
+
const preflight = plan.packages.get(id)?.preflight;
|
|
529
|
+
if (!preflight || preflight.publish === false) return;
|
|
452
530
|
if (stack.has(id)) throw new Error(`circular reference of deps: ${[...stack, id].join(" -> ")}`);
|
|
453
531
|
if (ordered.includes(id)) return;
|
|
454
|
-
|
|
455
|
-
if (deps) {
|
|
532
|
+
if (preflight.wait) {
|
|
456
533
|
stack.add(id);
|
|
457
|
-
for (const dep of
|
|
534
|
+
for (const dep of preflight.wait) scan(dep, stack);
|
|
458
535
|
stack.delete(id);
|
|
459
536
|
}
|
|
460
537
|
ordered.push(id);
|
|
461
538
|
}
|
|
462
|
-
for (const id of
|
|
539
|
+
for (const id of plan.packages.keys()) scan(id);
|
|
463
540
|
return ordered;
|
|
464
541
|
}
|
|
465
|
-
async function
|
|
466
|
-
const { dryRun = false } = options;
|
|
467
|
-
const
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
}
|
|
476
|
-
for (const id of
|
|
477
|
-
const plan = store.packages[id];
|
|
542
|
+
async function runPublishPlan(context, plan) {
|
|
543
|
+
const { dryRun = false } = plan.options;
|
|
544
|
+
const onPublishResult = async (pkg, publishResult) => {
|
|
545
|
+
const packagePlan = plan.packages.get(pkg.id);
|
|
546
|
+
if (!packagePlan) return;
|
|
547
|
+
packagePlan.publishResult = publishResult;
|
|
548
|
+
for (const plugin of context.plugins) await handlePluginError(plugin, "afterPublish", () => plugin.afterPublish?.call(context, {
|
|
549
|
+
pkg,
|
|
550
|
+
plan
|
|
551
|
+
}));
|
|
552
|
+
};
|
|
553
|
+
for (const id of resolvePublishTargets(plan)) {
|
|
478
554
|
const pkg = context.graph.get(id);
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
const entry = parsedChangelogs.get(id);
|
|
483
|
-
if (entry) changelogs.push(entry);
|
|
555
|
+
if (dryRun) {
|
|
556
|
+
await onPublishResult(pkg, { type: "published" });
|
|
557
|
+
continue;
|
|
484
558
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
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
|
-
});
|
|
559
|
+
let isSkipped = false;
|
|
560
|
+
for (const plugin of context.plugins) if (await handlePluginError(plugin, "willPublish", () => plugin.willPublish?.call(context, { pkg })) === false) {
|
|
561
|
+
isSkipped = true;
|
|
562
|
+
break;
|
|
563
|
+
}
|
|
564
|
+
if (isSkipped) {
|
|
565
|
+
await onPublishResult(pkg, { type: "skipped" });
|
|
506
566
|
continue;
|
|
507
567
|
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
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;
|
|
568
|
+
let published = false;
|
|
569
|
+
for (const plugin of context.plugins) {
|
|
570
|
+
const publishResult = await handlePluginError(plugin, "publish", () => plugin.publish?.call(context, {
|
|
571
|
+
pkg,
|
|
572
|
+
plan
|
|
573
|
+
}));
|
|
574
|
+
if (publishResult) {
|
|
575
|
+
published = true;
|
|
576
|
+
await onPublishResult(pkg, publishResult);
|
|
577
|
+
break;
|
|
538
578
|
}
|
|
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
579
|
}
|
|
580
|
+
if (!published) await onPublishResult(pkg, {
|
|
581
|
+
type: "failed",
|
|
582
|
+
error: `There is no plugin to publish package "${pkg.id}", please make sure the package has a supported provider plugin.`
|
|
583
|
+
});
|
|
551
584
|
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
585
|
+
await Promise.all(Array.from(plan.packages, async ([id, packagePlan]) => {
|
|
586
|
+
const pkg = context.graph.get(id);
|
|
587
|
+
if (!packagePlan.publishResult) await onPublishResult(pkg, { type: "skipped" });
|
|
588
|
+
}));
|
|
589
|
+
for (const plugin of context.plugins) await handlePluginError(plugin, "afterPublishAll", () => plugin.afterPublishAll?.call(context, { plan }));
|
|
590
|
+
}
|
|
591
|
+
async function runPreflights(context, plan) {
|
|
592
|
+
const promises = [];
|
|
593
|
+
const runPreflight = async (pkg) => {
|
|
594
|
+
const out = {};
|
|
595
|
+
for (const plugin of context.plugins) {
|
|
596
|
+
const res = await handlePluginError(plugin, "publishPreflight", () => plugin.publishPreflight?.call(context, {
|
|
597
|
+
pkg,
|
|
598
|
+
plan
|
|
599
|
+
}));
|
|
600
|
+
if (res?.publish !== void 0) out.publish = res.publish;
|
|
601
|
+
if (res?.wait) {
|
|
602
|
+
out.wait ??= [];
|
|
603
|
+
out.wait.push(...res.wait);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
return out;
|
|
557
607
|
};
|
|
608
|
+
for (const [id, packagePlan] of plan.packages) {
|
|
609
|
+
const pkg = context.graph.get(id);
|
|
610
|
+
if (!packagePlan.updated) {
|
|
611
|
+
packagePlan.preflight = { publish: false };
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
promises.push(runPreflight(pkg).then((preflight) => {
|
|
615
|
+
packagePlan.preflight = preflight;
|
|
616
|
+
}));
|
|
617
|
+
}
|
|
618
|
+
await Promise.all(promises);
|
|
619
|
+
}
|
|
620
|
+
async function publishPlanStatus(plan, context) {
|
|
621
|
+
for (const pkg of plan.packages.values()) {
|
|
622
|
+
if (!pkg.preflight) throw new Error("Should perform preflight before checking plan status.");
|
|
623
|
+
if (pkg.preflight.publish ?? true) return "pending";
|
|
624
|
+
}
|
|
625
|
+
try {
|
|
626
|
+
await Promise.all(context.plugins.map(async (plugin) => {
|
|
627
|
+
if (await handlePluginError(plugin, "resolvePlanStatus", () => plugin.resolvePlanStatus?.call(context, { plan })) === "pending") throw "pending";
|
|
628
|
+
}));
|
|
629
|
+
return "success";
|
|
630
|
+
} catch (e) {
|
|
631
|
+
if (e === "pending") return "pending";
|
|
632
|
+
throw e;
|
|
633
|
+
}
|
|
558
634
|
}
|
|
559
635
|
//#endregion
|
|
560
636
|
//#region src/index.ts
|
|
@@ -565,8 +641,15 @@ function tegami(options = {}) {
|
|
|
565
641
|
return createTegamiContext(options);
|
|
566
642
|
}
|
|
567
643
|
return {
|
|
568
|
-
async generateChangelog(
|
|
569
|
-
|
|
644
|
+
async generateChangelog(generateOptions = {}) {
|
|
645
|
+
const { write = true } = generateOptions;
|
|
646
|
+
const context = await $context;
|
|
647
|
+
const changelogs = await generateFromCommits(context, generateOptions);
|
|
648
|
+
if (write && changelogs.length > 0) {
|
|
649
|
+
await mkdir(context.changelogDir, { recursive: true });
|
|
650
|
+
await Promise.all(changelogs.map((entry) => writeFile(join(context.changelogDir, entry.filename), entry.content)));
|
|
651
|
+
}
|
|
652
|
+
return changelogs;
|
|
570
653
|
},
|
|
571
654
|
_internal: {
|
|
572
655
|
options,
|
|
@@ -579,25 +662,49 @@ function tegami(options = {}) {
|
|
|
579
662
|
},
|
|
580
663
|
async draft() {
|
|
581
664
|
const context = await $context;
|
|
582
|
-
|
|
665
|
+
const changelogs = await readChangelogEntries(context);
|
|
666
|
+
if (context.options.conventionalCommits) {
|
|
667
|
+
const generated = await generateFromCommits(context);
|
|
668
|
+
for (const entry of generated) {
|
|
669
|
+
const parsed = parseChangelogFile(entry.filename, entry.content);
|
|
670
|
+
if (!parsed) continue;
|
|
671
|
+
parsed.virtual = true;
|
|
672
|
+
changelogs.push(parsed);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
return createDraft(changelogs, context);
|
|
676
|
+
},
|
|
677
|
+
async publishStatus() {
|
|
678
|
+
const context = await $context;
|
|
679
|
+
const plan = await initPublishPlan(context, {});
|
|
680
|
+
if (!plan) return "idle";
|
|
681
|
+
await runPreflights(context, plan);
|
|
682
|
+
return publishPlanStatus(plan, context);
|
|
583
683
|
},
|
|
584
684
|
async publish(publishOptions = {}) {
|
|
585
685
|
const context = await $context;
|
|
586
|
-
const
|
|
587
|
-
if (!
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
for (const plugin of context.plugins) {
|
|
594
|
-
const next = await handlePluginError(plugin, "afterPublishAll", () => plugin.afterPublishAll?.call(publishCtx, result));
|
|
595
|
-
if (next) result = next;
|
|
596
|
-
}
|
|
597
|
-
return result;
|
|
686
|
+
const plan = await initPublishPlan(context, publishOptions);
|
|
687
|
+
if (!plan) return "skipped";
|
|
688
|
+
await runPreflights(context, plan);
|
|
689
|
+
if (await publishPlanStatus(plan, context) === "success") return "skipped";
|
|
690
|
+
await runPublishPlan(context, plan);
|
|
691
|
+
if (Array.from(plan.packages.values()).every((pkg) => pkg.publishResult.type === "skipped")) return "skipped";
|
|
692
|
+
return plan;
|
|
598
693
|
},
|
|
599
694
|
async cleanup() {
|
|
600
|
-
|
|
695
|
+
const context = await $context;
|
|
696
|
+
const plan = await initPublishPlan(context, {});
|
|
697
|
+
if (!plan) return {
|
|
698
|
+
state: "skipped",
|
|
699
|
+
reason: "no-plan"
|
|
700
|
+
};
|
|
701
|
+
await runPreflights(context, plan);
|
|
702
|
+
if (await publishPlanStatus(plan, context) !== "success") return {
|
|
703
|
+
state: "skipped",
|
|
704
|
+
reason: "pending"
|
|
705
|
+
};
|
|
706
|
+
await rm(context.lockPath, { force: true });
|
|
707
|
+
return { state: "removed" };
|
|
601
708
|
}
|
|
602
709
|
};
|
|
603
710
|
}
|