本分支持續處理 AI Code Review findings,最新推送新增以下修正:
commitFindings
exclusions.json
src/lib/gitref.js
assertSafeBranchRef
gitrepo.__test
pushWithCredential
action.yml
src/lib/gitrepo.js
test/gitrepo.test.js
gitref
.gitea/ai-review/exclusions.json
.gitea/ai-review/findings/*.json
npm test
git diff --check
本問題由 AI Code Review 依 PR #6 的審查結果自動建立,問題明細見下方留言。
codex
codex-cli 0.144.6
gpt-5.5
44c33b6c1ecb66ad56423a49142d54397d6cf5fd
flowchart LR A[整理 git diff] --> B[⚔️ 攻擊方找問題] B --> C[🛡️ 防守方裁決] C --> D[保存 findings] D --> E[留言到 PR]
package.json
readme.md
src/index.js
src/lib/agents.js
src/lib/context.js
src/lib/diagnostics.js
src/lib/gitea.js
src/lib/review.js
src/lib/roles.js
src/lib/templates.js
test/gitea.test.js
test/review.test.js
共 16 個檔案納入審查;另有 14 個檔案依 .reviewignore 排除。
.reviewignore
位置:src/index.js 第 72–115 行
問題描述
commitFindings() 的回傳值把「無實際變更」與「commit/push 失敗」都壓成 false。這個 API 六個月後很容易被誤用:呼叫端看到 boolean 只能猜是正常 no-op 還是遠端寫回失敗,後續 shouldFailMissingResultCommit() 也必須靠外部條件再推論,維護成本會隨流程分支增加。
commitFindings()
false
shouldFailMissingResultCommit()
修改建議
改回傳具名狀態,例如 { status: 'pushed' | 'unchanged' | 'failed', error },讓呼叫端直接依狀態決定是否阻擋 workflow,也讓日誌與測試能明確覆蓋每種情境。
{ status: 'pushed' | 'unchanged' | 'failed', error }
建議寫法
function commitFindings(...) { try { const committed = gitrepo.commitAndPushFindings(...); return committed ? { status: 'pushed' } : { status: 'unchanged' }; } catch (err) { log('收尾', 'WRN', `commit/push 審查結果檔失敗:${err.message}。`); return { status: 'failed', error: err }; } }
位置:src/index.js 第 107–117 行
commitFindings 現在把 commit/push 失敗轉成 false,而主流程文件也宣告「需要推送結果檔卻未成功推送」要 exit 1;但測試只驗證了 shouldFailMissingResultCommit 這個純 helper,沒有驗證 main() 真的會把 commitFindings 的 false 接成失敗 exit code。這條結果提交失敗路徑若接錯,workflow 可能仍靜默通過。
shouldFailMissingResultCommit
main()
補主流程層級測試:stub gitrepo.commitAndPushFindings 或 commitFindings 讓它回傳 false,並建構「有 filesToCommit」的情境,斷言 main() 回傳 1;同時補 filesToCommit=[] 的建問題模式無保留問題情境,斷言不會因沒有 commit 而失敗。
gitrepo.commitAndPushFindings
1
filesToCommit=[]
位置:src/index.js 第 213–216 行
建問題模式建立追蹤 issue 後,openTrackingIssue 逐則寫入暫存情境留言時會一邊成功一邊 shift()。最小重現:pendingIssueCommentBodies = [工具留言, diff留言, 角色留言],issue 建立成功、第一則留言成功後第二則 API 失敗;catch 會改走 fallbackToPrComments(),但第一則已被移出 buffer,只留在一個不再被連結的半成品 issue,PR fallback 也少了該則留言。這會讓降級流程的輸出不完整,且留下孤立 issue 副作用。
openTrackingIssue
shift()
pendingIssueCommentBodies = [工具留言, diff留言, 角色留言]
fallbackToPrComments()
在所有暫存留言都成功寫入後才清空 buffer;失敗時保留完整 buffer 讓 fallback 能完整回貼 PR。若已建立 issue 但寫入失敗,也應明確標記或連結該 issue,避免留下無人知道的半成品。
const openTrackingIssue = async (labelIds = []) => { trackingIssue = await gitea.createIssue(ctx, { title: ctx.prTitle || `AI Code Review:PR #${ctx.prNumber}`, body: templates.issueBody({ prNumber: ctx.prNumber, prBody: ctx.prBody }), labels: labelIds, }); log('建問題', 'INF', `已建立追蹤 issue #${trackingIssue.number},寫入 ${pendingIssueCommentBodies.length} 則情境留言。`); for (const body of pendingIssueCommentBodies) { await gitea.createCommentOnIssue(ctx, trackingIssue.number, body); } pendingIssueCommentBodies.length = 0; };
位置:src/lib/review.js 第 574–575 行
resultFilesToCommit 在建問題模式只於 severeCount > 0 時提交 findings。最小重現:create-issue=true、本輪只有「警告」或「建議」finding、exclusionsChanged=false。主流程會建立追蹤 issue,但 filesToCommit 會是空陣列,因此不會產生帶 [success] 的結果 commit;下一次 workflow 沒有步驟 1 的快速回報標記,會重新完整審查並可能再建立一個內容相同的追蹤 issue。
resultFilesToCommit
severeCount > 0
create-issue=true
exclusionsChanged=false
filesToCommit
[success]
建問題模式只要本輪已建立追蹤 issue 或有保留 findings,就應寫回一個可供下輪辨識的結果標記。若不想把非嚴重 findings 進版控,至少提交一個最小狀態檔;最直接的修法是讓函式接收 keptCount,有任何保留 finding 時都提交本輪 findings。
keptCount
function resultFilesToCommit({ createIssue, keptCount, relativePath, exclusionsChanged }) { const files = createIssue ? (keptCount > 0 ? [relativePath] : []) : [relativePath]; if (exclusionsChanged) { files.push(path.join('.gitea', 'ai-review', 'exclusions.json')); } return files; }
位置:src/lib/gitea.js 第 159–161 行
註解提到 createIssueAndFlushBufferedComments,但本次新增的實際閉包名稱是 openTrackingIssue。文件與樂譜上的主旋律不同調,讀者循著函式名回頭找脈絡時會撲空。
createIssueAndFlushBufferedComments
把 JSDoc 中的函式名稱改成實際存在的 openTrackingIssue,或若想強調語意,請同步調整實作命名,避免文件與程式碼各唱各的。
位置:src/lib/templates.js 第 305–307 行
issueBody 的使用情境同樣引用了不存在的 createIssueAndFlushBufferedComments,但實作裡負責建立 issue 並沖掉暫存留言的是 openTrackingIssue。這種過期命名像錯拍的註腳,會削弱註解可信度。
issueBody
統一使用實際函式名稱;若未來想保留「flush buffered comments」這個語意,可將 openTrackingIssue 重新命名成相同概念,讓文件與程式碼保持押韻。
No dependencies set.
The note is not visible to the blocked user.
變更摘要
本分支持續處理 AI Code Review findings,最新推送新增以下修正:
commitFindingsfail-open 相關嚴重 finding 寫入exclusions.json;現行主流程已在 failure 結果 commit 未成功時直接回傳 1。src/lib/gitref.js模組匯出assertSafeBranchRef,移除gitrepo.__test測試出口。pushWithCredential的 JSDoc,保留關鍵安全不變式。action.yml中文敘述中的全形斜線標點。影響範圍
src/lib/gitref.js/src/lib/gitrepo.js:分支 ref 驗證模組邊界與推送文件整理。test/gitrepo.test.js:改測正式gitrefAPI。action.yml:中文標點一致性。.gitea/ai-review/exclusions.json/.gitea/ai-review/findings/*.json:排除事項與 findings 狀態回寫。驗證
npm test通過:11 tests / 0 failed。git diff --check通過。風險與注意事項
🤖 AI Code Review|審查工具
codexcodex-cli 0.144.6gpt-5.544c33b6c1ecb66ad56423a49142d54397d6cf5fd📋 變更摘要(送審 git diff)
action.ymlpackage.jsonreadme.mdsrc/index.jssrc/lib/agents.jssrc/lib/context.jssrc/lib/diagnostics.jssrc/lib/gitea.jssrc/lib/gitref.jssrc/lib/gitrepo.jssrc/lib/review.jssrc/lib/roles.jssrc/lib/templates.jstest/gitea.test.jstest/gitrepo.test.jstest/review.test.js⚔️ 攻擊方登場
🛡️ 防守方登場
🟠 警告|🧰 Leo
位置:
src/index.js第 72–115 行問題描述
commitFindings()的回傳值把「無實際變更」與「commit/push 失敗」都壓成false。這個 API 六個月後很容易被誤用:呼叫端看到 boolean 只能猜是正常 no-op 還是遠端寫回失敗,後續shouldFailMissingResultCommit()也必須靠外部條件再推論,維護成本會隨流程分支增加。修改建議
改回傳具名狀態,例如
{ status: 'pushed' | 'unchanged' | 'failed', error },讓呼叫端直接依狀態決定是否阻擋 workflow,也讓日誌與測試能明確覆蓋每種情境。建議寫法
🟠 警告|🧪 Maya
位置:
src/index.js第 107–117 行問題描述
commitFindings現在把 commit/push 失敗轉成false,而主流程文件也宣告「需要推送結果檔卻未成功推送」要 exit 1;但測試只驗證了shouldFailMissingResultCommit這個純 helper,沒有驗證main()真的會把commitFindings的false接成失敗 exit code。這條結果提交失敗路徑若接錯,workflow 可能仍靜默通過。修改建議
補主流程層級測試:stub
gitrepo.commitAndPushFindings或commitFindings讓它回傳false,並建構「有 filesToCommit」的情境,斷言main()回傳1;同時補filesToCommit=[]的建問題模式無保留問題情境,斷言不會因沒有 commit 而失敗。🟠 警告|🔮 Mage
位置:
src/index.js第 213–216 行問題描述
建問題模式建立追蹤 issue 後,
openTrackingIssue逐則寫入暫存情境留言時會一邊成功一邊shift()。最小重現:pendingIssueCommentBodies = [工具留言, diff留言, 角色留言],issue 建立成功、第一則留言成功後第二則 API 失敗;catch 會改走fallbackToPrComments(),但第一則已被移出 buffer,只留在一個不再被連結的半成品 issue,PR fallback 也少了該則留言。這會讓降級流程的輸出不完整,且留下孤立 issue 副作用。修改建議
在所有暫存留言都成功寫入後才清空 buffer;失敗時保留完整 buffer 讓 fallback 能完整回貼 PR。若已建立 issue 但寫入失敗,也應明確標記或連結該 issue,避免留下無人知道的半成品。
建議寫法
🟠 警告|🔮 Mage
位置:
src/lib/review.js第 574–575 行問題描述
resultFilesToCommit在建問題模式只於severeCount > 0時提交 findings。最小重現:create-issue=true、本輪只有「警告」或「建議」finding、exclusionsChanged=false。主流程會建立追蹤 issue,但filesToCommit會是空陣列,因此不會產生帶[success]的結果 commit;下一次 workflow 沒有步驟 1 的快速回報標記,會重新完整審查並可能再建立一個內容相同的追蹤 issue。修改建議
建問題模式只要本輪已建立追蹤 issue 或有保留 findings,就應寫回一個可供下輪辨識的結果標記。若不想把非嚴重 findings 進版控,至少提交一個最小狀態檔;最直接的修法是讓函式接收
keptCount,有任何保留 finding 時都提交本輪 findings。建議寫法
🔵 建議|🎼 Bard
位置:
src/lib/gitea.js第 159–161 行問題描述
註解提到
createIssueAndFlushBufferedComments,但本次新增的實際閉包名稱是openTrackingIssue。文件與樂譜上的主旋律不同調,讀者循著函式名回頭找脈絡時會撲空。修改建議
把 JSDoc 中的函式名稱改成實際存在的
openTrackingIssue,或若想強調語意,請同步調整實作命名,避免文件與程式碼各唱各的。🔵 建議|🎼 Bard
位置:
src/lib/templates.js第 305–307 行問題描述
issueBody的使用情境同樣引用了不存在的createIssueAndFlushBufferedComments,但實作裡負責建立 issue 並沖掉暫存留言的是openTrackingIssue。這種過期命名像錯拍的註腳,會削弱註解可信度。修改建議
統一使用實際函式名稱;若未來想保留「flush buffered comments」這個語意,可將
openTrackingIssue重新命名成相同概念,讓文件與程式碼保持押韻。