# Gitee PR bot **Repository Path**: guoquan/gitee-pr-bot ## Basic Information - **Project Name**: Gitee PR bot - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-04-06 - **Last Updated**: 2026-04-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Gitee PR Bot 一个运行在 **Cloudflare Workers** 上的 Gitee PR 机器人,专为实验课 / 作业收集场景设计。 学生提交 Pull Request → Bot 自动校验规则 → 通过即自动合并,不通过则评论指出问题。 [![Deploy to Cloudflare Workers](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://gitee.com/guoquan/gitee-pr-bot) --- ## 功能 - 🔍 **自动校验** PR 是否符合提交规范(文件数量、README 登记、学号分区等) - ✅ **自动合并** 通过校验且无冲突的 PR(可开关) - 💬 **评论反馈** 校验不通过时生成 Markdown 表格,指出违反的规则和改进建议 - ⚡ **异步处理** 立即响应 Gitee webhook,重活放后台,避免超时 - 🛡️ **Webhook 鉴权** 通过 `X-Gitee-Token` 验证请求合法性 ## 校验规则 | 规则 | 说明 | |---|---| | R001 | PR 只能修改 `README.md` 和一个学号文件,不得包含其他文件 | | R002 | PR 必须修改 `README.md` | | R003 | PR 必须提交且只能提交一个学号文件(格式:`{8位以上学号}.md`) | | R004 | 能正常读取 HEAD README,并从 diff 补丁中提取到新增链接信息 | | R005 | 一次 PR 只能新增一个身份(不能一次注册多人) | | R006 | 不得重复新增同一学号链接 | | R007 | README 中登记的学号链接需与提交的学号文件一致 | | R008 | README 中的学号链接必须位于正确的尾号分区(如 `67` 号应在 `` `60`-`69` `` 区) | | R009 | PR 不得删除或修改 README 中已有内容,也不得新增非学号链接的内容 | | R010 | 学号文件内容必须包含该学号字符串 | ## 部署 ### 一、前置准备 1. **Cloudflare 账号**,已启用 Workers 2. **Gitee 访问令牌**(`GITEE_TOKEN`):在 [Gitee 个人设置 → 私人令牌](https://gitee.com/profile/personal_access_tokens) 中创建,需要 `pull_requests` 和 `projects` 权限 ### 二、一键部署 点击上方 **Deploy to Cloudflare Workers** 按钮,按提示 fork 并部署。 ### 三、手动部署 **1. 克隆并安装依赖** ```bash git clone https://gitee.com/guoquan/gitee-pr-bot cd gitee-pr-bot npm install ``` **2. 修改 `wrangler.jsonc`**,填入你的仓库信息: ```jsonc "vars": { "GITEE_OWNER": "你的Gitee用户名", "GITEE_REPO": "目标仓库名", "AUTO_MERGE": "false" // 调试完成后改为 "true" 开启自动合并 } ``` **3. 部署到 Cloudflare** ```bash npm run deploy # 部署成功后会输出 Worker 的访问地址,记下备用 ``` > **推荐部署工作流(软测试)** > > `wrangler.jsonc` 中的 `AUTO_MERGE` 默认保持 `"false"`,每次 `npm run deploy` 都以只评论不合并的模式上线,方便验证新版本行为。 > 确认 bot 评论正确后,手动在 **Cloudflare Dashboard → Workers → gitee-pr-bot → Settings → Variables** 中将 `AUTO_MERGE` 改为 `"true"` 开启自动合并,无需重新部署。 > > ⚠️ 注意:再次 `npm run deploy` 会将 Dashboard 中的值重置为 `"false"`,需重新手动开启。 **4. 在 Gitee 仓库配置 Webhook**(见下方第五节) 自己想一个随机密码字符串(如 `my-secret-abc123`),在 Gitee 页面填入,然后再用同一个字符串设置 Worker Secret: **5. 设置 Cloudflare Worker Secrets**(敏感信息通过此命令上传,不写入代码) ```bash # Gitee 个人访问令牌(在 Gitee → 设置 → 私人令牌 中创建) npx wrangler secret put GITEE_TOKEN # 与第四步在 Gitee Webhook 填写的"密码"保持一致 npx wrangler secret put GITEE_WEBHOOK_SECRET ``` ### 四、环境变量 | 变量 | 类型 | 说明 | |---|---|---| | `GITEE_OWNER` | var | 目标仓库的用户名/组织名,写在 `wrangler.jsonc` | | `GITEE_REPO` | var | 目标仓库名,写在 `wrangler.jsonc` | | `AUTO_MERGE` | var | `"true"` 开启自动合并,`"false"` 只评论不合并(默认) | | `GITEE_TOKEN` | secret | Gitee 个人访问令牌,通过 `wrangler secret put` 设置,不写入代码 | | `GITEE_WEBHOOK_SECRET` | secret | 你自己设定的 Webhook 密码,两端必须一致,通过 `wrangler secret put` 设置 | ### 五、配置 Gitee Webhook 进入 `https://gitee.com///hooks`,点击"添加 WebHook": | 字段 | 填写内容 | |---|---| | URL | 第三步部署后得到的 Worker 地址 | | 密码 | 自己设定的随机字符串(与 `GITEE_WEBHOOK_SECRET` 保持一致) | | 触发事件 | 勾选 **Pull Request** | | 激活 | ✅ | > 保存后点"测试"按钮,Bot 应返回 `{ "ok": true, "message": "webhook reachable", "event": "...", "prNumber": 1 }`,表示连通且鉴权通过。 ## 本地开发 ```bash npm install npm run dev # 本地开发服务器(wrangler dev) npm test # 运行测试 npm run deploy # 部署到 Cloudflare ``` 测试使用 `@cloudflare/vitest-pool-workers` 在真实 Workers 运行时中执行,覆盖: - Webhook 过滤逻辑(`action` / `action_desc` / `state` 早期忽略) - API 层忽略(已合并/关闭的 PR) - 各校验规则失败路径(R001、R002、R003、R007、R008;R004/R005/R006/R009/R010 由规则引擎集成覆盖) - 自动合并、dry-run、冲突阻塞等 happy path ## 自定义检查 / 扩展 框架采用**可插拔 Check 体系**,替换或新增检查只需修改 `src/presets/student-pr.ts`(或新建自己的 preset),然后在 `src/index.ts` 中引用。 ### Check 接口 ```typescript // src/types.ts type Check = { id: string; name: string; when?: (ctx: Ctx) => boolean; // 快速跳过门禁 run: (ctx: Ctx) => CheckResult[] | Promise; }; ``` `run` 支持 async,可在内部进行任意 HTTP 调用(外部 linter、CI 系统、数据库等): ```typescript const lintCheck: Check = { id: 'LINT', name: 'Run external linter', run: async (ctx) => { const res = await fetch('https://my-lint-service/check', { method: 'POST', body: JSON.stringify({ files: ctx.changedFiles }), }); const issues = await res.json() as Array<{ message: string; suggestion: string }>; return issues.map((i) => ({ ruleId: 'LINT', ruleName: 'Lint', ...i, })); }, }; ``` ### 上下文扩展 在 `BotConfig.buildContext` 中预取所有检查共用的数据,避免重复请求: ```typescript const myConfig: BotConfig = { checks: [myCheck1, myCheck2], buildContext: async (base) => ({ lintResult: await fetchLintResult(base.changedFiles), }), }; ``` --- ## 项目结构 ``` src/ index.ts # Worker 入口(thin) types.ts # 核心类型:Check, CheckResult, BotConfig, PrContext engine.ts # 通用 check 引擎:runChecks, buildContext, dedupeResults gitee/ api.ts # Gitee REST 客户端 webhook.ts # Webhook 解析与过滤 render.ts # Markdown 评论模板 checks/ files.ts # R001-R003:文件级检查 readme.ts # R004-R009:README diff 检查 + 工具函数 content.ts # R010:文件内容检查 presets/ student-pr.ts # 预置学生 PR 配置(开箱即用) test/ index.spec.ts # 单元/集成测试(webhook 层) e2e.spec.ts # 端到端测试(mock Gitee API) docs/ webhook-events.md # Gitee Webhook 事件字段完整参考 _bmad-output/ project-context.md # AI Agent 项目上下文 wrangler.jsonc # Cloudflare Workers 配置 ``` ## ROADMAP ### ✅ 已完成 - [x] Webhook 鉴权(`X-Gitee-Token` 比对) - [x] 异步处理(`ctx.waitUntil`),立即响应防超时 - [x] 事件过滤(`action` / `action_desc` / `state` 三层过滤) - [x] PR 校验规则 R001–R010(文件数量、README 登记、学号分区、内容保护、学号文件内容等) - [x] 校验失败时发 Markdown 表格评论,附 blob 行号链接 - [x] 可配置自动合并(`AUTO_MERGE` 开关) - [x] 端到端测试覆盖(webhook 过滤 + 规则失败 + 合并路径) - [x] **通用化重构**:可插拔 Check 体系,支持自定义检查和 async 外部工具调用;规则拆分到独立模块;`presets/student-pr.ts` 保留原有功能 ### 🔧 近期可做(稳定性 / 体验) - [ ] **幂等去重**:接入 Cloudflare KV,以 `{prNumber}:{headSha}` 为 key 避免重复评论。目前通过 action+state 过滤已大幅降低概率,但平台重复投递时仍可能触发 - [ ] **草稿 PR 跳过**:将 `cancel_draft` 加入 `allowedActions`,同时在 API 返回结果中检查 `draft` 字段,支持"取消草稿即触发校验"语义 - [ ] **评论去重更新**:校验失败时先查找已有 Bot 评论,有则更新而非新增,保持评论区整洁 - [ ] **README 规则增强**:检测姓名重复、链接格式异常、学号位数不足等更细粒度的错误 ### 🚀 中期扩展(功能增强) - [ ] **Peer review 门禁**:利用 `action=assign` 事件,指派审核员后等待通过再合并;`pull_request.reviewers` 字段已在 payload 中 - [ ] **CI 联动**:利用 `action=test` 事件,触发外部测试流水线,测试通过后再合并;`pull_request.testers` 字段已在 payload 中 - [ ] **Inline review comment**:目前是普通 PR 评论(表格形式)。若 Gitee 开放 review comment API,可升级为逐行 diff 评论,体验更接近 GitHub Code Review - [ ] **行号精确化**:当前 blob 链接用 README 文本行号,与 PR diff 行号不一致;需 diff 解析或 review comment API 才能真正对应到 diff 视图 ### 🌐 长期方向(通用化) - [ ] **多仓库支持**:当前 `GITEE_OWNER` / `GITEE_REPO` 写死一个仓库;可改为从 webhook payload 的 `repository.full_name` 动态路由,配合 KV 存储每个仓库的独立规则配置 - [ ] **规则配置化**:将 `POLICY` 从代码中抽离到 KV / R2,支持在不重新部署的情况下调整规则(如完成列表标题、学号格式) - [ ] **移植其他平台**:Worker 核心逻辑与 Gitee 解耦后,可适配 GitHub / GitLab webhook,复用同一套规则引擎 ## License MIT