From 098d4aea97733b57dece135bd7d088d827cbc052 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Thu, 14 May 2026 01:53:44 +0000 Subject: [PATCH] feat: expand diff exclusions --- README.md | 2 +- TODO.md | 4 ++-- app/gitea.js | 8 ++++++-- app/gitea.test.js | 20 +++++++++++--------- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 92c1000..1c90171 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ 4. 盡量將應用程式放在 ./app,修改 entrypoint.sh 與 Dockerfile 讓程式可以正常運行 5. 將提示詞放到 ./app/prompts 內供程式讀取 6. API Key 支援逗號分隔傳入多個,隨機順序各嘗試一次,全部失敗則 exit 1 -7. 讀取 Git Diff 時排除 `.gitea/` 資料夾內的所有檔案,避免 AI 分析 workflow 設定等非業務程式碼 +7. 讀取 Git Diff 時排除 `.gitea/`、`.amazonq/`、`.claude/`、`.codex/`、`.gemini/`、`.github/` 資料夾,以及 `CLAUDE.md`、`GEMINI.md`、`TODO.md`、`README.md`,避免 AI 分析 workflow 設定、skill 入口與文件等非業務程式碼 8. 階段七驗證 `findings.json` 與 `exclusions.json` 是否為合法 JSON 格式,格式錯誤時先嘗試透過 AI 修正內容,再重新驗證;修正後仍不合法才 exit 1;之後才檢查檔案是否存在,不存在則建立並寫入 `[]` 9. 傳給 AI 的 findings 只保留必要欄位(level、role、location、suggestion),排除 `is_new` 等內部欄位;system prompt 精簡為指令核心;exclusions hint 只傳 location 與 suggestion,減少 token 用量 diff --git a/TODO.md b/TODO.md index 489da49..23e1e63 100644 --- a/TODO.md +++ b/TODO.md @@ -6,8 +6,8 @@ - 已驗收:`code-review` job 的 log 已完整出現 `Step1` 到 `Step8`,並以 `Pipeline 完成` 結束。 ## 階段二:Git Diff 排除 .gitea/ 資料夾 -- 目標:讀取 Git Diff 時排除 `.gitea/` 資料夾內的所有檔案,避免 AI 分析 workflow 設定等非業務程式碼。 -- 驗收:PR 中有 `.gitea/` 路徑的變更時,diff 內容不包含該路徑的區塊,AI 分析結果不含 `.gitea/` 相關問題。 +- 目標:讀取 Git Diff 時排除 `.gitea/` 資料夾內的所有檔案,以及 `.amazonq/`、`.claude/`、`.codex/`、`.gemini/`、`.github/`、`CLAUDE.md`、`GEMINI.md`、`TODO.md`、`README.md`,避免 AI 分析 workflow 設定、skill 入口與文件等非業務程式碼。 +- 驗收:PR 中有上述路徑或檔案的變更時,diff 內容不包含該區塊,AI 分析結果不含這些路徑相關問題。 - 已驗收:`app/gitea.js` 已在取得 diff 時過濾 `.gitea/` 區塊,且相關單元測試已覆蓋。 ## 階段三:Findings 產生與合併 diff --git a/app/gitea.js b/app/gitea.js index 79f1f76..5976594 100644 --- a/app/gitea.js +++ b/app/gitea.js @@ -11,7 +11,7 @@ const api = (path) => `${GITEA_SERVER_URL.replace(/\/$/, '')}/api/v1${path}`; */ export async function getPRDiff() { const resp = await axios.get(api(`/repos/${GITEA_REPOSITORY}/pulls/${PR_NUMBER}.diff`), { headers: headers(), timeout: 60000, httpsAgent }); - return filterDiff(resp.data, ['.gitea/']); + return filterDiff(resp.data, ['.gitea/', '.amazonq/', '.claude/', '.codex/', '.gemini/', '.github/', 'CLAUDE.md', 'GEMINI.md', 'TODO.md', 'README.md']); } /** @@ -20,7 +20,11 @@ export async function getPRDiff() { */ export function filterDiff(diff, excludePrefixes) { return diff.split(/(?=^diff --git )/m) - .filter(block => !excludePrefixes.some(p => block.startsWith(`diff --git a/${p}`))) + .filter(block => !excludePrefixes.some(p => { + const prefix = `diff --git a/${p}`; + const singleFile = `diff --git a/${p} b/${p}`; + return block.startsWith(prefix) || block.startsWith(singleFile); + })) .join(''); } diff --git a/app/gitea.test.js b/app/gitea.test.js index 26e916a..a401db0 100644 --- a/app/gitea.test.js +++ b/app/gitea.test.js @@ -64,22 +64,24 @@ describe('filterDiff', async () => { const block = (file) => `diff --git a/${file} b/${file}\n--- a/${file}\n+++ b/${file}\n@@ -1 +1 @@\n-old\n+new\n`; - it('filters out .gitea/ blocks', () => { - const diff = block('.gitea/workflows/review.yaml') + block('src/index.js'); - const result = filterDiff(diff, ['.gitea/']); + it('filters out configured folder blocks', () => { + const diff = block('.gitea/workflows/review.yaml') + block('.amazonq/rules/triage-findings.md') + block('src/index.js'); + const result = filterDiff(diff, ['.gitea/', '.amazonq/']); assert.ok(!result.includes('.gitea/')); + assert.ok(!result.includes('.amazonq/')); assert.ok(result.includes('src/index.js')); }); - it('does not filter non-.gitea/ blocks', () => { - const diff = block('src/index.js') + block('README.md'); - const result = filterDiff(diff, ['.gitea/']); - assert.equal(result, diff); + it('filters out configured top-level file blocks', () => { + const diff = block('README.md') + block('src/index.js'); + const result = filterDiff(diff, ['README.md', 'TODO.md']); + assert.ok(!result.includes('README.md')); + assert.ok(result.includes('src/index.js')); }); it('returns empty string when all blocks are excluded', () => { - const diff = block('.gitea/workflows/review.yaml') + block('.gitea/ai-review/findings.json'); - const result = filterDiff(diff, ['.gitea/']); + const diff = block('.gitea/workflows/review.yaml') + block('.gitea/ai-review/findings.json') + block('CLAUDE.md'); + const result = filterDiff(diff, ['.gitea/', 'CLAUDE.md']); assert.equal(result, ''); });