versionary 0.2.0 → 0.4.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 +231 -12
  2. package/dist/app/release/artifact-rules.d.ts +3 -0
  3. package/dist/app/release/artifact-rules.js +186 -0
  4. package/dist/app/release/pr.d.ts +23 -0
  5. package/dist/{simple → app/release}/pr.js +90 -79
  6. package/dist/app/release/recovery.d.ts +20 -0
  7. package/dist/app/release/recovery.js +101 -0
  8. package/dist/app/release/release.d.ts +19 -0
  9. package/dist/app/release/release.js +111 -0
  10. package/dist/app/release/state.d.ts +9 -0
  11. package/dist/app/release/state.js +93 -0
  12. package/dist/app/release/verify.d.ts +2 -0
  13. package/dist/app/release/verify.js +5 -0
  14. package/dist/cli/index.js +71 -15
  15. package/dist/config/load-config.js +2 -12
  16. package/dist/config/schema.d.ts +1 -0
  17. package/dist/config/schema.js +34 -1
  18. package/dist/domain/release/changelog.d.ts +12 -0
  19. package/dist/domain/release/changelog.js +123 -0
  20. package/dist/{simple → domain/release}/plan.d.ts +4 -3
  21. package/dist/{simple → domain/release}/plan.js +32 -15
  22. package/dist/domain/release/semver.d.ts +15 -0
  23. package/dist/domain/release/semver.js +111 -0
  24. package/dist/domain/strategy/node.d.ts +2 -0
  25. package/dist/domain/strategy/node.js +67 -0
  26. package/dist/domain/strategy/r.d.ts +2 -0
  27. package/dist/domain/strategy/r.js +46 -0
  28. package/dist/domain/strategy/resolve.d.ts +3 -0
  29. package/dist/domain/strategy/resolve.js +19 -0
  30. package/dist/domain/strategy/rust.d.ts +2 -0
  31. package/dist/domain/strategy/rust.js +369 -0
  32. package/dist/domain/strategy/simple.d.ts +2 -0
  33. package/dist/domain/strategy/simple.js +28 -0
  34. package/dist/domain/strategy/types.d.ts +7 -0
  35. package/dist/domain/strategy/types.js +2 -0
  36. package/dist/index.d.ts +5 -3
  37. package/dist/index.js +5 -1
  38. package/dist/infra/git/commits.d.ts +65 -0
  39. package/dist/infra/git/commits.js +436 -0
  40. package/dist/infra/scm/github/plugin.d.ts +1 -0
  41. package/dist/infra/scm/github/plugin.js +5 -0
  42. package/dist/infra/scm/runtime.d.ts +2 -0
  43. package/dist/infra/scm/runtime.js +24 -0
  44. package/dist/infra/scm/types.d.ts +1 -0
  45. package/dist/infra/scm/types.js +2 -0
  46. package/dist/plugins/runtime.d.ts +1 -2
  47. package/dist/plugins/runtime.js +3 -22
  48. package/dist/scm/github-plugin.js +133 -40
  49. package/dist/strategies/node.d.ts +1 -0
  50. package/dist/strategies/node.js +5 -0
  51. package/dist/strategies/resolve.d.ts +1 -0
  52. package/dist/strategies/resolve.js +5 -0
  53. package/dist/strategies/simple.d.ts +1 -0
  54. package/dist/strategies/simple.js +5 -0
  55. package/dist/strategies/types.d.ts +1 -0
  56. package/dist/strategies/types.js +2 -0
  57. package/dist/types/config.d.ts +1 -0
  58. package/dist/types/plugins.d.ts +1 -0
  59. package/dist/verify/verify-project.js +3 -1
  60. package/package.json +3 -2
  61. package/dist/simple/changelog.d.ts +0 -3
  62. package/dist/simple/changelog.js +0 -46
  63. package/dist/simple/git.d.ts +0 -10
  64. package/dist/simple/git.js +0 -114
  65. package/dist/simple/pr.d.ts +0 -15
  66. package/dist/simple/release.d.ts +0 -1
  67. package/dist/simple/release.js +0 -77
  68. package/dist/simple/semver.d.ts +0 -8
  69. package/dist/simple/semver.js +0 -25
  70. package/dist/simple/state.d.ts +0 -3
  71. package/dist/simple/state.js +0 -47
  72. /package/dist/{simple → infra/git}/repo-url.d.ts +0 -0
  73. /package/dist/{simple → infra/git}/repo-url.js +0 -0
