Files
git-codereview/app/static/index.html
T
kgod 6dc77ce907 feat: 仓库导入、分支模型重构与审查历史摘要
仓库接入
- 新增「从 Gitea 导入」:用全局 Token 列出可见仓库,一键建配置
- 新增仓库只填 Git 地址,自动解析 owner/name,支持 https/ssh/scp 写法
- 新增「测试连接」按钮,保存前即可校验地址并拉取分支

分支模型
- 由单一 base_branch + glob 改为「一个管理分支 + 多个检查分支」
- 管理分支是唯一合并目标;检查分支全部纳入监控
- 支持从任意分支克隆创建管理分支
- 审查基准改为管理分支的 merge-base;仅目标为管理分支的 PR 才自动合并
- 旧库自动迁移:base_branch 播种 managed_branch,branch_patterns 展开为检查分支

审查历史
- 新增 review_records 表与「审查历史」页
- 记录触发来源、PR 链接、审查范围、阻断阈值、发布方式、自动合并设置、
  排除路径、LLM 模型、token 消耗、耗时、需求背景与全部审查意见
- 详情弹窗一览,支持按仓库过滤

AI 摘要
- 新增独立摘要模块(app/lib/summary.js),与代码审查提示词分离
- 专用提示词输出固定四节、500 字内的中文记录:结论/范围/问题/要点
- 与代码审查共用全局 LLM 设置;摘要失败不影响审查与合并,可单条重跑

修复
- 摘要改用内置 fetch:运行镜像没有 curl,原先 spawn curl 必然 ENOENT
- 去掉 blob:none 部分克隆并把凭据写入 .git/config:
  惰性取 blob 不会带上 per-command extraHeader,私有库会报 could not read Username

UI
- 审查背景改为多行文本域(可滚动)
- 分支改为可点选列表,管理分支高亮
- 仓库表格展示管理分支与检查分支
2026-09-20 12:38:23 +08:00

281 lines
11 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>启用</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>
<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.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 才会自动合并。</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>