tegami 0.2.1 → 1.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,5 @@
1
- import { O as Draft, S as PublishPlan, g as Tegami, t as Awaitable } from "../types-DEaKjB3O.js";
1
+ import { p as PublishPlan, t as Awaitable, w as Draft } from "../types-DnCUr2dB.js";
2
+ import { n as Tegami } from "../index-B4ehnvrS.js";
2
3
  import { Command } from "commander";
3
4
 
4
5
  //#region src/cli/index.d.ts
package/dist/cli/index.js CHANGED
@@ -1,9 +1,9 @@
1
- import { r as formatNpmDistTag } from "../semver-C4vJ4SK8.js";
2
- import { a as renderChangelog, n as generateFromCommits, r as generateReplays, t as changelogFilename } from "../generate-L7ucD7ic.js";
1
+ import { r as formatNpmDistTag } from "../semver-jcIUAvbl.js";
2
+ import { i as renderChangelog, n as generateFromCommits, t as changelogFilename } from "../generate-OZFKzXnu.js";
3
3
  import { a as isCI, n as execFailure, r as handlePluginError, t as CancelledError } from "../error-DNy8R5ue.js";
4
4
  import { c as updateIssueComment, i as findIssueCommentByPrefix, o as getPullRequest, t as createIssueComment } from "../api-D-jf_8xY.js";
5
5
  import { mkdir, readFile, writeFile } from "node:fs/promises";
6
- import path, { basename, isAbsolute, join, normalize, relative } from "node:path";
6
+ import path, { basename, join, relative } from "node:path";
7
7
  import { x } from "tinyexec";
8
8
  import z from "zod";
9
9
  import { resolveCommand } from "package-manager-detector";
@@ -15,35 +15,32 @@ async function getChangedPackages(graph, cwd) {
15
15
  }
16
16
  async function getChangedFilePaths(cwd) {
17
17
  const files = /* @__PURE__ */ new Set();
18
- for (const args of [["diff", "--name-only"], [
18
+ await Promise.all([["diff", "--name-only"], [
19
19
  "diff",
20
20
  "--cached",
21
21
  "--name-only"
22
- ]]) await addGitOutput(files, cwd, args);
22
+ ]].map(async (args) => {
23
+ const result = await x("git", args, { nodeOptions: { cwd } });
24
+ if (result.exitCode !== 0) return;
25
+ for (const line of result.stdout.split("\n")) {
26
+ const trimmed = line.trim();
27
+ if (trimmed) files.add(trimmed);
28
+ }
29
+ }));
23
30
  return Array.from(files);
24
31
  }
25
32
  function resolveChangedPackages(graph, files, cwd) {
26
33
  const packages = [...graph.getPackages()].sort((a, b) => b.path.length - a.path.length);
27
34
  const matched = /* @__PURE__ */ new Map();
28
- for (const file of files) for (const pkg of packages) if (isUnderDir(file, pkg.path, cwd)) {
29
- matched.set(pkg.id, pkg);
30
- break;
35
+ for (const file of files) {
36
+ const fullPath = join(cwd, file);
37
+ for (const pkg of packages) if (!relative(pkg.path, fullPath).startsWith("..")) {
38
+ matched.set(pkg.id, pkg);
39
+ break;
40
+ }
31
41
  }
32
42
  return [...matched.values()];
33
43
  }
34
- function isUnderDir(file, dir, cwd) {
35
- const absolute = join(cwd, file);
36
- const rel = relative(normalize(dir), absolute);
37
- return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
38
- }
39
- async function addGitOutput(files, cwd, args) {
40
- const result = await x("git", args, { nodeOptions: { cwd } });
41
- if (result.exitCode !== 0) return;
42
- for (const line of result.stdout.split("\n")) {
43
- const trimmed = line.trim();
44
- if (trimmed) files.add(trimmed);
45
- }
46
- }
47
44
  //#endregion
48
45
  //#region src/cli/changelog.ts
49
46
  async function runChangelogTui(tegami) {
@@ -81,11 +78,10 @@ async function runChangelogTui(tegami) {
81
78
  }
82
79
  });
83
80
  if (isCancel(message)) throw new CancelledError();