package/README.md CHANGED
@@ -1,13 +1,78 @@
1
- # versionary
1
+ # Versionary
2
2
 
3
3
  Versionary is a software-agnostic automated release tool focused on SemVer,
4
4
  conventional commits, release PR workflows, and extensibility.
5
5
 
6
- Configuration is loaded from `versionary.jsonc` by default.
6
+ ## Why this exists
7
+
8
+ Versionary is designed as a practical middle ground between `semantic-release`
9
+ and `release-please`.
10
+
11
+ - Like `semantic-release`, it supports direct release execution.
12
+ - Like `release-please`, it supports a release PR workflow so maintainers can
13
+ preview and review changes before publication.
14
+
15
+ The core idea is to keep versioning, changelog generation, tagging, and SCM
16
+ release metadata in one tool, while leaving package publication (npm, crates.io,
17
+ etc.) to dedicated CI workflows triggered by tags or releases.
18
+
19
+ ## Product direction
20
+
21
+ Versionary is being built to:
22
+
23
+ - support both direct releases and release-PR-gated releases
24
+ - work across repository types (Node, Rust, docs/LaTeX, etc.)
25
+ - stay SCM-agnostic at the core, with integrations via plugin capabilities
26
+ (GitHub first; GitLab/Codeberg later)
27
+ - keep a small, stable core with explicit extension points
28
+ - handle trunk-based development and monorepo workflows cleanly
29
+
30
+ ## Scope and non-goals
31
+
32
+ In scope:
33
+
34
+ - semantic version planning from commits
35
+ - changelog generation
36
+ - release PR automation
37
+ - tags + SCM release metadata (e.g. GitHub Releases)
38
+
39
+ Out of scope (intentional):
40
+
41
+ - publishing artifacts to language registries
42
+ - replacing package-specific publish tooling
43
+
44
+ Use your CI/CD platform for registry publishing, triggered from a created
45
+ release/tag.
46
+
47
+ ## Current status vs roadmap
48
+
49
+ Current implementation focuses on:
50
+
51
+ - strategy-based version updates (`simple`, `node`)
52
+ - release planning and changelog generation
53
+ - review-mode vs direct-mode release flow
54
+ - built-in GitHub SCM plugin capabilities
55
+
56
+ Planned/harder areas include deeper monorepo ergonomics, broader SCM coverage,
57
+ and stronger failure recovery around release steps.
58
+
59
+ ## Architecture layout (current migration)
60
+
61
+ The repository is moving to explicit layered modules:
62
+
63
+ - `src/app/`: command-level application services and orchestration boundaries
64
+ - `src/domain/`: release and strategy domain logic/contracts
65
+ - `src/infra/`: platform integrations (SCM, git/runtime adapters)
66
+
67
+ Legacy `src/simple/` has been removed. Remaining compatibility paths are
68
+ `src/strategies` and `src/scm` while migration is finalized.
69
+
70
+ Configuration is loaded from `versionary.jsonc` by default (or
71
+ `versionary.json`).
7
72
 
8
73
  Schema URL for editor support:
9
74
 
10
- - `https://raw.githubusercontent.com/jolars/versionary/main/schemas/versionary-schema.json`
75
+ - `https://raw.githubusercontent.com/jolars/versionary/main/schemas/config.json`
11
76
 
12
77
  ## Config (manifest style)
13
78
 
@@ -15,21 +80,85 @@ For a quick trial, use:
15
80
 
16
81
  - `version-file` (default `version.txt`) as version source
17
82
  - `changelog-file` (default `CHANGELOG.md`) as release notes output
18
- - stable release branch (`release-branch`, default:
19
- `versionary/release`) so release PRs are updated in-place
20
- - `baseline-file` (default `.versionary-manifest.json`) tracks baseline SHA for deterministic commit
21
- ranges independent of tags
22
- - review mode (`review-mode`): `review` (PR/MR style) or `direct` (no
23
- review request)
83
+ - `release-type: "node"` uses `package.json` as version source and updates it
84
+ during release PR prep
85
+ - `release-type: "r"` uses `DESCRIPTION` as version source and updates the
86
+ `Version:` field
87
+ - `release-type: "rust"` uses Cargo manifests (`Cargo.toml`) as version source;
88
+ `version-file` must point to a `Cargo.toml` (default: `Cargo.toml`)
89
+ - simple/default strategy keeps `version.txt` as source of truth and does not
90
+ update `package.json`
91
+ - stable release branch (`release-branch`, default: `versionary/release`) so
92
+ release PRs are updated in-place
93
+ - `baseline-file` (default `.versionary-manifest.json`) tracks baseline SHA for
94
+ deterministic commit ranges independent of tags
95
+ - pre-1.0 policy defaults to conservative major handling: for `0.y.z`, breaking
96
+ changes bump to `0.(y+1).0`; set `allow-stable-major: true` to allow explicit
97
+ auto-transition to `1.0.0` on a breaking release
98
+ - review mode (`review-mode`): `review` (PR/MR style) or `direct` (no review
99
+ request)
24
100
  - optional monorepo planning with `monorepo-mode` and `packages`:
