Buổi 13: CI/CD Pipeline — Automated Testing & Deployment 🚀
Thành quả: GitHub Actions pipeline: lint → test → build → deploy (tự động trên mỗi PR)
🎯 Mục Tiêu
- Hiểu CI/CD concepts và pipeline design
- Setup GitHub Actions cho automated testing
- Implement 8-gate deploy pipeline (cm-safe-deploy)
- Environment management (dev → staging → production)
- Rollback strategy khi deploy fail
📖 Phần 1: CI/CD Concepts
Continuous Integration (CI)
Developer pushes code → Automated pipeline runs:
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ LINT │ → │ TEST │ → │ BUILD │ → │ PREVIEW │
│ ESLint │ │ Unit │ │ Compile │ │ Deploy │
│ Prettier │ │ Integra. │ │ Bundle │ │ Preview │
│ TypeCheck│ │ Coverage │ │ Optimize │ │ URL │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
Gate 1 Gate 2 Gate 3 Gate 4
Any gate FAIL → Pipeline STOPS → PR cannot mergeContinuous Deployment (CD)
PR merged to main → Automatic production deploy:
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ SECRETS │ → │ SECURITY │ → │ DEPLOY │ → │ SMOKE │
│ Scan │ │ Audit │ │ Ship to │ │ Test │
│ No leaks │ │ OWASP │ │ Prod │ │ Health │
│ │ │ Deps │ │ │ │ Check │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
Gate 5 Gate 6 Gate 7 Gate 8📖 Phần 2: GitHub Actions Setup
CI Pipeline
yaml
# .github/workflows/ci.yml
name: CI Pipeline
on:
pull_request:
branches: [main, develop]
push:
branches: [develop]
env:
NODE_VERSION: '20'
jobs:
lint:
name: 🧹 Lint & Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run type-check
test:
name: 🧪 Test
runs-on: ubuntu-latest
needs: lint
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: testdb
POSTGRES_USER: test
POSTGRES_PASSWORD: test
ports: ['5432:5432']
options: --health-cmd pg_isready --health-interval 10s
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci
- run: npx prisma migrate deploy
env:
DATABASE_URL: postgresql://test:test@localhost:5432/testdb
- run: npm run test:coverage
env:
DATABASE_URL: postgresql://test:test@localhost:5432/testdb
JWT_ACCESS_SECRET: test-secret
JWT_REFRESH_SECRET: test-refresh
- uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage/
build:
name: 🏗️ Build
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: build-artifacts
path: dist/
preview:
name: 👁️ Preview Deploy
runs-on: ubuntu-latest
needs: build
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: build-artifacts
path: dist/
- name: Deploy to Preview
uses: cloudflare/wrangler-action@v3
with:
command: pages deploy dist --project-name=myapp --branch=${{ github.head_ref }}
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}CD Pipeline
yaml
# .github/workflows/cd.yml
name: CD Pipeline
on:
push:
branches: [main]
jobs:
security-scan:
name: 🔒 Security Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Secret Scan
uses: trufflesecurity/trufflehog@main
with:
path: ./
- name: Dependency Audit
run: npm audit --audit-level=high
deploy-production:
name: 🚀 Deploy Production
runs-on: ubuntu-latest
needs: security-scan
environment: production
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
- name: Deploy
uses: cloudflare/wrangler-action@v3
with:
command: pages deploy dist --project-name=myapp
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
smoke-test:
name: 🏥 Smoke Test
runs-on: ubuntu-latest
needs: deploy-production
steps:
- name: Health Check
run: |
sleep 30
STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://myapp.com/api/health)
if [ "$STATUS" != "200" ]; then
echo "❌ Health check failed: $STATUS"
exit 1
fi
echo "✅ Health check passed"📖 Phần 3: cm-safe-deploy — 8 Gate Pipeline
Gate 1: 🔒 Identity Check → cm-identity-guard
Gate 2: 🧹 Lint → eslint + prettier
Gate 3: 🧪 Tests → unit + integration
Gate 4: 📊 Coverage → min 80% threshold
Gate 5: 🏗️ Build → compilation success
Gate 6: 🔐 Secret Scan → no leaked credentials
Gate 7: 🚀 Deploy → push to hosting
Gate 8: 🏥 Smoke Test → verify live endpointGate Implementation
bash
#!/bin/bash
# deploy-gate.sh
set -e # Exit on any failure
echo "🔒 Gate 1: Identity Check"
EXPECTED_EMAIL="dev@mycompany.com"
ACTUAL_EMAIL=$(git config user.email)
if [ "$ACTUAL_EMAIL" != "$EXPECTED_EMAIL" ]; then
echo "❌ Wrong git identity: $ACTUAL_EMAIL (expected: $EXPECTED_EMAIL)"
exit 1
fi
echo "✅ Identity verified"
echo "🧹 Gate 2: Lint"
npm run lint || { echo "❌ Lint failed"; exit 1; }
echo "🧪 Gate 3: Tests"
npm run test || { echo "❌ Tests failed"; exit 1; }
echo "📊 Gate 4: Coverage"
COVERAGE=$(npm run test:coverage 2>&1 | grep "All files" | awk '{print $4}')
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
echo "❌ Coverage $COVERAGE% < 80%"
exit 1
fi
echo "✅ Coverage: $COVERAGE%"
echo "🏗️ Gate 5: Build"
npm run build || { echo "❌ Build failed"; exit 1; }
echo "🔐 Gate 6: Secret Scan"
npx secretlint --secretlintrc .secretlintrc.json "**/*"
echo "🚀 Gate 7: Deploy"
npx wrangler pages deploy dist/ --project-name=myapp
echo "🏥 Gate 8: Smoke Test"
sleep 15
curl -sf https://myapp.com/api/health > /dev/null || { echo "❌ Smoke test failed"; exit 1; }
echo "🎉 All 8 gates PASSED — Deploy successful!"📖 Phần 4: Rollback Strategy
IF smoke test fails:
1. Revert: wrangler pages deploy --rollback
2. Alert: notify Slack/Discord
3. Investigate: check error logs
4. Fix: create hotfix branch → run pipeline again
IF discovered in production:
1. Feature flag: disable feature remotely
2. Revert commit: git revert HEAD → push → auto-redeploy
3. Post-mortem: cm-debugging root cause analysis🧪 Lab: Setup Complete CI/CD
Task: GitHub Actions pipeline (60 min)
Step 1: Create .github/workflows/ci.yml
Step 2: Create .github/workflows/cd.yml
Step 3: Add GitHub Secrets:
→ CLOUDFLARE_API_TOKEN
→ DATABASE_URL (for test DB)
Step 4: Push to trigger pipeline
Step 5: Create PR → verify all checks pass
Step 6: Merge → verify production deploy
Step 7: Document the pipeline in AGENTS.md🎓 Tóm Tắt
| Concept | Implementation |
|---|---|
| CI | Lint → Test → Build → Preview (on every PR) |
| CD | Security → Deploy → Smoke (on merge to main) |
| 8 Gates | Identity → Lint → Test → Coverage → Build → Secret → Deploy → Smoke |
| Rollback | Auto-revert, feature flags, hotfix branch |
⏭️ Buổi tiếp theo
Buổi 14: Security & Quality — OWASP, Secret Scanning, Code Review 🔒