feat(ai-code-review): 建問題模式導向 issue,並整併流程調整、文件與 CI #6

Merged
admin merged 79 commits from ai-review-resolve/develop-20260717-185330 into develop 2026-07-21 09:39:48 +00:00
Showing only changes of commit b5264141c4 - Show all commits
+19 -6
View File
@@ -269,7 +269,7 @@ function commitAndPushFindings(cwd, { headRef, headSha, message, files, token, s
const remoteUrl = `${serverUrl}/${repository}.git`; const remoteUrl = `${serverUrl}/${repository}.git`;
// 一律以 token 的身分明確認證推送(不走 origin 的自動 token)——只要 token 是能觸發 CI 的 PAT // 一律以 token 的身分明確認證推送(不走 origin 的自動 token)——只要 token 是能觸發 CI 的 PAT
// 結果 commit 就會讓 PR 的 synchronize 事件再觸發 CI,由步驟 1 快速回報把結果蓋到新 head。 // 結果 commit 就會讓 PR 的 synchronize 事件再觸發 CI,由步驟 1 快速回報把結果蓋到新 head。
pushWithCredential(cwd, remoteUrl, token, refspec); pushWithCredential(cwd, remoteUrl, token, refspec, serverUrl);
return true; return true;
} }
@@ -278,20 +278,30 @@ function commitAndPushFindings(cwd, { headRef, headSha, message, files, token, s
* *
* 認證方式:等同 `https://ai-review-bot:<secret>@host/...` 的 HTTP Basicgit 會把 * 認證方式:等同 `https://ai-review-bot:<secret>@host/...` 的 HTTP Basicgit 會把
* URL 帳密轉成相同的 `Authorization: Basic` 標頭送出),但改以 git 的 * URL 帳密轉成相同的 `Authorization: Basic` 標頭送出),但改以 git 的
* `GIT_CONFIG_*` 環境變數注入 `http.<url>.extraheader`,使 base64 憑證**不出現在 argv** * `GIT_CONFIG_*` 環境變數注入 `http.<serverUrl>/.extraheader`,使 base64 憑證**不出現在 argv**
* (避免程序清單/例外回顯洩漏);推送目標 URL 亦不含帳密。 * (避免程序清單/例外回顯洩漏);推送目標 URL 亦不含帳密。
*
* 觸發 CI 關鍵:`actions/checkout` 會把「自動 Actions token」持久化在同一個
* `http.<serverUrl>/.extraheader` scope;若沿用它推送,Gitea 會視為「自動 token 觸發」而
* **不再觸發 workflow**(防遞迴)。故本函式對這次 push 於該 scope**先以空值重置**(清掉自動
* token——git 對 extraHeader 給空值即清空既有清單),**再注入 PAT 的 Authorization**,讓推送以
* PAT 身分進行、觸發 PR 的 synchronize;作用範圍僅限本次 push 的環境變數,不影響 action 其他
* 仰賴 checkout 持久化憑證的 fetch(如 {@link resolveMergeBase})。
* 推送失敗時**不重拋原始例外**(其 message 會含命令列與遠端 URL),改拋固定訊息。 * 推送失敗時**不重拋原始例外**(其 message 會含命令列與遠端 URL),改拋固定訊息。
* *
* @param {string} cwd - git 工作目錄(repo 的 checkout 路徑)。 * @param {string} cwd - git 工作目錄(repo 的 checkout 路徑)。
* @param {string} remoteUrl - 不含帳密的遠端 URL(形如 `https://host/owner/repo.git`)。 * @param {string} remoteUrl - 不含帳密的遠端 URL(形如 `https://host/owner/repo.git`)。
* @param {string} secret - 具 push 權限的 tokenPAT(作為 Basic 認證的密碼)。 * @param {string} secret - 具 push 權限的 tokenPAT(作為 Basic 認證的密碼)。
* @param {string} refspec - push 的 refspec(形如 `HEAD:refs/heads/<branch>`)。 * @param {string} refspec - push 的 refspec(形如 `HEAD:refs/heads/<branch>`)。
* @param {string} serverUrl - Gitea 伺服器根網址(用於定位 checkout 持久化 extraheader 的 scope)。
* @returns {void} 成功即返回;失敗拋出不含 URL/argv/token 的固定錯誤。 * @returns {void} 成功即返回;失敗拋出不含 URL/argv/token 的固定錯誤。
* @throws {Error} 推送失敗時拋出固定訊息(已隱藏遠端 URL 與認證資訊)。 * @throws {Error} 推送失敗時拋出固定訊息(已隱藏遠端 URL 與認證資訊)。
* @remarks 本函式未匯出,僅供 {@link commitAndPushFindings} 使用。 * @remarks 本函式未匯出,僅供 {@link commitAndPushFindings} 使用。
*/ */
function pushWithCredential(cwd, remoteUrl, secret, refspec) { function pushWithCredential(cwd, remoteUrl, secret, refspec, serverUrl) {
const basic = Buffer.from(`ai-review-bot:${secret}`).toString('base64'); const basic = Buffer.from(`ai-review-bot:${secret}`).toString('base64');
// checkout 持久化自動 token 的 scope 為 `http.<serverUrl>/.extraheader`(結尾帶斜線)。
const headerScope = `http.${serverUrl.replace(/\/+$/, '')}/.extraheader`;
try { try {
execFileSync('git', ['push', remoteUrl, refspec], { execFileSync('git', ['push', remoteUrl, refspec], {
cwd, cwd,
@@ -300,9 +310,12 @@ function pushWithCredential(cwd, remoteUrl, secret, refspec) {
env: { env: {
...process.env, ...process.env,
GIT_TERMINAL_PROMPT: '0', GIT_TERMINAL_PROMPT: '0',
GIT_CONFIG_COUNT: '1', // 兩筆同 scope 設定:先空值清掉 checkout 的自動 token,再注入 PAT 的 Authorization。
GIT_CONFIG_KEY_0: `http.${remoteUrl}.extraheader`, GIT_CONFIG_COUNT: '2',
GIT_CONFIG_VALUE_0: `Authorization: Basic ${basic}`, GIT_CONFIG_KEY_0: headerScope,
GIT_CONFIG_VALUE_0: '',
GIT_CONFIG_KEY_1: headerScope,
GIT_CONFIG_VALUE_1: `Authorization: Basic ${basic}`,
}, },
}); });
} catch { } catch {