25
101
  - `independent` computes package bumps per path
26
102
  - `fixed` computes one shared bump across configured package paths
27
103
 
104
+ Rust strategy examples:
105
+
106
+ ```jsonc
107
+ // Single crate
108
+ {
109
+ "release-type": "rust",
110
+ "version-file": "Cargo.toml"
111
+ }
112
+ ```
113
+
114
+ ```jsonc
115
+ // Workspace root (virtual or root crate + members)
116
+ {
117
+ "release-type": "rust",
118
+ "version-file": "Cargo.toml"
119
+ }
120
+ ```
121
+
122
+ Current rust auto-update behavior (phase scope):
123
+
124
+ - updates crate versions in each targeted crate `[package].version`
125
+ - updates internal workspace dependency versions when the dependency name
126
+ matches another targeted crate name
127
+ - applies dependency version rewrites in:
128
+ - `[dependencies]`, `[dev-dependencies]`, `[build-dependencies]`
129
+ - `[target.*.dependencies]`, `[target.*.dev-dependencies]`,
130
+ `[target.*.build-dependencies]`
131
+
132
+ Current rust non-goals/limits:
133
+
134
+ - does not update external dependency versions
135
+ - does not update `workspace.dependencies`
136
+ - does not add missing `version = ...` fields to dependency inline tables
137
+ - does not perform Cargo publish/release to crates.io
138
+
139
+ ## Commit parsing and release analysis
140
+
141
+ Release planning is based on Conventional Commit parsing semantics:
142
+
143
+ - parses type/scope/description from commit headers
144
+ - exposes structured parsed fields (`header`, `body`, `footer`, `type`, `scope`,
145
+ `description`, `notes`, `references`, `mentions`, `revert`)
146
+ - separates parser output from release policy mapping (`inferReleaseType*`)
147
+ - recognizes breaking changes from `!` and `BREAKING CHANGE` / `BREAKING-CHANGE`
148
+ footers
149
+ - maps release impact as `feat => minor`, `fix|perf => patch`, breaking => major
150
+ - treats `revert:` as non-releasable commits
151
+ - suppresses commits that are reverted within the analyzed release window so
152
+ they do not affect bump/changelog output
153
+ - emits parser diagnostics for malformed headers/footers/references and
154
+ ambiguous revert messages
155
+
28
156
  Commands:
29
157
 
30
158
  - `pnpm verify`
31
159
  - `pnpm run` (default orchestration: no-op, create/update release PR, or publish
32
160
  release based on context)
161
+ - `pnpm run -- --json` (machine-readable orchestration result)
33
162
  - `pnpm plan`
34
163
  - `pnpm changelog -- --write`
35
164
  - `pnpm pr`
@@ -39,8 +168,23 @@ Commands:
39
168
  via SCM plugin capability. `pnpm run` is the recommended CI entrypoint and
40
169
  auto-dispatches between PR/update and release publish.
41
170
 
42
- For first-run bootstrapping, set `bootstrap-sha` (similar to release-please). Subsequent runs use
43
- the baseline state file.
171
+ For first-run bootstrapping, set `bootstrap-sha` (similar to release-please).
172
+ Subsequent runs use the baseline state file.
173
+
174
+ ## Release retry and recovery behavior
175
+
176
+ Release publish (`pnpm release` or the publish path in `pnpm run`) is idempotent
177
+ by target tag:
178
+
179
+ - if a tag already exists, Versionary reuses it rather than recreating it
180
+ - if release metadata already exists for the tag (e.g., GitHub Release), it is
181
+ reused
182
+ - if a prior run created/pushed the tag but failed before metadata creation, a
183
+ rerun creates the missing metadata and proceeds
184
+
185
+ Versionary fails fast when recovery is unsafe (for example, local and remote
186
+ tags with the same name point to different SHAs). In these cases, the error
187
+ message includes remediation guidance so CI logs are actionable.
44
188
 
