name: CI/CD Pipeline on: push: branches: [ main, develop ] pull_request: branches: [ main ] jobs: test: name: 测试 runs-on: ubuntu-latest strategy: matrix: node-version: [18.x, 20.x] steps: - name: 检出代码 uses: actions/checkout@v4 - name: 设置 Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: 'npm' cache-dependency-path: frontend/package-lock.json - name: 安装依赖 working-directory: ./frontend run: npm ci - name: 类型检查 working-directory: ./frontend run: npm run type-check - name: 代码风格检查 working-directory: ./frontend run: npm run lint - name: 代码格式检查 working-directory: ./frontend run: npm run format:check - name: 运行单元测试 working-directory: ./frontend run: npm run test:unit:coverage - name: 上传覆盖率报告到 Codecov uses: codecov/codecov-action@v3 with: file: ./frontend/coverage/lcov.info flags: unittests name: codecov-umbrella - name: 构建应用 working-directory: ./frontend run: npm run build - name: 安装 Playwright working-directory: ./frontend run: npx playwright install --with-deps - name: 运行 E2E 测试 working-directory: ./frontend run: npm run test:e2e - name: 上传 E2E 测试报告 uses: actions/upload-artifact@v3 if: always() with: name: playwright-report path: frontend/playwright-report/ retention-days: 30 - name: 上传测试结果 uses: actions/upload-artifact@v3 if: always() with: name: test-results path: frontend/test-results/ retention-days: 30 security: name: 安全检查 runs-on: ubuntu-latest steps: - name: 检出代码 uses: actions/checkout@v4 - name: 设置 Node.js uses: actions/setup-node@v4 with: node-version: '20.x' cache: 'npm' cache-dependency-path: frontend/package-lock.json - name: 安装依赖 working-directory: ./frontend run: npm ci - name: 运行安全审计 working-directory: ./frontend run: npm audit --audit-level moderate - name: 运行 Snyk 安全扫描 uses: snyk/actions/node@master continue-on-error: true env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: args: --severity-threshold=high deploy: name: 部署 needs: [test, security] runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' && github.event_name == 'push' steps: - name: 检出代码 uses: actions/checkout@v4 - name: 设置 Node.js uses: actions/setup-node@v4 with: node-version: '20.x' cache: 'npm' cache-dependency-path: frontend/package-lock.json - name: 安装依赖 working-directory: ./frontend run: npm ci - name: 构建应用 working-directory: ./frontend run: npm run build - name: 部署到服务器 uses: appleboy/ssh-action@v1.0.0 with: host: ${{ secrets.HOST }} username: ${{ secrets.USERNAME }} key: ${{ secrets.SSH_KEY }} script: | cd /var/www/html git pull origin main cd frontend npm ci --production npm run build pm2 restart frontend-app notify: name: 通知 needs: [test, security, deploy] runs-on: ubuntu-latest if: always() steps: - name: 发送通知到 Slack uses: 8398a7/action-slack@v3 with: status: ${{ job.status }} channel: '#ci-cd' webhook_url: ${{ secrets.SLACK_WEBHOOK }} fields: repo,message,commit,author,action,eventName,ref,workflow