@ordojs/cli
Version:
Command-line interface for OrdoJS framework
550 lines (467 loc) • 11.5 kB
JavaScript
/**
* @fileoverview OrdoJS CLI - Docker configuration generator
*/
import { CLIError, ErrorType } from '../index.js';
/**
* Docker configuration generator for OrdoJS applications
*/
export class DockerGenerator {
defaultConfig = {
baseImage: 'node:18-alpine',
nodeVersion: '18',
buildStage: true,
productionStage: true,
multiStage: true,
port: 3000,
healthCheck: true,
environment: {},
volumes: [],
commands: []
};
/**
* Generate Dockerfile content for an OrdoJS application
*/
generateDockerfile(config, options = {}) {
const dockerConfig = this.mergeConfig(options);
try {
if (dockerConfig.multiStage) {
return this.generateMultiStageDockerfile(dockerConfig);
}
else {
return this.generateSimpleDockerfile(dockerConfig);
}
}
catch (error) {
throw new CLIError(`Failed to generate Dockerfile: ${error instanceof Error ? error.message : String(error)}`, ErrorType.DEPLOYMENT, 'DOCKER-001');
}
}
/**
* Generate docker-compose.yml content
*/
generateDockerCompose(config, options = {}) {
const dockerConfig = this.mergeConfig(options);
try {
return this.generateDockerComposeContent(dockerConfig, config);
}
catch (error) {
throw new CLIError(`Failed to generate docker-compose.yml: ${error instanceof Error ? error.message : String(error)}`, ErrorType.DEPLOYMENT, 'DOCKER-002');
}
}
/**
* Generate .dockerignore file content
*/
generateDockerignore() {
return `# Dependencies
node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage
.grunt
# Bower dependency directory
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons
build/Release
# Dependency directories
jspm_packages/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
.env.production
# parcel-bundler cache
.cache
.parcel-cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
public
# Storybook build outputs
.out
.storybook-out
# Temporary folders
tmp/
temp/
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# Grunt intermediate storage
.grunt
# Bower dependency directory
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# parcel-bundler cache
.cache
.parcel-cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# OrdoJS specific
.ordo-cache
build/
dist/
*.ordo.js
*.ordo.css
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# Git
.git/
.gitignore
# Documentation
docs/
*.md
# Tests
test/
tests/
__tests__/
*.test.js
*.test.ts
*.spec.js
*.spec.ts
# Development
.dev/
dev/
`;
}
/**
* Generate Kubernetes manifests
*/
generateKubernetesManifests(config, options = {}) {
const dockerConfig = this.mergeConfig(options);
try {
return {
deployment: this.generateK8sDeployment(dockerConfig, config),
service: this.generateK8sService(dockerConfig, config),
ingress: this.generateK8sIngress(dockerConfig, config),
configMap: this.generateK8sConfigMap(dockerConfig, config),
secret: this.generateK8sSecret(dockerConfig, config)
};
}
catch (error) {
throw new CLIError(`Failed to generate Kubernetes manifests: ${error instanceof Error ? error.message : String(error)}`, ErrorType.DEPLOYMENT, 'DOCKER-003');
}
}
mergeConfig(options) {
return {
...this.defaultConfig,
...options,
environment: { ...this.defaultConfig.environment, ...options.environment },
volumes: [...this.defaultConfig.volumes, ...(options.volumes || [])],
commands: [...this.defaultConfig.commands, ...(options.commands || [])]
};
}
generateMultiStageDockerfile(config) {
return `# Multi-stage Dockerfile for OrdoJS application
FROM node:${config.nodeVersion}-alpine AS base
# Set working directory
WORKDIR /app
# Copy package files
COPY package*.json ./
COPY pnpm-lock.yaml ./
# Install pnpm
RUN npm install -g pnpm
# Install dependencies
RUN pnpm install --frozen-lockfile
# Copy source code
COPY . .
# Build stage
FROM base AS builder
# Build the application
RUN pnpm run build
# Production stage
FROM node:${config.nodeVersion}-alpine AS production
# Create app user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S ordojs -u 1001
# Set working directory
WORKDIR /app
# Copy package files
COPY package*.json ./
COPY pnpm-lock.yaml ./
# Install pnpm and production dependencies only
RUN npm install -g pnpm
RUN pnpm install --frozen-lockfile --prod
# Copy built application from builder stage
COPY --from=builder --chown=ordojs:nodejs /app/dist ./dist
COPY --from=builder --chown=ordojs:nodejs /app/public ./public
# Switch to non-root user
USER ordojs
# Expose port
EXPOSE ${config.port}
# Set environment variables
${this.generateEnvironmentVariables(config.environment)}
# Health check
${config.healthCheck ? this.generateHealthCheck(config.port) : ''}
# Start the application
CMD ["node", "dist/server.js"]
`;
}
generateSimpleDockerfile(config) {
return `# Simple Dockerfile for OrdoJS application
FROM node:${config.nodeVersion}-alpine
# Set working directory
WORKDIR /app
# Copy package files
COPY package*.json ./
COPY pnpm-lock.yaml ./
# Install pnpm
RUN npm install -g pnpm
# Install dependencies
RUN pnpm install --frozen-lockfile
# Copy source code
COPY . .
# Build the application
RUN pnpm run build
# Expose port
EXPOSE ${config.port}
# Set environment variables
${this.generateEnvironmentVariables(config.environment)}
# Health check
${config.healthCheck ? this.generateHealthCheck(config.port) : ''}
# Start the application
CMD ["node", "dist/server.js"]
`;
}
generateDockerComposeContent(config, deploymentConfig) {
return `version: '3.8'
services:
ordojs-app:
build:
context: .
dockerfile: Dockerfile
ports:
- "${config.port}:${config.port}"
environment:
${this.generateDockerComposeEnvironment(config.environment)}
volumes:
${this.generateDockerComposeVolumes(config.volumes)}
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:${config.port}/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
default:
name: ordojs-network
`;
}
generateK8sDeployment(config, deploymentConfig) {
return `apiVersion: apps/v1
kind: Deployment
metadata:
name: ordojs-app
labels:
app: ordojs-app
spec:
replicas: 3
selector:
matchLabels:
app: ordojs-app
template:
metadata:
labels:
app: ordojs-app
spec:
containers:
- name: ordojs-app
image: ordojs-app:latest
ports:
- containerPort: ${config.port}
env:
${this.generateK8sEnvironment(config.environment)}
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: ${config.port}
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: ${config.port}
initialDelaySeconds: 5
periodSeconds: 5
`;
}
generateK8sService(config, deploymentConfig) {
return `apiVersion: v1
kind: Service
metadata:
name: ordojs-app-service
spec:
selector:
app: ordojs-app
ports:
- protocol: TCP
port: 80
targetPort: ${config.port}
type: ClusterIP
`;
}
generateK8sIngress(config, deploymentConfig) {
return `apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ordojs-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: ordojs-app.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ordojs-app-service
port:
number: 80
`;
}
generateK8sConfigMap(config, deploymentConfig) {
const envVars = Object.entries(config.environment)
.filter(([key]) => !key.toLowerCase().includes('secret') && !key.toLowerCase().includes('password'))
.map(([key, value]) => ` ${key}: "${value}"`)
.join('\n');
return `apiVersion: v1
kind: ConfigMap
metadata:
name: ordojs-app-config
data:
${envVars}
`;
}
generateK8sSecret(config, deploymentConfig) {
const secretVars = Object.entries(config.environment)
.filter(([key]) => key.toLowerCase().includes('secret') || key.toLowerCase().includes('password'))
.map(([key, value]) => ` ${key}: ${Buffer.from(value).toString('base64')}`)
.join('\n');
if (!secretVars) {
return '';
}
return `apiVersion: v1
kind: Secret
metadata:
name: ordojs-app-secret
type: Opaque
data:
${secretVars}
`;
}
generateEnvironmentVariables(environment) {
return Object.entries(environment)
.map(([key, value]) => `ENV ${key}=${value}`)
.join('\n');
}
generateHealthCheck(port) {
return `HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\
CMD curl -f http://localhost:${port}/health || exit 1`;
}
generateDockerComposeEnvironment(environment) {
return Object.entries(environment)
.map(([key, value]) => ` - ${key}=${value}`)
.join('\n');
}
generateDockerComposeVolumes(volumes) {
return volumes
.map(volume => ` - ${volume}`)
.join('\n');
}
generateK8sEnvironment(environment) {
return Object.entries(environment)
.map(([key, value]) => ` - name: ${key}
value: "${value}"`)
.join('\n');
}
}
//# sourceMappingURL=docker-generator.js.map