智慧水务管理系统 - 精河县供水工程综合管理平台

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. # ============================================================
  2. # 智慧水务管理系统 - CI/CD 流水线
  3. # 触发条件: push / pull_request 到 main, develop, feature/* 分支
  4. # 兼容 Gitea Actions (act_runner)
  5. # ============================================================
  6. name: CI/CD Pipeline
  7. on:
  8. push:
  9. branches:
  10. - main
  11. - develop
  12. - 'feature/**'
  13. paths-ignore:
  14. - '**.md'
  15. - 'docs/**'
  16. - '.gitignore'
  17. pull_request:
  18. branches:
  19. - main
  20. - develop
  21. env:
  22. # 容器镜像仓库地址(按实际环境修改)
  23. REGISTRY: ${{ secrets.REGISTRY_URL || 'registry.example.com' }}
  24. # 部署目标服务器
  25. DEPLOY_HOST_TESTING: ${{ secrets.DEPLOY_HOST_TESTING || 'testing.example.com' }}
  26. DEPLOY_HOST_PRODUCTION: ${{ secrets.DEPLOY_HOST_PRODUCTION || 'prod.example.com' }}
  27. DEPLOY_USER: ${{ secrets.DEPLOY_USER || 'deploy' }}
  28. DEPLOY_KEY: ${{ secrets.DEPLOY_SSH_KEY || '' }}
  29. # 企业微信 Webhook
  30. WECOM_WEBHOOK: ${{ secrets.WECOM_WEBHOOK || '' }}
  31. jobs:
  32. # ==================== 1. 代码检查 (Lint) ====================
  33. lint:
  34. name: 代码检查
  35. runs-on: ubuntu-latest
  36. steps:
  37. - name: 检出代码
  38. uses: actions/checkout@v4
  39. # Python lint (如有 Python 代码)
  40. - name: 设置 Python
  41. uses: actions/setup-python@v5
  42. with:
  43. python-version: '3.11'
  44. - name: Python Lint (ruff)
  45. run: |
  46. pip install ruff
  47. # 检查项目中是否存在 Python 文件
  48. PY_FILES=$(find . -name "*.py" -not -path "./.git/*" -not -path "*/node_modules/*" -not -path "*/__pycache__/*" 2>/dev/null || true)
  49. if [ -n "$PY_FILES" ]; then
  50. echo "发现 Python 文件,执行 ruff 检查..."
  51. ruff check . --exclude node_modules --exclude .git || echo "⚠️ ruff 检查发现问题,请修复"
  52. ruff format --check . --exclude node_modules --exclude .git || echo "⚠️ 格式化检查未通过,请执行 ruff format"
  53. else
  54. echo "未发现 Python 文件,跳过"
  55. fi
  56. # Java lint (Maven checkstyle)
  57. - name: 设置 JDK 17
  58. uses: actions/setup-java@v4
  59. with:
  60. distribution: 'temurin'
  61. java-version: '17'
  62. cache: 'maven'
  63. - name: Java Lint (Checkstyle)
  64. run: |
  65. if [ -f "pom.xml" ]; then
  66. echo "执行 Maven Checkstyle 检查..."
  67. mvn checkstyle:check -B 2>/dev/null || echo "⚠️ Checkstyle 未配置或检查未通过,跳过(非阻塞)"
  68. else
  69. echo "未发现 pom.xml,跳过 Java lint"
  70. fi
  71. # 前端基础校验
  72. - name: 前端校验
  73. run: |
  74. chmod +x scripts/lint.sh 2>/dev/null || true
  75. if [ -f "scripts/lint.sh" ]; then
  76. ./scripts/lint.sh
  77. else
  78. echo "lint.sh 不存在,跳过前端校验"
  79. fi
  80. # ==================== 2. 自动测试 (Test) ====================
  81. test:
  82. name: 自动测试
  83. runs-on: ubuntu-latest
  84. needs: lint
  85. steps:
  86. - name: 检出代码
  87. uses: actions/checkout@v4
  88. # Python 测试
  89. - name: 设置 Python
  90. uses: actions/setup-python@v5
  91. with:
  92. python-version: '3.11'
  93. - name: Python 测试 (pytest)
  94. run: |
  95. pip install pytest
  96. # 查找测试文件
  97. TEST_FILES=$(find . -name "test_*.py" -not -path "./.git/*" -not -path "*/node_modules/*" 2>/dev/null || true)
  98. if [ -n "$TEST_FILES" ]; then
  99. echo "发现测试文件: $TEST_FILES"
  100. # 安装项目依赖(如有 requirements.txt)
  101. [ -f requirements.txt ] && pip install -r requirements.txt || true
  102. pytest -v --tb=short || echo "⚠️ 部分测试未通过"
  103. else
  104. echo "未发现 Python 测试文件,跳过"
  105. fi
  106. # Java 测试
  107. - name: 设置 JDK 17
  108. uses: actions/setup-java@v4
  109. with:
  110. distribution: 'temurin'
  111. java-version: '17'
  112. cache: 'maven'
  113. - name: Java 测试 (Maven)
  114. run: |
  115. if [ -f "pom.xml" ]; then
  116. echo "执行 Maven 测试..."
  117. mvn test -B -pl wm-common,wm-patrol -am 2>/dev/null || echo "⚠️ 部分测试未通过(非阻塞)"
  118. else
  119. echo "未发现 pom.xml,跳过 Java 测试"
  120. fi
  121. # ==================== 3. Docker 镜像构建与推送 ====================
  122. build:
  123. name: 构建镜像
  124. runs-on: ubuntu-latest
  125. needs: test
  126. if: github.event_name == 'push'
  127. outputs:
  128. image_tag: ${{ steps.meta.outputs.tag }}
  129. steps:
  130. - name: 检出代码
  131. uses: actions/checkout@v4
  132. - name: 生成镜像标签
  133. id: meta
  134. run: |
  135. BRANCH="${GITHUB_REF_NAME//\//_}"
  136. SHA_SHORT="${GITHUB_SHA:0:8}"
  137. TAG="${BRANCH}-${SHA_SHORT}"
  138. echo "tag=${TAG}" >> $GITHUB_OUTPUT
  139. echo "branch=${BRANCH}" >> $GITHUB_OUTPUT
  140. echo "sha_short=${SHA_SHORT}" >> $GITHUB_OUTPUT
  141. echo "镜像标签: ${TAG}"
  142. - name: 登录容器镜像仓库
  143. if: env.REGISTRY != 'registry.example.com'
  144. run: |
  145. echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login ${REGISTRY} \
  146. -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
  147. - name: 构建所有镜像
  148. run: |
  149. chmod +x docker/ci/build.sh
  150. ./docker/ci/build.sh --tag ${{ steps.meta.outputs.tag }} \
  151. ${REGISTRY:+--registry ${REGISTRY}}
  152. - name: 构建 latest 标签
  153. if: github.ref == 'refs/heads/main'
  154. run: |
  155. chmod +x docker/ci/build.sh
  156. ./docker/ci/build.sh --tag latest \
  157. ${REGISTRY:+--registry ${REGISTRY}}
  158. - name: 推送镜像
  159. if: env.REGISTRY != 'registry.example.com'
  160. run: |
  161. chmod +x docker/ci/build.sh
  162. ./docker/ci/build.sh --tag ${{ steps.meta.outputs.tag }} \
  163. --registry ${REGISTRY} --push
  164. if [ "${{ github.ref }}" = "refs/heads/main" ]; then
  165. ./docker/ci/build.sh --tag latest \
  166. --registry ${REGISTRY} --push
  167. fi
  168. # ==================== 4. 自动部署 ====================
  169. deploy-testing:
  170. name: 部署到测试环境
  171. runs-on: ubuntu-latest
  172. needs: build
  173. if: github.ref == 'refs/heads/develop' || startsWith(github.ref, 'refs/heads/feature/')
  174. environment: testing
  175. steps:
  176. - name: 检出代码
  177. uses: actions/checkout@v4
  178. - name: 部署到测试环境
  179. run: |
  180. chmod +x scripts/deploy.sh
  181. ./scripts/deploy.sh \
  182. --env testing \
  183. --host ${{ env.DEPLOY_HOST_TESTING }} \
  184. --user ${{ env.DEPLOY_USER }} \
  185. --tag ${{ needs.build.outputs.image_tag }}
  186. - name: 部署结果通知
  187. if: always()
  188. run: |
  189. chmod +x scripts/deploy.sh
  190. ./scripts/deploy.sh --notify \
  191. --env testing \
  192. --status ${{ job.status }} \
  193. --webhook "${{ env.WECOM_WEBHOOK }}" \
  194. --branch "${{ github.ref_name }}" \
  195. --commit "${{ github.sha }}" \
  196. --project "智慧水务管理系统"
  197. deploy-production:
  198. name: 部署到生产环境
  199. runs-on: ubuntu-latest
  200. needs: build
  201. if: github.ref == 'refs/heads/main'
  202. environment: production
  203. steps:
  204. - name: 检出代码
  205. uses: actions/checkout@v4
  206. - name: 部署到生产环境
  207. run: |
  208. chmod +x scripts/deploy.sh
  209. ./scripts/deploy.sh \
  210. --env production \
  211. --host ${{ env.DEPLOY_HOST_PRODUCTION }} \
  212. --user ${{ env.DEPLOY_USER }} \
  213. --tag ${{ needs.build.outputs.image_tag }}
  214. - name: 部署结果通知
  215. if: always()
  216. run: |
  217. chmod +x scripts/deploy.sh
  218. ./scripts/deploy.sh --notify \
  219. --env production \
  220. --status ${{ job.status }} \
  221. --webhook "${{ env.WECOM_WEBHOOK }}" \
  222. --branch "${{ github.ref_name }}" \
  223. --commit "${{ github.sha }}" \
  224. --project "智慧水务管理系统"