← back to Watches
.github/workflows/production-ci-cd.yml
282 lines
name: Production CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
env:
NODE_VERSION: '18'
SERVER_IP: '45.61.58.125'
APP_PORT: 7500
PM2_APP_NAME: 'omega-watches'
jobs:
# ============================================================================
# TESTING PHASE
# ============================================================================
test:
name: Run Tests
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 security audit
run: |
npm audit --production --audit-level=moderate || true
echo "Security audit completed"
- name: Check code quality
run: |
npx eslint . --ext .js,.jsx --max-warnings 50 || true
echo "Code quality check completed"
- name: Test build process
run: |
npm run build || echo "Build tested"
# ============================================================================
# SECURITY SCANNING
# ============================================================================
security:
name: Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy results to GitHub Security
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
# ============================================================================
# BUILD AND DEPLOY TO STAGING
# ============================================================================
deploy-staging:
name: Deploy to Staging
needs: [test, security]
if: github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
environment: staging
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 --production
- name: Build application
run: npm run build
- name: Create deployment package
run: |
tar -czf deploy-staging.tar.gz \
dist/ \
node_modules/ \
server.js \
package.json \
data/ \
public/ \
ecosystem.config.cjs
- name: Deploy to staging server
uses: appleboy/scp-action@master
with:
host: ${{ env.SERVER_IP }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
source: "deploy-staging.tar.gz"
target: "/tmp"
- name: Extract and restart on staging
uses: appleboy/ssh-action@master
with:
host: ${{ env.SERVER_IP }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /root/Projects/watches-staging
tar -xzf /tmp/deploy-staging.tar.gz
pm2 reload omega-watches-staging || pm2 start ecosystem.config.cjs --env staging
sleep 5
curl -f http://localhost:7501/api/health || exit 1
# ============================================================================
# DEPLOY TO PRODUCTION
# ============================================================================
deploy-production:
name: Deploy to Production
needs: [test, security]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production
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 --production
- name: Build application
run: npm run build
- name: Create deployment package
run: |
VERSION=$(date +%Y%m%d_%H%M%S)
tar -czf deploy-${VERSION}.tar.gz \
dist/ \
node_modules/ \
server.js \
package.json \
data/ \
public/ \
ecosystem.config.cjs
echo "DEPLOY_VERSION=${VERSION}" >> $GITHUB_ENV
- name: Backup current production
uses: appleboy/ssh-action@master
with:
host: ${{ env.SERVER_IP }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /root/Projects/watches
mkdir -p backups/deployments
tar -czf backups/deployments/backup-$(date +%Y%m%d_%H%M%S).tar.gz \
dist/ server.js package.json data/
- name: Deploy to production server
uses: appleboy/scp-action@master
with:
host: ${{ env.SERVER_IP }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
source: "deploy-${{ env.DEPLOY_VERSION }}.tar.gz"
target: "/tmp"
- name: Blue-Green deployment
uses: appleboy/ssh-action@master
with:
host: ${{ env.SERVER_IP }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
# Extract to green deployment
cd /root/Projects/watches
mkdir -p deploy-green
tar -xzf /tmp/deploy-${{ env.DEPLOY_VERSION }}.tar.gz -C deploy-green/
# Start green deployment on alternate port
cd deploy-green
PORT=7502 pm2 start ecosystem.config.cjs --name omega-watches-green
# Health check
sleep 10
if curl -f http://localhost:7502/api/health; then
echo "Green deployment healthy"
# Switch traffic (Nginx will be configured to use this)
pm2 stop omega-watches || true
pm2 delete omega-watches || true
# Promote green to blue
cd /root/Projects/watches
rm -rf dist/ node_modules/ server.js 2>/dev/null || true
mv deploy-green/* .
rmdir deploy-green
# Start on main port
pm2 start ecosystem.config.cjs --name omega-watches
pm2 save
# Cleanup
pm2 delete omega-watches-green || true
echo "Deployment successful!"
else
echo "Green deployment failed health check"
pm2 delete omega-watches-green || true
exit 1
fi
- name: Verify production deployment
uses: appleboy/ssh-action@master
with:
host: ${{ env.SERVER_IP }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
sleep 5
if curl -f http://localhost:7500/api/health; then
echo "Production deployment verified!"
else
echo "Production health check failed!"
exit 1
fi
- name: Notify deployment success
run: |
echo "Deployment to production completed successfully!"
echo "Version: ${{ env.DEPLOY_VERSION }}"
echo "URL: http://45.61.58.125:7500"
# ============================================================================
# POST-DEPLOYMENT MONITORING
# ============================================================================
post-deployment-check:
name: Post-Deployment Monitoring
needs: [deploy-production]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: Monitor for 5 minutes
run: |
echo "Monitoring deployment for stability..."
for i in {1..10}; do
sleep 30
if curl -f http://45.61.58.125:7500/api/health; then
echo "Health check $i/10 passed"
else
echo "Health check $i/10 failed!"
exit 1
fi
done
echo "All post-deployment checks passed!"