versionary 0.11.1 → 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 +48 -18
  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
package/README.md CHANGED
@@ -52,7 +52,7 @@ Current implementation focuses on:
52
52
  - strategy-based version updates (`simple`, `node`, `rust`, `r`)
53
53
  - release planning and changelog generation
54
54
  - review-mode vs direct-mode release flow
55
- - built-in GitHub SCM plugin capabilities
55
+ - a static internal SCM client (`github` provider today)
56
56
 
57
57
  Planned/harder areas include deeper monorepo ergonomics, broader SCM coverage,
58
58
  and stronger failure recovery around release steps.
@@ -61,8 +61,8 @@ and stronger failure recovery around release steps.
61
61
 
62
62
  Versionary is set up so new language strategies can be added internally without
63
63
  changing release orchestration. A new strategy should implement the
64
- `VersionStrategy` contract in `src/domain/strategy/types.ts` and be wired in
65
- `src/domain/strategy/resolve.ts`.
64
+ `VersionStrategy` contract in `src/strategy/types.ts` and be wired in
65
+ `src/strategy/resolve.ts`.
66
66
 
67
67
  Checklist for new strategies (for example `python`):
68
68
 
@@ -71,8 +71,13 @@ Checklist for new strategies (for example `python`):
71
71
  - implement `readVersion(cwd, config)` with explicit malformed-file errors
72
72
  - implement `writeVersion(cwd, config, version)` returning deterministic updated
73
73
  file paths
74
- - add release-name extraction support if package tags should derive from
75
- language metadata (similar to Node/Rust/R)
74
+ - optionally implement `readPackageName(cwd, config)` so monorepo release tags
75
+ can derive from language metadata (similar to Node/Rust/R)
76
+ - optionally implement `propagateDependentPatchImpacts(cwd, packages)` if
77
+ dependency updates in this ecosystem should trigger dependent package patch
78
+ bumps
79
+ - optionally implement `finalizeVersionWrites(cwd, writes)` for ecosystem
80
+ post-processing after all target version files are written
76
81
  - add focused strategy tests for ecosystem-specific behavior and edge cases
77
82
  - add/extend strategy contract tests in `tests/strategy-contract.test.ts`
78
83
  - update schema/docs for new `release-type` behavior and defaults
@@ -91,16 +96,19 @@ Current ecosystem policy defaults:
91
96
  - Rust supports `version.workspace = true` via `[workspace.package].version`
92
97
  - other strategies should document equivalent inheritance behavior explicitly
93
98
 
94
- ## Architecture layout (current migration)
99
+ ## Architecture layout (canonical)
95
100
 
96
- The repository is moving to explicit layered modules:
101
+ Current runtime code uses a flat `src/` layout with clear module boundaries:
97
102
 
98
- - `src/app/`: command-level application services and orchestration boundaries
99
- - `src/domain/`: release and strategy domain logic/contracts
100
- - `src/infra/`: platform integrations (SCM, git/runtime adapters)
101
-
102
- Legacy `src/simple/` has been removed. Remaining compatibility paths are
103
- `src/strategies` and `src/scm` while migration is finalized.
103
+ - `src/cli/`: command router (`run`, `verify`, `plan`, `changelog`, `pr`, `release`)
104
+ - `src/release/`: release orchestration (plan/changelog/PR/release/state/recovery)
105
+ - `src/strategy/`: strategy contracts, resolver, and built-in implementations
106
+ (`simple`, `node`, `rust`, `r`)
107
+ - `src/scm/`: SCM client contracts and provider implementation(s)
108
+ - `src/config/`: config loading and schema validation
109
+ - `src/git/`: git commit/range and repository URL helpers
110
+ - `src/verify/`: repository/config verification
111
+ - `src/types/`: shared config/plugin-facing types
104
112
 
105
113
  Configuration is loaded from `versionary.jsonc` by default (or
106
114
  `versionary.json`).
@@ -132,6 +140,8 @@ For a quick trial, use:
132
140
  auto-transition to `1.0.0` on a breaking release
133
141
  - review mode (`review-mode`): `pr` (PR/MR style) or `direct` (no review
134
142
  request)
