versionary 0.11.1 → 0.13.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 (75) hide show
  1. package/README.md +39 -21
  2. package/dist/cli/index.js +22 -33
  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/release/changelog.d.ts +32 -0
  10. package/dist/{domain/release → release}/changelog.js +66 -7
  11. package/dist/release/plan.d.ts +37 -0
  12. package/dist/{domain/release → release}/plan.js +54 -19
  13. package/dist/{app/release → release}/pr.d.ts +13 -5
  14. package/dist/{app/release → release}/pr.js +109 -91
  15. package/dist/{app/release → release}/recovery.d.ts +2 -1
  16. package/dist/{app/release → release}/release.d.ts +14 -5
  17. package/dist/{app/release → release}/release.js +80 -40
  18. package/dist/{domain/release → release}/semver.js +14 -3
  19. package/dist/{app/release → release}/state.js +1 -1
  20. package/dist/{verify → release}/verify-project.js +2 -2
  21. package/dist/scm/client.d.ts +2 -0
  22. package/dist/scm/client.js +7 -0
  23. package/dist/scm/github-plugin.d.ts +2 -1
  24. package/dist/scm/github-plugin.js +2 -0
  25. package/dist/scm/types.d.ts +37 -0
  26. package/dist/{domain/strategy → strategy}/node.js +13 -0
  27. package/dist/{domain/strategy → strategy}/package-context.d.ts +1 -1
  28. package/dist/{domain/strategy → strategy}/package-context.js +2 -2
  29. package/dist/{domain/strategy → strategy}/r.js +14 -0
  30. package/dist/{domain/strategy → strategy}/resolve.d.ts +2 -1
  31. package/dist/strategy/resolve.js +21 -0
  32. package/dist/{domain/strategy → strategy}/rust.js +42 -0
  33. package/dist/strategy/types.d.ts +21 -0
  34. package/dist/types/config.d.ts +4 -0
  35. package/dist/types/plugins.d.ts +7 -30
  36. package/package.json +1 -1
  37. package/dist/app/release/artifact-rules.d.ts +0 -3
  38. package/dist/app/release/verify.d.ts +0 -2
  39. package/dist/app/release/verify.js +0 -5
  40. package/dist/domain/release/changelog.d.ts +0 -19
  41. package/dist/domain/release/plan.d.ts +0 -21
  42. package/dist/domain/strategy/resolve.js +0 -19
  43. package/dist/domain/strategy/types.d.ts +0 -7
  44. package/dist/infra/scm/github/plugin.d.ts +0 -1
  45. package/dist/infra/scm/github/plugin.js +0 -5
  46. package/dist/infra/scm/runtime.d.ts +0 -2
  47. package/dist/infra/scm/runtime.js +0 -7
  48. package/dist/infra/scm/types.d.ts +0 -1
  49. package/dist/plugins/runtime.d.ts +0 -1
  50. package/dist/plugins/runtime.js +0 -5
  51. package/dist/strategies/node.d.ts +0 -1
  52. package/dist/strategies/node.js +0 -5
  53. package/dist/strategies/resolve.d.ts +0 -1
  54. package/dist/strategies/resolve.js +0 -5
  55. package/dist/strategies/simple.d.ts +0 -1
  56. package/dist/strategies/simple.js +0 -5
  57. package/dist/strategies/types.d.ts +0 -1
  58. package/dist/strategies/types.js +0 -2
  59. /package/dist/{infra/git → git}/commits.js +0 -0
  60. /package/dist/{infra/git → git}/repo-url.d.ts +0 -0
  61. /package/dist/{infra/git → git}/repo-url.js +0 -0
  62. /package/dist/{app/release → release}/artifact-rules.js +0 -0
  63. /package/dist/{app/release → release}/recovery.js +0 -0
  64. /package/dist/{domain/release → release}/semver.d.ts +0 -0
  65. /package/dist/{app/release → release}/state.d.ts +0 -0
  66. /package/dist/{verify → release}/verify-project.d.ts +0 -0
  67. /package/dist/{plugins → scm}/capabilities.d.ts +0 -0
  68. /package/dist/{plugins → scm}/capabilities.js +0 -0
  69. /package/dist/{domain/strategy → scm}/types.js +0 -0
  70. /package/dist/{domain/strategy → strategy}/node.d.ts +0 -0
  71. /package/dist/{domain/strategy → strategy}/r.d.ts +0 -0
  72. /package/dist/{domain/strategy → strategy}/rust.d.ts +0 -0
  73. /package/dist/{domain/strategy → strategy}/simple.d.ts +0 -0
  74. /package/dist/{domain/strategy → strategy}/simple.js +0 -0
  75. /package/dist/{infra/scm → strategy}/types.js +0 -0
