tegami 0.0.1 → 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/dist/checks-CKBRRjgQ.js +100 -0
- package/dist/cli/{index.d.mts → index.d.ts} +2 -2
- package/dist/cli/{index.mjs → index.js} +59 -46
- 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 -3
- 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} +179 -194
- package/dist/plugins/{git.d.mts → git.d.ts} +1 -1
- package/dist/plugins/git.js +84 -0
- package/dist/plugins/{github.d.mts → github.d.ts} +23 -9
- package/dist/plugins/github.js +187 -0
- package/dist/providers/cargo.d.ts +2 -0
- package/dist/providers/{cargo.mjs → cargo.js} +110 -52
- 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 -22
- package/dist/context-CC36jtz1.d.mts +0 -297
- package/dist/exec-hOS852t5.mjs +0 -12
- package/dist/index-DJ7YxxdM.d.mts +0 -35
- package/dist/index.d.mts +0 -3
- package/dist/npm-BpFlXy8I.mjs +0 -281
- package/dist/plugins/git.mjs +0 -99
- package/dist/plugins/github.mjs +0 -146
- 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/semver-FSWx3_34.mjs +0 -35
- package/dist/workspace-B5_i21S0.mjs +0 -63
- /package/dist/{constants-B9qjNfvr.mjs → constants-B9qjNfvr.js} +0 -0
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
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";
|
|
6
9
|
import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
7
|
-
import path, { basename, dirname, join
|
|
10
|
+
import path, { basename, dirname, join } from "node:path";
|
|
8
11
|
import { x } from "tinyexec";
|
|
9
12
|
import { load } from "js-yaml";
|
|
10
13
|
import { fromMarkdown } from "mdast-util-from-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,187 +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/
|
|
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
|
+
};
|
|
217
|
+
}
|
|
218
|
+
//#endregion
|
|
219
|
+
//#region src/plans/draft.ts
|
|
182
220
|
var DraftPlan = class {
|
|
183
|
-
changelogs;
|
|
184
|
-
packages;
|
|
185
221
|
context;
|
|
186
|
-
#
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
222
|
+
#applied = false;
|
|
223
|
+
packages = /* @__PURE__ */ new Map();
|
|
224
|
+
changelogs = /* @__PURE__ */ new Map();
|
|
225
|
+
policies = [];
|
|
226
|
+
constructor(context) {
|
|
190
227
|
this.context = context;
|
|
228
|
+
this.policies.push(groupPolicy(context));
|
|
191
229
|
}
|
|
192
|
-
|
|
193
|
-
return
|
|
230
|
+
getPackagePlans() {
|
|
231
|
+
return this.packages;
|
|
194
232
|
}
|
|
195
|
-
|
|
233
|
+
getPackagePlan(id) {
|
|
196
234
|
return this.packages.get(id);
|
|
197
235
|
}
|
|
198
|
-
|
|
199
|
-
this.packages.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
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
|
|
204
251
|
});
|
|
252
|
+
return plan;
|
|
205
253
|
}
|
|
206
|
-
|
|
207
|
-
|
|
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;
|
|
208
261
|
}
|
|
209
|
-
|
|
210
|
-
return Array.from(this.changelogs.
|
|
262
|
+
getChangelogs() {
|
|
263
|
+
return Array.from(this.changelogs.values());
|
|
211
264
|
}
|
|
212
265
|
getChangelog(id) {
|
|
213
266
|
return this.changelogs.get(id);
|
|
214
267
|
}
|
|
215
|
-
|
|
216
|
-
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
|
+
}
|
|
217
278
|
}
|
|
218
279
|
deleteChangelog(id) {
|
|
219
280
|
return this.changelogs.delete(id);
|
|
220
281
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
const plan = {
|
|
228
|
-
id: `tegami-${Date.now().toString(36)}`,
|
|
229
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
230
|
-
changelogs: Object.fromEntries(Array.from(this.changelogs, ([id, entry]) => [id, {
|
|
231
|
-
filename: entry.filename,
|
|
232
|
-
subject: entry.subject,
|
|
233
|
-
packages: Array.from(entry.packages),
|
|
234
|
-
type: entry.type,
|
|
235
|
-
title: entry.title,
|
|
236
|
-
content: entry.content
|
|
237
|
-
}])),
|
|
238
|
-
packages: Object.fromEntries(this.packages)
|
|
239
|
-
};
|
|
240
|
-
await mkdir(dirname(this.context.planPath), { recursive: true });
|
|
241
|
-
await writeFile(this.context.planPath, planStoreSchema.encode(plan));
|
|
242
|
-
await this.removeConsumedChangelogs();
|
|
243
|
-
}
|
|
244
|
-
editable() {
|
|
245
|
-
return !this.#created;
|
|
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;
|
|
246
288
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
if (
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
const
|
|
253
|
-
if (status.state === "success") return;
|
|
254
|
-
const message = `Publish plan already exists at ${this.context.planPath} and is ${status.state}. Publish it before creating a new plan.`;
|
|
255
|
-
throw new Error(status.error ? `${message}\n${status.error}` : message);
|
|
256
|
-
}
|
|
257
|
-
async applyVersionChanges() {
|
|
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));
|
|
258
295
|
const { graph } = this.context;
|
|
259
|
-
const updatedPackages = /* @__PURE__ */ new Map();
|
|
260
296
|
const writes = [];
|
|
261
|
-
for (const [id,
|
|
297
|
+
for (const [id, packagePlan] of this.packages) {
|
|
262
298
|
const pkg = graph.get(id);
|
|
263
299
|
if (!pkg) continue;
|
|
264
|
-
|
|
265
|
-
plan,
|
|
266
|
-
version: bumpVersion(pkg.version, plan.type)
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
for (const pkg of graph.getPackages()) {
|
|
270
|
-
const updated = updatedPackages.get(pkg.id);
|
|
271
|
-
for (const [id, updatedDep] of updatedPackages) {
|
|
272
|
-
const target = graph.get(id);
|
|
273
|
-
if (target) await pkg.updateDependency?.(target, updatedDep.version, this.context);
|
|
274
|
-
}
|
|
275
|
-
if (updated) {
|
|
276
|
-
pkg.setVersion?.(updated.version);
|
|
277
|
-
writes.push(this.appendChangelog(pkg, updated.plan));
|
|
278
|
-
}
|
|
279
|
-
const write = pkg.write?.();
|
|
280
|
-
if (write) writes.push(write);
|
|
300
|
+
writes.push(this.appendChangelog(pkg, packagePlan));
|
|
281
301
|
}
|
|
302
|
+
for (const entry of this.changelogs.values()) writes.push(rm(path.join(this.context.changelogDir, entry.filename), { force: true }));
|
|
282
303
|
await Promise.all(writes);
|
|
304
|
+
await mkdir(dirname(this.context.planPath), { recursive: true });
|
|
305
|
+
await writeFile(this.context.planPath, createPlanStore(this, this.context));
|
|
283
306
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
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);
|
|
291
313
|
}
|
|
292
|
-
|
|
293
|
-
|
|
314
|
+
canApply() {
|
|
315
|
+
return !this.#applied;
|
|
294
316
|
}
|
|
295
317
|
async appendChangelog(pkg, plan) {
|
|
296
|
-
if (plan.
|
|
318
|
+
if (!plan.changelogs || plan.changelogs.length === 0) return;
|
|
297
319
|
const { generator = simpleGenerator() } = this.context.options;
|
|
298
|
-
const changelogs = [];
|
|
299
|
-
for (const id of plan.changelogIds) {
|
|
300
|
-
const entry = this.changelogs.get(id);
|
|
301
|
-
if (entry) changelogs.push(entry);
|
|
302
|
-
}
|
|
303
320
|
const generated = await generator.generate.call(this.context, {
|
|
321
|
+
packageId: pkg.id,
|
|
304
322
|
packageName: pkg.name,
|
|
305
323
|
version: pkg.version,
|
|
306
|
-
|
|
307
|
-
|
|
324
|
+
npm: plan.npm,
|
|
325
|
+
plan,
|
|
326
|
+
changelogs: plan.changelogs,
|
|
327
|
+
_draft: this
|
|
308
328
|
});
|
|
309
329
|
const path = join(pkg.path, "CHANGELOG.md");
|
|
310
330
|
const existing = await readFile(path, "utf8").catch(() => "");
|
|
311
331
|
await writeFile(path, `${generated.trim()}\n\n${existing}`.trimEnd() + "\n");
|
|
312
332
|
}
|
|
313
|
-
/** {@link
|
|
333
|
+
/** {@link applyPlan} but for `await using` syntax */
|
|
314
334
|
async [Symbol.asyncDispose]() {
|
|
315
|
-
return this.
|
|
335
|
+
return this.applyPlan();
|
|
316
336
|
}
|
|
317
337
|
};
|
|
318
|
-
async function
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
}
|
|
324
|
-
|
|
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" };
|
|
325
350
|
}
|
|
326
|
-
function createDraftPlan(changelogs, context) {
|
|
327
|
-
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
for (const requestedPackage of entry.packages) for (const pkg of context.graph.getByName(requestedPackage)) {
|
|
332
|
-
let entries = byPackage.get(pkg);
|
|
333
|
-
if (!entries) {
|
|
334
|
-
entries = [];
|
|
335
|
-
byPackage.set(pkg, entries);
|
|
336
|
-
}
|
|
337
|
-
entries.push(entry);
|
|
338
|
-
}
|
|
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;
|
|
339
356
|
}
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
const plan = createPackagePlan(pkg, entries, context);
|
|
343
|
-
if (plan) packages.set(pkg.id, plan);
|
|
344
|
-
}
|
|
345
|
-
return new DraftPlan(changelogMap, packages, context);
|
|
346
|
-
}
|
|
347
|
-
function createPackagePlan(pkg, entries, context) {
|
|
348
|
-
if (entries.length === 0) return null;
|
|
349
|
-
const packageOptions = context.options.packages?.[pkg.id] ?? context.options.packages?.[pkg.name] ?? {};
|
|
350
|
-
let type = entries[0].type;
|
|
351
|
-
const changelogIds = /* @__PURE__ */ new Set();
|
|
352
|
-
for (const entry of entries) {
|
|
353
|
-
changelogIds.add(entry.id);
|
|
354
|
-
type = maxBump(type, entry.type);
|
|
355
|
-
}
|
|
356
|
-
return {
|
|
357
|
-
type,
|
|
358
|
-
changelogIds,
|
|
359
|
-
distTag: packageOptions.distTag ?? pkg.distTag,
|
|
360
|
-
publish: packageOptions.publish ?? pkg.publish
|
|
361
|
-
};
|
|
357
|
+
for (const entry of changelogs) draft.addChangelog(entry);
|
|
358
|
+
return draft;
|
|
362
359
|
}
|
|
363
360
|
//#endregion
|
|
364
361
|
//#region src/utils/frontmatter.ts
|
|
@@ -384,20 +381,16 @@ function frontmatter(input) {
|
|
|
384
381
|
}
|
|
385
382
|
//#endregion
|
|
386
383
|
//#region src/changelog/parse.ts
|
|
387
|
-
async function
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
const content = await readFile(filePath, "utf8");
|
|
398
|
-
entries.push(...parseChangelogFile(filePath, content));
|
|
399
|
-
}
|
|
400
|
-
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();
|
|
401
394
|
}
|
|
402
395
|
/** Parse one changelog markdown file into release entries. */
|
|
403
396
|
function parseChangelogFile(file, content) {
|
|
@@ -465,12 +458,13 @@ function headingToBump(depth) {
|
|
|
465
458
|
async function publishFromPlan(context, store, options) {
|
|
466
459
|
const { dryRun = false } = options;
|
|
467
460
|
const packages = [];
|
|
461
|
+
if ((await publishPlanStatus(store, context)).state !== "pending") return { state: "skipped" };
|
|
468
462
|
for (const [id, plan] of Object.entries(store.packages)) {
|
|
469
463
|
if (!plan.publish) continue;
|
|
470
464
|
const pkg = context.graph.get(id);
|
|
471
465
|
if (!pkg) continue;
|
|
472
466
|
const changelogs = [];
|
|
473
|
-
for (const id of plan.changelogIds) {
|
|
467
|
+
for (const id of plan.changelogIds ?? []) {
|
|
474
468
|
const entry = store.changelogs[id];
|
|
475
469
|
if (entry) changelogs.push({
|
|
476
470
|
...entry,
|
|
@@ -479,12 +473,12 @@ async function publishFromPlan(context, store, options) {
|
|
|
479
473
|
});
|
|
480
474
|
}
|
|
481
475
|
if (!dryRun) {
|
|
482
|
-
if (await context.getRegistryClient(pkg).
|
|
476
|
+
if (await context.getRegistryClient(pkg).isPackagePublished(pkg)) {
|
|
483
477
|
packages.push({
|
|
484
478
|
id: pkg.id,
|
|
485
479
|
name: pkg.name,
|
|
486
480
|
version: pkg.version,
|
|
487
|
-
|
|
481
|
+
npm: plan.npm,
|
|
488
482
|
state: "success",
|
|
489
483
|
changelogs
|
|
490
484
|
});
|
|
@@ -492,12 +486,15 @@ async function publishFromPlan(context, store, options) {
|
|
|
492
486
|
}
|
|
493
487
|
}
|
|
494
488
|
try {
|
|
495
|
-
if (!dryRun) await context.getRegistryClient(pkg).publish(pkg, {
|
|
489
|
+
if (!dryRun) await context.getRegistryClient(pkg).publish(pkg, {
|
|
490
|
+
packageStore: plan,
|
|
491
|
+
store
|
|
492
|
+
});
|
|
496
493
|
packages.push({
|
|
497
494
|
id: pkg.id,
|
|
498
495
|
name: pkg.name,
|
|
499
496
|
version: pkg.version,
|
|
500
|
-
|
|
497
|
+
npm: plan.npm,
|
|
501
498
|
state: "success",
|
|
502
499
|
changelogs
|
|
503
500
|
});
|
|
@@ -506,19 +503,15 @@ async function publishFromPlan(context, store, options) {
|
|
|
506
503
|
id: pkg.id,
|
|
507
504
|
name: pkg.name,
|
|
508
505
|
version: pkg.version,
|
|
509
|
-
|
|
506
|
+
npm: plan.npm,
|
|
510
507
|
changelogs,
|
|
511
508
|
state: "failed",
|
|
512
509
|
error: error instanceof Error ? error.message : String(error)
|
|
513
510
|
});
|
|
514
511
|
}
|
|
515
512
|
}
|
|
516
|
-
if (packages.length === 0) return {
|
|
517
|
-
state: "skipped",
|
|
518
|
-
planPath: context.planPath
|
|
519
|
-
};
|
|
513
|
+
if (packages.length === 0) return { state: "skipped" };
|
|
520
514
|
return {
|
|
521
|
-
planPath: context.planPath,
|
|
522
515
|
state: packages.some((pkg) => pkg.state === "failed") ? "failed" : "created",
|
|
523
516
|
packages,
|
|
524
517
|
_rawPlan: store
|
|
@@ -547,31 +540,23 @@ function tegami(options = {}) {
|
|
|
547
540
|
},
|
|
548
541
|
async draft() {
|
|
549
542
|
const context = await $context;
|
|
550
|
-
|
|
551
|
-
for (const plugin of context.plugins) plan = await plugin.initPlan?.call(context, plan) ?? plan;
|
|
552
|
-
return plan;
|
|
543
|
+
return createDraftPlan(await readChangelogEntries(context), context);
|
|
553
544
|
},
|
|
554
545
|
async publish(publishOptions = {}) {
|
|
555
546
|
const context = await $context;
|
|
556
|
-
if ((await
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
};
|
|
560
|
-
const parsed = await readFile(context.planPath, "utf8").then((content) => planStoreSchema.decode(content)).catch((error) => {
|
|
561
|
-
if (isNodeError(error) && error.code === "ENOENT") return void 0;
|
|
562
|
-
throw error;
|
|
563
|
-
});
|
|
564
|
-
if (parsed === void 0) return {
|
|
565
|
-
state: "skipped",
|
|
566
|
-
planPath: context.planPath
|
|
567
|
-
};
|
|
547
|
+
if ((await getChangelogFiles(context)).length > 0) return { state: "skipped" };
|
|
548
|
+
const parsed = await readPlanStore(context);
|
|
549
|
+
if (!parsed) return { state: "skipped" };
|
|
568
550
|
let result = await publishFromPlan(context, parsed, publishOptions);
|
|
569
551
|
const publishCtx = {
|
|
570
552
|
...context,
|
|
571
553
|
publishOptions
|
|
572
554
|
};
|
|
573
|
-
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;
|
|
574
556
|
return result;
|
|
557
|
+
},
|
|
558
|
+
async cleanup() {
|
|
559
|
+
return cleanupPublishPlan(await $context);
|
|
575
560
|
}
|
|
576
561
|
};
|
|
577
562
|
}
|
|
@@ -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 };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { GitPluginOptions } from "./git.
|
|
1
|
+
import { a as Awaitable, d as TegamiPlugin, w as DraftPlan, x as PackagePublishResult } from "../index-Bhh2dJZp.js";
|
|
2
|
+
import { GitPluginOptions } from "./git.js";
|
|
3
3
|
|
|
4
4
|
//#region src/plugins/github.d.ts
|
|
5
5
|
interface GithubRelease {
|
|
@@ -10,29 +10,43 @@ interface GithubRelease {
|
|
|
10
10
|
/** Whether to mark release as prerelease */
|
|
11
11
|
prerelease?: boolean;
|
|
12
12
|
}
|
|
13
|
-
interface
|
|
14
|
-
/** Pull request branch. */
|
|
15
|
-
branch?: string;
|
|
16
|
-
/** Pull request base branch. */
|
|
17
|
-
base?: string;
|
|
13
|
+
interface VersionPullRequest {
|
|
18
14
|
/** Pull request title. */
|
|
19
15
|
title?: string;
|
|
20
16
|
/** Pull request body. */
|
|
21
17
|
body?: string;
|
|
22
18
|
}
|
|
19
|
+
interface VersionPullRequestOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Pull request branch.
|
|
22
|
+
*
|
|
23
|
+
* @default "tegami/version-packages"
|
|
24
|
+
*/
|
|
25
|
+
branch?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Pull request base branch.
|
|
28
|
+
*
|
|
29
|
+
* @default "main"
|
|
30
|
+
*/
|
|
31
|
+
base?: string;
|
|
32
|
+
}
|
|
23
33
|
/** Options for creating GitHub releases after a successful publish. */
|
|
24
34
|
interface GitHubPluginOptions extends GitPluginOptions {
|
|
25
35
|
/** GitHub repository. */
|
|
26
36
|
repo?: string;
|
|
27
|
-
/**
|
|
37
|
+
/** Override release details for a single package, return `false` to skip. */
|
|
28
38
|
onCreateRelease?: (result: PackagePublishResult) => Awaitable<GithubRelease | false>;
|
|
39
|
+
/** Override release details when multiple packages share a git tag, return `false` to skip. */
|
|
40
|
+
onCreateGroupedRelease?: (packages: PackagePublishResult[]) => Awaitable<GithubRelease | false>;
|
|
41
|
+
/** Override details for "Version Packages" PR. */
|
|
42
|
+
onCreateVersionPullRequest?: (publishPlan: DraftPlan) => Awaitable<VersionPullRequest | false>;
|
|
29
43
|
cli?: {
|
|
30
44
|
/**
|
|
31
45
|
* Open a version pull request after versioning.
|
|
32
46
|
* Defaults to enabled in CI and disabled locally.
|
|
33
47
|
* Set to `true` to always create the pull request.
|
|
34
48
|
*/
|
|
35
|
-
|
|
49
|
+
versionPr?: boolean | VersionPullRequestOptions;
|
|
36
50
|
};
|
|
37
51
|
}
|
|
38
52
|
/** Create GitHub releases for successfully published packages after the whole plan succeeds. */
|