143
+ - `release-draft` (default `false`) publishes GitHub releases as drafts when
144
+ enabled
135
145
  - optional monorepo planning with `monorepo-mode` and `packages`:
136
146
  - `independent` computes package bumps per path
137
147
  - `fixed` computes one shared bump across configured package paths
@@ -229,8 +239,8 @@ Commands:
229
239
  - `pnpm pr`
230
240
  - `pnpm release`
231
241
 
232
- `pnpm pr` prepares release commit + branch and opens/updates the review request
233
- via SCM plugin capability. `pnpm run` is the recommended CI entrypoint and
242
+ `pnpm pr` prepares release commit + branch and opens/updates a review request
243
+ through the SCM client. `pnpm run` is the recommended CI entrypoint and
234
244
  auto-dispatches between PR/update and release publish.
235
245
 
236
246
  For first-run bootstrapping, set `bootstrap-sha` (similar to release-please).
@@ -251,15 +261,21 @@ Versionary fails fast when recovery is unsafe (for example, local and remote
251
261
  tags with the same name point to different SHAs). In these cases, the error
252
262
  message includes remediation guidance so CI logs are actionable.
253
263
 
254
- ## Built-in plugins
264
+ ## SCM API model
265
+
266
+ Versionary currently uses a static internal SCM client model:
255
267
 
256
- Versionary ships with built-in SCM plugin support:
268
+ - `src/scm/types.ts` defines the `ScmClient` contract
269
+ - `src/scm/client.ts` returns the active provider client
270
+ - current provider is `github` via `src/scm/github-plugin.ts`
257
271
 
258
- - `github` (default): review request + release metadata
272
+ There is no runtime discovery/loading of external SCM providers in the release
273
+ flow. Adding another provider is an internal extension: implement `ScmClient`
274
+ and wire provider selection in `src/scm/client.ts`.
259
275
 
260
276
  ### GitHub integration: env, permissions, and flow
261
277
 
262
- Required environment for the built-in GitHub plugin:
278
+ Required environment for the GitHub SCM provider:
263
279
 
264
280
  - `GITHUB_REPOSITORY` (format: `owner/repo`)
265
281
  - one token env var: `VERSIONARY_PR_TOKEN` or `GH_TOKEN` or `GITHUB_TOKEN`
package/dist/cli/index.js CHANGED
@@ -1,19 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
- };
6
3
  Object.defineProperty(exports, "__esModule", { value: true });
7
4
  const node_child_process_1 = require("node:child_process");