@@ -3,24 +3,35 @@ 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;
7
+ exports.createReleasePlan = createReleasePlan;
6
8
  exports.createSimplePlan = createSimplePlan;
7
9
  const node_fs_1 = __importDefault(require("node:fs"));
8
10
  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");
11
+ const load_config_js_1 = require("../config/load-config.js");
12
+ const commits_js_1 = require("../git/commits.js");
12
13
  const package_context_js_1 = require("../strategy/package-context.js");
13
14
  const resolve_js_1 = require("../strategy/resolve.js");
14
- const rust_js_1 = require("../strategy/rust.js");
15
15
  const semver_js_1 = require("./semver.js");
16
+ const state_js_1 = require("./state.js");
16
17
  function getMode(configMode) {
17
18
  return configMode ?? "independent";
18
19
  }
19
- function createSimplePlan(cwd = process.cwd()) {
20
+ function getChangelogDefaults(config) {
21
+ const changelogFormat = config["changelog-format"] ??
22
+ (config["release-type"] === "r" ? "r-news" : "markdown-changelog");
23
+ const changelogFile = config["changelog-file"] ??
24
+ (changelogFormat === "r-news" ? "NEWS.md" : "CHANGELOG.md");
25
+ return { changelogFile, changelogFormat };
26
+ }
27
+ function createReleasePlan(cwd = process.cwd()) {
20
28
  const loaded = (0, load_config_js_1.loadConfig)(cwd);
21
29
  const strategy = (0, resolve_js_1.resolveVersionStrategy)(loaded.config);
22
30
  const versionFile = strategy.getVersionFile(loaded.config);
23
- const changelogFile = loaded.config["changelog-file"] ?? "CHANGELOG.md";
31
+ const { changelogFile, changelogFormat } = getChangelogDefaults(loaded.config);
32
+ const packageName = loaded.config["release-type"] === "r"
33
+ ? (strategy.readPackageName?.(cwd, loaded.config) ?? node_path_1.default.basename(cwd))
34
+ : node_path_1.default.basename(cwd);
24
35
  const releaseBranchPrefix = loaded.config["release-branch"] ?? "versionary/release";
25
36
  const baselineSha = (0, state_js_1.readBaselineSha)(cwd) ?? loaded.config["bootstrap-sha"] ?? null;
26
37
  const releaseTargetByPath = new Map((0, state_js_1.readReleaseTargets)(cwd).map((target) => [target.path, target]));
@@ -49,8 +60,10 @@ function createSimplePlan(cwd = process.cwd()) {
49
60
  releaseType,
50
61
  currentVersion,
51
62
  nextVersion,
63
+ packageName,
52
64
  versionFile,
53
65
  changelogFile,
66
+ changelogFormat,
54
67
  releaseBranchPrefix,
55
68
  baselineSha,
56
69
  commits,
@@ -72,32 +85,45 @@ function createSimplePlan(cwd = process.cwd()) {
72
85
  releaseType,
73
86
  currentVersion: packageCurrentVersion,
74
87
  nextVersion,
88
+ bumpReason: nextVersion ? "direct" : undefined,
75
89
  commits,
76
90
  parsedCommits,
77
91
  };
78
92
  })
79
93
  .sort((a, b) => a.path.localeCompare(b.path));
80
- const rustManifestVersionTargets = {};
81
- const rustPackageManifestByPath = {};
82
94
  const packageCurrentVersionByPath = {};
95
+ const strategyPackagesByName = new Map();
83
96
  for (const packagePlan of packagePlans) {
84
97
  const packageConfig = loaded.config.packages?.[packagePlan.path] ?? {};
85
98
  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);
99
+ const existingGroup = strategyPackagesByName.get(packageContext.strategy.name);
100
+ if (existingGroup) {
101
+ existingGroup.packages.push({
102
+ packagePath: packagePlan.path,
103
+ versionFile: packageContext.versionFile,
104
+ currentVersion: packagePlan.currentVersion,
105
+ nextVersion: packagePlan.nextVersion,
106
+ });
88
107
  }
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
- }
108
+ else {
109
+ strategyPackagesByName.set(packageContext.strategy.name, {
110
+ strategy: packageContext.strategy,
111
+ packages: [
112
+ {
113
+ packagePath: packagePlan.path,
114
+ versionFile: packageContext.versionFile,
115
+ currentVersion: packagePlan.currentVersion,
116
+ nextVersion: packagePlan.nextVersion,
117
+ },
118
+ ],
119
+ });
95
120
  }
