tegami 1.1.1 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,445 @@
1
+ import { r as formatNpmDistTag } from "./semver-EKJ8yK5U.js";
2
+ import { n as execFailure, o as isCI } from "./error-BhMYq9iW.js";
3
+ import { t as _accessExpressionAsString } from "./_accessExpressionAsString-QhbUZzwv.js";
4
+ import { n as _validateReport, t as _createStandardSchema } from "./_createStandardSchema-BGQyz-uA.js";
5
+ import { i as parsePublishLock } from "./draft-CzUiQasJ.js";
6
+ import { readFile, writeFile } from "node:fs/promises";
7
+ import { x } from "tinyexec";
8
+ //#region src/utils/version-request.ts
9
+ const validatePublishGroupStore = (() => {
10
+ const _io0 = (input) => Array.isArray(input.active) && input.active.every((elem) => "object" === typeof elem && null !== elem && _io1(elem)) && Array.isArray(input.pending) && input.pending.every((elem) => "object" === typeof elem && null !== elem && _io1(elem)) && "object" === typeof input.versions && null !== input.versions && false === Array.isArray(input.versions) && _io2(input.versions);
11
+ const _io1 = (input) => "string" === typeof input.title && "string" === typeof input.branch && Array.isArray(input.packages) && input.packages.every((elem) => "string" === typeof elem);
12
+ const _io2 = (input) => Object.keys(input).every((key) => {
13
+ const value = input[key];
14
+ if (void 0 === value) return true;
15
+ return "string" === typeof value;
16
+ });
17
+ const _vo0 = (input, _path, _exceptionable = true) => [
18
+ (Array.isArray(input.active) || _report(_exceptionable, {
19
+ path: _path + ".active",
20
+ expected: "Array<PublishGroup>",
21
+ value: input.active
22
+ })) && input.active.map((elem, _index4) => ("object" === typeof elem && null !== elem || _report(_exceptionable, {
23
+ path: _path + ".active[" + _index4 + "]",
24
+ expected: "PublishGroup",
25
+ value: elem
26
+ })) && _vo1(elem, _path + ".active[" + _index4 + "]", _exceptionable) || _report(_exceptionable, {
27
+ path: _path + ".active[" + _index4 + "]",
28
+ expected: "PublishGroup",
29
+ value: elem
30
+ })).every((flag) => flag) || _report(_exceptionable, {
31
+ path: _path + ".active",
32
+ expected: "Array<PublishGroup>",
33
+ value: input.active
34
+ }),
35
+ (Array.isArray(input.pending) || _report(_exceptionable, {
36
+ path: _path + ".pending",
37
+ expected: "Array<PublishGroup>",
38
+ value: input.pending
39
+ })) && input.pending.map((elem, _index5) => ("object" === typeof elem && null !== elem || _report(_exceptionable, {
40
+ path: _path + ".pending[" + _index5 + "]",
41
+ expected: "PublishGroup",
42
+ value: elem
43
+ })) && _vo1(elem, _path + ".pending[" + _index5 + "]", _exceptionable) || _report(_exceptionable, {
44
+ path: _path + ".pending[" + _index5 + "]",
45
+ expected: "PublishGroup",
46
+ value: elem
47
+ })).every((flag) => flag) || _report(_exceptionable, {
48
+ path: _path + ".pending",
49
+ expected: "Array<PublishGroup>",
50
+ value: input.pending
51
+ }),
52
+ ("object" === typeof input.versions && null !== input.versions && false === Array.isArray(input.versions) || _report(_exceptionable, {
53
+ path: _path + ".versions",
54
+ expected: "Record<string, string>",
55
+ value: input.versions
56
+ })) && _vo2(input.versions, _path + ".versions", _exceptionable) || _report(_exceptionable, {
57
+ path: _path + ".versions",
58
+ expected: "Record<string, string>",
59
+ value: input.versions
60
+ })
61
+ ].every((flag) => flag);
62
+ const _vo1 = (input, _path, _exceptionable = true) => [
63
+ "string" === typeof input.title || _report(_exceptionable, {
64
+ path: _path + ".title",
65
+ expected: "string",
66
+ value: input.title
67
+ }),
68
+ "string" === typeof input.branch || _report(_exceptionable, {
69
+ path: _path + ".branch",
70
+ expected: "string",
71
+ value: input.branch
72
+ }),
73
+ (Array.isArray(input.packages) || _report(_exceptionable, {
74
+ path: _path + ".packages",
75
+ expected: "Array<string>",
76
+ value: input.packages
77
+ })) && input.packages.map((elem, _index6) => "string" === typeof elem || _report(_exceptionable, {
78
+ path: _path + ".packages[" + _index6 + "]",
79
+ expected: "string",
80
+ value: elem
81
+ })).every((flag) => flag) || _report(_exceptionable, {
82
+ path: _path + ".packages",
83
+ expected: "Array<string>",
84
+ value: input.packages
85
+ })
86
+ ].every((flag) => flag);
87
+ const _vo2 = (input, _path, _exceptionable = true) => [false === _exceptionable || Object.keys(input).map((key) => {
88
+ const value = input[key];
89
+ if (void 0 === value) return true;
90
+ return "string" === typeof value || _report(_exceptionable, {
91
+ path: _path + _accessExpressionAsString(key),
92
+ expected: "string",
93
+ value
94
+ });
95
+ }).every((flag) => flag)].every((flag) => flag);
96
+ const __is = (input) => "object" === typeof input && null !== input && _io0(input);
97
+ let errors;
98
+ let _report;
99
+ return _createStandardSchema((input) => {
100
+ if (false === __is(input)) {
101
+ errors = [];
102
+ _report = _validateReport(errors);
103
+ ((input, _path, _exceptionable = true) => ("object" === typeof input && null !== input || _report(true, {
104
+ path: _path + "",
105
+ expected: "PublishGroupStore",
106
+ value: input
107
+ })) && _vo0(input, _path + "", true) || _report(true, {
108
+ path: _path + "",
109
+ expected: "PublishGroupStore",
110
+ value: input
111
+ }))(input, "$input", true);
112
+ const success = 0 === errors.length;
113
+ return success ? {
114
+ success,
115
+ data: input
116
+ } : {
117
+ success,
118
+ errors,
119
+ data: input
120
+ };
121
+ }
122
+ return {
123
+ success: true,
124
+ data: input
125
+ };
126
+ });
127
+ })();
128
+ function onVersionRequest(provider) {
129
+ const namespace = `${provider.name}:publish-group`;
130
+ /** package id -> version before applying the CLI draft */
131
+ const snapshots = /* @__PURE__ */ new Map();
132
+ /** publish group state restored from the lock, publish-time only */
133
+ let store;
134
+ function resolveConfig() {
135
+ if (provider.options === false) return;
136
+ const { forceCreate = false, branch = "tegami/version-packages", base = "main", groups, create } = provider.options ?? {};
137
+ return {
138
+ forceCreate,
139
+ branch,
140
+ base,
141
+ groups,
142
+ create
143
+ };
144
+ }
145
+ async function createDraftRequest(context, config, draft, versions, group) {
146
+ const custom = await config.create?.call(context, {
147
+ draft,
148
+ publishGroup: group?.packages
149
+ });
150
+ return {
151
+ title: custom?.title ?? group?.title ?? "Version Packages",
152
+ body: custom?.body ?? renderRequestBody(draftRequestItems(context, draft, versions, group), provider.summary)
153
+ };
154
+ }
155
+ async function upsertRequest(context, request) {
156
+ const handle = await provider.find(context, {
157
+ head: request.head,
158
+ base: request.base
159
+ });
160
+ if (handle !== void 0) await provider.update(context, handle, request);
161
+ else await provider.create(context, request);
162
+ }
163
+ return {
164
+ /** snapshot package versions, hook into `initCliDraft` */
165
+ initCliDraft() {
166
+ for (const pkg of this.graph.getPackages()) snapshots.set(pkg.id, pkg.version);
167
+ },
168
+ /** commit & push version branches, then upsert their requests, hook into `applyCliDraft` */
169
+ async applyCliDraft(draft) {
170
+ const config = resolveConfig();
171
+ if (!config || !provider.enabled(this)) return;
172
+ if (!(config.forceCreate || isCI()) || !await hasGitChanges(this.cwd)) return;
173
+ /** package id -> version before the bump */
174
+ const versions = {};
175
+ for (const id of draft.getPackageDrafts().keys()) {
176
+ const pkg = this.graph.get(id);
177
+ const original = snapshots.get(id);
178
+ if (!pkg?.version || !original || original === pkg.version) continue;
179
+ versions[id] = original;
180
+ }
181
+ const groups = resolvePublishGroups(this, config.branch, config.groups, versions);
182
+ if (groups.length === 0) {
183
+ const request = await createDraftRequest(this, config, draft, versions);
184
+ await createVersionCommit(this.cwd, request.title);
185
+ await pushBranch(this.cwd, config.branch);
186
+ await upsertRequest(this, {
187
+ ...request,
188
+ head: config.branch,
189
+ base: config.base
190
+ });
191
+ return;
192
+ }
193
+ const requests = [];
194
+ for (const group of groups) {
195
+ const request = await createDraftRequest(this, config, draft, versions, group);
196
+ group.title = request.title;
197
+ requests.push(request);
198
+ }
199
+ await createVersionCommit(this.cwd, "Version Packages");
200
+ const versionCommit = await run(this.cwd, ["rev-parse", "HEAD"], "Failed to resolve the version commit.");
201
+ if (!versionCommit) throw new Error("Failed to resolve the version commit.");
202
+ /** lock content of the version commit, without publish groups */
203
+ const lockContent = await readFile(this.lockPath, "utf8");
204
+ for (let i = 0; i < groups.length; i++) {
205
+ const group = groups[i];
206
+ const request = requests[i];
207
+ if (i > 0) await run(this.cwd, [
208
+ "checkout",
209
+ "--detach",
210
+ versionCommit
211
+ ], "Failed to check out the version commit.");
212
+ const lock = parsePublishLock(lockContent);
213
+ lock.write(namespace, {
214
+ active: [group],
215
+ pending: groups.filter((other) => other !== group),
216
+ versions
217
+ });
218
+ await writeFile(this.lockPath, lock.serialize());
219
+ await commitChanges(this.cwd, request.title);
220
+ await pushBranch(this.cwd, group.branch);
221
+ await upsertRequest(this, {
222
+ ...request,
223
+ head: group.branch,
224
+ base: config.base
225
+ });
226
+ }
227
+ },
228
+ /** restore publish groups from the lock into the plan, hook into `initPublishPlan` */
229
+ initPublishPlan({ lock, plan }) {
230
+ store = void 0;
231
+ let data;
232
+ const entries = [];
233
+ while ((data = lock.read(namespace)) !== void 0) {
234
+ const validated = validatePublishGroupStore(data);
235
+ if (validated.success) entries.push(validated.data);
236
+ }
237
+ if (entries.length === 0) return;
238
+ const merged = {
239
+ active: [],
240
+ pending: [],
241
+ versions: {}
242
+ };
243
+ const seen = /* @__PURE__ */ new Set();
244
+ for (const entry of entries) {
245
+ Object.assign(merged.versions, entry.versions);
246
+ for (const group of entry.active) {
247
+ if (seen.has(group.branch)) continue;
248
+ seen.add(group.branch);
249
+ merged.active.push(group);
250
+ }
251
+ }
252
+ for (const entry of entries) for (const group of entry.pending) {
253
+ if (seen.has(group.branch)) continue;
254
+ seen.add(group.branch);
255
+ merged.pending.push(group);
256
+ }
257
+ store = merged;
258
+ const packages = new Set(plan.options.packages);
259
+ for (const group of merged.active) for (const name of group.packages) packages.add(name);
260
+ if (packages.size > 0) plan.options = {
261
+ ...plan.options,
262
+ packages: Array.from(packages)
263
+ };
264
+ },
265
+ /** report `pending` while publish groups are waiting for their request, hook into `resolvePlanStatus` */
266
+ resolvePlanStatus() {
267
+ if (store && store.pending.length > 0) return "pending";
268
+ },
269
+ /** re-sync the version requests of pending publish groups, hook into `beforePublishAll` */
270
+ async beforePublishAll({ plan }) {
271
+ if (!store || store.pending.length === 0 || plan.options.dryRun) return;
272
+ const config = resolveConfig();
273
+ if (!config || !provider.enabled(this)) return;
274
+ const head = await run(this.cwd, ["rev-parse", "HEAD"], "Failed to resolve the current commit.");
275
+ const ref = await run(this.cwd, [
276
+ "rev-parse",
277
+ "--abbrev-ref",
278
+ "HEAD"
279
+ ], "Failed to resolve the current branch.");
280
+ const lockContent = await readFile(this.lockPath, "utf8");
281
+ try {
282
+ for (const group of store.pending) {
283
+ const lock = parsePublishLock(lockContent);
284
+ while (lock.read(namespace) !== void 0);
285
+ lock.write(namespace, {
286
+ active: [...store.active, group],
287
+ pending: store.pending.filter((other) => other !== group),
288
+ versions: store.versions
289
+ });
290
+ await run(this.cwd, [
291
+ "checkout",
292
+ "--detach",
293
+ head
294
+ ], "Failed to check out the current commit.");
295
+ await writeFile(this.lockPath, lock.serialize());
296
+ await commitChanges(this.cwd, group.title);
297
+ await pushBranch(this.cwd, group.branch);
298
+ await upsertRequest(this, {
299
+ title: group.title,
300
+ body: renderRequestBody(planRequestItems(this, plan, store.versions, group), provider.summary),
301
+ head: group.branch,
302
+ base: config.base
303
+ });
304
+ }
305
+ } finally {
306
+ await run(this.cwd, ["checkout", ref === "HEAD" ? head : ref], "Failed to restore the original checkout.");
307
+ }
308
+ }
309
+ };
310
+ }
311
+ function resolvePublishGroups(context, branch, groups, versions) {
312
+ if (!groups?.length) return [];
313
+ const out = [];
314
+ const matched = /* @__PURE__ */ new Set();
315
+ for (const entry of groups) {
316
+ const members = Array.isArray(entry) ? entry : [entry];
317
+ let hasMatched = false;
318
+ for (const name of members) for (const pkg of context.graph.getByName(name)) if (pkg.id in versions && !matched.has(pkg.id)) {
319
+ hasMatched = true;
320
+ matched.add(pkg.id);
321
+ }
322
+ if (!hasMatched) continue;
323
+ const slug = members.map(branchSlug).filter(Boolean).join("-") || "group";
324
+ out.push({
325
+ title: `Release ${members.join(", ")}`,
326
+ branch: `${branch}/${slug}`,
327
+ packages: members
328
+ });
329
+ }
330
+ const unlisted = Object.keys(versions).filter((id) => !matched.has(id));
331
+ if (unlisted.length > 0) out.push({
332
+ title: "Release unlisted packages",
333
+ branch: `${branch}/unlisted`,
334
+ packages: unlisted
335
+ });
336
+ return out;
337
+ }
338
+ function branchSlug(name) {
339
+ return name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
340
+ }
341
+ function resolveMembers(context, group) {
342
+ const ids = /* @__PURE__ */ new Set();
343
+ for (const name of group.packages) for (const pkg of context.graph.getByName(name)) ids.add(pkg.id);
344
+ return ids;
345
+ }
346
+ function draftRequestItems(context, draft, versions, group) {
347
+ const members = group ? resolveMembers(context, group) : void 0;
348
+ const items = [];
349
+ for (const [id, packageDraft] of draft.getPackageDrafts()) {
350
+ if (members && !members.has(id)) continue;
351
+ const pkg = context.graph.get(id);
352
+ if (!pkg) continue;
353
+ items.push({
354
+ pkg,
355
+ from: versions[id],
356
+ changelogs: packageDraft.changelogs ?? [],
357
+ distTag: packageDraft.npm?.distTag
358
+ });
359
+ }
360
+ return items;
361
+ }
362
+ function planRequestItems(context, plan, versions, group) {
363
+ const items = [];
364
+ for (const id of resolveMembers(context, group)) {
365
+ const pkg = context.graph.get(id);
366
+ const packagePlan = plan.packages.get(id);
367
+ if (!pkg || !packagePlan) continue;
368
+ items.push({
369
+ pkg,
370
+ from: versions[id],
371
+ changelogs: packagePlan.changelogs,
372
+ distTag: packagePlan.npm?.distTag
373
+ });
374
+ }
375
+ return items;
376
+ }
377
+ function renderRequestBody(items, summary) {
378
+ const packageLines = [];
379
+ const changesets = /* @__PURE__ */ new Map();
380
+ for (const { pkg, from, changelogs, distTag } of items) {
381
+ for (const entry of changelogs) {
382
+ const list = changesets.get(entry);
383
+ if (list) list.push(pkg);
384
+ else changesets.set(entry, [pkg]);
385
+ }
386
+ if (!from || from === pkg.version) continue;
387
+ packageLines.push(`| \`${pkg.name}\` | \`${from}\` | \`${pkg.version}\`${formatNpmDistTag(distTag)} |`);
388
+ }
389
+ const changelogLines = [];
390
+ for (const [entry, linkedPackages] of changesets) {
391
+ changelogLines.push(`### ${entry.subject ?? `\`${entry.filename}\``}`, "");
392
+ changelogLines.push("<details>", `<summary>Show Bumped Packages (${linkedPackages.length})</summary>`, "", ...linkedPackages.map((pkg) => `- \`${pkg.id}\``), "", "</details>", "");
393
+ for (const section of entry.sections) {
394
+ changelogLines.push(`#### ${section.title}`, "");
395
+ if (section.content) changelogLines.push(section.content);
396
+ }
397
+ }
398
+ const sections = [
399
+ "## Summary",
400
+ "",
401
+ summary,
402
+ ""
403
+ ];
404
+ if (packageLines.length > 0) sections.push("| Package | From | To |", "| --- | --- | --- |", ...packageLines);
405
+ if (changelogLines.length > 0) sections.push("", "## Changelogs", ...changelogLines);
406
+ sections.push("");
407
+ return sections.join("\n");
408
+ }
409
+ async function run(cwd, args, message) {
410
+ const result = await x("git", args, { nodeOptions: { cwd } });
411
+ if (result.exitCode !== 0) throw execFailure(message, result);
412
+ return result.stdout.trim();
413
+ }
414
+ async function hasGitChanges(cwd) {
415
+ return (await run(cwd, ["status", "--porcelain"], "Failed to check git status.")).length > 0;
416
+ }
417
+ async function commitChanges(cwd, title) {
418
+ await run(cwd, ["add", "-A"], "Failed to stage version changes.");
419
+ await run(cwd, [
420
+ "commit",
421
+ "-m",
422
+ title
423
+ ], "Failed to commit version changes.");
424
+ }
425
+ /** commit the working tree changes onto a detached HEAD */
426
+ async function createVersionCommit(cwd, title) {
427
+ await run(cwd, ["checkout", "--detach"], "Failed to detach HEAD for version branches.");
428
+ await commitChanges(cwd, title);
429
+ }
430
+ async function pushBranch(cwd, branch) {
431
+ await run(cwd, [
432
+ "checkout",
433
+ "-B",
434
+ branch
435
+ ], "Failed to create the version branch.");
436
+ await run(cwd, [
437
+ "push",
438
+ "--force",
439
+ "-u",
440
+ "origin",
441
+ branch
442
+ ], "Failed to push the version branch to origin. Ensure `origin` is configured and you have push access.");
443
+ }
444
+ //#endregion
445
+ export { onVersionRequest as t };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tegami",
3
- "version": "1.1.1",
4
- "description": "Utility for package versioning & publish",
3
+ "version": "1.1.3",
4
+ "description": "A tool to manage changelogs, versioning, and publishing in monorepo",
5
5
  "license": "MIT",
