relacher 0.0.7-rc.0 → 0.0.7-rc.2

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.
@@ -1,4 +1,5 @@
1
1
  import { type PackageList } from './shared';
2
2
  export interface CargoBuilderOptions {
3
+ includePrivate?: boolean;
3
4
  }
4
- export declare function loadCargoDeps(cwd: string, _options?: CargoBuilderOptions): PackageList;
5
+ export declare function loadCargoDeps(cwd: string, options?: CargoBuilderOptions): PackageList;
@@ -1,44 +1,29 @@
1
1
  import { type PackageList } from './builder';
2
2
  import type { PreparedUpdate } from './types';
3
3
  import { type VcsProvider } from './vcs';
4
- import { type CascadeRules, type SizePatterns } from './versioning';
4
+ import { type CascadeRules, type SizePatterns, type BumpSize } from './versioning';
5
5
  export interface RelacherConfig {
6
- /** Project root directory. Defaults to `process.cwd()` */
7
6
  cwd?: string;
8
- /** Discovered packages list */
9
7
  packages: PackageList;
10
- /** VCS Provider: 'git', 'jj', or custom VcsProvider. Defaults to auto-detection */
11
8
  vcs?: 'git' | 'jj' | VcsProvider;
12
- /** Custom RC identifier (default: 'rc') */
13
9
  rcIdentifier?: string;
14
- /** Custom Conventional Commit patterns */
15
10
  sizes?: SizePatterns;
16
- /** Dependency bump cascade rules */
17
11
  cascade?: CascadeRules;
18
- /** Exclude nested watch paths from parent bumps (default: true) */
19
12
  excludeNestedWatches?: boolean;
20
- /** Custom commit title callback */
13
+ /** Force a bump size across all packages (e.g. true for patch, or 'minor' / 'major') */
14
+ force?: boolean | BumpSize;
15
+ /** Selectively force bump sizes for specific packages */
16
+ forcePackages?: Record<string, BumpSize>;
21
17
  commitTitle?: (bumps: Record<string, string>, defaultTitle: string) => string;
22
18
  }
23
19
  export declare function createRelacher(config: RelacherConfig): {
24
20
  vcs: VcsProvider;
25
- /**
26
- * Initializes `.relacher.lock` and creates the baseline commit.
27
- */
28
21
  init(): Promise<void>;
29
- /**
30
- * Previews and calculates pending version bumps without writing changes.
31
- */
32
22
  prepare(options?: {
33
23
  mode?: "release" | "pre-release";
24
+ force?: boolean | BumpSize;
25
+ forcePackages?: Record<string, BumpSize>;
34
26
  }): Promise<PreparedUpdate>;
35
- /**
36
- * Writes planned updates to disk and commits via VCS.
37
- */
38
27
  run(prepared: PreparedUpdate): Promise<void>;
39
- /**
40
- * Full interactive CLI entry point.
41
- * Handles arguments, preflight logs, confirmation prompts, dry-runs, and execution.
42
- */
43
28
  cli(argv?: string[]): Promise<void>;
44
29
  };
@@ -6,7 +6,7 @@ import type { BumpSize } from './versioning/types';
6
6
  export declare function isBumpSizeMatch(actual: BumpSize, pattern: BumpSize): boolean;
7
7
  export declare function isUpdateActive(bump: BumpSize, onlyOn?: BumpSize[]): boolean;
8
8
  export declare function topologicalSort(items: IntermediateReport[]): IntermediateReport[];
