versionary 0.31.0 → 1.0.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 +93 -435
- package/dist/action/index.js +2 -2
- package/dist/cli/index.js +2 -7
- package/dist/config/schema.d.ts +5 -7
- package/dist/config/schema.js +11 -13
- package/dist/release/artifact-rules.d.ts +2 -2
- package/dist/release/artifact-rules.js +43 -8
- package/dist/release/changelog.d.ts +1 -3
- package/dist/release/changelog.js +29 -9
- package/dist/release/plan.d.ts +3 -5
- package/dist/release/plan.js +221 -65
- package/dist/release/pr.d.ts +7 -26
- package/dist/release/pr.js +13 -64
- package/dist/release/release-as.d.ts +29 -0
- package/dist/release/release-as.js +70 -0
- package/dist/release/release.d.ts +0 -8
- package/dist/release/release.js +0 -8
- package/dist/release/state.js +3 -12
- package/dist/strategy/composite.js +11 -0
- package/dist/strategy/node.js +15 -0
- package/dist/strategy/rust.js +50 -3
- package/dist/strategy/types.d.ts +11 -0
- package/dist/types/config.d.ts +2 -3
- package/package.json +10 -5
|
@@ -30,11 +30,3 @@ export interface RunReleaseOptions {
|
|
|
30
30
|
"dry-run"?: boolean;
|
|
31
31
|
}
|
|
32
32
|
export declare function runReleaseDetailed(cwd?: string, options?: RunReleaseOptions): Promise<RunReleaseResult>;
|
|
33
|
-
/** @deprecated Use RunReleaseResult. */
|
|
34
|
-
export type SimpleRunReleaseResult = RunReleaseResult;
|
|
35
|
-
/** @deprecated Use RunReleaseOptions. */
|
|
36
|
-
export type RunSimpleReleaseOptions = RunReleaseOptions;
|
|
37
|
-
/** @deprecated Use runRelease. */
|
|
38
|
-
export declare function runSimpleRelease(cwd?: string): Promise<string>;
|
|
39
|
-
/** @deprecated Use runReleaseDetailed. */
|
|
40
|
-
export declare function runSimpleReleaseDetailed(cwd?: string, options?: RunSimpleReleaseOptions): Promise<SimpleRunReleaseResult>;
|
package/dist/release/release.js
CHANGED
|
@@ -224,11 +224,3 @@ export async function runReleaseDetailed(cwd = process.cwd(), options = {}) {
|
|
|
224
224
|
message: `Published releases ${published.join(", ")}`,
|
|
225
225
|
};
|
|
226
226
|
}
|
|
227
|
-
/** @deprecated Use runRelease. */
|
|
228
|
-
export async function runSimpleRelease(cwd = process.cwd()) {
|
|
229
|
-
return runRelease(cwd);
|
|
230
|
-
}
|
|
231
|
-
/** @deprecated Use runReleaseDetailed. */
|
|
232
|
-
export async function runSimpleReleaseDetailed(cwd = process.cwd(), options = {}) {
|
|
233
|
-
return runReleaseDetailed(cwd, options);
|
|
234
|
-
}
|
package/dist/release/state.js
CHANGED
|
@@ -49,15 +49,7 @@ export function getBaselineStatePath(cwd) {
|
|
|
49
49
|
if (configured) {
|
|
50
50
|
return path.join(cwd, configured);
|
|
51
51
|
}
|
|
52
|
-
|
|
53
|
-
if (fs.existsSync(preferred)) {
|
|
54
|
-
return preferred;
|
|
55
|
-
}
|
|
56
|
-
const legacy = path.join(cwd, "versionary.versions.json");
|
|
57
|
-
if (fs.existsSync(legacy)) {
|
|
58
|
-
return legacy;
|
|
59
|
-
}
|
|
60
|
-
return preferred;
|
|
52
|
+
return path.join(cwd, ".versionary-manifest.json");
|
|
61
53
|
}
|
|
62
54
|
export function readBaselineSha(cwd = process.cwd()) {
|
|
63
55
|
const filePath = getBaselineStatePath(cwd);
|
|
@@ -80,15 +72,14 @@ export function readReleaseTargets(cwd = process.cwd()) {
|
|
|
80
72
|
}
|
|
81
73
|
// The publish set introduced by the current release PR. `release` consumes this
|
|
82
74
|
// so it only publishes/announces what this PR bumped, not every package in the
|
|
83
|
-
// accumulated baseline.
|
|
84
|
-
// written before this key existed (legacy compatibility).
|
|
75
|
+
// accumulated baseline.
|
|
85
76
|
export function readPendingReleaseTargets(cwd = process.cwd()) {
|
|
86
77
|
const filePath = getBaselineStatePath(cwd);
|
|
87
78
|
if (!fs.existsSync(filePath)) {
|
|
88
79
|
return [];
|
|
89
80
|
}
|
|
90
81
|
const parsed = parseStateFile(fs.readFileSync(filePath, "utf8"), filePath);
|
|
91
|
-
return
|
|
82
|
+
return parsed[PENDING_RELEASE_TARGETS_KEY] ?? [];
|
|
92
83
|
}
|
|
93
84
|
export function writeBaselineSha(cwd = process.cwd(), sha, releaseTargets) {
|
|
94
85
|
const baselineShaValue = sha ??
|
|
@@ -71,6 +71,17 @@ export function compositeVersionStrategy(strategies) {
|
|
|
71
71
|
return primary.readPackageName?.(cwd, config) ?? null;
|
|
72
72
|
};
|
|
73
73
|
}
|
|
74
|
+
if (primary.isPublishable || secondaries.some((s) => s.isPublishable)) {
|
|
75
|
+
composite.isPublishable = (cwd, pkg) => {
|
|
76
|
+
// Only strategies that recognize this package's version file have an
|
|
77
|
+
// opinion; among those, one publishing facet is enough to expose the
|
|
78
|
+
// package on a registry.
|
|
79
|
+
const opinions = [primary, ...secondaries]
|
|
80
|
+
.map((strategy) => strategy.isPublishable?.(cwd, pkg))
|
|
81
|
+
.filter((opinion) => typeof opinion === "boolean");
|
|
82
|
+
return opinions.length === 0 ? undefined : opinions.some(Boolean);
|
|
83
|
+
};
|
|
84
|
+
}
|
|
74
85
|
if (primary.propagateDependentPatchImpacts ||
|
|
75
86
|
secondaries.some((strategy) => strategy.propagateDependentPatchImpacts)) {
|
|
76
87
|
composite.propagateDependentPatchImpacts = (cwd, packages) => {
|
package/dist/strategy/node.js
CHANGED
|
@@ -71,4 +71,19 @@ export const nodeVersionStrategy = {
|
|
|
71
71
|
}
|
|
72
72
|
return name.trim();
|
|
73
73
|
},
|
|
74
|
+
isPublishable(cwd, pkg) {
|
|
75
|
+
if (path.basename(pkg.versionFile) !== "package.json") {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
const versionPath = path.join(cwd, pkg.versionFile);
|
|
79
|
+
if (!fs.existsSync(versionPath)) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
return readJsonFile(versionPath).private !== true;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
},
|
|
74
89
|
};
|
package/dist/strategy/rust.js
CHANGED
|
@@ -253,13 +253,53 @@ function collectRustTargetManifests(cwd, versionFile, includeWorkspaceMembers) {
|
|
|
253
253
|
: `"${versionFile}" has neither [package] nor [workspace].`;
|
|
254
254
|
throw new Error(`Configured rust target "${versionFile}" is not a Rust crate manifest. ${detail} Either remove the "packages" config so the workspace is auto-discovered, or point a package at a member crate path (e.g. "packages": { "crates/foo": {} }).`);
|
|
255
255
|
}
|
|
256
|
-
function
|
|
256
|
+
function isWorkspaceInheritedValue(rawVersion) {
|
|
257
257
|
if (!rawVersion || typeof rawVersion !== "object") {
|
|
258
258
|
return false;
|
|
259
259
|
}
|
|
260
260
|
const versionRecord = rawVersion;
|
|
261
261
|
return versionRecord.workspace === true;
|
|
262
262
|
}
|
|
263
|
+
function isPublishValueUnpublishable(rawPublish) {
|
|
264
|
+
// Cargo treats both `publish = false` and an empty registry list as
|
|
265
|
+
// "never publish"; a non-empty list still reaches a registry.
|
|
266
|
+
return (rawPublish === false ||
|
|
267
|
+
(Array.isArray(rawPublish) && rawPublish.length === 0));
|
|
268
|
+
}
|
|
269
|
+
function readManifestPublishable(cwd, manifest) {
|
|
270
|
+
const manifestPath = path.join(cwd, manifest);
|
|
271
|
+
if (!fs.existsSync(manifestPath)) {
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
274
|
+
const cargoTomlRaw = fs.readFileSync(manifestPath, "utf8");
|
|
275
|
+
let packageTable;
|
|
276
|
+
try {
|
|
277
|
+
({ packageTable } = parseCargoManifest(manifest, cargoTomlRaw));
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
if (!packageTable) {
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
const rawPublish = packageTable.publish;
|
|
286
|
+
if (!isWorkspaceInheritedValue(rawPublish)) {
|
|
287
|
+
return !isPublishValueUnpublishable(rawPublish);
|
|
288
|
+
}
|
|
289
|
+
let workspaceManifest;
|
|
290
|
+
try {
|
|
291
|
+
workspaceManifest = findWorkspaceManifestForMember(cwd, manifest);
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
const workspaceRaw = fs.readFileSync(path.join(cwd, workspaceManifest), "utf8");
|
|
297
|
+
const { workspaceTable } = parseCargoManifest(workspaceManifest, workspaceRaw);
|
|
298
|
+
const workspacePackage = workspaceTable?.package && typeof workspaceTable.package === "object"
|
|
299
|
+
? workspaceTable.package
|
|
300
|
+
: null;
|
|
301
|
+
return !isPublishValueUnpublishable(workspacePackage?.publish);
|
|
302
|
+
}
|
|
263
303
|
function readWorkspacePackageVersion(cargoTomlRaw, versionFile) {
|
|
264
304
|
const { workspaceTable } = parseCargoManifest(versionFile, cargoTomlRaw);
|
|
265
305
|
if (!workspaceTable || typeof workspaceTable !== "object") {
|
|
@@ -314,7 +354,7 @@ function readResolvedCargoVersion(cwd, manifest, cargoTomlRaw) {
|
|
|
314
354
|
if (typeof rawVersion === "string" && rawVersion.trim().length > 0) {
|
|
315
355
|
return rawVersion.trim();
|
|
316
356
|
}
|
|
317
|
-
if (!
|
|
357
|
+
if (!isWorkspaceInheritedValue(rawVersion)) {
|
|
318
358
|
throw new Error(`${manifest} has invalid [package].version. Expected a non-empty SemVer string or version.workspace = true.`);
|
|
319
359
|
}
|
|
320
360
|
const workspaceManifest = findWorkspaceManifestForMember(cwd, manifest);
|
|
@@ -425,7 +465,7 @@ function usesWorkspaceInheritedVersion(cargoTomlRaw, versionFile) {
|
|
|
425
465
|
return false;
|
|
426
466
|
}
|
|
427
467
|
const rawVersion = packageTable.version;
|
|
428
|
-
return
|
|
468
|
+
return isWorkspaceInheritedValue(rawVersion);
|
|
429
469
|
}
|
|
430
470
|
function isDependencySection(section) {
|
|
431
471
|
if (ROOT_DEPENDENCY_SECTIONS.has(section)) {
|
|
@@ -733,6 +773,13 @@ export const rustVersionStrategy = {
|
|
|
733
773
|
}
|
|
734
774
|
return readCargoPackageName(cargoTomlRaw, selectedManifest);
|
|
735
775
|
},
|
|
776
|
+
isPublishable(cwd, pkg) {
|
|
777
|
+
const manifest = normalizeSlashPath(pkg.versionFile);
|
|
778
|
+
if (path.posix.basename(manifest) !== "Cargo.toml") {
|
|
779
|
+
return undefined;
|
|
780
|
+
}
|
|
781
|
+
return readManifestPublishable(cwd, manifest);
|
|
782
|
+
},
|
|
736
783
|
propagateDependentPatchImpacts(cwd, packages) {
|
|
737
784
|
const manifestToVersion = {};
|
|
738
785
|
const candidateManifests = [];
|
package/dist/strategy/types.d.ts
CHANGED
|
@@ -22,6 +22,17 @@ export interface VersionStrategy {
|
|
|
22
22
|
writeVersion(cwd: string, config: VersionaryConfig, version: string): string[];
|
|
23
23
|
validateProject?(cwd: string, config: VersionaryConfig): string | null;
|
|
24
24
|
readPackageName?(cwd: string, config: VersionaryConfig): string | null;
|
|
25
|
+
/**
|
|
26
|
+
* Whether this package is published to a registry. A package that never
|
|
27
|
+
* reaches a registry cannot leave a stale published copy behind, so release
|
|
28
|
+
* planning exempts it from published-dependency freshness enforcement.
|
|
29
|
+
*
|
|
30
|
+
* Returns `undefined` to abstain, which a strategy must do for a version
|
|
31
|
+
* file it does not recognize — otherwise, composed with another strategy, it
|
|
32
|
+
* would outvote the one that actually owns the manifest. Strategies that
|
|
33
|
+
* omit this hook entirely are assumed to publish everything.
|
|
34
|
+
*/
|
|
35
|
+
isPublishable?(cwd: string, pkg: StrategyPackagePlanContext): boolean | undefined;
|
|
25
36
|
propagateDependentPatchImpacts?(cwd: string, packages: StrategyPackagePlanContext[]): string[];
|
|
26
37
|
finalizeVersionWrites?(cwd: string, writes: StrategyVersionWriteContext[], context: StrategyFinalizeContext): string[];
|
|
27
38
|
}
|
package/dist/types/config.d.ts
CHANGED
|
@@ -5,8 +5,8 @@ export interface VersionaryArtifactRule {
|
|
|
5
5
|
type: "json" | "toml" | "yaml" | "nix" | "regex";
|
|
6
6
|
path: string;
|
|
7
7
|
"field-path"?: string;
|
|
8
|
-
jsonpath?: string;
|
|
9
8
|
pattern?: string;
|
|
9
|
+
replacement?: string;
|
|
10
10
|
}
|
|
11
11
|
export interface VersionaryPackage {
|
|
12
12
|
"release-type"?: string | string[];
|
|
@@ -20,7 +20,7 @@ export interface VersionaryPackage {
|
|
|
20
20
|
}
|
|
21
21
|
export interface VersionaryConfig {
|
|
22
22
|
version: 1;
|
|
23
|
-
"review-mode"?: "direct" | "pr"
|
|
23
|
+
"review-mode"?: "direct" | "pr";
|
|
24
24
|
"version-file"?: string;
|
|
25
25
|
"changelog-file"?: string;
|
|
26
26
|
"changelog-format"?: VersionaryChangelogFormat;
|
|
@@ -28,7 +28,6 @@ export interface VersionaryConfig {
|
|
|
28
28
|
"release-reference-comments"?: ReleaseReferenceCommentsMode;
|
|
29
29
|
"release-branch"?: string;
|
|
30
30
|
"baseline-file"?: string;
|
|
31
|
-
"next-release-file"?: string;
|
|
32
31
|
"bootstrap-sha"?: string;
|
|
33
32
|
"monorepo-mode"?: "independent" | "fixed";
|
|
34
33
|
"bump-minor-pre-major"?: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "versionary",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Automatic release framework based on conventional commits and semantic versioning",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"releasing",
|
|
@@ -27,16 +27,18 @@
|
|
|
27
27
|
"main": "dist/index.js",
|
|
28
28
|
"types": "dist/index.d.ts",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"smol-toml": "^1.4.2",
|
|
31
30
|
"@octokit/rest": "^22.0.0",
|
|
32
31
|
"jsonc-parser": "^3.3.1",
|
|
32
|
+
"smol-toml": "^1.4.2",
|
|
33
33
|
"yaml": "^2.8.3",
|
|
34
34
|
"zod": "^4.1.12"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@types/node": "^
|
|
37
|
+
"@types/node": "^26.0.1",
|
|
38
38
|
"tsx": "^4.20.6",
|
|
39
|
-
"typescript": "^
|
|
39
|
+
"typescript": "^7.0.2",
|
|
40
|
+
"vite": "^8.0.0",
|
|
41
|
+
"vitepress": "^1.6.4",
|
|
40
42
|
"vitest": "^4.1.4"
|
|
41
43
|
},
|
|
42
44
|
"scripts": {
|
|
@@ -49,6 +51,9 @@
|
|
|
49
51
|
"plan": "tsx src/cli/index.ts plan",
|
|
50
52
|
"changelog": "tsx src/cli/index.ts changelog",
|
|
51
53
|
"pr": "tsx src/cli/index.ts pr",
|
|
52
|
-
"release": "tsx src/cli/index.ts release"
|
|
54
|
+
"release": "tsx src/cli/index.ts release",
|
|
55
|
+
"docs:dev": "vitepress dev docs",
|
|
56
|
+
"docs:build": "vitepress build docs",
|
|
57
|
+
"docs:preview": "vitepress preview docs"
|
|
53
58
|
}
|
|
54
59
|
}
|