feat(ai-review 對話收斂): 讀 PR review 留言判斷解決狀態並收斂 findings
This commit is contained in:
@@ -153,3 +153,76 @@ export async function postPullReview({ body, comments = [] }) {
|
||||
);
|
||||
return resp.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得 PR 上所有的 review(每個 review 可含多個行內 comment)。
|
||||
*/
|
||||
export async function listPullReviews() {
|
||||
const resp = await axios.get(
|
||||
api(`/repos/${GITEA_REPOSITORY}/pulls/${PR_NUMBER}/reviews`),
|
||||
{ headers: headers(), timeout: 30000, httpsAgent },
|
||||
);
|
||||
return Array.isArray(resp.data) ? resp.data : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得單一 review 底下的所有行內 comment。
|
||||
*/
|
||||
export async function getPullReviewComments(reviewId) {
|
||||
const resp = await axios.get(
|
||||
api(`/repos/${GITEA_REPOSITORY}/pulls/${PR_NUMBER}/reviews/${reviewId}/comments`),
|
||||
{ headers: headers(), timeout: 30000, httpsAgent },
|
||||
);
|
||||
return Array.isArray(resp.data) ? resp.data : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得 PR 上所有 review 的行內 comment,展平成單一陣列。
|
||||
* 單一 review 取 comment 失敗時記錄警告並略過,不中斷整體流程。
|
||||
*/
|
||||
export async function listAllReviewComments() {
|
||||
const reviews = await listPullReviews();
|
||||
const all = [];
|
||||
for (const review of reviews) {
|
||||
if (!review?.id) continue;
|
||||
try {
|
||||
all.push(...await getPullReviewComments(review.id));
|
||||
} catch (e) {
|
||||
warn(`取得 review #${review.id} 的 comments 失敗(略過): ${e.message}`);
|
||||
}
|
||||
}
|
||||
line(`取得 PR review comments: reviews=${reviews.length} comments=${all.length}`);
|
||||
return all;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解決(resolve)一個 review comment 所屬的對話。
|
||||
* 對應 Gitea 官方 API:POST /repos/{repo}/pulls/comments/{id}/resolve。
|
||||
*/
|
||||
export async function resolvePullReviewComment(commentId) {
|
||||
const resp = await axios.post(
|
||||
api(`/repos/${GITEA_REPOSITORY}/pulls/comments/${commentId}/resolve`),
|
||||
{},
|
||||
{ headers: headers(GITEA_COMMENT_TOKEN || GITEA_TOKEN), timeout: 30000, httpsAgent },
|
||||
);
|
||||
return resp.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得指定 ref(預設 PR head)下某檔案的最新文字內容;
|
||||
* Gitea contents API 回傳 base64,這裡解碼成字串。檔案不存在或非文字時回傳空字串。
|
||||
*/
|
||||
export async function getFileContentAtRef(filePath, ref = PR_HEAD_SHA || PR_HEAD_BRANCH) {
|
||||
try {
|
||||
const resp = await axios.get(
|
||||
api(`/repos/${GITEA_REPOSITORY}/contents/${encodeURIComponent(filePath).replace(/%2F/g, '/')}`),
|
||||
{ headers: headers(), params: ref ? { ref } : undefined, timeout: 30000, httpsAgent },
|
||||
);
|
||||
const { content, encoding } = resp.data || {};
|
||||
if (typeof content !== 'string') return '';
|
||||
return encoding === 'base64' ? Buffer.from(content, 'base64').toString('utf8') : content;
|
||||
} catch (e) {
|
||||
warn(`取得檔案內容失敗(視為空): ${filePath}@${ref || 'head'} error=${e.message}`);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user