tegami 0.0.0 → 0.1.0-beta.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/LICENSE +21 -0
- package/dist/checks-CKBRRjgQ.js +100 -0
- package/dist/cli/index.d.ts +12 -0
- package/dist/cli/index.js +212 -0
- package/dist/constants-B9qjNfvr.js +4 -0
- package/dist/error-DBK-9uBa.js +23 -0
- package/dist/generators/{simple.d.mts → simple.d.ts} +1 -1
- package/dist/generators/{simple.mjs → simple.js} +3 -2
- package/dist/graph-CUgwuRW5.js +107 -0
- package/dist/index-Bhh2dJZp.d.ts +460 -0
- package/dist/index.d.ts +2 -0
- package/dist/{index.mjs → index.js} +205 -210
- package/dist/plugins/{git.d.mts → git.d.ts} +4 -5
- package/dist/plugins/git.js +84 -0
- package/dist/plugins/github.d.ts +55 -0
- package/dist/plugins/github.js +187 -0
- package/dist/providers/cargo.d.ts +2 -0
- package/dist/providers/{cargo.mjs → cargo.js} +112 -54
- package/dist/providers/npm.d.ts +2 -0
- package/dist/providers/npm.js +278 -0
- package/dist/schemas-Cc4h6bq5.js +41 -0
- package/dist/semver-mWK2Khi2.js +33 -0
- package/package.json +22 -16
- package/dist/index.d.mts +0 -31
- package/dist/npm-BSE_dtB3.mjs +0 -280
- package/dist/plugins/git.mjs +0 -56
- package/dist/plugins/github.d.mts +0 -23
- package/dist/plugins/github.mjs +0 -41
- package/dist/providers/cargo.d.mts +0 -32
- package/dist/providers/npm.d.mts +0 -2
- package/dist/providers/npm.mjs +0 -2
- package/dist/types-DdIMewK9.d.mts +0 -283
- package/dist/workspace-B5_i21S0.mjs +0 -63
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { n as handlePluginError } from "./error-DBK-9uBa.js";
|
|
2
|
+
import { i as maxBump } from "./semver-mWK2Khi2.js";
|
|
3
|
+
import { t as PackageGraph } from "./graph-CUgwuRW5.js";
|
|
4
|
+
import { cargo } from "./providers/cargo.js";
|
|
5
|
+
import { t as changelogFrontmatterSchema } from "./schemas-Cc4h6bq5.js";
|
|
6
|
+
import { npm } from "./providers/npm.js";
|
|
7
|
+
import { simpleGenerator } from "./generators/simple.js";
|
|
8
|
+
import { i as readPlanStore, n as publishPlanStatus, r as createPlanStore, t as assertPublishPlanFinished } from "./checks-CKBRRjgQ.js";
|
|
5
9
|
import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
6
|
-
import path, { basename, dirname, join
|
|
10
|
+
import path, { basename, dirname, join } from "node:path";
|
|
7
11
|
import { x } from "tinyexec";
|
|
8
|
-
import { inc } from "semver";
|
|
9
12
|
import { load } from "js-yaml";
|
|
10
13
|
import { fromMarkdown } from "mdast-util-from-markdown";
|
|
11
14
|
import { toMarkdown } from "mdast-util-to-markdown";
|
|
@@ -19,7 +22,7 @@ async function createChangelog(context, options = {}) {
|
|
|
19
22
|
if (group) group.push(commit);
|
|
20
23
|
else groups.set(key, [commit]);
|
|
21
24
|
}
|
|
22
|
-
const directory =
|
|
25
|
+
const directory = context.changelogDir;
|
|
23
26
|
await mkdir(directory, { recursive: true });
|
|
24
27
|
const created = [];
|
|
25
28
|
const stamp = Date.now().toString(36);
|
|
@@ -132,17 +135,18 @@ function commandOutput(result) {
|
|
|
132
135
|
//#endregion
|
|
133
136
|
//#region src/context.ts
|
|
134
137
|
async function createTegamiContext(options = {}) {
|
|
135
|
-
const cwd = resolve(options.cwd
|
|
138
|
+
const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd();
|
|
139
|
+
const changelogDir = path.resolve(cwd, options.changelogDir ?? ".tegami");
|
|
136
140
|
const graph = new PackageGraph();
|
|
137
141
|
const registryClients = /* @__PURE__ */ new Map();
|
|
138
142
|
const ctx = {
|
|
139
143
|
cwd,
|
|
140
|
-
changelogDir
|
|
141
|
-
planPath: resolve(cwd, options.planPath
|
|
144
|
+
changelogDir,
|
|
145
|
+
planPath: options.planPath ? path.resolve(cwd, options.planPath) : path.join(changelogDir, "publish-plan"),
|
|
142
146
|
options,
|
|
143
147
|
plugins: resolvePlugins([
|
|
144
|
-
npm(options.
|
|
145
|
-
cargo(),
|
|
148
|
+
npm(options.npm),
|
|
149
|
+
cargo(options.cargo),
|
|
146
150
|
...options.plugins ?? []
|
|
147
151
|
]),
|
|
148
152
|
graph,
|
|
@@ -160,10 +164,25 @@ async function createTegamiContext(options = {}) {
|
|
|
160
164
|
return client;
|
|
161
165
|
}
|
|
162
166
|
};
|
|
163
|
-
for (const plugin of ctx.plugins) await plugin.init?.call(ctx);
|
|
164
|
-
for (const plugin of ctx.plugins) await plugin.resolve?.call(ctx);
|
|
167
|
+
for (const plugin of ctx.plugins) await handlePluginError(plugin, "init", () => plugin.init?.call(ctx));
|
|
168
|
+
for (const plugin of ctx.plugins) await handlePluginError(plugin, "resolve", () => plugin.resolve?.call(ctx));
|
|
169
|
+
const ignoreMatchers = options.ignore?.map((pattern) => {
|
|
170
|
+
if (pattern instanceof RegExp) return (pkg) => pattern.test(pkg.name) || pattern.test(pkg.id);
|
|
171
|
+
return (pkg) => pkg.name === pattern || pkg.id === pattern;
|
|
172
|
+
});
|
|
173
|
+
for (const [name, groupOptions] of Object.entries(options.groups ?? {})) graph.registerGroup(name, groupOptions);
|
|
174
|
+
for (const pkg of graph.getPackages()) {
|
|
175
|
+
if (ignoreMatchers?.length && ignoreMatchers.some((matcher) => matcher(pkg))) {
|
|
176
|
+
graph.delete(pkg.id);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const packageOptions = options.packages?.[pkg.id] ?? options.packages?.[pkg.name];
|
|
180
|
+
if (!packageOptions) continue;
|
|
181
|
+
pkg.setPackageOptions(packageOptions);
|
|
182
|
+
if (packageOptions.group) graph.addGroupMember(packageOptions.group, pkg.id);
|
|
183
|
+
}
|
|
165
184
|
for (const plugin of ctx.plugins) {
|
|
166
|
-
const clients = await plugin.createRegistryClient?.call(ctx);
|
|
185
|
+
const clients = await handlePluginError(plugin, "createRegistryClient", () => plugin.createRegistryClient?.call(ctx));
|
|
167
186
|
if (!clients) continue;
|
|
168
187
|
for (const client of Array.isArray(clients) ? clients : [clients]) registryClients.set(client.id, client);
|
|
169
188
|
}
|
|
@@ -178,195 +197,165 @@ function resolvePlugins(plugins = []) {
|
|
|
178
197
|
return plugins.flat(Infinity).sort((a, b) => PLUGIN_ORDER[a.enforce ?? "default"] - PLUGIN_ORDER[b.enforce ?? "default"]);
|
|
179
198
|
}
|
|
180
199
|
//#endregion
|
|
181
|
-
//#region src/
|
|
182
|
-
function
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
200
|
+
//#region src/plans/policy.ts
|
|
201
|
+
function groupPolicy({ graph }) {
|
|
202
|
+
return {
|
|
203
|
+
id: "group",
|
|
204
|
+
onUpdate({ pkg, plan }) {
|
|
205
|
+
if (!plan.type) return;
|
|
206
|
+
const group = graph.getPackageGroup(pkg.id);
|
|
207
|
+
if (!group || !group.options.syncBump) return;
|
|
208
|
+
for (const member of group.packages) {
|
|
209
|
+
if (member === pkg) continue;
|
|
210
|
+
this.bumpPackage(member, {
|
|
211
|
+
type: plan.type,
|
|
212
|
+
reason: `sync "${group.name}" group package versions`
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
};
|
|
191
217
|
}
|
|
192
218
|
//#endregion
|
|
193
|
-
//#region src/draft.ts
|
|
219
|
+
//#region src/plans/draft.ts
|
|
194
220
|
var DraftPlan = class {
|
|
195
|
-
changelogs;
|
|
196
|
-
packages;
|
|
197
221
|
context;
|
|
198
|
-
#
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
222
|
+
#applied = false;
|
|
223
|
+
packages = /* @__PURE__ */ new Map();
|
|
224
|
+
changelogs = /* @__PURE__ */ new Map();
|
|
225
|
+
policies = [];
|
|
226
|
+
constructor(context) {
|
|
202
227
|
this.context = context;
|
|
228
|
+
this.policies.push(groupPolicy(context));
|
|
203
229
|
}
|
|
204
|
-
|
|
205
|
-
return
|
|
230
|
+
getPackagePlans() {
|
|
231
|
+
return this.packages;
|
|
206
232
|
}
|
|
207
|
-
|
|
233
|
+
getPackagePlan(id) {
|
|
208
234
|
return this.packages.get(id);
|
|
209
235
|
}
|
|
210
|
-
|
|
211
|
-
this.packages.
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
236
|
+
bumpPackage(pkg, { type, reason }) {
|
|
237
|
+
let plan = this.packages.get(pkg.id);
|
|
238
|
+
if (!plan) {
|
|
239
|
+
plan = this.initPackagePlan(pkg);
|
|
240
|
+
this.packages.set(pkg.id, plan);
|
|
241
|
+
}
|
|
242
|
+
const prevVersion = plan.bumpVersion(pkg);
|
|
243
|
+
plan.type = plan.type ? maxBump(plan.type, type) : type;
|
|
244
|
+
if (reason) {
|
|
245
|
+
plan.bumpReasons ??= /* @__PURE__ */ new Set();
|
|
246
|
+
plan.bumpReasons.add(reason);
|
|
247
|
+
}
|
|
248
|
+
if (prevVersion !== plan.bumpVersion(pkg)) for (const policy of this.policies) policy.onUpdate?.call(this, {
|
|
249
|
+
plan,
|
|
250
|
+
pkg
|
|
216
251
|
});
|
|
252
|
+
return plan;
|
|
217
253
|
}
|
|
218
|
-
|
|
219
|
-
|
|
254
|
+
hasPending() {
|
|
255
|
+
const { graph } = this.context;
|
|
256
|
+
for (const [id, plan] of this.packages) {
|
|
257
|
+
const pkg = graph.get(id);
|
|
258
|
+
if (pkg && plan.bumpVersion(pkg) !== pkg.version) return true;
|
|
259
|
+
}
|
|
260
|
+
return false;
|
|
220
261
|
}
|
|
221
|
-
|
|
222
|
-
return Array.from(this.changelogs.
|
|
262
|
+
getChangelogs() {
|
|
263
|
+
return Array.from(this.changelogs.values());
|
|
223
264
|
}
|
|
224
265
|
getChangelog(id) {
|
|
225
266
|
return this.changelogs.get(id);
|
|
226
267
|
}
|
|
227
|
-
|
|
228
|
-
this.changelogs.set(id, entry);
|
|
268
|
+
addChangelog(entry) {
|
|
269
|
+
this.changelogs.set(entry.id, entry);
|
|
270
|
+
const { graph } = this.context;
|
|
271
|
+
const groupPackages = /* @__PURE__ */ new Set();
|
|
272
|
+
for (const name of entry.packages) for (const pkg of graph.getByName(name)) groupPackages.add(pkg);
|
|
273
|
+
for (const pkg of groupPackages) {
|
|
274
|
+
const plan = this.bumpPackage(pkg, { type: entry.type });
|
|
275
|
+
plan.changelogs ??= [];
|
|
276
|
+
plan.changelogs.push(entry);
|
|
277
|
+
}
|
|
229
278
|
}
|
|
230
279
|
deleteChangelog(id) {
|
|
231
280
|
return this.changelogs.delete(id);
|
|
232
281
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
const plan = {
|
|
240
|
-
id: `tegami-${Date.now().toString(36)}`,
|
|
241
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
242
|
-
changelogs: Object.fromEntries(Array.from(this.changelogs, ([id, entry]) => [id, {
|
|
243
|
-
filename: entry.filename,
|
|
244
|
-
subject: entry.subject,
|
|
245
|
-
packages: Array.from(entry.packages),
|
|
246
|
-
type: entry.type,
|
|
247
|
-
title: entry.title,
|
|
248
|
-
content: entry.content
|
|
249
|
-
}])),
|
|
250
|
-
packages: Object.fromEntries(this.packages)
|
|
251
|
-
};
|
|
252
|
-
await mkdir(dirname(this.context.planPath), { recursive: true });
|
|
253
|
-
await writeFile(this.context.planPath, planStoreSchema.encode(plan));
|
|
254
|
-
await this.removeConsumedChangelogs();
|
|
255
|
-
}
|
|
256
|
-
async assertPublishPlanFinished() {
|
|
257
|
-
const content = await readFile(this.context.planPath, "utf8").catch(() => void 0);
|
|
258
|
-
if (!content) return;
|
|
259
|
-
const parsed = planStoreSchema.safeDecode(content);
|
|
260
|
-
if (!parsed.success) return;
|
|
261
|
-
const status = await publishPlanStatus(this.context, parsed.data);
|
|
262
|
-
if (status.state === "success") return;
|
|
263
|
-
const message = `Publish plan already exists at ${this.context.planPath} and is ${status.state}. Publish it before creating a new plan.`;
|
|
264
|
-
throw new Error(status.error ? `${message}\n${status.error}` : message);
|
|
282
|
+
initPackagePlan(pkg) {
|
|
283
|
+
const context = this.context;
|
|
284
|
+
const plan = pkg.onPlan(context);
|
|
285
|
+
const group = context.graph.getPackageGroup(pkg.id);
|
|
286
|
+
if (group) plan.prerelease ??= group.options.prerelease;
|
|
287
|
+
return plan;
|
|
265
288
|
}
|
|
266
|
-
|
|
289
|
+
/** Apply the publish plan: update package versions, write the plan file, and consume changelog files. */
|
|
290
|
+
async applyPlan() {
|
|
291
|
+
if (this.#applied) throw new Error("This draft has already applied a publish plan.");
|
|
292
|
+
await assertPublishPlanFinished(this.context);
|
|
293
|
+
this.#applied = true;
|
|
294
|
+
for (const plugin of this.context.plugins) await handlePluginError(plugin, "applyPlan", () => plugin.applyPlan?.call(this.context, this));
|
|
267
295
|
const { graph } = this.context;
|
|
268
|
-
const updatedPackages = /* @__PURE__ */ new Map();
|
|
269
296
|
const writes = [];
|
|
270
|
-
for (const [id,
|
|
297
|
+
for (const [id, packagePlan] of this.packages) {
|
|
271
298
|
const pkg = graph.get(id);
|
|
272
299
|
if (!pkg) continue;
|
|
273
|
-
|
|
274
|
-
plan,
|
|
275
|
-
version: bumpVersion(pkg.version, plan.type)
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
for (const pkg of graph.getPackages()) {
|
|
279
|
-
const updated = updatedPackages.get(pkg.id);
|
|
280
|
-
for (const [id, updatedDep] of updatedPackages) {
|
|
281
|
-
const target = graph.get(id);
|
|
282
|
-
if (target) await pkg.updateDependency?.(target, updatedDep.version, this.context);
|
|
283
|
-
}
|
|
284
|
-
if (updated) {
|
|
285
|
-
pkg.setVersion?.(updated.version);
|
|
286
|
-
writes.push(this.appendChangelog(pkg, updated.plan));
|
|
287
|
-
}
|
|
288
|
-
const write = pkg.write?.();
|
|
289
|
-
if (write) writes.push(write);
|
|
300
|
+
writes.push(this.appendChangelog(pkg, packagePlan));
|
|
290
301
|
}
|
|
302
|
+
for (const entry of this.changelogs.values()) writes.push(rm(path.join(this.context.changelogDir, entry.filename), { force: true }));
|
|
291
303
|
await Promise.all(writes);
|
|
304
|
+
await mkdir(dirname(this.context.planPath), { recursive: true });
|
|
305
|
+
await writeFile(this.context.planPath, createPlanStore(this, this.context));
|
|
292
306
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
await Promise.all(writes);
|
|
307
|
+
addPolicy(policy) {
|
|
308
|
+
this.policies.push(policy);
|
|
309
|
+
}
|
|
310
|
+
removePolicy(policy) {
|
|
311
|
+
const idx = this.policies.indexOf(policy);
|
|
312
|
+
if (idx !== -1) this.policies.splice(idx, 1);
|
|
300
313
|
}
|
|
301
|
-
|
|
302
|
-
|
|
314
|
+
canApply() {
|
|
315
|
+
return !this.#applied;
|
|
303
316
|
}
|
|
304
317
|
async appendChangelog(pkg, plan) {
|
|
305
|
-
if (plan.
|
|
318
|
+
if (!plan.changelogs || plan.changelogs.length === 0) return;
|
|
306
319
|
const { generator = simpleGenerator() } = this.context.options;
|
|
307
|
-
const changelogs = [];
|
|
308
|
-
for (const id of plan.changelogIds) {
|
|
309
|
-
const entry = this.changelogs.get(id);
|
|
310
|
-
if (entry) changelogs.push(entry);
|
|
311
|
-
}
|
|
312
320
|
const generated = await generator.generate.call(this.context, {
|
|
321
|
+
packageId: pkg.id,
|
|
313
322
|
packageName: pkg.name,
|
|
314
323
|
version: pkg.version,
|
|
315
|
-
|
|
324
|
+
npm: plan.npm,
|
|
325
|
+
plan,
|
|
326
|
+
changelogs: plan.changelogs,
|
|
327
|
+
_draft: this
|
|
316
328
|
});
|
|
317
329
|
const path = join(pkg.path, "CHANGELOG.md");
|
|
318
330
|
const existing = await readFile(path, "utf8").catch(() => "");
|
|
319
331
|
await writeFile(path, `${generated.trim()}\n\n${existing}`.trimEnd() + "\n");
|
|
320
332
|
}
|
|
321
|
-
/** {@link
|
|
333
|
+
/** {@link applyPlan} but for `await using` syntax */
|
|
322
334
|
async [Symbol.asyncDispose]() {
|
|
323
|
-
return this.
|
|
335
|
+
return this.applyPlan();
|
|
324
336
|
}
|
|
325
337
|
};
|
|
326
|
-
async function
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
changelogMap.set(entry.id, entry);
|
|
339
|
-
for (const requestedPackage of entry.packages) for (const pkg of context.graph.getByName(requestedPackage)) {
|
|
340
|
-
let entries = byPackage.get(pkg);
|
|
341
|
-
if (!entries) {
|
|
342
|
-
entries = [];
|
|
343
|
-
byPackage.set(pkg, entries);
|
|
344
|
-
}
|
|
345
|
-
entries.push(entry);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
const packages = /* @__PURE__ */ new Map();
|
|
349
|
-
for (const [pkg, entries] of byPackage.entries()) {
|
|
350
|
-
const plan = createPackagePlan(pkg, entries, context);
|
|
351
|
-
if (plan) packages.set(pkg.id, plan);
|
|
352
|
-
}
|
|
353
|
-
return new DraftPlan(changelogMap, packages, context);
|
|
338
|
+
async function cleanupPublishPlan(context) {
|
|
339
|
+
const store = await readPlanStore(context);
|
|
340
|
+
if (!store) return {
|
|
341
|
+
state: "skipped",
|
|
342
|
+
reason: "missing"
|
|
343
|
+
};
|
|
344
|
+
if ((await publishPlanStatus(store, context)).state !== "success") return {
|
|
345
|
+
state: "skipped",
|
|
346
|
+
reason: "pending"
|
|
347
|
+
};
|
|
348
|
+
await rm(context.planPath, { force: true });
|
|
349
|
+
return { state: "removed" };
|
|
354
350
|
}
|
|
355
|
-
function
|
|
356
|
-
|
|
357
|
-
const
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
for (const entry of entries) {
|
|
361
|
-
changelogIds.add(entry.id);
|
|
362
|
-
type = maxBump(type, entry.type);
|
|
351
|
+
async function createDraftPlan(changelogs, context) {
|
|
352
|
+
let draft = new DraftPlan(context);
|
|
353
|
+
for (const plugin of context.plugins) {
|
|
354
|
+
const result = await handlePluginError(plugin, "initPlan", () => plugin.initPlan?.call(context, draft));
|
|
355
|
+
if (result) draft = result;
|
|
363
356
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
changelogIds,
|
|
367
|
-
distTag: packageOptions.distTag ?? pkg.distTag,
|
|
368
|
-
publish: packageOptions.publish ?? pkg.publish
|
|
369
|
-
};
|
|
357
|
+
for (const entry of changelogs) draft.addChangelog(entry);
|
|
358
|
+
return draft;
|
|
370
359
|
}
|
|
371
360
|
//#endregion
|
|
372
361
|
//#region src/utils/frontmatter.ts
|
|
@@ -392,20 +381,16 @@ function frontmatter(input) {
|
|
|
392
381
|
}
|
|
393
382
|
//#endregion
|
|
394
383
|
//#region src/changelog/parse.ts
|
|
395
|
-
async function
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
const content = await readFile(filePath, "utf8");
|
|
406
|
-
entries.push(...parseChangelogFile(filePath, content));
|
|
407
|
-
}
|
|
408
|
-
return entries;
|
|
384
|
+
async function getChangelogFiles(context) {
|
|
385
|
+
return (await readdir(context.changelogDir).catch(() => [])).filter((file) => file.endsWith(".md"));
|
|
386
|
+
}
|
|
387
|
+
async function readChangelogEntries(context) {
|
|
388
|
+
const dir = context.changelogDir;
|
|
389
|
+
const files = await getChangelogFiles(context);
|
|
390
|
+
return (await Promise.all(files.map(async (file) => {
|
|
391
|
+
const filePath = join(dir, file);
|
|
392
|
+
return parseChangelogFile(filePath, await readFile(filePath, "utf8"));
|
|
393
|
+
}))).flat();
|
|
409
394
|
}
|
|
410
395
|
/** Parse one changelog markdown file into release entries. */
|
|
411
396
|
function parseChangelogFile(file, content) {
|
|
@@ -470,23 +455,16 @@ function headingToBump(depth) {
|
|
|
470
455
|
}
|
|
471
456
|
//#endregion
|
|
472
457
|
//#region src/publish.ts
|
|
473
|
-
async function publishFromPlan(context,
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
state: packages.some((pkg) => pkg.state === "failed") ? "failed" : "success",
|
|
478
|
-
packages,
|
|
479
|
-
_rawPlan: plan
|
|
480
|
-
};
|
|
481
|
-
}
|
|
482
|
-
async function publishStoredPlan(store, context, { dryRun = false }) {
|
|
483
|
-
const results = [];
|
|
458
|
+
async function publishFromPlan(context, store, options) {
|
|
459
|
+
const { dryRun = false } = options;
|
|
460
|
+
const packages = [];
|
|
461
|
+
if ((await publishPlanStatus(store, context)).state !== "pending") return { state: "skipped" };
|
|
484
462
|
for (const [id, plan] of Object.entries(store.packages)) {
|
|
485
463
|
if (!plan.publish) continue;
|
|
486
464
|
const pkg = context.graph.get(id);
|
|
487
465
|
if (!pkg) continue;
|
|
488
466
|
const changelogs = [];
|
|
489
|
-
for (const id of plan.changelogIds) {
|
|
467
|
+
for (const id of plan.changelogIds ?? []) {
|
|
490
468
|
const entry = store.changelogs[id];
|
|
491
469
|
if (entry) changelogs.push({
|
|
492
470
|
...entry,
|
|
@@ -495,12 +473,12 @@ async function publishStoredPlan(store, context, { dryRun = false }) {
|
|
|
495
473
|
});
|
|
496
474
|
}
|
|
497
475
|
if (!dryRun) {
|
|
498
|
-
if (await context.getRegistryClient(pkg).
|
|
499
|
-
|
|
476
|
+
if (await context.getRegistryClient(pkg).isPackagePublished(pkg)) {
|
|
477
|
+
packages.push({
|
|
500
478
|
id: pkg.id,
|
|
501
479
|
name: pkg.name,
|
|
502
480
|
version: pkg.version,
|
|
503
|
-
|
|
481
|
+
npm: plan.npm,
|
|
504
482
|
state: "success",
|
|
505
483
|
changelogs
|
|
506
484
|
});
|
|
@@ -508,60 +486,77 @@ async function publishStoredPlan(store, context, { dryRun = false }) {
|
|
|
508
486
|
}
|
|
509
487
|
}
|
|
510
488
|
try {
|
|
511
|
-
if (!dryRun) await context.getRegistryClient(pkg).publish(pkg, {
|
|
512
|
-
|
|
489
|
+
if (!dryRun) await context.getRegistryClient(pkg).publish(pkg, {
|
|
490
|
+
packageStore: plan,
|
|
491
|
+
store
|
|
492
|
+
});
|
|
493
|
+
packages.push({
|
|
513
494
|
id: pkg.id,
|
|
514
495
|
name: pkg.name,
|
|
515
496
|
version: pkg.version,
|
|
516
|
-
|
|
497
|
+
npm: plan.npm,
|
|
517
498
|
state: "success",
|
|
518
499
|
changelogs
|
|
519
500
|
});
|
|
520
501
|
} catch (error) {
|
|
521
|
-
|
|
502
|
+
packages.push({
|
|
522
503
|
id: pkg.id,
|
|
523
504
|
name: pkg.name,
|
|
524
505
|
version: pkg.version,
|
|
525
|
-
|
|
506
|
+
npm: plan.npm,
|
|
526
507
|
changelogs,
|
|
527
508
|
state: "failed",
|
|
528
509
|
error: error instanceof Error ? error.message : String(error)
|
|
529
510
|
});
|
|
530
511
|
}
|
|
531
512
|
}
|
|
532
|
-
return
|
|
513
|
+
if (packages.length === 0) return { state: "skipped" };
|
|
514
|
+
return {
|
|
515
|
+
state: packages.some((pkg) => pkg.state === "failed") ? "failed" : "created",
|
|
516
|
+
packages,
|
|
517
|
+
_rawPlan: store
|
|
518
|
+
};
|
|
533
519
|
}
|
|
534
520
|
//#endregion
|
|
535
521
|
//#region src/index.ts
|
|
536
522
|
/** Create a Tegami project handle. */
|
|
537
523
|
function tegami(options = {}) {
|
|
524
|
+
const $context = init();
|
|
525
|
+
async function init() {
|
|
526
|
+
return createTegamiContext(options);
|
|
527
|
+
}
|
|
538
528
|
return {
|
|
539
|
-
async
|
|
540
|
-
return createChangelog(await
|
|
529
|
+
async generateChangelog(createOptions = {}) {
|
|
530
|
+
return createChangelog(await $context, createOptions);
|
|
541
531
|
},
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
532
|
+
_internal: {
|
|
533
|
+
options,
|
|
534
|
+
context() {
|
|
535
|
+
return $context;
|
|
536
|
+
},
|
|
537
|
+
async graph() {
|
|
538
|
+
return (await $context).graph;
|
|
539
|
+
}
|
|
547
540
|
},
|
|
548
|
-
async
|
|
549
|
-
|
|
541
|
+
async draft() {
|
|
542
|
+
const context = await $context;
|
|
543
|
+
return createDraftPlan(await readChangelogEntries(context), context);
|
|
550
544
|
},
|
|
551
545
|
async publish(publishOptions = {}) {
|
|
552
|
-
const context = await
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
});
|
|
557
|
-
if (parsed === void 0) throw new Error(`No publish plan found at ${context.planPath}.`);
|
|
546
|
+
const context = await $context;
|
|
547
|
+
if ((await getChangelogFiles(context)).length > 0) return { state: "skipped" };
|
|
548
|
+
const parsed = await readPlanStore(context);
|
|
549
|
+
if (!parsed) return { state: "skipped" };
|
|
558
550
|
let result = await publishFromPlan(context, parsed, publishOptions);
|
|
559
551
|
const publishCtx = {
|
|
560
552
|
...context,
|
|
561
553
|
publishOptions
|
|
562
554
|
};
|
|
563
|
-
for (const plugin of context.plugins) result = await plugin.afterPublish?.call(publishCtx, result) ?? result;
|
|
555
|
+
for (const plugin of context.plugins) result = await handlePluginError(plugin, "afterPublish", () => plugin.afterPublish?.call(publishCtx, result)) ?? result;
|
|
564
556
|
return result;
|
|
557
|
+
},
|
|
558
|
+
async cleanup() {
|
|
559
|
+
return cleanupPublishPlan(await $context);
|
|
565
560
|
}
|
|
566
561
|
};
|
|
567
562
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as TegamiPlugin } from "../index-Bhh2dJZp.js";
|
|
2
2
|
|
|
3
3
|
//#region src/plugins/git.d.ts
|
|
4
4
|
interface GitPluginOptions {
|
|
5
5
|
/** Set to false to skip creating git tags after all packages publish successfully. */
|
|
6
6
|
createTags?: boolean;
|
|
7
|
+
/** Push created tags to origin. Defaults to true in CI. */
|
|
8
|
+
pushTags?: boolean;
|
|
7
9
|
}
|
|
8
10
|
/**
|
|
9
11
|
* Basic Git integrations:
|
|
@@ -12,8 +14,5 @@ interface GitPluginOptions {
|
|
|
12
14
|
* Note: you do not need this with `github` plugin enabled.
|
|
13
15
|
*/
|
|
14
16
|
declare function git(options?: GitPluginOptions): TegamiPlugin;
|
|
15
|
-
/** create a Git tag, ignored if already exists */
|
|
16
|
-
declare function createGitTag(cwd: string, tag: string): Promise<void>;
|
|
17
|
-
declare function gitTagExists(cwd: string, tag: string): Promise<boolean>;
|
|
18
17
|
//#endregion
|
|
19
|
-
export { GitPluginOptions,
|
|
18
|
+
export { GitPluginOptions, git };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { t as execFailure } from "../error-DBK-9uBa.js";
|
|
2
|
+
import { t as isCI } from "../constants-B9qjNfvr.js";
|
|
3
|
+
import { x } from "tinyexec";
|
|
4
|
+
//#region src/plugins/git.ts
|
|
5
|
+
/**
|
|
6
|
+
* Basic Git integrations:
|
|
7
|
+
* - auto tags.
|
|
8
|
+
*
|
|
9
|
+
* Note: you do not need this with `github` plugin enabled.
|
|
10
|
+
*/
|
|
11
|
+
function git(options = {}) {
|
|
12
|
+
const { createTags = true, pushTags = isCI() } = options;
|
|
13
|
+
function resolveGitTag(context, result) {
|
|
14
|
+
const { graph } = context;
|
|
15
|
+
const pkg = graph.get(result.id);
|
|
16
|
+
if (!pkg) return `${result.name}@${result.version}`;
|
|
17
|
+
const group = graph.getPackageGroup(pkg.id);
|
|
18
|
+
if (group?.options.syncGitTag) return `${group.name}@${result.version}`;
|
|
19
|
+
return `${result.name}@${result.version}`;
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
name: "git",
|
|
23
|
+
enforce: "pre",
|
|
24
|
+
cli: { async init() {
|
|
25
|
+
if (!isCI()) return;
|
|
26
|
+
const gitOptions = { nodeOptions: { cwd: this.cwd } };
|
|
27
|
+
for (const args of [[
|
|
28
|
+
"config",
|
|
29
|
+
"user.name",
|
|
30
|
+
"github-actions[bot]"
|
|
31
|
+
], [
|
|
32
|
+
"config",
|
|
33
|
+
"user.email",
|
|
34
|
+
"41898282+github-actions[bot]@users.noreply.github.com"
|
|
35
|
+
]]) {
|
|
36
|
+
const result = await x("git", [...args], gitOptions);
|
|
37
|
+
if (result.exitCode !== 0) throw execFailure("Failed to configure git user for GitHub Actions.", result);
|
|
38
|
+
}
|
|
39
|
+
} },
|
|
40
|
+
async afterPublish(result) {
|
|
41
|
+
const { cwd, publishOptions: { dryRun = false } } = this;
|
|
42
|
+
if (dryRun || !createTags || result.state !== "created") return result;
|
|
43
|
+
const pendingTags = /* @__PURE__ */ new Set();
|
|
44
|
+
for (const pkg of result.packages) {
|
|
45
|
+
pkg.gitTag = resolveGitTag(this, pkg);
|
|
46
|
+
pendingTags.add(pkg.gitTag);
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const createdTags = [];
|
|
50
|
+
await Promise.all(Array.from(pendingTags).map(async (tag) => {
|
|
51
|
+
if (await gitTagExists(cwd, tag)) return;
|
|
52
|
+
const gitOut = await x("git", ["tag", tag], { nodeOptions: { cwd } });
|
|
53
|
+
if (gitOut.exitCode !== 0) throw execFailure(`Failed to create Git tag "${tag}" for release`, gitOut);
|
|
54
|
+
createdTags.push(tag);
|
|
55
|
+
}));
|
|
56
|
+
if (pushTags && createdTags.length > 0) {
|
|
57
|
+
const gitOut = await x("git", [
|
|
58
|
+
"push",
|
|
59
|
+
"origin",
|
|
60
|
+
...createdTags
|
|
61
|
+
], { nodeOptions: { cwd } });
|
|
62
|
+
if (gitOut.exitCode !== 0) throw execFailure(`Failed to push Git tags to origin: ${createdTags.join(", ")}`, gitOut);
|
|
63
|
+
}
|
|
64
|
+
} catch (error) {
|
|
65
|
+
return {
|
|
66
|
+
...result,
|
|
67
|
+
state: "failed",
|
|
68
|
+
error: error instanceof Error ? error.message : String(error)
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
async function gitTagExists(cwd, tag) {
|
|
76
|
+
return (await x("git", [
|
|
77
|
+
"rev-parse",
|
|
78
|
+
"-q",
|
|
79
|
+
"--verify",
|
|
80
|
+
`refs/tags/${tag}`
|
|
81
|
+
], { nodeOptions: { cwd } })).exitCode === 0;
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
export { git };
|