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.
@@ -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, updateIssueComment as c, findIssueCommentByPrefix as i, updatePullRequest as l, createPullRequest as n, getPullRequest as o, createRelease as r, releaseExistsByTag as s, createIssueComment as t };
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 };
@@ -1,5 +1,5 @@
1
- import { p as PublishPlan, t as Awaitable, w as Draft } from "../types-DKeF_CDv.js";
2
- import { n as Tegami } from "../index-CQXmwyLn.js";
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-CaCDNfVk.js";
3
- import { a as isCI, n as execFailure, r as handlePluginError, t as CancelledError } from "../error-D3dwQnwR.js";
4
- import { c as updateIssueComment, i as findIssueCommentByPrefix, o as getPullRequest, t as createIssueComment } from "../api-D-jf_8xY.js";
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 { isCI as a, isNodeError as i, execFailure as n, somePromise as o, handlePluginError as r, CancelledError as t };
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-D3dwQnwR.js";
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 { r as LogGenerator } from "../types-DKeF_CDv.js";
1
+ import { r as LogGenerator } from "../types-BHT_9k9p.js";
2
2
 
3
3
  //#region src/generators/simple.d.ts
4
4
  declare function simpleGenerator(): LogGenerator;
@@ -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-DKeF_CDv.js";
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-DKeF_CDv.js";
2
- import { i as CommitChangelog, n as Tegami, r as tegami, t as GenerateChangelogOptions } from "./index-CQXmwyLn.js";
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-CaCDNfVk.js";
3
- import { o as somePromise, r as handlePluginError } from "./error-D3dwQnwR.js";
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-B_43doHi.js";
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 getHeadingSections(tree)) {
111
- const sectionBumpType = headingToBump(section.heading.depth);
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.heading.depth,
115
- title: sectionToMarkdown(section.heading.children),
116
- content: sectionToMarkdown(section.children)
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 getHeadingSections(tree) {
164
+ function parseMarkdownSections(markdown) {
168
165
  const sections = [];
166
+ const lines = markdown.split(/\r\n|\r|\n/);
169
167
  let current;
170
- for (const child of tree.children) {
171
- if (child.type === "heading") {
172
- current = {
173
- heading: child,
174
- children: []
175
- };
176
- sections.push(current);
177
- continue;
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?.children.push(child);
187
+ current?.contentLines.push(line);
180
188
  }
189
+ if (current) sections.push(toMarkdownSection(current));
181
190
  return sections;
182
191
  }
183
- function sectionToMarkdown(children) {
184
- if (children.length === 0) return "";
185
- return toMarkdown({
186
- type: "root",
187
- children
188
- }, {
189
- bullet: "-",
190
- fence: "`"
191
- }).trim();
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-D3dwQnwR.js";
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
- else if (isPeer && onBreakPeerDep === "set") updatedRange = spec.linked.version;
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}`;
@@ -1,4 +1,4 @@
1
- import { s as TegamiPlugin } from "../types-DKeF_CDv.js";
1
+ import { s as TegamiPlugin } from "../types-BHT_9k9p.js";
2
2
 
3
3
  //#region src/plugins/git.d.ts
4
4
  interface GitPluginOptions {
@@ -1,4 +1,4 @@
1
- import { a as isCI, n as execFailure } from "../error-D3dwQnwR.js";
1
+ import { n as execFailure, o as isCI } from "../error-We7chQVJ.js";
2
2
  import { x } from "tinyexec";
3
3
  //#region src/plugins/git.ts
4
4
  /**
@@ -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-DKeF_CDv.js";
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
@@ -1,7 +1,8 @@
1
- import { i as formatPackageVersion, r as formatNpmDistTag } from "../semver-EKJ8yK5U.js";
2
- import { a as isCI, n as execFailure } from "../error-D3dwQnwR.js";
3
- import { a as findOpenPullRequest, l as updatePullRequest, n as createPullRequest, r as createRelease, s as releaseExistsByTag } from "../api-D-jf_8xY.js";
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
- function resolvePROptions() {
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()) cliOriginalPackageVersions.set(pkg.id, pkg.version);
101
+ for (const pkg of this.graph.getPackages()) cliSnapshots.set(pkg.id, pkg.version);
142
102
  },
143
103
  async draftApplied(draft) {
144
- const { cwd } = this;
145
- const [enabled, config] = resolvePROptions();
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 ?? defaultVersionPRBody(draft, this)
111
+ body: basePR?.body ?? createVersionRequestBody(draft, this, cliSnapshots, "Merge this PR to publish the versioned packages.")
153
112
  };
154
- const gitOptions = { nodeOptions: { cwd } };
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 cache = /* @__PURE__ */ new Map();
204
- async function resolveFileCommit(filename) {
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
- function formatCommitLink(commit) {
217
- const short = commit.slice(0, 7);
218
- const repo = context.github?.repo;
219
- if (!repo) return `\`${short}\``;
220
- return `[${short}](https://github.com/${repo}/commit/${commit})`;
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
- let commitPromise = cache.get(entry.filename);
224
- if (!commitPromise) {
225
- commitPromise = resolveFileCommit(entry.filename);
226
- cache.set(entry.filename, commitPromise);
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 };
@@ -1,4 +1,4 @@
1
- import { C as WorkspacePackage, O as BumpType, s as TegamiPlugin } from "../types-DKeF_CDv.js";
1
+ import { C as WorkspacePackage, O as BumpType, s as TegamiPlugin } from "../types-BHT_9k9p.js";
2
2
 
3
3
  //#region src/plugins/go.d.ts
4
4
  interface GoModFile {
@@ -1,4 +1,4 @@
1
- import { i as isNodeError, n as execFailure } from "../error-D3dwQnwR.js";
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: true,
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-DKeF_CDv.js";
1
+ import { g as cargo, h as CargoPluginOptions, m as CargoPackage } from "../types-BHT_9k9p.js";
2
2
  export { CargoPackage, CargoPluginOptions, cargo };
@@ -1,4 +1,4 @@
1
- import { i as isNodeError, n as execFailure } from "../error-D3dwQnwR.js";
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";
@@ -1,2 +1,2 @@
1
- import { _ as NpmPackage, v as NpmPluginOptions, y as npm } from "../types-DKeF_CDv.js";
1
+ import { _ as NpmPackage, v as NpmPluginOptions, y as npm } from "../types-BHT_9k9p.js";
2
2
  export { NpmPackage, NpmPluginOptions, npm };
@@ -1,2 +1,2 @@
1
- import { n as npm, t as NpmPackage } from "../npm-B_43doHi.js";
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
- /** npm dist-tag used when publishing. */distTag?: string;
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
- /** npm dist-tag used when publishing. */distTag?: string;
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.2",
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",