versionary 0.22.0 → 0.23.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.
- package/README.md +26 -0
- package/dist/config/schema.d.ts +1 -0
- package/dist/config/schema.js +86 -1
- package/dist/release/plan.d.ts +1 -1
- package/dist/release/plan.js +44 -1
- package/dist/release/semver.d.ts +1 -0
- package/dist/release/semver.js +13 -0
- package/dist/types/config.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -157,6 +157,32 @@ For a quick trial, use:
|
|
|
157
157
|
- per-package `package-name` can override release identity (labels + tag base)
|
|
158
158
|
- per-package `changelog-file` writes package release notes to
|
|
159
159
|
`<package-path>/<changelog-file>`
|
|
160
|
+
- per-package `follows` declares an asymmetric version link to one or more
|
|
161
|
+
source packages: when any source bumps, the follower releases too, with
|
|
162
|
+
bump = `max(own bump, max(source bumps))`. The follower's changelog gets a
|
|
163
|
+
`### Dependencies` section listing the followed sources. Use it when one
|
|
164
|
+
package bundles another's artifact (e.g. an editor extension that ships
|
|
165
|
+
the CLI binary). Cycles, self-references, unknown source paths, and
|
|
166
|
+
combining `follows` with `monorepo-mode: "fixed"` are config errors.
|
|
167
|
+
`follows` is non-transitive: A follows B does not imply A follows what B
|
|
168
|
+
follows.
|
|
169
|
+
|
|
170
|
+
```jsonc
|
|
171
|
+
// Editor extension that bundles the root CLI artifact
|
|
172
|
+
{
|
|
173
|
+
"version": 1,
|
|
174
|
+
"release-type": "rust",
|
|
175
|
+
"monorepo-mode": "independent",
|
|
176
|
+
"packages": {
|
|
177
|
+
".": { "exclude-paths": ["editors"] },
|
|
178
|
+
"editors/code": {
|
|
179
|
+
"release-type": "node",
|
|
180
|
+
"package-name": "panache-code",
|
|
181
|
+
"follows": ["."]
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
160
186
|
|
|
161
187
|
Rust strategy examples:
|
|
162
188
|
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -53,6 +53,7 @@ export declare const configSchema: z.ZodObject<{
|
|
|
53
53
|
jsonpath: z.ZodOptional<z.ZodString>;
|
|
54
54
|
pattern: z.ZodOptional<z.ZodString>;
|
|
55
55
|
}, z.core.$strip>>>;
|
|
56
|
+
follows: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
56
57
|
}, z.core.$strict>>>;
|
|
57
58
|
}, z.core.$strict>;
|
|
58
59
|
export type ConfigSchema = z.infer<typeof configSchema>;
|
package/dist/config/schema.js
CHANGED
|
@@ -60,6 +60,7 @@ const packageSchema = zod_1.z
|
|
|
60
60
|
"changelog-format": zod_1.z.enum(["markdown-changelog", "r-news"]).optional(),
|
|
61
61
|
"exclude-paths": zod_1.z.array(zod_1.z.string()).optional(),
|
|
62
62
|
"extra-files": zod_1.z.array(artifactRuleSchema).optional(),
|
|
63
|
+
follows: zod_1.z.array(zod_1.z.string().min(1)).optional(),
|
|
63
64
|
})
|
|
64
65
|
.strict();
|
|
65
66
|
exports.configSchema = zod_1.z
|
|
@@ -85,4 +86,88 @@ exports.configSchema = zod_1.z
|
|
|
85
86
|
"release-type": zod_1.z.string().optional(),
|
|
86
87
|
packages: zod_1.z.record(zod_1.z.string().min(1), packageSchema).optional(),
|
|
87
88
|
})
|
|
88
|
-
.strict()
|
|
89
|
+
.strict()
|
|
90
|
+
.superRefine((value, ctx) => {
|
|
91
|
+
const packages = value.packages;
|
|
92
|
+
if (!packages) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const knownPaths = new Set(Object.keys(packages));
|
|
96
|
+
const followsByPath = new Map();
|
|
97
|
+
for (const [packagePath, packageConfig] of Object.entries(packages)) {
|
|
98
|
+
const follows = packageConfig.follows;
|
|
99
|
+
if (!follows || follows.length === 0) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
followsByPath.set(packagePath, follows);
|
|
103
|
+
for (const sourcePath of follows) {
|
|
104
|
+
if (sourcePath === packagePath) {
|
|
105
|
+
ctx.addIssue({
|
|
106
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
107
|
+
message: `Package "${packagePath}" cannot follow itself.`,
|
|
108
|
+
path: ["packages", packagePath, "follows"],
|
|
109
|
+
});
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (!knownPaths.has(sourcePath)) {
|
|
113
|
+
ctx.addIssue({
|
|
114
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
115
|
+
message: `Package "${packagePath}" follows unknown package "${sourcePath}".`,
|
|
116
|
+
path: ["packages", packagePath, "follows"],
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (followsByPath.size > 0 && value["monorepo-mode"] === "fixed") {
|
|
122
|
+
for (const followerPath of followsByPath.keys()) {
|
|
123
|
+
ctx.addIssue({
|
|
124
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
125
|
+
message: 'Package "follows" cannot be combined with monorepo-mode "fixed" (fixed mode already pins all package versions together).',
|
|
126
|
+
path: ["packages", followerPath, "follows"],
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const reportedCycles = new Set();
|
|
131
|
+
const findCycleFrom = (start) => {
|
|
132
|
+
const trail = [];
|
|
133
|
+
const visit = (node) => {
|
|
134
|
+
const trailIndex = trail.indexOf(node);
|
|
135
|
+
if (trailIndex !== -1) {
|
|
136
|
+
return [...trail.slice(trailIndex), node];
|
|
137
|
+
}
|
|
138
|
+
const sources = followsByPath.get(node);
|
|
139
|
+
if (!sources || sources.length === 0) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
trail.push(node);
|
|
143
|
+
for (const source of sources) {
|
|
144
|
+
if (!knownPaths.has(source)) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const cycle = visit(source);
|
|
148
|
+
if (cycle) {
|
|
149
|
+
return cycle;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
trail.pop();
|
|
153
|
+
return null;
|
|
154
|
+
};
|
|
155
|
+
return visit(start);
|
|
156
|
+
};
|
|
157
|
+
for (const followerPath of followsByPath.keys()) {
|
|
158
|
+
const cycle = findCycleFrom(followerPath);
|
|
159
|
+
if (!cycle) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
const key = [...cycle].sort().join("->");
|
|
163
|
+
if (reportedCycles.has(key)) {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
reportedCycles.add(key);
|
|
167
|
+
ctx.addIssue({
|
|
168
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
169
|
+
message: `Package "follows" cycle detected: ${cycle.join(" -> ")}.`,
|
|
170
|
+
path: ["packages", cycle[0] ?? followerPath, "follows"],
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
});
|
package/dist/release/plan.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export interface ReleasePlan {
|
|
|
18
18
|
releaseType: ReleaseType;
|
|
19
19
|
currentVersion: string;
|
|
20
20
|
nextVersion: string | null;
|
|
21
|
-
bumpReason?: "direct" | "dependency-propagation";
|
|
21
|
+
bumpReason?: "direct" | "dependency-propagation" | "follows";
|
|
22
22
|
dependencySourcePaths?: string[];
|
|
23
23
|
commits: ParsedCommit[];
|
|
24
24
|
}>;
|
package/dist/release/plan.js
CHANGED
|
@@ -98,6 +98,8 @@ function createReleasePlan(cwd = process.cwd()) {
|
|
|
98
98
|
releaseType: null,
|
|
99
99
|
currentVersion: explicitPackagePlans[0]?.currentVersion ?? "0.0.0",
|
|
100
100
|
nextVersion: null,
|
|
101
|
+
bumpReason: undefined,
|
|
102
|
+
dependencySourcePaths: undefined,
|
|
101
103
|
commits: [],
|
|
102
104
|
parsedCommits: [],
|
|
103
105
|
resolvedVersionFile: versionFile,
|
|
@@ -171,7 +173,7 @@ function createReleasePlan(cwd = process.cwd()) {
|
|
|
171
173
|
}
|
|
172
174
|
}
|
|
173
175
|
}
|
|
174
|
-
const
|
|
176
|
+
const propagatedPackages = packagePlans.map((pkgPlan) => {
|
|
175
177
|
const dependencySourcePaths = [
|
|
176
178
|
...(dependencySourcePathsByPackage.get(pkgPlan.path) ??
|
|
177
179
|
new Set()),
|
|
@@ -196,6 +198,47 @@ function createReleasePlan(cwd = process.cwd()) {
|
|
|
196
198
|
dependencySourcePaths,
|
|
197
199
|
};
|
|
198
200
|
});
|
|
201
|
+
const followsByPath = new Map();
|
|
202
|
+
for (const [packagePath, packageConfig] of Object.entries(loaded.config.packages ?? {})) {
|
|
203
|
+
const follows = packageConfig.follows ?? [];
|
|
204
|
+
if (follows.length > 0) {
|
|
205
|
+
followsByPath.set(packagePath, follows);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const adjustedPackages = propagatedPackages.map((pkgPlan) => {
|
|
209
|
+
const followsSources = followsByPath.get(pkgPlan.path) ?? [];
|
|
210
|
+
const bumpingSources = followsSources
|
|
211
|
+
.map((sourcePath) => propagatedPackages.find((pkg) => pkg.path === sourcePath))
|
|
212
|
+
.filter((sourcePlan) => Boolean(sourcePlan?.nextVersion));
|
|
213
|
+
if (bumpingSources.length === 0) {
|
|
214
|
+
return pkgPlan;
|
|
215
|
+
}
|
|
216
|
+
const ownReleaseType = pkgPlan.releaseType;
|
|
217
|
+
const combinedReleaseType = (0, semver_js_1.maxReleaseType)([
|
|
218
|
+
ownReleaseType,
|
|
219
|
+
...bumpingSources.map((sourcePlan) => sourcePlan.releaseType),
|
|
220
|
+
]);
|
|
221
|
+
const mergedDependencySourcePaths = [
|
|
222
|
+
...new Set([
|
|
223
|
+
...(pkgPlan.dependencySourcePaths ?? []),
|
|
224
|
+
...bumpingSources.map((sourcePlan) => sourcePlan.path),
|
|
225
|
+
]),
|
|
226
|
+
].sort((a, b) => a.localeCompare(b));
|
|
227
|
+
const sourceDrove = combinedReleaseType !== ownReleaseType ||
|
|
228
|
+
pkgPlan.bumpReason === "dependency-propagation" ||
|
|
229
|
+
pkgPlan.bumpReason === undefined;
|
|
230
|
+
const baseVersion = packageCurrentVersionByPath[pkgPlan.path] ?? pkgPlan.currentVersion;
|
|
231
|
+
const nextVersion = combinedReleaseType
|
|
232
|
+
? (0, semver_js_1.bumpVersion)(baseVersion, combinedReleaseType, { allowStableMajor })
|
|
233
|
+
: null;
|
|
234
|
+
return {
|
|
235
|
+
...pkgPlan,
|
|
236
|
+
releaseType: combinedReleaseType,
|
|
237
|
+
nextVersion,
|
|
238
|
+
bumpReason: sourceDrove ? "follows" : pkgPlan.bumpReason,
|
|
239
|
+
dependencySourcePaths: mergedDependencySourcePaths,
|
|
240
|
+
};
|
|
241
|
+
});
|
|
199
242
|
const visiblePackages = adjustedPackages.filter((pkgPlan) => !pkgPlan.implicitRoot || hasExplicitRootPackage);
|
|
200
243
|
const rootPackagePlan = adjustedPackages.find((pkgPlan) => pkgPlan.path === ".");
|
|
201
244
|
if (!rootPackagePlan) {
|
package/dist/release/semver.d.ts
CHANGED
package/dist/release/semver.js
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.maxReleaseType = maxReleaseType;
|
|
3
4
|
exports.parseVersion = parseVersion;
|
|
4
5
|
exports.isValidVersion = isValidVersion;
|
|
5
6
|
exports.compareVersions = compareVersions;
|
|
6
7
|
exports.bumpVersion = bumpVersion;
|
|
8
|
+
function maxReleaseType(types) {
|
|
9
|
+
if (types.includes("major")) {
|
|
10
|
+
return "major";
|
|
11
|
+
}
|
|
12
|
+
if (types.includes("minor")) {
|
|
13
|
+
return "minor";
|
|
14
|
+
}
|
|
15
|
+
if (types.includes("patch")) {
|
|
16
|
+
return "patch";
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
7
20
|
const SEMVER_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/u;
|
|
8
21
|
const COMPAT_DOTTED_PRERELEASE_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/u;
|
|
9
22
|
function normalizeVersionInput(version) {
|
package/dist/types/config.d.ts
CHANGED