UNPKG

@re-shell/cli

Version:

Full-stack development platform uniting microservices and microfrontends. Build complete applications with .NET (ASP.NET Core Web API, Minimal API), Java (Spring Boot, Quarkus, Micronaut, Vert.x), Rust (Actix-Web, Warp, Rocket, Axum), Python (FastAPI, Dja

532 lines (531 loc) • 21.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.manageWorkspaceMigration = manageWorkspaceMigration; const chalk_1 = __importDefault(require("chalk")); const prompts_1 = __importDefault(require("prompts")); const fs = __importStar(require("fs-extra")); const semver = __importStar(require("semver")); const workspace_migration_1 = require("../utils/workspace-migration"); const error_handler_1 = require("../utils/error-handler"); const DEFAULT_WORKSPACE_FILE = 're-shell.workspaces.yaml'; async function manageWorkspaceMigration(options = {}) { const { spinner, verbose, json } = options; try { if (options.check) { await checkUpgrades(options, spinner); return; } if (options.plan) { await createMigrationPlan(options, spinner); return; } if (options.upgrade) { await upgradeWorkspace(options, spinner); return; } if (options.validate) { await validateWorkspaceDefinition(options, spinner); return; } if (options.history) { await showMigrationHistory(options, spinner); return; } if (options.rollback) { await rollbackMigration(options, spinner); return; } if (options.interactive) { await interactiveMigrationManagement(options, spinner); return; } // Default: check for upgrades await checkUpgrades(options, spinner); } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Migration operation failed')); throw error; } } async function checkUpgrades(options, spinner) { const workspaceFile = options.workspaceFile || DEFAULT_WORKSPACE_FILE; if (!(await fs.pathExists(workspaceFile))) { throw new error_handler_1.ValidationError(`Workspace file not found: ${workspaceFile}`); } if (spinner) spinner.setText('Checking for available upgrades...'); try { const upgrades = await (0, workspace_migration_1.checkForUpgrades)(workspaceFile); if (spinner) spinner.stop(); if (options.json) { console.log(JSON.stringify(upgrades, null, 2)); return; } console.log(chalk_1.default.cyan('\nšŸ”„ Workspace Upgrade Check')); console.log(chalk_1.default.gray('═'.repeat(50))); console.log(`Current version: ${chalk_1.default.yellow(upgrades.currentVersion)}`); if (upgrades.available.length === 0) { console.log(chalk_1.default.green('\nāœ… Workspace is up to date!')); console.log(chalk_1.default.gray('No upgrades available for your current version.')); return; } console.log(`\n${chalk_1.default.blue('Available upgrades:')}`); for (const version of upgrades.available) { const type = semver.diff(upgrades.currentVersion, version); const icon = type === 'major' ? '🚨' : type === 'minor' ? 'šŸ”§' : 'šŸ”Ø'; console.log(` ${icon} ${version} (${type})`); } if (upgrades.recommended) { console.log(`\n${chalk_1.default.green('Recommended:')} ${upgrades.recommended}`); } if (upgrades.breaking && upgrades.breaking.length > 0) { console.log(`\n${chalk_1.default.red('Breaking changes in:')} ${upgrades.breaking.join(', ')}`); } console.log(chalk_1.default.cyan('\nšŸ› ļø Commands:')); console.log(` • Plan upgrade: re-shell workspace-migration plan --target-version ${upgrades.recommended}`); console.log(` • Upgrade: re-shell workspace-migration upgrade --target-version ${upgrades.recommended}`); console.log(' • Interactive: re-shell workspace-migration interactive'); } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Failed to check upgrades')); throw error; } } async function createMigrationPlan(options, spinner) { const workspaceFile = options.workspaceFile || DEFAULT_WORKSPACE_FILE; if (!options.targetVersion) { throw new error_handler_1.ValidationError('Target version is required for migration planning'); } if (spinner) spinner.setText('Creating migration plan...'); try { const manager = await (0, workspace_migration_1.createWorkspaceMigrationManager)(); const definition = await manager['loadWorkspaceDefinition'](workspaceFile); const plan = await manager.createMigrationPlan(definition.version, options.targetVersion); if (spinner) spinner.stop(); if (options.json) { console.log(JSON.stringify(plan, null, 2)); return; } console.log(chalk_1.default.cyan('\nšŸ“‹ Migration Plan')); console.log(chalk_1.default.gray('═'.repeat(50))); console.log(`From: ${chalk_1.default.yellow(plan.currentVersion)}`); console.log(`To: ${chalk_1.default.green(plan.targetVersion)}`); console.log(`Steps: ${plan.steps.length}`); console.log(`Estimated duration: ${formatDuration(plan.estimatedDuration)}`); if (plan.hasBreakingChanges) { console.log(chalk_1.default.red('\nāš ļø This migration contains breaking changes!')); } if (plan.backupRequired) { console.log(chalk_1.default.yellow('\nšŸ’¾ Backup will be created automatically')); } console.log(chalk_1.default.cyan('\nšŸ“ Migration Steps:')); for (let i = 0; i < plan.steps.length; i++) { const step = plan.steps[i]; const icon = step.breaking ? '🚨' : 'šŸ”§'; console.log(` ${i + 1}. ${icon} ${step.name}`); if (options.verbose) { console.log(` ${chalk_1.default.gray(step.description)}`); console.log(` ${chalk_1.default.gray(`${step.fromVersion} → ${step.toVersion}`)}`); } } console.log(chalk_1.default.cyan('\nšŸš€ Next steps:')); console.log(` • Execute: re-shell workspace-migration upgrade --target-version ${options.targetVersion}`); console.log(` • Dry run: re-shell workspace-migration upgrade --target-version ${options.targetVersion} --dry-run`); } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Failed to create migration plan')); throw error; } } async function upgradeWorkspace(options, spinner) { const workspaceFile = options.workspaceFile || DEFAULT_WORKSPACE_FILE; if (!options.targetVersion) { throw new error_handler_1.ValidationError('Target version is required for upgrade'); } if (spinner) spinner.setText('Preparing workspace upgrade...'); try { const manager = await (0, workspace_migration_1.createWorkspaceMigrationManager)(); const definition = await manager['loadWorkspaceDefinition'](workspaceFile); const plan = await manager.createMigrationPlan(definition.version, options.targetVersion); if (spinner) spinner.setText('Executing migration...'); const upgradeOptions = { targetVersion: options.targetVersion, force: options.force, dryRun: options.dryRun, backup: options.backup ?? true, skipValidation: options.skipValidation, interactive: false }; const result = await manager.executeMigration(workspaceFile, plan, upgradeOptions); if (spinner) spinner.stop(); if (options.json) { console.log(JSON.stringify(result, null, 2)); return; } if (result.success) { if (options.dryRun) { console.log(chalk_1.default.cyan('šŸ” Migration Dry Run Completed')); } else { console.log(chalk_1.default.green('āœ… Migration completed successfully!')); } } else { console.log(chalk_1.default.red('āŒ Migration failed!')); } console.log(chalk_1.default.gray('═'.repeat(50))); console.log(`From: ${chalk_1.default.yellow(result.fromVersion)}`); console.log(`To: ${chalk_1.default.green(result.toVersion)}`); console.log(`Duration: ${formatDuration(result.duration / 1000)}`); if (result.backupId) { console.log(`Backup: ${chalk_1.default.blue(result.backupId)}`); } if (result.stepsExecuted.length > 0) { console.log(`\n${chalk_1.default.cyan('Executed steps:')}`); for (const step of result.stepsExecuted) { console.log(` āœ“ ${step}`); } } if (result.warnings.length > 0) { console.log(`\n${chalk_1.default.yellow('Warnings:')}`); for (const warning of result.warnings) { console.log(` āš ļø ${warning}`); } } if (result.errors.length > 0) { console.log(`\n${chalk_1.default.red('Errors:')}`); for (const error of result.errors) { console.log(` āŒ ${error}`); } } if (!options.dryRun && result.success) { // Record migration in history await manager.recordMigration(result.fromVersion, result.toVersion, result.backupId); console.log(chalk_1.default.cyan('\nšŸŽ‰ Upgrade complete!')); console.log(chalk_1.default.gray('Run workspace validation to ensure everything is working:')); console.log(' re-shell workspace-migration validate'); } } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Migration failed')); throw error; } } async function validateWorkspaceDefinition(options, spinner) { const workspaceFile = options.workspaceFile || DEFAULT_WORKSPACE_FILE; if (spinner) spinner.setText('Validating workspace definition...'); try { const validation = await (0, workspace_migration_1.validateWorkspace)(workspaceFile); if (spinner) spinner.stop(); if (options.json) { console.log(JSON.stringify(validation, null, 2)); return; } console.log(chalk_1.default.cyan('\nšŸ” Workspace Validation')); console.log(chalk_1.default.gray('═'.repeat(50))); if (validation.valid) { console.log(chalk_1.default.green('āœ… Workspace definition is valid!')); } else { console.log(chalk_1.default.red('āŒ Workspace definition has errors!')); } if (validation.errors.length > 0) { console.log(`\n${chalk_1.default.red('Errors:')} (${validation.errors.length})`); for (const error of validation.errors) { console.log(` āŒ ${error}`); } } if (validation.warnings.length > 0) { console.log(`\n${chalk_1.default.yellow('Warnings:')} (${validation.warnings.length})`); for (const warning of validation.warnings) { console.log(` āš ļø ${warning}`); } } if (validation.suggestions.length > 0) { console.log(`\n${chalk_1.default.blue('Suggestions:')} (${validation.suggestions.length})`); for (const suggestion of validation.suggestions) { console.log(` šŸ’” ${suggestion}`); } } if (!validation.valid) { process.exit(1); } } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Validation failed')); throw error; } } async function showMigrationHistory(options, spinner) { const workspaceFile = options.workspaceFile || DEFAULT_WORKSPACE_FILE; if (spinner) spinner.setText('Loading migration history...'); try { const manager = await (0, workspace_migration_1.createWorkspaceMigrationManager)(); const history = await manager.getMigrationHistory(workspaceFile); if (spinner) spinner.stop(); if (options.json) { console.log(JSON.stringify(history, null, 2)); return; } if (history.migrations.length === 0) { console.log(chalk_1.default.yellow('\nšŸ“ No migration history found')); console.log(chalk_1.default.gray('This workspace has not been migrated yet.')); return; } console.log(chalk_1.default.cyan('\nšŸ“š Migration History')); console.log(chalk_1.default.gray('═'.repeat(50))); for (let i = history.migrations.length - 1; i >= 0; i--) { const migration = history.migrations[i]; const date = new Date(migration.date).toLocaleString(); console.log(`\n${i + 1}. ${chalk_1.default.yellow(migration.fromVersion)} → ${chalk_1.default.green(migration.toVersion)}`); console.log(` Date: ${chalk_1.default.gray(date)}`); if (migration.backupId) { console.log(` Backup: ${chalk_1.default.blue(migration.backupId)}`); } } console.log(chalk_1.default.cyan('\nšŸ› ļø Commands:')); console.log(' • Show backup: re-shell workspace-backup show <backup-id>'); console.log(' • Restore backup: re-shell workspace-backup restore <backup-id>'); } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Failed to load migration history')); throw error; } } async function rollbackMigration(options, spinner) { if (spinner) spinner.setText('Preparing rollback...'); try { const manager = await (0, workspace_migration_1.createWorkspaceMigrationManager)(); const workspaceFile = options.workspaceFile || DEFAULT_WORKSPACE_FILE; const history = await manager.getMigrationHistory(workspaceFile); if (history.migrations.length === 0) { throw new error_handler_1.ValidationError('No migration history found for rollback'); } const lastMigration = history.migrations[history.migrations.length - 1]; if (!lastMigration.backupId) { throw new error_handler_1.ValidationError('No backup available for rollback'); } if (spinner) spinner.setText(`Rolling back to backup: ${lastMigration.backupId}`); // Use backup restore functionality const { manageWorkspaceBackup } = await Promise.resolve().then(() => __importStar(require('./workspace-backup'))); await manageWorkspaceBackup({ restore: true, name: lastMigration.backupId, force: options.force }); if (spinner) spinner.stop(); console.log(chalk_1.default.green('āœ… Rollback completed successfully!')); console.log(chalk_1.default.gray(`Restored to version: ${lastMigration.fromVersion}`)); console.log(chalk_1.default.gray(`From backup: ${lastMigration.backupId}`)); } catch (error) { if (spinner) spinner.fail(chalk_1.default.red('Rollback failed')); throw error; } } async function interactiveMigrationManagement(options, spinner) { if (spinner) spinner.stop(); const response = await (0, prompts_1.default)([ { type: 'select', name: 'action', message: 'What would you like to do?', choices: [ { title: 'šŸ”„ Check for upgrades', value: 'check' }, { title: 'šŸ“‹ Create migration plan', value: 'plan' }, { title: 'šŸš€ Upgrade workspace', value: 'upgrade' }, { title: 'šŸ” Validate workspace', value: 'validate' }, { title: 'šŸ“š View migration history', value: 'history' }, { title: 'ā†©ļø Rollback last migration', value: 'rollback' } ] } ]); if (!response.action) return; switch (response.action) { case 'check': await checkUpgrades({ ...options, interactive: false }); break; case 'plan': await createPlanInteractive(options); break; case 'upgrade': await upgradeInteractive(options); break; case 'validate': await validateWorkspaceDefinition({ ...options, interactive: false }); break; case 'history': await showMigrationHistory({ ...options, interactive: false }); break; case 'rollback': await rollbackInteractive(options); break; } } async function createPlanInteractive(options) { const response = await (0, prompts_1.default)([ { type: 'text', name: 'workspaceFile', message: 'Workspace file:', initial: 're-shell.workspaces.yaml' }, { type: 'text', name: 'targetVersion', message: 'Target version:' } ]); if (!response.workspaceFile || !response.targetVersion) return; await createMigrationPlan({ ...options, ...response, interactive: false }); } async function upgradeInteractive(options) { const response = await (0, prompts_1.default)([ { type: 'text', name: 'workspaceFile', message: 'Workspace file:', initial: 're-shell.workspaces.yaml' }, { type: 'text', name: 'targetVersion', message: 'Target version:' }, { type: 'confirm', name: 'dryRun', message: 'Perform dry run first?', initial: true }, { type: prev => prev ? null : 'confirm', name: 'backup', message: 'Create backup before upgrade?', initial: true }, { type: prev => prev === false ? null : 'confirm', name: 'force', message: 'Force upgrade (skip confirmations)?', initial: false } ]); if (!response.workspaceFile || !response.targetVersion) return; await upgradeWorkspace({ ...options, ...response, interactive: false }); } async function rollbackInteractive(options) { const response = await (0, prompts_1.default)([ { type: 'text', name: 'workspaceFile', message: 'Workspace file:', initial: 're-shell.workspaces.yaml' }, { type: 'confirm', name: 'confirm', message: 'Are you sure you want to rollback the last migration?', initial: false }, { type: prev => prev ? 'confirm' : null, name: 'force', message: 'Force rollback (overwrite existing files)?', initial: false } ]); if (!response.confirm) { console.log(chalk_1.default.yellow('Rollback cancelled')); return; } await rollbackMigration({ ...options, ...response, interactive: false }); } // Utility functions function formatDuration(seconds) { if (seconds < 60) { return `${seconds.toFixed(0)}s`; } else if (seconds < 3600) { const minutes = Math.floor(seconds / 60); const remainingSeconds = seconds % 60; return `${minutes}m ${remainingSeconds.toFixed(0)}s`; } else { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); return `${hours}h ${minutes}m`; } }