121
+ packageCurrentVersionByPath[packagePlan.path] = packagePlan.currentVersion;
96
122
  }
97
- const impactedRustManifests = (0, rust_js_1.detectRustDependencyImpact)(cwd, rustManifestVersionTargets, Object.values(rustPackageManifestByPath));
98
123
  const impactedPaths = new Set();
99
- for (const [pkgPath, manifest] of Object.entries(rustPackageManifestByPath)) {
100
- if (impactedRustManifests.includes(manifest)) {
124
+ for (const strategyGroup of strategyPackagesByName.values()) {
125
+ const impacted = strategyGroup.strategy.propagateDependentPatchImpacts?.(cwd, strategyGroup.packages);
126
+ for (const pkgPath of impacted ?? []) {
101
127
  impactedPaths.add(pkgPath);
102
128
  }
103
129
  }
@@ -110,6 +136,7 @@ function createSimplePlan(cwd = process.cwd()) {
110
136
  ...pkgPlan,
111
137
  releaseType: "patch",
112
138
  nextVersion: (0, semver_js_1.bumpVersion)(current, "patch", { allowStableMajor }),
139
+ bumpReason: "dependency-propagation",
113
140
  };
114
141
  });
115
142
  if (monorepoMode === "fixed") {
@@ -131,8 +158,10 @@ function createSimplePlan(cwd = process.cwd()) {
131
158
  releaseType: fixedType,
132
159
  currentVersion: fixedBaseVersion,
133
160
  nextVersion: fixedNextVersion,
161
+ packageName,
134
162
  versionFile,
135
163
  changelogFile,
164
+ changelogFormat,
136
165
  releaseBranchPrefix,
137
166
  baselineSha,
138
167
  commits: adjusted.flatMap((pkgPlan) => pkgPlan.commits),
@@ -151,11 +180,17 @@ function createSimplePlan(cwd = process.cwd()) {
151
180
  releaseType: overallType,
152
181
  currentVersion: overallBaseVersion,
153
182
  nextVersion: overallNextVersion,
183
+ packageName,
154
184
  versionFile,
155
185
  changelogFile,
186
+ changelogFormat,
156
187
  releaseBranchPrefix,
157
188
  baselineSha,
158
189
  commits: adjustedPackages.flatMap((pkgPlan) => pkgPlan.commits),
159
190
  packages: adjustedPackages,
160
191
  };
161
192
  }
193
+ /** @deprecated Use createReleasePlan. */
194
+ function createSimplePlan(cwd = process.cwd()) {
195
+ return createReleasePlan(cwd);
196
+ }
@@ -1,11 +1,11 @@
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 ReleasePlan, type SimplePlan } from "./plan.js";
4
4
  export declare function splitSafeDirtyFiles(files: string[]): {
5
5
  ignored: string[];
6
6
  blocking: string[];
7
7
  };
