CI/CD
Bob keeps making mistakes every time he deploys manually—forgetting to run migrations, configuring environment variables incorrectly, and pushing code to production before it passes tests. Charlie needs to automate CI/CD: automatic testing upon code push, automatic pull request previews, and automatic deployment to production from the main branch, all with zero manual intervention.
1. What You'll Learn
- GitHub Actions workflow: lint → test → build → deploy
- Code Quality Checks: ESLint + Prettier + TypeCheck + Vitest Code Coverage
- Environment Management: development → staging → production
- Deployment Strategy: Blue-Green Deployment + Rolling Updates + Rollback
- MegaShop PR Auto Preview + main Auto Deployment
2. A True Story of an Administrator
(1) Pain Point: Frequent errors during manual deployment
Bob manually deploys MegaShop. The steps are: 1) Clone the repository 2) Run npm install 3) Run tests (forgot) 4) Build 5) Upload 6) Run migrations (forgot) 7) Restart the service. Missing even one step causes a problem, resulting in an average of two deployment incidents per month.
(2) A Solution Using GitHub Actions CI/CD
The full process runs automatically with every push:
# .github/workflows/deploy.yml
on: push
jobs:
test: → lint + typecheck + vitest
build: → npm run build
deploy: → docker compose up -d
(3) Benefits: Zero labor + Zero accidents
Fully automated testing, building, and deployment after code is pushed; pull requests automatically generate preview environments; code merges into the main branch are automatically deployed; and deployment incidents are reduced to zero.
3. GitHub Actions Workflows
(1) CI/CD Pipeline Stages
flowchart LR
A[Push / PR] --> B[Lint + TypeCheck]
B --> C[Unit Tests]
C --> D[Build]
D --> E{Branch?}
E -->|PR| F[Preview Deploy]
E -->|main| G[Staging Deploy]
G --> H[Smoke Test]
H --> I[Production Deploy]
I --> J[Health Check]
J --> K[Done ✅]
(1) ▶ Example: A Complete CI Workflow
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npx nuxi typecheck
test:
runs-on: ubuntu-latest
needs: lint
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: megashop_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
DATABASE_URL: postgresql://test:test@localhost:5432/megashop_test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npx prisma migrate deploy
- run: npm run test:coverage
- name: Upload coverage
uses: codecov/codecov-action@v4
build:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npx prisma generate
- run: npm run build
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: nuxt-build
path: .output/
Output:
CI/CD pipeline loaded
Pipeline status: passed
Tests: 12 passed, 0 failed
4. Code Quality Control
(1) Quality Access Control Configuration
(1) ▶ Example: ESLint + Prettier Configuration
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxt/eslint'],
eslint: {
config: {
stylistic: {
indent: 2,
quotes: 'single',
semi: false
}
}
}
})
Output:
// Execution Successful
(2) ▶ Example: package.json scripts
{
"scripts": {
"dev": "nuxi dev",
"build": "nuxi build",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"typecheck": "nuxi typecheck",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"test:e2e": "playwright test",
"validate": "npm run lint && npm run typecheck && npm run test"
}
}
Output:
{
"scripts": {
"dev": "nuxi dev",
"build": "nuxi build",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"typecheck": "nuxi typecheck",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"test:e2e": "playwright test",
"validate": "npm run lint && npm run typecheck && npm run test"
}
}
(2) Quality Access Control Metrics
| Metric | Tool | Access Threshold | Description |
|---|---|---|---|
| Code Style | ESLint | 0 errors | Consistent Code Style |
| Formatting | Prettier | 0 warnings | Auto-formatting |
| Type Checking | vue-tsc | 0 errors | TypeScript Type Safety |
| Unit Tests | Vitest | ≥ 80% coverage | Core Logic Coverage |
| E2E Testing | Playwright | All Passed | Key Process Validation |
| Bundle Size | rollup-plugin | < 200 KB gzip | Prevent size bloat |
5. Multi-Environment Management
(1) ▶ Example: Environment Configuration File
# .env.development
DATABASE_URL=postgresql://dev:dev@localhost:5432/megashop_dev
REDIS_URL=redis://localhost:6379
JWT_ACCESS_SECRET=dev-access-secret
# .env.staging
DATABASE_URL=postgresql://staging:xxx@staging-db.internal:5432/megashop_staging
REDIS_URL=redis://staging-redis.internal:6379
JWT_ACCESS_SECRET=${{ secrets.STAGING_JWT_SECRET }}
# .env.production
DATABASE_URL=postgresql://prod:xxx@prod-db.internal:5432/megashop
REDIS_URL=redis://prod-redis.internal:6379
JWT_ACCESS_SECRET=${{ secrets.PROD_JWT_SECRET }}
(2) ▶ Example: Staging Deployment Workflow
# .github/workflows/deploy-staging.yml
name: Deploy Staging
on:
push:
branches: [main]
jobs:
deploy-staging:
runs-on: ubuntu-latest
needs: [lint, test]
environment: staging
steps:
- uses: actions/checkout@v4
- name: Deploy to staging
run: |
ssh staging-server << 'EOF'
cd /opt/megashop
git pull origin main
docker compose up -d --build
docker compose exec web npx prisma migrate deploy
EOF
- name: Smoke test
run: |
sleep 10
curl -f https://staging.megashop.com/api/products?limit=1 || exit 1
- name: Notify team
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: |
{"text": "Staging deployment failed!"}
Output:
CONTAINER ID IMAGE STATUS PORTS
abc123 nginx:latest Up 2 hours 0.0.0.0:80->80/tcp
(1) Environmental Comparison
| Environment | Purpose | Database | Deployment Method | Access Permissions |
|---|---|---|---|---|
| development | local development | local PostgreSQL | npm run dev | developers |
| staging | Integration Testing | Standalone PostgreSQL | Automated (main push) | Team |
| production | Production Environment | Production PostgreSQL | Automatic (tag/release) | All Users |
6. Deployment Strategy
(1) Comparison of Deployment Strategies
| Strategy | Principle | Downtime | Rollback Speed | Complexity |
|---|---|---|---|---|
| Direct Replacement | Phase Out and Roll Out | 🔴 Yes (5-30 s) | 🟡 Redeployment | 🟢 Simple |
| Blue-Green Deployment | Switching Between Two Environments | 🟢 None | 🟢 Switching in Seconds | 🟡 Medium |
| Rolling Update | Replace Instances One by One | 🟢 None | 🟡 Roll Back One by One | 🟡 In Progress |
| Canary Release | Validate with a Small User Base First | 🟢 None | 🟢 Roll Back Immediately | 🔴 Complex |
(1) ▶ Example: Blue-Green Deployment Script
#!/bin/bash
# deploy-blue-green.sh
CURRENT=$(docker compose ps --format '{{.Name}}' | grep -o 'blue\|green' | head -1)
if [ "$CURRENT" = "blue" ]; then
NEXT="green"
else
NEXT="blue"
fi
echo "Deploying to $NEXT environment..."
# Build and start next environment
docker compose -f docker-compose.yml -f docker-compose.$NEXT.yml up -d --build
# Wait for health check
for i in {1..30}; do
if curl -sf http://localhost:3001/health; then
echo "Health check passed"
break
fi
sleep 2
done
# Switch Nginx to new environment
sed "s/$CURRENT/$NEXT/g" nginx.conf > /tmp/nginx.conf
docker compose exec nginx nginx -s reload
echo "Switched from $CURRENT to $NEXT"
Output:
CONTAINER ID IMAGE STATUS
abc123 latest Up 2 hours
7. Comprehensive Example: The Complete MegaShop CI/CD Process
# .github/workflows/deploy-production.yml
name: Deploy Production
on:
release:
types: [published]
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t megashop:${{ github.sha }} .
- name: Push to registry
run: |
docker tag megashop:${{ github.sha }} ghcr.io/megashop/megashop:latest
echo ${{ secrets.GHCR_TOKEN }} | docker login ghcr.io -u $ --password-stdin
docker push ghcr.io/megashop/megashop:latest
- name: Deploy to production
run: |
ssh prod-server << EOF
cd /opt/megashop
docker pull ghcr.io/megashop/megashop:latest
docker compose up -d --no-build
docker compose exec web npx prisma migrate deploy
EOF
- name: Health check
run: |
for i in {1..10}; do
if curl -sf https://megashop.com/api/health; then exit 0; fi
sleep 5
done
exit 1
- name: Rollback on failure
if: failure()
run: |
ssh prod-server << EOF
cd /opt/megashop
docker compose down
docker tag megashop:previous megashop:latest
docker compose up -d
EOF
❓ FAQ
prisma migrate deploy (which only applies existing migrations and does not create new ones). During development, use prisma migrate dev to create migration files and commit them to Git.git revert and redeploy. For Docker, restart using the previous image tag. For PM2, use pm2 stop and then start the old version. To automate rollbacks, add logic for handling failed health checks to the deployment script.runtimeConfig are server-side only. In CI, reference them using ${{ secrets.XXX }}.📖 Summary
- Implementing a fully automated pipeline (lint → test → build → deploy) using GitHub Actions
- Code Quality Requirements: ESLint + TypeCheck + Vitest ≥ 80% coverage
- Three-environment management: development (local) → staging (integration testing) → production (live)
- Blue-green deployment ensures zero downtime; automatic rollback upon health check failure
- MegaShop: Automatic preview for PRs + automatic staging for "main" + automatic deployment to production for "release"
📝 Exercises
- Basic Exercise (Difficulty: ⭐): Create a GitHub Actions CI workflow that automatically runs linting, type checking, and tests when a commit is pushed.
- Advanced Exercise (Difficulty ⭐⭐): Add automatic deployment to staging—when the main branch is pushed, automatically deploy to the staging server and run a smoke test after deployment.
- Challenge (Difficulty: ⭐⭐⭐): Implement a blue-green deployment script + automatic rollback—automatically switch back to the previous version when a health check fails
---|



