tegami 1.1.2 → 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.
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +35 -11
- package/dist/generators/simple.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -5
- package/dist/{npm-DoPhFKji.js → npm-CaBYeOeV.js} +115 -74
- package/dist/plugins/cargo.d.ts +1 -1
- package/dist/plugins/git.d.ts +1 -1
- package/dist/plugins/github.d.ts +18 -3
- package/dist/plugins/github.js +42 -32
- package/dist/plugins/gitlab.d.ts +18 -3
- package/dist/plugins/gitlab.js +44 -37
- package/dist/plugins/go.d.ts +1 -1
- package/dist/providers/npm.d.ts +1 -1
- package/dist/providers/npm.js +1 -1
- package/dist/{types-B50RK1rR.d.ts → types-DEyZ2r-2.d.ts} +34 -8
- package/dist/version-request-DlLpLLK3.js +445 -0
- package/package.json +2 -2
- package/dist/version-request-oxy16TJ1.js +0 -71
package/dist/plugins/gitlab.js
CHANGED
|
@@ -3,7 +3,7 @@ import { t as changelogFilename } from "../generate-Bg86OJP4.js";
|
|
|
3
3
|
import { a as cached, n as execFailure, o as isCI, s as joinPath } from "../error-BhMYq9iW.js";
|
|
4
4
|
import { o as readChangelogEntries, t as createDraft } from "../draft-CzUiQasJ.js";
|
|
5
5
|
import { git } from "./git.js";
|
|
6
|
-
import {
|
|
6
|
+
import { t as onVersionRequest } from "../version-request-DlLpLLK3.js";
|
|
7
7
|
import { readFile, writeFile } from "node:fs/promises";
|
|
8
8
|
import { basename, join, relative, resolve } from "node:path";
|
|
9
9
|
import { x } from "tinyexec";
|
|
@@ -309,7 +309,39 @@ function gitlab(options = {}) {
|
|
|
309
309
|
function getRenderer(context) {
|
|
310
310
|
return renderer ??= createChangelogRenderer(context);
|
|
311
311
|
}
|
|
312
|
-
const
|
|
312
|
+
const versionRequests = onVersionRequest({
|
|
313
|
+
name: "gitlab",
|
|
314
|
+
summary: "Merge this MR to publish the versioned packages.",
|
|
315
|
+
options: options.versionMr,
|
|
316
|
+
enabled(context) {
|
|
317
|
+
const { repo, token } = context.gitlab ?? {};
|
|
318
|
+
return Boolean(repo && token);
|
|
319
|
+
},
|
|
320
|
+
find(context, { head, base }) {
|
|
321
|
+
return findOpenMergeRequest(context.gitlab.repo, {
|
|
322
|
+
head,
|
|
323
|
+
base,
|
|
324
|
+
...gitLabApiOptions(context.gitlab)
|
|
325
|
+
});
|
|
326
|
+
},
|
|
327
|
+
create(context, request) {
|
|
328
|
+
return createMergeRequest(context.gitlab.repo, {
|
|
329
|
+
title: request.title,
|
|
330
|
+
body: request.body,
|
|
331
|
+
head: request.head,
|
|
332
|
+
base: request.base,
|
|
333
|
+
...gitLabApiOptions(context.gitlab)
|
|
334
|
+
});
|
|
335
|
+
},
|
|
336
|
+
update(context, number, request) {
|
|
337
|
+
return updateMergeRequest(context.gitlab.repo, number, {
|
|
338
|
+
title: request.title,
|
|
339
|
+
body: request.body,
|
|
340
|
+
base: request.base,
|
|
341
|
+
...gitLabApiOptions(context.gitlab)
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
});
|
|
313
345
|
return [git(options), {
|
|
314
346
|
name: "gitlab",
|
|
315
347
|
init() {
|
|
@@ -321,6 +353,7 @@ function gitlab(options = {}) {
|
|
|
321
353
|
};
|
|
322
354
|
},
|
|
323
355
|
async resolvePlanStatus({ plan }) {
|
|
356
|
+
if (versionRequests.resolvePlanStatus() === "pending") return "pending";
|
|
324
357
|
const { repo, token } = this.gitlab;
|
|
325
358
|
if (!repo || !token || releaseOptions === false) return;
|
|
326
359
|
const requiredTags = /* @__PURE__ */ new Set();
|
|
@@ -394,42 +427,16 @@ function gitlab(options = {}) {
|
|
|
394
427
|
if (result.exitCode !== 0) throw execFailure("Failed to configure git remote for GitLab CI.", result);
|
|
395
428
|
},
|
|
396
429
|
initCliDraft() {
|
|
397
|
-
|
|
430
|
+
versionRequests.initCliDraft.call(this);
|
|
398
431
|
},
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
body: baseMR?.body ?? createVersionRequestBody(draft, this, cliOriginalPackageVersions, "Merge this MR to publish the versioned packages.")
|
|
408
|
-
};
|
|
409
|
-
await commitVersionBranchChanges(this.cwd, branch, mr.title);
|
|
410
|
-
const api = gitLabApiOptions(this.gitlab);
|
|
411
|
-
if (!repo) return;
|
|
412
|
-
const openMr = await findOpenMergeRequest(repo, {
|
|
413
|
-
head: branch,
|
|
414
|
-
base,
|
|
415
|
-
...api
|
|
416
|
-
});
|
|
417
|
-
if (openMr !== void 0) {
|
|
418
|
-
await updateMergeRequest(repo, openMr, {
|
|
419
|
-
title: mr.title,
|
|
420
|
-
body: mr.body,
|
|
421
|
-
base,
|
|
422
|
-
...api
|
|
423
|
-
});
|
|
424
|
-
return;
|
|
425
|
-
}
|
|
426
|
-
await createMergeRequest(repo, {
|
|
427
|
-
title: mr.title,
|
|
428
|
-
body: mr.body,
|
|
429
|
-
head: branch,
|
|
430
|
-
base,
|
|
431
|
-
...api
|
|
432
|
-
});
|
|
432
|
+
applyCliDraft(draft) {
|
|
433
|
+
return versionRequests.applyCliDraft.call(this, draft);
|
|
434
|
+
},
|
|
435
|
+
initPublishPlan(opts) {
|
|
436
|
+
versionRequests.initPublishPlan.call(this, opts);
|
|
437
|
+
},
|
|
438
|
+
beforePublishAll(opts) {
|
|
439
|
+
return versionRequests.beforePublishAll.call(this, opts);
|
|
433
440
|
}
|
|
434
441
|
}];
|
|
435
442
|
}
|
package/dist/plugins/go.d.ts
CHANGED
package/dist/providers/npm.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { C as NpmPackage, S as NpmGraph, l as NpmPluginOptions, u as npm, x as DependencySpec } from "../types-
|
|
1
|
+
import { C as NpmPackage, S as NpmGraph, l as NpmPluginOptions, u as npm, x as DependencySpec } from "../types-DEyZ2r-2.js";
|
|
2
2
|
export { type DependencySpec, type NpmGraph, NpmPackage, NpmPluginOptions, npm };
|
package/dist/providers/npm.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as NpmPackage, t as npm } from "../npm-
|
|
1
|
+
import { n as NpmPackage, t as npm } from "../npm-CaBYeOeV.js";
|
|
2
2
|
export { NpmPackage, npm };
|
|
@@ -582,6 +582,18 @@ interface PackagePublishPlan {
|
|
|
582
582
|
interface PublishOptions {
|
|
583
583
|
/** Validate the publish plan without publishing packages, creating tags, or running release plugins. */
|
|
584
584
|
dryRun?: boolean;
|
|
585
|
+
/**
|
|
586
|
+
* Publish only the given packages and their dependencies.
|
|
587
|
+
*
|
|
588
|
+
* Each entry can be a package id, package name, or `group:name`.
|
|
589
|
+
*/
|
|
590
|
+
packages?: string[];
|
|
591
|
+
/**
|
|
592
|
+
* The max amount of concurrent publishes (unstable, can change in anytime).
|
|
593
|
+
*
|
|
594
|
+
* @default 5
|
|
595
|
+
*/
|
|
596
|
+
unstable_maxChunk?: number;
|
|
585
597
|
}
|
|
586
598
|
type PackagePublishResult = {
|
|
587
599
|
type: "published" | "skipped";
|
|
@@ -628,9 +640,9 @@ interface Tegami {
|
|
|
628
640
|
*
|
|
629
641
|
* Prefer `publish()` over this if you are publishing packages, it will also check the publish status.
|
|
630
642
|
*/
|
|
631
|
-
publishStatus(): Promise<"pending" | "success" | "idle">;
|
|
643
|
+
publishStatus(options?: PublishOptions): Promise<"pending" | "success" | "idle">;
|
|
632
644
|
/** Remove the publish lock file after publishing has finished successfully. */
|
|
633
|
-
cleanup(): Promise<{
|
|
645
|
+
cleanup(options?: PublishOptions): Promise<{
|
|
634
646
|
state: "removed";
|
|
635
647
|
} | {
|
|
636
648
|
state: "skipped";
|
|
@@ -647,13 +659,17 @@ interface Tegami {
|
|
|
647
659
|
declare function tegami<const Groups extends string = string>(options?: TegamiOptions<Groups>): Tegami;
|
|
648
660
|
//#endregion
|
|
649
661
|
//#region src/cli/core.d.ts
|
|
650
|
-
|
|
651
|
-
|
|
662
|
+
type ArgValue = boolean | string | string[] | boolean[];
|
|
663
|
+
type PositionalValue = string | string[];
|
|
664
|
+
interface TegamiCliCommand<Values extends Record<string, ArgValue | undefined>, Positionals extends Record<string, PositionalValue | undefined>> {
|
|
665
|
+
option<const Name extends string, const T extends "string" | "boolean", const Multiple extends boolean = false>(name: Name, opts: {
|
|
652
666
|
type: T;
|
|
653
667
|
short?: string;
|
|
654
668
|
description?: string;
|
|
655
|
-
|
|
669
|
+
multiple?: Multiple;
|
|
670
|
+
}): TegamiCliCommand<Values & { [k in Name]?: Multiple extends true ? T extends "string" ? string[] : boolean[] : T extends "string" ? string : boolean }, Positionals>;
|
|
656
671
|
positional<const Name extends string, const Required extends boolean = true>(name: Name, required?: Required): TegamiCliCommand<Values, Positionals & { [K in Name]: Required extends true ? string : string | undefined }>;
|
|
672
|
+
positionals<const Name extends string>(name: Name): TegamiCliCommand<Values, Positionals & { [K in Name]: string[] }>;
|
|
657
673
|
action(fn: (options: {
|
|
658
674
|
context: TegamiContext;
|
|
659
675
|
values: Values;
|
|
@@ -839,6 +855,10 @@ interface TegamiPlugin {
|
|
|
839
855
|
resolvePlanStatus?(this: TegamiContext, opts: {
|
|
840
856
|
plan: PublishPlan;
|
|
841
857
|
}): Awaitable<"success" | "pending" | undefined | void | Awaitable<"success" | "pending" | undefined>[]>;
|
|
858
|
+
/** Called after preflights, before Tegami starts publishing the packages of a plan. */
|
|
859
|
+
beforePublishAll?(this: TegamiContext, opts: {
|
|
860
|
+
plan: PublishPlan;
|
|
861
|
+
}): Awaitable<void>;
|
|
842
862
|
/** Called before a package will be published, return `false` to prevent from publishing. */
|
|
843
863
|
willPublish?(this: TegamiContext, opts: {
|
|
844
864
|
pkg: WorkspacePackage;
|
|
@@ -861,17 +881,23 @@ type Awaitable<T> = T | Promise<T>;
|
|
|
861
881
|
type RequireFields<Obj, K extends keyof Obj> = Obj & { [R in K]-?: NonNullable<Obj[R]> };
|
|
862
882
|
interface PublishPreflight {
|
|
863
883
|
/**
|
|
864
|
-
* Whether the package should be published, the state **must
|
|
884
|
+
* Whether the package should be published, the state **must only depend on local inputs** (e.g. local `package.json` or `publish-lock.yaml`).
|
|
865
885
|
*
|
|
866
886
|
* To note if the package is already published, hook `resolvePlanStatus` on plugins, or skip at publish-time.
|
|
867
887
|
*/
|
|
868
888
|
shouldPublish: boolean;
|
|
869
889
|
/**
|
|
870
|
-
* Package ids that must be published before this one, this
|
|
890
|
+
* Package ids that **must be** published before this one, this disallows circular dependency.
|
|
871
891
|
*
|
|
872
|
-
* It is okay to add unpublished packages
|
|
892
|
+
* It is okay to add unpublished packages, they will be ignored.
|
|
873
893
|
*/
|
|
874
894
|
wait?: string[];
|
|
895
|
+
/**
|
|
896
|
+
* Package ids that **are preferred** to publish before this one, this allows circular dependency.
|
|
897
|
+
*
|
|
898
|
+
* It is okay to add unpublished packages, they will be ignored.
|
|
899
|
+
*/
|
|
900
|
+
optionalWait?: string[];
|
|
875
901
|
}
|
|
876
902
|
//#endregion
|
|
877
903
|
export { WorkspacePackage as A, NpmPackage as C, cargo as D, CargoPluginOptions as E, DraftPolicy as M, PackageDraft as N, PackageGraph as O, BumpType as P, NpmGraph as S, CargoPackage as T, PublishOptions as _, PublishPreflight as a, TegamiContext as b, TegamiPluginOption as c, GenerateChangelogOptions as d, Tegami as f, PackagePublishResult as g, PackagePublishPlan as h, PackageOptions as i, Draft as j, PackageGroup as k, NpmPluginOptions as l, PublishLock as m, GroupOptions as n, TegamiOptions as o, tegami as p, LogGenerator as r, TegamiPlugin as s, Awaitable as t, npm as u, PublishPlan as v, CargoGraph as w, DependencySpec as x, CommitChangelog as y };
|
|
@@ -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.
|
|
4
|
-
"description": "
|
|
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": {
|