dev-manager-tauri/.blueprint/modules/gitea-integration.md

252 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Gitea 集成
对接已有的自建 Gitea 实例,作为所有被管理项目的统一 git 后端。接入包「增配档」的核心。
## 风筝线模型(炼境与 Gitea 的关系)
🪁 **风筝 = Gitea 本体**git 存储 + CI 执行):独立部署、独立运行,炼境**不托管其进程、不背运维**。
🧵 **线 = 炼境的掌控**(控制面):炼境是**唯一持线人**——Gitea 连接/token 统一存炼境,建仓/关联/迁移/配置 lefthook&CI 的操控全经炼境,子项目对 Gitea 的动作都从它手里过。
👀 **关注风筝的动态 = 观测面**(飞轮燃料):炼境持续感知每个子项目 ↔ Gitea 的连接动态push 的 commit type/scope、PR、CI 三阶段、review、停滞项目
> 「线」≠ 松散 API 对接:炼境是**主动掌控者**而非被动客户端。风筝越多 → 线越多 → 动态越丰富 → 飞轮越强(契合核心愿景)。
## 其他边界
- 替代炼境现有 GitHub 能力:`github-auth` / `github-publish` 已退役2026-07-02见 github-decommission`cicd.rs` 的 GitHub Actions 生成改造为 Gitea Actions
- 炼境自身仓库也迁 Gitea发布产物仍走 OSS updater 不变)
- **不使用 Gitea Issues / Projects / Milestones / Wiki**任务跟踪的意图层acceptance/complexity/depends/复盘)由蓝图任务卡承载,与 Claude 工作流深度耦合Gitea 只做三件事——存代码、跑 CI、发事件。蓝图与 Gitea 的唯一耦合关节 = conventional commit scope ↔ 蓝图 module id 映射(单点、单向、可降级)
## 参考实现
`enterprise-system` 已趟通完整链路,属「照搬」而非「从零探索」:
- Gitea origin`git.yljt.info`+ Gitee 镜像(备份)
- lefthook 强制 conventional commit + typecheckpre-commit
- Gitea Actions 三阶段 CI静态检查 → 测试DeepSeek-V3 自修)→ PR code reviewDeepSeek
- Gitea Actions 语法兼容 GitHub Actions迁移成本低
> 详见 `E:/code-project/enterprise-system/docs/ai-context/git-workflow.md` 与 `AGENTS.md`。
## 架构设计2026-06-30 /architect
### 实现策略
**webhook 接收端**:扩展已有 MCP ServerAxum端口 27190添加 `POST /webhook/gitea/:project_id` 路由。零新依赖,复用端口和进程。
**HTTP 客户端**`ureq`Cargo.toml 已有github.rs 已有使用范例),调 Gitea API v1。
**数据表**:新增 `gitea_instances`(实例管理)+ `gitea_repos`(项目-仓库绑定)。
```sql
CREATE TABLE IF NOT EXISTS gitea_instances (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
url TEXT NOT NULL, -- https://gitea.myserver.com
access_token TEXT NOT NULL,
is_default INTEGER NOT NULL DEFAULT 0,
created_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS gitea_repos (
id TEXT PRIMARY KEY,
instance_id TEXT NOT NULL REFERENCES gitea_instances(id) ON DELETE CASCADE,
project_id TEXT NOT NULL, -- blueprint_buffs.project_idUUID
gitea_owner TEXT NOT NULL,
gitea_repo_name TEXT NOT NULL,
clone_url TEXT,
webhook_secret TEXT, -- HMAC-SHA256 secret
webhook_id INTEGER, -- Gitea 返回的 hook ID
linked_at TEXT DEFAULT (datetime('now'))
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_gitea_repos_project ON gitea_repos(project_id);
```
**webhook 流程**
```
Gitea push → POST /webhook/gitea/:project_id
1. 从 gitea_repos 查 webhook_secret
2. HMAC-SHA256 验签 X-Gitea-Signature兼容 X-Hub-Signature-256
3. 解析 payload.commits[]sha / message / timestamp
4. 批量 record_commit(project_id, sha, message, date)
5. 返回 200 OK验签失败记 log_event
```
> 修正2026-07-02R10原设计写的签名头 `X-Gitea-Signature-256` 有误Gitea 实际发送
> `X-Gitea-Signature`payload 的 HMAC-SHA256 hex实现以实际行为为准并兼容 GitHub 风格头。
> project_id 采用与 commit_metrics/ingest_full_git_history 相同的 Project.idgetProjects 体系),
> 避免重蹈 project_id 双路径冲突b13dc83 教训)。
**网络说明**Gitea 服务器需能访问宿主机 `{ip}:27190`MCP 端口。UI 显示可复制的 webhook 回调地址,用户自行确认网络可达。
---
## 任务卡concept待 /architect
### 💭 Gitea API 对接(握线基础)
- status: concept
- complexity: L
- acceptance: TBD —— 建仓/关联、推送、读 CI 状态、读 PR review 结果
> ⚠️ 建仓/关联部分已被 G1/G2 实现取代;剩余范围收窄为「读 CI 状态、读 PR review 结果」(依赖 Gitea Actions 落地后再议)。
### 💭 观测面Gitea webhook 接入(持线人感知动态)
- status: concept
- complexity: L
- files: src-tauri/src/mcp_server.rs内嵌 HTTP server 加 webhook 端点), src-tauri/src/commands/blueprint.rs
- acceptance: TBD —— 复用炼境内嵌 HTTP server 新增 Gitea webhook 接收端点;实时接住各子项目 push/PR/CI/review 事件 → 解析 conventional commit对接 flywheel-intelligence 的 L0 解析层)→ 写飞轮快照 + 刷新连接动态webhook 不可达时降级为定时轮询 Gitea API
> ⚠️ push 事件部分已被 G3/G4 实现取代剩余范围收窄为「PR/CI/review 事件 + 轮询降级」见「PR 事件 ↔ 蓝图任务卡联动」concept 卡)。
### ✅ Gitea Actions workflow 生成
- status: done
- complexity: M
- depends: G1
- files: src-tauri/src/commands/cicd.rs, src/components/dashboard/CicdModal.tsx
- acceptance: generate_workflow 产出 Gitea Actions 模板(.gitea/workflows/,语法兼容 GitHub Actions参考 enterprise-system 三阶段 CIweb_ssh 与 tauri_oss 两类配置均支持CicdModal 的 Secrets 提示文案改为 Gitea 路径Settings → Actions → Secrets生成后模板中不残留 github.com 引用
> 一石三鸟:炼境自身仓库迁 Gitea 有了工具CicdModal 残留 GitHub 模板的问题解决(见 github-decommission 复盘遗留②CI 事实流有了源头。
### 💭 DeepSeek CI review 集成(可选插件)
- status: concept
- complexity: L
- acceptance: TBD —— 静态检查 + 测试自修 + PR review作为复杂项目可选增配不进基线档
### ✅ R0. 炼境自身发版链路迁移(本机 act_runner + Gitea Actions
- status: done
- complexity: M
- depends: Gitea Actions workflow 生成
- files: .gitea/workflows/release.yml生成, .github/workflows/release.yml删除
- acceptance: 本机安装 act_runner 并注册到 git.yljt.infowindows 标签,出站长连接、无入站需求);用 CicdModal 为炼境生成 Gitea 版 release workflow 并按需微调;删除 .github/workflows/ 死配置push 一个测试 tag 走通「构建 → 签名 → OSS 上传 → latest.json」全链路客户端自动更新恢复供给
> 背景GitHub 退役后 tag 不再触发旧 CI自动更新断供——这是当前唯一的结构性不自洽。act_runner 主动出站拉任务,完美适配公网 Gitea + 内网本机拓扑Tauri Windows 构建本就需要 Windows 环境,本机即最合适的 runner。
### 💭 旧项目 GitHub → Gitea 迁移
- status: concept
- complexity: M
- acceptance: TBD —— remote 切换 + 推送,安全增量,不丢历史
### ✅ G7. 新建仓库后一键接线(本地 init + 首次 push
- status: done
- complexity: M
- depends: G2
- files: src/components/dashboard/GiteaPanel.tsx, src/lib/commands.ts
- acceptance: gitea_create_repo/gitea_link_repo 成功后,检测项目本地状态(复用 scan_local_git无 .git → 提供「一键接线」按钮执行 init + 首次 commit复用 git_init_and_commit+ 设 origingit_remote_setclone_url 已知)+ pushgit_push已有 git 但无 origin → 只做后两步;已有 origin → 不显示按钮;每步失败给出可读错误;接线完成后提示「日常 commit/push 归项目会话(接线/放风筝边界)」
### 💭 /ship 泛化 + 工作流档位分发
- status: concept
- notes: /ship 去 enterprise-system 硬编码(仓库路径从 git remote get-url origin 推导、分支模型可配置),进入增配档接入包成为可一键分发的能力;配套「基线档 push CI」workflow 模板master push → typecheck + cargo test/vitest远端强制测试补"测试烂在本地"的洞,产出 CI 状态数据即观测面首批 CI 燃料)。项目导师按画像提示升降档。
### 💭 PR 事件 ↔ 蓝图任务卡联动
- status: concept
- depends: G3
- notes: webhook 收到 PR 事件 → 解析 title 的 conventional scope → 匹配蓝图模块 → 对应任务卡置 🔵 in_progress加锁提示。铁律 R09绝不自动置 ✅,完成语义只能由 Claude/人工验收产生merge 事件仅在导师报告中生成"待验收提醒"。不使用 Gitea Issues/Projects 做任务系统(见决策记录)。
---
## 任务卡(可执行,拆自 2026-06-30 /architect
### ✅ G1. DB schema + Gitea 实例 CRUD
- status: done
- complexity: M
- files: src-tauri/src/db.rs, src-tauri/src/commands/gitea.rs, src-tauri/src/lib.rs, src/lib/commands.ts
- acceptance: gitea_instances + gitea_repos 表建好migratesave/list/delete/test_connection 命令可调test_connection 调 GET /api/v1/user 返回 Gitea 用户名验证 token 有效性
### ✅ G2. 仓库创建 / 迁移 / 绑定
- status: done
- complexity: M
- depends: G1
- files: src-tauri/src/commands/gitea.rs, src/lib/commands.ts
- acceptance: gitea_create_repo 调 Gitea API 建仓后写 gitea_reposgitea_migrate_repo 能从 GitHub/GitLab 迁移仓库到 Giteagitea_link_repo 绑定已有仓库;命令失败返回可读错误
### ✅ G3. Webhook 接收端MCP Server 扩展)
- status: done
- complexity: M
- depends: G1
- files: src-tauri/src/mcp_server.rs
- acceptance: POST /webhook/gitea/:project_id 路由上线HMAC-SHA256 验签通过后解析 commits 数组批量写 commit_metrics验签失败记 log_event单元测试覆盖 parse_push_payload + hmac_verify
### ✅ G4. Webhook 注册命令
- status: done
- complexity: M
- depends: G2, G3
- files: src-tauri/src/commands/gitea.rs, src/lib/commands.ts
- acceptance: gitea_setup_webhook 生成随机 secret调 Gitea API POST /repos/:owner/:repo/hooks 注册events=push写 webhook_secret + webhook_id 到 gitea_reposgitea_unlink_repo 清理绑定
### ✅ G6. 远端轮询采集webhook 不可达时的降级路径)
- status: done
- complexity: M
- depends: G2
- files: src-tauri/src/commands/gitea.rs, src-tauri/src/lib.rs, src/lib/commands.ts, src/components/dashboard/GiteaPanel.tsx
- acceptance: 后台常驻线程每 10 分钟对所有 gitea_repos 绑定仓库调 GET /api/v1/repos/:owner/:repo/commits 拉取最新 commitrecord_commit 幂等写入gitea_poll_now 命令供 UI 手动触发并返回摘要;解析函数有单元测试;轮询结果记 log_event适配「公网 Gitea + 内网炼境」拓扑(纯出站,无需 webhook 可达)
> 背景:用户实际拓扑为公网云 Gitea + 内网本机炼境webhook 入站不可达;且不宜 frp 全端口映射 27190MCP 路由无鉴权)。轮询是该拓扑下唯一安全的远端采集方式。
### ✅ G5. Gitea 治理面板 UI
- status: done
- complexity: M
- depends: G1, G2, G3, G4
- files: src/components/dashboard/GiteaPanel.tsx, src/components/dashboard/BlueprintModal.tsx
- acceptance: 治理面板新增"Gitea"区块;可添加/测试/删除实例;显示已绑定仓库列表(仓库名/webhook 状态);操作:新建仓库、迁移、绑定已有、设置 webhook显示可复制的 webhook 回调地址
## 决策记录
- **公网 Gitea + 内网炼境为标准拓扑2026-07-02 裁决)**:观测面以 G6 出站轮询为主(每 10 分钟webhook 仅作同网/有穿透场景的补充。理由:① 炼境 27190 端口MCP 路由无鉴权)保持零公网暴露;② 飞轮是统计系统非监控系统10 分钟延迟在天/周分析粒度下为零影响;③ /ship 在 enterprise-system 已实证全出站 API 可支撑完整 PR 流水线;④ 主动拉取更贴合风筝线"持线人"定位。若未来需秒级实时:云服务器 nginx 仅反代 /webhook/gitea/ 路径 + 内网穿透(备案,不建议)
- 不用 frp 直接映射 27190MCP Server 工具路由无鉴权,全端口暴露 = append_project_note 等工具裸奔公网
- **建仓边界·接线/放风筝2026-07-03 裁决)**:炼境管"接线"=一次性 git 基建(建远端仓库/迁移/绑定/webhook + 本地 init/首次 commit/设 origin/首次 push——机械、零意图判断子项目 AI 会话管"放风筝"=日常内容生产commit/push/分支/PR/蓝图内容——每步带意图)。判据:不需要理解项目内容的 git 操作归炼境,需要理解的归项目会话。原 GitHub PublishModal 本就覆盖全链路Gitea 版只重建了远端一半,本地接线断档由 G7 补
- **工作流两档制2026-07-02 裁决)**/ship 完整 PR 流水线是"稳定剂"元素,有明确 scope事故成本高对外交付/生产系统)与 boundary探索期高频迭代项目PR 税会腰斩节奏——炼境自身单日 20+ commit 实证)。炼境不统一推广任何工作流,按项目画像分档:基线档=直推+lefthook+本地测试+push CI增配档=/ship 全流水线enterprise-system 为活样板)。升降档判据交给飞轮数据(返工率/CI 拦截率/review 有效率),工作流选择本身进入置信度体系。炼境自身升档时机:稳定使用期 或 飞轮阶段三需要 PR/review 数据
## 复盘笔记
【复盘】G7 一键接线 + autoforphone 首个 UI 全流程接入2026-07-03
任务类型: 前端组件 + 实战接入
复杂度: M
实际轮数: 3轮预估 1 轮)
是否返工: 是
返工原因: ① 建仓 403——token 缺 write:user scopePOST /user/repos 归 user 类,权限指导遗漏);② 改 Token 静默失效——giteaUpdateInstance 前端传 snake_case 参数被 Tauri camelCase 匹配丢弃(潜伏自 G1 的未使用封装);③ 首推 980MB 断连——lib/ 下 6 个 AutoJS6 APK + 源码归档被收进首次 commit超反代请求体限制
有效策略: "没有最近活动"Gitea token 页)证明请求未到达 → 直指本地存储问题git ls-tree -l 按体积排序秒定大文件元凶;远端为空时 amend 首次 commit 即可,无历史包袱
遗留改进G7 检测盲区): ① origin 已配置但远端为空/首推未成功的中间态不触发接线引导(本次因手动 remote add 提前存在而按钮未现);② 接线前无大文件预检(>50MB 警告),撞上 APK 类产物会断连——两项待下轮迭代
auto_applied_rules: R08, R10
rule_effectiveness: R08=有效(两处"UI 报成功实际没发生"均按此定性), R10=有效scope 归类以 403 实测为准)
【复盘】R0 发版链路迁移 + 换钥2026-07-02
任务类型: 基础设施 + 架构调整
复杂度: M实际含排障接近 L
实际轮数: 4轮预估 1 轮——3 次构建失败排障 + 1 次换钥
是否返工: 是
返工原因: ① 签名密钥密码丢失(唯一存储在不可读的 GitHub Secrets + 用户记忆),构建反复死于 Wrong password本机全部留痕渠道shell 历史/AI 会话/文档 git 历史/密钥库搜索无果最终按单人场景换钥手动装一次新版的代价≈0② act_runner 排障三连:生成的 config.yaml 默认 docker labels 导致 daemon 拒启(须 docker_host: "-" + labels windows:host、迁移仓库默认关闭 Actions 单元API PATCH has_actions 开启、Gitea 1.22 无 /actions/runs API改用 commit statuses API 监控)
有效策略: runner 在本机 = 失败日志本地可查trace 级日志直接定位 Wrong password 真凶);换钥前先验证「存量客户端规模」推翻了"换钥死锁"的默认假设
遗留风险: 无。全链路已验证tag push → 本机 runner 构建签名4m43s→ OSS latest.json 0.1.16 上线
auto_applied_rules: R10
rule_effectiveness: R10=有效Gitea 1.22 API 行为以实测为准,两处文档假设被纠正)
【教训·已固化】密钥类 secret 必须双写存储:新签名密码同时存于 Gitea Secrets + 炼境密钥凭据库。单一存储在"不可读的 secret 管理器 + 人脑"等于定时炸弹。
【复盘】G6 远端轮询采集2026-07-02
任务类型: 后端命令 + 前端组件
复杂度: M
实际轮数: 1轮预估 1 轮)
是否返工: 否
有效策略: 需求源自真实拓扑约束(用户确认公网 Gitea + 内网炼境),先做安全裁决(否决 frp 全端口映射)再写代码;解析函数纯函数化可测;复用 record_commit 幂等性使轮询与本地 watcher/全量导入三路径共存不重复计数
遗留风险: ① 轮询间隔 600s 硬编码仓库数大时50+)单轮串行请求可能拉长,届时可加并发或间隔配置;② limit=50 意味着 10 分钟内单仓库超 50 commit 会漏采(实际不可能,全量导入可兜底)
auto_applied_rules: R01, R07
rule_effectiveness: R01=有效gitea_poll_now 命令与 commands.ts 封装同步), R07=有效(解析纯函数 2 测试)
【复盘】Gitea Actions workflow 生成2026-07-02
任务类型: 后端命令 + 前端组件
复杂度: M
实际轮数: 1轮预估 1 轮)
是否返工: 否
有效策略: 语法兼容性使改造收敛为三处——输出目录 .gitea/workflows、去掉 GitHub Release 步骤(发布走 OSS 不需要 Release 页、runs-on 改自建 runner 标签;用单元测试断言"无 github.com/GITHUB_TOKEN 残留"把验收标准变成回归测试
遗留风险: ① tauri_oss 模板需要带 windows 标签的自建 act_runner尚未实际部署② actions/cachesetup-node 的 pnpm 缓存)依赖 act_runner 的 cache server旧版本 runner 可能不生效
auto_applied_rules: R01, R07
rule_effectiveness: R01=有效(命令未新增,仅改产出), R07=有效(模板残留断言测试)
【复盘】G2-G5 控制面 + 观测面全链路2026-07-02
任务类型: 后端命令 + MCP工具 + 前端组件
复杂度: M×4
实际轮数: 1轮预估 2 轮)
是否返工: 否
有效策略: 续接 🔵 锁前先读代码判断真实断点G1 已含查询命令G2 只缺三个写命令webhook 验签/解析拆成纯函数使单元测试不依赖 HTTP 层;绑定 UI 的 project_id 显式对齐 ingest_full_git_history 的 Project.id 体系
遗留风险: ① ~~全链路未在真实 Gitea 实例上端到端验证~~已消除2026-07-02 晚git.yljt.info 实测通过——实例连接 ✓ 迁移绑定 ✓ push ✓ 轮询采集 ✓webhook 因公网拓扑不适用,由 G6 轮询替代);② gitea_migrate_repo 未处理同名仓库已存在的场景Gitea 返回 409错误信息可读但需手动改名③ webhook 回调地址依赖用户确认网络可达,无自动探测
auto_applied_rules: R01, R05, R06, R07, R10
rule_effectiveness: R01=有效, R05=有效(复用已有表无新 migration, R06=有效upsert 依赖注入可测), R07=有效5 个新测试), R10=有效(纠正了设计文档中错误的签名头 X-Gitea-Signature-256 → 实际 X-Gitea-Signature