6
6
  "author": "Fuma Nama",
7
7
  "repository": {
@@ -1,71 +0,0 @@
1
- import { r as formatNpmDistTag } from "./semver-EKJ8yK5U.js";
2
- import { n as execFailure } from "./error-BhMYq9iW.js";
3
- import { x } from "tinyexec";
4
- //#region src/utils/version-request.ts
5
- async function hasGitChanges(cwd) {
6
- const result = await x("git", ["status", "--porcelain"], { nodeOptions: { cwd } });
7
- if (result.exitCode !== 0) throw execFailure("Failed to check git status.", result);
8
- return result.stdout.trim().length > 0;
9
- }
10
- async function commitVersionBranchChanges(cwd, branch, title) {
11
- const gitOptions = { nodeOptions: { cwd } };
12
- let result = await x("git", [
13
- "checkout",
14
- "-B",
15
- branch
16
- ], gitOptions);
17
- if (result.exitCode !== 0) throw execFailure("Failed to create the version branch.", result);
18
- result = await x("git", ["add", "-A"], gitOptions);
19
- if (result.exitCode !== 0) throw execFailure("Failed to stage version changes.", result);
20
- result = await x("git", [
21
- "commit",
22
- "-m",
23
- title
24
- ], gitOptions);
25
- if (result.exitCode !== 0) throw execFailure("Failed to commit version changes.", result);
26
- result = await x("git", [
27
- "push",
28
- "--force",
29
- "-u",
30
- "origin",
31
- branch
32
- ], gitOptions);
33
- if (result.exitCode !== 0) throw execFailure("Failed to push the version branch to origin. Ensure `origin` is configured and you have push access.", result);
34
- }
35
- function createVersionRequestBody(draft, context, snapshots, summary) {
36
- const packageLines = [];
37
- const changesets = /* @__PURE__ */ new Map();
38
- for (const [id, packageDraft] of draft.getPackageDrafts()) {
39
- const pkg = context.graph.get(id);
40
- if (!pkg) continue;
41
- for (const entry of packageDraft.changelogs ?? []) {
42
- const list = changesets.get(entry);
43
- if (list) list.push(pkg);
44
- else changesets.set(entry, [pkg]);
45
- }
46
- const originalVersion = snapshots.get(pkg.id);
47
- if (!originalVersion || originalVersion === pkg.version) continue;
48
- packageLines.push(`| \`${pkg.name}\` | \`${originalVersion}\` | \`${pkg.version}\`${formatNpmDistTag(packageDraft.npm?.distTag)} |`);
49
- }
50
- const changelogLines = [];
51
- for (const [entry, linkedPackages] of changesets) {
52
- changelogLines.push(`### ${entry.subject ?? `\`${entry.filename}\``}`, "");
53
- changelogLines.push("<details>", `<summary>Show Bumped Packages (${linkedPackages.length})</summary>`, "", ...linkedPackages.map((pkg) => `- \`${pkg.id}\``), "", "</details>", "");
54
- for (const section of entry.sections) {
55
- changelogLines.push(`#### ${section.title}`, "");
56
- if (section.content) changelogLines.push(section.content);
57
- }
58
- }
59
- const sections = [
60
- "## Summary",
61
- "",
62
- summary,
63
- ""
64
- ];
65
- if (packageLines.length > 0) sections.push("| Package | From | To |", "| --- | --- | --- |", ...packageLines);
66
- if (changelogLines.length > 0) sections.push("", "## Changelogs", ...changelogLines);
67
- sections.push("");
68
- return sections.join("\n");
69
- }
70
- //#endregion
71
- export { createVersionRequestBody as n, hasGitChanges as r, commitVersionBranchChanges as t };
@@ -3,8 +3,8 @@ import { r as handlePluginError } from "./error-BhMYq9iW.js";
3
3
  import { t as _accessExpressionAsString } from "./_accessExpressionAsString-QhbUZzwv.js";
4
4
  import { n as _validateReport, t as _createStandardSchema } from "./_createStandardSchema-BGQyz-uA.js";
5
5
  import { n as validateChangelogFrontmatter, t as renderChangelog } from "./shared-C_iSTp_s.js";
6
- import { t as _assertGuard } from "./_assertGuard-BBn2NbSz.js";
7
6
  import { simpleGenerator } from "./generators/simple.js";
7
+ import { t as _assertGuard } from "./_assertGuard-BBn2NbSz.js";
8
8
  import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
9
9
  import path, { basename, dirname, join } from "node:path";
10
10
  import * as semver$1 from "semver";