@ordojs/cli
Version:
Command-line interface for OrdoJS framework
266 lines (264 loc) • 13.3 kB
JavaScript
/**
* @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