versionary 0.11.0 → 0.12.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.
Files changed (73) hide show
  1. package/README.md +35 -19
  2. package/dist/cli/index.js +7 -18
  3. package/dist/config/schema.d.ts +9 -0
  4. package/dist/config/schema.js +3 -0
  5. package/dist/{infra/git → git}/commits.d.ts +1 -1
  6. package/dist/index.d.ts +6 -5
  7. package/dist/index.js +10 -10
  8. package/dist/release/artifact-rules.d.ts +3 -0
  9. package/dist/{domain/release → release}/changelog.d.ts +13 -2
  10. package/dist/{domain/release → release}/changelog.js +59 -6
  11. package/dist/{domain/release → release}/plan.d.ts +13 -1
  12. package/dist/{domain/release → release}/plan.js +50 -19
  13. package/dist/{app/release → release}/pr.d.ts +3 -3
  14. package/dist/{app/release → release}/pr.js +60 -66
  15. package/dist/{app/release → release}/recovery.d.ts +2 -1
  16. package/dist/{app/release → release}/release.d.ts +2 -2
  17. package/dist/{app/release → release}/release.js +14 -17
  18. package/dist/{app/release → release}/state.js +1 -1
  19. package/dist/{verify → release}/verify-project.js +2 -2
  20. package/dist/scm/client.d.ts +2 -0
  21. package/dist/scm/client.js +7 -0
  22. package/dist/scm/github-plugin.d.ts +2 -1
  23. package/dist/scm/github-plugin.js +2 -0
  24. package/dist/scm/types.d.ts +37 -0
  25. package/dist/{domain/strategy → strategy}/node.js +13 -0
  26. package/dist/{domain/strategy → strategy}/package-context.d.ts +1 -1
  27. package/dist/{domain/strategy → strategy}/package-context.js +2 -2
  28. package/dist/{domain/strategy → strategy}/r.js +14 -0
  29. package/dist/{domain/strategy → strategy}/resolve.d.ts +2 -1
  30. package/dist/strategy/resolve.js +21 -0
  31. package/dist/{domain/strategy → strategy}/rust.js +42 -0
  32. package/dist/strategy/types.d.ts +21 -0
  33. package/dist/types/config.d.ts +4 -0
  34. package/dist/types/plugins.d.ts +7 -30
  35. package/package.json +1 -1
  36. package/dist/app/release/artifact-rules.d.ts +0 -3
  37. package/dist/app/release/verify.d.ts +0 -2
  38. package/dist/app/release/verify.js +0 -5
  39. package/dist/domain/strategy/resolve.js +0 -19
  40. package/dist/domain/strategy/types.d.ts +0 -7
  41. package/dist/infra/scm/github/plugin.d.ts +0 -1
  42. package/dist/infra/scm/github/plugin.js +0 -5
  43. package/dist/infra/scm/runtime.d.ts +0 -2
  44. package/dist/infra/scm/runtime.js +0 -7
  45. package/dist/infra/scm/types.d.ts +0 -1
  46. package/dist/plugins/runtime.d.ts +0 -1
  47. package/dist/plugins/runtime.js +0 -5
  48. package/dist/strategies/node.d.ts +0 -1
  49. package/dist/strategies/node.js +0 -5
  50. package/dist/strategies/resolve.d.ts +0 -1
  51. package/dist/strategies/resolve.js +0 -5
  52. package/dist/strategies/simple.d.ts +0 -1
  53. package/dist/strategies/simple.js +0 -5
  54. package/dist/strategies/types.d.ts +0 -1
  55. package/dist/strategies/types.js +0 -2
  56. /package/dist/{infra/git → git}/commits.js +0 -0
  57. /package/dist/{infra/git → git}/repo-url.d.ts +0 -0
  58. /package/dist/{infra/git → git}/repo-url.js +0 -0
  59. /package/dist/{app/release → release}/artifact-rules.js +0 -0
  60. /package/dist/{app/release → release}/recovery.js +0 -0
  61. /package/dist/{domain/release → release}/semver.d.ts +0 -0
  62. /package/dist/{domain/release → release}/semver.js +0 -0
  63. /package/dist/{app/release → release}/state.d.ts +0 -0
  64. /package/dist/{verify → release}/verify-project.d.ts +0 -0
  65. /package/dist/{plugins → scm}/capabilities.d.ts +0 -0
  66. /package/dist/{plugins → scm}/capabilities.js +0 -0
  67. /package/dist/{domain/strategy → scm}/types.js +0 -0
  68. /package/dist/{domain/strategy → strategy}/node.d.ts +0 -0
  69. /package/dist/{domain/strategy → strategy}/r.d.ts +0 -0
  70. /package/dist/{domain/strategy → strategy}/rust.d.ts +0 -0
  71. /package/dist/{domain/strategy → strategy}/simple.d.ts +0 -0
  72. /package/dist/{domain/strategy → strategy}/simple.js +0 -0
  73. /package/dist/{infra/scm → strategy}/types.js +0 -0