45
189
  ## Built-in plugins
46
190
 
@@ -48,8 +192,83 @@ Versionary ships with built-in SCM plugin support:
48
192
 
49
193
  - `github` (default): review request + release metadata
50
194
 
195
+ ### GitHub integration: env, permissions, and flow
196
+
197
+ Required environment for the built-in GitHub plugin:
198
+
199
+ - `GITHUB_REPOSITORY` (format: `owner/repo`)
200
+ - one token env var: `VERSIONARY_PR_TOKEN` or `GH_TOKEN` or `GITHUB_TOKEN`
201
+
202
+ Token precedence is:
203
+
204
+ - `VERSIONARY_PR_TOKEN` > `GH_TOKEN` > `GITHUB_TOKEN`
205
+
206
+ Minimum GitHub token/repo permissions for Versionary-managed metadata:
207
+
208
+ - release PR create/update flow: `contents: write`, `pull-requests: write`
209
+ - release metadata flow (GitHub Release create/read): `contents: write`
210
+
211
+ `review-mode` behavior:
212
+
213
+ - `review`: `pnpm run run` prepares/updates the release branch and creates or
214
+ updates a release PR
215
+ - `direct`: `pnpm run run` prepares/updates the release branch and skips review
216
+ request creation
217
+
218
+ Concise GitHub Actions examples:
219
+
220
+ ```yaml
221
+ # 1) Release PR / update flow (run on push to default branch)
222
+ permissions:
223
+ contents: write
224
+ pull-requests: write
225
+
226
+ steps:
227
+ - uses: actions/checkout@v6
228
+ with:
229
+ fetch-depth: 0
230
+ fetch-tags: true
231
+ - id: versionary
232
+ uses: jolars/versionary@v1
233
+ with:
234
+ github-token: ${{ secrets.RELEASE_TOKEN }}
235
+ ```
236
+
237
+ ```yaml
238
+ # 2) Release publish flow after merge (release commit context)
239
+ permissions:
240
+ contents: write
241
+
242
+ steps:
243
+ - uses: actions/checkout@v6
244
+ with:
245
+ fetch-depth: 0
246
+ fetch-tags: true
247
+ - id: versionary
248
+ uses: jolars/versionary@v1
249
+ with:
250
+ github-token: ${{ secrets.RELEASE_TOKEN }}
251
+ - if: ${{ steps.versionary.outputs.release_created == 'true' }}
252
+ run: echo "Released ${{ steps.versionary.outputs.tag_name }}"
253
+ ```
254
+
255
+ Action outputs:
256
+
257
+ - `action`: `noop`, `pr-prepared`, `release-published`, `release-skipped`
258
+ - `message`: human-readable summary
259
+ - `release_created`: `"true"` when at least one release was published
260
+ - `tag_name`: first published tag (for single-target flows)
261
+ - `tag_names`: JSON array of published tags
262
+ - `review_url`: review request URL when PR flow runs
263
+
264
+ For GitHub Action consumers, publish immutable tags (for example `v1.2.3`) and
265
+ maintain a moving major tag (`v1`, `v2`, ...). A small release-triggered
266
+ workflow should update `v<major>` to the latest release tag so `uses:
267
+ jolars/versionary@v1` stays current without breaking major compatibility.
268
+
51
269
  Package publication is intentionally out of scope in the current release flow.
52
- Use separate CI workflows for publishing after Versionary has prepared/tagged the release.
270
+ Use separate CI workflows for publishing after Versionary has prepared/tagged
271
+ the release.
53
272
 
54
273
  ## Install from GitHub
55
274
 
