ci(woodpecker): 部署通道收口为单链 —— CI 只做门禁,部署恒走宿主 Gitea hook
ci/woodpecker/push/main Pipeline was successful

② 现状:push origin main 同时触发两条写生产链 ——
   (a) 宿主 Gitea post-receive hook → /usr/local/sbin/gitea-cma-deploy-hook.sh → deploy.sh(铺站 + 重启 + 冒烟)
   (b) Woodpecker pipeline 的 frontend-deploy(rsync --delete dist → /var/www/cma + nginx reload)
       与 backend-deploy(在开发区 git pull + systemctl restart cma-backend)
   两条链并发 ⇒ 两套在途部署判定、重复劳动与证据歧义(2026-10-13 事故即此形态)。
本提交复用 ci/wp-v3-fix-20260916 已写就的 .woodpecker/main.yml(wecom-project 2026-09-16 8ddcbe1):
   删除 variables(ssh_setup) 与 frontend-deploy/backend-deploy 两步,只留门禁
   (frontend-install/typecheck/build + backend-test),并补国内镜像与 pytest 安装。
零生产写:候选仅落本 worktree 分支,未 push。
This commit is contained in:
wecom-fullstack
2026-10-16 03:05:57 +08:00
committed by Hermes CI Fix
parent d2cb812bfa
commit ff2d92ba54
+21 -31
View File
@@ -1,19 +1,20 @@
# CMA CI 门禁(单一部署通道)
#
# 本 workflow 只做「门禁」:前端 typecheck/build + 后端测试。
# 部署不走 CI —— 由宿主 Gitea post-receive hook(/root/cma-management/deploy.sh)承担,
# 避免 CI 与宿主 hook 双通道同时 git pull / systemctl restart 互相打架。
#
# 依赖安装走国内源:容器里直连 pypi.org 装 backend 依赖 >240s 未完成(2026-09-16 实测),
# 华为云镜像同依赖 14s。
when: when:
- branch: main - branch: main
event: push event: push
variables:
- &ssh_setup |
apk add --no-cache openssh-client rsync
mkdir -p ~/.ssh
printf '%s\n' "$SSH_DEPLOY_KEY" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -H git.sxbh.ltd >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
steps: steps:
frontend-install: frontend-install:
image: node:20-alpine image: node:20-alpine
environment:
npm_config_registry: https://registry.npmmirror.com
commands: commands:
- apk add --no-cache git - apk add --no-cache git
- cd frontend - cd frontend
@@ -24,6 +25,8 @@ steps:
frontend-typecheck: frontend-typecheck:
image: node:20-alpine image: node:20-alpine
environment:
npm_config_registry: https://registry.npmmirror.com
commands: commands:
- cd frontend - cd frontend
- npm install -g pnpm - npm install -g pnpm
@@ -34,6 +37,8 @@ steps:
frontend-build: frontend-build:
image: node:20-alpine image: node:20-alpine
environment:
npm_config_registry: https://registry.npmmirror.com
commands: commands:
- cd frontend - cd frontend
- npm install -g pnpm - npm install -g pnpm
@@ -44,31 +49,16 @@ steps:
backend-test: backend-test:
image: python:3.12 image: python:3.12
environment:
PIP_INDEX_URL: https://mirrors.huaweicloud.com/repository/pypi/simple/
PIP_DISABLE_PIP_VERSION_CHECK: "1"
PIP_TIMEOUT: "30"
PIP_RETRIES: "5"
commands: commands:
- cd backend - cd backend
- pip install -r requirements.txt --quiet - pip install -r requirements.txt --quiet
# pytest/pytest-timeout 不在 requirements.txt 里,不装则下面一行永远 No module named pytest
- pip install pytest pytest-timeout --quiet
- python -m pytest tests/ -x -q --disable-warnings --timeout=60 || true - python -m pytest tests/ -x -q --disable-warnings --timeout=60 || true
when: when:
- path: backend/** - path: backend/**
frontend-deploy:
image: alpine:latest
secrets:
- SSH_DEPLOY_KEY
commands:
- *ssh_setup
- rsync -avz --delete frontend/dist/ root@git.sxbh.ltd:/var/www/cma/
- ssh root@git.sxbh.ltd 'nginx -s reload || systemctl reload nginx'
when:
- path: frontend/**
backend-deploy:
image: alpine:latest
secrets:
- SSH_DEPLOY_KEY
commands:
- *ssh_setup
- |
ssh root@git.sxbh.ltd 'set -e; cd /root/cma-management; DIRTY=$(git status --porcelain 2>/dev/null | grep -v "__pycache__" | head -10); if [ -n "$DIRTY" ]; then echo "❌ 宿主机有未提交修改,中止部署:"; echo "$DIRTY"; exit 1; fi; git pull origin main; cd backend; pip install -r requirements.txt --quiet --no-cache-dir; systemctl restart cma-backend; SMOKE_READY_MAX="${SMOKE_READY_MAX:-30}"; READY_TRY=0; READY_OK=0; READY_T0=$(date +%s); READY_BODY=/tmp/cma-ci-ready-body.json; while [ $(( $(date +%s) - READY_T0 )) -lt "$SMOKE_READY_MAX" ]; do CODE=$(curl -s -o "$READY_BODY" -w "%{http_code}" --max-time 2 http://127.0.0.1:8010/health || echo 000); if [ "$CODE" = "200" ] && grep -q "\"status\":\"ok\"" "$READY_BODY" 2>/dev/null; then READY_OK=1; break; fi; sleep 0.5; READY_TRY=$(( READY_TRY + 1 )); done; if [ "$READY_OK" != "1" ]; then echo "🚨 后端就绪超时 ${SMOKE_READY_MAX}s(未达 HTTP200 + status=ok)"; cat "$READY_BODY" 2>/dev/null; exit 1; fi; echo "✅ 后端就绪(轮询 ${READY_TRY} 次,上限 ${SMOKE_READY_MAX}s)"; cat "$READY_BODY"'
when:
- path: backend/**