# Gitea Git Hooks vs Woodpecker CI — 方案评估报告 > 报告日期: 2026-07-12 > 评估对象: cma-management 项目全流程自动化 > 场景: 单服务器、单开发者(全栈Bot)、前端Vue3 + 后端FastAPI --- ## 1. 当前环境状态 | 组件 | 版本 | 状态 | |------|------|------| | Gitea | 1.22.6 (Docker) | ✅ 正常运行 | | Woodpecker Server | v3.12.0 (Docker) | ❌ OAuth集成故障 | | Woodpecker Agent | v3.12.0 (Docker) | ❌ 无任务可执行 | | cma-management | main分支 | ✅ Git仓库正常 | --- ## 2. 核心发现 ### Woodpecker CI 故障根因 ``` GetRepo: invalid character 'o' in literal null (expecting 'u') ``` - Woodpecker v3.12.0 调用 Gitea API 获取仓库信息时,Gitea 返回了非预期的 null 响应 - JSON 解析器期望一个对象(`{`),但收到了 `null`(字母 `n` 的 ascii 是 110,`o` 是 111 — 所以错误信息中出现了 `'o'` 字符) - 这是一个 **Woodpecker 与 Gitea 1.22 之间的兼容性 bug**,需要等待上游修复 - Cron 任务每 30 分钟重复失败,Webhook 调用也返回 400 - **结论:Woodpecker CI 在当前环境下不可用,且无短期可修复的 workaround** ### Gitea Git Hooks 机制已验证 Gitea 使用 `hooks/post-receive` → `hooks/post-receive.d/*` 的 hook 分发机制: ``` hooks/post-receive # 主脚本(Gitea自动生成) hooks/post-receive.d/ ├── gitea # Gitea内部hook(处理Webhook/Gitea Actions等) └── deploy # 自定义部署hook ← 我们添加的 ``` 关键发现: - Hook 脚本在 **Gitea Docker 容器内**以 `git` 用户(UID 1000)身份运行 - 容器与宿主机共享 Gitea 数据卷,但无法直接访问宿主机文件系统或 systemd - Gitea 容器内已安装 SSH 客户端,可通过 SSH 回到宿主机执行命令 --- ## 3. 方案对比 | 维度 | Git Hooks ✅(本方案) | Woodpecker CI ❌ | |------|:---------------------:|:----------------:| | **实现复杂度** | ★☆☆ 极简 — 1个shell脚本 | ★★★ 复杂 — 需要修复OAuth bug | | **运维成本** | ★☆☆ 零 — 无额外服务 | ★★★ 高 — Docker容器+SSH密钥+Agent维护 | | **故障排查** | ★★☆ 直接看push输出 | ★★★ 日志链路长:Gitea→OAuth→Woodpecker→Agent→容器 | | **流水线可视化** | ❌ 无Web UI(push输出可见) | ✅ 有Web UI(但当前不可用) | | **安全性(沙箱隔离)** | ❌ 直接在宿主机执行 | ✅ Docker容器隔离 | | **多步骤并行** | ❌ 顺序执行 | ✅ 支持并行 | | **Secrets管理** | ⚠️ 使用现有SSH密钥 | ✅ 内置Secrets管理 | | **是否满足当前需求** | ✅ **完全满足** | ❌ 当前不可用 | | **资源占用** | 0(零额外资源) | ~256MB内存 + Docker容器 | | **PR集成** | 不需要(单开发者) | 需要但用不到 | | **push到部署耗时** | ~10-15秒(含build) | ~20-30秒(含容器启动) | ### 详细分析 #### Git Hooks 为什么更适合这个场景? 1. **单服务器** — 所有操作都在本机,SSH回环比Docker容器隔离更直接 2. **单开发者(Bot)** — 不需要多用户协作、不需要PR流水线 3. **已有 deploy.sh** — 部署逻辑已封装好,hook只需要触发它 4. **零额外基础设施** — 不增加新的Docker容器,不增加API调用链路 5. **即时反馈** — `git push` 输出中直接看到构建部署日志 6. **Woodpecker 方案做了多余的事** — 它的 `.woodpecker/main.yml` 用 SSH key 从容器SSH回宿主机部署,而我们直接用 Gitea hook SSH 回宿主机 — 逻辑完全相同,但少了一层 Woodpecker 中间件 #### Woodpecker 的优势(在这个场景下用不到) - 多容器环境下的沙箱隔离 → 单服务器,信任域内 - 并行步骤/矩阵构建 → 构建+部署是线性流程 - Web UI 流水线可视化 → push输出可见,部署频率低(一天几次) --- ## 4. 推荐方案:方案A(Git Hooks) **明确推荐 Git Hooks 方案,并已实际部署验证通过。** ### 已实施的实现 #### a) Gitea Post-Receive Hook **位置**: `/data/git/repositories/sxbh_admin/cma-management.git/hooks/post-receive.d/deploy` (实际路径: `/root/docker/gitea/gitea/data/git/repositories/sxbh_admin/cma-management.git/hooks/post-receive.d/deploy`) ```bash #!/bin/bash # 每次 push 到 main 分支后,通过 SSH 到宿主机执行部署 set -e HOST="172.17.0.1" SSH_KEY="/data/git/.ssh/id_ed25519" SSH_CMD="ssh -i ${SSH_KEY} -o StrictHostKeyChecking=no root@${HOST}" while read oldrev newrev refname; do if [ "$refname" = "refs/heads/main" ]; then ${SSH_CMD} ' cd /root/cma-management git pull origin main bash deploy.sh ' fi done ``` #### b) 部署脚本(已修复) **位置**: `/root/cma-management/deploy.sh` 修复内容: - 移除 `pnpm build --no-frozen-lockfile`(Vite不认识该选项) - 后端 pip install 使用 `source venv/bin/activate`(解决 Ubuntu PEP 668 externally-managed-environment) #### c) SSH 密钥配置 - 使用已有的 `id_ed25519_ci_deploy` 密钥(原为 Woodpecker 准备) - 公钥已添加到宿主机的 `~/.ssh/authorized_keys` - 私钥存放在 Gitea 容器内 `/data/git/.ssh/id_ed25519` - 容器内 `git` 用户可读 ### 工作流程 ``` 开发者 push → Gitea 接收 → post-receive hook 触发 → post-receive.d/deploy 执行 → SSH 到宿主机(172.17.0.1) → cd /root/cma-management → git pull origin main → bash deploy.sh → [1/4] pnpm build(前端构建) → [2/4] cp dist/* /var/www/cma/(前端部署) → [3/4] pip install(后端依赖更新) → [4/4] systemctl restart cma-backend(后端重启) ← 部署完成 ✓ ← SSH 返回 ← push 完成 ``` ### 验证结果 已通过实际 push 验证(3次自动部署均成功): - 前端构建耗时: ~8-9秒 - 前端部署: ~1秒 - 后端依赖更新: ~1秒 - 后端服务重启: ~2秒 - **总计: ~12-15秒完成全流程部署** --- ## 5. 后续建议 ### Woodpecker CI 保留(可选) - **不要删除** Woodpecker 容器,上游修复后可以重新启用 - 未来如果需要多环境部署、并行测试等高级功能,Woodpecker 仍是更好的选择 - 当前版本(v3.12.0 + Gitea 1.22)存在兼容性问题,升级 Gitea 或 Woodpecker 任一版本可能修复 ### 扩展考虑 - 如果需要部署失败通知,可以在 hook 中添加企业微信/钉钉 webhook - 如果需要增量构建,可以在 hook 中检测改动的文件路径(仅构建有改动的部分) - 如果需要回滚,hook 可以保留上次构建的备份 --- ## 6. 文件变更清单 | 文件 | 操作 | 说明 | |------|------|------| | `hooks/post-receive.d/deploy` | **新建** | Gitea 自动部署 hook | | `/root/cma-management/deploy.sh` | **修改** | 移除 `--no-frozen-lockfile`,使用 venv pip | | `/root/cma-management/scripts/post-receive-hook.sh` | **新建** | Hook 脚本的版本控制副本 | | `/root/cma-management/docs/ci-comparison-report.md` | **新建** | 本报告 |