三个导致「提交了新 PR 但没有任何反应」的独立问题: 1. 从不创建 Webhook 服务只被动接收事件,但配置仓库时不会去 Gitea 里建 Webhook, 结果仓库永远收不到 push / PR 事件,看起来和坏掉一样。 - 保存仓库时自动创建或更新 Webhook(POST /repos 返回值带 webhook 结果) - 新增 GET/POST /api/repos/:id/webhook 查询与修复 - 仓库列表新增 Webhook 列,未配置可一键「修复 Webhook」 - 新增 CR_WEBHOOK_URL,留空则推导为「Gitea 主机名 + 本服务端口」 2. 审查范围用了错的分支做基准 resolveRange 优先取 managed_branch 而不是 job.base_ref, 于是 PR 被拿去和一个无关分支比较;当两者内容相同就报 「base and head resolve to the same commit」直接跳过。 改为优先用该改动实际要合入的分支(PR 的目标分支), 仅 push 事件回退到 managed_branch。 3. 检查分支的匹配语义反了 原先要求 PR 的 head(功能分支)出现在 check_branches 里, 而用户配置的是「要保护的目标分支」(如 prd/test), 功能分支永远不会被列出,所以 PR 一律被过滤掉。 新增 pullRequestMatches:PR 的 base 命中检查分支即审查, head 命中仍保留支持。这样「审查所有合入 prd/test 的改动」成立。 验证:PR offerpai/offerpai_h5#2 重跑通过,7 条内联评论、 2 条阻断、commit status failure、Issue #3 创建。
282 lines
12 KiB
HTML
282 lines
12 KiB
HTML
<!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="records">审查历史</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>
|
|
<div class="actions">
|
|
<button id="import-repo">从 Gitea 导入</button>
|
|
<button class="primary" id="add-repo">新增仓库</button>
|
|
</div>
|
|
</div>
|
|
<table id="repos-table">
|
|
<thead>
|
|
<tr>
|
|
<th>仓库</th><th>管理分支</th><th>检查分支</th><th>范围</th>
|
|
<th>Webhook</th><th>启用</th><th>自动合并</th><th>阻断级别</th><th></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="tab-records" class="panel">
|
|
<div class="row">
|
|
<h2>审查历史摘要</h2>
|
|
<div class="actions">
|
|
<select id="record-filter"><option value="">全部仓库</option></select>
|
|
<button id="refresh-records">刷新</button>
|
|
</div>
|
|
</div>
|
|
<div id="records-list" class="records"></div>
|
|
</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://192.168.31.51" /></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>
|
|
<label>Webhook 回调地址 <input name="webhookUrl" placeholder="留空自动推导为 <Gitea 主机>:<本服务端口>" /></label>
|
|
<p class="hint">保存仓库时会自动在 Gitea 里创建/更新 Webhook,地址用上面这一项,密钥用 Webhook 密钥。<code id="hook-url"></code></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.6-sol" /></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="import-modal" class="modal hidden">
|
|
<div class="modal-body">
|
|
<h2>从 Gitea 导入仓库</h2>
|
|
<p class="hint">使用全局 Token 拉取当前账号可见的仓库,点击即可创建监控配置。</p>
|
|
<input id="import-search" placeholder="按仓库名过滤…" />
|
|
<div id="import-list" class="import-list"></div>
|
|
<div class="actions">
|
|
<button type="button" id="import-close">关闭</button>
|
|
</div>
|
|
</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="管理分支" /></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="record-modal" class="modal hidden">
|
|
<div class="modal-body">
|
|
<h2 id="record-title">审查记录</h2>
|
|
<div id="record-body"></div>
|
|
<div class="actions">
|
|
<button type="button" id="record-resummarise">重新生成摘要</button>
|
|
<button type="button" id="record-close">关闭</button>
|
|
</div>
|
|
</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" />
|
|
<fieldset>
|
|
<legend>仓库</legend>
|
|
<label>Git 地址
|
|
<span class="inline">
|
|
<input name="repo_url" placeholder="http://192.168.31.51/kgod/myrepo.git" required />
|
|
<button type="button" id="repo-test">测试连接</button>
|
|
</span>
|
|
</label>
|
|
<p class="hint" id="repo-parsed"></p>
|
|
</fieldset>
|
|
|
|
<fieldset>
|
|
<legend>分支</legend>
|
|
<label>管理分支(合并目标)
|
|
<span class="inline">
|
|
<input name="managed_branch" placeholder="main" />
|
|
<button type="button" id="branch-create">克隆创建</button>
|
|
</span>
|
|
</label>
|
|
<p class="hint">所有检查通过后只合并到这一个分支;它也会出现在下面的检查分支里。</p>
|
|
<label>检查分支(可多选)
|
|
<span class="inline">
|
|
<input name="check_branches" placeholder="main,release/1.0" />
|
|
<button type="button" id="branch-reload">加载分支</button>
|
|
</span>
|
|
</label>
|
|
<div id="branch-list" class="branch-list"></div>
|
|
<p class="hint">填「被保护的目标分支」。任何合并进这些分支的 PR 都会审查(功能分支不用列出来);向这些分支推送也会审查。只有指向管理分支的 PR 才会自动合并。</p>
|
|
</fieldset>
|
|
|
|
<fieldset>
|
|
<legend>审查</legend>
|
|
<div class="grid">
|
|
<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>
|
|
</div>
|
|
<label>审查背景 / 需求
|
|
<textarea name="background_template" rows="6" placeholder="补充业务上下文、本次需求说明;会作为审查背景传给模型,并记录到审查历史。"></textarea>
|
|
</label>
|
|
</fieldset>
|
|
|
|
<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="modal-close">取消</button>
|
|
</div>
|
|
<pre id="repo-result" class="log hidden"></pre>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="clone-modal" class="modal hidden">
|
|
<div class="modal-body narrow">
|
|
<h2>创建管理分支</h2>
|
|
<form id="clone-form">
|
|
<label>新分支名 <input name="new_branch" placeholder="main" required /></label>
|
|
<label>从哪个分支复制
|
|
<select name="from_branch" id="clone-source"></select>
|
|
</label>
|
|
<div class="actions">
|
|
<button type="submit">创建</button>
|
|
<button type="button" id="clone-close">取消</button>
|
|
</div>
|
|
<pre id="clone-result" class="log hidden"></pre>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="/app.js"></script>
|
|
</body>
|
|
</html> |