@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
JavaScript
;
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`;
}
}