tegami 0.1.0-beta.4 → 0.1.1

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,4 @@
1
- import { n as handlePluginError } from "./error-DBK-9uBa.js";
1
+ import { n as handlePluginError } from "./error-BaOQJtvf.js";
2
2
  import { n as jsonCodec, t as bumpTypeSchema } from "./schemas-CurBAaW5.js";
3
3
  import z$1 from "zod";
4
4
  import { readFile } from "fs/promises";
@@ -1,4 +1,4 @@
1
- import { C as PublishResult, O as DraftPlan, _ as Tegami, t as Awaitable } from "../types-Cx-uvEWw.js";
1
+ import { k as DraftPlan, t as Awaitable, v as Tegami, w as PublishResult } from "../types-Diwnh8Tn.js";
2
2
  import { Command } from "commander";
3
3
 
4
4
  //#region src/cli/index.d.ts
package/dist/cli/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { a as changelogFilename, t as assertPublishPlanFinished } from "../checks-BQISvt_o.js";
2
- import { n as handlePluginError } from "../error-DBK-9uBa.js";
3
- import { r as formatNpmDistTag, t as bumpDepth } from "../semver-CPtl0XNq.js";
1
+ import { a as changelogFilename, t as assertPublishPlanFinished } from "../checks-Bz3Rf2OX.js";
2
+ import { n as handlePluginError, t as execFailure } from "../error-BaOQJtvf.js";
3
+ import { n as formatNpmDistTag } from "../semver-mWK2Khi2.js";
4
4
  import { t as isCI } from "../constants-B9qjNfvr.js";
5
5
  import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
6
6
  import path, { basename, isAbsolute, join, normalize, relative, resolve } from "node:path";