9
- export declare function initReportItems(packages: PackageConfig[], cwd: string, excludeNestedWatches?: boolean): Effect.Effect<IntermediateReport[], Error, VersionManager>;
9
+ export declare function initReportItems(packages: PackageConfig[], cwd: string, options?: PrepareOptions): Effect.Effect<IntermediateReport[], Error, VersionManager>;
10
10
  export declare function prepare(packages: PackageConfig[] & {
11
11
  errors?: Array<{
12
12
  name: string;
@@ -27,6 +27,14 @@ export interface PackageConfig {
27
27
  coupled?: string[];
28
28
  group?: string;
29
29
  }
30
+ export interface PrepareOptions {
31
+ cwd?: string;
32
+ excludeNestedWatches?: boolean;
33
+ /** Force a bump size across all packages (e.g. true for patch, or 'minor' / 'major') */
34
+ force?: boolean | BumpSize;
35
+ /** Selectively force bump sizes for specific packages */
36
+ forcePackages?: Record<string, BumpSize>;
37
+ }
30
38
  export interface PrepareOptions {
31
39
  cwd?: string;
32
40
  excludeNestedWatches?: boolean;
@@ -0,0 +1,13 @@
1
+ import type { BumpSize, PreRelease } from './types';
2
+ /**
3
+ * Type guard for pre-release bump objects.
4
+ */
5
+ export declare function isPreRelease(val: unknown): val is PreRelease;
6
+ /**
7
+ * Numeric priority for bump sizes: major (4) > minor (3) > patch (2) > pre (1) > skip (0).
8
+ */
9
+ export declare function getBumpPriority(bump: BumpSize): number;
10
+ export declare function isBumpGreater(a: BumpSize, b: BumpSize): boolean;
11
+ export declare function maxBump(a: BumpSize, b: BumpSize): BumpSize;
12
+ export declare function isBumpEqual(a: BumpSize, b: BumpSize): boolean;
13
+ export declare function getBumpByPriority(priority: number, fallbackPre?: PreRelease): BumpSize;
@@ -1,4 +1,6 @@
1
1
  export * from './types';
2
+ export * from './bump';
3
+ export * from './semver';
2
4
  export * from './utils';
3
5
  export * from './default-data';
4
6
  export * from './vcs-version-manager';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relacher",
3
- "version": "0.0.7-rc.0",
3
+ "version": "0.0.7-rc.2",
4
4
  "description": "Scriptable release orchestration library for monorepos",
5
5
  "type": "module",
6
6
  "private": false,
@@ -9,7 +9,9 @@ import { isPathTrackedSync } from '../vcs/common';
9
9
 
10
10
  import { createPackageList, type PackageList } from './shared';
11
11
 
12
- export interface CargoBuilderOptions {}
12
+ export interface CargoBuilderOptions {
13
+ includePrivate?: boolean;
14
+ }
13
15
 
14
16
  interface PathDep {
15
17
  name: string;
@@ -250,7 +252,7 @@ function buildCrateConfig(
250
252
  };
251
253
  }
252
254
 
253
- export function loadCargoDeps(cwd: string, _options?: CargoBuilderOptions): PackageList {
255
+ export function loadCargoDeps(cwd: string, options?: CargoBuilderOptions): PackageList {
254
256
  const workspaceRoot = findCargoWorkspaceRoot(cwd);
255
257
  const rootCargo = path.join(workspaceRoot, 'Cargo.toml');
256
258
  if (!fs.existsSync(rootCargo)) return createPackageList([]);
@@ -265,9 +267,12 @@ export function loadCargoDeps(cwd: string, _options?: CargoBuilderOptions): Pack
265
267
  const hasLock = fs.existsSync(path.join(workspaceRoot, 'Cargo.lock'));
266
268
 
267
269
  const publishableTracked = scanner.crateInfos.filter((info) => {
268
- const publishVal = info.doc?.package?.publish;
269
- if (publishVal === false) return false;
270
- if (Array.isArray(publishVal) && publishVal.length === 0) return false;
270
+ // Respect includePrivate flag (defaults to false)
271
+ if (!options?.includePrivate) {
272
+ const publishVal = info.doc?.package?.publish;
273
+ if (publishVal === false) return false;
274
+ if (Array.isArray(publishVal) && publishVal.length === 0) return false;
275
+ }
271
276
 
272
277
  const cargoPath = path.join(info.memberPath, 'Cargo.toml');
273
278
  return isPathTrackedSync(cargoPath, workspaceRoot);
@@ -82,6 +82,7 @@ export function prettyPrint(prepared: PreparedUpdate): void {
82
82
  );
83
83
  console.log(` ${files.join(' ')}`);
84
84
 
85
+ // 1. Show commits
85
86
  for (const commit of report.commits) {
86
87
  const commitBump = matchBumpSize(commit.message, defaultSizes);
87
88
  const marker = commitBump !== 'skip' ? `${c.green('✦')}` : `${c.gray('○')}`;
@@ -90,6 +91,7 @@ export function prettyPrint(prepared: PreparedUpdate): void {
90
91
  );
91
92
  }
92
93
 
94
+ // 2. Show Cascades
93
95
  const changedDeps = prepared.deps.filter(
94
96
  (r) => report.depends?.includes(r.name) && r.currentVersion !== r.newVersion,
95
97
  );
@@ -107,6 +109,11 @@ export function prettyPrint(prepared: PreparedUpdate): void {
107
109
  );
108
110
  }
109
111
 
112
+ // 3. Fallback for forced releases with no commits and no cascades
113
+ if (report.commits.length === 0 && changedDeps.length === 0) {
114
+ console.log(` ${c.gray('○ (forced release - no new commits)')}`);
115
+ }
116
+
110
117
  console.log('');
111
118
  }
112
119
  }
@@ -13,35 +13,31 @@ import { makeGitVcsProvider, makeJjVcsProvider, VcsProviderService, type VcsProv
13
13
  import { isInsideJjWorkTree } from './vcs/common';
14
14
  import {
15
15
  makeRCVersionManager,
16
- makeVcsVersionManager,
17
16
  VersionManagerService,
18
17
  type CascadeRules,
19
18
  type SizePatterns,
19
+ type BumpSize,
20
20
  } from './versioning';
21
21
 
22
+ // Replace lines 20-35 in src/orchestrator.ts:
22
23
  export interface RelacherConfig {
23
- /** Project root directory. Defaults to `process.cwd()` */
24
24
  cwd?: string;
25
- /** Discovered packages list */
26
25
  packages: PackageList;
27
- /** VCS Provider: 'git', 'jj', or custom VcsProvider. Defaults to auto-detection */
28
26
  vcs?: 'git' | 'jj' | VcsProvider;
29
- /** Custom RC identifier (default: 'rc') */
30
27
  rcIdentifier?: string;
31
- /** Custom Conventional Commit patterns */
32
28
  sizes?: SizePatterns;
33
- /** Dependency bump cascade rules */
34
29
  cascade?: CascadeRules;
35
- /** Exclude nested watch paths from parent bumps (default: true) */
36
30
  excludeNestedWatches?: boolean;
37
- /** Custom commit title callback */
31
+ /** Force a bump size across all packages (e.g. true for patch, or 'minor' / 'major') */
32
+ force?: boolean | BumpSize;
33
+ /** Selectively force bump sizes for specific packages */
34
+ forcePackages?: Record<string, BumpSize>;
38
35
  commitTitle?: (bumps: Record<string, string>, defaultTitle: string) => string;
39
36
  }
40
37
 
41
38
  export function createRelacher(config: RelacherConfig) {
42
39
  const cwd = config.cwd || process.cwd();
43
40
 
44
- // 1. Resolve VCS Provider
45
41
  let vcs: VcsProvider;
46
42
  if (config.vcs && typeof config.vcs === 'object') {
47
43
  vcs = config.vcs;
@@ -50,11 +46,9 @@ export function createRelacher(config: RelacherConfig) {
50
46
  } else if (config.vcs === 'jj') {
51
47
  vcs = makeJjVcsProvider(cwd);
52
48
  } else {
53
- // Auto-detect JJ or fallback to Git
54
49
  vcs = isInsideJjWorkTree(cwd) ? makeJjVcsProvider(cwd) : makeGitVcsProvider(cwd);
55
50
  }
56
51
 
57
- // 2. Factory for Version Manager
58
52
  const createVM = (mode: 'release' | 'pre-release') => {
59
53
  return makeRCVersionManager(vcs, {
60
54
  upgradeReady: mode === 'release',
@@ -67,9 +61,6 @@ export function createRelacher(config: RelacherConfig) {
67
61
  return {
68
62
  vcs,
69
63
 
70
- /**
71
- * Initializes `.relacher.lock` and creates the baseline commit.
72
- */
73
64
  async init(): Promise<void> {
74
65
  const program = init(config.packages, { cwd }).pipe(
75
66
  Effect.provideService(VcsProviderService, vcs),
@@ -77,16 +68,22 @@ export function createRelacher(config: RelacherConfig) {
77
68
  return Effect.runPromise(program);
78
69
  },
79
70
 
80
- /**
81
- * Previews and calculates pending version bumps without writing changes.
82
- */
83
- async prepare(options: { mode?: 'release' | 'pre-release' } = {}): Promise<PreparedUpdate> {
71
+
72
+ async prepare(
73
+ options: {
74
+ mode?: 'release' | 'pre-release';
75
+ force?: boolean | BumpSize;
76
+ forcePackages?: Record<string, BumpSize>;
77
+ } = {},
78
+ ): Promise<PreparedUpdate> {
84
79
  const mode = options.mode || 'release';
85
80
  const vm = createVM(mode);
86
81
 
87
82
  const program = prepare(config.packages, {
88
83
  cwd,
89
84
  excludeNestedWatches: config.excludeNestedWatches ?? true,
85
+ force: options.force ?? config.force,
86
+ forcePackages: options.forcePackages ?? config.forcePackages,
90
87
  }).pipe(
91
88
  Effect.provideService(VersionManagerService, vm),
92
89
  Effect.provideService(VcsProviderService, vcs),
@@ -94,10 +91,6 @@ export function createRelacher(config: RelacherConfig) {
94
91
 
95
92
  return Effect.runPromise(program);
96
93
  },
97
-
98
- /**
99
- * Writes planned updates to disk and commits via VCS.
100
- */
101
94
  async run(prepared: PreparedUpdate): Promise<void> {
102
95
  const program = run(prepared, {
103
96
  cwd,
@@ -108,14 +101,22 @@ export function createRelacher(config: RelacherConfig) {
108
101
  return Effect.runPromise(program);
109
102
  },
110
103
 
111
- /**
112
- * Full interactive CLI entry point.
113
- * Handles arguments, preflight logs, confirmation prompts, dry-runs, and execution.
114
- */
115
104
  async cli(argv: string[] = process.argv.slice(2)): Promise<void> {
116
105
  const dryRun = argv.includes('--dry-run');
117
106
  const yes = argv.includes('-y') || argv.includes('--yes');
118
- const positional = argv.filter((a) => !a.startsWith('-'));
107
+
108
+ // Parse force / empty flags
109
+ const forceFlagIdx = argv.findIndex((a) => a === '--force');
110
+ const hasEmptyFlag = argv.includes('--empty');
111
+ let forceOption: boolean | BumpSize | undefined = undefined;
112
+
113
+ if (forceFlagIdx !== -1 && argv[forceFlagIdx + 1] && !argv[forceFlagIdx + 1]?.startsWith('-')) {
114
+ forceOption = argv[forceFlagIdx + 1] as BumpSize;
115
+ } else if (forceFlagIdx !== -1 || hasEmptyFlag) {
116
+ forceOption = true;
117
+ }
118
+
119
+ const positional = argv.filter((a) => !a.startsWith('-') && a !== forceOption);
119
120
  const command = positional[0] as 'init' | 'pre-release' | 'release' | undefined;
120
121
 
121
122
  if (!command || !['init', 'pre-release', 'release'].includes(command)) {
@@ -124,8 +125,8 @@ export function createRelacher(config: RelacherConfig) {
124
125
  'Invalid or missing release command.',
125
126
  '',
126
127
  'Usage:',
127
- ' relacher pre-release [--dry-run] [-y]',
128
- ' relacher release [--dry-run] [-y]',
128
+ ' relacher pre-release [--force] [--dry-run] [-y]',
129
+ ' relacher release [--force [patch|minor|major]] [--dry-run] [-y]',
129
130
  ' relacher init',
130
131
  ].join('\n'),
131
132
  );
@@ -143,11 +144,14 @@ export function createRelacher(config: RelacherConfig) {
143
144
  return;
144
145
  }
145
146
 
146
- const updates = await this.prepare({ mode: command });
147
+ const updates = await this.prepare({ mode: command, force: forceOption });
147
148
  log.step('Proposed Updates');
148
149
  prettyPrint(updates);
149
150
 
150
- if (updates.isEmpty) return;
151
+ if (updates.isEmpty) {
152
+ log.ok('Everything is up to date.');
153
+ return;
154
+ }
151
155
 
152
156
  if (dryRun) {
153
157
  log.step('Dry run active');
package/src/prepare.ts CHANGED
@@ -16,6 +16,7 @@ import type {
16
16
  import type { UpdateAction, UpdateActionResolved } from './updater';
17
17
  import { VcsProviderService, type VcsProvider } from './vcs';
18
18
  import { VersionManagerService, type VersionManager } from './versioning';
19
+ import { isBumpEqual, isPreRelease } from './versioning/bump';
19
20
  import type { BumpSize } from './versioning/types';
20
21
  import { getNestedExcludedPaths } from './workspace/paths';
21
22
 
@@ -23,16 +24,9 @@ export function isBumpSizeMatch(actual: BumpSize, pattern: BumpSize): boolean {
23
24
  if (typeof actual === 'string' && typeof pattern === 'string') {
24
25
  return actual === pattern;
25
26
  }
26
- if (
27
- typeof actual === 'object' &&
28
- actual !== null &&
29
- typeof pattern === 'object' &&
30
- pattern !== null
31
- ) {
32
- if (actual.kind === 'pre' && pattern.kind === 'pre') {
33
- if (pattern.size === undefined || pattern.size === null) return true;
34
- return actual.size === pattern.size;
35
- }
27
+ if (isPreRelease(actual) && isPreRelease(pattern)) {
28
+ if (pattern.size === undefined || pattern.size === null) return true;
29
+ return actual.size === pattern.size;
36
30
  }
37
31
  return false;
38
32
  }
@@ -67,10 +61,31 @@ export function topologicalSort(items: IntermediateReport[]): IntermediateReport
67
61
  return sorted;
68
62
  }
69
63
 
64
+ function resolvePackageBump(
65
+ name: string,
66
+ evaluatedBump: BumpSize,
67
+ options: PrepareOptions,
68
+ ): BumpSize {
69
+ // 1. Check specific package overrides
70
+ if (options.forcePackages && name in options.forcePackages) {
71
+ return options.forcePackages[name]!;
72
+ }
73
+
74
+ // 2. Check global force flag
75
+ if (options.force) {
76
+ if (typeof options.force === 'boolean') {
77
+ return evaluatedBump === 'skip' ? 'patch' : evaluatedBump;
78
+ }
79
+ return options.force;
80
+ }
81
+
82
+ return evaluatedBump;
83
+ }
84
+
70
85
  export function initReportItems(
71
86
  packages: PackageConfig[],
72
87
  cwd: string,
73
- excludeNestedWatches = false,
88
+ options: PrepareOptions = {},
74
89
  ): Effect.Effect<IntermediateReport[], Error, VersionManager> {
75
90
  return Effect.gen(function* () {
76
91
  const versionManager = yield* VersionManagerService;
@@ -87,7 +102,7 @@ export function initReportItems(
87
102
  const isMissingVersion = currentVersion === null;
88
103
  const actualVersion = currentVersion || '0.0.0';
89
104
 
90
- const exclude = excludeNestedWatches ? getNestedExcludedPaths(dep, packages) : [];
105
+ const exclude = options.excludeNestedWatches ? getNestedExcludedPaths(dep, packages) : [];
91
106
  const allCommits = yield* versionManager.getCommits(dep, cachedLockfile, exclude, cwd);
92
107
  let commitsSincePreRelease = [...allCommits];
93
108
 
@@ -100,7 +115,8 @@ export function initReportItems(
100
115
  }
101
116
  }
102
117
 
103
- const selfBump = versionManager.evaluateCommitsBump(commitsSincePreRelease);
118
+ let selfBump = versionManager.evaluateCommitsBump(commitsSincePreRelease);
119
+ selfBump = resolvePackageBump(dep.name, selfBump, options);
104
120
 
105
121
  let isErroneous = isMissingVersion;
106
122
  for (const u of dep.updates || []) {
@@ -187,7 +203,7 @@ export function prepare(
187
203
  }
188
204
  }
189
205
 
190
- const items = yield* initReportItems(trackedPackages, cwd, options.excludeNestedWatches);
206
+ const items = yield* initReportItems(trackedPackages, cwd, options);
191
207
  const sorted = topologicalSort(items);
192
208
  versionManager.propagateBumps(sorted);
193
209
  versionManager.propagateCoupledBumps(sorted);
package/src/run.ts CHANGED
@@ -33,10 +33,12 @@ export function generateCommitMessage(
33
33
  const firstReleaseBadge = report.isFirstRelease ? ' (first release)' : '';
34
34
  commitMessage += `${report.name} (${report.currentVersion} -> ${report.newVersion}) [${report.bump}]${firstReleaseBadge}\n`;
35
35
 
36
+ // 1. Commits list
36
37
  for (const commit of report.commits) {
37
38
  commitMessage += ` - ${commit.shortHash} ${commit.message} (<${commit.author}> ${commit.date})\n`;
38
39
  }
39
40
 
41
+ // 2. Cascades from local dependencies
40
42
  const changedDeps = reports.filter(
41
43
  (r) => report.depends?.includes(r.name) && r.currentVersion !== r.newVersion,
42
44
  );
@@ -46,6 +48,11 @@ export function generateCommitMessage(
46
48
  commitMessage += ` - Cascaded from deps: ${depsStr}\n`;
47
49
  }
48
50
 
51
+ // 3. Fallback note for forced releases with no commits and no cascades
52
+ if (report.commits.length === 0 && changedDeps.length === 0) {
53
+ commitMessage += ` - forced release bump (no new commits)\n`;
54
+ }
55
+
49
56
  commitMessage += '\n';
50
57
  }
51
58
 
package/src/types.ts CHANGED
@@ -31,6 +31,16 @@ export interface PackageConfig {
31
31
  group?: string;
32
32
  }
33
33
 
34
+ // In src/types.ts:
35
+ export interface PrepareOptions {
36
+ cwd?: string;
37
+ excludeNestedWatches?: boolean;
38
+ /** Force a bump size across all packages (e.g. true for patch, or 'minor' / 'major') */
39
+ force?: boolean | BumpSize;
40
+ /** Selectively force bump sizes for specific packages */
41
+ forcePackages?: Record<string, BumpSize>;
42
+ }
43
+
34
44
  export interface PrepareOptions {
35
45
  cwd?: string;
36
46
  excludeNestedWatches?: boolean;
@@ -0,0 +1,41 @@
1
+ import type { BumpSize, PreRelease } from './types';
2
+
3
+ /**
4
+ * Type guard for pre-release bump objects.
5
+ */
6
+ export function isPreRelease(val: unknown): val is PreRelease {
7
+ return typeof val === 'object' && val !== null && 'kind' in val && (val as PreRelease).kind === 'pre';
8
+ }
9
+
10
+ /**
11
+ * Numeric priority for bump sizes: major (4) > minor (3) > patch (2) > pre (1) > skip (0).
12
+ */
13
+ export function getBumpPriority(bump: BumpSize): number {
14
+ if (bump === 'major') return 4;
15
+ if (bump === 'minor') return 3;
16
+ if (bump === 'patch') return 2;
17
+ if (isPreRelease(bump)) return 1;
18
+ return 0;
19
+ }
20
+
21
+ export function isBumpGreater(a: BumpSize, b: BumpSize): boolean {
22
+ return getBumpPriority(a) > getBumpPriority(b);
23
+ }
24
+
25
+ export function maxBump(a: BumpSize, b: BumpSize): BumpSize {
26
+ return getBumpPriority(a) >= getBumpPriority(b) ? a : b;
27
+ }
28
+
29
+ export function isBumpEqual(a: BumpSize, b: BumpSize): boolean {
30
+ if (typeof a === 'string' && typeof b === 'string') return a === b;
31
+ if (isPreRelease(a) && isPreRelease(b)) return a.size === b.size;
32
+ return false;
33
+ }
34
+
35
+ export function getBumpByPriority(priority: number, fallbackPre?: PreRelease): BumpSize {
36
+ if (priority === 4) return 'major';
37
+ if (priority === 3) return 'minor';
38
+ if (priority === 2) return 'patch';
39
+ if (priority === 1) return fallbackPre ?? { kind: 'pre' };
40
+ return 'skip';
41
+ }
@@ -1,4 +1,6 @@
1
1
  export * from './types';
2
+ export * from './bump';
3
+ export * from './semver';
2
4
  export * from './utils';
3
5
  export * from './default-data';
4
6
  export * from './vcs-version-manager';
@@ -4,6 +4,13 @@ import { findLastReleaseCommit, type LockfileData } from '../lockfile';
4
4
  import type { Commit, IntermediateReport, PackageConfig } from '../types';
5
5
  import { VcsProviderService, type VcsProvider } from '../vcs';
6
6
 
7
+ import {
8
+ getBumpByPriority,
9
+ getBumpPriority,
10
+ isBumpEqual,
11
+ isBumpGreater,
12
+ isPreRelease,
13
+ } from './bump';
7
14
  import { defaultCascadeRules, defaultSizes } from './default-data';
8
15
  import type { BumpSize, CascadeRules, SizePatterns } from './types';
9
16
  import { defaultBumpVersion, isVersionGreater, matchBumpSize } from './utils';
@@ -31,38 +38,6 @@ export interface VersionManager {
31
38
 
32
39
  export const VersionManagerService = Context.Service<VersionManager>('VersionManager');
33
40
 
34
- const getBumpPriority = (bump: BumpSize): number => {
35
- if (typeof bump === 'string') {
36
- if (bump === 'major') return 4;
37
- if (bump === 'minor') return 3;
38
- if (bump === 'patch') return 2;
39
- return 0;
40
- }
41
- if (bump && bump.kind === 'pre') return 1;
42
- return 0;
43
- };
44
-
45
- const isBumpSizeEqual = (a: BumpSize, b: BumpSize): boolean => {
46
- if (typeof a === 'string' && typeof b === 'string') return a === b;
47
- if (typeof a === 'object' && a !== null && typeof b === 'object' && b !== null) {
48
- if (a.kind === 'pre' && b.kind === 'pre') return a.size === b.size;
49
- }
50
- return false;
51
- };
52
-
53
- const getBumpSizeByPriority = (priorityValue: number, originalBump: BumpSize): BumpSize => {
54
- if (priorityValue === 4) return 'major';
55
- if (priorityValue === 3) return 'minor';
56
- if (priorityValue === 2) return 'patch';
57
- if (priorityValue === 1) {
58
- if (typeof originalBump === 'object' && originalBump !== null && originalBump.kind === 'pre') {
59
- return originalBump;
60
- }
61
- return { kind: 'pre' };
62
- }
63
- return 'skip';
64
- };
65
-
66
41
  export const makeVcsVersionManager = (
67
42
  vcs: VcsProvider,
68
43
  options?: {
@@ -142,14 +117,14 @@ export const makeVcsVersionManager = (
142
117
  },
143
118
 
144
119
  evaluateCommitsBump: (commits) => {
145
- let maxBump: BumpSize = 'skip';
120
+ let max: BumpSize = 'skip';
146
121
  for (const commit of commits) {
147
122
  const commitBump = matchBumpSize(commit.message, sizes);
148
- if (getBumpPriority(commitBump) > getBumpPriority(maxBump)) {
149
- maxBump = commitBump;
123
+ if (isBumpGreater(commitBump, max)) {
124
+ max = commitBump;
150
125
  }
151
126
  }
152
- return maxBump;
127
+ return max;
153
128
  },
154
129
 
155
130
  propagateBumps: (sorted) => {
@@ -180,23 +155,20 @@ export const makeVcsVersionManager = (
180
155
  const depBumpKey =
181
156
  typeof depItem.bump === 'string'
182
157
  ? depItem.bump
183
- : depItem.bump.kind === 'pre'
158
+ : isPreRelease(depItem.bump)
184
159
  ? depItem.bump.size
185
160
  ? `pre-${depItem.bump.size}`
186
161
  : 'pre'
187
162
  : 'patch';
188
163
 
189
164
  const cascadedResult = activeRules[depBumpKey];
190
- if (
191
- cascadedResult &&
192
- getBumpPriority(cascadedResult) > getBumpPriority(maxCascadedBump)
193
- ) {
165
+ if (cascadedResult && isBumpGreater(cascadedResult, maxCascadedBump)) {
194
166
  maxCascadedBump = cascadedResult;
195
167
  }
196
168
  }
197
169
  }
198
170
 
199
- if (getBumpPriority(maxCascadedBump) > getBumpPriority(item.bump)) {
171
+ if (isBumpGreater(maxCascadedBump, item.bump)) {
200
172
  item.bump = maxCascadedBump;
201
173
  }
202
174
 
@@ -226,14 +198,17 @@ export const makeVcsVersionManager = (
226
198
  } else if (maxPriority === otherPri) {
227
199
  targetBump = other.bump;
228
200
  } else {
229
- targetBump = getBumpSizeByPriority(maxPriority, item.bump);
201
+ targetBump = getBumpByPriority(
202
+ maxPriority,
203
+ isPreRelease(item.bump) ? item.bump : undefined,
204
+ );
230
205
  }
231
206
 
232
- if (!isBumpSizeEqual(item.bump, targetBump)) {
207
+ if (!isBumpEqual(item.bump, targetBump)) {
233
208
  item.bump = targetBump;
234
209
  changed = true;
235
210
  }
236
- if (!isBumpSizeEqual(other.bump, targetBump)) {
211
+ if (!isBumpEqual(other.bump, targetBump)) {
237
212
  other.bump = targetBump;
238
213
  changed = true;
239
214
  }