backend-mcp
Version:
Generador automΓ‘tico de backends con Node.js, Express, Prisma y mΓ³dulos configurables. Servidor MCP compatible con npx para agentes IA. Soporta PostgreSQL, MySQL, MongoDB y SQLite.
1,262 lines (1,078 loc) β’ 32.8 kB
JavaScript
// modules/ci/init.js
const fs = require('fs');
const path = require('path');
class CIModule {
constructor(config = {}) {
this.config = {
platform: config.platform || 'github', // github, gitlab, jenkins
environments: config.environments || ['development', 'staging', 'production'],
testing: config.testing !== false,
security: config.security !== false,
docker: config.docker || false,
notifications: config.notifications || {},
deployment: config.deployment || {},
qualityGates: config.qualityGates || {},
...config
};
this.projectRoot = config.projectRoot || process.cwd();
}
async init() {
console.log('π Initializing CI/CD Module...');
try {
await this.setupDirectories();
await this.generateWorkflows();
await this.generateScripts();
await this.generateConfigs();
await this.updatePackageJson();
console.log('β
CI/CD Module initialized successfully!');
console.log('π Generated files:', this.getGeneratedFiles());
return {
success: true,
message: 'CI/CD module initialized successfully',
files: this.getGeneratedFiles()
};
} catch (error) {
console.error('β Error initializing CI/CD module:', error);
throw error;
}
}
async setupDirectories() {
const dirs = [
'.github/workflows',
'scripts/ci',
'scripts/deployment',
'config/ci'
];
for (const dir of dirs) {
const dirPath = path.join(this.projectRoot, dir);
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
console.log(`π Created directory: ${dir}`);
}
}
}
async generateWorkflows() {
if (this.config.platform === 'github') {
await this.generateGitHubActions();
} else if (this.config.platform === 'gitlab') {
await this.generateGitLabCI();
} else if (this.config.platform === 'jenkins') {
await this.generateJenkinsfile();
}
}
async generateGitHubActions() {
// CI Workflow
const ciWorkflow = `name: CI
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
env:
NODE_VERSION: '18'
REGISTRY: ghcr.io
IMAGE_NAME: \${{ github.repository }}
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: \${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Check formatting
run: npm run format:check
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16, 18, 20]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js \${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: \${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm run test:coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
token: \${{ secrets.CODECOV_TOKEN }}
file: ./coverage/lcov.info
security:
runs-on: ubuntu-latest
if: \${{ github.event_name == 'push' || github.event_name == 'pull_request' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run security audit
run: npm audit --audit-level=high
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: javascript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
build:
runs-on: ubuntu-latest
needs: [lint, test, security]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: \${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build application
run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: build-artifacts
path: dist/
retention-days: 30
${this.config.docker ? `
- name: Build Docker image
run: docker build -t \${{ env.REGISTRY }}/\${{ env.IMAGE_NAME }}:\${{ github.sha }} .
- name: Log in to Container Registry
uses: docker/login-action@v2
with:
registry: \${{ env.REGISTRY }}
username: \${{ github.actor }}
password: \${{ secrets.GITHUB_TOKEN }}
- name: Push Docker image
run: docker push \${{ env.REGISTRY }}/\${{ env.IMAGE_NAME }}:\${{ github.sha }}` : ''}
quality-gate:
runs-on: ubuntu-latest
needs: [build]
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: SonarQube Scan
uses: sonarqube-quality-gate-action@master
env:
SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
- name: Quality Gate check
id: sonarqube-quality-gate-check
uses: sonarqube-quality-gate-action@master
timeout-minutes: 5
env:
SONAR_TOKEN: \${{ secrets.SONAR_TOKEN }}
notify:
runs-on: ubuntu-latest
needs: [quality-gate]
if: always()
steps:
- name: Notify Slack
if: \${{ contains(fromJSON('["success", "failure"]'), job.status) }}
uses: 8398a7/action-slack@v3
with:
status: \${{ job.status }}
channel: '#ci-cd'
webhook_url: \${{ secrets.SLACK_WEBHOOK }}
`;
// CD Workflow
const cdWorkflow = `name: CD
on:
push:
branches: [ main ]
workflow_dispatch:
inputs:
environment:
description: 'Environment to deploy'
required: true
default: 'staging'
type: choice
options:
- staging
- production
env:
NODE_VERSION: '18'
REGISTRY: ghcr.io
IMAGE_NAME: \${{ github.repository }}
jobs:
deploy-staging:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' || github.event.inputs.environment == 'staging'
environment:
name: staging
url: https://staging.example.com
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: build-artifacts
path: dist/
- name: Deploy to staging
run: |
echo "Deploying to staging environment..."
# Add your deployment commands here
./scripts/deployment/deploy.sh staging
- name: Run health check
run: ./scripts/ci/health-check.sh staging
- name: Notify deployment
uses: 8398a7/action-slack@v3
with:
status: 'success'
text: 'π Successfully deployed to staging'
webhook_url: \${{ secrets.SLACK_WEBHOOK }}
deploy-production:
runs-on: ubuntu-latest
if: github.event.inputs.environment == 'production'
environment:
name: production
url: https://example.com
needs: [deploy-staging]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: build-artifacts
path: dist/
- name: Deploy to production
run: |
echo "Deploying to production environment..."
./scripts/deployment/deploy.sh production
- name: Run health check
run: ./scripts/ci/health-check.sh production
- name: Notify deployment
uses: 8398a7/action-slack@v3
with:
status: 'success'
text: 'π Successfully deployed to production'
webhook_url: \${{ secrets.SLACK_WEBHOOK }}
rollback:
runs-on: ubuntu-latest
if: failure()
environment: production
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Rollback deployment
run: ./scripts/deployment/rollback.sh
- name: Notify rollback
uses: 8398a7/action-slack@v3
with:
status: 'warning'
text: 'β οΈ Rollback executed due to deployment failure'
webhook_url: \${{ secrets.SLACK_WEBHOOK }}
`;
// Security Workflow
const securityWorkflow = `name: Security
on:
schedule:
- cron: '0 2 * * 1' # Weekly on Monday at 2 AM
workflow_dispatch:
jobs:
dependency-check:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run dependency audit
run: npm audit --audit-level=moderate
- name: Check for outdated packages
run: npm outdated
container-security:
runs-on: ubuntu-latest
if: \${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t security-scan .
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'security-scan'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
secrets-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run GitLeaks
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
`;
// Write workflow files
fs.writeFileSync(path.join(this.projectRoot, '.github/workflows/ci.yml'), ciWorkflow);
fs.writeFileSync(path.join(this.projectRoot, '.github/workflows/cd.yml'), cdWorkflow);
fs.writeFileSync(path.join(this.projectRoot, '.github/workflows/security.yml'), securityWorkflow);
// Dependabot configuration
const dependabot = `version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
reviewers:
- "@team-leads"
assignees:
- "@maintainers"
commit-message:
prefix: "chore"
include: "scope"
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
reviewers:
- "@devops-team"
`;
fs.writeFileSync(path.join(this.projectRoot, '.github/dependabot.yml'), dependabot);
console.log('β
Generated GitHub Actions workflows');
}
async generateGitLabCI() {
const gitlabCI = `# .gitlab-ci.yml
stages:
- validate
- test
- security
- build
- deploy
variables:
NODE_VERSION: "18"
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: "/certs"
default:
image: node:\$NODE_VERSION
cache:
paths:
- node_modules/
- .npm/
before_script:
- npm ci --cache .npm --prefer-offline
# Validation Stage
lint:
stage: validate
script:
- npm run lint
- npm run format:check
rules:
- if: \$CI_PIPELINE_SOURCE == "merge_request_event"
- if: \$CI_COMMIT_BRANCH == \$CI_DEFAULT_BRANCH
# Testing Stage
unit-tests:
stage: test
script:
- npm run test:coverage
coverage: '/Lines\s*:\s*(\d+\.?\d*)%/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
paths:
- coverage/
expire_in: 30 days
rules:
- if: \$CI_PIPELINE_SOURCE == "merge_request_event"
- if: \$CI_COMMIT_BRANCH == \$CI_DEFAULT_BRANCH
integration-tests:
stage: test
services:
- postgres:13
- redis:6
variables:
POSTGRES_DB: test_db
POSTGRES_USER: test_user
POSTGRES_PASSWORD: test_password
DATABASE_URL: "postgresql://test_user:test_password@postgres:5432/test_db"
REDIS_URL: "redis://redis:6379"
script:
- npm run test:integration
rules:
- if: \$CI_PIPELINE_SOURCE == "merge_request_event"
- if: \$CI_COMMIT_BRANCH == \$CI_DEFAULT_BRANCH
# Security Stage
security-audit:
stage: security
script:
- npm audit --audit-level=high
allow_failure: true
rules:
- if: \$CI_PIPELINE_SOURCE == "merge_request_event"
- if: \$CI_COMMIT_BRANCH == \$CI_DEFAULT_BRANCH
sast:
stage: security
include:
- template: Security/SAST.gitlab-ci.yml
rules:
- if: \$CI_COMMIT_BRANCH == \$CI_DEFAULT_BRANCH
dependency-scanning:
stage: security
include:
- template: Security/Dependency-Scanning.gitlab-ci.yml
rules:
- if: \$CI_COMMIT_BRANCH == \$CI_DEFAULT_BRANCH
# Build Stage
build:
stage: build
script:
- npm run build
artifacts:
paths:
- dist/
expire_in: 1 week
rules:
- if: \$CI_COMMIT_BRANCH == \$CI_DEFAULT_BRANCH
- if: \$CI_PIPELINE_SOURCE == "merge_request_event"
docker-build:
stage: build
image: docker:20.10.16
services:
- docker:20.10.16-dind
variables:
DOCKER_IMAGE_TAG: \$CI_REGISTRY_IMAGE:\$CI_COMMIT_SHA
script:
- docker login -u \$CI_REGISTRY_USER -p \$CI_REGISTRY_PASSWORD \$CI_REGISTRY
- docker build -t \$DOCKER_IMAGE_TAG .
- docker push \$DOCKER_IMAGE_TAG
rules:
- if: \$CI_COMMIT_BRANCH == \$CI_DEFAULT_BRANCH
# Deploy Stage
deploy-staging:
stage: deploy
environment:
name: staging
url: https://staging.example.com
script:
- ./scripts/deployment/deploy.sh staging
- ./scripts/ci/health-check.sh staging
rules:
- if: \$CI_COMMIT_BRANCH == \$CI_DEFAULT_BRANCH
deploy-production:
stage: deploy
environment:
name: production
url: https://example.com
script:
- ./scripts/deployment/deploy.sh production
- ./scripts/ci/health-check.sh production
when: manual
rules:
- if: \$CI_COMMIT_BRANCH == \$CI_DEFAULT_BRANCH
`;
fs.writeFileSync(path.join(this.projectRoot, '.gitlab-ci.yml'), gitlabCI);
console.log('β
Generated GitLab CI configuration');
}
async generateJenkinsfile() {
const jenkinsfile = `pipeline {
agent any
environment {
NODE_VERSION = '18'
DOCKER_REGISTRY = 'your-registry.com'
IMAGE_NAME = 'your-app'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Setup') {
steps {
sh 'nvm use \$NODE_VERSION'
sh 'npm ci'
}
}
stage('Lint') {
steps {
sh 'npm run lint'
sh 'npm run format:check'
}
}
stage('Test') {
parallel {
stage('Unit Tests') {
steps {
sh 'npm run test:coverage'
}
post {
always {
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'coverage',
reportFiles: 'index.html',
reportName: 'Coverage Report'
])
}
}
}
stage('Integration Tests') {
steps {
sh 'npm run test:integration'
}
}
}
}
stage('Security') {
parallel {
stage('Audit') {
steps {
sh 'npm audit --audit-level=high'
}
}
stage('SAST') {
steps {
sh 'npm run security:scan'
}
}
}
}
stage('Build') {
steps {
sh 'npm run build'
archiveArtifacts artifacts: 'dist/**', fingerprint: true
}
}
stage('Docker Build') {
when {
branch 'main'
}
steps {
script {
def image = docker.build("\${DOCKER_REGISTRY}/\${IMAGE_NAME}:\${BUILD_NUMBER}")
docker.withRegistry('https://\${DOCKER_REGISTRY}', 'docker-registry-credentials') {
image.push()
image.push('latest')
}
}
}
}
stage('Deploy to Staging') {
when {
branch 'main'
}
steps {
sh './scripts/deployment/deploy.sh staging'
sh './scripts/ci/health-check.sh staging'
}
}
stage('Deploy to Production') {
when {
branch 'main'
}
steps {
input message: 'Deploy to production?', ok: 'Deploy'
sh './scripts/deployment/deploy.sh production'
sh './scripts/ci/health-check.sh production'
}
}
}
post {
always {
cleanWs()
}
success {
slackSend(
channel: '#ci-cd',
color: 'good',
message: "β
Pipeline succeeded for \${env.JOB_NAME} - \${env.BUILD_NUMBER}"
)
}
failure {
slackSend(
channel: '#ci-cd',
color: 'danger',
message: "β Pipeline failed for \${env.JOB_NAME} - \${env.BUILD_NUMBER}"
)
}
}
}`;
fs.writeFileSync(path.join(this.projectRoot, 'Jenkinsfile'), jenkinsfile);
console.log('β
Generated Jenkinsfile');
}
async generateScripts() {
// Deploy script
const deployScript = `#!/bin/bash
# scripts/deployment/deploy.sh
set -e
ENVIRONMENT=\$1
if [ -z "\$ENVIRONMENT" ]; then
echo "Usage: \$0 <environment>"
exit 1
fi
echo "π Deploying to \$ENVIRONMENT environment..."
# Load environment-specific configuration
case \$ENVIRONMENT in
"development")
SERVER="dev.example.com"
PORT="3000"
;;
"staging")
SERVER="staging.example.com"
PORT="3000"
;;
"production")
SERVER="example.com"
PORT="3000"
;;
*)
echo "β Unknown environment: \$ENVIRONMENT"
exit 1
;;
esac
# Backup current deployment
echo "π¦ Creating backup..."
ssh deploy@\$SERVER "mkdir -p /var/backups/app/\$(date +%Y%m%d_%H%M%S)"
ssh deploy@\$SERVER "cp -r /var/www/app/* /var/backups/app/\$(date +%Y%m%d_%H%M%S)/"
# Upload new build
echo "π€ Uploading new build..."
rsync -avz --delete dist/ deploy@\$SERVER:/var/www/app/
# Install dependencies
echo "π¦ Installing dependencies..."
ssh deploy@\$SERVER "cd /var/www/app && npm ci --production"
# Run database migrations
echo "ποΈ Running database migrations..."
ssh deploy@\$SERVER "cd /var/www/app && npm run db:migrate"
# Restart application
echo "π Restarting application..."
ssh deploy@\$SERVER "pm2 restart app-\$ENVIRONMENT"
# Wait for application to start
echo "β³ Waiting for application to start..."
sleep 10
echo "β
Deployment to \$ENVIRONMENT completed successfully!"
`;
// Rollback script
const rollbackScript = `#!/bin/bash
# scripts/deployment/rollback.sh
set -e
ENVIRONMENT=\$1
BACKUP_VERSION=\$2
if [ -z "\$ENVIRONMENT" ]; then
echo "Usage: \$0 <environment> [backup_version]"
exit 1
fi
echo "π Rolling back \$ENVIRONMENT environment..."
# Load environment-specific configuration
case \$ENVIRONMENT in
"staging")
SERVER="staging.example.com"
;;
"production")
SERVER="example.com"
;;
*)
echo "β Unknown environment: \$ENVIRONMENT"
exit 1
;;
esac
# Get latest backup if version not specified
if [ -z "\$BACKUP_VERSION" ]; then
BACKUP_VERSION=\$(ssh deploy@\$SERVER "ls -1t /var/backups/app/ | head -1")
fi
echo "π¦ Rolling back to version: \$BACKUP_VERSION"
# Stop application
echo "π Stopping application..."
ssh deploy@\$SERVER "pm2 stop app-\$ENVIRONMENT"
# Restore backup
echo "π₯ Restoring backup..."
ssh deploy@\$SERVER "rm -rf /var/www/app/*"
ssh deploy@\$SERVER "cp -r /var/backups/app/\$BACKUP_VERSION/* /var/www/app/"
# Restart application
echo "π Restarting application..."
ssh deploy@\$SERVER "pm2 start app-\$ENVIRONMENT"
# Wait for application to start
echo "β³ Waiting for application to start..."
sleep 10
echo "β
Rollback to \$BACKUP_VERSION completed successfully!"
`;
// Health check script
const healthCheckScript = `#!/bin/bash
# scripts/ci/health-check.sh
set -e
ENVIRONMENT=\$1
MAX_RETRIES=30
RETRY_INTERVAL=10
if [ -z "\$ENVIRONMENT" ]; then
echo "Usage: \$0 <environment>"
exit 1
fi
# Set environment-specific URL
case \$ENVIRONMENT in
"development")
URL="http://localhost:3000"
;;
"staging")
URL="https://staging.example.com"
;;
"production")
URL="https://example.com"
;;
*)
echo "β Unknown environment: \$ENVIRONMENT"
exit 1
;;
esac
echo "π₯ Running health check for \$ENVIRONMENT environment..."
echo "π Checking URL: \$URL"
# Health check function
check_health() {
local response=\$(curl -s -o /dev/null -w "%{http_code}" "\$URL/health" || echo "000")
if [ "\$response" = "200" ]; then
return 0
else
return 1
fi
}
# Retry logic
for i in \$(seq 1 \$MAX_RETRIES); do
echo "π Attempt \$i/\$MAX_RETRIES..."
if check_health; then
echo "β
Health check passed! Application is healthy."
# Additional checks
echo "π Running additional checks..."
# Check database connectivity
DB_RESPONSE=\$(curl -s -o /dev/null -w "%{http_code}" "\$URL/health/db" || echo "000")
if [ "\$DB_RESPONSE" = "200" ]; then
echo "β
Database connectivity: OK"
else
echo "β οΈ Database connectivity: FAILED (\$DB_RESPONSE)"
fi
# Check Redis connectivity
REDIS_RESPONSE=\$(curl -s -o /dev/null -w "%{http_code}" "\$URL/health/redis" || echo "000")
if [ "\$REDIS_RESPONSE" = "200" ]; then
echo "β
Redis connectivity: OK"
else
echo "β οΈ Redis connectivity: FAILED (\$REDIS_RESPONSE)"
fi
# Check API endpoints
API_RESPONSE=\$(curl -s -o /dev/null -w "%{http_code}" "\$URL/api/health" || echo "000")
if [ "\$API_RESPONSE" = "200" ]; then
echo "β
API endpoints: OK"
else
echo "β οΈ API endpoints: FAILED (\$API_RESPONSE)"
fi
echo "π All health checks completed successfully!"
exit 0
else
echo "β Health check failed. Retrying in \$RETRY_INTERVAL seconds..."
sleep \$RETRY_INTERVAL
fi
done
echo "π₯ Health check failed after \$MAX_RETRIES attempts!"
exit 1
`;
// Setup CI script
const setupCIScript = `#!/bin/bash
# scripts/ci/setup-ci.sh
set -e
echo "π§ Setting up CI/CD configuration..."
# Create necessary directories
mkdir -p .github/workflows
mkdir -p scripts/ci
mkdir -p scripts/deployment
mkdir -p config/ci
# Make scripts executable
chmod +x scripts/deployment/*.sh
chmod +x scripts/ci/*.sh
# Install CI dependencies
echo "π¦ Installing CI dependencies..."
npm install --save-dev \
jest \
@types/jest \
supertest \
@types/supertest \
eslint \
prettier \
husky \
lint-staged
# Setup Git hooks
echo "πͺ Setting up Git hooks..."
npx husky install
npx husky add .husky/pre-commit "npx lint-staged"
npx husky add .husky/commit-msg "npx commitlint --edit \$1"
# Create lint-staged configuration
cat > .lintstagedrc.json << EOF
{
"*.{js,ts,jsx,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{json,md,yml,yaml}": [
"prettier --write"
]
}
EOF
echo "β
CI/CD setup completed successfully!"
echo "π Don't forget to:"
echo " 1. Configure secrets in your repository settings"
echo " 2. Update deployment URLs in scripts"
echo " 3. Configure notification webhooks"
echo " 4. Set up environment-specific configurations"
`;
// Write scripts
fs.writeFileSync(path.join(this.projectRoot, 'scripts/deployment/deploy.sh'), deployScript);
fs.writeFileSync(path.join(this.projectRoot, 'scripts/deployment/rollback.sh'), rollbackScript);
fs.writeFileSync(path.join(this.projectRoot, 'scripts/ci/health-check.sh'), healthCheckScript);
fs.writeFileSync(path.join(this.projectRoot, 'scripts/ci/setup-ci.sh'), setupCIScript);
// Make scripts executable (Unix systems)
if (process.platform !== 'win32') {
const scripts = [
'scripts/deployment/deploy.sh',
'scripts/deployment/rollback.sh',
'scripts/ci/health-check.sh',
'scripts/ci/setup-ci.sh'
];
scripts.forEach(script => {
try {
fs.chmodSync(path.join(this.projectRoot, script), '755');
} catch (error) {
console.warn(`β οΈ Could not make ${script} executable:`, error.message);
}
});
}
console.log('β
Generated CI/CD scripts');
}
async generateConfigs() {
// SonarQube configuration
const sonarConfig = `# sonar-project.properties
sonar.projectKey=your-project-key
sonar.projectName=Your Project Name
sonar.projectVersion=1.0.0
# Source code
sonar.sources=src
sonar.exclusions=**/*.test.ts,**/*.spec.ts,**/node_modules/**,**/dist/**,**/coverage/**
# Test coverage
sonar.typescript.lcov.reportPaths=coverage/lcov.info
sonar.testExecutionReportPaths=test-results/sonar-report.xml
# Language
sonar.language=ts
sonar.sourceEncoding=UTF-8
# Quality gates
sonar.qualitygate.wait=true
# Code analysis
sonar.typescript.node=node
sonar.typescript.exclusions=**/*.d.ts
`;
// ESLint configuration for CI
const eslintConfig = `// .eslintrc.ci.js
module.exports = {
extends: ['.eslintrc.js'],
rules: {
// Stricter rules for CI
'no-console': 'error',
'no-debugger': 'error',
'no-unused-vars': 'error',
'@typescript-eslint/no-unused-vars': 'error',
'prefer-const': 'error',
'no-var': 'error'
},
env: {
node: true,
jest: true
}
};
`;
// Prettier configuration
const prettierConfig = `{
"semi": true,
"trailingComma": "es5",
"singleQuote": true,
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"bracketSpacing": true,
"arrowParens": "avoid",
"endOfLine": "lf"
}
`;
// Commitlint configuration
const commitlintConfig = `// commitlint.config.js
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat',
'fix',
'docs',
'style',
'refactor',
'perf',
'test',
'chore',
'ci',
'build',
'revert'
]
],
'subject-max-length': [2, 'always', 100],
'subject-case': [2, 'always', 'lower-case'],
'header-max-length': [2, 'always', 100]
}
};
`;
// Write configuration files
fs.writeFileSync(path.join(this.projectRoot, 'sonar-project.properties'), sonarConfig);
fs.writeFileSync(path.join(this.projectRoot, '.eslintrc.ci.js'), eslintConfig);
fs.writeFileSync(path.join(this.projectRoot, '.prettierrc'), prettierConfig);
fs.writeFileSync(path.join(this.projectRoot, 'commitlint.config.js'), commitlintConfig);
console.log('β
Generated CI/CD configuration files');
}
async updatePackageJson() {
const packageJsonPath = path.join(this.projectRoot, 'package.json');
let packageJson = {};
if (fs.existsSync(packageJsonPath)) {
packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
}
// Add CI/CD scripts
packageJson.scripts = {
...packageJson.scripts,
// Linting and formatting
"lint": "eslint src --ext .ts,.js",
"lint:fix": "eslint src --ext .ts,.js --fix",
"lint:ci": "eslint src --ext .ts,.js --config .eslintrc.ci.js",
"format": "prettier --write \"src/**/*.{ts,js,json,md}\"",
"format:check": "prettier --check \"src/**/*.{ts,js,json,md}\"",
// Testing
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage",
"test:ci": "jest --ci --coverage --watchAll=false",
"test:integration": "jest --config jest.integration.config.js",
"test:e2e": "jest --config jest.e2e.config.js",
// Security
"security:audit": "npm audit",
"security:scan": "npm audit --audit-level=high",
"security:fix": "npm audit fix",
// Build and deployment
"build": "tsc && npm run build:assets",
"build:assets": "echo 'Building assets...'",
"build:docker": "docker build -t app .",
// CI/CD utilities
"ci:setup": "./scripts/ci/setup-ci.sh",
"ci:validate": "npm run lint:ci && npm run test:ci",
"deploy:staging": "./scripts/deployment/deploy.sh staging",
"deploy:production": "./scripts/deployment/deploy.sh production",
"rollback": "./scripts/deployment/rollback.sh",
"health-check": "./scripts/ci/health-check.sh",
// Quality gates
"quality:check": "npm run lint:ci && npm run test:coverage && npm run security:scan",
"quality:report": "npm run test:coverage && npm run lint:ci -- --format json --output-file reports/eslint-report.json",
// Git hooks
"prepare": "husky install",
"pre-commit": "lint-staged",
"commit-msg": "commitlint --edit $1"
};
// Add development dependencies
packageJson.devDependencies = {
...packageJson.devDependencies,
"@commitlint/cli": "^17.0.0",
"@commitlint/config-conventional": "^17.0.0",
"@types/jest": "^29.0.0",
"@types/supertest": "^2.0.12",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"eslint": "^8.0.0",
"eslint-config-prettier": "^8.0.0",
"eslint-plugin-prettier": "^4.0.0",
"husky": "^8.0.0",
"jest": "^29.0.0",
"lint-staged": "^13.0.0",
"prettier": "^2.0.0",
"supertest": "^6.0.0",
"ts-jest": "^29.0.0"
};
// Add Jest configuration
packageJson.jest = {
preset: 'ts-jest',
testEnvironment: 'node',
roots: ['<rootDir>/src'],
testMatch: ['**/__tests__/**/*.ts', '**/?(*.)+(spec|test).ts'],
transform: {
'^.+\\.ts$': 'ts-jest'
},
collectCoverageFrom: [
'src/**/*.ts',
'!src/**/*.d.ts',
'!src/**/*.test.ts',
'!src/**/*.spec.ts'
],
coverageDirectory: 'coverage',
coverageReporters: ['text', 'lcov', 'html', 'cobertura'],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80
}
}
};
// Add lint-staged configuration
packageJson['lint-staged'] = {
'*.{ts,js}': ['eslint --fix', 'prettier --write'],
'*.{json,md,yml,yaml}': ['prettier --write']
};
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
console.log('β
Updated package.json with CI/CD scripts and dependencies');
}
getGeneratedFiles() {
const files = [
'.github/workflows/ci.yml',
'.github/workflows/cd.yml',
'.github/workflows/security.yml',
'.github/dependabot.yml',
'scripts/deployment/deploy.sh',
'scripts/deployment/rollback.sh',
'scripts/ci/health-check.sh',
'scripts/ci/setup-ci.sh',
'sonar-project.properties',
'.eslintrc.ci.js',
'.prettierrc',
'commitlint.config.js'
];
if (this.config.platform === 'gitlab') {
files.push('.gitlab-ci.yml');
}
if (this.config.platform === 'jenkins') {
files.push('Jenkinsfile');
}
return files;
}
}
module.exports = CIModule;