@@ -12,16 +12,13 @@ exports.isReleaseCommitMessage = isReleaseCommitMessage;
12
12
  const node_child_process_1 = require("node:child_process");
13
13
  const node_fs_1 = __importDefault(require("node:fs"));
14
14
  const node_path_1 = __importDefault(require("node:path"));
15
- const toml_1 = __importDefault(require("@iarna/toml"));
16
- const load_config_js_1 = require("../../config/load-config.js");
17
- const changelog_js_1 = require("../../domain/release/changelog.js");
18
- const plan_js_1 = require("../../domain/release/plan.js");
19
- const package_context_js_1 = require("../../domain/strategy/package-context.js");
20
- const resolve_js_1 = require("../../domain/strategy/resolve.js");
21
- const rust_js_1 = require("../../domain/strategy/rust.js");
22
- const capabilities_js_1 = require("../../plugins/capabilities.js");
23
- const runtime_js_1 = require("../../plugins/runtime.js");
15
+ const load_config_js_1 = require("../config/load-config.js");
16
+ const client_js_1 = require("../scm/client.js");
17
+ const package_context_js_1 = require("../strategy/package-context.js");
18
+ const resolve_js_1 = require("../strategy/resolve.js");
24
19
  const artifact_rules_js_1 = require("./artifact-rules.js");
20
+ const changelog_js_1 = require("./changelog.js");
21
+ const plan_js_1 = require("./plan.js");
25
22
  const state_js_1 = require("./state.js");
