# ============================================================ # 智慧水务管理系统 - CI/CD 流水线 # 触发条件: push / pull_request 到 main, develop, feature/* 分支 # 兼容 Gitea Actions (act_runner) # ============================================================ name: CI/CD Pipeline on: push: branches: - main - develop - 'feature/**' paths-ignore: - '**.md' - 'docs/**' - '.gitignore' pull_request: branches: - main - develop env: # 容器镜像仓库地址(按实际环境修改) REGISTRY: ${{ secrets.REGISTRY_URL || 'registry.example.com' }} # 部署目标服务器 DEPLOY_HOST_TESTING: ${{ secrets.DEPLOY_HOST_TESTING || 'testing.example.com' }} DEPLOY_HOST_PRODUCTION: ${{ secrets.DEPLOY_HOST_PRODUCTION || 'prod.example.com' }} DEPLOY_USER: ${{ secrets.DEPLOY_USER || 'deploy' }} DEPLOY_KEY: ${{ secrets.DEPLOY_SSH_KEY || '' }} # 企业微信 Webhook WECOM_WEBHOOK: ${{ secrets.WECOM_WEBHOOK || '' }} jobs: # ==================== 1. 代码检查 (Lint) ==================== lint: name: 代码检查 runs-on: ubuntu-latest steps: - name: 检出代码 uses: actions/checkout@v4 # Python lint (如有 Python 代码) - name: 设置 Python uses: actions/setup-python@v5 with: python-version: '3.11' - name: Python Lint (ruff) run: | pip install ruff # 检查项目中是否存在 Python 文件 PY_FILES=$(find . -name "*.py" -not -path "./.git/*" -not -path "*/node_modules/*" -not -path "*/__pycache__/*" 2>/dev/null || true) if [ -n "$PY_FILES" ]; then echo "发现 Python 文件,执行 ruff 检查..." ruff check . --exclude node_modules --exclude .git || echo "⚠️ ruff 检查发现问题,请修复" ruff format --check . --exclude node_modules --exclude .git || echo "⚠️ 格式化检查未通过,请执行 ruff format" else echo "未发现 Python 文件,跳过" fi # Java lint (Maven checkstyle) - name: 设置 JDK 17 uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17' cache: 'maven' - name: Java Lint (Checkstyle) run: | if [ -f "pom.xml" ]; then echo "执行 Maven Checkstyle 检查..." mvn checkstyle:check -B 2>/dev/null || echo "⚠️ Checkstyle 未配置或检查未通过,跳过(非阻塞)" else echo "未发现 pom.xml,跳过 Java lint" fi # 前端基础校验 - name: 前端校验 run: | chmod +x scripts/lint.sh 2>/dev/null || true if [ -f "scripts/lint.sh" ]; then ./scripts/lint.sh else echo "lint.sh 不存在,跳过前端校验" fi # ==================== 2. 自动测试 (Test) ==================== test: name: 自动测试 runs-on: ubuntu-latest needs: lint steps: - name: 检出代码 uses: actions/checkout@v4 # Python 测试 - name: 设置 Python uses: actions/setup-python@v5 with: python-version: '3.11' - name: Python 测试 (pytest) run: | pip install pytest # 查找测试文件 TEST_FILES=$(find . -name "test_*.py" -not -path "./.git/*" -not -path "*/node_modules/*" 2>/dev/null || true) if [ -n "$TEST_FILES" ]; then echo "发现测试文件: $TEST_FILES" # 安装项目依赖(如有 requirements.txt) [ -f requirements.txt ] && pip install -r requirements.txt || true pytest -v --tb=short || echo "⚠️ 部分测试未通过" else echo "未发现 Python 测试文件,跳过" fi # Java 测试 - name: 设置 JDK 17 uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17' cache: 'maven' - name: Java 测试 (Maven) run: | if [ -f "pom.xml" ]; then echo "执行 Maven 测试..." mvn test -B -pl wm-common,wm-patrol -am 2>/dev/null || echo "⚠️ 部分测试未通过(非阻塞)" else echo "未发现 pom.xml,跳过 Java 测试" fi # ==================== 3. Docker 镜像构建与推送 ==================== build: name: 构建镜像 runs-on: ubuntu-latest needs: test if: github.event_name == 'push' outputs: image_tag: ${{ steps.meta.outputs.tag }} steps: - name: 检出代码 uses: actions/checkout@v4 - name: 生成镜像标签 id: meta run: | BRANCH="${GITHUB_REF_NAME//\//_}" SHA_SHORT="${GITHUB_SHA:0:8}" TAG="${BRANCH}-${SHA_SHORT}" echo "tag=${TAG}" >> $GITHUB_OUTPUT echo "branch=${BRANCH}" >> $GITHUB_OUTPUT echo "sha_short=${SHA_SHORT}" >> $GITHUB_OUTPUT echo "镜像标签: ${TAG}" - name: 登录容器镜像仓库 if: env.REGISTRY != 'registry.example.com' run: | echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login ${REGISTRY} \ -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin - name: 构建所有镜像 run: | chmod +x docker/ci/build.sh ./docker/ci/build.sh --tag ${{ steps.meta.outputs.tag }} \ ${REGISTRY:+--registry ${REGISTRY}} - name: 构建 latest 标签 if: github.ref == 'refs/heads/main' run: | chmod +x docker/ci/build.sh ./docker/ci/build.sh --tag latest \ ${REGISTRY:+--registry ${REGISTRY}} - name: 推送镜像 if: env.REGISTRY != 'registry.example.com' run: | chmod +x docker/ci/build.sh ./docker/ci/build.sh --tag ${{ steps.meta.outputs.tag }} \ --registry ${REGISTRY} --push if [ "${{ github.ref }}" = "refs/heads/main" ]; then ./docker/ci/build.sh --tag latest \ --registry ${REGISTRY} --push fi # ==================== 4. 自动部署 ==================== deploy-testing: name: 部署到测试环境 runs-on: ubuntu-latest needs: build if: github.ref == 'refs/heads/develop' || startsWith(github.ref, 'refs/heads/feature/') environment: testing steps: - name: 检出代码 uses: actions/checkout@v4 - name: 部署到测试环境 run: | chmod +x scripts/deploy.sh ./scripts/deploy.sh \ --env testing \ --host ${{ env.DEPLOY_HOST_TESTING }} \ --user ${{ env.DEPLOY_USER }} \ --tag ${{ needs.build.outputs.image_tag }} - name: 部署结果通知 if: always() run: | chmod +x scripts/deploy.sh ./scripts/deploy.sh --notify \ --env testing \ --status ${{ job.status }} \ --webhook "${{ env.WECOM_WEBHOOK }}" \ --branch "${{ github.ref_name }}" \ --commit "${{ github.sha }}" \ --project "智慧水务管理系统" deploy-production: name: 部署到生产环境 runs-on: ubuntu-latest needs: build if: github.ref == 'refs/heads/main' environment: production steps: - name: 检出代码 uses: actions/checkout@v4 - name: 部署到生产环境 run: | chmod +x scripts/deploy.sh ./scripts/deploy.sh \ --env production \ --host ${{ env.DEPLOY_HOST_PRODUCTION }} \ --user ${{ env.DEPLOY_USER }} \ --tag ${{ needs.build.outputs.image_tag }} - name: 部署结果通知 if: always() run: | chmod +x scripts/deploy.sh ./scripts/deploy.sh --notify \ --env production \ --status ${{ job.status }} \ --webhook "${{ env.WECOM_WEBHOOK }}" \ --branch "${{ github.ref_name }}" \ --commit "${{ github.sha }}" \ --project "智慧水务管理系统"