relacher 0.0.7-rc.4 → 0.0.7
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/lib-types/builder/shared.d.ts +9 -5
- package/lib-types/lockfile.d.ts +1 -1
- package/package.json +1 -1
- package/src/builder/shared.ts +20 -5
- package/src/lockfile.ts +21 -9
- package/src/prepare.ts +10 -27
- package/src/versioning/vcs-version-manager.ts +10 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ChangelogContext, PackageConfig } from '../types';
|
|
2
2
|
import { type UpdateAction, type VersionFallback } from '../updater';
|
|
3
|
+
import type { BumpSize } from '../versioning/types';
|
|
3
4
|
export interface PackageListError {
|
|
4
5
|
name: string;
|
|
5
6
|
message: string;
|
|
@@ -11,31 +12,34 @@ export declare class PackageList extends Array<PackageConfig> {
|
|
|
11
12
|
onPackageBump(name: string, ...actions: UpdateAction[]): this;
|
|
12
13
|
onAllPackages(...actions: UpdateAction[]): this;
|
|
13
14
|
group(groupName: string, ...packageNames: string[]): this;
|
|
14
|
-
/**
|
|
15
|
-
* Couples two or more packages together so they share the exact same version bump.
|
|
16
|
-
* Supports: `.couple('a', 'b')` or `.couple(['a', 'b'], ['c', 'd'])`.
|
|
17
|
-
*/
|
|
18
15
|
couple(...args: [string, string] | [string[]]): this;
|
|
19
16
|
/**
|
|
20
17
|
* Automatically adds a CHANGELOG.md update action to each package's directory.
|
|
18
|
+
* Defaults to onlyOn: ['major', 'minor', 'patch'] so pre-releases are skipped.
|
|
21
19
|
*/
|
|
22
20
|
withChangelogs(options?: {
|
|
23
21
|
only?: string[];
|
|
24
22
|
exclude?: string[];
|
|
23
|
+
onlyOn?: BumpSize[];
|
|
25
24
|
template?: (ctx: ChangelogContext) => string;
|
|
26
25
|
}): this;
|
|
27
26
|
/**
|
|
28
27
|
* Attaches a workspace-wide root CHANGELOG.md that captures all changes across packages.
|
|
28
|
+
* Defaults to onlyOn: ['major', 'minor', 'patch'] so pre-releases are skipped.
|
|
29
29
|
*/
|
|
30
30
|
withRootChangelog(options?: {
|
|
31
31
|
github?: string;
|
|
32
32
|
path?: string;
|
|
33
|
+
onlyOn?: BumpSize[];
|
|
33
34
|
template?: (ctx: ChangelogContext) => string;
|
|
34
35
|
}): this;
|
|
35
36
|
/**
|
|
36
37
|
* Declaratively syncs a package version to any file on disk (e.g. `flake.nix`, `README.md`).
|
|
38
|
+
* Supports `options.onlyOn` to restrict updates to specific bump types.
|
|
37
39
|
*/
|
|
38
|
-
syncVersion(packageName: string, filePath: string, pattern?: string | RegExp, replaceTemplate?: string
|
|
40
|
+
syncVersion(packageName: string, filePath: string, pattern?: string | RegExp, replaceTemplate?: string, options?: {
|
|
41
|
+
onlyOn?: BumpSize[];
|
|
42
|
+
}): this;
|
|
39
43
|
assertFound(...names: string[]): this;
|
|
40
44
|
addDepsOn(pkgName: string, dependsOn: string | string[]): this;
|
|
41
45
|
ignore(...names: string[]): this;
|
package/lib-types/lockfile.d.ts
CHANGED
|
@@ -12,4 +12,4 @@ export declare const LOCKFILE_NAME = ".relacher.lock";
|
|
|
12
12
|
export declare function readLockfile(cwd: string): LockfileData;
|
|
13
13
|
export declare function writeLockfile(cwd: string, data: LockfileData): void;
|
|
14
14
|
export declare function updateLockfile(cwd: string, reports: DependencyUpdateReport[]): void;
|
|
15
|
-
export declare function findLastReleaseCommit(vcs: VcsProvider, packageName: string,
|
|
15
|
+
export declare function findLastReleaseCommit(vcs: VcsProvider, packageName: string, targetVersion: string): Effect.Effect<string | null, VcsError>;
|
package/package.json
CHANGED
package/src/builder/shared.ts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
|
|
3
3
|
import type { ChangelogContext, PackageConfig } from '../types';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
changelogUpdate,
|
|
6
|
+
githubChangelogTemplate,
|
|
7
|
+
regexUpdate,
|
|
8
|
+
type UpdateAction,
|
|
9
|
+
type VersionFallback,
|
|
10
|
+
} from '../updater';
|
|
11
|
+
import type { BumpSize } from '../versioning/types';
|
|
5
12
|
|
|
6
13
|
export interface PackageListError {
|
|
7
14
|
name: string;
|
|
@@ -70,10 +77,6 @@ export class PackageList extends Array<PackageConfig> {
|
|
|
70
77
|
return this;
|
|
71
78
|
}
|
|
72
79
|
|
|
73
|
-
/**
|
|
74
|
-
* Couples two or more packages together so they share the exact same version bump.
|
|
75
|
-
* Supports: `.couple('a', 'b')` or `.couple(['a', 'b'], ['c', 'd'])`.
|
|
76
|
-
*/
|
|
77
80
|
public couple(...args: [string, string] | [string[]]): this {
|
|
78
81
|
if (Array.isArray(args[0])) {
|
|
79
82
|
for (const groupMembers of args as string[][]) {
|
|
@@ -87,12 +90,16 @@ export class PackageList extends Array<PackageConfig> {
|
|
|
87
90
|
|
|
88
91
|
/**
|
|
89
92
|
* Automatically adds a CHANGELOG.md update action to each package's directory.
|
|
93
|
+
* Defaults to onlyOn: ['major', 'minor', 'patch'] so pre-releases are skipped.
|
|
90
94
|
*/
|
|
91
95
|
public withChangelogs(options?: {
|
|
92
96
|
only?: string[];
|
|
93
97
|
exclude?: string[];
|
|
98
|
+
onlyOn?: BumpSize[];
|
|
94
99
|
template?: (ctx: ChangelogContext) => string;
|
|
95
100
|
}): this {
|
|
101
|
+
const onlyOn = options?.onlyOn ?? ['major', 'minor', 'patch'];
|
|
102
|
+
|
|
96
103
|
for (const pkg of this) {
|
|
97
104
|
if (options?.only && !options.only.includes(pkg.name)) continue;
|
|
98
105
|
if (options?.exclude && options.exclude.includes(pkg.name)) continue;
|
|
@@ -103,6 +110,7 @@ export class PackageList extends Array<PackageConfig> {
|
|
|
103
110
|
this.onPackageBump(
|
|
104
111
|
pkg.name,
|
|
105
112
|
changelogUpdate(changelogPath, {
|
|
113
|
+
onlyOn,
|
|
106
114
|
template: options?.template,
|
|
107
115
|
}),
|
|
108
116
|
);
|
|
@@ -112,18 +120,22 @@ export class PackageList extends Array<PackageConfig> {
|
|
|
112
120
|
|
|
113
121
|
/**
|
|
114
122
|
* Attaches a workspace-wide root CHANGELOG.md that captures all changes across packages.
|
|
123
|
+
* Defaults to onlyOn: ['major', 'minor', 'patch'] so pre-releases are skipped.
|
|
115
124
|
*/
|
|
116
125
|
public withRootChangelog(options?: {
|
|
117
126
|
github?: string;
|
|
118
127
|
path?: string;
|
|
128
|
+
onlyOn?: BumpSize[];
|
|
119
129
|
template?: (ctx: ChangelogContext) => string;
|
|
120
130
|
}): this {
|
|
121
131
|
const changelogPath = options?.path || 'CHANGELOG.md';
|
|
122
132
|
const template = options?.template ?? (options?.github ? githubChangelogTemplate(options.github) : undefined);
|
|
133
|
+
const onlyOn = options?.onlyOn ?? ['major', 'minor', 'patch'];
|
|
123
134
|
|
|
124
135
|
this.onAllPackages(
|
|
125
136
|
changelogUpdate(changelogPath, {
|
|
126
137
|
global: true,
|
|
138
|
+
onlyOn,
|
|
127
139
|
template,
|
|
128
140
|
}),
|
|
129
141
|
);
|
|
@@ -132,12 +144,14 @@ export class PackageList extends Array<PackageConfig> {
|
|
|
132
144
|
|
|
133
145
|
/**
|
|
134
146
|
* Declaratively syncs a package version to any file on disk (e.g. `flake.nix`, `README.md`).
|
|
147
|
+
* Supports `options.onlyOn` to restrict updates to specific bump types.
|
|
135
148
|
*/
|
|
136
149
|
public syncVersion(
|
|
137
150
|
packageName: string,
|
|
138
151
|
filePath: string,
|
|
139
152
|
pattern: string | RegExp = 'version = "[^"]+"',
|
|
140
153
|
replaceTemplate = 'version = "{{version}}"',
|
|
154
|
+
options?: { onlyOn?: BumpSize[] },
|
|
141
155
|
): this {
|
|
142
156
|
const search = typeof pattern === 'string' ? pattern : pattern.source;
|
|
143
157
|
return this.onPackageBump(
|
|
@@ -145,6 +159,7 @@ export class PackageList extends Array<PackageConfig> {
|
|
|
145
159
|
regexUpdate(filePath, {
|
|
146
160
|
search,
|
|
147
161
|
replace: replaceTemplate,
|
|
162
|
+
onlyOn: options?.onlyOn,
|
|
148
163
|
}),
|
|
149
164
|
);
|
|
150
165
|
}
|
package/src/lockfile.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { Effect } from 'effect';
|
|
|
5
5
|
|
|
6
6
|
import type { DependencyUpdateReport } from './types';
|
|
7
7
|
import type { VcsError, VcsProvider } from './vcs';
|
|
8
|
+
import { inferLastStableVersion } from './versioning/semver';
|
|
8
9
|
|
|
9
10
|
export interface LockfilePackageEntry {
|
|
10
11
|
version: string;
|
|
@@ -44,7 +45,14 @@ export function updateLockfile(cwd: string, reports: DependencyUpdateReport[]):
|
|
|
44
45
|
const isPrerelease = dep.newVersion.includes('-');
|
|
45
46
|
const previousEntry = lockfile.packages[dep.name];
|
|
46
47
|
|
|
47
|
-
let lastStable =
|
|
48
|
+
let lastStable =
|
|
49
|
+
previousEntry?.lastStableVersion ||
|
|
50
|
+
previousEntry?.version ||
|
|
51
|
+
dep.lastStableVersion ||
|
|
52
|
+
(dep.currentVersion && !dep.currentVersion.includes('-')
|
|
53
|
+
? dep.currentVersion
|
|
54
|
+
: inferLastStableVersion(dep.currentVersion));
|
|
55
|
+
|
|
48
56
|
if (!isPrerelease) {
|
|
49
57
|
lastStable = dep.newVersion;
|
|
50
58
|
}
|
|
@@ -61,7 +69,7 @@ export function updateLockfile(cwd: string, reports: DependencyUpdateReport[]):
|
|
|
61
69
|
export function findLastReleaseCommit(
|
|
62
70
|
vcs: VcsProvider,
|
|
63
71
|
packageName: string,
|
|
64
|
-
|
|
72
|
+
targetVersion: string,
|
|
65
73
|
): Effect.Effect<string | null, VcsError> {
|
|
66
74
|
return Effect.gen(function* () {
|
|
67
75
|
if (!vcs.getFileHistoryCommits || !vcs.getFileAtCommit) {
|
|
@@ -71,8 +79,10 @@ export function findLastReleaseCommit(
|
|
|
71
79
|
const hashes = yield* vcs.getFileHistoryCommits(LOCKFILE_NAME);
|
|
72
80
|
if (hashes.length === 0) return null;
|
|
73
81
|
|
|
74
|
-
let
|
|
82
|
+
let foundMatch = false;
|
|
83
|
+
let earliestMatchingHash: string | null = null;
|
|
75
84
|
|
|
85
|
+
// Hashes are ordered from newest to oldest
|
|
76
86
|
for (const hash of hashes) {
|
|
77
87
|
const content = yield* vcs.getFileAtCommit(LOCKFILE_NAME, hash);
|
|
78
88
|
if (!content) continue;
|
|
@@ -81,16 +91,18 @@ export function findLastReleaseCommit(
|
|
|
81
91
|
const data = JSON.parse(content) as LockfileData;
|
|
82
92
|
const version = data.packages?.[packageName]?.version;
|
|
83
93
|
|
|
84
|
-
if (version ===
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
94
|
+
if (version === targetVersion) {
|
|
95
|
+
foundMatch = true;
|
|
96
|
+
earliestMatchingHash = hash;
|
|
97
|
+
} else if (foundMatch) {
|
|
98
|
+
// Reached an older version before targetVersion was introduced
|
|
99
|
+
return earliestMatchingHash;
|
|
88
100
|
}
|
|
89
101
|
} catch {
|
|
90
|
-
return
|
|
102
|
+
if (foundMatch) return earliestMatchingHash;
|
|
91
103
|
}
|
|
92
104
|
}
|
|
93
105
|
|
|
94
|
-
return
|
|
106
|
+
return earliestMatchingHash;
|
|
95
107
|
}) as Effect.Effect<string | null, VcsError>;
|
|
96
108
|
}
|
package/src/prepare.ts
CHANGED
|
@@ -14,7 +14,7 @@ import type {
|
|
|
14
14
|
PrepareOptions,
|
|
15
15
|
} from './types';
|
|
16
16
|
import type { UpdateAction, UpdateActionResolved } from './updater';
|
|
17
|
-
import { VcsProviderService
|
|
17
|
+
import { VcsProviderService } from './vcs';
|
|
18
18
|
import { VersionManagerService, type VersionManager } from './versioning';
|
|
19
19
|
import { isBumpEqual, isPreRelease } from './versioning/bump';
|
|
20
20
|
import type { BumpSize } from './versioning/types';
|
|
@@ -116,6 +116,13 @@ export function initReportItems(
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
let selfBump = versionManager.evaluateCommitsBump(commitsSincePreRelease);
|
|
119
|
+
|
|
120
|
+
// If graduating an existing pre-release to stable (e.g. 1.1.0-rc.0 -> 1.1.0),
|
|
121
|
+
// ensure it is never skipped even if no new commits were added after the RC was cut.
|
|
122
|
+
if (!versionManager.isRCMode && actualVersion.includes('-') && selfBump === 'skip') {
|
|
123
|
+
selfBump = 'patch';
|
|
124
|
+
}
|
|
125
|
+
|
|
119
126
|
selfBump = resolvePackageBump(dep.name, selfBump, options);
|
|
120
127
|
|
|
121
128
|
let isErroneous = isMissingVersion;
|
|
@@ -177,32 +184,8 @@ export function prepare(
|
|
|
177
184
|
|
|
178
185
|
const cwd = options.cwd || process.cwd();
|
|
179
186
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const vcs: VcsProvider = vcsOption.value;
|
|
183
|
-
if (typeof vcs.isTracked === 'function') {
|
|
184
|
-
const filtered: PackageConfig[] = [];
|
|
185
|
-
for (const pkg of packages) {
|
|
186
|
-
// Use relative path directly rather than resolving to absolute
|
|
187
|
-
const targetPath = pkg.manifestPath || pkg.watch?.[0] || '.';
|
|
188
|
-
|
|
189
|
-
const isTracked = yield* vcs.isTracked(targetPath);
|
|
190
|
-
if (isTracked) {
|
|
191
|
-
filtered.push(pkg);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
trackedPackages = filtered;
|
|
195
|
-
|
|
196
|
-
const activeNames = new Set(trackedPackages.map((p) => p.name));
|
|
197
|
-
for (const pkg of trackedPackages) {
|
|
198
|
-
if (pkg.depends) {
|
|
199
|
-
pkg.depends = pkg.depends.filter((d) => activeNames.has(d));
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const items = yield* initReportItems(trackedPackages, cwd, options);
|
|
187
|
+
// Packages passed in were already validated and tracked by the builder.
|
|
188
|
+
const items = yield* initReportItems(packages, cwd, options);
|
|
206
189
|
const sorted = topologicalSort(items);
|
|
207
190
|
versionManager.propagateBumps(sorted);
|
|
208
191
|
versionManager.propagateCoupledBumps(sorted);
|
|
@@ -104,10 +104,18 @@ export const makeVcsVersionManager = (
|
|
|
104
104
|
return vcs.getCommits(dep.watch || [], null, excludePaths);
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
// In stable release mode, if the package was in pre-release (e.g. 1.1.0-rc.0),
|
|
108
|
+
// we query commits since the last STABLE version (e.g. 1.0.0) so that all commits
|
|
109
|
+
// developed during the RC cycle are included in the final changelog and bump.
|
|
110
|
+
const targetVersion =
|
|
111
|
+
!isRCMode && lockVersion.includes('-') && entry?.lastStableVersion
|
|
112
|
+
? entry.lastStableVersion
|
|
113
|
+
: lockVersion;
|
|
114
|
+
|
|
107
115
|
const findCommitEffect =
|
|
108
116
|
typeof vcs.findLastReleaseCommit === 'function'
|
|
109
|
-
? vcs.findLastReleaseCommit(dep.name,
|
|
110
|
-
: findLastReleaseCommit(vcs, dep.name,
|
|
117
|
+
? vcs.findLastReleaseCommit(dep.name, targetVersion)
|
|
118
|
+
: findLastReleaseCommit(vcs, dep.name, targetVersion);
|
|
111
119
|
|
|
112
120
|
return findCommitEffect.pipe(
|
|
113
121
|
Effect.flatMap((lastCommit) =>
|