UNPKG

@ordojs/cli

Version:

Command-line interface for OrdoJS framework

266 lines (264 loc) 13.3 kB
/** * @fileoverview OrdoJS CLI - Infrastructure command */ import { Command } from 'commander'; import { CICDGenerator } from '../utils/deployment/cicd-generator.js'; import { DockerGenerator } from '../utils/deployment/docker-generator.js'; import { MonitoringGenerator } from '../utils/deployment/monitoring-generator.js'; import { mkdir, writeFile } from '../utils/fs.js'; import { CLIError, ErrorType, logger } from '../utils/index.js'; /** * Register the infrastructure command */ export function registerInfrastructureCommand(program) { program .command('infrastructure') .description('Generate deployment infrastructure for OrdoJS applications') .option('-t, --type <type>', 'Infrastructure type (docker, cicd, monitoring, all)', 'all') .option('-p, --platform <platform>', 'CI/CD platform (github, gitlab, jenkins)', 'github') .option('-o, --output <dir>', 'Output directory for generated files', '.') .option('--node-version <version>', 'Node.js version', '18') .option('--port <port>', 'Application port', '3000') .option('--multi-stage', 'Use multi-stage Dockerfile', true) .option('--health-check', 'Enable health checks', true) .option('--auto-deploy', 'Enable automatic deployment', false) .option('--monitoring', 'Enable monitoring and observability', true) .option('--env <variables>', 'Environment variables in KEY=VALUE format', collectEnvVars, {}) .action(async (options) => { try { await infrastructureCommand(options); } catch (error) { if (error instanceof CLIError) { logger.error(`${error.type.toUpperCase()} ERROR: ${error.message}`); if (error.code) { logger.error(`Error code: ${error.code}`); } if (error.suggestions && error.suggestions.length > 0) { logger.info('Suggestions:'); error.suggestions.forEach(suggestion => { logger.info(` - ${suggestion}`); }); } } else { logger.error(`Infrastructure generation failed: ${error instanceof Error ? error.message : String(error)}`); } process.exit(1); } }); } /** * Collect environment variables from command line */ function collectEnvVars(value, previous) { const [key, val] = value.split('='); if (!key || !val) { throw new CLIError('Environment variables must be in KEY=VALUE format', ErrorType.VALIDATION, 'CLI-201', [ 'Example: --env NODE_ENV=production' ]); } return { ...previous, [key]: val }; } /** * Infrastructure command implementation */ export async function infrastructureCommand(options) { logger.info(`Generating ${options.type} infrastructure...`); try { // Create output directory if it doesn't exist await mkdir(options.output, { recursive: true }); // Initialize generators const dockerGenerator = new DockerGenerator(); const cicdGenerator = new CICDGenerator(); const monitoringGenerator = new MonitoringGenerator(); // Mock deployment config for generation const deploymentConfig = { outputDir: 'dist', isStatic: false, includeServerFunctions: true, env: options.env }; const generatedFiles = []; // Generate Docker infrastructure if (options.type === 'docker' || options.type === 'all') { logger.info('Generating Docker infrastructure...'); const dockerfile = dockerGenerator.generateDockerfile(deploymentConfig, { nodeVersion: options.nodeVersion, port: options.port, multiStage: options.multiStage, healthCheck: options.healthCheck, environment: options.env }); const dockerCompose = dockerGenerator.generateDockerCompose(deploymentConfig, { nodeVersion: options.nodeVersion, port: options.port, environment: options.env }); const dockerignore = dockerGenerator.generateDockerignore(); const k8sManifests = dockerGenerator.generateKubernetesManifests(deploymentConfig, { nodeVersion: options.nodeVersion, port: options.port, environment: options.env }); // Write Docker files await writeFile(`${options.output}/Dockerfile`, dockerfile); await writeFile(`${options.output}/docker-compose.yml`, dockerCompose); await writeFile(`${options.output}/.dockerignore`, dockerignore); // Write Kubernetes manifests await mkdir(`${options.output}/k8s`, { recursive: true }); await writeFile(`${options.output}/k8s/deployment.yaml`, k8sManifests.deployment); await writeFile(`${options.output}/k8s/service.yaml`, k8sManifests.service); if (k8sManifests.ingress) { await writeFile(`${options.output}/k8s/ingress.yaml`, k8sManifests.ingress); } if (k8sManifests.configMap) { await writeFile(`${options.output}/k8s/configmap.yaml`, k8sManifests.configMap); } if (k8sManifests.secret) { await writeFile(`${options.output}/k8s/secret.yaml`, k8sManifests.secret); } generatedFiles.push('Dockerfile', 'docker-compose.yml', '.dockerignore', 'k8s/deployment.yaml', 'k8s/service.yaml'); if (k8sManifests.ingress) generatedFiles.push('k8s/ingress.yaml'); if (k8sManifests.configMap) generatedFiles.push('k8s/configmap.yaml'); if (k8sManifests.secret) generatedFiles.push('k8s/secret.yaml'); } // Generate CI/CD infrastructure if (options.type === 'cicd' || options.type === 'all') { logger.info(`Generating ${options.platform} CI/CD pipeline...`); const pipeline = cicdGenerator.generatePipeline(deploymentConfig, { platform: options.platform, nodeVersion: options.nodeVersion, autoDeploy: options.autoDeploy, environments: ['production', 'staging'] }); // Write CI/CD files switch (options.platform) { case 'github': await mkdir(`${options.output}/.github/workflows`, { recursive: true }); await writeFile(`${options.output}/.github/workflows/ci-cd.yml`, pipeline); generatedFiles.push('.github/workflows/ci-cd.yml'); break; case 'gitlab': await writeFile(`${options.output}/.gitlab-ci.yml`, pipeline); generatedFiles.push('.gitlab-ci.yml'); break; case 'jenkins': await writeFile(`${options.output}/Jenkinsfile`, pipeline); generatedFiles.push('Jenkinsfile'); break; default: throw new CLIError(`Unsupported CI/CD platform: ${options.platform}`, ErrorType.VALIDATION, 'CLI-202', [ 'Supported platforms: github, gitlab, jenkins' ]); } } // Generate monitoring infrastructure if (options.type === 'monitoring' || options.type === 'all') { if (options.monitoring) { logger.info('Generating monitoring infrastructure...'); const monitoringConfig = monitoringGenerator.generateMonitoringConfig(deploymentConfig, { logLevel: 'info', structuredLogging: true, metricsCollection: true, distributedTracing: true, errorReporting: true, healthChecks: true, performanceMonitoring: true, alerting: true }); // Create monitoring directory await mkdir(`${options.output}/monitoring`, { recursive: true }); await mkdir(`${options.output}/src/monitoring`, { recursive: true }); // Write monitoring configuration files await writeFile(`${options.output}/src/monitoring/logger.js`, monitoringConfig.logger); await writeFile(`${options.output}/src/monitoring/metrics.js`, monitoringConfig.metrics); await writeFile(`${options.output}/src/monitoring/tracing.js`, monitoringConfig.tracing); await writeFile(`${options.output}/src/monitoring/health-check.js`, monitoringConfig.healthCheck); await writeFile(`${options.output}/src/monitoring/error-handler.js`, monitoringConfig.errorHandler); // Write Docker Compose monitoring services await writeFile(`${options.output}/docker-compose.monitoring.yml`, monitoringConfig.dockerCompose); // Write Kubernetes monitoring manifests await mkdir(`${options.output}/k8s/monitoring`, { recursive: true }); await writeFile(`${options.output}/k8s/monitoring/monitoring.yml`, monitoringConfig.kubernetes); // Create Prometheus configuration const prometheusConfig = `global: scrape_interval: 15s scrape_configs: - job_name: 'ordojs-app' static_configs: - targets: ['ordojs-app:3000'] metrics_path: '/metrics' scrape_interval: 5s - job_name: 'prometheus' static_configs: - targets: ['localhost:9090'] `; await writeFile(`${options.output}/monitoring/prometheus.yml`, prometheusConfig); generatedFiles.push('src/monitoring/logger.js', 'src/monitoring/metrics.js', 'src/monitoring/tracing.js', 'src/monitoring/health-check.js', 'src/monitoring/error-handler.js', 'docker-compose.monitoring.yml', 'k8s/monitoring/monitoring.yml', 'monitoring/prometheus.yml'); } } // Generate package.json scripts if (options.type === 'all') { logger.info('Generating package.json scripts...'); const packageJsonScripts = { "docker:build": "docker build -t ordojs-app .", "docker:run": "docker run -p 3000:3000 ordojs-app", "docker:compose": "docker-compose up -d", "docker:compose:down": "docker-compose down", "k8s:apply": "kubectl apply -f k8s/", "k8s:delete": "kubectl delete -f k8s/", "monitoring:start": "docker-compose -f docker-compose.monitoring.yml up -d", "monitoring:stop": "docker-compose -f docker-compose.monitoring.yml down" }; const packageJsonPath = `${options.output}/package.json`; try { const existingPackageJson = await import('fs').then(fs => fs.readFileSync(packageJsonPath, 'utf8')); const packageJson = JSON.parse(existingPackageJson); packageJson.scripts = { ...packageJson.scripts, ...packageJsonScripts }; await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2)); } catch (error) { logger.warn('Could not update package.json scripts - file may not exist'); } } // Display generated files logger.success('\nInfrastructure generation completed successfully!'); logger.info('\nGenerated files:'); generatedFiles.forEach(file => { logger.info(` - ${file}`); }); // Display next steps logger.info('\nNext steps:'); if (options.type === 'docker' || options.type === 'all') { logger.info(' Docker:'); logger.info(' - docker build -t ordojs-app .'); logger.info(' - docker run -p 3000:3000 ordojs-app'); logger.info(' - docker-compose up -d'); } if (options.type === 'cicd' || options.type === 'all') { logger.info(` CI/CD (${options.platform}):`); logger.info(' - Commit and push your changes'); logger.info(' - Check the CI/CD pipeline in your platform'); } if (options.type === 'monitoring' || options.type === 'all') { logger.info(' Monitoring:'); logger.info(' - docker-compose -f docker-compose.monitoring.yml up -d'); logger.info(' - Access Grafana at http://localhost:3001 (admin/admin)'); logger.info(' - Access Jaeger at http://localhost:16686'); logger.info(' - Access Prometheus at http://localhost:9090'); } } catch (error) { if (error instanceof CLIError) { throw error; } else { throw new CLIError(`Infrastructure generation failed: ${error instanceof Error ? error.message : String(error)}`, ErrorType.DEPLOYMENT, 'CLI-203'); } } } //# sourceMappingURL=infrastructure.js.map