@muverse/core 0.1.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 +22 -0
- package/dist/adapters/gradle/constants.d.ts +13 -0
- package/dist/adapters/gradle/constants.d.ts.map +1 -0
- package/dist/adapters/gradle/constants.js +12 -0
- package/dist/adapters/gradle/gradle-project-information.d.ts +18 -0
- package/dist/adapters/gradle/gradle-project-information.d.ts.map +1 -0
- package/dist/adapters/gradle/gradle-project-information.js +93 -0
- package/dist/adapters/gradle/gradle-properties.d.ts +15 -0
- package/dist/adapters/gradle/gradle-properties.d.ts.map +1 -0
- package/dist/adapters/gradle/gradle-properties.js +46 -0
- package/dist/adapters/gradle/init-project-information.gradle.kts +143 -0
- package/dist/adapters/gradle/services/gradle-adapter-identifier.d.ts +21 -0
- package/dist/adapters/gradle/services/gradle-adapter-identifier.d.ts.map +1 -0
- package/dist/adapters/gradle/services/gradle-adapter-identifier.js +44 -0
- package/dist/adapters/gradle/services/gradle-module-detector.d.ts +18 -0
- package/dist/adapters/gradle/services/gradle-module-detector.d.ts.map +1 -0
- package/dist/adapters/gradle/services/gradle-module-detector.js +26 -0
- package/dist/adapters/gradle/services/gradle-module-system-factory.d.ts +23 -0
- package/dist/adapters/gradle/services/gradle-module-system-factory.d.ts.map +1 -0
- package/dist/adapters/gradle/services/gradle-module-system-factory.js +27 -0
- package/dist/adapters/gradle/services/gradle-version-update-strategy.d.ts +21 -0
- package/dist/adapters/gradle/services/gradle-version-update-strategy.d.ts.map +1 -0
- package/dist/adapters/gradle/services/gradle-version-update-strategy.js +36 -0
- package/dist/adapters/project-information.d.ts +58 -0
- package/dist/adapters/project-information.d.ts.map +1 -0
- package/dist/adapters/project-information.js +1 -0
- package/dist/changelog/index.d.ts +27 -0
- package/dist/changelog/index.d.ts.map +1 -0
- package/dist/changelog/index.js +204 -0
- package/dist/config/index.d.ts +122 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +115 -0
- package/dist/factories/adapter-identifier-registry.d.ts +12 -0
- package/dist/factories/adapter-identifier-registry.d.ts.map +1 -0
- package/dist/factories/adapter-identifier-registry.js +24 -0
- package/dist/factories/module-system-factory.d.ts +10 -0
- package/dist/factories/module-system-factory.d.ts.map +1 -0
- package/dist/factories/module-system-factory.js +18 -0
- package/dist/git/index.d.ts +253 -0
- package/dist/git/index.d.ts.map +1 -0
- package/dist/git/index.js +581 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/semver/index.d.ts +85 -0
- package/dist/semver/index.d.ts.map +1 -0
- package/dist/semver/index.js +176 -0
- package/dist/services/adapter-identifier-registry.d.ts +38 -0
- package/dist/services/adapter-identifier-registry.d.ts.map +1 -0
- package/dist/services/adapter-identifier-registry.js +59 -0
- package/dist/services/adapter-identifier.d.ts +31 -0
- package/dist/services/adapter-identifier.d.ts.map +1 -0
- package/dist/services/adapter-identifier.js +1 -0
- package/dist/services/adapter-metadata-provider.d.ts +51 -0
- package/dist/services/adapter-metadata-provider.d.ts.map +1 -0
- package/dist/services/adapter-metadata-provider.js +66 -0
- package/dist/services/changelog-generator.d.ts +13 -0
- package/dist/services/changelog-generator.d.ts.map +1 -0
- package/dist/services/changelog-generator.js +26 -0
- package/dist/services/commit-analyzer.d.ts +44 -0
- package/dist/services/commit-analyzer.d.ts.map +1 -0
- package/dist/services/commit-analyzer.js +86 -0
- package/dist/services/configuration-loader.d.ts +23 -0
- package/dist/services/configuration-loader.d.ts.map +1 -0
- package/dist/services/configuration-loader.js +79 -0
- package/dist/services/configuration-validator.d.ts +16 -0
- package/dist/services/configuration-validator.d.ts.map +1 -0
- package/dist/services/configuration-validator.js +24 -0
- package/dist/services/git-operations.d.ts +16 -0
- package/dist/services/git-operations.d.ts.map +1 -0
- package/dist/services/git-operations.js +89 -0
- package/dist/services/module-detector.d.ts +24 -0
- package/dist/services/module-detector.d.ts.map +1 -0
- package/dist/services/module-detector.js +1 -0
- package/dist/services/module-registry.d.ts +45 -0
- package/dist/services/module-registry.d.ts.map +1 -0
- package/dist/services/module-registry.js +57 -0
- package/dist/services/module-system-factory.d.ts +24 -0
- package/dist/services/module-system-factory.d.ts.map +1 -0
- package/dist/services/module-system-factory.js +1 -0
- package/dist/services/verse-runner.d.ts +45 -0
- package/dist/services/verse-runner.d.ts.map +1 -0
- package/dist/services/verse-runner.js +182 -0
- package/dist/services/version-applier.d.ts +26 -0
- package/dist/services/version-applier.d.ts.map +1 -0
- package/dist/services/version-applier.js +63 -0
- package/dist/services/version-bumper.d.ts +156 -0
- package/dist/services/version-bumper.d.ts.map +1 -0
- package/dist/services/version-bumper.js +291 -0
- package/dist/services/version-manager.d.ts +68 -0
- package/dist/services/version-manager.d.ts.map +1 -0
- package/dist/services/version-manager.js +94 -0
- package/dist/services/version-update-strategy.d.ts +18 -0
- package/dist/services/version-update-strategy.d.ts.map +1 -0
- package/dist/services/version-update-strategy.js +1 -0
- package/dist/utils/banner.d.ts +2 -0
- package/dist/utils/banner.d.ts.map +1 -0
- package/dist/utils/banner.js +8 -0
- package/dist/utils/commits.d.ts +12 -0
- package/dist/utils/commits.d.ts.map +1 -0
- package/dist/utils/commits.js +24 -0
- package/dist/utils/file.d.ts +7 -0
- package/dist/utils/file.d.ts.map +1 -0
- package/dist/utils/file.js +19 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/logger.d.ts +14 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +22 -0
- package/dist/utils/properties.d.ts +16 -0
- package/dist/utils/properties.d.ts.map +1 -0
- package/dist/utils/properties.js +62 -0
- package/dist/utils/versioning.d.ts +8 -0
- package/dist/utils/versioning.d.ts.map +1 -0
- package/dist/utils/versioning.js +17 -0
- package/package.json +70 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version Bumper Service for μVERSE.
|
|
3
|
+
* Implements core version calculation logic: analyzes commits, cascades changes through
|
|
4
|
+
* dependencies, and applies versions with support for prereleases, metadata, and snapshots.
|
|
5
|
+
*/
|
|
6
|
+
import { logger } from "../utils/logger.js";
|
|
7
|
+
import { getDependencyBumpType } from "../config/index.js";
|
|
8
|
+
import { calculateBumpFromCommits } from "../utils/commits.js";
|
|
9
|
+
import { bumpSemVer, bumpToPrerelease, formatSemVer, addBuildMetadata, generateTimestampPrereleaseId, maxBumpType, } from "../semver/index.js";
|
|
10
|
+
import { getCurrentCommitShortSha } from "../git/index.js";
|
|
11
|
+
import { applySnapshotSuffix } from "../utils/versioning.js";
|
|
12
|
+
/**
|
|
13
|
+
* Service for calculating version bumps across modules.
|
|
14
|
+
* Handles commit analysis, dependency cascade effects, and various versioning strategies
|
|
15
|
+
* (regular, prerelease, snapshot).
|
|
16
|
+
*/
|
|
17
|
+
export class VersionBumper {
|
|
18
|
+
moduleRegistry;
|
|
19
|
+
options;
|
|
20
|
+
/**
|
|
21
|
+
* Creates a new VersionBumper instance.
|
|
22
|
+
* @param moduleRegistry - Registry containing all modules and their interdependencies
|
|
23
|
+
* @param options - Configuration options controlling version bump behavior
|
|
24
|
+
*/
|
|
25
|
+
constructor(moduleRegistry, options) {
|
|
26
|
+
this.moduleRegistry = moduleRegistry;
|
|
27
|
+
this.options = options;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Calculates version bumps for all modules based on their commits.
|
|
31
|
+
* Orchestrates a three-phase process: initial bumps (commit analysis), cascade effects (dependency propagation),
|
|
32
|
+
* and version application (applying strategies like prerelease, timestamps, build metadata).
|
|
33
|
+
* @param moduleCommits - Map of module IDs to their commits since last version
|
|
34
|
+
* @returns Promise resolving to array of processed module changes (only modules that need updates)
|
|
35
|
+
* @throws {Error} If git operations fail
|
|
36
|
+
*/
|
|
37
|
+
async calculateVersionBumps(moduleCommits) {
|
|
38
|
+
logger.info("🔢 Calculating version bumps from commits...");
|
|
39
|
+
// Generate timestamp-based prerelease ID if timestamp versions are enabled
|
|
40
|
+
let effectivePrereleaseId = this.options.prereleaseId;
|
|
41
|
+
if (this.options.timestampVersions && this.options.prereleaseMode) {
|
|
42
|
+
effectivePrereleaseId = generateTimestampPrereleaseId(this.options.prereleaseId);
|
|
43
|
+
logger.info(`🕐 Generated timestamp prerelease ID: ${effectivePrereleaseId}`);
|
|
44
|
+
}
|
|
45
|
+
// Get current commit short SHA if build metadata is enabled
|
|
46
|
+
let shortSha;
|
|
47
|
+
if (this.options.addBuildMetadata) {
|
|
48
|
+
shortSha = await getCurrentCommitShortSha({ cwd: this.options.repoRoot });
|
|
49
|
+
logger.info(`📋 Build metadata will include short SHA: ${shortSha}`);
|
|
50
|
+
}
|
|
51
|
+
// Step 1: Calculate initial bump types for all modules
|
|
52
|
+
const processingModuleChanges = this.calculateInitialBumps(moduleCommits);
|
|
53
|
+
// Step 2: Calculate cascade effects
|
|
54
|
+
logger.info("🌊 Calculating cascade effects...");
|
|
55
|
+
const cascadedChanges = this.calculateCascadeEffects(processingModuleChanges);
|
|
56
|
+
// Step 3: Apply version calculations and transformations
|
|
57
|
+
logger.info("🔢 Calculating actual versions...");
|
|
58
|
+
return this.applyVersionCalculations(cascadedChanges, effectivePrereleaseId, shortSha);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Calculates initial version bump types for all modules based on commits.
|
|
62
|
+
*
|
|
63
|
+
* This is Phase 1 of the version calculation process. It analyzes commits for each
|
|
64
|
+
* module to determine the required version bump type using Conventional Commits
|
|
65
|
+
* specification.
|
|
66
|
+
*
|
|
67
|
+
* The method creates a `ProcessingModuleChange` for **every** module in the registry,
|
|
68
|
+
* not just those with commits. The `needsProcessing` flag determines which modules
|
|
69
|
+
* will ultimately be updated.
|
|
70
|
+
*
|
|
71
|
+
* **Processing Decision Logic**:
|
|
72
|
+
* - Module has commits requiring bump: `needsProcessing = true, reason = 'commits'`
|
|
73
|
+
* - Prerelease mode with bumpUnchanged: `needsProcessing = true, reason = 'prerelease-unchanged'`
|
|
74
|
+
* - Build metadata enabled: `needsProcessing = true, reason = 'build-metadata'`
|
|
75
|
+
* - Otherwise: `needsProcessing = false, reason = 'unchanged'`
|
|
76
|
+
*
|
|
77
|
+
* @param moduleCommits - Map of module IDs to their commits since last version.
|
|
78
|
+
*
|
|
79
|
+
* @returns Array of processing module changes for all modules in the registry
|
|
80
|
+
*/
|
|
81
|
+
calculateInitialBumps(moduleCommits) {
|
|
82
|
+
const processingModuleChanges = [];
|
|
83
|
+
// Iterate through ALL modules in the registry
|
|
84
|
+
for (const [projectId, projectInfo] of this.moduleRegistry.getModules()) {
|
|
85
|
+
const commits = moduleCommits.get(projectId) || [];
|
|
86
|
+
// Determine bump type from commits only
|
|
87
|
+
// Uses Conventional Commits spec to analyze commit types
|
|
88
|
+
const bumpType = calculateBumpFromCommits(commits, this.options.config);
|
|
89
|
+
// Determine processing requirements and reason
|
|
90
|
+
let reason = "unchanged";
|
|
91
|
+
let needsProcessing = false;
|
|
92
|
+
if (bumpType !== "none") {
|
|
93
|
+
// Module has commits that require version changes
|
|
94
|
+
needsProcessing = true;
|
|
95
|
+
reason = "commits";
|
|
96
|
+
}
|
|
97
|
+
else if (this.options.prereleaseMode && this.options.bumpUnchanged) {
|
|
98
|
+
// Prerelease mode with bumpUnchanged - include modules with no changes
|
|
99
|
+
needsProcessing = true;
|
|
100
|
+
reason = "prerelease-unchanged";
|
|
101
|
+
}
|
|
102
|
+
else if (this.options.addBuildMetadata) {
|
|
103
|
+
// Build metadata mode - all modules need updates for metadata
|
|
104
|
+
needsProcessing = true;
|
|
105
|
+
reason = "build-metadata";
|
|
106
|
+
}
|
|
107
|
+
// Create module change for ALL modules - processing flag determines behavior
|
|
108
|
+
processingModuleChanges.push({
|
|
109
|
+
module: projectInfo,
|
|
110
|
+
fromVersion: projectInfo.version,
|
|
111
|
+
toVersion: "", // Will be calculated later
|
|
112
|
+
bumpType: bumpType,
|
|
113
|
+
reason: reason,
|
|
114
|
+
needsProcessing: needsProcessing,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return processingModuleChanges;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Calculates cascade effects when modules change.
|
|
121
|
+
*
|
|
122
|
+
* This is Phase 2 of the version calculation process. It propagates version changes
|
|
123
|
+
* through the module dependency graph, ensuring that when a module changes, all
|
|
124
|
+
* modules that depend on it are also bumped appropriately.
|
|
125
|
+
*
|
|
126
|
+
* **Algorithm**: Uses a breadth-first traversal of the dependency graph:
|
|
127
|
+
* 1. Start with all modules marked for processing (needsProcessing = true)
|
|
128
|
+
* 2. For each module being processed, find all modules that depend on it
|
|
129
|
+
* 3. Calculate required bump for dependents using dependency bump rules
|
|
130
|
+
* 4. If dependent needs a higher bump, update it and add to processing queue
|
|
131
|
+
* 5. Continue until no more cascades are needed
|
|
132
|
+
*
|
|
133
|
+
* **Complexity**: O(V + E) where V = number of modules, E = number of dependencies
|
|
134
|
+
*
|
|
135
|
+
* **In-Place Modification**: This method modifies the input array in place for
|
|
136
|
+
* efficiency. The same array reference is returned with cascade effects applied.
|
|
137
|
+
*
|
|
138
|
+
* @param allModuleChanges - Array of all module changes (will be modified in place).
|
|
139
|
+
* Should include all modules from calculateInitialBumps().
|
|
140
|
+
*
|
|
141
|
+
* @returns The same array with cascade effects applied
|
|
142
|
+
*/
|
|
143
|
+
calculateCascadeEffects(allModuleChanges) {
|
|
144
|
+
const processed = new Set();
|
|
145
|
+
const moduleMap = new Map();
|
|
146
|
+
// Create module map for O(1) lookups
|
|
147
|
+
for (const change of allModuleChanges) {
|
|
148
|
+
moduleMap.set(change.module.id, change);
|
|
149
|
+
}
|
|
150
|
+
// Start with ALL modules - treat them completely equally
|
|
151
|
+
const queue = [...allModuleChanges];
|
|
152
|
+
while (queue.length > 0) {
|
|
153
|
+
const currentChange = queue.shift();
|
|
154
|
+
// No processing needed, mark as processed
|
|
155
|
+
if (!currentChange.needsProcessing || currentChange.bumpType === "none") {
|
|
156
|
+
logger.debug(`🔄 Skipping module ${currentChange.module.id} - no processing needed`);
|
|
157
|
+
processed.add(currentChange.module.id);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
// Skip if already processed
|
|
161
|
+
if (processed.has(currentChange.module.id)) {
|
|
162
|
+
logger.debug(`🔄 Skipping module ${currentChange.module.id} - already processed`);
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
// Mark as processed to avoid duplicate work
|
|
166
|
+
processed.add(currentChange.module.id);
|
|
167
|
+
const currentModuleInfo = this.moduleRegistry.getModule(currentChange.module.id);
|
|
168
|
+
// Iterate through all modules that depend on the current module
|
|
169
|
+
for (const dependentName of currentModuleInfo.affectedModules) {
|
|
170
|
+
logger.debug(`➡️ Processing dependent module ${dependentName} affected by ${currentChange.module.id} with bump ${currentChange.bumpType}`);
|
|
171
|
+
// Get the dependent module using O(1) lookup
|
|
172
|
+
const existingChange = moduleMap.get(dependentName);
|
|
173
|
+
if (!existingChange) {
|
|
174
|
+
logger.debug(`⚠️ Dependent module ${dependentName} not found in module changes list`);
|
|
175
|
+
continue; // Module not found in our module list
|
|
176
|
+
}
|
|
177
|
+
// Calculate the bump needed for the dependent
|
|
178
|
+
// Uses configuration rules to determine how changes propagate
|
|
179
|
+
const requiredBump = getDependencyBumpType(currentChange.bumpType, this.options.config);
|
|
180
|
+
if (requiredBump === "none") {
|
|
181
|
+
logger.debug(`➡️ No cascade bump needed for module ${dependentName} from ${currentChange.module.id}`);
|
|
182
|
+
continue; // No cascade needed
|
|
183
|
+
}
|
|
184
|
+
// Update the existing change with cascade information
|
|
185
|
+
// Take the maximum bump type if multiple dependencies affect this module
|
|
186
|
+
const mergedBump = maxBumpType([existingChange.bumpType, requiredBump]);
|
|
187
|
+
if (mergedBump !== existingChange.bumpType) {
|
|
188
|
+
logger.debug(`🔄 Cascading bump for module ${dependentName} from ${existingChange.bumpType} to ${mergedBump} due to ${currentChange.module.id}`);
|
|
189
|
+
// Update the module change in place
|
|
190
|
+
existingChange.bumpType = mergedBump;
|
|
191
|
+
existingChange.reason = "cascade";
|
|
192
|
+
existingChange.needsProcessing = true;
|
|
193
|
+
// Add to queue for further processing (transitive cascades)
|
|
194
|
+
processed.delete(dependentName); // Allow re-processing
|
|
195
|
+
queue.push(existingChange);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
logger.debug(`🔄 No changes needed for module ${dependentName} - already at ${existingChange.bumpType}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// Return the modified array (same reference, but with cascade effects applied)
|
|
203
|
+
return allModuleChanges;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Applies version calculations and transformations to all modules.
|
|
207
|
+
*
|
|
208
|
+
* This is Phase 3 (final) of the version calculation process. It takes modules
|
|
209
|
+
* with calculated bump types and applies version transformations including:
|
|
210
|
+
* - Semantic version bumping (major, minor, patch)
|
|
211
|
+
* - Prerelease version generation
|
|
212
|
+
* - Build metadata appending
|
|
213
|
+
* - Snapshot suffix appending
|
|
214
|
+
*
|
|
215
|
+
* **Version Application Scenarios**:
|
|
216
|
+
* 1. **Commits + Regular Mode**: Bump semantic version normally
|
|
217
|
+
* 2. **Commits + Prerelease Mode**: Bump to prerelease version
|
|
218
|
+
* 3. **No Commits + Prerelease + bumpUnchanged**: Force prerelease bump
|
|
219
|
+
* 4. **Build Metadata Mode**: Append git SHA as metadata
|
|
220
|
+
* 5. **Snapshot Mode**: Append -SNAPSHOT suffix
|
|
221
|
+
*
|
|
222
|
+
* @param processingModuleChanges - All module changes with calculated bump types
|
|
223
|
+
* from cascade effects phase.
|
|
224
|
+
*
|
|
225
|
+
* @param effectivePrereleaseId - Prerelease identifier to use (may include timestamp).
|
|
226
|
+
* Example: 'alpha', 'alpha.20251021143022'
|
|
227
|
+
*
|
|
228
|
+
* @param shortSha - Optional git commit short SHA for build metadata.
|
|
229
|
+
* Example: 'a1b2c3d'
|
|
230
|
+
*
|
|
231
|
+
* @returns Array of processed module changes ready for application (only modules with needsProcessing = true)
|
|
232
|
+
*/
|
|
233
|
+
applyVersionCalculations(processingModuleChanges, effectivePrereleaseId, shortSha) {
|
|
234
|
+
const processedModuleChanges = [];
|
|
235
|
+
for (const change of processingModuleChanges) {
|
|
236
|
+
let newVersion = change.fromVersion;
|
|
237
|
+
// Only apply version changes if module needs processing
|
|
238
|
+
if (change.needsProcessing) {
|
|
239
|
+
// Apply version bumps based on module state
|
|
240
|
+
if (change.bumpType !== "none" && this.options.prereleaseMode) {
|
|
241
|
+
// Scenario 1: Commits with changes in prerelease mode
|
|
242
|
+
// Bump semantic version AND add prerelease identifier
|
|
243
|
+
newVersion = bumpToPrerelease(change.fromVersion, change.bumpType, effectivePrereleaseId);
|
|
244
|
+
}
|
|
245
|
+
else if (change.bumpType !== "none" && !this.options.prereleaseMode) {
|
|
246
|
+
// Scenario 2: Commits with changes in normal mode
|
|
247
|
+
// Standard semantic version bump (major.minor.patch)
|
|
248
|
+
newVersion = bumpSemVer(change.fromVersion, change.bumpType);
|
|
249
|
+
}
|
|
250
|
+
else if (change.reason === "prerelease-unchanged") {
|
|
251
|
+
// Scenario 3: No changes but force prerelease bump (bumpUnchanged enabled)
|
|
252
|
+
// Keep semantic version, just add prerelease identifier
|
|
253
|
+
newVersion = bumpToPrerelease(change.fromVersion, "none", effectivePrereleaseId);
|
|
254
|
+
}
|
|
255
|
+
// Scenario 4: reason === 'build-metadata' or 'unchanged' - no version bump, keep fromVersion
|
|
256
|
+
// Add build metadata if enabled (applies to all scenarios)
|
|
257
|
+
// Build metadata doesn't affect version precedence per semver spec
|
|
258
|
+
if (this.options.addBuildMetadata && shortSha) {
|
|
259
|
+
newVersion = addBuildMetadata(newVersion, shortSha);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// Convert to string version
|
|
263
|
+
change.toVersion = formatSemVer(newVersion);
|
|
264
|
+
// Apply append snapshot suffix if enabled (to all modules in append mode)
|
|
265
|
+
if (this.options.appendSnapshot &&
|
|
266
|
+
this.options.adapter.capabilities.supportsSnapshots) {
|
|
267
|
+
const originalVersion = change.toVersion;
|
|
268
|
+
change.toVersion = applySnapshotSuffix(change.toVersion);
|
|
269
|
+
// If snapshot suffix was actually added and module wasn't already being processed, mark it for processing
|
|
270
|
+
if (!change.needsProcessing && change.toVersion !== originalVersion) {
|
|
271
|
+
change.needsProcessing = true;
|
|
272
|
+
change.reason = "gradle-snapshot";
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
// Add to update collection only if module needs processing
|
|
276
|
+
if (change.needsProcessing) {
|
|
277
|
+
// Convert to ProcessedModuleChange since we know needsProcessing is true
|
|
278
|
+
const processedChange = {
|
|
279
|
+
module: change.module,
|
|
280
|
+
fromVersion: change.fromVersion,
|
|
281
|
+
toVersion: change.toVersion,
|
|
282
|
+
bumpType: change.bumpType,
|
|
283
|
+
reason: change.reason, // Safe cast since needsProcessing is true
|
|
284
|
+
};
|
|
285
|
+
processedModuleChanges.push(processedChange);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
logger.info(`📈 Calculated versions for ${processedModuleChanges.length} modules requiring updates`);
|
|
289
|
+
return processedModuleChanges;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { SemVer } from "semver";
|
|
2
|
+
import { ModuleRegistry } from "./module-registry.js";
|
|
3
|
+
import { VersionUpdateStrategy } from "./version-update-strategy.js";
|
|
4
|
+
/**
|
|
5
|
+
* Manages version updates for modules with staged commits and batch persistence.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* Implements a two-phase update strategy:
|
|
9
|
+
* 1. Stage updates in memory via `updateVersion()`
|
|
10
|
+
* 2. Persist all updates via `commit()`
|
|
11
|
+
*
|
|
12
|
+
* Uses {@link VersionUpdateStrategy} for build system-specific operations.
|
|
13
|
+
* Validates modules against {@link ModuleRegistry}.
|
|
14
|
+
*/
|
|
15
|
+
export declare class VersionManager {
|
|
16
|
+
private readonly hierarchyManager;
|
|
17
|
+
private readonly strategy;
|
|
18
|
+
/** Pending version updates awaiting commit (module ID → version string). */
|
|
19
|
+
private readonly pendingUpdates;
|
|
20
|
+
/**
|
|
21
|
+
* Creates a new VersionManager.
|
|
22
|
+
*
|
|
23
|
+
* @param hierarchyManager - Module registry for validation
|
|
24
|
+
* @param strategy - Build system-specific strategy for writing updates
|
|
25
|
+
*/
|
|
26
|
+
constructor(hierarchyManager: ModuleRegistry, strategy: VersionUpdateStrategy);
|
|
27
|
+
/**
|
|
28
|
+
* Stages a version update for a module without persisting to files.
|
|
29
|
+
*
|
|
30
|
+
* @param moduleId - Module identifier (e.g., `':'`, `':core'`)
|
|
31
|
+
* @param newVersion - New version as SemVer object or string
|
|
32
|
+
* @throws {Error} If module ID doesn't exist in registry
|
|
33
|
+
*/
|
|
34
|
+
updateVersion(moduleId: string, newVersion: SemVer | string): void;
|
|
35
|
+
/**
|
|
36
|
+
* Commits all pending version updates to build files in a single batch operation.
|
|
37
|
+
*
|
|
38
|
+
* @returns Promise that resolves when all updates are written
|
|
39
|
+
* @throws {Error} If file operations fail (specific errors depend on strategy)
|
|
40
|
+
*/
|
|
41
|
+
commit(): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Returns a copy of all pending updates that haven't been committed.
|
|
44
|
+
*
|
|
45
|
+
* @returns Map of module ID to version string
|
|
46
|
+
*/
|
|
47
|
+
getPendingUpdates(): Map<string, string>;
|
|
48
|
+
/**
|
|
49
|
+
* Checks whether there are any pending updates awaiting commit.
|
|
50
|
+
*
|
|
51
|
+
* @returns `true` if updates are staged, `false` otherwise
|
|
52
|
+
*/
|
|
53
|
+
hasPendingUpdates(): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Clears all pending updates without committing them.
|
|
56
|
+
*
|
|
57
|
+
* @remarks
|
|
58
|
+
* Use with caution - this operation cannot be undone.
|
|
59
|
+
*/
|
|
60
|
+
clearPendingUpdates(): void;
|
|
61
|
+
/**
|
|
62
|
+
* Gets the number of pending updates in the queue.
|
|
63
|
+
*
|
|
64
|
+
* @returns The count of pending updates that have not been processed yet.
|
|
65
|
+
*/
|
|
66
|
+
getPendingUpdatesCount(): number;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=version-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-manager.d.ts","sourceRoot":"","sources":["../../src/services/version-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAGrE;;;;;;;;;;GAUG;AACH,qBAAa,cAAc;IAWvB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAX3B,4EAA4E;IAC5E,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA6B;IAE5D;;;;;OAKG;gBAEgB,gBAAgB,EAAE,cAAc,EAChC,QAAQ,EAAE,qBAAqB;IAGlD;;;;;;OAMG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAclE;;;;;OAKG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAa7B;;;;OAIG;IACH,iBAAiB,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAIxC;;;;OAIG;IACH,iBAAiB,IAAI,OAAO;IAI5B;;;;;OAKG;IACH,mBAAmB,IAAI,IAAI;IAI3B;;;;OAIG;IACH,sBAAsB,IAAI,MAAM;CAGjC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { formatSemVer } from "../semver/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Manages version updates for modules with staged commits and batch persistence.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* Implements a two-phase update strategy:
|
|
7
|
+
* 1. Stage updates in memory via `updateVersion()`
|
|
8
|
+
* 2. Persist all updates via `commit()`
|
|
9
|
+
*
|
|
10
|
+
* Uses {@link VersionUpdateStrategy} for build system-specific operations.
|
|
11
|
+
* Validates modules against {@link ModuleRegistry}.
|
|
12
|
+
*/
|
|
13
|
+
export class VersionManager {
|
|
14
|
+
hierarchyManager;
|
|
15
|
+
strategy;
|
|
16
|
+
/** Pending version updates awaiting commit (module ID → version string). */
|
|
17
|
+
pendingUpdates = new Map();
|
|
18
|
+
/**
|
|
19
|
+
* Creates a new VersionManager.
|
|
20
|
+
*
|
|
21
|
+
* @param hierarchyManager - Module registry for validation
|
|
22
|
+
* @param strategy - Build system-specific strategy for writing updates
|
|
23
|
+
*/
|
|
24
|
+
constructor(hierarchyManager, strategy) {
|
|
25
|
+
this.hierarchyManager = hierarchyManager;
|
|
26
|
+
this.strategy = strategy;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Stages a version update for a module without persisting to files.
|
|
30
|
+
*
|
|
31
|
+
* @param moduleId - Module identifier (e.g., `':'`, `':core'`)
|
|
32
|
+
* @param newVersion - New version as SemVer object or string
|
|
33
|
+
* @throws {Error} If module ID doesn't exist in registry
|
|
34
|
+
*/
|
|
35
|
+
updateVersion(moduleId, newVersion) {
|
|
36
|
+
// Validate module exists in registry
|
|
37
|
+
if (!this.hierarchyManager.hasModule(moduleId)) {
|
|
38
|
+
throw new Error(`Module ${moduleId} not found`);
|
|
39
|
+
}
|
|
40
|
+
// Convert SemVer to string if needed, otherwise use string directly
|
|
41
|
+
const versionString = typeof newVersion === "string" ? newVersion : formatSemVer(newVersion);
|
|
42
|
+
// Store update in pending updates map
|
|
43
|
+
this.pendingUpdates.set(moduleId, versionString);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Commits all pending version updates to build files in a single batch operation.
|
|
47
|
+
*
|
|
48
|
+
* @returns Promise that resolves when all updates are written
|
|
49
|
+
* @throws {Error} If file operations fail (specific errors depend on strategy)
|
|
50
|
+
*/
|
|
51
|
+
async commit() {
|
|
52
|
+
// Early return if nothing to commit
|
|
53
|
+
if (this.pendingUpdates.size === 0) {
|
|
54
|
+
return; // Nothing to commit
|
|
55
|
+
}
|
|
56
|
+
// Write all version updates using build system-specific strategy
|
|
57
|
+
await this.strategy.writeVersionUpdates(this.pendingUpdates);
|
|
58
|
+
// Clear the pending updates after successful commit
|
|
59
|
+
this.pendingUpdates.clear();
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Returns a copy of all pending updates that haven't been committed.
|
|
63
|
+
*
|
|
64
|
+
* @returns Map of module ID to version string
|
|
65
|
+
*/
|
|
66
|
+
getPendingUpdates() {
|
|
67
|
+
return new Map(this.pendingUpdates);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Checks whether there are any pending updates awaiting commit.
|
|
71
|
+
*
|
|
72
|
+
* @returns `true` if updates are staged, `false` otherwise
|
|
73
|
+
*/
|
|
74
|
+
hasPendingUpdates() {
|
|
75
|
+
return this.pendingUpdates.size > 0;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Clears all pending updates without committing them.
|
|
79
|
+
*
|
|
80
|
+
* @remarks
|
|
81
|
+
* Use with caution - this operation cannot be undone.
|
|
82
|
+
*/
|
|
83
|
+
clearPendingUpdates() {
|
|
84
|
+
this.pendingUpdates.clear();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Gets the number of pending updates in the queue.
|
|
88
|
+
*
|
|
89
|
+
* @returns The count of pending updates that have not been processed yet.
|
|
90
|
+
*/
|
|
91
|
+
getPendingUpdatesCount() {
|
|
92
|
+
return this.pendingUpdates.size;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strategy for writing version updates to build system-specific files.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Implementations handle version persistence for different build systems (Gradle, Maven, npm).
|
|
6
|
+
* Created by {@link ModuleSystemFactory} and used by {@link VersionManager}.
|
|
7
|
+
*/
|
|
8
|
+
export interface VersionUpdateStrategy {
|
|
9
|
+
/**
|
|
10
|
+
* Writes version updates for multiple modules to build system configuration files.
|
|
11
|
+
*
|
|
12
|
+
* @param moduleVersions - Map of module ID to new version string
|
|
13
|
+
* @returns Promise that resolves when all updates are written
|
|
14
|
+
* @throws {Error} If build files cannot be found, are not writable, or I/O operations fail
|
|
15
|
+
*/
|
|
16
|
+
writeVersionUpdates(moduleVersions: Map<string, string>): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=version-update-strategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-update-strategy.d.ts","sourceRoot":"","sources":["../../src/services/version-update-strategy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;;OAMG;IACH,mBAAmB,CAAC,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"banner.d.ts","sourceRoot":"","sources":["../../src/utils/banner.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM,EAAE,MAOpB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const banner = `
|
|
2
|
+
██╗ ██╗███████╗██████╗ ███████╗███████╗
|
|
3
|
+
██║ ██║██╔════╝██╔══██╗██╔════╝██╔════╝
|
|
4
|
+
██║ ██║█████╗ ██████╔╝███████╗█████╗
|
|
5
|
+
╚██╗ ██╔╝██╔══╝ ██╔══██╗╚════██║██╔══╝
|
|
6
|
+
╚████╔╝ ███████╗██║ ██║███████║███████╗
|
|
7
|
+
╚═══╝ ╚══════╝╚═╝ ╚═╝╚══════╝╚══════╝
|
|
8
|
+
`;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Config } from "../config/index.js";
|
|
2
|
+
import { CommitInfo } from "../git/index.js";
|
|
3
|
+
import { BumpType } from "../semver/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Calculates the overall semantic version bump type from a collection of commits.
|
|
6
|
+
* Returns the highest bump type: major > minor > patch > none.
|
|
7
|
+
* @param commits - Array of commit information to analyze
|
|
8
|
+
* @param config - Configuration containing commit type mappings
|
|
9
|
+
* @returns The highest BumpType required across all commits
|
|
10
|
+
*/
|
|
11
|
+
export declare function calculateBumpFromCommits(commits: CommitInfo[], config: Config): BumpType;
|
|
12
|
+
//# sourceMappingURL=commits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commits.d.ts","sourceRoot":"","sources":["../../src/utils/commits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAe,MAAM,oBAAoB,CAAC;AAE3D;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,UAAU,EAAE,EACrB,MAAM,EAAE,MAAM,GACb,QAAQ,CAiBV"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { getBumpTypeForCommit } from "../config/index.js";
|
|
2
|
+
import { maxBumpType } from "../semver/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Calculates the overall semantic version bump type from a collection of commits.
|
|
5
|
+
* Returns the highest bump type: major > minor > patch > none.
|
|
6
|
+
* @param commits - Array of commit information to analyze
|
|
7
|
+
* @param config - Configuration containing commit type mappings
|
|
8
|
+
* @returns The highest BumpType required across all commits
|
|
9
|
+
*/
|
|
10
|
+
export function calculateBumpFromCommits(commits, config) {
|
|
11
|
+
// Collect bump types for all commits
|
|
12
|
+
const bumpTypes = [];
|
|
13
|
+
// Analyze each commit and determine its version impact
|
|
14
|
+
for (const commit of commits) {
|
|
15
|
+
const bumpType = getBumpTypeForCommit(commit.type, commit.breaking, config);
|
|
16
|
+
// Only include commits that require a version bump
|
|
17
|
+
if (bumpType !== "none") {
|
|
18
|
+
bumpTypes.push(bumpType);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// Return the highest bump type required across all commits
|
|
22
|
+
// If no meaningful commits found, returns 'none'
|
|
23
|
+
return maxBumpType(bumpTypes);
|
|
24
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks whether a file or directory exists at the specified path.
|
|
3
|
+
* @param path - Absolute or relative path to check
|
|
4
|
+
* @returns True if the path exists and is accessible, false otherwise
|
|
5
|
+
*/
|
|
6
|
+
export declare function exists(path: string): Promise<boolean>;
|
|
7
|
+
//# sourceMappingURL=file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/utils/file.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAW3D"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { promises as fs } from "fs";
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether a file or directory exists at the specified path.
|
|
4
|
+
* @param path - Absolute or relative path to check
|
|
5
|
+
* @returns True if the path exists and is accessible, false otherwise
|
|
6
|
+
*/
|
|
7
|
+
export async function exists(path) {
|
|
8
|
+
try {
|
|
9
|
+
// Attempt to access the path
|
|
10
|
+
// If access succeeds, the path exists and is accessible
|
|
11
|
+
await fs.access(path);
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// If access fails (any error), consider path as non-existent
|
|
16
|
+
// This includes ENOENT (doesn't exist) and EACCES (no permission)
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface Logger {
|
|
2
|
+
debug(message: string): void;
|
|
3
|
+
info(message: string): void;
|
|
4
|
+
warning(message: string | Error, context?: Record<string, unknown>): void;
|
|
5
|
+
error(message: string | Error, context?: Record<string, unknown>): void;
|
|
6
|
+
}
|
|
7
|
+
export declare function initLogger(logger: Logger): void;
|
|
8
|
+
/**
|
|
9
|
+
* Convenience proxy so existing call sites can
|
|
10
|
+
* import `logger` and call methods. The proxy delegates
|
|
11
|
+
* to the mutable `_current` at call-time.
|
|
12
|
+
*/
|
|
13
|
+
export declare const logger: Logger;
|
|
14
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC1E,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CACzE;AAYD,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,QAExC;AAED;;;;GAIG;AACH,eAAO,MAAM,MAAM,EAAE,MAOpB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// default no-op
|
|
2
|
+
const noopLogger = {
|
|
3
|
+
debug: (_message) => { },
|
|
4
|
+
info: (_message) => { },
|
|
5
|
+
warning: (_message, _context) => { },
|
|
6
|
+
error: (_message, _context) => { },
|
|
7
|
+
};
|
|
8
|
+
let _current = noopLogger;
|
|
9
|
+
export function initLogger(logger) {
|
|
10
|
+
_current = logger;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Convenience proxy so existing call sites can
|
|
14
|
+
* import `logger` and call methods. The proxy delegates
|
|
15
|
+
* to the mutable `_current` at call-time.
|
|
16
|
+
*/
|
|
17
|
+
export const logger = {
|
|
18
|
+
debug: (message) => _current.debug(message),
|
|
19
|
+
info: (message) => _current.info(message),
|
|
20
|
+
warning: (message, context) => _current.warning(message, context),
|
|
21
|
+
error: (message, context) => _current.error(message, context),
|
|
22
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Updates or inserts a single property in a Java-style properties file.
|
|
3
|
+
* @param propertiesPath - Path to the properties file
|
|
4
|
+
* @param key - Property key to update or insert
|
|
5
|
+
* @param value - Property value to set
|
|
6
|
+
*/
|
|
7
|
+
export declare function upsertProperty(propertiesPath: string, key: string, value: string): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Updates or inserts multiple properties in a Java-style properties file.
|
|
10
|
+
* Updates existing properties in place, appends new ones to the end.
|
|
11
|
+
* @param propertiesPath - Path to the properties file
|
|
12
|
+
* @param properties - Map of property keys to values
|
|
13
|
+
* @throws {Error} If file operations fail
|
|
14
|
+
*/
|
|
15
|
+
export declare function upsertProperties(propertiesPath: string, properties: Map<string, string>): Promise<void>;
|
|
16
|
+
//# sourceMappingURL=properties.d.ts.map
|