@@ -89,8 +89,7 @@ async function buildPrPreview(context, draft, options = {}) {
89
89
  const pullRequest = await resolvePullRequest(context, options);
90
90
  const tegamiCommand = await formatRunScriptCommand(context.cwd, "tegami", context.options.npm?.client);
91
91
  const prChangelogFiles = await listPullRequestChangelogFiles(context, pullRequest.baseSha, pullRequest.headSha);
92
- const changelogDir = relative(context.cwd, context.changelogDir) || ".tegami";
93
- const createLink = createChangelogUrl(pullRequest.headRepo, pullRequest.headRef, changelogDir, changelogFilename());
92
+ const createLink = createChangelogUrl(context, pullRequest.headRepo, pullRequest.headRef, changelogFilename());
94
93
  const lines = [
95
94
  "### Tegami",
96
95
  "",
@@ -145,7 +144,7 @@ async function postPrComment(body) {
145
144
  "--jq",
146
145
  `[.[] | select(.body | startswith("${COMMENT_MARKER}")) | .id][0] // empty`
147
146
  ]);
148
- if (listResult.exitCode !== 0) throw new Error(listResult.stderr || "Failed to list pull request comments.");
147
+ if (listResult.exitCode !== 0) throw execFailure("Failed to list pull request comments.", listResult);
149
148
  const existingId = listResult.stdout.trim();
150
149
  if (existingId) {
151
150
  const dir = await mkdtemp(join(tmpdir(), "tegami-pr-comment-"));
@@ -160,7 +159,7 @@ async function postPrComment(body) {
160
159
  "--input",
161
160
  inputPath
162
161
  ]);
163
- if (updateResult.exitCode !== 0) throw new Error(updateResult.stderr || "Failed to update pull request comment.");
162
+ if (updateResult.exitCode !== 0) throw execFailure("Failed to update pull request comment.", updateResult);
164
163
  } finally {
165
164
  await rm(dir, {
166
165
  recursive: true,
@@ -178,7 +177,7 @@ async function postPrComment(body) {
178
177
  "--repo",
179
178
  repo
180
179
  ]);
181
- if (createResult.exitCode !== 0) throw new Error(createResult.stderr || "Failed to create pull request comment.");
180
+ if (createResult.exitCode !== 0) throw execFailure("Failed to create pull request comment.", createResult);
182
181
  }
183
182
  async function readPullRequestNumberFromWorkflowRunEvent() {
184
183
  const eventPath = process.env.GITHUB_EVENT_PATH;
@@ -221,7 +220,7 @@ async function readPullRequestFromGh(repo, number) {
221
220
  "--json",
222
221
  "headRefName,baseRefOid,headRefOid,headRepository"
223
222
  ]);
224
- if (result.exitCode !== 0) throw new Error(result.stderr || `Failed to resolve pull request #${number}.`);
223
+ if (result.exitCode !== 0) throw execFailure(`Failed to resolve pull request #${number}.`, result);
225
224
  const data = JSON.parse(result.stdout);
226
225
  return {
227
226
  repo,
@@ -259,10 +258,7 @@ async function listPullRequestChangelogFiles(context, baseSha, headSha) {
259
258
  "--",
260
259
  `${dir}/`
261
260
  ], { nodeOptions: { cwd: context.cwd } });
262
- if (result.exitCode !== 0) {
263
- const detail = result.stderr.trim();
264
- throw new Error(detail ? `Failed to list pull request changelog files: ${detail}` : "Failed to list pull request changelog files.");
265
- }
261
+ if (result.exitCode !== 0) throw execFailure("Failed to list pull request changelog files.", result);
266
262
  const files = /* @__PURE__ */ new Set();
267
263
  for (const line of result.stdout.split("\n")) {
268
264
  const trimmed = line.trim();
@@ -270,9 +266,9 @@ async function listPullRequestChangelogFiles(context, baseSha, headSha) {
270
266
  }
271
267
  return files;
272
268
  }
273
- function createChangelogUrl(repo, branch, changelogDir, filename) {
274
- const segments = [...changelogDir.split("/").filter(Boolean), filename].map((part) => encodeURIComponent(part));
275
- return `https://github.com/${repo}/new/${branch.split("/").map(encodeURIComponent).join("/")}/${segments.join("/")}`;
269
+ function createChangelogUrl(context, repo, branch, filename) {
270
+ const filePath = join(relative(context.cwd, context.changelogDir), filename).replaceAll("\\", "/");
271
+ return `https://github.com/${repo}/new/${branch.split("/").map(encodeURIComponent).join("/")}?${new URLSearchParams({ filename: filePath })}`;
276
272
  }
277
273
  //#endregion
278
274
  //#region src/utils/git-changes.ts
@@ -400,7 +396,7 @@ async function createChangelogs(tegami, _options) {
400
396
  for (const [group, changed] of groups) {
401
397
  const members = group.packages.map(getPackageLabel).join(", ");
402
398
  selectOptions.push({
403
- label: `Group ${group.name}`,
399
+ label: `(Group) ${group.name}`,
404
400
  value: `group:${group.name}`,
405
401
  hint: changed ? `changed · ${members}` : members
406
402
  });
@@ -440,7 +436,8 @@ async function createChangelogs(tegami, _options) {
440
436
  outro("Changelogs ready.");
441
437
  return;
442
438
  }
443
- const type = await select({
439
+ const packageBumpMap = {};
440
+ const bumpType = await select({
444
441
  message: "Select release type",
445
442
  options: [
446
443
  {
@@ -454,10 +451,36 @@ async function createChangelogs(tegami, _options) {
454
451
  {
455
452
  value: "major",
456
453
  label: "major"
454
+ },
455
+ {
456
+ value: "per-package",
457
+ label: "choose per-package"
457
458
  }
458
459
  ]
459
460
  });
460
- if (isCancel(type)) throw new CancelledError();
461
+ if (isCancel(bumpType)) throw new CancelledError();
462
+ if (bumpType === "per-package") for (const pkg of selectedPackages) {
463
+ const bumpType = await select({
464
+ message: `Select release type for "${pkg}"`,
465
+ options: [
466
+ {
467
+ value: "patch",
468
+ label: "patch"
469
+ },
470
+ {
471
+ value: "minor",
472
+ label: "minor"
473
+ },
474
+ {
475
+ value: "major",
476
+ label: "major"
477
+ }
478
+ ]
479
+ });
480
+ if (isCancel(bumpType)) throw new CancelledError();
481
+ packageBumpMap[pkg] = bumpType;
482
+ }
483
+ else for (const pkg of selectedPackages) packageBumpMap[pkg] = bumpType;
461
484
  const message = await multiline({
462
485
  message: "Describe change (Markdown supported, press tab then enter to exit)",
463
486
  placeholder: "The first line is heading\n\nAdditional description.",
@@ -471,9 +494,11 @@ async function createChangelogs(tegami, _options) {
471
494
  const s = spinner();
472
495
  s.start("Creating changelog");
473
496
  await mkdir(context.changelogDir, { recursive: true });
474
- await writeFile(join(context.changelogDir, filename), renderManualChangelog(selectedPackages, type, message.trim()));
497
+ await writeFile(join(context.changelogDir, filename), renderManualChangelog(packageBumpMap, message.trim()));
475
498
  s.stop("Created changelog file");
476
- note(`${filename}\n${selectedPackages.join(", ")}: ${type}`, "Created changelog");
499
+ const notes = [filename];
500
+ for (const pkg of selectedPackages) notes.push(`${pkg}: ${packageBumpMap[pkg]}`);
501
+ note(notes.join("\n"), "Created changelog");
477
502
  outro("Changelog ready.");
478
503
  }
479
504
  async function versionPackages(tegami, options) {
@@ -563,16 +588,13 @@ async function runCleanup(tegami) {
563
588
  }
564
589
  outro(`Publish plan at ${planPath} is still pending. Publish it before cleanup.`);
565
590
  }
566
- function renderManualChangelog(packages, type, message) {
567
- const prefix = "#".repeat(bumpDepth(type));
568
- const packageMap = {};
569
- for (const name of packages) packageMap[name] = type;
591
+ function renderManualChangelog(packageBumpMap, message) {
570
592
  return [
571
593
  "---",
572
- dump({ packages: packageMap }).trim(),
594
+ dump({ packages: packageBumpMap }).trim(),
573
595
  "---",
574
596
  "",
575
- `${prefix} ${message}`,
597
+ `## ${message}`,
576
598
  ""
577
599
  ].join("\n");
578
600
  }
@@ -1,11 +1,10 @@
1
1
  //#region src/utils/error.ts
2
- function commandOutput(result) {
3
- return [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
4
- }
5
2
  function execFailure(context, result) {
6
3
  const lines = [context, `(exit ${result.exitCode})`];
7
- const output = commandOutput(result);
8
- if (output) lines.push(output);
4
+ const out = result.stdout.trim();
5
+ const err = result.stderr.trim();
6
+ if (out) lines.push(out);
7
+ if (err) lines.push(err);
9
8
  return new Error(lines.join("\n"));
10
9
  }
11
10
  function isNodeError(error) {
@@ -1,4 +1,4 @@
1
- import { r as LogGenerator } from "../types-Cx-uvEWw.js";
1
+ import { r as LogGenerator } from "../types-Diwnh8Tn.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-CPtl0XNq.js";
1
+ import { r as formatPackageVersion } from "../semver-mWK2Khi2.js";
2
2
  //#region src/generators/simple.ts
3
3
  function simpleGenerator() {
4
4
  return { generate({ changelogs, version, packageName, plan }) {
@@ -1,4 +1,4 @@
1
- import { n as bumpVersion } from "./semver-CPtl0XNq.js";
1
+ import { t as bumpVersion } from "./semver-mWK2Khi2.js";
2
2
  //#region src/graph.ts
3
3
  /** Package discovered in the workspace. */
4
4
  var WorkspacePackage = class {
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { C as PublishResult, D as WorkspacePackage, E as PackageGroup, O as DraftPlan, S as PublishOptions, T as PackageGraph, _ as Tegami, a as RegistryClient, b as CreatedChangelog, c as TegamiPluginOption, i as PackageOptions, k as PackagePlan, n as GroupOptions, o as TegamiOptions, r as LogGenerator, s as TegamiPlugin, v as tegami, x as PackagePublishResult, y as CreateChangelogOptions } from "./types-Cx-uvEWw.js";
2
- export { type CreateChangelogOptions, type CreatedChangelog, type DraftPlan, type GroupOptions, type LogGenerator, type PackageGraph, type PackageGroup, type PackageOptions, type PackagePlan, type PackagePublishResult, type PublishOptions, type PublishResult, type RegistryClient, Tegami, type TegamiOptions, type TegamiPlugin, type TegamiPluginOption, type WorkspacePackage, tegami };
1
+ import { A as PackagePlan, C as PublishOptions, D as PackageGroup, E as PackageGraph, O as WorkspacePackage, S as PackagePublishResult, a as PublishPreflight, b as CreateChangelogOptions, c as TegamiPlugin, i as PackageOptions, k as DraftPlan, l as TegamiPluginOption, n as GroupOptions, o as RegistryClient, r as LogGenerator, s as TegamiOptions, v as Tegami, w as PublishResult, x as CreatedChangelog, y as tegami } from "./types-Diwnh8Tn.js";
2
+ export { type CreateChangelogOptions, type CreatedChangelog, type DraftPlan, type GroupOptions, type LogGenerator, type PackageGraph, type PackageGroup, type PackageOptions, type PackagePlan, type PackagePublishResult, type PublishOptions, type PublishPreflight, type PublishResult, type RegistryClient, Tegami, type TegamiOptions, type TegamiPlugin, type TegamiPluginOption, type WorkspacePackage, tegami };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { a as changelogFilename, i as readPlanStore, n as publishPlanStatus, r as createPlanStore, t as assertPublishPlanFinished } from "./checks-BQISvt_o.js";
2
- import { n as handlePluginError, t as execFailure } from "./error-DBK-9uBa.js";
3
- import { a as maxBump } from "./semver-CPtl0XNq.js";
4
- import { t as PackageGraph } from "./graph-B22NBRUG.js";
1
+ import { a as changelogFilename, i as readPlanStore, n as publishPlanStatus, r as createPlanStore, t as assertPublishPlanFinished } from "./checks-Bz3Rf2OX.js";
2
+ import { n as handlePluginError, t as execFailure } from "./error-BaOQJtvf.js";
3
+ import { i as maxBump } from "./semver-mWK2Khi2.js";
4
+ import { t as PackageGraph } from "./graph-CUgwuRW5.js";
5
5
  import { cargo } from "./providers/cargo.js";
6
6
  import { t as bumpTypeSchema } from "./schemas-CurBAaW5.js";
7
7
  import { npm } from "./providers/npm.js";
@@ -490,14 +490,48 @@ function headingToBump(depth) {
490
490
  }
491
491
  //#endregion
492
492
  //#region src/publish.ts
493
+ async function resolvePublishTargets(context, store) {
494
+ const targets = [];
495
+ const preflightPromises = [];
496
+ for (const [id, plan] of Object.entries(store.packages)) {
497
+ if (!plan.publish) continue;
498
+ const pkg = context.graph.get(id);
499
+ if (!pkg) continue;
500
+ targets.push(pkg.id);
501
+ preflightPromises.push(context.getRegistryClient(pkg).publishPreflight?.(pkg, {
502
+ store,
503
+ packageStore: plan
504
+ }));
505
+ }
506
+ const preflights = await Promise.all(preflightPromises);
507
+ const children = /* @__PURE__ */ new Map();
508
+ for (let i = 0; i < targets.length; i++) {
509
+ const id = targets[i];
510
+ children.set(id, preflights[i]?.wait);
511
+ }
512
+ const ordered = [];
513
+ function scan(id, stack = /* @__PURE__ */ new Set()) {
514
+ if (stack.has(id)) throw new Error(`circular reference of deps: ${[...stack, id].join(" -> ")}`);
515
+ if (ordered.includes(id)) return;
516
+ const deps = children.get(id);
517
+ if (deps) {
518
+ stack.add(id);
519
+ for (const dep of deps) scan(dep, stack);
520
+ stack.delete(id);
521
+ }
522
+ ordered.push(id);
523
+ }
524
+ for (const id of targets) scan(id);
525
+ return ordered;
526
+ }
493
527
  async function publishFromPlan(context, store, options) {
494
528
  const { dryRun = false } = options;
495
529
  const packages = [];
496
530
  if ((await publishPlanStatus(store, context)).state !== "pending") return { state: "skipped" };
497
- for (const [id, plan] of Object.entries(store.packages)) {
498
- if (!plan.publish) continue;
531
+ const orderedIds = await resolvePublishTargets(context, store);
532
+ for (const id of orderedIds) {
533
+ const plan = store.packages[id];
499
534
  const pkg = context.graph.get(id);
500
- if (!pkg) continue;
501
535
  const registryClient = context.getRegistryClient(pkg);
502
536
  const changelogs = [];
503
537
  for (const id of plan.changelogIds ?? []) {
@@ -1,4 +1,4 @@
1
- import { s as TegamiPlugin } from "../types-Cx-uvEWw.js";
1
+ import { c as TegamiPlugin } from "../types-Diwnh8Tn.js";
2
2
 
3
3
  //#region src/plugins/git.d.ts
4
4
  interface GitPluginOptions {
@@ -1,4 +1,4 @@
1
- import { t as execFailure } from "../error-DBK-9uBa.js";
1
+ import { t as execFailure } from "../error-BaOQJtvf.js";
2
2
  import { t as isCI } from "../constants-B9qjNfvr.js";
3
3
  import { x } from "tinyexec";
4
4
  //#region src/plugins/git.ts
@@ -1,4 +1,4 @@
1
- import { O as DraftPlan, s as TegamiPlugin, t as Awaitable, w as TegamiContext, x as PackagePublishResult } from "../types-Cx-uvEWw.js";
1
+ import { S as PackagePublishResult, T as TegamiContext, c as TegamiPlugin, k as DraftPlan, t as Awaitable } from "../types-Diwnh8Tn.js";
2
2
  import { GitPluginOptions } from "./git.js";
3
3
 
4
4
  //#region src/plugins/github.d.ts
@@ -1,5 +1,5 @@
1
- import { t as execFailure } from "../error-DBK-9uBa.js";
2
- import { i as formatPackageVersion, r as formatNpmDistTag } from "../semver-CPtl0XNq.js";
1
+ import { t as execFailure } from "../error-BaOQJtvf.js";
2
+ import { n as formatNpmDistTag, r as formatPackageVersion } from "../semver-mWK2Khi2.js";
3
3
  import { t as isCI } from "../constants-B9qjNfvr.js";
4
4
  import { git } from "./git.js";
5
5
  import { join, relative } from "node:path";
@@ -1,2 +1,2 @@
1
- import { d as CargoRegistryClient, f as cargo, l as CargoPackage, u as CargoPluginOptions } from "../types-Cx-uvEWw.js";
1
+ import { d as CargoPluginOptions, f as CargoRegistryClient, p as cargo, u as CargoPackage } from "../types-Diwnh8Tn.js";
2
2
  export { CargoPackage, CargoPluginOptions, CargoRegistryClient, cargo };
@@ -1,10 +1,10 @@
1
- import { r as isNodeError } from "../error-DBK-9uBa.js";
2
- import { n as WorkspacePackage } from "../graph-B22NBRUG.js";
1
+ import { r as isNodeError, t as execFailure } from "../error-BaOQJtvf.js";
2
+ import { n as WorkspacePackage } from "../graph-CUgwuRW5.js";
3
3
  import { readFile, writeFile } from "node:fs/promises";
4
4
  import { join, normalize } from "node:path";
5
5
  import { x } from "tinyexec";
6
+ import initToml, { edit, parse } from "@rainbowatcher/toml-edit-js";
6
7
  import * as semver from "semver";
7
- import { parse as parse$1, stringify } from "smol-toml";
8
8
  import { glob } from "tinyglobby";
9
9
  //#region src/providers/cargo.ts
10
10
  const DEP_FIELDS = [
@@ -15,12 +15,14 @@ const DEP_FIELDS = [
15
15
  var CargoPackage = class extends WorkspacePackage {
16
16
  path;
17
17
  manifest;
18
+ content;
18
19
  workspaceManifest;
19
20
  manager = "cargo";
20
- constructor(path, manifest, workspaceManifest) {
21
+ constructor(path, manifest, content, workspaceManifest) {
21
22
  super();
22
23
  this.path = path;
23
24
  this.manifest = manifest;
25
+ this.content = content;
24
26
  this.workspaceManifest = workspaceManifest;
25
27
  }
26
28
  get name() {
@@ -34,8 +36,15 @@ var CargoPackage = class extends WorkspacePackage {
34
36
  defaults.publish ??= this.packageInfo.publish !== false;
35
37
  return defaults;
36
38
  }
39
+ setVersion(version) {
40
+ this.packageInfo.version = version;
41
+ this.patch("package.version", version);
42
+ }
37
43
  async write() {
38
- await writeFile(join(this.path, "Cargo.toml"), stringify(this.manifest));
44
+ await writeFile(join(this.path, "Cargo.toml"), this.content);
45
+ }
46
+ patch(path, value) {
47
+ this.content = edit(this.content, path, value);
39
48
  }
40
49
  get packageInfo() {
41
50
  this.manifest.package ??= {};
@@ -46,9 +55,12 @@ var CargoPackage = class extends WorkspacePackage {
46
55
  }
47
56
  };
48
57
  var CargoRegistryClient = class {
58
+ graph;
49
59
  id = "cargo";
50
60
  #versionMap = /* @__PURE__ */ new Map();
51
- constructor(_graph) {}
61
+ constructor(graph) {
62
+ this.graph = graph;
63
+ }
52
64
  supports(pkg) {
53
65
  return pkg instanceof CargoPackage;
54
66
  }
@@ -65,14 +77,24 @@ var CargoRegistryClient = class {
65
77
  }
66
78
  return info;
67
79
  }
68
- async publish(pkg) {
69
- await x("cargo", ["publish"], {
70
- nodeOptions: { cwd: pkg.path },
71
- throwOnError: true
72
- });
80
+ publishPreflight(pkg, { store }) {
81
+ const wait = [];
82
+ for (const { table } of dependencyTables(pkg.manifest, "")) for (const [rawName, rawSpec] of Object.entries(table)) {
83
+ if (!isTableValue(rawSpec) || typeof rawSpec.path !== "string") continue;
84
+ const id = `cargo:${stringValue(rawSpec.package) ?? rawName}`;
85
+ if (!store.packages[id]?.publish) continue;
86
+ const linked = this.graph.get(id);
87
+ if (!linked || !(linked instanceof CargoPackage)) continue;
88
+ wait.push(id);
89
+ }
90
+ return { wait };
91
+ }
92
+ async publish(pkg, _env) {
93
+ const result = await x("cargo", ["publish"], { nodeOptions: { cwd: pkg.path } });
94
+ if (result.exitCode !== 0) throw execFailure(`Failed to publish ${pkg.name}@${pkg.version}.`, result);
73
95
  }
74
96
  };
75
- function cargo({ bumpDep: getBumpDepType = ({ kind }) => {
97
+ function cargo({ updateLockFile = false, bumpDep: getBumpDepType = ({ kind }) => {
76
98
  switch (kind) {
77
99
  case "dependencies": return "patch";
78
100
  case "build-dependencies":
@@ -90,7 +112,7 @@ function cargo({ bumpDep: getBumpDepType = ({ kind }) => {
90
112
  onUpdate({ pkg, plan }) {
91
113
  for (const other of graph.getPackages()) {
92
114
  if (!(other instanceof CargoPackage)) continue;
93
- for (const { table, kind } of dependencyTables(other.manifest)) for (const [rawName, rawSpec] of Object.entries(table)) {
115
+ for (const { table, kind } of dependencyTables(other.manifest, "")) for (const [rawName, rawSpec] of Object.entries(table)) {
94
116
  const spec = parseSpec(rawSpec);
95
117
  if (!spec) continue;
96
118
  const packageName = spec.package ?? rawName;
@@ -114,6 +136,9 @@ function cargo({ bumpDep: getBumpDepType = ({ kind }) => {
114
136
  return {
115
137
  name: "cargo",
116
138
  enforce: "pre",
139
+ async init() {
140
+ await initToml();
141
+ },
117
142
  async resolve() {
118
143
  await discoverCargoPackages(this.cwd, (pkg) => this.graph.add(pkg));
119
144
  },
@@ -129,11 +154,11 @@ function cargo({ bumpDep: getBumpDepType = ({ kind }) => {
129
154
  for (const pkg of graph.getPackages()) {
130
155
  if (!(pkg instanceof CargoPackage)) continue;
131
156
  const plan = draft.getPackagePlan(pkg.id);
132
- if (plan) pkg.packageInfo.version = plan.bumpVersion(pkg);
157
+ if (plan) pkg.setVersion(plan.bumpVersion(pkg));
133
158
  }
134
159
  for (const pkg of graph.getPackages()) {
135
160
  if (!(pkg instanceof CargoPackage)) continue;
136
- for (const { table } of dependencyTables(pkg.manifest)) for (const [rawName, rawSpec] of Object.entries(table)) {
161
+ for (const { table, path: tablePath } of dependencyTables(pkg.manifest, "")) for (const [rawName, rawSpec] of Object.entries(table)) {
137
162
  const spec = parseSpec(rawSpec);
138
163
  if (!spec) continue;
139
164
  const packageName = spec.package ?? rawName;
@@ -142,11 +167,17 @@ function cargo({ bumpDep: getBumpDepType = ({ kind }) => {
142
167
  const result = updateRange(spec.version, linked.version);
143
168
  if (result === false) continue;
144
169
  table[rawName] = spec.setVersion(result);
170
+ pkg.patch(typeof rawSpec === "string" ? `${tablePath}.${rawName}` : `${tablePath}.${rawName}.version`, result);
145
171
  }
146
172
  writes.push(pkg.write());
147
173
  }
148
174
  await Promise.all(writes);
149
- }
175
+ },
176
+ cli: { async publishPlanApplied() {
177
+ if (!updateLockFile) return;
178
+ const result = await x("cargo", ["update", "--workspace"], { nodeOptions: { cwd: this.cwd } });
179
+ if (result.exitCode !== 0) throw execFailure("Failed to update Cargo lock file", result);
180
+ } }
150
181
  };
151
182
  }
152
183
  async function discoverCargoPackages(cwd, add) {
@@ -155,8 +186,8 @@ async function discoverCargoPackages(cwd, add) {
155
186
  throw error;
156
187
  });
157
188
  if (!root) return;
158
- addCargoPackage(cwd, root, root, add);
159
- const workspace = tableValue(root.workspace);
189
+ addCargoPackage(cwd, root.manifest, root.content, root.manifest, add);
190
+ const workspace = tableValue(root.manifest.workspace);
160
191
  const members = workspace?.members;
161
192
  if (!workspace || !Array.isArray(members)) return;
162
193
  const exclude = Array.isArray(workspace.exclude) ? workspace.exclude.filter((member) => typeof member === "string") : [];
@@ -165,14 +196,14 @@ async function discoverCargoPackages(cwd, add) {
165
196
  path,
166
197
  manifest
167
198
  })).catch(() => void 0)));
168
- for (const entry of manifests) if (entry) addCargoPackage(entry.path, entry.manifest, root, add);
199
+ for (const entry of manifests) if (entry) addCargoPackage(entry.path, entry.manifest.manifest, entry.manifest.content, root.manifest, add);
169
200
  }
170
- function addCargoPackage(path, manifest, workspaceManifest, add) {
201
+ function addCargoPackage(path, manifest, content, workspaceManifest, add) {
171
202
  const packageInfo = tableValue(manifest.package);
172
203
  const workspacePackage = tableValue(workspaceManifest.workspace)?.package;
173
204
  if (!packageInfo?.name) return;
174
205
  if (!packageInfo.version && !tableValue(workspacePackage)?.version) return;
175
- add(new CargoPackage(path, manifest, workspaceManifest));
206
+ add(new CargoPackage(path, manifest, content, workspaceManifest));
176
207
  }
177
208
  async function expandWorkspaceMembers(cwd, members, exclude) {
178
209
  const paths = members.includes(".") ? [cwd] : [];
@@ -186,24 +217,30 @@ async function expandWorkspaceMembers(cwd, members, exclude) {
186
217
  }));
187
218
  return paths.map(normalize);
188
219
  }
189
- function dependencyTables(manifest) {
220
+ function dependencyTables(manifest, prefix) {
190
221
  const tables = [];
191
222
  for (const field of DEP_FIELDS) {
192
223
  const table = tableValue(manifest[field]);
193
- if (table) tables.push({
194
- kind: field,
195
- table
196
- });
224
+ if (table) {
225
+ const path = prefix ? `${prefix}.${field}` : field;
226
+ tables.push({
227
+ kind: field,
228
+ table,
229
+ path
230
+ });
231
+ }
197
232
  }
198
233
  const target = tableValue(manifest.target);
199
- if (target) for (const targetConfig of Object.values(target)) {
234
+ if (target) for (const [targetKey, targetConfig] of Object.entries(target)) {
200
235
  const targetTable = tableValue(targetConfig);
201
236
  if (!targetTable) continue;
237
+ const targetPath = prefix ? `${prefix}.target.${targetKey}` : `target.${targetKey}`;
202
238
  for (const field of DEP_FIELDS) {
203
239
  const table = tableValue(targetTable[field]);
204
240
  if (table) tables.push({
205
241
  kind: field,
206
- table
242
+ table,
243
+ path: `${targetPath}.${field}`
207
244
  });
208
245
  }
209
246
  }
@@ -228,7 +265,11 @@ function parseSpec(v) {
228
265
  };
229
266
  }
230
267
  async function readCargoManifest(path) {
231
- return parse$1(await readFile(join(path, "Cargo.toml"), "utf8"));
268
+ const content = await readFile(join(path, "Cargo.toml"), "utf8");
269
+ return {
270
+ manifest: parse(content),
271
+ content
272
+ };
232
273
  }
233
274
  function isTableValue(value) {
234
275
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -1,2 +1,2 @@
1
- import { g as npm, h as NpmRegistryClient, m as NpmPluginOptions, p as NpmPackage } from "../types-Cx-uvEWw.js";
1
+ import { _ as npm, g as NpmRegistryClient, h as NpmPluginOptions, m as NpmPackage } from "../types-Diwnh8Tn.js";
2
2
  export { NpmPackage, NpmPluginOptions, NpmRegistryClient, npm };
@@ -1,5 +1,5 @@
1
- import { r as isNodeError, t as execFailure } from "../error-DBK-9uBa.js";
2
- import { n as WorkspacePackage } from "../graph-B22NBRUG.js";
1
+ import { r as isNodeError, t as execFailure } from "../error-BaOQJtvf.js";
2
+ import { n as WorkspacePackage } from "../graph-CUgwuRW5.js";
3
3
  import { i as pnpmWorkspaceSchema, r as packageManifestSchema } from "../schemas-CurBAaW5.js";
4
4
  import { readFile, writeFile } from "node:fs/promises";
5
5
  import path from "node:path";
@@ -70,9 +70,8 @@ var NpmRegistryClient = class {
70
70
  if (registry) args.push("--registry", registry);
71
71
  const result = await x(this.client === "pnpm" ? "pnpm" : "npm", args, { nodeOptions: { cwd: this.cwd } });
72
72
  if (result.exitCode === 0) return true;
73
- const output = commandOutput(result);
74
- if (isMissingRegistryEntry(output)) return false;
75
- throw new Error(`Unable to validate ${pkg.name}@${pkg.version} against the npm registry${registry ? ` "${registry}"` : ""}: ${output.trim() || `command exited with code ${result.exitCode}`}`);
73
+ if (isMissingRegistryEntry(commandOutput(result))) return false;
74
+ throw execFailure(`Unable to validate ${pkg.name}@${pkg.version} against the npm registry${registry ? ` "${registry}"` : ""}.`, result);
76
75
  };
77
76
  info = run();
78
77
  this.#versionMap.set(cacheKey, info);
@@ -11,11 +11,6 @@ const WEIGHTS = {
11
11
  minor: 2,
12
12
  patch: 1
13
13
  };
14
- const DEPTH = {
15
- major: 1,
16
- minor: 2,
17
- patch: 3
18
- };
19
14
  const PRE = {
20
15
  major: "premajor",
21
16
  minor: "preminor",
@@ -25,9 +20,6 @@ function maxBump(a, b) {
25
20
  if (WEIGHTS[a] > WEIGHTS[b]) return a;
26
21
  return b;
27
22
  }
28
- function bumpDepth(type) {
29
- return DEPTH[type];
30
- }
31
23
  function bumpVersion(version, type, prerelease) {
32
24
  let next = version;
33
25
  if (prerelease) {
@@ -38,4 +30,4 @@ function bumpVersion(version, type, prerelease) {
38
30
  return next;
39
31
  }
40
32
  //#endregion
41
- export { maxBump as a, formatPackageVersion as i, bumpVersion as n, formatNpmDistTag as r, bumpDepth as t };
33
+ export { maxBump as i, formatNpmDistTag as n, formatPackageVersion as r, bumpVersion as t };
@@ -1,4 +1,3 @@
1
- import { TomlTable } from "smol-toml";
2
1
  import z$1, { z } from "zod";
3
2
  import { AgentName } from "package-manager-detector";
4
3
 
@@ -355,29 +354,51 @@ declare function npm({
355
354
  }?: NpmPluginOptions): TegamiPlugin;
356
355
  //#endregion
357
356
  //#region src/providers/cargo.d.ts
357
+ interface TomlTable {
358
+ [key: string]: TomlValue;
359
+ }
360
+ type TomlValue = string | number | boolean | TomlTable | TomlValue[];
358
361
  declare const DEP_FIELDS: readonly ["dependencies", "dev-dependencies", "build-dependencies"];
359
362
  declare class CargoPackage extends WorkspacePackage {
360
363
  readonly path: string;
361
364
  readonly manifest: TomlTable;
365
+ private content;
362
366
  private readonly workspaceManifest?;
363
367
  readonly manager = "cargo";
364
- constructor(path: string, manifest: TomlTable, workspaceManifest?: TomlTable | undefined);
368
+ constructor(path: string, manifest: TomlTable, content: string, workspaceManifest?: TomlTable | undefined);
365
369
  get name(): string;
366
370
  get version(): string;
367
371
  onPlan(context: TegamiContext): PackagePlan;
372
+ setVersion(version: string): void;
368
373
  write(): Promise<void>;
374
+ patch(path: string, value: unknown): void;
369
375
  get packageInfo(): TomlTable;
370
376
  private get workspaceVersion();
371
377
  }
372
378
  declare class CargoRegistryClient implements RegistryClient {
373
379
  #private;
380
+ private readonly graph;
374
381
  readonly id = "cargo";
375
- constructor(_graph: PackageGraph);
382
+ constructor(graph: PackageGraph);
376
383
  supports(pkg: WorkspacePackage): boolean;
377
384
  isPackagePublished(pkg: CargoPackage): Promise<boolean>;
378
- publish(pkg: CargoPackage): Promise<void>;
385
+ publishPreflight(pkg: CargoPackage, {
386
+ store
387
+ }: {
388
+ store: PlanStore;
389
+ }): PublishPreflight;
390
+ publish(pkg: CargoPackage, _env: {
391
+ store: PlanStore;
392
+ packageStore: PackagePlanStore;
393
+ }): Promise<void>;
379
394
  }
380
395
  interface CargoPluginOptions {
396
+ /**
397
+ * Update lock file after versioning.
398
+ *
399
+ * @default false
400
+ */
401
+ updateLockFile?: boolean;
381
402
  bumpDep?: (opts: {
382
403
  kind: (typeof DEP_FIELDS)[number];
383
404
  name: string;
@@ -385,6 +406,7 @@ interface CargoPluginOptions {
385
406
  }) => BumpType | false;
386
407
  }
387
408
  declare function cargo({
409
+ updateLockFile,
388
410
  bumpDep: getBumpDepType
389
411
  }?: CargoPluginOptions): TegamiPlugin;
390
412
  //#endregion
@@ -397,7 +419,7 @@ interface LogGenerator {
397
419
  version: string;
398
420
  changelogs: ChangelogEntry[];
399
421
  plan: PackagePlan;
400
- _draft: DraftPlan;
422
+ unstable_draft: DraftPlan;
401
423
  }): string | Promise<string>;
402
424
  }
403
425
  interface TegamiOptions<Groups extends string = string> {
@@ -480,14 +502,22 @@ type Awaitable<T> = T | Promise<T>;
480
502
  interface PublishPlanStatus {
481
503
  state: "pending" | "success" | "missing";
482
504
  }
505
+ interface PublishPreflight {
506
+ /** Package ids that must be published before this one, this will automatically disallow circular dependency. */
507
+ wait: string[];
508
+ }
483
509
  interface RegistryClient {
484
510
  id: string;
485
511
  supports(pkg: WorkspacePackage): boolean;
486
512
  isPackagePublished(pkg: WorkspacePackage): Promise<boolean>;
513
+ publishPreflight?(pkg: WorkspacePackage, env: {
514
+ store: PlanStore;
515
+ packageStore: PackagePlanStore;
516
+ }): Awaitable<PublishPreflight | void | undefined>;
487
517
  publish(pkg: WorkspacePackage, env: {
488
518
  store: PlanStore;
489
519
  packageStore: PackagePlanStore;
490
520
  }): Promise<void>;
491
521
  }
492
522
  //#endregion
493
- export { PublishResult as C, WorkspacePackage as D, PackageGroup as E, DraftPlan as O, PublishOptions as S, PackageGraph as T, Tegami as _, RegistryClient as a, CreatedChangelog as b, TegamiPluginOption as c, CargoRegistryClient as d, cargo as f, npm as g, NpmRegistryClient as h, PackageOptions as i, PackagePlan as k, CargoPackage as l, NpmPluginOptions as m, GroupOptions as n, TegamiOptions as o, NpmPackage as p, LogGenerator as r, TegamiPlugin as s, Awaitable as t, CargoPluginOptions as u, tegami as v, TegamiContext as w, PackagePublishResult as x, CreateChangelogOptions as y };
523
+ export { PackagePlan as A, PublishOptions as C, PackageGroup as D, PackageGraph as E, WorkspacePackage as O, PackagePublishResult as S, TegamiContext as T, npm as _, PublishPreflight as a, CreateChangelogOptions as b, TegamiPlugin as c, CargoPluginOptions as d, CargoRegistryClient as f, NpmRegistryClient as g, NpmPluginOptions as h, PackageOptions as i, DraftPlan as k, TegamiPluginOption as l, NpmPackage as m, GroupOptions as n, RegistryClient as o, cargo as p, LogGenerator as r, TegamiOptions as s, Awaitable as t, CargoPackage as u, Tegami as v, PublishResult as w, CreatedChangelog as x, tegami as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tegami",
3
- "version": "0.1.0-beta.4",
3
+ "version": "0.1.1",
4
4
  "description": "Utility for package versioning & publish",
5
5
  "license": "MIT",
6
6
  "author": "Fuma Nama",
@@ -27,13 +27,13 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@clack/prompts": "^1.5.1",
30
+ "@rainbowatcher/toml-edit-js": "^0.6.5",
30
31
  "commander": "^15.0.0",
31
32
  "js-yaml": "^4.2.0",
32
33
  "mdast-util-from-markdown": "^2.0.3",
33
34
  "mdast-util-to-markdown": "^2.1.2",
34
35
  "package-manager-detector": "^1.6.0",
35
36
  "semver": "^7.8.4",
36
- "smol-toml": "^1.6.1",
37
37
  "tinyexec": "^1.2.4",
38
38
  "tinyglobby": "^0.2.17",
39
39
  "zod": "^4.4.3"