8
- export declare function prepareSimpleReleasePr(cwd?: string, options?: {
8
+ export declare function prepareReleasePr(cwd?: string, options?: {
9
9
  logger?: VersionaryPluginContext["logger"];
10
10
  }): {
11
11
  branch: string;
@@ -13,9 +13,17 @@ export declare function prepareSimpleReleasePr(cwd?: string, options?: {
13
13
  version: string;
14
14
  previousVersion: string;
15
15
  commits: ParsedCommit[];
16
- plan: SimplePlan;
16
+ plan: ReleasePlan;
17
17
  };
18
18
  export declare function renderSimpleReviewRequestBody(version: string, previousVersion: string, commits: ParsedCommit[], plan?: SimplePlan | null, cwd?: string): string;
19
+ export declare function openOrUpdateReviewRequest(cwd: string, branch: string, title: string, version: string, previousVersion: string, commits: ParsedCommit[], plan?: SimplePlan | null, options?: {
20
+ logger?: VersionaryPluginContext["logger"];
21
+ }): Promise<string>;
22
+ /** @deprecated Use prepareReleasePr. */
23
+ export declare function prepareSimpleReleasePr(cwd?: string, options?: {
24
+ logger?: VersionaryPluginContext["logger"];
25
+ }): ReturnType<typeof prepareReleasePr>;
26
+ /** @deprecated Use openOrUpdateReviewRequest. */
19
27
  export declare function openOrUpdateSimpleReviewRequest(cwd: string, branch: string, title: string, version: string, previousVersion: string, commits: ParsedCommit[], plan?: SimplePlan | null, options?: {
20
28
  logger?: VersionaryPluginContext["logger"];
21
29
  }): Promise<string>;
@@ -4,24 +4,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.splitSafeDirtyFiles = splitSafeDirtyFiles;
7
- exports.prepareSimpleReleasePr = prepareSimpleReleasePr;
7
+ exports.prepareReleasePr = prepareReleasePr;
8
8
  exports.renderSimpleReviewRequestBody = renderSimpleReviewRequestBody;
9
+ exports.openOrUpdateReviewRequest = openOrUpdateReviewRequest;
10
+ exports.prepareSimpleReleasePr = prepareSimpleReleasePr;
9
11
  exports.openOrUpdateSimpleReviewRequest = openOrUpdateSimpleReviewRequest;
10
12
  exports.pushReleaseBranch = pushReleaseBranch;
11
13
  exports.isReleaseCommitMessage = isReleaseCommitMessage;
12
14
  const node_child_process_1 = require("node:child_process");
13
15
  const node_fs_1 = __importDefault(require("node:fs"));
14
16
  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");
17
+ const load_config_js_1 = require("../config/load-config.js");
18
+ const client_js_1 = require("../scm/client.js");
19
+ const package_context_js_1 = require("../strategy/package-context.js");
20
+ const resolve_js_1 = require("../strategy/resolve.js");
24
21
  const artifact_rules_js_1 = require("./artifact-rules.js");
22
+ const changelog_js_1 = require("./changelog.js");
23
+ const plan_js_1 = require("./plan.js");
25
24
  const state_js_1 = require("./state.js");
26
25
  const SAFE_DIRTY_FILES = new Set([
27
26
  "pnpm-lock.yaml",
@@ -133,47 +132,12 @@ function normalizeReleaseNameForTag(releaseName) {
133
132
  .replaceAll("/", "-")
134
133
  .replace(/\s+/gu, "-");
135
134
  }
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) {
135
+ function resolveReleaseName(cwd, packagePath, packageConfig, strategy, strategyConfig) {
162
136
  const configuredName = packageConfig["package-name"]?.trim();
163
137
  if (configuredName) {
164
138
  return configuredName;
165
139
  }
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;
140
+ return strategy.readPackageName?.(cwd, strategyConfig) ?? packagePath;
177
141
  }
178
142
  function buildReleaseTargets(cwd, plan, loadedConfig) {
179
143
  const releaseTargets = plan.packages
@@ -189,7 +153,7 @@ function buildReleaseTargets(cwd, plan, loadedConfig) {
189
153
  }
190
154
  const packageConfig = loadedConfig.packages?.[pkg.path] ?? {};
191
155
  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);
156
+ const releaseName = resolveReleaseName(cwd, pkg.path, packageConfig, packageContext.strategy, packageContext.config);
193
157
  const tagPrefix = normalizeReleaseNameForTag(releaseName);
194
158
  return {
195
159
  path: pkg.path,
@@ -222,7 +186,7 @@ function buildPackageReleaseMetadata(cwd, plan, loadedConfig) {
222
186
  }
223
187
  const packageConfig = loadedConfig.packages?.[pkg.path] ?? {};
224
188
  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);
189
+ const releaseName = resolveReleaseName(cwd, pkg.path, packageConfig, packageContext.strategy, packageContext.config);
226
190
  metadataByPath[pkg.path] = {
227
191
  releaseName,
228
192
  tagPrefix: normalizeReleaseNameForTag(releaseName),
@@ -240,8 +204,8 @@ function formatReleaseCommitTitle(releaseTargets) {
240
204
  }
241
205
  return `chore(release): ${tags[0]} (+${tags.length - 1} more)`;
242
206
  }
243
- function prepareSimpleReleasePr(cwd = process.cwd(), options = {}) {
244
- const plan = (0, plan_js_1.createSimplePlan)(cwd);
207
+ function prepareReleasePr(cwd = process.cwd(), options = {}) {
208
+ const plan = (0, plan_js_1.createReleasePlan)(cwd);
245
209
  const loaded = (0, load_config_js_1.loadConfig)(cwd);
246
210
  const strategy = (0, resolve_js_1.resolveVersionStrategy)(loaded.config);
247
211
  if (!plan.nextVersion) {
@@ -249,7 +213,18 @@ function prepareSimpleReleasePr(cwd = process.cwd(), options = {}) {
249
213
  }
250
214
  ensureCleanWorktree(cwd, options.logger);
251
215
  const updatedVersionFiles = [];
252
- const rustManifestVersionTargets = {};
216
+ const writesByStrategy = new Map();
217
+ const addStrategyWrite = (strategy, write) => {
218
+ const existing = writesByStrategy.get(strategy.name);
219
+ if (existing) {
220
+ existing.writes.push(write);
221
+ return;
222
+ }
223
+ writesByStrategy.set(strategy.name, {
224
+ strategy,
225
+ writes: [write],
226
+ });
227
+ };
253
228
  if (plan.packages && plan.packages.length > 0) {
254
229
  for (const packagePlan of plan.packages) {
255
230
  if (!packagePlan.nextVersion) {
@@ -259,31 +234,40 @@ function prepareSimpleReleasePr(cwd = process.cwd(), options = {}) {
259
234
  const packageContext = (0, package_context_js_1.resolvePackageStrategyContext)(loaded.config, packagePlan.path, packageConfig);
260
235
  const packageUpdated = packageContext.strategy.writeVersion(cwd, packageContext.config, packagePlan.nextVersion);
261
236
  updatedVersionFiles.push(...packageUpdated);
262
- if (packageContext.strategy.name === rust_js_1.rustVersionStrategy.name) {
263
- rustManifestVersionTargets[packageContext.versionFile] =
264
- packagePlan.nextVersion;
265
- }
237
+ addStrategyWrite(packageContext.strategy, {
238
+ packagePath: packagePlan.path,
239
+ versionFile: packageContext.versionFile,
240
+ version: packagePlan.nextVersion,
241
+ });
266
242
  }
267
- updatedVersionFiles.push(...(0, rust_js_1.applyRustWorkspaceDependencyUpdates)(cwd, rustManifestVersionTargets));
268
243
  }
269
244
  else {
270
245
  updatedVersionFiles.push(...strategy.writeVersion(cwd, loaded.config, plan.nextVersion));
246
+ addStrategyWrite(strategy, {
247
+ packagePath: ".",
248
+ versionFile: strategy.getVersionFile(loaded.config),
249
+ version: plan.nextVersion,
250
+ });
251
+ }
252
+ for (const strategyGroup of writesByStrategy.values()) {
253
+ updatedVersionFiles.push(...(strategyGroup.strategy.finalizeVersionWrites?.(cwd, strategyGroup.writes) ?? []));
271
254
  }
272
255
  const updatedArtifactFiles = (0, artifact_rules_js_1.applyConfiguredArtifactRules)(cwd, loaded.config, plan);
273
256
  const updatedRustLockFiles = ensureCargoLockUpToDate(cwd);
274
257
  const packageReleaseMetadata = buildPackageReleaseMetadata(cwd, plan, loaded.config);
275
- const section = (0, changelog_js_1.renderSimpleChangelog)(plan);
276
- (0, changelog_js_1.prependChangelog)(cwd, plan.changelogFile, section);
258
+ const section = (0, changelog_js_1.renderReleasePlanChangelog)(plan);
259
+ (0, changelog_js_1.prependChangelog)(cwd, plan.changelogFile, section, plan.changelogFormat);
277
260
  const updatedChangelogFiles = [plan.changelogFile];
278
261
  for (const packagePlan of plan.packages ?? []) {
279
262
  if (!packagePlan.nextVersion || packagePlan.path === ".") {
280
263
  continue;
281
264
  }
282
265
  const packageConfig = loaded.config.packages?.[packagePlan.path] ?? {};
283
- const packageChangelogFile = packageConfig["changelog-file"];
284
- if (!packageChangelogFile) {
285
- continue;
286
- }
266
+ const { changelogFile: packageChangelogFile } = (0, plan_js_1.getChangelogDefaults)({
267
+ "release-type": packageConfig["release-type"] ?? loaded.config["release-type"],
268
+ "changelog-file": packageConfig["changelog-file"] ?? loaded.config["changelog-file"],
269
+ "changelog-format": packageConfig["changelog-format"] ?? loaded.config["changelog-format"],
270
+ });
287
271
  const packageMetadata = packageReleaseMetadata[packagePlan.path];
288
272
  if (!packageMetadata) {
289
273
  continue;
@@ -295,7 +279,7 @@ function prepareSimpleReleasePr(cwd = process.cwd(), options = {}) {
295
279
  tagPrefix: packageMetadata.tagPrefix,
296
280
  cwd,
297
281
  });
298
- (0, changelog_js_1.prependChangelog)(cwd, node_path_1.default.posix.join(packagePlan.path, packageChangelogFile), packageSection);
282
+ (0, changelog_js_1.prependChangelog)(cwd, node_path_1.default.posix.join(packagePlan.path, packageChangelogFile), packageSection, "markdown-changelog");
299
283
  updatedChangelogFiles.push(node_path_1.default.posix.join(packagePlan.path, packageChangelogFile));
300
284
  }
301
285
  const releaseTargets = buildReleaseTargets(cwd, plan, loaded.config);
@@ -342,31 +326,65 @@ function prepareSimpleReleasePr(cwd = process.cwd(), options = {}) {
342
326
  function renderSimpleReviewRequestBody(version, previousVersion, commits, plan = null, cwd = process.cwd()) {
343
327
  const rootPackageLabel = node_path_1.default.basename(cwd);
344
328
  const formatPackageLabel = (packagePath) => packagePath === "." ? rootPackageLabel : packagePath;
329
+ const isDirectBump = (pkg) => pkg.bumpReason === "direct" ||
330
+ (pkg.bumpReason === undefined &&
331
+ Boolean(pkg.nextVersion) &&
332
+ pkg.commits.length > 0);
333
+ const findPropagatedDependencies = (packagePath, packages) => {
334
+ const target = packages.find((pkg) => pkg.path === packagePath);
335
+ if (!target || target.bumpReason !== "dependency-propagation") {
336
+ return [];
337
+ }
338
+ const directSources = packages
339
+ .filter((pkg) => isDirectBump(pkg))
340
+ .map((pkg) => ({
341
+ name: formatPackageLabel(pkg.path),
342
+ version: pkg.nextVersion ?? "",
343
+ }))
344
+ .filter((dependency) => dependency.version.length > 0)
345
+ .sort((a, b) => a.name.localeCompare(b.name));
346
+ return directSources;
347
+ };
348
+ const relabelSectionHeader = (notes, packageLabel, nextVersion) => {
349
+ const linkedHeader = notes.match(/^##\s+\[([^\]]+)\]\(([^)]+)\)\s+\(([^)]+)\)/u);
350
+ if (linkedHeader) {
351
+ const [, , compareUrl, date] = linkedHeader;
352
+ return notes.replace(/^##\s+\[[^\]]+\]\([^)]+\)\s+\([^)]+\)/u, `## [${packageLabel}: ${nextVersion}](${compareUrl}) (${date})`);
353
+ }
354
+ const plainHeader = notes.match(/^##\s+([^\s]+)\s+\(([^)]+)\)/u);
355
+ if (plainHeader) {
356
+ const [, , date] = plainHeader;
357
+ return notes.replace(/^##\s+[^\s]+\s+\([^)]+\)/u, `## ${packageLabel}: ${nextVersion} (${date})`);
358
+ }
359
+ return notes;
360
+ };
345
361
  if (plan?.packages && plan.packages.length > 1) {
346
- const sections = plan.packages
347
- .filter((pkg) => pkg.nextVersion)
362
+ const sections = [];
363
+ const rootPackage = plan.packages.find((pkg) => pkg.path === "." && pkg.nextVersion);
364
+ if (rootPackage?.nextVersion) {
365
+ const rootNotes = (0, changelog_js_1.renderReleasePlanChangelog)(plan);
366
+ sections.push(relabelSectionHeader(rootNotes, formatPackageLabel("."), rootPackage.nextVersion));
367
+ }
368
+ const packageSections = plan.packages
369
+ .filter((pkg) => pkg.path !== "." && pkg.nextVersion)
348
370
  .map((pkg) => {
349
371
  const packageLabel = formatPackageLabel(pkg.path);
372
+ const propagatedDependencies = findPropagatedDependencies(pkg.path, plan.packages ?? []);
350
373
  const notes = (0, changelog_js_1.renderSimpleReleaseNotes)({
351
374
  currentVersion: pkg.currentVersion,
352
375
  nextVersion: pkg.nextVersion ?? "",
353
376
  commits: pkg.commits,
354
377
  cwd,
378
+ dependencies: propagatedDependencies,
355
379
  }, { includeFooter: false });
356
- const linkedHeader = notes.match(/^##\s+\[([^\]]+)\]\(([^)]+)\)\s+\(([^)]+)\)/u);
357
- if (linkedHeader) {
358
- const [, , compareUrl, date] = linkedHeader;
359
- return notes.replace(/^##\s+\[[^\]]+\]\([^)]+\)\s+\([^)]+\)/u, `## [${packageLabel}: ${pkg.nextVersion ?? ""}](${compareUrl}) (${date})`);
360
- }
361
- const plainHeader = notes.match(/^##\s+([^\s]+)\s+\(([^)]+)\)/u);
362
- if (plainHeader) {
363
- const [, , date] = plainHeader;
364
- return notes.replace(/^##\s+[^\s]+\s+\([^)]+\)/u, `## ${packageLabel}: ${pkg.nextVersion ?? ""} (${date})`);
365
- }
366
- return notes;
367
- })
368
- .join("\n\n");
369
- return `${sections}\n\nThis PR was generated by Versionary.`;
380
+ return relabelSectionHeader(notes, packageLabel, pkg.nextVersion ?? "");
381
+ });
382
+ sections.push(...packageSections);
383
+ const bodySections = sections.join("\n\n");
384
+ if (bodySections.length === 0) {
385
+ return "This PR was generated by Versionary.";
386
+ }
387
+ return `${bodySections}\n\nThis PR was generated by Versionary.`;
370
388
  }
371
389
  return (0, changelog_js_1.renderSimpleReleaseNotes)({
372
390
  currentVersion: previousVersion,
@@ -375,22 +393,14 @@ function renderSimpleReviewRequestBody(version, previousVersion, commits, plan =
375
393
  cwd,
376
394
  }, { includeFooter: true });
377
395
  }
378
- async function openOrUpdateSimpleReviewRequest(cwd, branch, title, version, previousVersion, commits, plan = null, options = {}) {
396
+ async function openOrUpdateReviewRequest(cwd, branch, title, version, previousVersion, commits, plan = null, options = {}) {
379
397
  const loaded = (0, load_config_js_1.loadConfig)(cwd);
380
398
  const releaseFlow = loaded.config["review-mode"] ?? "pr";
381
399
  if (releaseFlow === "direct") {
382
400
  return "Release flow mode is direct; skipping review request creation.";
383
401
  }
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({
402
+ const scmClient = (0, client_js_1.getScmClient)();
403
+ const result = await scmClient.createOrUpdateReviewRequest({
394
404
  baseBranch: process.env.VERSIONARY_BASE_BRANCH ?? "main",
395
405
  headBranch: branch,
396
406
  title,
@@ -402,6 +412,14 @@ async function openOrUpdateSimpleReviewRequest(cwd, branch, title, version, prev
402
412
  });
403
413
  return result.url;
404
414
  }
415
+ /** @deprecated Use prepareReleasePr. */
416
+ function prepareSimpleReleasePr(cwd = process.cwd(), options = {}) {
417
+ return prepareReleasePr(cwd, options);
418
+ }
419
+ /** @deprecated Use openOrUpdateReviewRequest. */
420
+ async function openOrUpdateSimpleReviewRequest(cwd, branch, title, version, previousVersion, commits, plan = null, options = {}) {
421
+ return openOrUpdateReviewRequest(cwd, branch, title, version, previousVersion, commits, plan, options);
422
+ }
405
423
  function pushReleaseBranch(cwd, branch) {
406
424
  (0, node_child_process_1.execFileSync)("git", ["push", "--force-with-lease", "origin", branch], {
407
425
  cwd,
@@ -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,8 +1,9 @@
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
+ export declare function extractReleaseNotes(content: string, version: string, changelogFormat: "markdown-changelog" | "r-news"): string;
3
4
  export declare function resolveTargetChangelogFile(config: VersionaryConfig, rootChangelogFile: string, targetPath: string): string;
4
- export declare function runSimpleRelease(cwd?: string): Promise<string>;
5
- export type SimpleRunReleaseResult = {
5
+ export declare function runRelease(cwd?: string): Promise<string>;
6
+ export type RunReleaseResult = {
6
7
  action: "release-skipped";
7
8
  reason: string;
8
9
  } | {
@@ -22,8 +23,16 @@ export type SimpleRunReleaseResult = {
22
23
  metadataStatus: "created" | "exists";
23
24
  }[];
24
25
  };
25
- export interface RunSimpleReleaseOptions {
26
+ export interface RunReleaseOptions {
26
27
  logger?: VersionaryPluginContext["logger"];
27
28
  "dry-run"?: boolean;
28
29
  }
30
+ export declare function runReleaseDetailed(cwd?: string, options?: RunReleaseOptions): Promise<RunReleaseResult>;
31
+ /** @deprecated Use RunReleaseResult. */
32
+ export type SimpleRunReleaseResult = RunReleaseResult;
33
+ /** @deprecated Use RunReleaseOptions. */
34
+ export type RunSimpleReleaseOptions = RunReleaseOptions;
35
+ /** @deprecated Use runRelease. */
36
+ export declare function runSimpleRelease(cwd?: string): Promise<string>;
37
+ /** @deprecated Use runReleaseDetailed. */
29
38
  export declare function runSimpleReleaseDetailed(cwd?: string, options?: RunSimpleReleaseOptions): Promise<SimpleRunReleaseResult>;