fix(ai-review): 結果推送失敗時回報工作流失敗
This commit is contained in:
+18
-19
@@ -4,7 +4,7 @@
|
||||
console.log('================================================');
|
||||
console.log('Action : AI Code Review');
|
||||
console.log('用途 : AI 多角色 code review:攻擊方找問題、防守方裁決誤報,結果留言到 PR 並保存 findings');
|
||||
console.log('更新時間: 2026/07/17 18:49:58');
|
||||
console.log('更新時間: 2026/07/21 17:19:15');
|
||||
console.log('================================================');
|
||||
|
||||
const fs = require('fs');
|
||||
@@ -126,15 +126,14 @@ function commitFindings({ cwd, ctx, files, result }) {
|
||||
* 建問題模式會把審查情境與每條 finding 發到追蹤 issue;沒有保留 finding 時不建立 issue、PR 也不留言。
|
||||
* 嚴重 finding 會寫入 failure 結果 commit,警告與建議只建立追蹤資訊,不直接阻擋合併。
|
||||
*
|
||||
* @returns {Promise<number>} process exit code:本輪「審查」一律回傳 0(不因嚴重問題直接讓檢查失敗——
|
||||
* 失敗改由推出的 `[ai-review-bot][failure]` 結果 commit,於下一輪在步驟 1 讀 commit 訊息時回報);
|
||||
* 回傳 1 僅發生於:步驟 1 偵測到 `[ai-review-bot][failure]` 結果 commit,或前置條件不足
|
||||
* (缺 PR 編號/token、找不到 AI 工具)等無法進行審查的情況。
|
||||
* @returns {Promise<number>} process exit code:沒有嚴重問題且結果 commit 已成功推送時回傳 0;
|
||||
* 若步驟 1 偵測到 `[ai-review-bot][failure]`、前置條件不足,或需要推送結果檔卻未成功推送,
|
||||
* 則回傳 1,避免 token 權限不足或遠端競態讓 workflow 靜默通過。
|
||||
* @remarks
|
||||
* 使用情境:由本檔尾端的頂層呼叫端執行 —— `main().then((code) => process.exit(code))`;
|
||||
* 非預期例外由頂層 `catch` 記 ERR log 後以 exit code 1 收場,且刻意不 commit 結果標記,
|
||||
* 讓下一次 workflow 觸發時重新完整審查。警告+建議等級不影響結果標記,只有「嚴重」會使結果 commit
|
||||
* 標記為 failure;而「失敗檢查(exit 1)」只由步驟 1 讀到該 failure 結果 commit 時產生,審查本輪不直接 exit 1。
|
||||
* 標記為 failure;若結果檔需要 push 卻失敗,本輪直接 exit 1,避免缺權限時無聲放行。
|
||||
* 建問題模式只改變問題明細的落地方式(issue 留言取代 findings 進版控),不改變上述結果標記判定。
|
||||
*/
|
||||
async function main() {
|
||||
@@ -193,7 +192,7 @@ async function main() {
|
||||
return created;
|
||||
};
|
||||
/**
|
||||
* 建問題模式:建立追蹤 issue(標題=PR 標題、本文=PR 描述+回溯 PR 的引言,連同挑好的標籤一次建立),
|
||||
* 建問題模式:開啟追蹤 issue(標題=PR 標題、本文=PR 描述+回溯 PR 的引言,連同挑好的標籤一次建立),
|
||||
* 並把 `pendingIssueCommentBodies` 內暫存的情境留言依流程順序寫入 issue;
|
||||
* 設定閉包變數 `trackingIssue` 供後續留言直接發到 issue。
|
||||
* 僅於「確定有保留問題」時呼叫一次。標籤於建立時一次帶入,省去「先建空標籤 issue 再補掛」的多餘 API 往返。
|
||||
@@ -202,17 +201,18 @@ async function main() {
|
||||
* 空陣列或省略時不掛任何標籤(`gitea.createIssue` 對空陣列不帶 labels 欄位)。
|
||||
* @returns {Promise<void>} 無回傳值;結果反映在閉包變數 `trackingIssue` 與 issue 留言。
|
||||
*/
|
||||
const createIssueAndFlushBufferedComments = async (labelIds = []) => {
|
||||
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) {
|
||||
while (pendingIssueCommentBodies.length > 0) {
|
||||
const body = pendingIssueCommentBodies[0];
|
||||
await gitea.createCommentOnIssue(ctx, trackingIssue.number, body);
|
||||
pendingIssueCommentBodies.shift();
|
||||
}
|
||||
pendingIssueCommentBodies.length = 0;
|
||||
};
|
||||
/**
|
||||
* 建問題模式降級:追蹤 issue 無法建立或寫入時,改把已暫存的情境留言發回 PR,後續沿用一般模式。
|
||||
@@ -337,7 +337,7 @@ async function main() {
|
||||
log('建問題', 'WRN', `標籤挑選失敗(${err.message}),issue 不掛標籤。`);
|
||||
}
|
||||
try {
|
||||
await createIssueAndFlushBufferedComments(labelIds);
|
||||
await openTrackingIssue(labelIds);
|
||||
} catch (err) {
|
||||
log('建問題', 'WRN', `建立或寫入追蹤 issue 失敗(${err.message}),改用 PR 留言與 findings 檔流程。`);
|
||||
await fallbackToPrComments();
|
||||
@@ -377,7 +377,7 @@ async function main() {
|
||||
}
|
||||
|
||||
// ── 建問題模式收束:在 PR 回貼 issue 連結(雙向關聯);僅在有嚴重問題時才讓 PR 相依於該 issue ─
|
||||
// 標籤已於建立 issue 時一次帶入(見上方 selectLabels → createIssueAndFlushBufferedComments),此處不再補掛。
|
||||
// 標籤已於建立 issue 時一次帶入(見上方 selectLabels → openTrackingIssue),此處不再補掛。
|
||||
if (issueModeActive && trackingIssue) {
|
||||
await review.resolveOldIssueLinkComments({ ctx, gitea });
|
||||
await gitea.createIssueComment(
|
||||
@@ -420,14 +420,13 @@ async function main() {
|
||||
} else {
|
||||
log('收尾', 'INF', '建問題模式且 exclusions.json 無變更,略過 commit/push。');
|
||||
}
|
||||
// 本輪「審查」一律以成功收場、不直接讓檢查失敗;有嚴重問題時已推出 [failure] 結果 commit,
|
||||
// 由它再觸發的下一輪在步驟 1 讀 commit 訊息時才回報失敗(exit 1)。如此失敗檢查落在帶有結果
|
||||
// 標記的最新 head 上,與合併判定一致。(result 僅用於上方 commit 訊息的結果標記。)
|
||||
// 需要推送結果檔卻沒成功時直接失敗;這通常代表 token 權限不足、非快轉或分支保護阻擋。
|
||||
if (review.shouldFailMissingResultCommit({ filesToCommit, resultCommitted })) {
|
||||
log('收尾', 'ERR', '審查結果檔需要 push 但未成功產生結果 commit;直接回報失敗避免缺權限時靜默通過。');
|
||||
return 1;
|
||||
}
|
||||
// 嚴重問題已推出 [failure] 結果 commit 時,由它再觸發的下一輪在步驟 1 讀 commit 訊息回報失敗。
|
||||
if (result === 'failure') {
|
||||
if (!resultCommitted) {
|
||||
log('收尾', 'ERR', '本輪有嚴重問題,但未成功產生 [failure] 結果 commit;直接回報失敗避免 fail-open。');
|
||||
return 1;
|
||||
}
|
||||
log('收尾', 'INF', '本輪有嚴重問題:已標記結果 commit 為 [failure],失敗檢查由下一輪步驟 1 讀 commit 訊息回報。');
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -579,6 +579,18 @@ function resultFilesToCommit({ createIssue, severeCount, relativePath, exclusion
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判斷本輪是否因結果 commit 未成功推送而必須失敗。
|
||||
*
|
||||
* @param {Object} params - 解構參數。
|
||||
* @param {string[]} params.filesToCommit - 本輪預期寫回遠端分支的結果檔清單。
|
||||
* @param {boolean} params.resultCommitted - 結果檔是否已成功 commit 並 push。
|
||||
* @returns {boolean} 需要寫回結果檔卻沒有成功推送時回傳 true。
|
||||
*/
|
||||
function shouldFailMissingResultCommit({ filesToCommit, resultCommitted }) {
|
||||
return filesToCommit.length > 0 && !resultCommitted;
|
||||
}
|
||||
|
||||
/**
|
||||
* 就地排序 findings:依 嚴重→警告→建議、再依檔案路徑、再依起始行遞增。
|
||||
*
|
||||
@@ -914,6 +926,7 @@ module.exports = {
|
||||
sortFindings,
|
||||
appendExclusions,
|
||||
resultFilesToCommit,
|
||||
shouldFailMissingResultCommit,
|
||||
selectLabels,
|
||||
postSevereToIssue,
|
||||
postOthersToIssue,
|
||||
|
||||
Reference in New Issue
Block a user