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

347 lines (346 loc) • 15.5 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.manageIncrementalBuild = manageIncrementalBuild; exports.registerIncrementalBuildCommands = registerIncrementalBuildCommands; const path = __importStar(require("path")); const fs = __importStar(require("fs-extra")); const chalk_1 = __importDefault(require("chalk")); const spinner_1 = require("../utils/spinner"); const error_handler_1 = require("../utils/error-handler"); const incremental_builder_1 = require("../utils/incremental-builder"); // Main command handler for incremental building async function manageIncrementalBuild(options = {}) { const spinner = new spinner_1.ProgressSpinner({ text: 'Initializing incremental builder...' }); try { const rootPath = process.cwd(); // Validate that we're in a Re-Shell project const packageJsonPath = path.join(rootPath, 'package.json'); if (!await fs.pathExists(packageJsonPath)) { throw new error_handler_1.ValidationError('Not in a valid project directory (package.json not found)'); } spinner.start(); const builder = await (0, incremental_builder_1.createIncrementalBuilder)(rootPath, { maxParallelBuilds: options.maxParallelBuilds, enableCache: options.enableCache !== false, cacheLocation: options.cacheLocation, cleanBuild: options.cleanBuild || false, dryRun: options.dryRun || false, verbose: options.verbose || false, skipTests: options.skipTests || false, failFast: options.failFast !== false, buildTimeout: options.buildTimeout }); spinner.stop(); // Handle different command modes if (options.clearCache) { await handleClearCache(builder); } else if (options.stats) { await handleShowStats(builder, options); } else if (options.plan) { await handleShowPlan(builder, options); } else { await handleBuild(builder, options); } } catch (error) { spinner.stop(); if (error instanceof error_handler_1.ValidationError) { throw error; } throw new error_handler_1.ValidationError(`Incremental build failed: ${error}`); } } // Handle build execution async function handleBuild(builder, options) { console.log(chalk_1.default.cyan('\nšŸš€ Incremental Build')); console.log(chalk_1.default.gray('='.repeat(25))); const plan = await builder.createBuildPlan(options.changedFiles); if (plan.targets.length === 0) { console.log(chalk_1.default.green('āœ… No targets need rebuilding - all builds are up to date!')); return; } // Show plan summary console.log(`\nšŸ“‹ Build Plan:`); console.log(` • Targets to build: ${chalk_1.default.yellow(plan.targets.length)}`); console.log(` • Estimated time: ${chalk_1.default.yellow(Math.round(plan.totalEstimatedTime / 1000))}s`); console.log(` • Parallel groups: ${chalk_1.default.yellow(plan.parallelGroups.length)}`); if (options.verbose && plan.optimizations.length > 0) { console.log(`\nšŸ’” Optimizations:`); plan.optimizations.forEach(opt => console.log(` • ${opt}`)); } // Execute build const results = await builder.executeBuildPlan(plan); // Output results if (options.format === 'json') { const output = { plan, results, summary: { total: results.length, successful: results.filter(r => r.success).length, failed: results.filter(r => !r.success).length, totalTime: results.reduce((sum, r) => sum + r.duration, 0), cacheHits: results.filter(r => r.cacheHit).length } }; if (options.output) { await fs.writeJson(options.output, output, { spaces: 2 }); console.log(chalk_1.default.green(`āœ“ Build results saved to ${options.output}`)); } else { console.log(JSON.stringify(output, null, 2)); } } else { await outputBuildResults(results, options.verbose || false); } } // Handle showing build plan without execution async function handleShowPlan(builder, options) { console.log(chalk_1.default.cyan('\nšŸ“‹ Build Plan Analysis')); console.log(chalk_1.default.gray('='.repeat(30))); const plan = await builder.createBuildPlan(options.changedFiles); if (plan.targets.length === 0) { console.log(chalk_1.default.green('āœ… No targets need rebuilding - all builds are up to date!')); return; } // Show detailed plan console.log(`\nšŸ“Š Summary:`); console.log(` • Targets to build: ${chalk_1.default.yellow(plan.targets.length)}`); console.log(` • Build order: ${plan.buildOrder.join(' → ')}`); console.log(` • Parallel groups: ${chalk_1.default.yellow(plan.parallelGroups.length)}`); console.log(` • Estimated time: ${chalk_1.default.yellow(Math.round(plan.totalEstimatedTime / 1000))}s`); console.log(`\nšŸ—ļø Targets:`); plan.targets.forEach((target, index) => { const typeColor = getTargetTypeColor(target.type); console.log(` ${chalk_1.default.yellow(index + 1)}. ${typeColor(target.name)} (${target.type})`); if (options.verbose) { console.log(` Path: ${chalk_1.default.gray(target.path)}`); console.log(` Build: ${chalk_1.default.gray(target.buildScript)}`); if (target.dependencies.length > 0) { console.log(` Dependencies: ${chalk_1.default.gray(target.dependencies.join(', '))}`); } } }); console.log(`\nšŸ”€ Parallel Execution Groups:`); plan.parallelGroups.forEach((group, index) => { console.log(` Group ${chalk_1.default.yellow(index + 1)}: ${group.join(', ')}`); }); if (plan.optimizations.length > 0) { console.log(`\nšŸ’” Optimizations:`); plan.optimizations.forEach(opt => console.log(` • ${opt}`)); } // Output to file if requested if (options.output) { if (options.format === 'json') { await fs.writeJson(options.output, plan, { spaces: 2 }); } else { const planText = `Build Plan\n${JSON.stringify(plan, null, 2)}`; await fs.writeFile(options.output, planText); } console.log(chalk_1.default.green(`\nāœ“ Build plan saved to ${options.output}`)); } } // Handle showing build statistics async function handleShowStats(builder, options) { console.log(chalk_1.default.cyan('\nšŸ“Š Build Statistics')); console.log(chalk_1.default.gray('='.repeat(25))); const stats = builder.getBuildStats(); console.log(`\nšŸ“ˆ Cache Performance:`); console.log(` • Total builds: ${chalk_1.default.yellow(stats.totalBuilds)}`); console.log(` • Cache hit rate: ${chalk_1.default.yellow(Math.round(stats.cacheHitRate))}%`); console.log(` • Average build time: ${chalk_1.default.yellow(Math.round(stats.averageBuildTime / 1000))}s`); console.log(` • Total cache size: ${chalk_1.default.yellow(formatBytes(stats.totalCacheSize))}`); // Performance recommendations console.log(`\nšŸ’” Recommendations:`); if (stats.cacheHitRate < 50) { console.log(` • Consider enabling build caching for better performance`); } if (stats.averageBuildTime > 60000) { console.log(` • Consider optimizing build scripts or increasing parallel builds`); } if (stats.totalCacheSize > 1000000000) { // 1GB console.log(` • Consider clearing old cache entries to save disk space`); } // Output to file if requested if (options.output) { if (options.format === 'json') { await fs.writeJson(options.output, stats, { spaces: 2 }); } else { const statsText = `Build Statistics\n${JSON.stringify(stats, null, 2)}`; await fs.writeFile(options.output, statsText); } console.log(chalk_1.default.green(`\nāœ“ Statistics saved to ${options.output}`)); } } // Handle clearing build cache async function handleClearCache(builder) { console.log(chalk_1.default.cyan('\n🧹 Clearing Build Cache')); console.log(chalk_1.default.gray('='.repeat(30))); await builder.clearCache(); console.log(chalk_1.default.green('āœ… Build cache cleared successfully!')); } // Output build results in text format async function outputBuildResults(results, verbose) { const successful = results.filter(r => r.success); const failed = results.filter(r => !r.success); const cacheHits = results.filter(r => r.cacheHit); console.log(`\nšŸ“Š Build Results:`); console.log(` • Total: ${chalk_1.default.yellow(results.length)}`); console.log(` • Successful: ${chalk_1.default.green(successful.length)}`); console.log(` • Failed: ${failed.length > 0 ? chalk_1.default.red(failed.length) : chalk_1.default.gray('0')}`); console.log(` • Cache hits: ${chalk_1.default.cyan(cacheHits.length)}`); if (successful.length > 0) { console.log(`\nāœ… Successful Builds:`); successful.forEach(result => { const durationText = result.cacheHit ? 'cached' : `${Math.round(result.duration / 1000)}s`; const sizeText = result.outputSize ? ` (${formatBytes(result.outputSize)})` : ''; console.log(` • ${result.target}: ${chalk_1.default.green(durationText)}${sizeText}`); }); } if (failed.length > 0) { console.log(`\nāŒ Failed Builds:`); failed.forEach(result => { console.log(` • ${result.target}: ${chalk_1.default.red('failed')}`); if (verbose && result.error) { console.log(` Error: ${chalk_1.default.gray(result.error)}`); } }); } // Performance summary const totalTime = results.reduce((sum, r) => sum + r.duration, 0); const averageTime = results.length > 0 ? totalTime / results.length : 0; console.log(`\nā±ļø Performance:`); console.log(` • Total time: ${chalk_1.default.yellow(Math.round(totalTime / 1000))}s`); console.log(` • Average per target: ${chalk_1.default.yellow(Math.round(averageTime / 1000))}s`); if (cacheHits.length > 0) { const timeSaved = cacheHits.length * averageTime; console.log(` • Time saved by cache: ${chalk_1.default.green(Math.round(timeSaved / 1000))}s`); } } // Get color for target type function getTargetTypeColor(type) { switch (type) { case 'app': return chalk_1.default.blue; case 'package': return chalk_1.default.green; case 'lib': return chalk_1.default.magenta; case 'tool': return chalk_1.default.cyan; default: return chalk_1.default.white; } } // Format bytes for display function formatBytes(bytes) { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`; } // Register incremental build commands function registerIncrementalBuildCommands(program) { const incrementalBuild = program .command('incremental-build') .alias('ibuild') .description('Intelligent incremental building with change detection'); incrementalBuild .command('build') .description('Run incremental build') .option('--targets <targets...>', 'Specific targets to build') .option('--changed-files <files...>', 'Specific changed files to analyze') .option('--max-parallel <num>', 'Maximum parallel builds', '4') .option('--no-cache', 'Disable build caching') .option('--cache-location <path>', 'Build cache location') .option('--clean', 'Clean build (ignore cache)') .option('--dry-run', 'Show what would be built without building') .option('--verbose', 'Show detailed information') .option('--skip-tests', 'Skip test execution') .option('--no-fail-fast', 'Continue building after failures') .option('--build-timeout <ms>', 'Build timeout in milliseconds', '300000') .option('--output <file>', 'Output file path') .option('--format <format>', 'Output format (text|json)', 'text') .action(async (options) => { await manageIncrementalBuild({ ...options, maxParallelBuilds: parseInt(options.maxParallel), buildTimeout: parseInt(options.buildTimeout), enableCache: options.cache !== false, cleanBuild: options.clean, dryRun: options.dryRun, failFast: options.failFast !== false }); }); incrementalBuild .command('plan') .description('Show build plan without executing') .option('--changed-files <files...>', 'Specific changed files to analyze') .option('--verbose', 'Show detailed information') .option('--output <file>', 'Output file path') .option('--format <format>', 'Output format (text|json)', 'text') .action(async (options) => { await manageIncrementalBuild({ ...options, plan: true }); }); incrementalBuild .command('stats') .description('Show build statistics and performance metrics') .option('--output <file>', 'Output file path') .option('--format <format>', 'Output format (text|json)', 'text') .action(async (options) => { await manageIncrementalBuild({ ...options, stats: true }); }); incrementalBuild .command('clear-cache') .description('Clear build cache') .action(async () => { await manageIncrementalBuild({ clearCache: true }); }); }