26
23
  const SAFE_DIRTY_FILES = new Set([
27
24
  "pnpm-lock.yaml",
@@ -133,47 +130,12 @@ function normalizeReleaseNameForTag(releaseName) {
133
130
  .replaceAll("/", "-")
134
131
  .replace(/\s+/gu, "-");
135
132
  }
136
- function readNodePackageName(versionPath) {
137
- const raw = JSON.parse(node_fs_1.default.readFileSync(versionPath, "utf8"));
138
- const name = raw.name;
139
- if (typeof name !== "string" || name.trim().length === 0) {
140
- return null;
141
- }
142
- return name.trim();
143
- }
144
- function readRustPackageName(versionPath) {
145
- const parsed = toml_1.default.parse(node_fs_1.default.readFileSync(versionPath, "utf8"));
146
- const name = parsed.package?.name;
147
- if (typeof name !== "string" || name.trim().length === 0) {
148
- return null;
149
- }
150
- return name.trim();
151
- }
152
- function readRPackageName(versionPath) {
153
- const content = node_fs_1.default.readFileSync(versionPath, "utf8");
154
- const match = content.match(/^Package:\s*(.+)\s*$/mu);
155
- if (!match?.[1]) {
156
- return null;
157
- }
158
- const name = match[1].trim();
159
- return name.length > 0 ? name : null;
160
- }
161
- function resolveReleaseName(cwd, packagePath, packageConfig, strategyName, versionFile) {
133
+ function resolveReleaseName(cwd, packagePath, packageConfig, strategy, strategyConfig) {
162
134
  const configuredName = packageConfig["package-name"]?.trim();
163
135
  if (configuredName) {
164
136
  return configuredName;
165
137
  }
166
- const versionPath = node_path_1.default.join(cwd, versionFile);
167
- if (strategyName === "node") {
168
- return readNodePackageName(versionPath) ?? packagePath;
169
- }
170
- if (strategyName === "rust") {
171
- return readRustPackageName(versionPath) ?? packagePath;
172
- }
173
- if (strategyName === "r") {
174
- return readRPackageName(versionPath) ?? packagePath;
175
- }
176
- return packagePath;
138
+ return strategy.readPackageName?.(cwd, strategyConfig) ?? packagePath;
177
139
  }
178
140
  function buildReleaseTargets(cwd, plan, loadedConfig) {
179
141
  const releaseTargets = plan.packages
@@ -189,7 +151,7 @@ function buildReleaseTargets(cwd, plan, loadedConfig) {
189
151
  }
190
152
  const packageConfig = loadedConfig.packages?.[pkg.path] ?? {};
191
153
  const packageContext = (0, package_context_js_1.resolvePackageStrategyContext)(loadedConfig, pkg.path, packageConfig);
192
- const releaseName = resolveReleaseName(cwd, pkg.path, packageConfig, packageContext.strategy.name, packageContext.versionFile);
154
+ const releaseName = resolveReleaseName(cwd, pkg.path, packageConfig, packageContext.strategy, packageContext.config);
193
155
  const tagPrefix = normalizeReleaseNameForTag(releaseName);
194
156
  return {
195
157
  path: pkg.path,
@@ -222,7 +184,7 @@ function buildPackageReleaseMetadata(cwd, plan, loadedConfig) {
222
184
  }
223
185
  const packageConfig = loadedConfig.packages?.[pkg.path] ?? {};
224
186
  const packageContext = (0, package_context_js_1.resolvePackageStrategyContext)(loadedConfig, pkg.path, packageConfig);
225
- const releaseName = resolveReleaseName(cwd, pkg.path, packageConfig, packageContext.strategy.name, packageContext.versionFile);
187
+ const releaseName = resolveReleaseName(cwd, pkg.path, packageConfig, packageContext.strategy, packageContext.config);
226
188
  metadataByPath[pkg.path] = {
227
189
  releaseName,
228
190
  tagPrefix: normalizeReleaseNameForTag(releaseName),
@@ -249,7 +211,18 @@ function prepareSimpleReleasePr(cwd = process.cwd(), options = {}) {
249
211
  }
250
212
  ensureCleanWorktree(cwd, options.logger);
251
213
  const updatedVersionFiles = [];
252
- const rustManifestVersionTargets = {};
214
+ const writesByStrategy = new Map();
215
+ const addStrategyWrite = (strategy, write) => {
216
+ const existing = writesByStrategy.get(strategy.name);
217
+ if (existing) {
218
+ existing.writes.push(write);
219
+ return;
220
+ }
221
+ writesByStrategy.set(strategy.name, {
222
+ strategy,
223
+ writes: [write],
224
+ });
225
+ };
253
226
  if (plan.packages && plan.packages.length > 0) {
254
227
  for (const packagePlan of plan.packages) {
255
228
  if (!packagePlan.nextVersion) {
@@ -259,21 +232,29 @@ function prepareSimpleReleasePr(cwd = process.cwd(), options = {}) {
259
232
  const packageContext = (0, package_context_js_1.resolvePackageStrategyContext)(loaded.config, packagePlan.path, packageConfig);
260
233
  const packageUpdated = packageContext.strategy.writeVersion(cwd, packageContext.config, packagePlan.nextVersion);
261
234
  updatedVersionFiles.push(...packageUpdated);
262
- if (packageContext.strategy.name === rust_js_1.rustVersionStrategy.name) {
263
- rustManifestVersionTargets[packageContext.versionFile] =
264
- packagePlan.nextVersion;
265
- }
235
+ addStrategyWrite(packageContext.strategy, {
236
+ packagePath: packagePlan.path,
237
+ versionFile: packageContext.versionFile,
238
+ version: packagePlan.nextVersion,
239
+ });
266
240
  }
267
- updatedVersionFiles.push(...(0, rust_js_1.applyRustWorkspaceDependencyUpdates)(cwd, rustManifestVersionTargets));
268
241
  }
269
242
  else {
270
243
  updatedVersionFiles.push(...strategy.writeVersion(cwd, loaded.config, plan.nextVersion));
244
+ addStrategyWrite(strategy, {
245
+ packagePath: ".",
246
+ versionFile: strategy.getVersionFile(loaded.config),
247
+ version: plan.nextVersion,
248
+ });
249
+ }
250
+ for (const strategyGroup of writesByStrategy.values()) {
251
+ updatedVersionFiles.push(...(strategyGroup.strategy.finalizeVersionWrites?.(cwd, strategyGroup.writes) ?? []));
271
252
  }
272
253
  const updatedArtifactFiles = (0, artifact_rules_js_1.applyConfiguredArtifactRules)(cwd, loaded.config, plan);
273
254
  const updatedRustLockFiles = ensureCargoLockUpToDate(cwd);
274
255
  const packageReleaseMetadata = buildPackageReleaseMetadata(cwd, plan, loaded.config);
275
256
  const section = (0, changelog_js_1.renderSimpleChangelog)(plan);
276
- (0, changelog_js_1.prependChangelog)(cwd, plan.changelogFile, section);
257
+ (0, changelog_js_1.prependChangelog)(cwd, plan.changelogFile, section, plan.changelogFormat);
277
258
  const updatedChangelogFiles = [plan.changelogFile];
278
259
  for (const packagePlan of plan.packages ?? []) {
279
260
  if (!packagePlan.nextVersion || packagePlan.path === ".") {
@@ -295,7 +276,7 @@ function prepareSimpleReleasePr(cwd = process.cwd(), options = {}) {
295
276
  tagPrefix: packageMetadata.tagPrefix,
296
277
  cwd,
297
278
  });
298
- (0, changelog_js_1.prependChangelog)(cwd, node_path_1.default.posix.join(packagePlan.path, packageChangelogFile), packageSection);
279
+ (0, changelog_js_1.prependChangelog)(cwd, node_path_1.default.posix.join(packagePlan.path, packageChangelogFile), packageSection, "markdown-changelog");
299
280
  updatedChangelogFiles.push(node_path_1.default.posix.join(packagePlan.path, packageChangelogFile));
300
281
  }
301
282
  const releaseTargets = buildReleaseTargets(cwd, plan, loaded.config);
@@ -342,16 +323,37 @@ function prepareSimpleReleasePr(cwd = process.cwd(), options = {}) {
342
323
  function renderSimpleReviewRequestBody(version, previousVersion, commits, plan = null, cwd = process.cwd()) {
343
324
  const rootPackageLabel = node_path_1.default.basename(cwd);
344
325
  const formatPackageLabel = (packagePath) => packagePath === "." ? rootPackageLabel : packagePath;
326
+ const isDirectBump = (pkg) => pkg.bumpReason === "direct" ||
327
+ (pkg.bumpReason === undefined &&
328
+ Boolean(pkg.nextVersion) &&
329
+ pkg.commits.length > 0);
330
+ const findPropagatedDependencies = (packagePath, packages) => {
331
+ const target = packages.find((pkg) => pkg.path === packagePath);
332
+ if (!target || target.bumpReason !== "dependency-propagation") {
333
+ return [];
334
+ }
335
+ const directSources = packages
336
+ .filter((pkg) => isDirectBump(pkg))
337
+ .map((pkg) => ({
338
+ name: formatPackageLabel(pkg.path),
339
+ version: pkg.nextVersion ?? "",
340
+ }))
341
+ .filter((dependency) => dependency.version.length > 0)
342
+ .sort((a, b) => a.name.localeCompare(b.name));
343
+ return directSources;
344
+ };
345
345
  if (plan?.packages && plan.packages.length > 1) {
346
346
  const sections = plan.packages
347
347
  .filter((pkg) => pkg.nextVersion)
348
348
  .map((pkg) => {
349
349
  const packageLabel = formatPackageLabel(pkg.path);
350
+ const propagatedDependencies = findPropagatedDependencies(pkg.path, plan.packages ?? []);
350
351
  const notes = (0, changelog_js_1.renderSimpleReleaseNotes)({
351
352
  currentVersion: pkg.currentVersion,
352
353
  nextVersion: pkg.nextVersion ?? "",
353
354
  commits: pkg.commits,
354
355
  cwd,
356
+ dependencies: propagatedDependencies,
355
357
  }, { includeFooter: false });
356
358
  const linkedHeader = notes.match(/^##\s+\[([^\]]+)\]\(([^)]+)\)\s+\(([^)]+)\)/u);
357
359
  if (linkedHeader) {
@@ -381,16 +383,8 @@ async function openOrUpdateSimpleReviewRequest(cwd, branch, title, version, prev
381
383
  if (releaseFlow === "direct") {
382
384
  return "Release flow mode is direct; skipping review request creation.";
383
385
  }
384
- const plugins = (0, runtime_js_1.loadRuntimePlugins)();
385
- const scmPlugins = (0, capabilities_js_1.findPluginsByCapability)(plugins, "scm.reviewRequest");
386
- if (scmPlugins.length === 0) {
387
- throw new Error("review-mode is pr but no scm.reviewRequest plugin is available.");
388
- }
389
- const plugin = scmPlugins[0];
390
- if (!plugin?.createOrUpdateReviewRequest) {
391
- throw new Error(`Plugin "${plugin?.name ?? "unknown"}" does not implement createOrUpdateReviewRequest.`);
392
- }
393
- const result = await plugin.createOrUpdateReviewRequest({
386
+ const scmClient = (0, client_js_1.getScmClient)();
387
+ const result = await scmClient.createOrUpdateReviewRequest({
394
388
  baseBranch: process.env.VERSIONARY_BASE_BRANCH ?? "main",
395
389
  headBranch: branch,
396
390
  title,
@@ -1,9 +1,10 @@
1
- import type { VersionaryScmReleaseMetadataResult } from "../../types/plugins.js";
1
+ import type { VersionaryScmReleaseMetadataResult } from "../types/plugins.js";
2
2
  export type TagStepResult = "created" | "exists";
3
3
  export interface ReleaseTargetInput {
4
4
  tag: string;
5
5
  version: string;
6
6
  notes: string;
7
+ draft?: boolean;
7
8
  }
8
9
  export interface ReleaseExecutionContext {
9
10
  createReleaseMetadata: (input: ReleaseTargetInput) => Promise<VersionaryScmReleaseMetadataResult>;
@@ -1,5 +1,5 @@
1
- import type { VersionaryConfig } from "../../types/config.js";
2
- import type { VersionaryPluginContext } from "../../types/plugins.js";
1
+ import type { VersionaryConfig } from "../types/config.js";
2
+ import type { VersionaryPluginContext } from "../types/plugins.js";
3
3
  export declare function resolveTargetChangelogFile(config: VersionaryConfig, rootChangelogFile: string, targetPath: string): string;
4
4
  export declare function runSimpleRelease(cwd?: string): Promise<string>;
5
5
  export type SimpleRunReleaseResult = {
@@ -9,10 +9,10 @@ exports.runSimpleReleaseDetailed = runSimpleReleaseDetailed;
9
9
  const node_child_process_1 = require("node:child_process");
10
10
  const node_fs_1 = __importDefault(require("node:fs"));
11
11
  const node_path_1 = __importDefault(require("node:path"));
12
- const load_config_js_1 = require("../../config/load-config.js");
13
- const resolve_js_1 = require("../../domain/strategy/resolve.js");
14
- const capabilities_js_1 = require("../../plugins/capabilities.js");
15
- const runtime_js_1 = require("../../plugins/runtime.js");
12
+ const load_config_js_1 = require("../config/load-config.js");
13
+ const client_js_1 = require("../scm/client.js");
14
+ const resolve_js_1 = require("../strategy/resolve.js");
15
+ const plan_js_1 = require("./plan.js");
16
16
  const pr_js_1 = require("./pr.js");
17
17
  const recovery_js_1 = require("./recovery.js");
18
18
  const state_js_1 = require("./state.js");
@@ -30,7 +30,12 @@ function readReleaseNotes(cwd, version, changelogFile) {
30
30
  }
31
31
  const content = node_fs_1.default.readFileSync(changelogPath, "utf8");
32
32
  const lines = content.split("\n");
33
- const start = lines.findIndex((line) => line.startsWith(`## ${version} -`) || line.startsWith(`## [${version}](`));
33
+ const shortVersion = version.replace(/\.\d+$/u, "");
34
+ const start = lines.findIndex((line) => line.startsWith(`## ${version} -`) ||
35
+ line.startsWith(`## [${version}](`) ||
36
+ line.startsWith(`# ${shortVersion} -`) ||
37
+ line.startsWith(`# [${shortVersion}](`) ||
38
+ new RegExp(`^#\\s+.+\\s+${shortVersion}\\s*$`, "u").test(line));
34
39
  if (start < 0) {
35
40
  return `Automated release for v${version}`;
36
41
  }
@@ -74,7 +79,7 @@ async function runSimpleReleaseDetailed(cwd = process.cwd(), options = {}) {
74
79
  }
75
80
  const loaded = (0, load_config_js_1.loadConfig)(cwd);
76
81
  const strategy = (0, resolve_js_1.resolveVersionStrategy)(loaded.config);
77
- const changelogFile = loaded.config["changelog-file"] ?? "CHANGELOG.md";
82
+ const { changelogFile } = (0, plan_js_1.getChangelogDefaults)(loaded.config);
78
83
  const version = strategy.readVersion(cwd, loaded.config);
79
84
  const defaultTag = `v${version}`;
80
85
  const releaseTargets = (0, state_js_1.readReleaseTargets)(cwd);
@@ -98,16 +103,7 @@ async function runSimpleReleaseDetailed(cwd = process.cwd(), options = {}) {
98
103
  message: `Dry run: would publish releases ${targetList.join(", ")}`,
99
104
  };
100
105
  }
101
- const plugins = (0, runtime_js_1.loadRuntimePlugins)();
102
- const scmPlugins = (0, capabilities_js_1.findPluginsByCapability)(plugins, "scm.releaseMetadata");
103
- if (scmPlugins.length === 0) {
104
- throw new Error("No scm.releaseMetadata plugin is available.");
105
- }
106
- const plugin = scmPlugins[0];
107
- if (!plugin?.createReleaseMetadata) {
108
- throw new Error(`Plugin "${plugin?.name ?? "unknown"}" does not implement createReleaseMetadata.`);
109
- }
110
- const createReleaseMetadata = plugin.createReleaseMetadata;
106
+ const scmClient = (0, client_js_1.getScmClient)();
111
107
  const releases = [];
112
108
  for (const target of targets) {
113
109
  const targetChangelogFile = resolveTargetChangelogFile(loaded.config, changelogFile, target.path);
@@ -115,8 +111,9 @@ async function runSimpleReleaseDetailed(cwd = process.cwd(), options = {}) {
115
111
  tag: target.tag,
116
112
  version: target.version,
117
113
  notes: readReleaseNotes(cwd, target.version, targetChangelogFile),
114
+ draft: loaded.config["release-draft"] ?? false,
118
115
  }, {
119
- createReleaseMetadata: (input) => createReleaseMetadata(input, {
116
+ createReleaseMetadata: (input) => scmClient.createReleaseMetadata(input, {
120
117
  cwd,
121
118
  logger: options.logger,
122
119
  }),
@@ -10,7 +10,7 @@ exports.writeBaselineSha = writeBaselineSha;
10
10
  const node_child_process_1 = require("node:child_process");
11
11
  const node_fs_1 = __importDefault(require("node:fs"));
12
12
  const node_path_1 = __importDefault(require("node:path"));
13
- const load_config_js_1 = require("../../config/load-config.js");
13
+ const load_config_js_1 = require("../config/load-config.js");
14
14
  const MANIFEST_VERSION_KEY = "manifest-version";
15
15
  const BASELINE_SHA_KEY = "baseline-sha";
16
16
  const RELEASE_TARGETS_KEY = "release-targets";
@@ -7,8 +7,8 @@ exports.verifyProject = verifyProject;
7
7
  const node_fs_1 = __importDefault(require("node:fs"));
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
9
  const load_config_js_1 = require("../config/load-config.js");
10
- const package_context_js_1 = require("../domain/strategy/package-context.js");
11
- const resolve_js_1 = require("../domain/strategy/resolve.js");
10
+ const package_context_js_1 = require("../strategy/package-context.js");
11
+ const resolve_js_1 = require("../strategy/resolve.js");
12
12
  function verifyProject(cwd = process.cwd()) {
13
13
  const checks = [];
14
14
  const config = (0, load_config_js_1.loadConfig)(cwd);
@@ -0,0 +1,2 @@
1
+ import type { ScmClient } from "./types.js";
2
+ export declare function getScmClient(): ScmClient;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getScmClient = getScmClient;
4
+ const github_plugin_js_1 = require("./github-plugin.js");
5
+ function getScmClient() {
6
+ return (0, github_plugin_js_1.createGitHubPlugin)();
7
+ }
@@ -1,2 +1,3 @@
1
1
  import type { VersionaryPluginRuntime } from "../types/plugins.js";
2
- export declare function createGitHubPlugin(): VersionaryPluginRuntime;
2
+ import type { ScmClient } from "./types.js";
3
+ export declare function createGitHubPlugin(): VersionaryPluginRuntime & ScmClient;
@@ -90,6 +90,7 @@ function createGitHubPlugin() {
90
90
  return {
91
91
  name: "github",
92
92
  capabilities: ["scm.reviewRequest", "scm.releaseMetadata"],
93
+ provider: "github",
93
94
  async createOrUpdateReviewRequest(input, _context) {
94
95
  const repo = getRepoFromEnv();
95
96
  const octokit = new rest_1.Octokit({ auth: getGitHubToken() });
@@ -194,6 +195,7 @@ function createGitHubPlugin() {
194
195
  tag_name: input.tag,
195
196
  name: input.tag,
196
197
  body: input.notes,
198
+ draft: input.draft ?? false,
197
199
  });
198
200
  data = response.data;
199
201
  }
@@ -0,0 +1,37 @@
1
+ export type ScmProvider = "github";
2
+ export interface ScmClientContext {
3
+ cwd: string;
4
+ logger?: {
5
+ info: (message: string) => void;
6
+ warn: (message: string) => void;
7
+ error: (message: string) => void;
8
+ };
9
+ }
10
+ export interface ScmReviewRequestInput {
11
+ baseBranch: string;
12
+ headBranch: string;
13
+ title: string;
14
+ body: string;
15
+ labels?: string[];
16
+ }
17
+ export interface ScmReviewRequestResult {
18
+ id: string;
19
+ number?: number;
20
+ url: string;
21
+ state: "open" | "closed" | "merged";
22
+ }
23
+ export interface ScmReleaseMetadataInput {
24
+ tag: string;
25
+ version: string;
26
+ notes: string;
27
+ draft?: boolean;
28
+ }
29
+ export interface ScmReleaseMetadataResult {
30
+ url: string;
31
+ status?: "created" | "exists";
32
+ }
33
+ export interface ScmClient {
34
+ provider: ScmProvider;
35
+ createOrUpdateReviewRequest: (input: ScmReviewRequestInput, context: ScmClientContext) => Promise<ScmReviewRequestResult>;
36
+ createReleaseMetadata: (input: ScmReleaseMetadataInput, context: ScmClientContext) => Promise<ScmReleaseMetadataResult>;
37
+ }
@@ -64,4 +64,17 @@ exports.nodeVersionStrategy = {
64
64
  ];
65
65
  return updatedFiles;
66
66
  },
67
+ readPackageName(cwd, config) {
68
+ const versionFile = this.getVersionFile(config);
69
+ const versionPath = node_path_1.default.join(cwd, versionFile);
70
+ if (!node_fs_1.default.existsSync(versionPath)) {
71
+ throw new Error(`Versionary requires ${versionFile} to exist.`);
72
+ }
73
+ const packageJson = readJsonFile(versionPath);
74
+ const name = packageJson.name;
75
+ if (typeof name !== "string" || name.trim().length === 0) {
76
+ return null;
77
+ }
78
+ return name.trim();
79
+ },
67
80
  };
@@ -1,4 +1,4 @@
1
- import type { VersionaryConfig, VersionaryPackage } from "../../types/config.js";
1
+ import type { VersionaryConfig, VersionaryPackage } from "../types/config.js";
2
2
  import type { VersionStrategy } from "./types.js";
3
3
  export declare function resolvePackageStrategyContext(rootConfig: VersionaryConfig, packagePath: string, packageConfig: VersionaryPackage): {
4
4
  strategy: VersionStrategy;
@@ -34,7 +34,7 @@ function resolvePackageStrategyContext(rootConfig, packagePath, packageConfig) {
34
34
  }));
35
35
  const config = withVersionFile({
36
36
  ...baseConfig,
37
- packages: undefined,
37
+ packages: packagePath === "." ? baseConfig.packages : undefined,
38
38
  }, versionFile);
39
39
  return {
40
40
  strategy: baseStrategy,
@@ -50,7 +50,7 @@ function resolvePackageStrategyContext(rootConfig, packagePath, packageConfig) {
50
50
  }));
51
51
  const config = withVersionFile({
52
52
  ...baseConfig,
53
- packages: undefined,
53
+ packages: packagePath === "." ? baseConfig.packages : undefined,
54
54
  }, packageVersionFile);
55
55
  const strategy = (0, resolve_js_1.resolveVersionStrategy)(config);
56
56
  return {
@@ -43,4 +43,18 @@ exports.rVersionStrategy = {
43
43
  node_fs_1.default.writeFileSync(versionPath, updated, "utf8");
44
44
  return [versionFile];
45
45
  },
46
+ readPackageName(cwd, config) {
47
+ const versionFile = this.getVersionFile(config);
48
+ const versionPath = node_path_1.default.join(cwd, versionFile);
49
+ if (!node_fs_1.default.existsSync(versionPath)) {
50
+ throw new Error(`Versionary requires ${versionFile} to exist.`);
51
+ }
52
+ const content = node_fs_1.default.readFileSync(versionPath, "utf8");
53
+ const match = content.match(/^Package:\s*(.+)\s*$/mu);
54
+ if (!match?.[1]) {
55
+ return null;
56
+ }
57
+ const name = match[1].trim();
58
+ return name.length > 0 ? name : null;
59
+ },
46
60
  };
@@ -1,3 +1,4 @@
1
- import type { VersionaryConfig } from "../../types/config.js";
1
+ import type { VersionaryConfig } from "../types/config.js";
2
2
  import type { VersionStrategy } from "./types.js";
3
+ export declare function listKnownReleaseTypes(): string[];
3
4
  export declare function resolveVersionStrategy(config: VersionaryConfig): VersionStrategy;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listKnownReleaseTypes = listKnownReleaseTypes;
4
+ exports.resolveVersionStrategy = resolveVersionStrategy;
5
+ const node_js_1 = require("./node.js");
6
+ const r_js_1 = require("./r.js");
7
+ const rust_js_1 = require("./rust.js");
8
+ const simple_js_1 = require("./simple.js");
9
+ const strategyRegistry = {
10
+ simple: simple_js_1.simpleVersionStrategy,
11
+ node: node_js_1.nodeVersionStrategy,
12
+ rust: rust_js_1.rustVersionStrategy,
13
+ r: r_js_1.rVersionStrategy,
14
+ };
15
+ function listKnownReleaseTypes() {
16
+ return Object.keys(strategyRegistry).sort((a, b) => a.localeCompare(b));
17
+ }
18
+ function resolveVersionStrategy(config) {
19
+ const releaseType = config["release-type"] ?? "simple";
20
+ return strategyRegistry[releaseType] ?? simple_js_1.simpleVersionStrategy;
21
+ }
@@ -613,4 +613,46 @@ exports.rustVersionStrategy = {
613
613
  }
614
614
  return updatedFiles.sort((a, b) => a.localeCompare(b));
615
615
  },
616
+ readPackageName(cwd, config) {
617
+ const versionFile = this.getVersionFile(config);
618
+ const manifests = collectRustTargetManifests(cwd, versionFile, !config.packages);
619
+ const selectedManifest = manifests[0];
620
+ if (!selectedManifest) {
621
+ throw new Error(`Configured rust target "${versionFile}" did not resolve to a Rust crate manifest.`);
622
+ }
623
+ const versionPath = node_path_1.default.join(cwd, selectedManifest);
624
+ if (!node_fs_1.default.existsSync(versionPath)) {
625
+ throw new Error(`Versionary requires ${selectedManifest} to exist.`);
626
+ }
627
+ const cargoTomlRaw = node_fs_1.default.readFileSync(versionPath, "utf8");
628
+ if (!isCrateManifest(selectedManifest, cargoTomlRaw)) {
629
+ return null;
630
+ }
631
+ return readCargoPackageName(cargoTomlRaw, selectedManifest);
632
+ },
633
+ propagateDependentPatchImpacts(cwd, packages) {
634
+ const manifestToVersion = {};
635
+ const candidateManifests = [];
636
+ const manifestToPath = new Map();
637
+ for (const pkg of packages) {
638
+ const manifest = pkg.versionFile;
639
+ candidateManifests.push(manifest);
640
+ manifestToPath.set(manifest, pkg.packagePath);
641
+ if (pkg.nextVersion) {
642
+ manifestToVersion[manifest] = pkg.nextVersion;
643
+ }
644
+ }
645
+ const impactedManifests = detectRustDependencyImpact(cwd, manifestToVersion, candidateManifests);
646
+ return impactedManifests
647
+ .map((manifest) => manifestToPath.get(manifest))
648
+ .filter((pkgPath) => Boolean(pkgPath))
649
+ .sort((a, b) => a.localeCompare(b));
650
+ },
651
+ finalizeVersionWrites(cwd, writes) {
652
+ const manifestToVersion = {};
653
+ for (const write of writes) {
654
+ manifestToVersion[write.versionFile] = write.version;
655
+ }
656
+ return applyRustWorkspaceDependencyUpdates(cwd, manifestToVersion);
657
+ },
616
658
  };
@@ -0,0 +1,21 @@
1
+ import type { VersionaryConfig } from "../types/config.js";
2
+ export interface StrategyPackagePlanContext {
3
+ packagePath: string;
4
+ versionFile: string;
5
+ currentVersion: string;
6
+ nextVersion: string | null;
7
+ }
8
+ export interface StrategyVersionWriteContext {
9
+ packagePath: string;
10
+ versionFile: string;
11
+ version: string;
12
+ }
13
+ export interface VersionStrategy {
14
+ name: string;
15
+ getVersionFile(config: VersionaryConfig): string;
16
+ readVersion(cwd: string, config: VersionaryConfig): string;
17
+ writeVersion(cwd: string, config: VersionaryConfig, version: string): string[];
18
+ readPackageName?(cwd: string, config: VersionaryConfig): string | null;
19
+ propagateDependentPatchImpacts?(cwd: string, packages: StrategyPackagePlanContext[]): string[];
20
+ finalizeVersionWrites?(cwd: string, writes: StrategyVersionWriteContext[]): string[];
21
+ }
@@ -1,4 +1,5 @@
1
1
  export type ConfigFileFormat = "jsonc" | "json" | "toml" | "js";
2
+ export type VersionaryChangelogFormat = "markdown-changelog" | "r-news";
2
3
  export interface VersionaryArtifactRule {
3
4
  type: "json" | "toml" | "yaml" | "regex";
4
5
  path: string;
@@ -10,6 +11,7 @@ export interface VersionaryPackage {
10
11
  "release-type"?: string;
11
12
  "package-name"?: string;
12
13
  "changelog-file"?: string;
14
+ "changelog-format"?: VersionaryChangelogFormat;
13
15
  "exclude-paths"?: string[];
14
16
  "extra-files"?: VersionaryArtifactRule[];
15
17
  }
@@ -18,6 +20,8 @@ export interface VersionaryConfig {
18
20
  "review-mode"?: "direct" | "pr" | "review";
19
21
  "version-file"?: string;
20
22
  "changelog-file"?: string;
23
+ "changelog-format"?: VersionaryChangelogFormat;
24
+ "release-draft"?: boolean;
21
25
  "release-branch"?: string;
22
26
  "baseline-file"?: string;
23
27
  "bootstrap-sha"?: string;
@@ -1,37 +1,14 @@
1
+ import type { ScmClientContext, ScmProvider, ScmReleaseMetadataInput, ScmReleaseMetadataResult, ScmReviewRequestInput, ScmReviewRequestResult } from "../scm/types.js";
1
2
  export type VersionaryPluginCapability = "scm.reviewRequest" | "scm.releaseMetadata";
2
- export interface VersionaryScmReviewRequestInput {
3
- baseBranch: string;
4
- headBranch: string;
5
- title: string;
6
- body: string;
7
- labels?: string[];
8
- }
9
- export interface VersionaryScmReviewRequestResult {
10
- id: string;
11
- number?: number;
12
- url: string;
13
- state: "open" | "closed" | "merged";
14
- }
15
- export interface VersionaryScmReleaseMetadataInput {
16
- tag: string;
17
- version: string;
18
- notes: string;
19
- }
20
- export interface VersionaryScmReleaseMetadataResult {
21
- url: string;
22
- status?: "created" | "exists";
23
- }
24
- export interface VersionaryPluginContext {
25
- cwd: string;
26
- logger?: {
27
- info: (message: string) => void;
28
- warn: (message: string) => void;
29
- error: (message: string) => void;
30
- };
31
- }
3
+ export type VersionaryScmReviewRequestInput = ScmReviewRequestInput;
4
+ export type VersionaryScmReviewRequestResult = ScmReviewRequestResult;
5
+ export type VersionaryScmReleaseMetadataInput = ScmReleaseMetadataInput;
6
+ export type VersionaryScmReleaseMetadataResult = ScmReleaseMetadataResult;
7
+ export type VersionaryPluginContext = ScmClientContext;
32
8
  export interface VersionaryPluginRuntime {
33
9
  name: string;
34
10
  capabilities: VersionaryPluginCapability[];
11
+ provider?: ScmProvider;
35
12
  createOrUpdateReviewRequest?: (input: VersionaryScmReviewRequestInput, context: VersionaryPluginContext) => Promise<VersionaryScmReviewRequestResult>;
36
13
  createReleaseMetadata?: (input: VersionaryScmReleaseMetadataInput, context: VersionaryPluginContext) => Promise<VersionaryScmReleaseMetadataResult>;
37
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "versionary",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "Automatic release framework based on conventional commits and semantic versioning",
5
5
  "keywords": [
6
6
  "releasing",
@@ -1,3 +0,0 @@
1
- import type { SimplePlan } from "../../domain/release/plan.js";
2
- import type { VersionaryConfig } from "../../types/config.js";
3
- export declare function applyConfiguredArtifactRules(cwd: string, config: VersionaryConfig, plan: SimplePlan): string[];
@@ -1,2 +0,0 @@
1
- export type { VerifyResult } from "../../verify/verify-project.js";
2
- export { verifyProject } from "../../verify/verify-project.js";