tegami 1.0.0-beta.2 → 1.0.0-beta.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/{api-D-jf_8xY.js → api-CGfXmmEM.js} +7 -1
- package/dist/cli/index.d.ts +2 -2
- package/dist/cli/index.js +3 -3
- package/dist/{error-D3dwQnwR.js → error-We7chQVJ.js} +12 -1
- package/dist/{generate-CaCDNfVk.js → generate-BfYdNTFi.js} +1 -1
- package/dist/generators/simple.d.ts +1 -1
- package/dist/{index-CQXmwyLn.d.ts → index-syNgzQTi.d.ts} +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +47 -30
- package/dist/{npm-B_43doHi.js → npm-BzhclYfR.js} +2 -2
- package/dist/plugins/git.d.ts +1 -1
- package/dist/plugins/git.js +1 -1
- package/dist/plugins/github.d.ts +1 -1
- package/dist/plugins/github.js +48 -90
- package/dist/plugins/gitlab.d.ts +86 -0
- package/dist/plugins/gitlab.js +346 -0
- package/dist/plugins/go.d.ts +1 -1
- package/dist/plugins/go.js +3 -2
- package/dist/providers/cargo.d.ts +1 -1
- package/dist/providers/cargo.js +1 -1
- package/dist/providers/npm.d.ts +1 -1
- package/dist/providers/npm.js +1 -1
- package/dist/{types-DKeF_CDv.d.ts → types-BHT_9k9p.d.ts} +31 -6
- package/dist/version-request-cFS0Suzd.js +69 -0
- package/package.json +2 -4
|
@@ -70,6 +70,12 @@ async function createPullRequest(repo, options) {
|
|
|
70
70
|
})
|
|
71
71
|
})).ok) throw new Error("Failed to create the version pull request.");
|
|
72
72
|
}
|
|
73
|
+
async function listPullRequestsForCommit(repo, commitSha, token) {
|
|
74
|
+
const { owner, repo: name } = parseGitHubRepo(repo);
|
|
75
|
+
const response = await githubRequest(`/repos/${owner}/${name}/commits/${commitSha}/pulls`, token);
|
|
76
|
+
if (!response.ok) throw new Error(`Failed to list pull requests for commit ${commitSha.slice(0, 7)}.`);
|
|
77
|
+
return await response.json();
|
|
78
|
+
}
|
|
73
79
|
async function getPullRequest(repo, number, token) {
|
|
74
80
|
const { owner, repo: name } = parseGitHubRepo(repo);
|
|
75
81
|
const response = await githubRequest(`/repos/${owner}/${name}/pulls/${number}`, token);
|
|
@@ -113,4 +119,4 @@ async function createIssueComment(repo, issueNumber, body, token) {
|
|
|
113
119
|
})).ok) throw new Error("Failed to create pull request comment.");
|
|
114
120
|
}
|
|
115
121
|
//#endregion
|
|
116
|
-
export { findOpenPullRequest as a,
|
|
122
|
+
export { findOpenPullRequest as a, releaseExistsByTag as c, findIssueCommentByPrefix as i, updateIssueComment as l, createPullRequest as n, getPullRequest as o, createRelease as r, listPullRequestsForCommit as s, createIssueComment as t, updatePullRequest as u };
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { p as PublishPlan, t as Awaitable, w as Draft } from "../types-
|
|
2
|
-
import { n as Tegami } from "../index-
|
|
1
|
+
import { p as PublishPlan, t as Awaitable, w as Draft } from "../types-BHT_9k9p.js";
|
|
2
|
+
import { n as Tegami } from "../index-syNgzQTi.js";
|
|
3
3
|
import { Command } from "commander";
|
|
4
4
|
|
|
5
5
|
//#region src/cli/index.d.ts
|
package/dist/cli/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { r as formatNpmDistTag } from "../semver-EKJ8yK5U.js";
|
|
2
|
-
import { i as renderChangelog, n as generateFromCommits, t as changelogFilename } from "../generate-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { i as renderChangelog, n as generateFromCommits, t as changelogFilename } from "../generate-BfYdNTFi.js";
|
|
3
|
+
import { n as execFailure, o as isCI, r as handlePluginError, t as CancelledError } from "../error-We7chQVJ.js";
|
|
4
|
+
import { i as findIssueCommentByPrefix, l as updateIssueComment, o as getPullRequest, t as createIssueComment } from "../api-CGfXmmEM.js";
|
|
5
5
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
6
6
|
import path, { basename, join, relative } from "node:path";
|
|
7
7
|
import { x } from "tinyexec";
|
|
@@ -20,6 +20,17 @@ async function somePromise(promises, fn) {
|
|
|
20
20
|
}
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
|
+
function cached(cacheKey, fn, cacheMap = /* @__PURE__ */ new Map()) {
|
|
24
|
+
return (...args) => {
|
|
25
|
+
const key = cacheKey(...args);
|
|
26
|
+
let out = cacheMap.get(key);
|
|
27
|
+
if (!out) {
|
|
28
|
+
out = fn(...args);
|
|
29
|
+
cacheMap.set(key, out);
|
|
30
|
+
}
|
|
31
|
+
return out;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
23
34
|
//#endregion
|
|
24
35
|
//#region src/utils/error.ts
|
|
25
36
|
var CancelledError = class extends Error {
|
|
@@ -62,4 +73,4 @@ async function handlePluginError(plugin, hookName, callback) {
|
|
|
62
73
|
}
|
|
63
74
|
}
|
|
64
75
|
//#endregion
|
|
65
|
-
export {
|
|
76
|
+
export { cached as a, isNodeError as i, execFailure as n, isCI as o, handlePluginError as r, somePromise as s, CancelledError as t };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as maxBump, t as bumpDepth } from "./semver-EKJ8yK5U.js";
|
|
2
|
-
import { n as execFailure } from "./error-
|
|
2
|
+
import { n as execFailure } from "./error-We7chQVJ.js";
|
|
3
3
|
import { x } from "tinyexec";
|
|
4
4
|
import z from "zod";
|
|
5
5
|
import { dump } from "js-yaml";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as ChangelogPackageConfig, O as BumpType, b as TegamiContext, f as PublishOptions, o as TegamiOptions, p as PublishPlan, w as Draft, x as PackageGraph } from "./types-
|
|
1
|
+
import { D as ChangelogPackageConfig, O as BumpType, b as TegamiContext, f as PublishOptions, o as TegamiOptions, p as PublishPlan, w as Draft, x as PackageGraph } from "./types-BHT_9k9p.js";
|
|
2
2
|
|
|
3
3
|
//#region src/changelog/generate.d.ts
|
|
4
4
|
interface GenerateFromCommitsOptions {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { C as WorkspacePackage, E as PackageDraft, S as PackageGroup, T as DraftPolicy, a as PublishPreflight, c as TegamiPluginOption, d as PackagePublishResult, f as PublishOptions, i as PackageOptions, l as PublishLock, n as GroupOptions, o as TegamiOptions, p as PublishPlan, r as LogGenerator, s as TegamiPlugin, u as PackagePublishPlan, w as Draft, x as PackageGraph } from "./types-
|
|
2
|
-
import { i as CommitChangelog, n as Tegami, r as tegami, t as GenerateChangelogOptions } from "./index-
|
|
1
|
+
import { C as WorkspacePackage, E as PackageDraft, S as PackageGroup, T as DraftPolicy, a as PublishPreflight, c as TegamiPluginOption, d as PackagePublishResult, f as PublishOptions, i as PackageOptions, l as PublishLock, n as GroupOptions, o as TegamiOptions, p as PublishPlan, r as LogGenerator, s as TegamiPlugin, u as PackagePublishPlan, w as Draft, x as PackageGraph } from "./types-BHT_9k9p.js";
|
|
2
|
+
import { i as CommitChangelog, n as Tegami, r as tegami, t as GenerateChangelogOptions } from "./index-syNgzQTi.js";
|
|
3
3
|
export { type CommitChangelog, type Draft, type DraftPolicy, GenerateChangelogOptions, type GroupOptions, type LogGenerator, type PackageDraft, type PackageGraph, type PackageGroup, type PackageOptions, type PackagePublishPlan, type PackagePublishResult, type PublishLock, type PublishOptions, type PublishPlan, type PublishPreflight, Tegami, type TegamiOptions, type TegamiPlugin, type TegamiPluginOption, type WorkspacePackage, tegami };
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { a as maxBump } from "./semver-EKJ8yK5U.js";
|
|
2
|
-
import { n as generateFromCommits, r as changelogFrontmatterSchema } from "./generate-
|
|
3
|
-
import {
|
|
2
|
+
import { n as generateFromCommits, r as changelogFrontmatterSchema } from "./generate-BfYdNTFi.js";
|
|
3
|
+
import { r as handlePluginError, s as somePromise } from "./error-We7chQVJ.js";
|
|
4
4
|
import { t as PackageGraph } from "./graph-gThXu8Cz.js";
|
|
5
5
|
import { cargo } from "./providers/cargo.js";
|
|
6
|
-
import { n as npm } from "./npm-
|
|
6
|
+
import { n as npm } from "./npm-BzhclYfR.js";
|
|
7
7
|
import { simpleGenerator } from "./generators/simple.js";
|
|
8
8
|
import fs, { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
9
9
|
import path, { basename, dirname, join } from "node:path";
|
|
10
10
|
import * as semver$1 from "semver";
|
|
11
11
|
import z from "zod";
|
|
12
12
|
import { dump, load, visit } from "js-yaml";
|
|
13
|
-
import { fromMarkdown } from "mdast-util-from-markdown";
|
|
14
|
-
import { toMarkdown } from "mdast-util-to-markdown";
|
|
15
13
|
//#region src/context.ts
|
|
16
14
|
async function createTegamiContext(options = {}) {
|
|
17
15
|
const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd();
|
|
@@ -103,17 +101,16 @@ function parseChangelogFile(filename, content) {
|
|
|
103
101
|
const parsed = frontmatter(content);
|
|
104
102
|
const { success, data } = changelogFrontmatterSchema.safeParse(parsed.data);
|
|
105
103
|
if (!success || !data.packages) return;
|
|
106
|
-
const tree = fromMarkdown(parsed.content);
|
|
107
104
|
let headingBump;
|
|
108
105
|
const packages = /* @__PURE__ */ new Map();
|
|
109
106
|
const sections = [];
|
|
110
|
-
for (const section of
|
|
111
|
-
const sectionBumpType = headingToBump(section.
|
|
107
|
+
for (const section of parseMarkdownSections(parsed.content)) {
|
|
108
|
+
const sectionBumpType = headingToBump(section.depth);
|
|
112
109
|
if (sectionBumpType) headingBump = headingBump ? maxBump(headingBump, sectionBumpType) : sectionBumpType;
|
|
113
110
|
sections.push({
|
|
114
|
-
depth: section.
|
|
115
|
-
title:
|
|
116
|
-
content:
|
|
111
|
+
depth: section.depth,
|
|
112
|
+
title: section.title,
|
|
113
|
+
content: section.content
|
|
117
114
|
});
|
|
118
115
|
}
|
|
119
116
|
if (sections.length === 0) return;
|
|
@@ -164,31 +161,51 @@ function parseReplayCondition(condition) {
|
|
|
164
161
|
version: condition.slice(idx + 1)
|
|
165
162
|
};
|
|
166
163
|
}
|
|
167
|
-
function
|
|
164
|
+
function parseMarkdownSections(markdown) {
|
|
168
165
|
const sections = [];
|
|
166
|
+
const lines = markdown.split(/\r\n|\r|\n/);
|
|
169
167
|
let current;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
168
|
+
let fence;
|
|
169
|
+
for (const line of lines) {
|
|
170
|
+
const fenceMarker = line.match(/^ {0,3}(`{3,}|~{3,})/);
|
|
171
|
+
if (fenceMarker) {
|
|
172
|
+
const marker = fenceMarker[1];
|
|
173
|
+
if (!fence) fence = marker;
|
|
174
|
+
else if (marker[0] === fence[0] && marker.length >= fence.length) fence = void 0;
|
|
175
|
+
}
|
|
176
|
+
if (!fence) {
|
|
177
|
+
const heading = parseHeading(line);
|
|
178
|
+
if (heading) {
|
|
179
|
+
if (current) sections.push(toMarkdownSection(current));
|
|
180
|
+
current = {
|
|
181
|
+
...heading,
|
|
182
|
+
contentLines: []
|
|
183
|
+
};
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
178
186
|
}
|
|
179
|
-
current?.
|
|
187
|
+
current?.contentLines.push(line);
|
|
180
188
|
}
|
|
189
|
+
if (current) sections.push(toMarkdownSection(current));
|
|
181
190
|
return sections;
|
|
182
191
|
}
|
|
183
|
-
function
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
+
function parseHeading(line) {
|
|
193
|
+
const match = line.match(/^ {0,3}(#{1,6})(?:[ \t]+|$)(.*)$/);
|
|
194
|
+
if (!match) return;
|
|
195
|
+
return {
|
|
196
|
+
depth: match[1].length,
|
|
197
|
+
title: stripClosingHeadingSequence(match[2]).trim()
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
function stripClosingHeadingSequence(value) {
|
|
201
|
+
return value.replace(/[ \t]+#{1,}[ \t]*$/, "");
|
|
202
|
+
}
|
|
203
|
+
function toMarkdownSection(section) {
|
|
204
|
+
return {
|
|
205
|
+
depth: section.depth,
|
|
206
|
+
title: section.title,
|
|
207
|
+
content: section.contentLines.join("\n").trim()
|
|
208
|
+
};
|
|
192
209
|
}
|
|
193
210
|
function headingToBump(depth) {
|
|
194
211
|
switch (depth) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as isNodeError, n as execFailure } from "./error-
|
|
1
|
+
import { i as isNodeError, n as execFailure } from "./error-We7chQVJ.js";
|
|
2
2
|
import { n as WorkspacePackage } from "./graph-gThXu8Cz.js";
|
|
3
3
|
import { readFile, writeFile } from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
@@ -198,7 +198,7 @@ function npm({ client: defaultClient, onBreakPeerDep = "set", updateLockFile = t
|
|
|
198
198
|
let updatedRange;
|
|
199
199
|
const isPeer = field === "peerDependencies";
|
|
200
200
|
if (isPeer && onBreakPeerDep === "ignore") continue;
|
|
201
|
-
|
|
201
|
+
if (isPeer && onBreakPeerDep === "set") updatedRange = spec.linked.version;
|
|
202
202
|
else if (isPeer && onBreakPeerDep === "error") throw new Error(`[Tegami] the version of "${spec.linked.name}" is beyond its peer dependency constraint "${v}" in package "${pkg.name}", please update the constraint to satisfy.`);
|
|
203
203
|
else if (spec.range.startsWith("^")) updatedRange = `^${spec.linked.version}`;
|
|
204
204
|
else if (spec.range.startsWith("~")) updatedRange = `~${spec.linked.version}`;
|
package/dist/plugins/git.d.ts
CHANGED
package/dist/plugins/git.js
CHANGED
package/dist/plugins/github.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as WorkspacePackage, b as TegamiContext, p as PublishPlan, s as TegamiPlugin, t as Awaitable, w as Draft } from "../types-
|
|
1
|
+
import { C as WorkspacePackage, b as TegamiContext, p as PublishPlan, s as TegamiPlugin, t as Awaitable, w as Draft } from "../types-BHT_9k9p.js";
|
|
2
2
|
import { GitPluginOptions } from "./git.js";
|
|
3
3
|
|
|
4
4
|
//#region src/plugins/github.d.ts
|
package/dist/plugins/github.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { i as formatPackageVersion
|
|
2
|
-
import { a as
|
|
3
|
-
import { a as findOpenPullRequest,
|
|
1
|
+
import { i as formatPackageVersion } from "../semver-EKJ8yK5U.js";
|
|
2
|
+
import { a as cached, n as execFailure, o as isCI } from "../error-We7chQVJ.js";
|
|
3
|
+
import { a as findOpenPullRequest, c as releaseExistsByTag, n as createPullRequest, r as createRelease, s as listPullRequestsForCommit, u as updatePullRequest } from "../api-CGfXmmEM.js";
|
|
4
4
|
import { git } from "./git.js";
|
|
5
|
+
import { n as createVersionRequestBody, r as hasGitChanges, t as commitVersionBranchChanges } from "../version-request-cFS0Suzd.js";
|
|
5
6
|
import { join, relative } from "node:path";
|
|
6
7
|
import { x } from "tinyexec";
|
|
7
8
|
import semver from "semver";
|
|
@@ -13,48 +14,7 @@ function github(options = {}) {
|
|
|
13
14
|
function getRenderer(context) {
|
|
14
15
|
return renderer ??= createChangelogRenderer(context);
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
-
const config = options.versionPr ?? {};
|
|
18
|
-
if (config === false) return [false];
|
|
19
|
-
if (config.forceCreate || isCI()) return [true, config];
|
|
20
|
-
return [false];
|
|
21
|
-
}
|
|
22
|
-
function defaultVersionPRBody(draft, context) {
|
|
23
|
-
const packageLines = [];
|
|
24
|
-
const changesets = /* @__PURE__ */ new Map();
|
|
25
|
-
for (const [id, packageDraft] of draft.getPackageDrafts()) {
|
|
26
|
-
const pkg = context.graph.get(id);
|
|
27
|
-
if (!pkg) continue;
|
|
28
|
-
for (const entry of packageDraft.changelogs ?? []) {
|
|
29
|
-
const list = changesets.get(entry);
|
|
30
|
-
if (list) list.push(pkg);
|
|
31
|
-
else changesets.set(entry, [pkg]);
|
|
32
|
-
}
|
|
33
|
-
const originalVersion = cliOriginalPackageVersions.get(pkg.id);
|
|
34
|
-
if (!originalVersion || originalVersion === pkg.version) continue;
|
|
35
|
-
packageLines.push(`| \`${pkg.name}\` | \`${originalVersion}\` | \`${pkg.version}\`${formatNpmDistTag(packageDraft.npm?.distTag)} |`);
|
|
36
|
-
}
|
|
37
|
-
const changelogLines = [];
|
|
38
|
-
for (const [entry, linkedPackages] of changesets) {
|
|
39
|
-
changelogLines.push(`### ${entry.subject ?? `\`${entry.filename}\``}`, "");
|
|
40
|
-
changelogLines.push("<details>", `<summary>Show Bumped Packages (${linkedPackages.length})</summary>`, "", ...linkedPackages.map((pkg) => `- \`${pkg.id}\``), "", "</details>", "");
|
|
41
|
-
for (const section of entry.sections) {
|
|
42
|
-
changelogLines.push(`#### ${section.title}`, "");
|
|
43
|
-
if (section.content) changelogLines.push(section.content);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
const sections = [
|
|
47
|
-
"## Summary",
|
|
48
|
-
"",
|
|
49
|
-
"Merge this PR to publish the versioned packages.",
|
|
50
|
-
""
|
|
51
|
-
];
|
|
52
|
-
if (packageLines.length > 0) sections.push("| Package | From | To |", "| --- | --- | --- |", ...packageLines);
|
|
53
|
-
if (changelogLines.length > 0) sections.push("", "## Changelogs", ...changelogLines);
|
|
54
|
-
sections.push("");
|
|
55
|
-
return sections.join("\n");
|
|
56
|
-
}
|
|
57
|
-
const cliOriginalPackageVersions = /* @__PURE__ */ new Map();
|
|
17
|
+
const cliSnapshots = /* @__PURE__ */ new Map();
|
|
58
18
|
return [git(options), {
|
|
59
19
|
name: "github",
|
|
60
20
|
init() {
|
|
@@ -138,42 +98,19 @@ function github(options = {}) {
|
|
|
138
98
|
if (result.exitCode !== 0) throw execFailure("Failed to configure git remote for GitHub Actions.", result);
|
|
139
99
|
},
|
|
140
100
|
draftCreated() {
|
|
141
|
-
for (const pkg of this.graph.getPackages())
|
|
101
|
+
for (const pkg of this.graph.getPackages()) cliSnapshots.set(pkg.id, pkg.version);
|
|
142
102
|
},
|
|
143
103
|
async draftApplied(draft) {
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
if (!enabled || !await hasGitChanges(cwd)) return;
|
|
104
|
+
const config = options.versionPr ?? {};
|
|
105
|
+
if (config === false || !(config.forceCreate || isCI()) || !await hasGitChanges(this.cwd)) return;
|
|
147
106
|
const repo = this.github?.repo;
|
|
148
107
|
const { branch = "tegami/version-packages", base = "main" } = config;
|
|
149
108
|
const basePR = await config.create?.call(this, { draft });
|
|
150
109
|
const pr = {
|
|
151
110
|
title: basePR?.title ?? "Version Packages",
|
|
152
|
-
body: basePR?.body ??
|
|
111
|
+
body: basePR?.body ?? createVersionRequestBody(draft, this, cliSnapshots, "Merge this PR to publish the versioned packages.")
|
|
153
112
|
};
|
|
154
|
-
|
|
155
|
-
let result = await x("git", [
|
|
156
|
-
"checkout",
|
|
157
|
-
"-B",
|
|
158
|
-
branch
|
|
159
|
-
], gitOptions);
|
|
160
|
-
if (result.exitCode !== 0) throw execFailure("Failed to create the version pull request branch.", result);
|
|
161
|
-
result = await x("git", ["add", "-A"], gitOptions);
|
|
162
|
-
if (result.exitCode !== 0) throw execFailure("Failed to stage version changes.", result);
|
|
163
|
-
result = await x("git", [
|
|
164
|
-
"commit",
|
|
165
|
-
"-m",
|
|
166
|
-
pr.title
|
|
167
|
-
], gitOptions);
|
|
168
|
-
if (result.exitCode !== 0) throw execFailure("Failed to commit version changes.", result);
|
|
169
|
-
result = await x("git", [
|
|
170
|
-
"push",
|
|
171
|
-
"--force",
|
|
172
|
-
"-u",
|
|
173
|
-
"origin",
|
|
174
|
-
branch
|
|
175
|
-
], gitOptions);
|
|
176
|
-
if (result.exitCode !== 0) throw execFailure("Failed to push the version branch to origin. Ensure `origin` is configured and you have push access.", result);
|
|
113
|
+
await commitVersionBranchChanges(this.cwd, branch, pr.title);
|
|
177
114
|
const token = this.github?.token;
|
|
178
115
|
if (!repo) return;
|
|
179
116
|
const openPr = await findOpenPullRequest(repo, branch, token);
|
|
@@ -196,12 +133,9 @@ function github(options = {}) {
|
|
|
196
133
|
}
|
|
197
134
|
}];
|
|
198
135
|
}
|
|
199
|
-
async function hasGitChanges(cwd) {
|
|
200
|
-
return (await x("git", ["status", "--porcelain"], { nodeOptions: { cwd } })).stdout.trim().length > 0;
|
|
201
|
-
}
|
|
202
136
|
function createChangelogRenderer(context) {
|
|
203
|
-
const
|
|
204
|
-
|
|
137
|
+
const { repo, token } = context.github;
|
|
138
|
+
const resolveFileCommit = cached((filename) => filename, async (filename) => {
|
|
205
139
|
const result = await x("git", [
|
|
206
140
|
"log",
|
|
207
141
|
"--diff-filter=A",
|
|
@@ -212,26 +146,50 @@ function createChangelogRenderer(context) {
|
|
|
212
146
|
], { nodeOptions: { cwd: context.cwd } });
|
|
213
147
|
if (result.exitCode !== 0) return;
|
|
214
148
|
return result.stdout.trim() || void 0;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
149
|
+
});
|
|
150
|
+
const resolveEntryMeta = cached((entry) => entry.id, async (entry) => {
|
|
151
|
+
const commit = await resolveFileCommit(entry.filename);
|
|
152
|
+
if (!commit || !repo) return {
|
|
153
|
+
commit,
|
|
154
|
+
pullRequests: []
|
|
155
|
+
};
|
|
156
|
+
return {
|
|
157
|
+
commit,
|
|
158
|
+
pullRequests: await listPullRequestsForCommit(repo, commit, token).catch(() => [])
|
|
159
|
+
};
|
|
160
|
+
});
|
|
161
|
+
function formatEntryDetails(meta) {
|
|
162
|
+
if (meta.pullRequests.length === 0) return;
|
|
163
|
+
const lines = [];
|
|
164
|
+
for (const pr of meta.pullRequests) {
|
|
165
|
+
let line = repo ? `- [#${pr.number} ${pr.title}](https://github.com/${repo}/pull/${pr.number})` : `- #${pr.number} ${pr.title}`;
|
|
166
|
+
if (pr.user) line += ` by @${pr.user.login}`;
|
|
167
|
+
lines.push(line);
|
|
168
|
+
}
|
|
169
|
+
return [
|
|
170
|
+
"<details>",
|
|
171
|
+
"<summary>Pull request & contributors</summary>",
|
|
172
|
+
"",
|
|
173
|
+
...lines,
|
|
174
|
+
"",
|
|
175
|
+
"</details>"
|
|
176
|
+
].join("\n");
|
|
221
177
|
}
|
|
222
178
|
return async (entry) => {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
179
|
+
const meta = await resolveEntryMeta(entry);
|
|
180
|
+
let commitSuffix = "";
|
|
181
|
+
if (meta.commit) {
|
|
182
|
+
const short = meta.commit.slice(0, 7);
|
|
183
|
+
const link = repo ? `[${short}](https://github.com/${repo}/commit/${meta.commit})` : `\`${short}\``;
|
|
184
|
+
commitSuffix += ` (${link})`;
|
|
227
185
|
}
|
|
228
|
-
const commit = await commitPromise;
|
|
229
|
-
const commitSuffix = commit ? ` (${formatCommitLink(commit)})` : "";
|
|
230
186
|
const lines = [];
|
|
231
187
|
for (const section of entry.sections) {
|
|
232
188
|
lines.push(`### ${section.title}${commitSuffix}`, "");
|
|
233
189
|
if (section.content) lines.push(section.content, "");
|
|
234
190
|
}
|
|
191
|
+
const details = formatEntryDetails(meta);
|
|
192
|
+
if (details) lines.push(details);
|
|
235
193
|
return lines.join("\n").trim();
|
|
236
194
|
};
|
|
237
195
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { C as WorkspacePackage, b as TegamiContext, p as PublishPlan, s as TegamiPlugin, t as Awaitable, w as Draft } from "../types-BHT_9k9p.js";
|
|
2
|
+
import { GitPluginOptions } from "./git.js";
|
|
3
|
+
|
|
4
|
+
//#region src/plugins/gitlab.d.ts
|
|
5
|
+
interface GitlabRelease {
|
|
6
|
+
/** Release title */
|
|
7
|
+
title?: string;
|
|
8
|
+
/** Release notes */
|
|
9
|
+
notes?: string;
|
|
10
|
+
/** Whether to mark release as prerelease */
|
|
11
|
+
prerelease?: boolean;
|
|
12
|
+
}
|
|
13
|
+
interface VersionMergeRequest {
|
|
14
|
+
/** Merge request title. */
|
|
15
|
+
title?: string;
|
|
16
|
+
/** Merge request body. */
|
|
17
|
+
body?: string;
|
|
18
|
+
}
|
|
19
|
+
interface VersionMergeRequestOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Create the MR even outside of CI.
|
|
22
|
+
*
|
|
23
|
+
* @default false
|
|
24
|
+
*/
|
|
25
|
+
forceCreate?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Merge request branch.
|
|
28
|
+
*
|
|
29
|
+
* @default "tegami/version-packages"
|
|
30
|
+
*/
|
|
31
|
+
branch?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Merge request base branch.
|
|
34
|
+
*
|
|
35
|
+
* @default "main"
|
|
36
|
+
*/
|
|
37
|
+
base?: string;
|
|
38
|
+
/** Override details for "Version Packages" MR. */
|
|
39
|
+
create?: (this: TegamiContext, opts: {
|
|
40
|
+
draft: Draft;
|
|
41
|
+
}) => Awaitable<VersionMergeRequest>;
|
|
42
|
+
}
|
|
43
|
+
/** Options for creating GitLab releases after a successful publish. */
|
|
44
|
+
interface GitLabPluginOptions extends GitPluginOptions {
|
|
45
|
+
/** GitLab repository. */
|
|
46
|
+
repo?: string;
|
|
47
|
+
/** Optional GitLab token for Git & GitLab operations. */
|
|
48
|
+
token?: string;
|
|
49
|
+
/** GitLab API URL. Defaults to `https://gitlab.com/api/v4`. */
|
|
50
|
+
apiUrl?: string;
|
|
51
|
+
/** GitLab web URL. Defaults to `https://gitlab.com`. */
|
|
52
|
+
webUrl?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Create GitLab release for published packages.
|
|
55
|
+
*
|
|
56
|
+
* @default true
|
|
57
|
+
*/
|
|
58
|
+
release?: boolean | {
|
|
59
|
+
/**
|
|
60
|
+
* Create GitLab release immediately after successful publish, without waiting for others.
|
|
61
|
+
*
|
|
62
|
+
* @default false
|
|
63
|
+
*/
|
|
64
|
+
eager?: boolean; /** Override release details for a single package. */
|
|
65
|
+
create?: (this: TegamiContext, opts: {
|
|
66
|
+
tag: string;
|
|
67
|
+
pkg: WorkspacePackage;
|
|
68
|
+
plan: PublishPlan;
|
|
69
|
+
}) => Awaitable<GitlabRelease>; /** Override release details when multiple packages share a git tag. */
|
|
70
|
+
createGrouped?: (this: TegamiContext, opts: {
|
|
71
|
+
tag: string;
|
|
72
|
+
packages: WorkspacePackage[];
|
|
73
|
+
plan: PublishPlan;
|
|
74
|
+
}) => Awaitable<GitlabRelease>;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* (CLI only) Open a version merge request after versioning.
|
|
78
|
+
*
|
|
79
|
+
* Defaults to enabled in CI and disabled locally.
|
|
80
|
+
*/
|
|
81
|
+
versionMr?: VersionMergeRequestOptions | false;
|
|
82
|
+
}
|
|
83
|
+
/** Create GitLab releases for successfully published packages after the whole plan succeeds. */
|
|
84
|
+
declare function gitlab(options?: GitLabPluginOptions): TegamiPlugin[];
|
|
85
|
+
//#endregion
|
|
86
|
+
export { GitLabPluginOptions, gitlab };
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { i as formatPackageVersion } from "../semver-EKJ8yK5U.js";
|
|
2
|
+
import { a as cached, n as execFailure, o as isCI } from "../error-We7chQVJ.js";
|
|
3
|
+
import { git } from "./git.js";
|
|
4
|
+
import { n as createVersionRequestBody, r as hasGitChanges, t as commitVersionBranchChanges } from "../version-request-cFS0Suzd.js";
|
|
5
|
+
import { join, relative } from "node:path";
|
|
6
|
+
import { x } from "tinyexec";
|
|
7
|
+
import semver from "semver";
|
|
8
|
+
//#region src/plugins/gitlab/api.ts
|
|
9
|
+
function parseGitLabRepo(repo) {
|
|
10
|
+
const projectPath = repo.replace(/^\/+|\/+$/g, "");
|
|
11
|
+
if (!projectPath || !projectPath.includes("/")) throw new Error(`Invalid GitLab repository: ${repo}`);
|
|
12
|
+
return {
|
|
13
|
+
projectPath,
|
|
14
|
+
encodedProjectPath: encodeURIComponent(projectPath)
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function gitlabApiUrl(apiUrl = "https://gitlab.com/api/v4") {
|
|
18
|
+
return apiUrl.replace(/\/+$/, "");
|
|
19
|
+
}
|
|
20
|
+
function gitlabWebUrl(webUrl = "https://gitlab.com") {
|
|
21
|
+
return webUrl.replace(/\/+$/, "");
|
|
22
|
+
}
|
|
23
|
+
async function gitlabRequest(options, path, init = {}) {
|
|
24
|
+
const headers = new Headers(init.headers);
|
|
25
|
+
headers.set("Accept", "application/json");
|
|
26
|
+
if (options.token) headers.set(options.token.type === "job-token" ? "JOB-TOKEN" : "PRIVATE-TOKEN", options.token.value);
|
|
27
|
+
return fetch(`${gitlabApiUrl(options.apiUrl)}${path}`, {
|
|
28
|
+
...init,
|
|
29
|
+
headers
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
async function releaseExistsByTag(repo, tag, options = {}) {
|
|
33
|
+
const { encodedProjectPath } = parseGitLabRepo(repo);
|
|
34
|
+
const response = await gitlabRequest(options, `/projects/${encodedProjectPath}/releases/${encodeURIComponent(tag)}`, { method: "HEAD" });
|
|
35
|
+
if (response.status === 404) return false;
|
|
36
|
+
if (!response.ok) throw new Error(`Failed to get GitLab release for ${tag}.`);
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
async function createRelease(repo, options) {
|
|
40
|
+
const { encodedProjectPath } = parseGitLabRepo(repo);
|
|
41
|
+
if (!(await gitlabRequest(options, `/projects/${encodedProjectPath}/releases`, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
headers: { "Content-Type": "application/json" },
|
|
44
|
+
body: JSON.stringify({
|
|
45
|
+
tag_name: options.tag,
|
|
46
|
+
name: options.title,
|
|
47
|
+
description: options.notes
|
|
48
|
+
})
|
|
49
|
+
})).ok) throw new Error(`Failed to create GitLab release for ${options.tag}.`);
|
|
50
|
+
}
|
|
51
|
+
async function findOpenMergeRequest(repo, options) {
|
|
52
|
+
const { encodedProjectPath } = parseGitLabRepo(repo);
|
|
53
|
+
const params = new URLSearchParams({
|
|
54
|
+
source_branch: options.head,
|
|
55
|
+
state: "opened"
|
|
56
|
+
});
|
|
57
|
+
if (options.base) params.set("target_branch", options.base);
|
|
58
|
+
const response = await gitlabRequest(options, `/projects/${encodedProjectPath}/merge_requests?${params}`);
|
|
59
|
+
if (!response.ok) throw new Error("Failed to check for an existing version merge request.");
|
|
60
|
+
return (await response.json())[0]?.iid;
|
|
61
|
+
}
|
|
62
|
+
async function updateMergeRequest(repo, number, options) {
|
|
63
|
+
const { encodedProjectPath } = parseGitLabRepo(repo);
|
|
64
|
+
if (!(await gitlabRequest(options, `/projects/${encodedProjectPath}/merge_requests/${number}`, {
|
|
65
|
+
method: "PUT",
|
|
66
|
+
headers: { "Content-Type": "application/json" },
|
|
67
|
+
body: JSON.stringify({
|
|
68
|
+
title: options.title,
|
|
69
|
+
description: options.body,
|
|
70
|
+
...options.base === void 0 ? {} : { target_branch: options.base }
|
|
71
|
+
})
|
|
72
|
+
})).ok) throw new Error("Failed to update the version merge request.");
|
|
73
|
+
}
|
|
74
|
+
async function createMergeRequest(repo, options) {
|
|
75
|
+
const { encodedProjectPath } = parseGitLabRepo(repo);
|
|
76
|
+
if (!(await gitlabRequest(options, `/projects/${encodedProjectPath}/merge_requests`, {
|
|
77
|
+
method: "POST",
|
|
78
|
+
headers: { "Content-Type": "application/json" },
|
|
79
|
+
body: JSON.stringify({
|
|
80
|
+
title: options.title,
|
|
81
|
+
description: options.body,
|
|
82
|
+
source_branch: options.head,
|
|
83
|
+
target_branch: options.base
|
|
84
|
+
})
|
|
85
|
+
})).ok) throw new Error("Failed to create the version merge request.");
|
|
86
|
+
}
|
|
87
|
+
async function listMergeRequestsForCommit(repo, commitSha, options = {}) {
|
|
88
|
+
const { encodedProjectPath } = parseGitLabRepo(repo);
|
|
89
|
+
const response = await gitlabRequest(options, `/projects/${encodedProjectPath}/repository/commits/${commitSha}/merge_requests`);
|
|
90
|
+
if (!response.ok) throw new Error(`Failed to list merge requests for commit ${commitSha.slice(0, 7)}.`);
|
|
91
|
+
return (await response.json()).map((mergeRequest) => ({
|
|
92
|
+
number: mergeRequest.iid,
|
|
93
|
+
title: mergeRequest.title,
|
|
94
|
+
user: mergeRequest.author ? { login: mergeRequest.author.username } : void 0
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region src/plugins/gitlab.ts
|
|
99
|
+
/** Create GitLab releases for successfully published packages after the whole plan succeeds. */
|
|
100
|
+
function gitlab(options = {}) {
|
|
101
|
+
const { release: releaseOptions = true } = options;
|
|
102
|
+
let renderer;
|
|
103
|
+
function getRenderer(context) {
|
|
104
|
+
return renderer ??= createChangelogRenderer(context);
|
|
105
|
+
}
|
|
106
|
+
const cliOriginalPackageVersions = /* @__PURE__ */ new Map();
|
|
107
|
+
return [git(options), {
|
|
108
|
+
name: "gitlab",
|
|
109
|
+
init() {
|
|
110
|
+
this.gitlab = {
|
|
111
|
+
repo: options.repo ?? process.env.GITLAB_REPOSITORY ?? process.env.CI_PROJECT_PATH,
|
|
112
|
+
token: resolveGitLabToken(options.token),
|
|
113
|
+
apiUrl: options.apiUrl ?? process.env.GITLAB_API_URL ?? process.env.CI_API_V4_URL,
|
|
114
|
+
webUrl: options.webUrl ?? process.env.GITLAB_SERVER_URL ?? process.env.CI_SERVER_URL
|
|
115
|
+
};
|
|
116
|
+
},
|
|
117
|
+
async resolvePlanStatus({ plan }) {
|
|
118
|
+
const { repo, token } = this.gitlab;
|
|
119
|
+
if (!repo || !token || releaseOptions === false) return;
|
|
120
|
+
const requiredTags = /* @__PURE__ */ new Set();
|
|
121
|
+
const api = gitLabApiOptions(this.gitlab);
|
|
122
|
+
for (const pkg of plan.packages.values()) if (pkg.preflight.shouldPublish && pkg.git?.tag) requiredTags.add(pkg.git.tag);
|
|
123
|
+
return Array.from(requiredTags, async (tag) => {
|
|
124
|
+
if (!await releaseExistsByTag(repo, tag, api)) return "pending";
|
|
125
|
+
});
|
|
126
|
+
},
|
|
127
|
+
async afterPublishAll({ plan }) {
|
|
128
|
+
const { repo, token } = this.gitlab;
|
|
129
|
+
if (!repo || !token || releaseOptions === false) return;
|
|
130
|
+
const api = gitLabApiOptions(this.gitlab);
|
|
131
|
+
const { eager = false, create, createGrouped } = releaseOptions === true ? {} : releaseOptions;
|
|
132
|
+
const groups = /* @__PURE__ */ new Map();
|
|
133
|
+
for (const [id, { preflight, publishResult, git }] of plan.packages) {
|
|
134
|
+
if (!eager && publishResult.type === "failed") return;
|
|
135
|
+
const tag = git?.tag;
|
|
136
|
+
if (!tag || !preflight.shouldPublish) continue;
|
|
137
|
+
const pkg = this.graph.get(id);
|
|
138
|
+
const group = groups.get(tag);
|
|
139
|
+
if (group) group.push(pkg);
|
|
140
|
+
else groups.set(tag, [pkg]);
|
|
141
|
+
}
|
|
142
|
+
await Promise.all(Array.from(groups, async ([tag, packages]) => {
|
|
143
|
+
for (const member of packages) if (plan.packages.get(member.id).publishResult.type === "failed") return;
|
|
144
|
+
if (await releaseExistsByTag(repo, tag, api)) return;
|
|
145
|
+
let release;
|
|
146
|
+
if (packages.length > 1) {
|
|
147
|
+
const overrides = await createGrouped?.call(this, {
|
|
148
|
+
tag,
|
|
149
|
+
packages,
|
|
150
|
+
plan
|
|
151
|
+
}) ?? {};
|
|
152
|
+
release = {
|
|
153
|
+
title: overrides.title ?? tag,
|
|
154
|
+
notes: overrides.notes ?? await defaultGroupedNotes(getRenderer(this), plan, packages),
|
|
155
|
+
prerelease: overrides.prerelease ?? packages.some((pkg) => pkg.version && semver.prerelease(pkg.version))
|
|
156
|
+
};
|
|
157
|
+
} else {
|
|
158
|
+
const pkg = packages[0];
|
|
159
|
+
const overrides = await create?.call(this, {
|
|
160
|
+
tag,
|
|
161
|
+
pkg,
|
|
162
|
+
plan
|
|
163
|
+
}) ?? {};
|
|
164
|
+
const packagePlan = plan.packages.get(pkg.id);
|
|
165
|
+
release = {
|
|
166
|
+
title: overrides.title ?? formatPackageVersion(pkg.name, pkg.version, packagePlan?.npm?.distTag),
|
|
167
|
+
notes: overrides.notes ?? await defaultNotes(getRenderer(this), pkg, packagePlan),
|
|
168
|
+
prerelease: overrides.prerelease ?? (pkg.version !== void 0 && semver.prerelease(pkg.version) !== null)
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
await createRelease(repo, {
|
|
172
|
+
tag,
|
|
173
|
+
title: release.title,
|
|
174
|
+
notes: release.notes,
|
|
175
|
+
prerelease: release.prerelease,
|
|
176
|
+
...api
|
|
177
|
+
});
|
|
178
|
+
}));
|
|
179
|
+
},
|
|
180
|
+
cli: {
|
|
181
|
+
async init() {
|
|
182
|
+
if (!isCI()) return;
|
|
183
|
+
const { repo, token, webUrl } = this.gitlab ?? {};
|
|
184
|
+
if (!token || !repo) return;
|
|
185
|
+
const result = await x("git", [
|
|
186
|
+
"remote",
|
|
187
|
+
"set-url",
|
|
188
|
+
"origin",
|
|
189
|
+
gitlabRemoteUrl(repo, token, webUrl)
|
|
190
|
+
], { nodeOptions: { cwd: this.cwd } });
|
|
191
|
+
if (result.exitCode !== 0) throw execFailure("Failed to configure git remote for GitLab Actions.", result);
|
|
192
|
+
},
|
|
193
|
+
draftCreated() {
|
|
194
|
+
for (const pkg of this.graph.getPackages()) cliOriginalPackageVersions.set(pkg.id, pkg.version);
|
|
195
|
+
},
|
|
196
|
+
async draftApplied(draft) {
|
|
197
|
+
const config = options.versionMr ?? {};
|
|
198
|
+
if (config === false || !(config.forceCreate || isCI()) || !await hasGitChanges(this.cwd)) return;
|
|
199
|
+
const repo = this.gitlab?.repo;
|
|
200
|
+
const { branch = "tegami/version-packages", base = "main" } = config;
|
|
201
|
+
const baseMR = await config.create?.call(this, { draft });
|
|
202
|
+
const mr = {
|
|
203
|
+
title: baseMR?.title ?? "Version Packages",
|
|
204
|
+
body: baseMR?.body ?? createVersionRequestBody(draft, this, cliOriginalPackageVersions, "Merge this MR to publish the versioned packages.")
|
|
205
|
+
};
|
|
206
|
+
await commitVersionBranchChanges(this.cwd, branch, mr.title);
|
|
207
|
+
const api = gitLabApiOptions(this.gitlab);
|
|
208
|
+
if (!repo) return;
|
|
209
|
+
const openMr = await findOpenMergeRequest(repo, {
|
|
210
|
+
head: branch,
|
|
211
|
+
base,
|
|
212
|
+
...api
|
|
213
|
+
});
|
|
214
|
+
if (openMr !== void 0) {
|
|
215
|
+
await updateMergeRequest(repo, openMr, {
|
|
216
|
+
title: mr.title,
|
|
217
|
+
body: mr.body,
|
|
218
|
+
base,
|
|
219
|
+
...api
|
|
220
|
+
});
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
await createMergeRequest(repo, {
|
|
224
|
+
title: mr.title,
|
|
225
|
+
body: mr.body,
|
|
226
|
+
head: branch,
|
|
227
|
+
base,
|
|
228
|
+
...api
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}];
|
|
233
|
+
}
|
|
234
|
+
function createChangelogRenderer(context) {
|
|
235
|
+
const { repo, webUrl } = context.gitlab;
|
|
236
|
+
const api = gitLabApiOptions(context.gitlab);
|
|
237
|
+
const baseUrl = gitlabWebUrl(webUrl);
|
|
238
|
+
const resolveFileCommit = cached((filename) => filename, async (filename) => {
|
|
239
|
+
const result = await x("git", [
|
|
240
|
+
"log",
|
|
241
|
+
"--diff-filter=A",
|
|
242
|
+
"-1",
|
|
243
|
+
"--format=%H",
|
|
244
|
+
"--",
|
|
245
|
+
relative(context.cwd, join(context.changelogDir, filename))
|
|
246
|
+
], { nodeOptions: { cwd: context.cwd } });
|
|
247
|
+
if (result.exitCode !== 0) return;
|
|
248
|
+
return result.stdout.trim() || void 0;
|
|
249
|
+
});
|
|
250
|
+
const resolveEntryMeta = cached((entry) => entry.id, async (entry) => {
|
|
251
|
+
const commit = await resolveFileCommit(entry.filename);
|
|
252
|
+
if (!commit || !repo) return {
|
|
253
|
+
commit,
|
|
254
|
+
mergeRequests: []
|
|
255
|
+
};
|
|
256
|
+
return {
|
|
257
|
+
commit,
|
|
258
|
+
mergeRequests: await listMergeRequestsForCommit(repo, commit, api).catch(() => [])
|
|
259
|
+
};
|
|
260
|
+
});
|
|
261
|
+
function formatEntryDetails(meta) {
|
|
262
|
+
if (meta.mergeRequests.length === 0) return;
|
|
263
|
+
const lines = [];
|
|
264
|
+
for (const mr of meta.mergeRequests) {
|
|
265
|
+
let line = repo ? `- [!${mr.number} ${mr.title}](${baseUrl}/${repo}/-/merge_requests/${mr.number})` : `- #${mr.number} ${mr.title}`;
|
|
266
|
+
if (mr.user) line += ` by @${mr.user.login}`;
|
|
267
|
+
lines.push(line);
|
|
268
|
+
}
|
|
269
|
+
return [
|
|
270
|
+
"<details>",
|
|
271
|
+
"<summary>Pull request & contributors</summary>",
|
|
272
|
+
"",
|
|
273
|
+
...lines,
|
|
274
|
+
"",
|
|
275
|
+
"</details>"
|
|
276
|
+
].join("\n");
|
|
277
|
+
}
|
|
278
|
+
return async (entry) => {
|
|
279
|
+
const meta = await resolveEntryMeta(entry);
|
|
280
|
+
let commitSuffix = "";
|
|
281
|
+
if (meta.commit) {
|
|
282
|
+
const short = meta.commit.slice(0, 7);
|
|
283
|
+
const link = repo ? `[${short}](${baseUrl}/${repo}/-/commit/${meta.commit})` : `\`${short}\``;
|
|
284
|
+
commitSuffix += ` (${link})`;
|
|
285
|
+
}
|
|
286
|
+
const lines = [];
|
|
287
|
+
for (const section of entry.sections) {
|
|
288
|
+
lines.push(`### ${section.title}${commitSuffix}`, "");
|
|
289
|
+
if (section.content) lines.push(section.content, "");
|
|
290
|
+
}
|
|
291
|
+
const details = formatEntryDetails(meta);
|
|
292
|
+
if (details) lines.push(details);
|
|
293
|
+
return lines.join("\n").trim();
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
async function defaultNotes(renderer, pkg, packagePlan) {
|
|
297
|
+
if (packagePlan && packagePlan.changelogs.length > 0) return (await Promise.all(packagePlan.changelogs.map(renderer))).join("\n\n");
|
|
298
|
+
return `Published ${formatPackageVersion(pkg.name, pkg.version, packagePlan?.npm?.distTag)}.`;
|
|
299
|
+
}
|
|
300
|
+
async function defaultGroupedNotes(renderer, plan, packages) {
|
|
301
|
+
const changelogs = /* @__PURE__ */ new Map();
|
|
302
|
+
for (const pkg of packages) {
|
|
303
|
+
const packagePlan = plan.packages.get(pkg.id);
|
|
304
|
+
if (!packagePlan) continue;
|
|
305
|
+
for (const entry of packagePlan.changelogs) changelogs.set(entry.id, entry);
|
|
306
|
+
}
|
|
307
|
+
const sections = [packages.map((pkg) => {
|
|
308
|
+
const packagePlan = plan.packages.get(pkg.id);
|
|
309
|
+
return `- ${formatPackageVersion(pkg.name, pkg.version, packagePlan?.npm?.distTag)}`;
|
|
310
|
+
}).join("\n")];
|
|
311
|
+
if (changelogs.size > 0) {
|
|
312
|
+
const notes = await Promise.all(Array.from(changelogs.values(), renderer));
|
|
313
|
+
sections.push("", notes.join("\n\n"));
|
|
314
|
+
}
|
|
315
|
+
return sections.join("\n");
|
|
316
|
+
}
|
|
317
|
+
function gitLabApiOptions(gitlab) {
|
|
318
|
+
const options = {};
|
|
319
|
+
if (gitlab?.apiUrl) options.apiUrl = gitlab.apiUrl;
|
|
320
|
+
if (gitlab?.token) options.token = gitlab.token;
|
|
321
|
+
return options;
|
|
322
|
+
}
|
|
323
|
+
function resolveGitLabToken(optionToken) {
|
|
324
|
+
if (optionToken) return {
|
|
325
|
+
value: optionToken,
|
|
326
|
+
type: "private-token"
|
|
327
|
+
};
|
|
328
|
+
if (process.env.GITLAB_TOKEN) return {
|
|
329
|
+
value: process.env.GITLAB_TOKEN,
|
|
330
|
+
type: "private-token"
|
|
331
|
+
};
|
|
332
|
+
if (process.env.GL_TOKEN) return {
|
|
333
|
+
value: process.env.GL_TOKEN,
|
|
334
|
+
type: "private-token"
|
|
335
|
+
};
|
|
336
|
+
if (process.env.CI_JOB_TOKEN) return {
|
|
337
|
+
value: process.env.CI_JOB_TOKEN,
|
|
338
|
+
type: "job-token"
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
function gitlabRemoteUrl(repo, token, webUrl) {
|
|
342
|
+
const username = token.type === "job-token" ? "gitlab-ci-token" : "oauth2";
|
|
343
|
+
return `${gitlabWebUrl(webUrl).replace(/^https?:\/\//, `https://${username}:${token.value}@`)}/${repo}.git`;
|
|
344
|
+
}
|
|
345
|
+
//#endregion
|
|
346
|
+
export { gitlab };
|
package/dist/plugins/go.d.ts
CHANGED
package/dist/plugins/go.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as isNodeError, n as execFailure } from "../error-
|
|
1
|
+
import { i as isNodeError, n as execFailure } from "../error-We7chQVJ.js";
|
|
2
2
|
import { n as WorkspacePackage } from "../graph-gThXu8Cz.js";
|
|
3
3
|
import { relative, resolve } from "node:path";
|
|
4
4
|
import { x } from "tinyexec";
|
|
@@ -135,6 +135,7 @@ function go({ updateLockFile = true, bumpDep: getBumpDepType } = {}) {
|
|
|
135
135
|
},
|
|
136
136
|
async publishPreflight({ pkg }) {
|
|
137
137
|
if (!(pkg instanceof GoPackage)) return;
|
|
138
|
+
const shouldPublish = pkg.getPackageOptions().go?.publish ?? this.graph.getPackageGroup(pkg.id)?.options?.go?.publish ?? true;
|
|
138
139
|
const wait = [];
|
|
139
140
|
for (const [moduleName] of pkg.mod.requires) {
|
|
140
141
|
const linked = this.graph.get(`go:${moduleName}`);
|
|
@@ -147,7 +148,7 @@ function go({ updateLockFile = true, bumpDep: getBumpDepType } = {}) {
|
|
|
147
148
|
wait.push(linked.id);
|
|
148
149
|
}
|
|
149
150
|
return {
|
|
150
|
-
shouldPublish
|
|
151
|
+
shouldPublish,
|
|
151
152
|
wait
|
|
152
153
|
};
|
|
153
154
|
},
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { g as cargo, h as CargoPluginOptions, m as CargoPackage } from "../types-
|
|
1
|
+
import { g as cargo, h as CargoPluginOptions, m as CargoPackage } from "../types-BHT_9k9p.js";
|
|
2
2
|
export { CargoPackage, CargoPluginOptions, cargo };
|
package/dist/providers/cargo.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as isNodeError, n as execFailure } from "../error-
|
|
1
|
+
import { i as isNodeError, n as execFailure } from "../error-We7chQVJ.js";
|
|
2
2
|
import { n as WorkspacePackage } from "../graph-gThXu8Cz.js";
|
|
3
3
|
import { readFile, writeFile } from "node:fs/promises";
|
|
4
4
|
import { join, normalize } from "node:path";
|
package/dist/providers/npm.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as NpmPackage, v as NpmPluginOptions, y as npm } from "../types-
|
|
1
|
+
import { _ as NpmPackage, v as NpmPluginOptions, y as npm } from "../types-BHT_9k9p.js";
|
|
2
2
|
export { NpmPackage, NpmPluginOptions, npm };
|
package/dist/providers/npm.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as npm, t as NpmPackage } from "../npm-
|
|
1
|
+
import { n as npm, t as NpmPackage } from "../npm-BzhclYfR.js";
|
|
2
2
|
export { NpmPackage, npm };
|
|
@@ -138,6 +138,12 @@ declare class PackageGraph {
|
|
|
138
138
|
unregisterGroup(name: string): void;
|
|
139
139
|
}
|
|
140
140
|
//#endregion
|
|
141
|
+
//#region src/plugins/gitlab/api.d.ts
|
|
142
|
+
interface GitLabToken {
|
|
143
|
+
value: string;
|
|
144
|
+
type: "private-token" | "job-token";
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
141
147
|
//#region src/context.d.ts
|
|
142
148
|
interface TegamiContext {
|
|
143
149
|
/** absolute path */
|
|
@@ -154,6 +160,13 @@ interface TegamiContext {
|
|
|
154
160
|
repo?: string;
|
|
155
161
|
token?: string;
|
|
156
162
|
};
|
|
163
|
+
/** additional context when GitLab plugin is configured */
|
|
164
|
+
gitlab?: {
|
|
165
|
+
repo?: string;
|
|
166
|
+
token?: GitLabToken;
|
|
167
|
+
apiUrl?: string;
|
|
168
|
+
webUrl?: string;
|
|
169
|
+
};
|
|
157
170
|
/** additional context when npm plugin is configured */
|
|
158
171
|
npm?: {
|
|
159
172
|
client: AgentName;
|
|
@@ -376,6 +389,18 @@ interface TegamiOptions<Groups extends string = string> {
|
|
|
376
389
|
npm?: NpmPluginOptions;
|
|
377
390
|
cargo?: CargoPluginOptions;
|
|
378
391
|
}
|
|
392
|
+
interface SharedGoOptions {
|
|
393
|
+
/**
|
|
394
|
+
* Whether to publish this module (create git tags).
|
|
395
|
+
*
|
|
396
|
+
* @default true
|
|
397
|
+
*/
|
|
398
|
+
publish?: boolean;
|
|
399
|
+
}
|
|
400
|
+
interface SharedNpmOptions {
|
|
401
|
+
/** npm dist-tag used when publishing. */
|
|
402
|
+
distTag?: string;
|
|
403
|
+
}
|
|
379
404
|
interface GroupOptions {
|
|
380
405
|
/** Prerelease identifier appended to bumped versions (e.g. `alpha` → `1.1.0-alpha.0`). */
|
|
381
406
|
prerelease?: string;
|
|
@@ -384,9 +409,9 @@ interface GroupOptions {
|
|
|
384
409
|
/** when multiple packages in the group are published, only one git tag will be created (as well as GitHub release) */
|
|
385
410
|
syncGitTag?: boolean;
|
|
386
411
|
/** npm-specific options. */
|
|
387
|
-
npm?:
|
|
388
|
-
|
|
389
|
-
|
|
412
|
+
npm?: SharedNpmOptions;
|
|
413
|
+
/** go-specific options. */
|
|
414
|
+
go?: SharedGoOptions;
|
|
390
415
|
}
|
|
391
416
|
interface PackageOptions<Group extends string = string> {
|
|
392
417
|
/** Prerelease identifier appended to bumped versions (e.g. `alpha` → `1.1.0-alpha.0`). */
|
|
@@ -394,9 +419,9 @@ interface PackageOptions<Group extends string = string> {
|
|
|
394
419
|
/** the group of this package, ignored if the group doesn't exist */
|
|
395
420
|
group?: Group;
|
|
396
421
|
/** npm-specific options. */
|
|
397
|
-
npm?:
|
|
398
|
-
|
|
399
|
-
|
|
422
|
+
npm?: SharedNpmOptions;
|
|
423
|
+
/** go-specific options. */
|
|
424
|
+
go?: SharedGoOptions;
|
|
400
425
|
}
|
|
401
426
|
type TegamiPluginOption = TegamiPlugin | TegamiPluginOption[];
|
|
402
427
|
interface TegamiPlugin {
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { r as formatNpmDistTag } from "./semver-EKJ8yK5U.js";
|
|
2
|
+
import { n as execFailure } from "./error-We7chQVJ.js";
|
|
3
|
+
import { x } from "tinyexec";
|
|
4
|
+
//#region src/utils/version-request.ts
|
|
5
|
+
async function hasGitChanges(cwd) {
|
|
6
|
+
return (await x("git", ["status", "--porcelain"], { nodeOptions: { cwd } })).stdout.trim().length > 0;
|
|
7
|
+
}
|
|
8
|
+
async function commitVersionBranchChanges(cwd, branch, title) {
|
|
9
|
+
const gitOptions = { nodeOptions: { cwd } };
|
|
10
|
+
let result = await x("git", [
|
|
11
|
+
"checkout",
|
|
12
|
+
"-B",
|
|
13
|
+
branch
|
|
14
|
+
], gitOptions);
|
|
15
|
+
if (result.exitCode !== 0) throw execFailure("Failed to create the version branch.", result);
|
|
16
|
+
result = await x("git", ["add", "-A"], gitOptions);
|
|
17
|
+
if (result.exitCode !== 0) throw execFailure("Failed to stage version changes.", result);
|
|
18
|
+
result = await x("git", [
|
|
19
|
+
"commit",
|
|
20
|
+
"-m",
|
|
21
|
+
title
|
|
22
|
+
], gitOptions);
|
|
23
|
+
if (result.exitCode !== 0) throw execFailure("Failed to commit version changes.", result);
|
|
24
|
+
result = await x("git", [
|
|
25
|
+
"push",
|
|
26
|
+
"--force",
|
|
27
|
+
"-u",
|
|
28
|
+
"origin",
|
|
29
|
+
branch
|
|
30
|
+
], gitOptions);
|
|
31
|
+
if (result.exitCode !== 0) throw execFailure("Failed to push the version branch to origin. Ensure `origin` is configured and you have push access.", result);
|
|
32
|
+
}
|
|
33
|
+
function createVersionRequestBody(draft, context, snapshots, summary) {
|
|
34
|
+
const packageLines = [];
|
|
35
|
+
const changesets = /* @__PURE__ */ new Map();
|
|
36
|
+
for (const [id, packageDraft] of draft.getPackageDrafts()) {
|
|
37
|
+
const pkg = context.graph.get(id);
|
|
38
|
+
if (!pkg) continue;
|
|
39
|
+
for (const entry of packageDraft.changelogs ?? []) {
|
|
40
|
+
const list = changesets.get(entry);
|
|
41
|
+
if (list) list.push(pkg);
|
|
42
|
+
else changesets.set(entry, [pkg]);
|
|
43
|
+
}
|
|
44
|
+
const originalVersion = snapshots.get(pkg.id);
|
|
45
|
+
if (!originalVersion || originalVersion === pkg.version) continue;
|
|
46
|
+
packageLines.push(`| \`${pkg.name}\` | \`${originalVersion}\` | \`${pkg.version}\`${formatNpmDistTag(packageDraft.npm?.distTag)} |`);
|
|
47
|
+
}
|
|
48
|
+
const changelogLines = [];
|
|
49
|
+
for (const [entry, linkedPackages] of changesets) {
|
|
50
|
+
changelogLines.push(`### ${entry.subject ?? `\`${entry.filename}\``}`, "");
|
|
51
|
+
changelogLines.push("<details>", `<summary>Show Bumped Packages (${linkedPackages.length})</summary>`, "", ...linkedPackages.map((pkg) => `- \`${pkg.id}\``), "", "</details>", "");
|
|
52
|
+
for (const section of entry.sections) {
|
|
53
|
+
changelogLines.push(`#### ${section.title}`, "");
|
|
54
|
+
if (section.content) changelogLines.push(section.content);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const sections = [
|
|
58
|
+
"## Summary",
|
|
59
|
+
"",
|
|
60
|
+
summary,
|
|
61
|
+
""
|
|
62
|
+
];
|
|
63
|
+
if (packageLines.length > 0) sections.push("| Package | From | To |", "| --- | --- | --- |", ...packageLines);
|
|
64
|
+
if (changelogLines.length > 0) sections.push("", "## Changelogs", ...changelogLines);
|
|
65
|
+
sections.push("");
|
|
66
|
+
return sections.join("\n");
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
export { createVersionRequestBody as n, hasGitChanges as r, commitVersionBranchChanges as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tegami",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.3",
|
|
4
4
|
"description": "Utility for package versioning & publish",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Fuma Nama",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"./generators/simple": "./dist/generators/simple.js",
|
|
19
19
|
"./plugins/git": "./dist/plugins/git.js",
|
|
20
20
|
"./plugins/github": "./dist/plugins/github.js",
|
|
21
|
+
"./plugins/gitlab": "./dist/plugins/gitlab.js",
|
|
21
22
|
"./plugins/go": "./dist/plugins/go.js",
|
|
22
23
|
"./providers/cargo": "./dist/providers/cargo.js",
|
|
23
24
|
"./providers/npm": "./dist/providers/npm.js",
|
|
@@ -31,8 +32,6 @@
|
|
|
31
32
|
"@rainbowatcher/toml-edit-js": "^0.6.5",
|
|
32
33
|
"commander": "^15.0.0",
|
|
33
34
|
"js-yaml": "^5.1.0",
|
|
34
|
-
"mdast-util-from-markdown": "^2.0.3",
|
|
35
|
-
"mdast-util-to-markdown": "^2.1.2",
|
|
36
35
|
"package-manager-detector": "^1.6.0",
|
|
37
36
|
"semver": "^7.8.5",
|
|
38
37
|
"tinyexec": "^1.2.4",
|
|
@@ -40,7 +39,6 @@
|
|
|
40
39
|
"zod": "^4.4.3"
|
|
41
40
|
},
|
|
42
41
|
"devDependencies": {
|
|
43
|
-
"@types/mdast": "^4.0.4",
|
|
44
42
|
"@types/node": "^26.0.0",
|
|
45
43
|
"@types/semver": "^7.7.1",
|
|
46
44
|
"tsdown": "^0.22.3",
|