From ff2d92ba541b09f78ce3bf73bc5f1edb80fdb031 Mon Sep 17 00:00:00 2001 From: wecom-fullstack Date: Wed, 14 Oct 2026 13:37:58 +0800 Subject: [PATCH] =?UTF-8?q?ci(woodpecker):=20=E9=83=A8=E7=BD=B2=E9=80=9A?= =?UTF-8?q?=E9=81=93=E6=94=B6=E5=8F=A3=E4=B8=BA=E5=8D=95=E9=93=BE=20?= =?UTF-8?q?=E2=80=94=E2=80=94=20CI=20=E5=8F=AA=E5=81=9A=E9=97=A8=E7=A6=81?= =?UTF-8?q?=EF=BC=8C=E9=83=A8=E7=BD=B2=E6=81=92=E8=B5=B0=E5=AE=BF=E4=B8=BB?= =?UTF-8?q?=20Gitea=20hook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ② 现状: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。 --- .woodpecker/main.yml | 52 ++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/.woodpecker/main.yml b/.woodpecker/main.yml index a9ff2a30..65425d26 100644 --- a/.woodpecker/main.yml +++ b/.woodpecker/main.yml @@ -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: - branch: main 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: frontend-install: image: node:20-alpine + environment: + npm_config_registry: https://registry.npmmirror.com commands: - apk add --no-cache git - cd frontend @@ -24,6 +25,8 @@ steps: frontend-typecheck: image: node:20-alpine + environment: + npm_config_registry: https://registry.npmmirror.com commands: - cd frontend - npm install -g pnpm @@ -34,6 +37,8 @@ steps: frontend-build: image: node:20-alpine + environment: + npm_config_registry: https://registry.npmmirror.com commands: - cd frontend - npm install -g pnpm @@ -44,31 +49,16 @@ steps: backend-test: 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: - cd backend - 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 when: - 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/**