832 lines
26 KiB
Markdown
832 lines
26 KiB
Markdown
# CI/CD PIPELINE - ERP Generic
|
|
|
|
**Última actualización:** 2025-11-24
|
|
**Responsable:** DevOps Team / Tech Lead
|
|
**Estado:** ✅ Production-Ready
|
|
|
|
---
|
|
|
|
## TABLE OF CONTENTS
|
|
|
|
1. [Overview](#1-overview)
|
|
2. [CI/CD Architecture](#2-cicd-architecture)
|
|
3. [GitHub Actions Workflows](#3-github-actions-workflows)
|
|
4. [Automated Testing Integration](#4-automated-testing-integration)
|
|
5. [Code Quality Gates](#5-code-quality-gates)
|
|
6. [Security Scanning](#6-security-scanning)
|
|
7. [Docker Build & Push](#7-docker-build--push)
|
|
8. [Deployment Automation](#8-deployment-automation)
|
|
9. [Rollback Automation](#9-rollback-automation)
|
|
10. [Notifications](#10-notifications)
|
|
|
|
---
|
|
|
|
## 1. OVERVIEW
|
|
|
|
### 1.1 CI/CD Pipeline Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Developer Workflow │
|
|
│ 1. git push origin feature/new-feature │
|
|
│ 2. Create Pull Request │
|
|
└────────────┬────────────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ CI Pipeline (GitHub Actions) │
|
|
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │
|
|
│ │ Lint │→ │ Build │→ │ Test │→ │Security│ │
|
|
│ │ │ │ │ │ (1.5k) │ │ Scan │ │
|
|
│ └────────┘ └────────┘ └────────┘ └────────┘ │
|
|
│ ↓ ↓ ↓ ↓ │
|
|
│ ┌─────────────────────────────────────────────┐ │
|
|
│ │ Quality Gate (SonarQube) │ │
|
|
│ │ - Coverage >80% │ │
|
|
│ │ - No critical bugs │ │
|
|
│ └─────────────────────────────────────────────┘ │
|
|
└────────────┬────────────────────────────────────────────────┘
|
|
│ (If all checks pass)
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ CD Pipeline (Deployment) │
|
|
│ │
|
|
│ develop branch → QA (Auto) │
|
|
│ main branch → Staging (Manual approval) │
|
|
│ release tags → Production (Manual approval) │
|
|
│ │
|
|
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │
|
|
│ │ Build │→ │ Push │→ │ Deploy │→ │ Verify │ │
|
|
│ │ Docker │ │ to │ │ to │ │ Health │ │
|
|
│ │ Image │ │Registry│ │ Server │ │ Checks │ │
|
|
│ └────────┘ └────────┘ └────────┘ └────────┘ │
|
|
└────────────┬────────────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Post-Deployment │
|
|
│ - Health checks │
|
|
│ - Smoke tests │
|
|
│ - Notifications (Slack/Discord) │
|
|
│ - Rollback if failure │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 1.2 Pipeline Stages
|
|
|
|
| Stage | Duration | Trigger | Blocking |
|
|
|-------|----------|---------|----------|
|
|
| **Lint** | 30s | Every push | Yes |
|
|
| **Build** | 2-3 min | Every push | Yes |
|
|
| **Unit Tests** | 1-2 min | Every push | Yes |
|
|
| **Integration Tests** | 5-10 min | Every push | Yes |
|
|
| **E2E Tests** | 15-30 min | Push to main/develop | No (parallel) |
|
|
| **Security Scan** | 2-5 min | Every push | Yes (critical only) |
|
|
| **Quality Gate** | 1 min | Every push | Yes |
|
|
| **Docker Build** | 5-10 min | Merge to main/develop | No |
|
|
| **Deploy QA** | 3-5 min | Merge to develop | No |
|
|
| **Deploy Production** | 10-15 min | Release tag + approval | No |
|
|
|
|
**Total CI time:** ~15-25 minutes (blocking)
|
|
**Total CD time:** 3-15 minutes (per environment)
|
|
|
|
---
|
|
|
|
## 2. CI/CD ARCHITECTURE
|
|
|
|
### 2.1 Branching Strategy (GitFlow)
|
|
|
|
```
|
|
main (production)
|
|
│
|
|
├── release/v1.0.0 (staging)
|
|
│ │
|
|
│ └── hotfix/critical-bug
|
|
│
|
|
└── develop (QA)
|
|
│
|
|
├── feature/user-authentication
|
|
├── feature/sales-orders
|
|
└── bugfix/fix-inventory-calc
|
|
```
|
|
|
|
**Branch Protection Rules:**
|
|
|
|
```yaml
|
|
# main branch
|
|
required_reviews: 2
|
|
require_code_owner_review: true
|
|
dismiss_stale_reviews: true
|
|
require_linear_history: true
|
|
required_status_checks:
|
|
- ci/lint
|
|
- ci/build
|
|
- ci/test
|
|
- ci/security
|
|
- ci/quality-gate
|
|
|
|
# develop branch
|
|
required_reviews: 1
|
|
require_code_owner_review: false
|
|
required_status_checks:
|
|
- ci/lint
|
|
- ci/test
|
|
```
|
|
|
|
### 2.2 Deployment Environments
|
|
|
|
| Environment | Branch | Trigger | Approval Required |
|
|
|-------------|--------|---------|-------------------|
|
|
| **Development** | feature/* | Manual | No |
|
|
| **QA** | develop | Automatic | No |
|
|
| **Staging** | main | Manual | Yes (Tech Lead) |
|
|
| **Production** | tags/v* | Manual | Yes (CTO + PO) |
|
|
|
|
---
|
|
|
|
## 3. GITHUB ACTIONS WORKFLOWS
|
|
|
|
### 3.1 CI Workflow (Main Pipeline)
|
|
|
|
**File:** `.github/workflows/ci.yml`
|
|
|
|
```yaml
|
|
name: CI Pipeline
|
|
|
|
on:
|
|
push:
|
|
branches: [main, develop]
|
|
pull_request:
|
|
branches: [main, develop]
|
|
|
|
env:
|
|
NODE_VERSION: '20'
|
|
PNPM_VERSION: '8'
|
|
|
|
jobs:
|
|
lint:
|
|
name: Lint Code
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
steps:
|
|
- 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 ESLint
|
|
run: npm run lint
|
|
|
|
- name: Run Prettier check
|
|
run: npm run format:check
|
|
|
|
build:
|
|
name: Build Application
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
needs: lint
|
|
steps:
|
|
- 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 backend
|
|
run: npm run build --workspace=backend
|
|
|
|
- name: Build frontend
|
|
run: npm run build --workspace=frontend
|
|
|
|
- name: Upload build artifacts
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: build-artifacts
|
|
path: |
|
|
backend/dist
|
|
frontend/dist
|
|
retention-days: 7
|
|
|
|
test-unit:
|
|
name: Unit Tests
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
needs: build
|
|
steps:
|
|
- 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 unit tests (Backend)
|
|
run: npm run test:unit --workspace=backend -- --coverage
|
|
|
|
- name: Run unit tests (Frontend)
|
|
run: npm run test:unit --workspace=frontend -- --coverage
|
|
|
|
- name: Upload coverage to Codecov
|
|
uses: codecov/codecov-action@v3
|
|
with:
|
|
files: ./backend/coverage/coverage-final.json,./frontend/coverage/coverage-final.json
|
|
flags: unit-tests
|
|
name: unit-tests-coverage
|
|
|
|
test-integration:
|
|
name: Integration Tests
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 20
|
|
needs: build
|
|
services:
|
|
postgres:
|
|
image: postgres:16-alpine
|
|
env:
|
|
POSTGRES_DB: test_db
|
|
POSTGRES_USER: test_user
|
|
POSTGRES_PASSWORD: test_password
|
|
options: >-
|
|
--health-cmd pg_isready
|
|
--health-interval 10s
|
|
--health-timeout 5s
|
|
--health-retries 5
|
|
ports:
|
|
- 5432:5432
|
|
|
|
redis:
|
|
image: redis:7-alpine
|
|
options: >-
|
|
--health-cmd "redis-cli ping"
|
|
--health-interval 10s
|
|
--health-timeout 5s
|
|
--health-retries 5
|
|
ports:
|
|
- 6379:6379
|
|
|
|
steps:
|
|
- 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 Prisma migrations
|
|
run: npx prisma migrate deploy --workspace=backend
|
|
env:
|
|
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/test_db
|
|
|
|
- name: Seed test data
|
|
run: npm run seed:test --workspace=backend
|
|
env:
|
|
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/test_db
|
|
|
|
- name: Run integration tests
|
|
run: npm run test:integration --workspace=backend
|
|
env:
|
|
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/test_db
|
|
REDIS_URL: redis://localhost:6379
|
|
|
|
- name: Upload test results
|
|
if: always()
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: integration-test-results
|
|
path: backend/test-results/
|
|
retention-days: 7
|
|
|
|
test-e2e:
|
|
name: E2E Tests
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
needs: build
|
|
steps:
|
|
- 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: Install Playwright
|
|
run: npx playwright install --with-deps
|
|
|
|
- name: Start services (Docker Compose)
|
|
run: docker-compose -f docker-compose.test.yml up -d
|
|
|
|
- name: Wait for services to be ready
|
|
run: |
|
|
timeout 60 bash -c 'until curl -f http://localhost:3000/health; do sleep 2; done'
|
|
|
|
- name: Run E2E tests
|
|
run: npm run test:e2e
|
|
env:
|
|
BASE_URL: http://localhost:5173
|
|
|
|
- name: Upload Playwright report
|
|
if: always()
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: playwright-report
|
|
path: playwright-report/
|
|
retention-days: 30
|
|
|
|
- name: Stop services
|
|
if: always()
|
|
run: docker-compose -f docker-compose.test.yml down
|
|
|
|
security-scan:
|
|
name: Security Scanning
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
needs: build
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Run Snyk security scan
|
|
uses: snyk/actions/node@master
|
|
env:
|
|
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
|
with:
|
|
args: --severity-threshold=high --fail-on=all
|
|
|
|
- name: Run OWASP Dependency Check
|
|
uses: dependency-check/Dependency-Check_Action@main
|
|
with:
|
|
project: 'erp-generic'
|
|
path: '.'
|
|
format: 'HTML'
|
|
args: >
|
|
--failOnCVSS 7
|
|
--enableRetired
|
|
|
|
- name: Upload dependency check report
|
|
if: always()
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: dependency-check-report
|
|
path: reports/
|
|
retention-days: 30
|
|
|
|
quality-gate:
|
|
name: Quality Gate (SonarQube)
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
needs: [test-unit, test-integration]
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0 # Full history for SonarQube
|
|
|
|
- name: SonarQube Scan
|
|
uses: sonarsource/sonarqube-scan-action@master
|
|
env:
|
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
|
|
with:
|
|
args: >
|
|
-Dsonar.projectKey=erp-generic
|
|
-Dsonar.qualitygate.wait=true
|
|
|
|
- name: Check Quality Gate status
|
|
run: |
|
|
STATUS=$(curl -s -u ${{ secrets.SONAR_TOKEN }}: \
|
|
"${{ secrets.SONAR_HOST_URL }}/api/qualitygates/project_status?projectKey=erp-generic" \
|
|
| jq -r '.projectStatus.status')
|
|
|
|
if [ "$STATUS" != "OK" ]; then
|
|
echo "Quality Gate failed: $STATUS"
|
|
exit 1
|
|
fi
|
|
|
|
notify-success:
|
|
name: Notify Success
|
|
runs-on: ubuntu-latest
|
|
needs: [lint, build, test-unit, test-integration, test-e2e, security-scan, quality-gate]
|
|
if: success()
|
|
steps:
|
|
- name: Send Slack notification
|
|
uses: slackapi/slack-github-action@v1
|
|
with:
|
|
webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
payload: |
|
|
{
|
|
"text": "✅ CI Pipeline passed for ${{ github.repository }}",
|
|
"blocks": [
|
|
{
|
|
"type": "section",
|
|
"text": {
|
|
"type": "mrkdwn",
|
|
"text": "*CI Pipeline Success* ✅\n*Repository:* ${{ github.repository }}\n*Branch:* ${{ github.ref_name }}\n*Commit:* ${{ github.sha }}\n*Author:* ${{ github.actor }}"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
notify-failure:
|
|
name: Notify Failure
|
|
runs-on: ubuntu-latest
|
|
needs: [lint, build, test-unit, test-integration, test-e2e, security-scan, quality-gate]
|
|
if: failure()
|
|
steps:
|
|
- name: Send Slack notification
|
|
uses: slackapi/slack-github-action@v1
|
|
with:
|
|
webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
payload: |
|
|
{
|
|
"text": "❌ CI Pipeline failed for ${{ github.repository }}",
|
|
"blocks": [
|
|
{
|
|
"type": "section",
|
|
"text": {
|
|
"type": "mrkdwn",
|
|
"text": "*CI Pipeline Failed* ❌\n*Repository:* ${{ github.repository }}\n*Branch:* ${{ github.ref_name }}\n*Commit:* ${{ github.sha }}\n*Author:* ${{ github.actor }}\n*Logs:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Logs>"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### 3.2 CD Workflow (Deployment to QA)
|
|
|
|
**File:** `.github/workflows/cd-qa.yml`
|
|
|
|
```yaml
|
|
name: CD - Deploy to QA
|
|
|
|
on:
|
|
push:
|
|
branches: [develop]
|
|
workflow_dispatch: # Manual trigger
|
|
|
|
env:
|
|
DOCKER_REGISTRY: ghcr.io
|
|
IMAGE_NAME: ${{ github.repository }}
|
|
|
|
jobs:
|
|
deploy-qa:
|
|
name: Deploy to QA Environment
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
environment:
|
|
name: qa
|
|
url: https://qa.erp-generic.local
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Login to GitHub Container Registry
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ env.DOCKER_REGISTRY }}
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Build and push Backend Docker image
|
|
uses: docker/build-push-action@v5
|
|
with:
|
|
context: ./backend
|
|
file: ./backend/Dockerfile
|
|
push: true
|
|
tags: |
|
|
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}-backend:qa
|
|
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}-backend:qa-${{ github.sha }}
|
|
cache-from: type=registry,ref=${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}-backend:qa
|
|
cache-to: type=inline
|
|
|
|
- name: Build and push Frontend Docker image
|
|
uses: docker/build-push-action@v5
|
|
with:
|
|
context: ./frontend
|
|
file: ./frontend/Dockerfile
|
|
push: true
|
|
tags: |
|
|
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}-frontend:qa
|
|
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}-frontend:qa-${{ github.sha }}
|
|
cache-from: type=registry,ref=${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}-frontend:qa
|
|
cache-to: type=inline
|
|
|
|
- name: Deploy to QA server
|
|
uses: appleboy/ssh-action@v1.0.0
|
|
with:
|
|
host: ${{ secrets.QA_SERVER_HOST }}
|
|
username: ${{ secrets.QA_SERVER_USER }}
|
|
key: ${{ secrets.QA_SERVER_SSH_KEY }}
|
|
script: |
|
|
cd /opt/erp-generic
|
|
docker-compose pull
|
|
docker-compose up -d --no-deps backend frontend
|
|
docker-compose exec -T backend npx prisma migrate deploy
|
|
docker image prune -f
|
|
|
|
- name: Wait for services to be ready
|
|
run: |
|
|
timeout 120 bash -c 'until curl -f https://qa.erp-generic.local/health; do sleep 5; done'
|
|
|
|
- name: Run smoke tests
|
|
run: |
|
|
curl -f https://qa.erp-generic.local/api/health || exit 1
|
|
# Add more smoke tests here
|
|
|
|
- name: Notify deployment success
|
|
uses: slackapi/slack-github-action@v1
|
|
with:
|
|
webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
payload: |
|
|
{
|
|
"text": "✅ Deployed to QA: ${{ github.sha }}",
|
|
"blocks": [
|
|
{
|
|
"type": "section",
|
|
"text": {
|
|
"type": "mrkdwn",
|
|
"text": "*Deployment to QA* ✅\n*Environment:* QA\n*Version:* ${{ github.sha }}\n*URL:* https://qa.erp-generic.local\n*Deployed by:* ${{ github.actor }}"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### 3.3 CD Workflow (Deployment to Production)
|
|
|
|
**File:** `.github/workflows/cd-production.yml`
|
|
|
|
```yaml
|
|
name: CD - Deploy to Production
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- 'v*.*.*'
|
|
workflow_dispatch:
|
|
inputs:
|
|
version:
|
|
description: 'Version to deploy (e.g., v1.0.0)'
|
|
required: true
|
|
|
|
env:
|
|
DOCKER_REGISTRY: ghcr.io
|
|
IMAGE_NAME: ${{ github.repository }}
|
|
|
|
jobs:
|
|
deploy-production:
|
|
name: Deploy to Production
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
environment:
|
|
name: production
|
|
url: https://erp-generic.com
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Extract version
|
|
id: version
|
|
run: |
|
|
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
|
|
echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Login to GitHub Container Registry
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ${{ env.DOCKER_REGISTRY }}
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Build and push Backend Docker image
|
|
uses: docker/build-push-action@v5
|
|
with:
|
|
context: ./backend
|
|
file: ./backend/Dockerfile
|
|
push: true
|
|
tags: |
|
|
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}-backend:${{ steps.version.outputs.VERSION }}
|
|
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}-backend:latest
|
|
cache-from: type=registry,ref=${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}-backend:latest
|
|
cache-to: type=inline
|
|
|
|
- name: Build and push Frontend Docker image
|
|
uses: docker/build-push-action@v5
|
|
with:
|
|
context: ./frontend
|
|
file: ./frontend/Dockerfile
|
|
push: true
|
|
tags: |
|
|
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}-frontend:${{ steps.version.outputs.VERSION }}
|
|
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}-frontend:latest
|
|
cache-from: type=registry,ref=${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}-frontend:latest
|
|
cache-to: type=inline
|
|
|
|
- name: Create database backup
|
|
uses: appleboy/ssh-action@v1.0.0
|
|
with:
|
|
host: ${{ secrets.PROD_SERVER_HOST }}
|
|
username: ${{ secrets.PROD_SERVER_USER }}
|
|
key: ${{ secrets.PROD_SERVER_SSH_KEY }}
|
|
script: |
|
|
/opt/erp-generic/scripts/backup-postgres.sh
|
|
|
|
- name: Deploy to Production server (Blue-Green)
|
|
uses: appleboy/ssh-action@v1.0.0
|
|
with:
|
|
host: ${{ secrets.PROD_SERVER_HOST }}
|
|
username: ${{ secrets.PROD_SERVER_USER }}
|
|
key: ${{ secrets.PROD_SERVER_SSH_KEY }}
|
|
script: |
|
|
cd /opt/erp-generic
|
|
./scripts/deploy-blue-green.sh production ${{ steps.version.outputs.VERSION }}
|
|
|
|
- name: Verify deployment
|
|
run: |
|
|
timeout 300 bash -c 'until curl -f https://erp-generic.com/health; do sleep 10; done'
|
|
|
|
- name: Run post-deployment tests
|
|
run: |
|
|
npm run test:smoke:production
|
|
|
|
- name: Notify deployment success
|
|
uses: slackapi/slack-github-action@v1
|
|
with:
|
|
webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
payload: |
|
|
{
|
|
"text": "✅ Deployed to Production: ${{ steps.version.outputs.VERSION }}",
|
|
"blocks": [
|
|
{
|
|
"type": "section",
|
|
"text": {
|
|
"type": "mrkdwn",
|
|
"text": "*Deployment to Production* ✅\n*Environment:* Production\n*Version:* ${{ steps.version.outputs.VERSION }}\n*URL:* https://erp-generic.com\n*Deployed by:* ${{ github.actor }}"
|
|
}
|
|
},
|
|
{
|
|
"type": "section",
|
|
"text": {
|
|
"type": "mrkdwn",
|
|
"text": "*Rollback command:*\n```./scripts/rollback.sh ${{ steps.version.outputs.VERSION }}```"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
- name: Create GitHub Release
|
|
uses: actions/create-release@v1
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
with:
|
|
tag_name: ${{ steps.version.outputs.VERSION }}
|
|
release_name: Release ${{ steps.version.outputs.VERSION }}
|
|
body: |
|
|
## Changes in this release
|
|
- Deployed to production on $(date)
|
|
- Docker images: ${{ steps.version.outputs.VERSION }}
|
|
|
|
## Rollback
|
|
If issues arise, run: `./scripts/rollback.sh ${{ steps.version.outputs.VERSION }}`
|
|
draft: false
|
|
prerelease: false
|
|
```
|
|
|
|
---
|
|
|
|
## 4. AUTOMATED TESTING INTEGRATION
|
|
|
|
**Test Execution Summary:**
|
|
- **Unit Tests:** 876 tests (backend: 526, frontend: 350) - ~2 minutes
|
|
- **Integration Tests:** 438 tests (API + DB + Components) - ~10 minutes
|
|
- **E2E Tests:** 147 tests (Critical flows) - ~25 minutes
|
|
- **Total:** 1,461 automated tests
|
|
|
|
**Coverage Requirements:**
|
|
- Line coverage: >80%
|
|
- Branch coverage: >75%
|
|
- Function coverage: >85%
|
|
|
|
---
|
|
|
|
## 5. CODE QUALITY GATES
|
|
|
|
**SonarQube Quality Gate:**
|
|
- **Coverage:** >80%
|
|
- **Duplicated Lines:** <3%
|
|
- **Code Smells:** <10 per 1000 LOC
|
|
- **Bugs:** 0 critical, 0 major
|
|
- **Vulnerabilities:** 0 critical, 0 major
|
|
- **Security Hotspots:** Reviewed
|
|
- **Maintainability Rating:** A or B
|
|
- **Reliability Rating:** A
|
|
- **Security Rating:** A
|
|
|
|
---
|
|
|
|
## 6. SECURITY SCANNING
|
|
|
|
**Tools:**
|
|
- **Snyk:** Dependency vulnerability scanning
|
|
- **OWASP Dependency Check:** Known CVE scanning
|
|
- **GitGuardian:** Secret scanning
|
|
- **Trivy:** Container image scanning
|
|
|
|
**Fail Criteria:**
|
|
- Critical vulnerabilities: Block merge
|
|
- High vulnerabilities: Warning (fail after 7 days)
|
|
- Medium/Low vulnerabilities: Warning only
|
|
|
|
---
|
|
|
|
## 7. DOCKER BUILD & PUSH
|
|
|
|
**Image Naming Convention:**
|
|
```
|
|
ghcr.io/your-org/erp-generic-backend:latest
|
|
ghcr.io/your-org/erp-generic-backend:v1.0.0
|
|
ghcr.io/your-org/erp-generic-backend:qa
|
|
ghcr.io/your-org/erp-generic-backend:qa-abc123
|
|
```
|
|
|
|
**Image Scanning:**
|
|
```yaml
|
|
- name: Scan Docker image
|
|
uses: aquasecurity/trivy-action@master
|
|
with:
|
|
image-ref: ghcr.io/${{ github.repository }}-backend:latest
|
|
format: 'sarif'
|
|
output: 'trivy-results.sarif'
|
|
```
|
|
|
|
---
|
|
|
|
## 8. DEPLOYMENT AUTOMATION
|
|
|
|
**Deployment Strategies:**
|
|
1. **QA:** Rolling update (zero-downtime)
|
|
2. **Staging:** Blue-green deployment
|
|
3. **Production:** Blue-green with canary (10% → 50% → 100%)
|
|
|
|
**Pre-Deployment Checklist:**
|
|
- [ ] All tests passing
|
|
- [ ] Security scans clean
|
|
- [ ] Database backup created
|
|
- [ ] Migration scripts reviewed
|
|
- [ ] Rollback plan documented
|
|
- [ ] On-call team notified
|
|
|
|
---
|
|
|
|
## 9. ROLLBACK AUTOMATION
|
|
|
|
**Automated Rollback Triggers:**
|
|
- Health check failures (>5 consecutive)
|
|
- Error rate >5% for >5 minutes
|
|
- p95 latency >2s for >5 minutes
|
|
- Manual trigger via GitHub Actions
|
|
|
|
---
|
|
|
|
## 10. NOTIFICATIONS
|
|
|
|
**Notification Channels:**
|
|
- **Slack:** #erp-deployments (all deployments), #erp-alerts (failures)
|
|
- **Email:** devops@erp-generic.com (production deployments)
|
|
- **PagerDuty:** On-call engineer (production failures)
|
|
|
|
---
|
|
|
|
## REFERENCES
|
|
|
|
- [GitHub Actions Documentation](https://docs.github.com/en/actions)
|
|
- [Docker Build Best Practices](https://docs.docker.com/develop/dev-best-practices/)
|
|
- [Deployment Guide](./DEPLOYMENT-GUIDE.md)
|
|
|
|
---
|
|
|
|
**Documento:** CI-CD-PIPELINE.md
|
|
**Versión:** 1.0
|
|
**Total Páginas:** ~16
|
|
**Última Actualización:** 2025-11-24
|