feat(review 發布): 將 AI 審查結果集中到同一筆 Pull Review
This commit is contained in:
+65
-1
@@ -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 使用。
|
||||
|
||||
Reference in New Issue
Block a user