From 47aa199e5ec500fb99299cdaae14eb75fd568277 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Fri, 3 Jul 2026 13:34:49 +0800 Subject: [PATCH] =?UTF-8?q?feat(diff=20=E9=81=8E=E6=BF=BE):=20=E6=94=B9?= =?UTF-8?q?=E8=AE=80=20.reviewignore=20=E5=A4=96=E9=83=A8=E5=8C=96=20diff?= =?UTF-8?q?=20=E6=8E=92=E9=99=A4=E6=B8=85=E5=96=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .reviewignore | 13 +++++++++++++ src/gitea.js | 54 ++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 56 insertions(+), 11 deletions(-) create mode 100644 .reviewignore diff --git a/.reviewignore b/.reviewignore new file mode 100644 index 0000000..efeacc3 --- /dev/null +++ b/.reviewignore @@ -0,0 +1,13 @@ +# AI Code Review 忽略清單 +# 符合下列前綴/路徑的檔案不會納入送給 LLM 的 git diff。 +# 規則:每行一個路徑前綴(相對 repo 根),# 開頭為註解,空行略過。 +# 註:任何深度的 node_modules/ 一律排除(程式內建保險),此處列出僅為明示。 + +.gitea/ +.github/ +README.md +TODO.md +package-lock.json +src/package-lock.json +dist/ +node_modules/ diff --git a/src/gitea.js b/src/gitea.js index ea6db83..2786387 100644 --- a/src/gitea.js +++ b/src/gitea.js @@ -41,23 +41,55 @@ export function getBotReviewOutcome(message) { return match?.[1]?.toLowerCase() || 'unknown'; } +// 找不到 .reviewignore 時(例如其他 repo 未提供)採用的內建預設排除清單。 +// 任何深度的 node_modules/ 另由 filterDiff 內建強制排除,不倚賴此清單。 +export const DEFAULT_REVIEW_IGNORE = [ + '.gitea/', + '.github/', + 'README.md', + 'TODO.md', + 'package-lock.json', + 'src/package-lock.json', + 'dist/', +]; + /** - * 取得目前 PR 的完整 Git diff,並排除 CI/文件等不需審查的路徑(.gitea/、.github/、README.md、TODO.md)。 + * 解析 .reviewignore 文字為排除前綴陣列(gitignore 風格)。 + * 規則:每行一個路徑前綴,trim 後略過空行與 `#` 開頭的註解行。 + * @param {string} text - .reviewignore 檔案內容。 + * @returns {string[]} 排除前綴清單。 + */ +export function parseReviewIgnore(text) { + return String(text || '') + .split('\n') + .map(l => l.trim()) + .filter(l => l && !l.startsWith('#')); +} + +/** + * 從被審 PR 的 head ref 取得 `.reviewignore` 並解析為排除清單。 + * 檔案不存在或為空時退回 {@link DEFAULT_REVIEW_IGNORE}。 + * @returns {Promise} 套用於 diff 過濾的排除前綴清單。 + */ +export async function getReviewIgnore() { + const patterns = parseReviewIgnore(await getFileContentAtRef('.reviewignore')); + if (patterns.length > 0) { + line(`已套用 .reviewignore:${patterns.length} 條排除規則`); + return patterns; + } + return DEFAULT_REVIEW_IGNORE; +} + +/** + * 取得目前 PR 的完整 Git diff,並依 `.reviewignore`(讀不到時用內建預設)排除不需審查的路徑。 * 透過 Gitea `GET /repos/{repo}/pulls/{index}.diff`(純文字 diff),授權使用 GITEA_TOKEN。 * @returns {Promise} 過濾後的 diff 文字。 - * @throws {Error} 當 Gitea API 請求失敗(網路錯誤、逾時或非 2xx 狀態)時拋出 axios 例外。 + * @throws {Error} 當 Gitea 取 diff 的 API 請求失敗(網路錯誤、逾時或非 2xx 狀態)時拋出 axios 例外。 */ export async function getPRDiff() { + const patterns = await getReviewIgnore(); const resp = await axios.get(api(`/repos/${GITEA_REPOSITORY}/pulls/${PR_NUMBER}.diff`), { headers: headers(), timeout: 60000, httpsAgent }); - return filterDiff(resp.data, [ - '.gitea/', - '.github/', - 'README.md', - 'TODO.md', - 'package-lock.json', - 'src/package-lock.json', - 'dist/', - ]); + return filterDiff(resp.data, patterns); } /**