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

458 lines (457 loc) 18.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.migrationManager = exports.MigrationManager = void 0; exports.autoMigrate = autoMigrate; exports.migrateGlobalConfig = migrateGlobalConfig; exports.migrateProjectConfig = migrateProjectConfig; exports.checkConfigIntegrity = checkConfigIntegrity; const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); const yaml = __importStar(require("yaml")); const config_1 = require("./config"); const error_handler_1 = require("./error-handler"); const semver_1 = __importDefault(require("semver")); // Configuration version history and migrations const CURRENT_CONFIG_VERSION = '1.2.0'; const GLOBAL_CONFIG_MIGRATIONS = [ { version: '1.0.1', description: 'Add CLI theme support', up: (config) => ({ ...config, cli: { ...config.cli, theme: config.cli?.theme || 'auto' } }), validate: (config) => config.cli && typeof config.cli.theme === 'string' }, { version: '1.1.0', description: 'Add plugin marketplace configuration', up: (config) => ({ ...config, plugins: { ...config.plugins, marketplace: { registry: 'https://registry.npmjs.org', autoUpdate: false, ...config.plugins?.marketplace } } }), validate: (config) => config.plugins?.marketplace?.registry }, { version: '1.2.0', description: 'Add user profile and enhanced paths', up: (config) => ({ ...config, user: { name: undefined, email: undefined, organization: undefined, ...config.user }, paths: { ...config.paths, workspace: path.join(config.paths?.cache || '~/.re-shell/cache', 'workspaces'), logs: path.join(config.paths?.cache || '~/.re-shell/cache', 'logs') } }), validate: (config) => config.user && config.paths?.workspace && config.paths?.logs } ]; const PROJECT_CONFIG_MIGRATIONS = [ { version: '1.0.1', description: 'Add environment configurations', up: (config) => ({ ...config, environments: config.environments || { development: { name: 'development', variables: { NODE_ENV: 'development' }, build: { mode: 'development', optimization: false, sourcemaps: true }, deployment: {} }, staging: { name: 'staging', variables: { NODE_ENV: 'staging' }, build: { mode: 'staging', optimization: true, sourcemaps: true }, deployment: {} }, production: { name: 'production', variables: { NODE_ENV: 'production' }, build: { mode: 'production', optimization: true, sourcemaps: false }, deployment: {} } } }), validate: (config) => config.environments && Object.keys(config.environments).length > 0 }, { version: '1.1.0', description: 'Enhanced workspace configuration', up: (config) => ({ ...config, workspaces: { root: '.', patterns: ['apps/*', 'packages/*', 'libs/*', 'tools/*'], types: ['app', 'package', 'lib', 'tool'], ...config.workspaces } }), validate: (config) => config.workspaces?.patterns && Array.isArray(config.workspaces.patterns) }, { version: '1.2.0', description: 'Add quality and security configurations', up: (config) => ({ ...config, quality: { linting: true, testing: true, coverage: { enabled: true, threshold: 80 }, security: { enabled: true, autoFix: false }, ...config.quality } }), validate: (config) => config.quality && typeof config.quality.linting === 'boolean' } ]; // Migration manager class class MigrationManager { constructor() { this.migrations = new Map(); this.migrations.set('global', GLOBAL_CONFIG_MIGRATIONS); this.migrations.set('project', PROJECT_CONFIG_MIGRATIONS); } // Check if migration is needed async needsMigration(configType, currentVersion) { const version = currentVersion || await this.getCurrentVersion(configType); return semver_1.default.lt(version, CURRENT_CONFIG_VERSION); } // Get current configuration version async getCurrentVersion(configType, projectPath) { try { if (configType === 'global') { const globalConfig = await config_1.configManager.loadGlobalConfig(); return globalConfig.version || '1.0.0'; } else { const projectConfig = await config_1.configManager.loadProjectConfig(projectPath); return projectConfig?.version || '1.0.0'; } } catch { return '1.0.0'; } } // Get available migrations for version range getAvailableMigrations(configType, fromVersion, toVersion = CURRENT_CONFIG_VERSION) { const migrations = this.migrations.get(configType) || []; return migrations.filter(migration => { return semver_1.default.gt(migration.version, fromVersion) && semver_1.default.lte(migration.version, toVersion); }).sort((a, b) => semver_1.default.compare(a.version, b.version)); } // Apply migrations async migrate(configType, projectPath) { const fromVersion = await this.getCurrentVersion(configType, projectPath); const toVersion = CURRENT_CONFIG_VERSION; if (!await this.needsMigration(configType, fromVersion)) { return { success: true, fromVersion, toVersion, appliedMigrations: [], warnings: ['Configuration is already up to date'] }; } const migrations = this.getAvailableMigrations(configType, fromVersion, toVersion); const appliedMigrations = []; const errors = []; const warnings = []; try { // Load current configuration let config; if (configType === 'global') { config = await config_1.configManager.loadGlobalConfig(); } else { config = await config_1.configManager.loadProjectConfig(projectPath); if (!config) { throw new error_handler_1.ValidationError('No project configuration found'); } } // Create backup before migration const backupPath = await this.createMigrationBackup(configType, config, projectPath); warnings.push(`Backup created at: ${backupPath}`); // Apply migrations sequentially for (const migration of migrations) { try { console.log(`Applying migration ${migration.version}: ${migration.description}`); // Apply the migration config = migration.up(config); config.version = migration.version; // Validate the result if validation function exists if (migration.validate && !migration.validate(config)) { throw new Error(`Migration validation failed for version ${migration.version}`); } appliedMigrations.push(migration.version); } catch (error) { errors.push(`Migration ${migration.version} failed: ${error.message}`); break; } } // Save migrated configuration if no errors if (errors.length === 0) { config.version = toVersion; if (configType === 'global') { await config_1.configManager.saveGlobalConfig(config); } else { await config_1.configManager.saveProjectConfig(config, projectPath); } } return { success: errors.length === 0, fromVersion, toVersion, appliedMigrations, errors: errors.length > 0 ? errors : undefined, warnings }; } catch (error) { return { success: false, fromVersion, toVersion, appliedMigrations, errors: [`Migration failed: ${error.message}`] }; } } // Rollback to previous version async rollback(configType, targetVersion, projectPath) { const currentVersion = await this.getCurrentVersion(configType, projectPath); if (semver_1.default.gte(targetVersion, currentVersion)) { return { success: false, fromVersion: currentVersion, toVersion: targetVersion, appliedMigrations: [], errors: ['Target version must be lower than current version'] }; } // Get migrations to rollback (in reverse order) const migrations = this.getAvailableMigrations(configType, targetVersion, currentVersion); const reversedMigrations = migrations.reverse(); const appliedMigrations = []; const errors = []; try { // Load current configuration let config; if (configType === 'global') { config = await config_1.configManager.loadGlobalConfig(); } else { config = await config_1.configManager.loadProjectConfig(projectPath); } // Apply rollback migrations for (const migration of reversedMigrations) { if (migration.down) { try { config = migration.down(config); appliedMigrations.push(`rollback-${migration.version}`); } catch (error) { errors.push(`Rollback ${migration.version} failed: ${error.message}`); break; } } else { errors.push(`No rollback available for migration ${migration.version}`); break; } } // Save rolled back configuration if (errors.length === 0) { config.version = targetVersion; if (configType === 'global') { await config_1.configManager.saveGlobalConfig(config); } else { await config_1.configManager.saveProjectConfig(config, projectPath); } } return { success: errors.length === 0, fromVersion: currentVersion, toVersion: targetVersion, appliedMigrations, errors: errors.length > 0 ? errors : undefined }; } catch (error) { return { success: false, fromVersion: currentVersion, toVersion: targetVersion, appliedMigrations, errors: [`Rollback failed: ${error.message}`] }; } } // Create migration backup async createMigrationBackup(configType, config, projectPath) { const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const backupDir = configType === 'global' ? path.join(process.env.HOME || '~', '.re-shell', 'backups', 'migrations') : path.join(projectPath || process.cwd(), '.re-shell', 'backups', 'migrations'); const backupPath = path.join(backupDir, `${configType}-config-${timestamp}.yaml`); await fs.ensureDir(backupDir); const content = yaml.stringify(config); await fs.writeFile(backupPath, content, 'utf8'); return backupPath; } // Check configuration integrity async checkIntegrity(configType, projectPath) { const issues = []; const recommendations = []; try { const version = await this.getCurrentVersion(configType, projectPath); // Check if migration is needed if (await this.needsMigration(configType, version)) { issues.push(`Configuration version ${version} is outdated (current: ${CURRENT_CONFIG_VERSION})`); recommendations.push('Run migration to update to latest version'); } // Load and validate configuration let config; if (configType === 'global') { config = await config_1.configManager.loadGlobalConfig(); } else { config = await config_1.configManager.loadProjectConfig(projectPath); if (!config) { issues.push('No project configuration found'); recommendations.push('Initialize project configuration'); return { valid: false, version, issues, recommendations }; } } // Validate against current schema const migrations = this.getAvailableMigrations(configType, '1.0.0', CURRENT_CONFIG_VERSION); for (const migration of migrations) { if (migration.validate && !migration.validate(config)) { issues.push(`Configuration does not satisfy requirements for version ${migration.version}`); } } return { valid: issues.length === 0, version, issues, recommendations }; } catch (error) { return { valid: false, version: '1.0.0', issues: [`Configuration check failed: ${error.message}`], recommendations: ['Check configuration file syntax and permissions'] }; } } // Auto-migrate on CLI startup if needed async autoMigrate() { const results = { global: null, project: null }; // Auto-migrate global configuration if (await this.needsMigration('global')) { results.global = await this.migrate('global'); } // Auto-migrate project configuration if in a project directory try { const projectConfig = await config_1.configManager.loadProjectConfig(); if (projectConfig && await this.needsMigration('project')) { results.project = await this.migrate('project'); } } catch { // Not in a project directory, skip project migration } return results; } // Get migration history async getMigrationHistory(configType, projectPath) { const currentVersion = await this.getCurrentVersion(configType, projectPath); const allMigrations = this.migrations.get(configType) || []; const availableVersions = allMigrations.map(m => m.version); const appliedMigrations = allMigrations .filter(m => semver_1.default.lte(m.version, currentVersion)) .map(m => m.version); const pendingMigrations = allMigrations .filter(m => semver_1.default.gt(m.version, currentVersion)) .map(m => m.version); return { currentVersion, availableVersions, appliedMigrations, pendingMigrations }; } } exports.MigrationManager = MigrationManager; // Export singleton instance exports.migrationManager = new MigrationManager(); // Helper functions async function autoMigrate() { return exports.migrationManager.autoMigrate(); } async function migrateGlobalConfig() { return exports.migrationManager.migrate('global'); } async function migrateProjectConfig(projectPath) { return exports.migrationManager.migrate('project', projectPath); } async function checkConfigIntegrity(configType, projectPath) { return exports.migrationManager.checkIntegrity(configType, projectPath); }