84
- const packages = generateReplays(context.graph, packageBumpMap);
85
81
  await persistChangelogs(context, [{
86
82
  filename: changelogFilename(),
87
- content: renderChangelog({ packages }, `## ${message.trim()}`),
88
- packages
83
+ content: renderChangelog({ packages: packageBumpMap }, `## ${message.trim()}`),
84
+ packages: packageBumpMap
89
85
  }]);
90
86
  }
91
87
  async function persistChangelogs(context, entries, emptyMessage = "No changelogs created.") {
@@ -307,11 +303,8 @@ async function buildPrPreview(context, draft, options = {}) {
307
303
  lines.push("");
308
304
  }
309
305
  if (prChangelogs.length > 0) {
310
- lines.push("#### Changelogs in this PR", "");
311
- for (const entry of prChangelogs) {
312
- const title = entry.sections[0]?.title ?? entry.filename;
313
- lines.push(`- \`${entry.filename}\` — ${title}`);
314
- }
306
+ lines.push("#### Changelogs in this PR", "", "| Changelog | Title |", "| --- | --- |");
307
+ for (const entry of prChangelogs) for (const section of entry.sections) lines.push(`| \`${entry.filename}\` | ${section.title} |`);
315
308
  lines.push("");
316
309
  } else if (pendingPackages.length === 0) lines.push("#### No changelogs yet", "", "This PR has no pending changelog files. If your changes require a release, add a changelog before merging.", "");
317
310
  else if (prChangelogFiles.size === 0) lines.push("This PR does not add changelog files. Pending changelogs from other branches are included in the preview above.", "");
@@ -1,8 +1,6 @@
1
- import { a as maxBump, t as bumpDepth } from "./semver-C4vJ4SK8.js";
1
+ import { a as maxBump, t as bumpDepth } from "./semver-jcIUAvbl.js";
2
2
  import { n as execFailure } from "./error-DNy8R5ue.js";
3
- import { t as bumpTypeSchema } from "./schemas-BdUlXfSu.js";
4
3
  import { x } from "tinyexec";
5
- import * as semver from "semver";
6
4
  import z from "zod";
7
5
  import { dump } from "js-yaml";
8
6
  //#region src/utils/conventional-commit.ts
@@ -71,6 +69,11 @@ function conventionalCommitToBump(type, breaking) {
71
69
  }
72
70
  //#endregion
73
71
  //#region src/changelog/shared.ts
72
+ const bumpTypeSchema = z.enum([
73
+ "major",
74
+ "minor",
75
+ "patch"
76
+ ]);
74
77
  const changelogPackageConfigSchema = z.object({
75
78
  type: bumpTypeSchema.optional(),
76
79
  replay: z.array(z.string().min(1)).optional()
@@ -109,8 +112,7 @@ async function generateFromCommits(context, { from, to } = {}) {
109
112
  let bumpType = "patch";
110
113
  for (const change of changes) bumpType = maxBump(change.type, bumpType);
111
114
  const packageBumpMap = Object.fromEntries(packageNames.map((name) => [name, bumpType]));
112
- const packages = generateReplays(context.graph, packageBumpMap);
113
- const content = renderChangelog({ packages }, changes.map((change) => {
115
+ const content = renderChangelog({ packages: packageBumpMap }, changes.map((change) => {
114
116
  const heading = "#".repeat(bumpDepth(change.type));
115
117
  if (!change.body) return `${heading} ${change.title}`;
116
118
  return `${heading} ${change.title}\n\n${change.body}`;
@@ -118,7 +120,7 @@ async function generateFromCommits(context, { from, to } = {}) {
118
120
  return {
119
121
  filename: changelogFilename(index),
120
122
  content,
121
- packages,
123
+ packages: packageBumpMap,
122
124
  changes
123
125
  };
124
126
  });
@@ -164,26 +166,9 @@ async function latestTag(cwd) {
164
166
  if (result.exitCode !== 0) return;
165
167
  return result.stdout.trim() || void 0;
166
168
  }
167
- function generateReplays(graph, base) {
168
- const packages = { ...base };
169
- for (const [ref, type] of Object.entries(base)) {
170
- const resolved = graph.getByName(ref);
171
- for (const pkg of resolved) {
172
- const plan = pkg.initDraft();
173
- pkg.configureDraft(plan, graph.getPackageGroup(pkg.id));
174
- const prerelease = semver.prerelease(pkg.version)?.[0];
175
- const targetPrerelease = plan.prerelease;
176
- if (targetPrerelease && !prerelease || targetPrerelease && prerelease && targetPrerelease === prerelease) packages[pkg.id] = {
177
- type,
178
- replay: [`exit prerelease: ${pkg.name}`]
179
- };
180
- }
181
- }
182
- return packages;
183
- }
184
169
  function changelogFilename(disambiguator = 0) {
185
170
  const date = /* @__PURE__ */ new Date();
186
171
  return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}-${(Date.now() + disambiguator).toString(36)}.md`;
187
172
  }
188
173
  //#endregion
189
- export { renderChangelog as a, changelogFrontmatterSchema as i, generateFromCommits as n, generateReplays as r, changelogFilename as t };
174
+ export { renderChangelog as i, generateFromCommits as n, changelogFrontmatterSchema as r, changelogFilename as t };
@@ -1,4 +1,4 @@
1
- import { r as LogGenerator } from "../types-DEaKjB3O.js";
1
+ import { r as LogGenerator } from "../types-DnCUr2dB.js";
2
2
 
3
3
  //#region src/generators/simple.d.ts
4
4
  declare function simpleGenerator(): LogGenerator;
@@ -1,4 +1,4 @@
1
- import { i as formatPackageVersion } from "../semver-C4vJ4SK8.js";
1
+ import { i as formatPackageVersion } from "../semver-jcIUAvbl.js";
2
2
  //#region src/generators/simple.ts
3
3
  function simpleGenerator() {
4
4
  return { generate({ pkg, packageDraft }) {
@@ -1,4 +1,4 @@
1
- import { n as bumpVersion } from "./semver-C4vJ4SK8.js";
1
+ import { n as bumpVersion } from "./semver-jcIUAvbl.js";
2
2
  //#region src/graph.ts
3
3
  /** Package discovered in the workspace. */
4
4
  var WorkspacePackage = class {
@@ -21,13 +21,8 @@ var WorkspacePackage = class {
21
21
  }
22
22
  /** configure an initial draft to match script-level configs. */
23
23
  configureDraft(draft, group) {
24
- const groupOptions = group?.options;
25
- const { prerelease = groupOptions?.prerelease, npm: { distTag = groupOptions?.npm?.distTag } = {} } = this.opts;
24
+ const { prerelease = group?.options?.prerelease } = this.opts;
26
25
  if (prerelease !== void 0) draft.prerelease = prerelease;
27
- if (distTag) {
28
- draft.npm ??= {};
29
- draft.npm.distTag = distTag;
30
- }
31
26
  }
32
27
  };
33
28
  /** Dependency graph for discovered workspace packages. */
@@ -0,0 +1,64 @@
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-DnCUr2dB.js";
2
+
3
+ //#region src/changelog/generate.d.ts
4
+ interface GenerateFromCommitsOptions {
5
+ /** Start revision. Defaults to the latest reachable git tag, or all history if none exists. */
6
+ from?: string;
7
+ /** End revision. Defaults to HEAD. */
8
+ to?: string;
9
+ }
10
+ interface CommitChangelog {
11
+ filename: string;
12
+ content: string;
13
+ packages: Record<string, BumpType | ChangelogPackageConfig>;
14
+ changes: CommitChange[];
15
+ }
16
+ interface CommitChange {
17
+ hash: string;
18
+ subject: string;
19
+ body: string;
20
+ packages: string[];
21
+ type: BumpType;
22
+ title: string;
23
+ }
24
+ //#endregion
25
+ //#region src/index.d.ts
26
+ interface GenerateChangelogOptions extends GenerateFromCommitsOptions {
27
+ /**
28
+ * Write changelog files to disk.
29
+ *
30
+ * @default true
31
+ */
32
+ write?: boolean;
33
+ }
34
+ interface Tegami {
35
+ /** Create pending changelog files from git commit history. */
36
+ generateChangelog(options?: GenerateChangelogOptions): Promise<CommitChangelog[]>;
37
+ /** Build a draft from pending changelog files. */
38
+ draft(): Promise<Draft>;
39
+ /** Publish packages from the publish lock. */
40
+ publish(options?: PublishOptions): Promise<PublishPlan | "skipped">;
41
+ /**
42
+ * Check publish status.
43
+ *
44
+ * Prefer `publish()` over this if you are publishing packages, it will also check the publish status.
45
+ */
46
+ publishStatus(): Promise<"pending" | "success" | "idle">;
47
+ /** Remove the publish lock file after publishing has finished successfully. */
48
+ cleanup(): Promise<{
49
+ state: "removed";
50
+ } | {
51
+ state: "skipped";
52
+ reason: "no-plan" | "pending";
53
+ }>;
54
+ /** Internal APIs, do not use it unless you know what you are doing */
55
+ _internal: {
56
+ context(): Promise<TegamiContext>;
57
+ graph(): Promise<PackageGraph>;
58
+ options: TegamiOptions;
59
+ };
60
+ }
61
+ /** Create a Tegami project handle. */
62
+ declare function tegami<const Groups extends string = string>(options?: TegamiOptions<Groups>): Tegami;
63
+ //#endregion
64
+ export { CommitChangelog as i, Tegami as n, tegami as r, GenerateChangelogOptions as t };
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
- import { A as PackageDraft, C as CommitChangelog, D as WorkspacePackage, E as PackageGroup, O as Draft, S as PublishPlan, T as PackageGraph, _ as tegami, a as PublishPreflight, b as PackagePublishResult, c as TegamiPluginOption, g as Tegami, h as GenerateChangelogOptions, i as PackageOptions, k as DraftPolicy, n as GroupOptions, o as TegamiOptions, r as LogGenerator, s as TegamiPlugin, v as PublishLock, x as PublishOptions, y as PackagePublishPlan } from "./types-DEaKjB3O.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-DnCUr2dB.js";
2
+ import { i as CommitChangelog, n as Tegami, r as tegami, t as GenerateChangelogOptions } from "./index-B4ehnvrS.js";
2
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,9 +1,9 @@
1
- import { a as maxBump } from "./semver-C4vJ4SK8.js";
2
- import { i as changelogFrontmatterSchema, n as generateFromCommits } from "./generate-L7ucD7ic.js";
1
+ import { a as maxBump } from "./semver-jcIUAvbl.js";
2
+ import { n as generateFromCommits, r as changelogFrontmatterSchema } from "./generate-OZFKzXnu.js";
3
3
  import { r as handlePluginError } from "./error-DNy8R5ue.js";
4
- import { t as PackageGraph } from "./graph-DrzluXw8.js";
4
+ import { t as PackageGraph } from "./graph-OnX9ncdQ.js";
5
5
  import { cargo } from "./providers/cargo.js";
6
- import { npm } from "./providers/npm.js";
6
+ import { n as npm } from "./npm-Q0qvAkIu.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";
@@ -36,12 +36,18 @@ async function createTegamiContext(options = {}) {
36
36
  return (pkg) => pkg.name === pattern || pkg.id === pattern;
37
37
  });
38
38
  for (const [name, groupOptions] of Object.entries(options.groups ?? {})) graph.registerGroup(name, groupOptions);
39
+ let getPackageOptions;
40
+ if (typeof options.packages === "function") getPackageOptions = options.packages;
41
+ else if (options.packages) {
42
+ const packages = options.packages;
43
+ getPackageOptions = (pkg) => packages[pkg.id] ?? packages[pkg.name];
44
+ }
39
45
  for (const pkg of graph.getPackages()) {
40
- if (ignoreMatchers?.length && ignoreMatchers.some((matcher) => matcher(pkg))) {
46
+ if (ignoreMatchers && ignoreMatchers.some((matcher) => matcher(pkg))) {
41
47
  graph.delete(pkg.id);
42
48
  continue;
43
49
  }
44
- const packageOptions = options.packages?.[pkg.id] ?? options.packages?.[pkg.name];
50
+ const packageOptions = getPackageOptions?.(pkg);
45
51
  if (!packageOptions) continue;
46
52
  pkg.setPackageOptions(packageOptions);
47
53
  if (packageOptions.group) graph.addGroupMember(packageOptions.group, pkg.id);
@@ -410,6 +416,11 @@ var Draft = class {
410
416
  applyReplays(snapshots) {
411
417
  const updated = /* @__PURE__ */ new Map();
412
418
  const { graph } = this.context;
419
+ const defaultReplays = (name) => {
420
+ const replay = [];
421
+ for (const pkg of graph.getByName(name)) if (this.packages.get(pkg.id)?.prerelease) replay.push(`exit prerelease: ${pkg.id}`);
422
+ return replay;
423
+ };
413
424
  const isMatch = (condition) => {
414
425
  if (condition.type === "on-exit-prerelease") return graph.getByName(condition.name).some((pkg) => {
415
426
  const previous = snapshots.get(pkg.id);
@@ -421,8 +432,10 @@ var Draft = class {
421
432
  const updatedPackages = /* @__PURE__ */ new Map();
422
433
  const matchedNames = /* @__PURE__ */ new Set();
423
434
  for (const [name, config] of entry.packages) {
424
- if (!config.replay || config.replay.length === 0) continue;
425
- const replay = config.replay.filter((item) => {
435
+ let replay = config.replay;
436
+ if (config.type) replay ??= defaultReplays(name);
437
+ if (!replay || replay.length === 0) continue;
438
+ replay = replay.filter((item) => {
426
439
  const condition = parseReplayCondition(item);
427
440
  if (condition && isMatch(condition)) {
428
441
  matchedNames.add(name);
@@ -545,47 +558,35 @@ async function runPublishPlan(context, plan) {
545
558
  const packagePlan = plan.packages.get(pkg.id);
546
559
  if (!packagePlan) return;
547
560
  packagePlan.publishResult = publishResult;
561
+ if (publishResult.type === "skipped") return;
548
562
  for (const plugin of context.plugins) await handlePluginError(plugin, "afterPublish", () => plugin.afterPublish?.call(context, {
549
563
  pkg,
550
564
  plan
551
565
  }));
552
566
  };
553
- for (const id of resolvePublishTargets(plan)) {
567
+ publishLoop: for (const id of resolvePublishTargets(plan)) {
554
568
  const pkg = context.graph.get(id);
555
569
  if (dryRun) {
556
570
  await onPublishResult(pkg, { type: "published" });
557
571
  continue;
558
572
  }
559
- let isSkipped = false;
560
- for (const plugin of context.plugins) if (await handlePluginError(plugin, "willPublish", () => plugin.willPublish?.call(context, { pkg })) === false) {
561
- isSkipped = true;
562
- break;
563
- }
564
- if (isSkipped) {
565
- await onPublishResult(pkg, { type: "skipped" });
566
- continue;
567
- }
568
- let published = false;
573
+ for (const plugin of context.plugins) if (await handlePluginError(plugin, "willPublish", () => plugin.willPublish?.call(context, { pkg })) === false) continue publishLoop;
569
574
  for (const plugin of context.plugins) {
570
575
  const publishResult = await handlePluginError(plugin, "publish", () => plugin.publish?.call(context, {
571
576
  pkg,
572
577
  plan
573
578
  }));
574
579
  if (publishResult) {
575
- published = true;
576
580
  await onPublishResult(pkg, publishResult);
577
- break;
581
+ continue publishLoop;
578
582
  }
579
583
  }
580
- if (!published) await onPublishResult(pkg, {
584
+ await onPublishResult(pkg, {
581
585
  type: "failed",
582
586
  error: `There is no plugin to publish package "${pkg.id}", please make sure the package has a supported provider plugin.`
583
587
  });
584
588
  }
585
- await Promise.all(Array.from(plan.packages, async ([id, packagePlan]) => {
586
- const pkg = context.graph.get(id);
587
- if (!packagePlan.publishResult) await onPublishResult(pkg, { type: "skipped" });
588
- }));
589
+ for (const packagePlan of plan.packages.values()) packagePlan.publishResult ??= { type: "skipped" };
589
590
  for (const plugin of context.plugins) await handlePluginError(plugin, "afterPublishAll", () => plugin.afterPublishAll?.call(context, { plan }));
590
591
  }
591
592
  async function runPreflights(context, plan) {