feat: Gitea 自动代码审查服务
基于 OpenCodeReview 的 webhook 服务:监听 Gitea 的 push 与 Pull Request 事件, 调用 OCR 审查 diff,把结果发布回 Gitea,并按阻断阈值决定是否自动合并。 主要能力: - Push / PR 事件触发,支持分支 glob 过滤与 PR-only / push-only 范围 - PR 内联评论(按 diff 行号定位)、汇总评论、Issue 生命周期、提交状态 - 可配置阻断阈值(严重级别 / 类别 / 任意意见) - 无阻断问题时自动合并,审查覆盖不完整时拒绝合并 - 内置 Web 后台:仓库配置、任务日志、失败重跑、连通性自检 - SQLite 持久化,worker 重启回收卡死任务,失败自动重试 实现为独立服务而非 Gitea Action:本机 act_runner 指向的实例不可达, 且后台配置与任务历史需要独立进程承载。
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Gitea 代码审查</title>
|
||||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ctext y='14' font-size='14'%3E%F0%9F%94%8D%3C/text%3E%3C/svg%3E" />
|
||||
<link rel="stylesheet" href="/style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Gitea 代码审查</h1>
|
||||
<div class="right"><div class="status" id="status">加载中…</div><button class="linkish hidden" id="sign-out">清除访问 Token</button></div>
|
||||
</header>
|
||||
|
||||
<nav>
|
||||
<button class="tab active" data-tab="repos">仓库</button>
|
||||
<button class="tab" data-tab="jobs">任务</button>
|
||||
<button class="tab" data-tab="settings">设置</button>
|
||||
</nav>
|
||||
|
||||
<main>
|
||||
<div id="banner" class="banner hidden"></div>
|
||||
|
||||
<section id="tab-repos" class="panel active">
|
||||
<div class="row">
|
||||
<h2>已配置仓库</h2>
|
||||
<button id="add-repo">新增仓库</button>
|
||||
</div>
|
||||
<table id="repos-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>仓库</th><th>分支过滤</th><th>范围</th><th>启用</th>
|
||||
<th>自动合并</th><th>阻断级别</th><th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section id="tab-jobs" class="panel">
|
||||
<div class="row">
|
||||
<h2>审查任务</h2>
|
||||
<button id="refresh-jobs">刷新</button>
|
||||
</div>
|
||||
<table id="jobs-table">
|
||||
<thead>
|
||||
<tr><th>#</th><th>仓库</th><th>分支</th><th>提交</th><th>状态</th>
|
||||
<th>意见</th><th>阻断</th><th>合并</th><th>开始</th><th></th></tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
<pre id="job-log" class="log hidden"></pre>
|
||||
</section>
|
||||
|
||||
<section id="tab-settings" class="panel">
|
||||
<h2>全局设置</h2>
|
||||
<form id="settings-form">
|
||||
<fieldset>
|
||||
<legend>Gitea</legend>
|
||||
<label>API 地址 <input name="giteaUrl" placeholder="http://127.0.0.1:80" /></label>
|
||||
<label>管理员 Token <input name="giteaToken" type="password" placeholder="留空表示不修改" /></label>
|
||||
<label>Webhook 密钥 <input name="webhookSecret" type="password" placeholder="留空表示不修改" /></label>
|
||||
<label>后台访问 Token <input name="adminToken" type="password" placeholder="留空表示不修改" /></label>
|
||||
<p class="hint">Webhook 地址:<code id="hook-url"></code>(在仓库 Settings → Webhooks 中添加,密钥填上面这一项)</p>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>LLM</legend>
|
||||
<label>接口地址 <input name="llmUrl" placeholder="https://api.openai.com/v1" /></label>
|
||||
<label>API Key <input name="llmToken" type="password" placeholder="留空表示不修改" /></label>
|
||||
<label>模型 <input name="llmModel" placeholder="gpt-5.5" /></label>
|
||||
<label>协议 <input name="llmProtocol" placeholder="openai / anthropic" /></label>
|
||||
<label>自定义认证头 <input name="llmAuthHeader" placeholder="留空使用默认" /></label>
|
||||
<label>附加请求头 <input name="llmExtraHeaders" placeholder="K=V,K=V" /></label>
|
||||
<label>审查规则文件 <input name="rulePath" placeholder="/etc/gitea-codereview/rule.json" /></label>
|
||||
</fieldset>
|
||||
<div class="actions">
|
||||
<button type="submit">保存</button>
|
||||
<button type="button" id="test-gitea">测试 Gitea</button>
|
||||
<button type="button" id="test-llm">测试 LLM</button>
|
||||
</div>
|
||||
<pre id="settings-result" class="log hidden"></pre>
|
||||
</form>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<div id="token-gate" class="modal hidden">
|
||||
<div class="modal-body narrow">
|
||||
<h2>需要访问 Token</h2>
|
||||
<p class="hint">该服务设置了 <code>CR_ADMIN_TOKEN</code>,请输入后才能管理仓库与任务。</p>
|
||||
<form id="token-form">
|
||||
<label>访问 Token
|
||||
<input name="token" type="password" autocomplete="current-password" required />
|
||||
</label>
|
||||
<div class="actions">
|
||||
<button type="submit">进入</button>
|
||||
</div>
|
||||
<pre id="token-error" class="log hidden"></pre>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="manual-modal" class="modal hidden">
|
||||
<div class="modal-body narrow">
|
||||
<h2>立即审查</h2>
|
||||
<form id="manual-form">
|
||||
<input type="hidden" name="repo_id" />
|
||||
<p class="hint" id="manual-repo"></p>
|
||||
<label>分支 <input name="ref" placeholder="main" required /></label>
|
||||
<label>提交 SHA <input name="sha" placeholder="40 位 commit hash" required /></label>
|
||||
<label>基准分支 <input name="base_ref" placeholder="main" /></label>
|
||||
<label>关联 Pull Request 编号(可选) <input name="pr_number" type="number" min="1" /></label>
|
||||
<div class="actions">
|
||||
<button type="submit">加入队列</button>
|
||||
<button type="button" id="manual-close">取消</button>
|
||||
</div>
|
||||
<pre id="manual-result" class="log hidden"></pre>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal" class="modal hidden">
|
||||
<div class="modal-body">
|
||||
<h2 id="modal-title">仓库配置</h2>
|
||||
<form id="repo-form">
|
||||
<input type="hidden" name="id" />
|
||||
<div class="grid">
|
||||
<label>所有者 <input name="owner" required /></label>
|
||||
<label>仓库名 <input name="name" required /></label>
|
||||
<label>目标分支 <input name="base_branch" placeholder="main" /></label>
|
||||
<label>监听分支模式 <input name="branch_patterns" placeholder="*, release/*" /></label>
|
||||
<label>审查范围
|
||||
<select name="review_scope">
|
||||
<option value="both">Push 与 PR 都审查</option>
|
||||
<option value="pr">仅 Pull Request</option>
|
||||
<option value="push">仅分支 Push</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>发布方式
|
||||
<select name="publish_mode">
|
||||
<option value="inline">PR 内联评论</option>
|
||||
<option value="issue-only">仅 Issue</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>阻断级别 <input name="block_severity" placeholder="critical,high" /></label>
|
||||
<label>阻断类别 <input name="block_categories" placeholder="security" /></label>
|
||||
<label>Issue 标签 <input name="issue_labels" placeholder="code-review" /></label>
|
||||
<label>最大意见数 <input name="max_comments" type="number" min="1" max="200" /></label>
|
||||
<label>并发数 <input name="concurrency" type="number" min="1" max="16" /></label>
|
||||
<label>排除路径 <input name="excludes" placeholder="**/dist/**,**/*.lock" /></label>
|
||||
<label>仓库专用 Gitea Token <input name="gitea_token" type="password" placeholder="留空使用全局" /></label>
|
||||
<label>仓库专用 LLM Key <input name="llm_token" type="password" placeholder="留空使用全局" /></label>
|
||||
<label>LLM 模型 <input name="llm_model" placeholder="留空使用全局" /></label>
|
||||
<label>审查背景 <input name="background_template" placeholder="补充业务上下文" /></label>
|
||||
</div>
|
||||
<div class="checks">
|
||||
<label><input type="checkbox" name="enabled" /> 启用</label>
|
||||
<label><input type="checkbox" name="create_issue" /> 发现问题时创建 Issue</label>
|
||||
<label><input type="checkbox" name="auto_merge" /> 无阻断问题时自动合并</label>
|
||||
<label><input type="checkbox" name="delete_branch" /> 合并后删除分支</label>
|
||||
<label><input type="checkbox" name="fail_on_findings" /> 有意见即判定失败</label>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<label>自动合并方式
|
||||
<select name="auto_merge_mode">
|
||||
<option value="when_checks_succeed">等待检查通过后合并</option>
|
||||
<option value="immediate">立即合并</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>合并方式
|
||||
<select name="merge_method">
|
||||
<option value="squash">squash</option>
|
||||
<option value="merge">merge</option>
|
||||
<option value="rebase">rebase</option>
|
||||
<option value="rebase-merge">rebase-merge</option>
|
||||
<option value="fast-forward-only">fast-forward-only</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button type="submit">保存</button>
|
||||
<button type="button" id="discover">测试连接</button>
|
||||
<button type="button" id="modal-close">取消</button>
|
||||
</div>
|
||||
<pre id="repo-result" class="log hidden"></pre>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user