feat(review 發布): 將 AI 審查結果集中到同一筆 Pull Review

This commit is contained in:
2026-06-22 09:41:09 +00:00
parent 1b3c5a7aec
commit 1477822f4b
3 changed files with 88 additions and 21 deletions
+65 -1
View File
@@ -1,6 +1,6 @@
import fs from 'fs';
import path from 'path';
import { postComment, postPullReviewComment } from './gitea.js';
import { createPullReview, postComment, postPullReviewComment } from './gitea.js';
import { FINDINGS_PATH } from './config.js';
import { ok, line, warn } from './log.js';
@@ -36,6 +36,70 @@ function inlineCommentBody(f) {
return `**等級**${levelText(f)}\n**審查員**${f.role}\n**建議**${f.suggestion}`;
}
function reviewSection(title, findings) {
if (findings.length === 0) return '';
return `${title}\n\n${buildTable(findings)}`;
}
function findingGroupLabel(f) {
if (!f.is_new) return '舊有未解決問題';
if (f.level === 'critical') return '新嚴重問題';
return '新發現問題';
}
export function buildReviewPayload(intro, findings, { forceBodyFindings = false } = {}) {
const inlineComments = [];
const bodyFindings = [];
for (const f of findings) {
const loc = forceBodyFindings ? null : parseLocation(f.location);
if (loc) {
inlineComments.push({
path: loc.file,
body: `**分類**${findingGroupLabel(f)}\n${inlineCommentBody(f)}`,
new_position: loc.line,
});
} else {
bodyFindings.push(f);
}
}
const bodyOld = bodyFindings.filter(f => !f.is_new);
const bodyNewNonCritical = bodyFindings.filter(f => f.is_new && f.level !== 'critical');
const bodyNewCritical = bodyFindings.filter(f => f.is_new && f.level === 'critical');
const sections = [
intro,
reviewSection(`## 📋 無法行內標註的舊有未解決問題(${bodyOld.length} 筆)`, bodyOld),
reviewSection(`## 🔍 無法行內標註的新發現問題(${bodyNewNonCritical.length} 筆)`, bodyNewNonCritical),
reviewSection(`## 🚨 無法行內標註的新嚴重問題(${bodyNewCritical.length} 筆)`, bodyNewCritical),
].filter(Boolean);
if (inlineComments.length > 0) {
sections.push(`## 💬 行內標註問題(${inlineComments.length} 筆)\n\n詳見本 review 底下的行內 comments。`);
}
return {
body: sections.join('\n\n'),
comments: inlineComments,
};
}
export async function postFindingsReview(intro, findings, deps = {}) {
const { postReview = createPullReview } = deps;
const payload = buildReviewPayload(intro, findings);
try {
await postReview(payload);
ok(`Review 發布成功 (body findings=${findings.length - payload.comments.length} inline=${payload.comments.length})`);
} catch (e) {
if (payload.comments.length === 0) throw e;
warn(`Review 行內 comment 批次發布失敗,改將所有問題放入同一筆 Review body: ${e.message}`);
const fallbackPayload = buildReviewPayload(intro, findings, { forceBodyFindings: true });
await postReview(fallbackPayload);
ok(`Review 發布成功 (body findings=${findings.length} inline=0)`);
}
}
/**
* 寫入 findings.json。
* 預設寫到 workspace;若提供 mirrorDir,則同步寫入另一份供 repo commit 使用。