@@ -0,0 +1,3 @@
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[];
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.applyConfiguredArtifactRules = applyConfiguredArtifactRules;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const toml_1 = __importDefault(require("@iarna/toml"));
10
+ const yaml_1 = __importDefault(require("yaml"));
11
+ function isRecord(value) {
12
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
13
+ }
14
+ function parseJsonPath(jsonpath) {
15
+ if (!jsonpath.startsWith("$")) {
16
+ throw new Error(`Invalid jsonpath "${jsonpath}". Must start with "$".`);
17
+ }
18
+ const tokens = [];
19
+ let index = 1;
20
+ while (index < jsonpath.length) {
21
+ const current = jsonpath[index];
22
+ if (current === ".") {
23
+ const keyMatch = jsonpath.slice(index + 1).match(/^[A-Za-z0-9_-]+/u);
24
+ if (!keyMatch) {
25
+ throw new Error(`Invalid jsonpath "${jsonpath}" near index ${index}.`);
26
+ }
27
+ tokens.push(keyMatch[0]);
28
+ index += 1 + keyMatch[0].length;
29
+ continue;
30
+ }
31
+ if (current === "[") {
32
+ const rest = jsonpath.slice(index + 1);
33
+ const numberMatch = rest.match(/^(\d+)\]/u);
34
+ if (numberMatch) {
35
+ tokens.push(Number(numberMatch[1]));
36
+ index += 2 + numberMatch[1].length;
37
+ continue;
38
+ }
39
+ const keyMatch = rest.match(/^"([^"]+)"\]/u);
40
+ if (keyMatch) {
41
+ tokens.push(keyMatch[1]);
42
+ index += 4 + keyMatch[1].length;
43
+ continue;
44
+ }
45
+ throw new Error(`Invalid jsonpath "${jsonpath}" near index ${index}.`);
46
+ }
47
+ throw new Error(`Invalid jsonpath "${jsonpath}" near index ${index}.`);
48
+ }
49
+ if (tokens.length === 0) {
50
+ throw new Error(`Invalid jsonpath "${jsonpath}". Path must target a field.`);
51
+ }
52
+ return tokens;
53
+ }
54
+ function setVersionAtJsonPath(document, jsonpath, version) {
55
+ const tokens = parseJsonPath(jsonpath);
56
+ let cursor = document;
57
+ for (let index = 0; index < tokens.length - 1; index += 1) {
58
+ const token = tokens[index];
59
+ if (typeof token === "number") {
60
+ if (!Array.isArray(cursor) || token >= cursor.length) {
61
+ throw new Error(`jsonpath "${jsonpath}" does not resolve to an existing field.`);
62
+ }
63
+ cursor = cursor[token];
64
+ continue;
65
+ }
66
+ if (!isRecord(cursor) || !(token in cursor)) {
67
+ throw new Error(`jsonpath "${jsonpath}" does not resolve to an existing field.`);
68
+ }
69
+ cursor = cursor[token];
70
+ }
71
+ const leaf = tokens.at(-1);
72
+ if (typeof leaf === "number") {
73
+ if (!Array.isArray(cursor) || leaf >= cursor.length) {
74
+ throw new Error(`jsonpath "${jsonpath}" does not resolve to an existing field.`);
75
+ }
76
+ const current = cursor[leaf];
77
+ if (typeof current !== "string" && typeof current !== "number") {
78
+ throw new Error(`jsonpath "${jsonpath}" must point to a string or number field for version updates.`);
79
+ }
80
+ cursor[leaf] = version;
81
+ return;
82
+ }
83
+ if (!isRecord(cursor) || !(leaf in cursor)) {
84
+ throw new Error(`jsonpath "${jsonpath}" does not resolve to an existing field.`);
85
+ }
86
+ const current = cursor[leaf];
87
+ if (typeof current !== "string" && typeof current !== "number") {
88
+ throw new Error(`jsonpath "${jsonpath}" must point to a string or number field for version updates.`);
89
+ }
90
+ cursor[leaf] = version;
91
+ }
92
+ function parseRegexPattern(pattern) {
93
+ const slashPattern = pattern.match(/^\/((?:\\\/|[^/])+)\/([a-z]*)$/u);
94
+ if (slashPattern) {
95
+ return new RegExp(slashPattern[1], slashPattern[2]);
96
+ }
97
+ return new RegExp(pattern, "m");
98
+ }
99
+ function applyRegexRule(content, pattern, version) {
100
+ const regex = parseRegexPattern(pattern);
101
+ const matchFlags = regex.flags.includes("g")
102
+ ? regex.flags
103
+ : `${regex.flags}g`;
104
+ const globalRegex = new RegExp(regex.source, matchFlags);
105
+ const matches = [...content.matchAll(globalRegex)];
106
+ if (matches.length !== 1) {
107
+ throw new Error(`Regex pattern must match exactly one occurrence; matched ${matches.length}.`);
108
+ }
109
+ const match = matches[0];
110
+ const start = match.index;
111
+ if (start === undefined) {
112
+ throw new Error("Regex match did not include an index.");
113
+ }
114
+ const full = match[0];
115
+ const groupOne = match[1];
116
+ const replacement = typeof groupOne === "string" ? full.replace(groupOne, version) : version;
117
+ return `${content.slice(0, start)}${replacement}${content.slice(start + full.length)}`;
118
+ }
119
+ function applyArtifactRuleToContent(content, rule, version) {
120
+ if (rule.type === "regex") {
121
+ return applyRegexRule(content, rule.pattern, version);
122
+ }
123
+ if (rule.type === "json") {
124
+ const parsed = JSON.parse(content);
125
+ setVersionAtJsonPath(parsed, rule.jsonpath, version);
126
+ return `${JSON.stringify(parsed, null, 2)}\n`;
127
+ }
128
+ if (rule.type === "toml") {
129
+ const parsed = toml_1.default.parse(content);
130
+ setVersionAtJsonPath(parsed, rule.jsonpath, version);
131
+ return `${toml_1.default.stringify(parsed)}\n`;
132
+ }
133
+ const parsed = yaml_1.default.parse(content);
134
+ setVersionAtJsonPath(parsed, rule.jsonpath, version);
135
+ return `${yaml_1.default.stringify(parsed)}`;
136
+ }
137
+ function normalizeRelative(base, target) {
138
+ return node_path_1.default.relative(base, target).replaceAll("\\", "/");
139
+ }
140
+ function applyArtifactRulesForPackage(cwd, packagePath, packageConfig, version) {
141
+ const rules = packageConfig["extra-files"] ?? [];
142
+ if (rules.length === 0) {
143
+ return [];
144
+ }
145
+ const packageBase = node_path_1.default.join(cwd, packagePath);
146
+ const updated = [];
147
+ for (const rule of rules) {
148
+ const targetPath = node_path_1.default.join(packageBase, rule.path);
149
+ if (!node_fs_1.default.existsSync(targetPath)) {
150
+ throw new Error(`Artifact rule target missing for package "${packagePath}": ${rule.path}`);
151
+ }
152
+ const existing = node_fs_1.default.readFileSync(targetPath, "utf8");
153
+ let next;
154
+ try {
155
+ next = applyArtifactRuleToContent(existing, rule, version);
156
+ }
157
+ catch (error) {
158
+ const message = error instanceof Error ? error.message : String(error);
159
+ throw new Error(`Failed applying artifact rule (${rule.type}) for package "${packagePath}" file "${rule.path}": ${message}`);
160
+ }
161
+ node_fs_1.default.writeFileSync(targetPath, next, "utf8");
162
+ updated.push(normalizeRelative(cwd, targetPath));
163
+ }
164
+ return updated;
165
+ }
166
+ function applyConfiguredArtifactRules(cwd, config, plan) {
167
+ const packageConfigs = config.packages ?? {};
168
+ if (!plan.packages || plan.packages.length === 0) {
169
+ return [];
170
+ }
171
+ const updated = new Set();
172
+ for (const packagePlan of plan.packages) {
173
+ if (!packagePlan.nextVersion) {
174
+ continue;
175
+ }
176
+ const packageConfig = packageConfigs[packagePlan.path];
177
+ if (!packageConfig?.["extra-files"]?.length) {
178
+ continue;
179
+ }
180
+ const files = applyArtifactRulesForPackage(cwd, packagePlan.path, packageConfig, packagePlan.nextVersion);
181
+ for (const file of files) {
182
+ updated.add(file);
183
+ }
184
+ }
185
+ return [...updated].sort((a, b) => a.localeCompare(b));
186
+ }
@@ -0,0 +1,23 @@
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";
4
+ export declare function splitSafeDirtyFiles(files: string[]): {
5
+ ignored: string[];
6
+ blocking: string[];
7
+ };
8
+ export declare function prepareSimpleReleasePr(cwd?: string, options?: {
9
+ logger?: VersionaryPluginContext["logger"];
10
+ }): {
11
+ branch: string;
12
+ title: string;
13
+ version: string;
14
+ previousVersion: string;
15
+ commits: ParsedCommit[];
16
+ plan: SimplePlan;
17
+ };
18
+ export declare function renderSimpleReviewRequestBody(version: string, previousVersion: string, commits: ParsedCommit[], plan?: SimplePlan | null, cwd?: string): string;
19
+ export declare function openOrUpdateSimpleReviewRequest(cwd: string, branch: string, title: string, version: string, previousVersion: string, commits: ParsedCommit[], plan?: SimplePlan | null, options?: {
20
+ logger?: VersionaryPluginContext["logger"];
21
+ }): Promise<string>;
22
+ export declare function pushReleaseBranch(cwd: string, branch: string): void;
23
+ export declare function isReleaseCommitMessage(subject: string): boolean;