8
- const node_fs_1 = __importDefault(require("node:fs"));
9
- const node_path_1 = __importDefault(require("node:path"));
10
- const pr_js_1 = require("../app/release/pr.js");
11
- const release_js_1 = require("../app/release/release.js");
12
- const verify_js_1 = require("../app/release/verify.js");
13
- const changelog_js_1 = require("../domain/release/changelog.js");
14
- const plan_js_1 = require("../domain/release/plan.js");
5
+ const changelog_js_1 = require("../release/changelog.js");
6
+ const plan_js_1 = require("../release/plan.js");
7
+ const pr_js_1 = require("../release/pr.js");
8
+ const release_js_1 = require("../release/release.js");
9
+ const verify_project_js_1 = require("../release/verify-project.js");
15
10
  function printVerifyResult() {
16
- const result = (0, verify_js_1.verifyProject)();
11
+ const result = (0, verify_project_js_1.verifyProject)();
17
12
  const categories = [
18
13
  { key: "config", title: "Config" },
19
14
  { key: "paths", title: "Paths" },
@@ -186,13 +181,7 @@ async function main() {
186
181
  console.log(section);
187
182
  return 0;
188
183
  }
189
- const changelogPath = node_path_1.default.join(process.cwd(), plan.changelogFile);
190
- const existing = node_fs_1.default.existsSync(changelogPath)
191
- ? node_fs_1.default.readFileSync(changelogPath, "utf8")
192
- : "";
193
- const heading = "# Changelog\n\n";
194
- const body = existing.replace(/^# Changelog\s*/u, "");
195
- node_fs_1.default.writeFileSync(changelogPath, `${`${heading}${section}\n${body}`.trimEnd()}\n`, "utf8");
184
+ (0, changelog_js_1.prependChangelog)(process.cwd(), plan.changelogFile, section, plan.changelogFormat);
196
185
  console.log(`Updated ${plan.changelogFile}`);
197
186
  return 0;
198
187
  }
@@ -9,6 +9,11 @@ export declare const configSchema: z.ZodObject<{
9
9
  }>>;
10
10
  "version-file": z.ZodOptional<z.ZodString>;
11
11
  "changelog-file": z.ZodOptional<z.ZodString>;
12
+ "changelog-format": z.ZodOptional<z.ZodEnum<{
13
+ "markdown-changelog": "markdown-changelog";
14
+ "r-news": "r-news";
15
+ }>>;
16
+ "release-draft": z.ZodOptional<z.ZodBoolean>;
12
17
  "release-branch": z.ZodOptional<z.ZodString>;
13
18
  "baseline-file": z.ZodOptional<z.ZodString>;
14
19
  "bootstrap-sha": z.ZodOptional<z.ZodString>;
@@ -24,6 +29,10 @@ export declare const configSchema: z.ZodObject<{
24
29
  "release-type": z.ZodOptional<z.ZodString>;
25
30
  "package-name": z.ZodOptional<z.ZodString>;
26
31
  "changelog-file": z.ZodOptional<z.ZodString>;
32
+ "changelog-format": z.ZodOptional<z.ZodEnum<{
33
+ "markdown-changelog": "markdown-changelog";
34
+ "r-news": "r-news";
35
+ }>>;
27
36
  "exclude-paths": z.ZodOptional<z.ZodArray<z.ZodString>>;
28
37
  "extra-files": z.ZodOptional<z.ZodArray<z.ZodObject<{
29
38
  type: z.ZodEnum<{
@@ -54,6 +54,7 @@ const packageSchema = zod_1.z
54
54
  "release-type": zod_1.z.string().optional(),
55
55
  "package-name": zod_1.z.string().optional(),
56
56
  "changelog-file": zod_1.z.string().optional(),
57
+ "changelog-format": zod_1.z.enum(["markdown-changelog", "r-news"]).optional(),
57
58
  "exclude-paths": zod_1.z.array(zod_1.z.string()).optional(),
58
59
  "extra-files": zod_1.z.array(artifactRuleSchema).optional(),
59
60
  })
@@ -65,6 +66,8 @@ exports.configSchema = zod_1.z
65
66
  "review-mode": zod_1.z.enum(["direct", "pr", "review"]).optional(),
66
67
  "version-file": zod_1.z.string().optional(),
67
68
  "changelog-file": zod_1.z.string().optional(),
69
+ "changelog-format": zod_1.z.enum(["markdown-changelog", "r-news"]).optional(),
70
+ "release-draft": zod_1.z.boolean().optional(),
68
71
  "release-branch": zod_1.z.string().optional(),
69
72
  "baseline-file": zod_1.z.string().optional(),
70
73
  "bootstrap-sha": zod_1.z.string().optional(),
@@ -1,4 +1,4 @@
1
- import type { ReleaseType } from "../../domain/release/semver.js";
1
+ import type { ReleaseType } from "../release/semver.js";
2
2
  export interface CommitInfo {
3
3
  hash: string;
4
4
  subject: string;
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  export { loadConfig } from "./config/load-config.js";
2
- export { resolveVersionStrategy } from "./domain/strategy/resolve.js";
3
- export { createGitHubPlugin } from "./infra/scm/github/plugin.js";
4
- export { findPluginsByCapability, pluginHasCapability, } from "./plugins/capabilities.js";
5
- export { loadRuntimePlugins } from "./plugins/runtime.js";
2
+ export { verifyProject } from "./release/verify-project.js";
3
+ export { findPluginsByCapability, pluginHasCapability, } from "./scm/capabilities.js";
4
+ export { getScmClient } from "./scm/client.js";
5
+ export { createGitHubPlugin } from "./scm/github-plugin.js";
6
+ export type { ScmClient, ScmClientContext, ScmProvider, ScmReleaseMetadataInput, ScmReleaseMetadataResult, ScmReviewRequestInput, ScmReviewRequestResult, } from "./scm/types.js";
7
+ export { resolveVersionStrategy } from "./strategy/resolve.js";
6
8
  export type { VersionaryArtifactRule, VersionaryConfig, VersionaryPackage, } from "./types/config.js";
7
9
  export type { VersionaryPluginCapability, VersionaryPluginContext, VersionaryPluginRuntime, VersionaryScmReleaseMetadataInput, VersionaryScmReleaseMetadataResult, VersionaryScmReviewRequestInput, VersionaryScmReviewRequestResult, } from "./types/plugins.js";
8
- export { verifyProject } from "./verify/verify-project.js";
package/dist/index.js CHANGED
@@ -1,16 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.verifyProject = exports.loadRuntimePlugins = exports.pluginHasCapability = exports.findPluginsByCapability = exports.createGitHubPlugin = exports.resolveVersionStrategy = exports.loadConfig = void 0;
3
+ exports.resolveVersionStrategy = exports.createGitHubPlugin = exports.getScmClient = exports.pluginHasCapability = exports.findPluginsByCapability = exports.verifyProject = exports.loadConfig = void 0;
4
4
  var load_config_js_1 = require("./config/load-config.js");
5
5
  Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return load_config_js_1.loadConfig; } });
6
- var resolve_js_1 = require("./domain/strategy/resolve.js");
7
- Object.defineProperty(exports, "resolveVersionStrategy", { enumerable: true, get: function () { return resolve_js_1.resolveVersionStrategy; } });
8
- var plugin_js_1 = require("./infra/scm/github/plugin.js");
9
- Object.defineProperty(exports, "createGitHubPlugin", { enumerable: true, get: function () { return plugin_js_1.createGitHubPlugin; } });
10
- var capabilities_js_1 = require("./plugins/capabilities.js");
6
+ var verify_project_js_1 = require("./release/verify-project.js");
7
+ Object.defineProperty(exports, "verifyProject", { enumerable: true, get: function () { return verify_project_js_1.verifyProject; } });
8
+ var capabilities_js_1 = require("./scm/capabilities.js");
11
9
  Object.defineProperty(exports, "findPluginsByCapability", { enumerable: true, get: function () { return capabilities_js_1.findPluginsByCapability; } });
12
10
  Object.defineProperty(exports, "pluginHasCapability", { enumerable: true, get: function () { return capabilities_js_1.pluginHasCapability; } });
13
- var runtime_js_1 = require("./plugins/runtime.js");
14
- Object.defineProperty(exports, "loadRuntimePlugins", { enumerable: true, get: function () { return runtime_js_1.loadRuntimePlugins; } });
15
- var verify_project_js_1 = require("./verify/verify-project.js");
16
- Object.defineProperty(exports, "verifyProject", { enumerable: true, get: function () { return verify_project_js_1.verifyProject; } });
11
+ var client_js_1 = require("./scm/client.js");
12
+ Object.defineProperty(exports, "getScmClient", { enumerable: true, get: function () { return client_js_1.getScmClient; } });
13
+ var github_plugin_js_1 = require("./scm/github-plugin.js");
14
+ Object.defineProperty(exports, "createGitHubPlugin", { enumerable: true, get: function () { return github_plugin_js_1.createGitHubPlugin; } });
15
+ var resolve_js_1 = require("./strategy/resolve.js");
16
+ Object.defineProperty(exports, "resolveVersionStrategy", { enumerable: true, get: function () { return resolve_js_1.resolveVersionStrategy; } });
@@ -0,0 +1,3 @@
1
+ import type { VersionaryConfig } from "../types/config.js";
2
+ import type { SimplePlan } from "./plan.js";
3
+ export declare function applyConfiguredArtifactRules(cwd: string, config: VersionaryConfig, plan: SimplePlan): string[];
@@ -1,10 +1,15 @@
1
- import { type ParsedCommit } from "../../infra/git/commits.js";
1
+ import { type ParsedCommit } from "../git/commits.js";
2
+ import type { VersionaryChangelogFormat } from "../types/config.js";
2
3
  import type { SimplePlan } from "./plan.js";
3
4
  export declare function renderSimpleReleaseNotes(input: {
4
5
  currentVersion: string;
5
6
  nextVersion: string;
6
7
  commits: ParsedCommit[];
7
8
  cwd?: string;
9
+ dependencies?: Array<{
10
+ name: string;
11
+ version: string;
12
+ }>;
8
13
  }, options?: {
9
14
  includeFooter?: boolean;
10
15
  }): string;
@@ -16,4 +21,10 @@ export declare function renderPackageChangelogSection(input: {
16
21
  tagPrefix: string;
17
22
  cwd?: string;
18
23
  }): string;
19
- export declare function prependChangelog(cwd: string, changelogFile: string, section: string): void;
24
+ export declare function prependChangelog(cwd: string, changelogFile: string, section: string, format?: VersionaryChangelogFormat): void;
25
+ export declare function renderRNewsReleaseNotes(input: {
26
+ packageName: string;
27
+ nextVersion: string;
28
+ commits: ParsedCommit[];
29
+ cwd?: string;
30
+ }): string;
@@ -7,10 +7,11 @@ exports.renderSimpleReleaseNotes = renderSimpleReleaseNotes;
7
7
  exports.renderSimpleChangelog = renderSimpleChangelog;
8
8
  exports.renderPackageChangelogSection = renderPackageChangelogSection;
9
9
  exports.prependChangelog = prependChangelog;
10
+ exports.renderRNewsReleaseNotes = renderRNewsReleaseNotes;
10
11
  const node_fs_1 = __importDefault(require("node:fs"));
11
12
  const node_path_1 = __importDefault(require("node:path"));
12
- const commits_js_1 = require("../../infra/git/commits.js");
13
- const repo_url_js_1 = require("../../infra/git/repo-url.js");
13
+ const commits_js_1 = require("../git/commits.js");
14
+ const repo_url_js_1 = require("../git/repo-url.js");
14
15
  function formatDate() {
15
16
  return new Date().toISOString().slice(0, 10);
16
17
  }
@@ -102,6 +103,9 @@ function renderSimpleReleaseNotes(input, options = {}) {
102
103
  if (grouped.reverts.length > 0) {
103
104
  sections.push("### Reverts", ...grouped.reverts, "");
104
105
  }
106
+ if (input.dependencies && input.dependencies.length > 0) {
107
+ sections.push("### Dependencies", ...input.dependencies.map((dependency) => `- updated ${dependency.name} to v${dependency.version}`), "");
108
+ }
105
109
  const lines = [header, "", ...sections];
106
110
  if (options.includeFooter) {
107
111
  lines.push("\n---\n\nThis PR was generated by [Versionary](https://github.com/jolars/versionary).");
@@ -112,11 +116,33 @@ function renderSimpleChangelog(plan) {
112
116
  if (!plan.nextVersion) {
113
117
  return "";
114
118
  }
119
+ const propagatedRootPackage = plan.packages?.find((pkg) => pkg.path === "." && pkg.bumpReason === "dependency-propagation");
120
+ const isDirectBump = (pkg) => pkg.bumpReason === "direct" ||
121
+ (pkg.bumpReason === undefined &&
122
+ Boolean(pkg.nextVersion) &&
123
+ pkg.commits.length > 0);
124
+ const dependencies = propagatedRootPackage && plan.packages
125
+ ? plan.packages
126
+ .filter((pkg) => pkg.path !== "." && isDirectBump(pkg) && pkg.nextVersion)
127
+ .map((pkg) => ({
128
+ name: pkg.path,
129
+ version: pkg.nextVersion,
130
+ }))
131
+ : [];
132
+ if (plan.changelogFormat === "r-news") {
133
+ return renderRNewsReleaseNotes({
134
+ packageName: plan.packageName,
135
+ nextVersion: plan.nextVersion,
136
+ commits: plan.commits,
137
+ cwd: process.cwd(),
138
+ });
139
+ }
115
140
  return renderSimpleReleaseNotes({
116
141
  currentVersion: plan.currentVersion,
117
142
  nextVersion: plan.nextVersion,
118
143
  commits: plan.commits,
119
144
  cwd: process.cwd(),
145
+ dependencies,
120
146
  });
121
147
  }
122
148
  function renderPackageChangelogSection(input) {
@@ -140,14 +166,41 @@ function renderPackageChangelogSection(input) {
140
166
  }
141
167
  return [header, "", ...sections].join("\n");
142
168
  }
143
- function prependChangelog(cwd, changelogFile, section) {
169
+ function prependChangelog(cwd, changelogFile, section, format = "markdown-changelog") {
144
170
  const changelogPath = node_path_1.default.join(cwd, changelogFile);
145
171
  const existing = node_fs_1.default.existsSync(changelogPath)
146
172
  ? node_fs_1.default.readFileSync(changelogPath, "utf8")
147
173
  : "";
148
- const heading = existing.startsWith("# Changelog") ? "" : "# Changelog\n\n";
174
+ if (format === "r-news") {
175
+ const separator = existing.length > 0 ? "\n\n" : "";
176
+ const next = `${section}${separator}${existing}`.trimEnd() + "\n";
177
+ node_fs_1.default.writeFileSync(changelogPath, next, "utf8");
178
+ return;
179
+ }
180
+ const heading = "# Changelog\n\n";
181
+ const bodyWithoutHeading = existing.replace(/^# Changelog\s*/u, "");
149
182
  const separator = existing.length > 0 ? "\n" : "";
150
- const next = `${heading}${section}${separator}${existing.replace(/^# Changelog\s*/u, "")}`.trimEnd() +
151
- "\n";
183
+ const next = `${heading}${section}${separator}${bodyWithoutHeading}`.trimEnd() + "\n";
152
184
  node_fs_1.default.writeFileSync(changelogPath, next, "utf8");
153
185
  }
186
+ function renderRNewsReleaseNotes(input) {
187
+ const repoUrl = (0, repo_url_js_1.resolveRepositoryWebBaseUrl)(input.cwd ?? process.cwd());
188
+ const grouped = groupCommitLines(input.commits, repoUrl);
189
+ const normalizedVersion = input.nextVersion.replace(/\.\d+$/u, "");
190
+ const sections = [];
191
+ if (grouped.breaking.length > 0) {
192
+ sections.push("## Breaking changes", "", ...grouped.breaking, "");
193
+ }
194
+ if (grouped.features.length > 0) {
195
+ sections.push("## Features", "", ...grouped.features, "");
196
+ }
197
+ if (grouped.fixes.length > 0) {
198
+ sections.push("## Bug fixes", "", ...grouped.fixes, "");
199
+ }
200
+ if (grouped.reverts.length > 0) {
201
+ sections.push("## Reverts", "", ...grouped.reverts, "");
202
+ }
203
+ return [`# ${input.packageName} ${normalizedVersion}`, "", ...sections]
204
+ .join("\n")
205
+ .trimEnd();
206
+ }
@@ -1,12 +1,15 @@
1
- import { type ParsedCommit } from "../../infra/git/commits.js";
1
+ import { type ParsedCommit } from "../git/commits.js";
2
+ import type { VersionaryChangelogFormat, VersionaryConfig } from "../types/config.js";
2
3
  import { type ReleaseType } from "./semver.js";
3
4
  export interface SimplePlan {
4
5
  mode: "simple";
5
6
  releaseType: ReleaseType;
6
7
  currentVersion: string;
7
8
  nextVersion: string | null;
9
+ packageName: string;
8
10
  versionFile: string;
9
11
  changelogFile: string;
12
+ changelogFormat: VersionaryChangelogFormat;
10
13
  releaseBranchPrefix: string;
11
14
  baselineSha: string | null;
12
15
  commits: ParsedCommit[];
@@ -15,7 +18,16 @@ export interface SimplePlan {
15
18
  releaseType: ReleaseType;
16
19
  currentVersion: string;
17
20
  nextVersion: string | null;
21
+ bumpReason?: "direct" | "dependency-propagation";
18
22
  commits: ParsedCommit[];
19
23
  }>;
20
24
  }
25
+ export declare function getChangelogDefaults(config: {
26
+ "release-type"?: VersionaryConfig["release-type"];
27
+ "changelog-file"?: VersionaryConfig["changelog-file"];
28
+ "changelog-format"?: VersionaryConfig["changelog-format"];
29
+ }): {
30
+ changelogFile: string;
31
+ changelogFormat: VersionaryChangelogFormat;
32
+ };
21
33
  export declare function createSimplePlan(cwd?: string): SimplePlan;
@@ -3,24 +3,34 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getChangelogDefaults = getChangelogDefaults;
6
7
  exports.createSimplePlan = createSimplePlan;
7
8
  const node_fs_1 = __importDefault(require("node:fs"));
8
9
  const node_path_1 = __importDefault(require("node:path"));
9
- const state_js_1 = require("../../app/release/state.js");
10
- const load_config_js_1 = require("../../config/load-config.js");
11
- const commits_js_1 = require("../../infra/git/commits.js");
10
+ const load_config_js_1 = require("../config/load-config.js");
11
+ const commits_js_1 = require("../git/commits.js");
12
12
  const package_context_js_1 = require("../strategy/package-context.js");
13
13
  const resolve_js_1 = require("../strategy/resolve.js");
14
- const rust_js_1 = require("../strategy/rust.js");
15
14
  const semver_js_1 = require("./semver.js");
15
+ const state_js_1 = require("./state.js");
16
16
  function getMode(configMode) {
17
17
  return configMode ?? "independent";
18
18
  }
19
+ function getChangelogDefaults(config) {
20
+ const changelogFormat = config["changelog-format"] ??
21
+ (config["release-type"] === "r" ? "r-news" : "markdown-changelog");
22
+ const changelogFile = config["changelog-file"] ??
23
+ (changelogFormat === "r-news" ? "NEWS.md" : "CHANGELOG.md");
24
+ return { changelogFile, changelogFormat };
25
+ }
19
26
  function createSimplePlan(cwd = process.cwd()) {
20
27
  const loaded = (0, load_config_js_1.loadConfig)(cwd);
21
28
  const strategy = (0, resolve_js_1.resolveVersionStrategy)(loaded.config);
22
29
  const versionFile = strategy.getVersionFile(loaded.config);
23
- const changelogFile = loaded.config["changelog-file"] ?? "CHANGELOG.md";
30
+ const { changelogFile, changelogFormat } = getChangelogDefaults(loaded.config);
31
+ const packageName = loaded.config["release-type"] === "r"
32
+ ? (strategy.readPackageName?.(cwd, loaded.config) ?? node_path_1.default.basename(cwd))
33
+ : node_path_1.default.basename(cwd);
24
34
  const releaseBranchPrefix = loaded.config["release-branch"] ?? "versionary/release";
25
35
  const baselineSha = (0, state_js_1.readBaselineSha)(cwd) ?? loaded.config["bootstrap-sha"] ?? null;
26
36
  const releaseTargetByPath = new Map((0, state_js_1.readReleaseTargets)(cwd).map((target) => [target.path, target]));
@@ -49,8 +59,10 @@ function createSimplePlan(cwd = process.cwd()) {
49
59
  releaseType,
50
60
  currentVersion,
51
61
  nextVersion,
62
+ packageName,
52
63
  versionFile,
53
64
  changelogFile,
65
+ changelogFormat,
54
66
  releaseBranchPrefix,
55
67
  baselineSha,
56
68
  commits,
@@ -72,32 +84,45 @@ function createSimplePlan(cwd = process.cwd()) {
72
84
  releaseType,
73
85
  currentVersion: packageCurrentVersion,
74
86
  nextVersion,
87
+ bumpReason: nextVersion ? "direct" : undefined,
75
88
  commits,
76
89
  parsedCommits,
77
90
  };
78
91
  })
79
92
  .sort((a, b) => a.path.localeCompare(b.path));
80
- const rustManifestVersionTargets = {};
81
- const rustPackageManifestByPath = {};
82
93
  const packageCurrentVersionByPath = {};
94
+ const strategyPackagesByName = new Map();
83
95
  for (const packagePlan of packagePlans) {
84
96
  const packageConfig = loaded.config.packages?.[packagePlan.path] ?? {};
85
97
  const packageContext = (0, package_context_js_1.resolvePackageStrategyContext)(loaded.config, packagePlan.path, packageConfig);
86
- if (packageContext.strategy.name === rust_js_1.rustVersionStrategy.name) {
87
- rustPackageManifestByPath[packagePlan.path] = (0, rust_js_1.toCargoManifestPath)(packagePlan.path);
98
+ const existingGroup = strategyPackagesByName.get(packageContext.strategy.name);
99
+ if (existingGroup) {
100
+ existingGroup.packages.push({
101
+ packagePath: packagePlan.path,
102
+ versionFile: packageContext.versionFile,
103
+ currentVersion: packagePlan.currentVersion,
104
+ nextVersion: packagePlan.nextVersion,
105
+ });
88
106
  }
89
- packageCurrentVersionByPath[packagePlan.path] = packagePlan.currentVersion;
90
- if (packageContext.strategy.name === rust_js_1.rustVersionStrategy.name) {
91
- const next = packagePlan.nextVersion;
92
- if (next) {
93
- rustManifestVersionTargets[packageContext.versionFile] = next;
94
- }
107
+ else {
108
+ strategyPackagesByName.set(packageContext.strategy.name, {
109
+ strategy: packageContext.strategy,
110
+ packages: [
111
+ {
112
+ packagePath: packagePlan.path,
113
+ versionFile: packageContext.versionFile,
114
+ currentVersion: packagePlan.currentVersion,
115
+ nextVersion: packagePlan.nextVersion,
116
+ },
117
+ ],
118
+ });
95
119
  }
120
+ packageCurrentVersionByPath[packagePlan.path] = packagePlan.currentVersion;
96
121
  }
97
- const impactedRustManifests = (0, rust_js_1.detectRustDependencyImpact)(cwd, rustManifestVersionTargets, Object.values(rustPackageManifestByPath));
98
122
  const impactedPaths = new Set();
99
- for (const [pkgPath, manifest] of Object.entries(rustPackageManifestByPath)) {
100
- if (impactedRustManifests.includes(manifest)) {
123
+ for (const strategyGroup of strategyPackagesByName.values()) {
124
+ const impacted = strategyGroup.strategy.propagateDependentPatchImpacts?.(cwd, strategyGroup.packages);
125
+ for (const pkgPath of impacted ?? []) {
101
126
  impactedPaths.add(pkgPath);
102
127
  }
103
128
  }
@@ -110,6 +135,7 @@ function createSimplePlan(cwd = process.cwd()) {
110
135
  ...pkgPlan,
111
136
  releaseType: "patch",
112
137
  nextVersion: (0, semver_js_1.bumpVersion)(current, "patch", { allowStableMajor }),
138
+ bumpReason: "dependency-propagation",
113
139
  };
114
140
  });
115
141
  if (monorepoMode === "fixed") {
@@ -131,8 +157,10 @@ function createSimplePlan(cwd = process.cwd()) {
131
157
  releaseType: fixedType,
132
158
  currentVersion: fixedBaseVersion,
133
159
  nextVersion: fixedNextVersion,
160
+ packageName,
134
161
  versionFile,
135
162
  changelogFile,
163
+ changelogFormat,
136
164
  releaseBranchPrefix,
137
165
  baselineSha,
138
166
  commits: adjusted.flatMap((pkgPlan) => pkgPlan.commits),
@@ -151,8 +179,10 @@ function createSimplePlan(cwd = process.cwd()) {
151
179
  releaseType: overallType,
152
180
  currentVersion: overallBaseVersion,
153
181
  nextVersion: overallNextVersion,
182
+ packageName,
154
183
  versionFile,
155
184
  changelogFile,
185
+ changelogFormat,
156
186
  releaseBranchPrefix,
157
187
  baselineSha,
158
188
  commits: adjustedPackages.flatMap((pkgPlan) => pkgPlan.commits),
@@ -1,6 +1,6 @@
1
- import { type SimplePlan } from "../../domain/release/plan.js";
2
- import type { ParsedCommit } from "../../infra/git/commits.js";
3
- import type { VersionaryPluginContext } from "../../types/plugins.js";
1
+ import type { ParsedCommit } from "../git/commits.js";
2
+ import type { VersionaryPluginContext } from "../types/plugins.js";
3
+ import { type SimplePlan } from "./plan.js";
4
4
  export declare function splitSafeDirtyFiles(files: string[]): {
5
5
  ignored: string[];
6
6
  blocking: string[];