Some checks failed
CI/CD Pipeline / Code Quality (push) Failing after 3s
CI/CD Pipeline / Unit Tests (push) Has been skipped
CI/CD Pipeline / Build Test Image (push) Has been skipped
CI/CD Pipeline / Build Production Image (push) Has been skipped
CI/CD Pipeline / Deploy to Test (push) Has been skipped
CI/CD Pipeline / Deploy to Production (push) Has been skipped
211 lines
5.5 KiB
YAML
211 lines
5.5 KiB
YAML
# Gitea Actions CI/CD 配置
|
||
# Duoqi API - 双分支工作流(develop → main)
|
||
#
|
||
# 工作流:
|
||
# develop push → quality → test → build → 自动部署测试环境
|
||
# main push → quality → test → build → 手动确认部署生产环境
|
||
|
||
name: CI/CD Pipeline
|
||
|
||
on:
|
||
push:
|
||
branches: [main, develop]
|
||
|
||
env:
|
||
DEPLOY_DIR: /opt/duoqi-api
|
||
|
||
jobs:
|
||
# ==================== 代码质量检查 ====================
|
||
quality:
|
||
name: Code Quality
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- name: Install git
|
||
run: apk add --no-cache git
|
||
|
||
- name: Checkout code
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Setup Bun
|
||
uses: oven-sh/setup-bun@v2
|
||
|
||
- name: Install dependencies
|
||
run: bun install --frozen-lockfile
|
||
|
||
- name: Run ESLint
|
||
run: bun run lint
|
||
|
||
- name: Type check
|
||
run: bun run typecheck
|
||
|
||
# ==================== 运行测试 ====================
|
||
test:
|
||
name: Unit Tests
|
||
runs-on: ubuntu-latest
|
||
needs: quality
|
||
steps:
|
||
- name: Install git
|
||
run: apk add --no-cache git
|
||
|
||
- name: Checkout code
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Setup Bun
|
||
uses: oven-sh/setup-bun@v2
|
||
|
||
- name: Install dependencies
|
||
run: bun install --frozen-lockfile
|
||
|
||
- name: Run tests with coverage
|
||
run: bun run test:coverage
|
||
|
||
- name: Upload coverage
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: coverage-report
|
||
path: coverage/
|
||
|
||
# ==================== 构建测试镜像 ====================
|
||
build-test:
|
||
name: Build Test Image
|
||
runs-on: ubuntu-latest
|
||
needs: [quality, test]
|
||
if: github.ref == 'refs/heads/develop'
|
||
steps:
|
||
- name: Install git
|
||
run: apk add --no-cache git
|
||
|
||
- name: Checkout code
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Build test image
|
||
run: |
|
||
docker build --build-arg NODE_ENV=test -t duoqi-api:test .
|
||
mkdir -p /tmp/images
|
||
docker save duoqi-api:test -o /tmp/images/duoqi-api-test.tar
|
||
|
||
- name: Upload image artifact
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: docker-images-test
|
||
path: /tmp/images/
|
||
retention-days: 1
|
||
|
||
# ==================== 构建生产镜像 ====================
|
||
build-prod:
|
||
name: Build Production Image
|
||
runs-on: ubuntu-latest
|
||
needs: [quality, test]
|
||
if: github.ref == 'refs/heads/main'
|
||
steps:
|
||
- name: Install git
|
||
run: apk add --no-cache git
|
||
|
||
- name: Checkout code
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Build production image
|
||
run: |
|
||
docker build -t duoqi-api:prod .
|
||
mkdir -p /tmp/images
|
||
docker save duoqi-api:prod -o /tmp/images/duoqi-api-prod.tar
|
||
|
||
- name: Upload image artifact
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: docker-images-prod
|
||
path: /tmp/images/
|
||
retention-days: 1
|
||
|
||
# ==================== 部署到测试环境(develop push 自动触发) ====================
|
||
deploy-test:
|
||
name: Deploy to Test
|
||
runs-on: ubuntu-latest
|
||
needs: build-test
|
||
if: github.ref == 'refs/heads/develop'
|
||
environment:
|
||
name: test
|
||
url: http://test-api.duoqi.me
|
||
steps:
|
||
- name: Download image artifact
|
||
uses: actions/download-artifact@v4
|
||
with:
|
||
name: docker-images-test
|
||
path: /tmp/images/
|
||
|
||
- name: Load Docker image
|
||
run: docker load -i /tmp/images/duoqi-api-test.tar
|
||
|
||
- name: Deploy test environment
|
||
run: |
|
||
cd ${{ env.DEPLOY_DIR }}
|
||
docker compose --profile test up -d --no-build api-test
|
||
|
||
- name: Health check
|
||
run: |
|
||
sleep 10
|
||
for i in {1..5}; do
|
||
if curl -f http://localhost:3001/health; then
|
||
echo "Test environment is healthy!"
|
||
exit 0
|
||
fi
|
||
echo "Health check attempt $i failed, retrying..."
|
||
sleep 5
|
||
done
|
||
echo "Test environment health check failed"
|
||
exit 1
|
||
|
||
# ==================== 部署到生产环境(main push,手动确认) ====================
|
||
deploy-prod:
|
||
name: Deploy to Production
|
||
runs-on: ubuntu-latest
|
||
needs: build-prod
|
||
if: github.ref == 'refs/heads/main'
|
||
environment:
|
||
name: production
|
||
url: https://api.duoqi.me
|
||
steps:
|
||
- name: Download image artifact
|
||
uses: actions/download-artifact@v4
|
||
with:
|
||
name: docker-images-prod
|
||
path: /tmp/images/
|
||
|
||
- name: Load Docker image
|
||
run: docker load -i /tmp/images/duoqi-api-prod.tar
|
||
|
||
- name: Deploy production
|
||
run: |
|
||
cd ${{ env.DEPLOY_DIR }}
|
||
|
||
# 备份当前镜像(用于回滚)
|
||
docker tag duoqi-api:prod duoqi-api:rollback 2>/dev/null || true
|
||
|
||
# 滚动更新
|
||
docker compose up -d --no-build api-prod
|
||
|
||
- name: Health check
|
||
run: |
|
||
sleep 15
|
||
for i in {1..5}; do
|
||
if curl -f http://localhost:3000/health; then
|
||
echo "Production deployment successful!"
|
||
exit 0
|
||
fi
|
||
echo "Health check attempt $i failed, retrying..."
|
||
sleep 5
|
||
done
|
||
|
||
# 健康检查失败,自动回滚
|
||
echo "Health check failed! Rolling back..."
|
||
cd ${{ env.DEPLOY_DIR }}
|
||
docker tag duoqi-api:rollback duoqi-api:prod
|
||
docker compose up -d --no-build api-prod
|
||
exit 1
|
||
|
||
- name: Cleanup
|
||
if: always()
|
||
run: |
|
||
docker image prune -f
|
||
rm -rf /tmp/images
|