ng-upgrade-orchestrator
Version:
Enterprise-grade Angular Multi-Version Upgrade Orchestrator with automatic npm installation, comprehensive dependency management, and seamless integration of all 9 official Angular migrations. Safely migrate Angular applications across multiple major vers
431 lines • 18.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.UpgradeOrchestrator = void 0;
const events_1 = require("events");
const VersionHandlerRegistry_1 = require("./VersionHandlerRegistry");
const CheckpointManager_1 = require("./CheckpointManager");
const UpgradePathCalculator_1 = require("./UpgradePathCalculator");
const ProjectAnalyzer_1 = require("./ProjectAnalyzer");
const ValidatorFramework_1 = require("./ValidatorFramework");
const RollbackEngine_1 = require("./RollbackEngine");
/**
* Main orchestrator class for Angular multi-version upgrades.
*
* The UpgradeOrchestrator is the central coordination engine that manages the entire
* upgrade process from planning to execution to validation. It orchestrates multiple
* subsystems to provide a safe, reliable, and comprehensive upgrade experience.
*
* @class UpgradeOrchestrator
* @extends EventEmitter
*
* @example
* ```typescript
* const orchestrator = new UpgradeOrchestrator('/path/to/angular/project');
*
* // Set up event listeners
* orchestrator.on('progress', (report) => console.log(report.message));
* orchestrator.on('step-complete', (step) => console.log(`✅ ${step.toVersion}`));
*
* // Execute upgrade
* const result = await orchestrator.orchestrateUpgrade({
* targetVersion: '17',
* strategy: 'balanced',
* checkpointFrequency: 'major-versions',
* validationLevel: 'comprehensive'
* });
* ```
*
* @emits progress - Emitted during upgrade progress with status updates
* @emits analysis-complete - Emitted when project analysis is finished
* @emits path-calculated - Emitted when upgrade path has been calculated
* @emits step-start - Emitted when starting an individual upgrade step
* @emits step-complete - Emitted when completing an individual upgrade step
* @emits step-failed - Emitted when an upgrade step fails
* @emits manual-intervention - Emitted when manual user intervention is required
* @emits upgrade-complete - Emitted when entire upgrade process succeeds
* @emits upgrade-failed - Emitted when upgrade process fails
* @emits rollback-start - Emitted when rollback process begins
* @emits rollback-complete - Emitted when rollback process completes
*/
class UpgradeOrchestrator extends events_1.EventEmitter {
projectPath;
versionHandlers;
checkpointManager;
pathCalculator;
projectAnalyzer;
validator;
rollbackEngine;
currentCheckpoint;
/**
* Creates a new UpgradeOrchestrator instance.
*
* @param {string} projectPath - Absolute path to the Angular project root directory
*
* @throws {Error} If projectPath is not a valid directory
*
* @example
* ```typescript
* const orchestrator = new UpgradeOrchestrator('/Users/dev/my-angular-app');
* ```
*/
constructor(projectPath) {
super();
this.projectPath = projectPath;
this.versionHandlers = new VersionHandlerRegistry_1.VersionHandlerRegistry();
this.checkpointManager = new CheckpointManager_1.CheckpointManager(projectPath);
this.pathCalculator = new UpgradePathCalculator_1.UpgradePathCalculator();
this.projectAnalyzer = new ProjectAnalyzer_1.ProjectAnalyzer(projectPath);
this.validator = new ValidatorFramework_1.ValidatorFramework(projectPath);
this.rollbackEngine = new RollbackEngine_1.RollbackEngine(this.checkpointManager);
}
/**
* Main orchestration method for multi-version Angular upgrades.
*
* This is the primary entry point for executing an Angular upgrade. It coordinates
* all aspects of the upgrade process including analysis, path calculation, checkpoint
* creation, step-by-step execution, validation, and rollback on failure.
*
* The method follows this high-level flow:
* 1. Analyze the current project state and dependencies
* 2. Calculate the optimal upgrade path from current to target version
* 3. Validate prerequisites for the entire upgrade journey
* 4. Create initial checkpoint for rollback safety
* 5. Execute each upgrade step sequentially with validation
* 6. Create checkpoints at configurable intervals
* 7. Perform final validation of the upgraded application
* 8. Handle failures with automatic rollback if configured
*
* @param {UpgradeOptions} options - Configuration options for the upgrade process
* @param {string} options.targetVersion - Target Angular version (e.g., '17', '18')
* @param {'conservative'|'balanced'|'progressive'} options.strategy - Upgrade strategy
* @param {'every-step'|'major-versions'|'custom'} options.checkpointFrequency - When to create checkpoints
* @param {'basic'|'comprehensive'} options.validationLevel - Depth of validation testing
* @param {'automatic'|'manual'|'prompt'} options.thirdPartyHandling - How to handle third-party deps
* @param {'auto-on-failure'|'manual'|'never'} options.rollbackPolicy - Rollback behavior
* @param {boolean} options.parallelProcessing - Enable parallel processing where safe
* @param {string} [options.backupPath] - Custom backup location
*
* @returns {Promise<UpgradeResult>} Result object containing success status, timing, and details
*
* @throws {Error} If project analysis fails or invalid configuration provided
*
* @example
* ```typescript
* // Basic upgrade to Angular 17
* const result = await orchestrator.orchestrateUpgrade({
* targetVersion: '17',
* strategy: 'balanced'
* });
*
* // Conservative upgrade with comprehensive validation
* const result = await orchestrator.orchestrateUpgrade({
* targetVersion: '16',
* strategy: 'conservative',
* checkpointFrequency: 'every-step',
* validationLevel: 'comprehensive',
* rollbackPolicy: 'auto-on-failure'
* });
* ```
*/
async orchestrateUpgrade(options) {
const startTime = Date.now();
const completedSteps = [];
const checkpoints = [];
try {
this.emit('progress', { message: 'Starting upgrade orchestration', phase: 'initialization' });
// 1. Analyze current project
const analysis = await this.projectAnalyzer.analyze();
this.emit('analysis-complete', analysis);
// 2. Calculate upgrade path
const upgradePath = await this.pathCalculator.calculatePath(analysis.currentVersion, this.parseVersion(options.targetVersion), options);
this.emit('path-calculated', upgradePath);
// 3. Validate prerequisites for entire path
await this.validatePrerequisites(upgradePath, options);
// 4. Create initial checkpoint
const initialCheckpoint = await this.checkpointManager.createCheckpoint('initial', `Before upgrade from ${analysis.currentVersion.full} to ${options.targetVersion}`);
checkpoints.push(initialCheckpoint);
this.currentCheckpoint = initialCheckpoint;
// 5. Execute upgrade steps
for (const step of upgradePath.steps) {
this.emit('step-start', step);
try {
await this.executeUpgradeStep(step, options, analysis);
completedSteps.push(step);
// Create checkpoint after each step if configured
if (this.shouldCreateCheckpoint(step, options)) {
const checkpoint = await this.checkpointManager.createCheckpoint(`step-${step.toVersion}`, `After upgrade to Angular ${step.toVersion}`);
checkpoints.push(checkpoint);
this.currentCheckpoint = checkpoint;
}
this.emit('step-complete', step);
}
catch (error) {
this.emit('step-failed', { step, error });
if (options.rollbackPolicy === 'auto-on-failure') {
await this.handleFailureRollback(error, options);
}
throw new Error(`Upgrade step failed: ${step.fromVersion} -> ${step.toVersion}: ${error}`);
}
}
// 6. Final validation
await this.performFinalValidation(options);
const duration = Date.now() - startTime;
const result = {
success: true,
fromVersion: analysis.currentVersion.full,
toVersion: options.targetVersion,
completedSteps,
warnings: [],
checkpoints,
duration,
rollbackAvailable: checkpoints.length > 0
};
this.emit('upgrade-complete', result);
return result;
}
catch (error) {
const duration = Date.now() - startTime;
const result = {
success: false,
fromVersion: '',
toVersion: options.targetVersion,
completedSteps,
error: error,
warnings: [],
checkpoints,
duration,
rollbackAvailable: checkpoints.length > 0
};
this.emit('upgrade-failed', result);
return result;
}
}
/**
* Execute a single upgrade step within the upgrade journey.
*
* This method handles the execution of one version-to-version upgrade step,
* including prerequisite validation, breaking change application, version-specific
* transformations, and step validation.
*
* @private
* @param {UpgradeStep} step - The upgrade step configuration to execute
* @param {UpgradeOptions} options - Overall upgrade options
* @param {ProjectAnalysis} analysis - Current project analysis results
*
* @throws {Error} If any part of the step execution fails
*
* @example
* ```typescript
* // Internal usage - executes Angular 16 -> 17 upgrade
* await this.executeUpgradeStep(
* { fromVersion: '16', toVersion: '17', ... },
* options,
* analysis
* );
* ```
*/
async executeUpgradeStep(step, options, analysis) {
// Get version-specific handler
const handler = this.versionHandlers.getHandler(step.toVersion);
if (!handler) {
throw new Error(`No handler found for Angular version ${step.toVersion}`);
}
// Update progress
this.emit('progress', {
message: `Executing upgrade: ${step.fromVersion} -> ${step.toVersion}`,
phase: 'execution',
step
});
// Execute prerequisites
await this.executePrerequisites(step, options);
// Apply breaking changes
await this.applyBreakingChanges(step, options);
// Run version-specific handler
await handler.execute(this.projectPath, step, options);
// Run validations
await this.runStepValidations(step, options);
}
/**
* Validate prerequisites for entire upgrade path
*/
async validatePrerequisites(path, options) {
this.emit('progress', { message: 'Validating prerequisites', phase: 'validation' });
for (const step of path.steps) {
for (const prereq of step.prerequisites) {
if (prereq.critical) {
const isValid = await this.validator.validatePrerequisite(prereq);
if (!isValid) {
throw new Error(`Critical prerequisite not met: ${prereq.name} ${prereq.requiredVersion}`);
}
}
}
}
}
/**
* Execute prerequisites for a single step
*/
async executePrerequisites(step, options) {
for (const prereq of step.prerequisites) {
const isValid = await this.validator.validatePrerequisite(prereq);
if (!isValid && prereq.critical) {
throw new Error(`Prerequisite validation failed: ${prereq.name}`);
}
}
}
/**
* Apply breaking changes for a step
*/
async applyBreakingChanges(step, options) {
for (const change of step.breakingChanges) {
if (change.migration.type === 'automatic') {
// Apply automatic transformation
const transformer = this.versionHandlers.getTransformer(change.type);
await transformer?.apply(this.projectPath, change);
}
else if (change.migration.type === 'manual') {
// Emit manual intervention required
this.emit('manual-intervention', {
change,
instructions: change.migration.instructions
});
}
}
}
/**
* Run validations for a single step
*/
async runStepValidations(step, options) {
for (const validation of step.validations) {
if (validation.required || options.validationLevel === 'comprehensive') {
const result = await this.validator.runValidation(validation);
if (!result.success && validation.required) {
throw new Error(`Validation failed: ${validation.description} - ${result.error}`);
}
}
}
}
/**
* Perform final validation after all steps
*/
async performFinalValidation(options) {
this.emit('progress', { message: 'Performing final validation', phase: 'final-validation' });
const validations = [
{ type: 'build', description: 'Final build validation', required: true },
{ type: 'test', description: 'Final test validation', required: options.validationLevel === 'comprehensive' }
];
for (const validation of validations) {
if (validation.required) {
const result = await this.validator.runValidation(validation);
if (!result.success) {
throw new Error(`Final validation failed: ${validation.description}`);
}
}
}
}
/**
* Handle failure rollback
*/
async handleFailureRollback(error, options) {
if (this.currentCheckpoint) {
this.emit('rollback-start', { checkpoint: this.currentCheckpoint, reason: error.message });
await this.rollbackEngine.rollbackToCheckpoint(this.currentCheckpoint.id);
this.emit('rollback-complete', { checkpoint: this.currentCheckpoint });
}
}
/**
* Determine if checkpoint should be created after step
*/
shouldCreateCheckpoint(step, options) {
switch (options.checkpointFrequency) {
case 'every-step':
return true;
case 'major-versions':
return step.required;
case 'custom':
return step.required; // Could be customized further
default:
return false;
}
}
/**
* Parse version string to AngularVersion object
*/
parseVersion(versionString) {
const [major, minor = 0, patch = 0] = versionString.split('.').map(Number);
return {
major,
minor,
patch,
full: `${major}.${minor}.${patch}`
};
}
/**
* Get list of available checkpoints for this project.
*
* Returns all checkpoints that have been created during upgrade processes,
* sorted by creation time. Each checkpoint represents a complete snapshot
* of the project at a specific point in the upgrade journey.
*
* @returns {Promise<Checkpoint[]>} Array of available checkpoints
*
* @example
* ```typescript
* const checkpoints = await orchestrator.getCheckpoints();
* checkpoints.forEach(cp => {
* console.log(`${cp.id}: ${cp.description} (${cp.version})`);
* });
* ```
*/
async getCheckpoints() {
return this.checkpointManager.listCheckpoints();
}
/**
* Rollback project to a specific checkpoint.
*
* This method safely restores the project to a previous state by rolling back
* all changes made since the specified checkpoint was created. This includes
* code changes, configuration updates, and dependency modifications.
*
* @param {string} checkpointId - Unique identifier of the checkpoint to restore
*
* @throws {Error} If checkpoint doesn't exist or rollback fails
*
* @emits rollback-start - When rollback process begins
* @emits rollback-complete - When rollback process completes successfully
*
* @example
* ```typescript
* // Rollback to checkpoint created before Angular 17 upgrade
* await orchestrator.rollbackToCheckpoint('pre-angular-17');
* ```
*/
async rollbackToCheckpoint(checkpointId) {
this.emit('rollback-start', { checkpointId });
await this.rollbackEngine.rollbackToCheckpoint(checkpointId);
this.emit('rollback-complete', { checkpointId });
}
/**
* Get current upgrade progress information.
*
* Returns real-time progress information about an ongoing upgrade process,
* including current step, completion percentage, and estimated time remaining.
* Returns null if no upgrade is currently in progress.
*
* @returns {ProgressReport | null} Current progress information or null
*
* @example
* ```typescript
* const progress = orchestrator.getProgress();
* if (progress) {
* console.log(`Progress: ${progress.completedSteps}/${progress.totalSteps}`);
* console.log(`Current: ${progress.currentStep.description}`);
* }
* ```
*/
getProgress() {
// Implementation would track current progress
return null;
}
}
exports.UpgradeOrchestrator = UpgradeOrchestrator;
//# sourceMappingURL=UpgradeOrchestrator.js.map