feat: AI Pull Request action — opencode 自動產生 PR 並通過 AI review #2

Open
jiantw83 wants to merge 24 commits from ai-review-resolve/develop-20260626-114117 into develop
Member

變更摘要

將 Docker Action 範本實作為「AI Pull Request」action:抓取來源/目標分支差異,呼叫 opencode 將 git diff 總結成 PR 標題與描述(固定繁體中文),透過 Gitea token 自動建立 PR;偵測到合併衝突時改建解衝突分支並開對應 PR。並逐輪處理 AI code review findings。

重點變更

  • app/(Node.js 應用程式)
    • index.js:主流程(計算差異 → opencode 摘要 → 衝突偵測 → 建立 PR/解衝突 PR)。
    • lib/inputs.jslib/git.jslib/gitea.jslib/opencode.jslib/util.js:環境變數讀取、git 操作、Gitea API、opencode 呼叫與共用工具。
  • Dockerfile:基底 node:20-bookworm-slim,安裝 git/curl 與 opencode-ai CLI,改用 WORKDIR /app
  • action.yaml:定義 source_branchtarget_branchopencode_* inputs;GITEA_TOKEN 固定由 gitea.token 注入。
  • entrypoint.shset -euo pipefail,進入點改為 node /app/index.js
  • .gitea/workflows/:保留正確命名的 ci/cd,移除路徑含空白的錯誤檔。
  • README.md:功能、參數與使用範例。

AI Code Review 處理結果

逐輪處理 AI review findings:

  • 已修復:錯誤訊息 token 遮蔽、opencode 暫存設定清理、解衝突分支名稱截斷、HOME 改用 os.homedir()、衝突偵測暫存分支加 PID 與 finally 清理、Dockerfile 改用 WORKDIR、解衝突 PR 加入人工檢查清單。
  • 誤報歸檔.gitea/ai-review/exclusions.json,附理由):token 在 header/findOpenPull 分頁/remoteUrl 網域/max-count/maxBuffer/git config --global/maskSecrets 變體/main SRP/ahead=0 早返/PR 描述 XSS/固定 timeout/spawnSync 競態/殘留衝突標記(刻意保留)/設定檔 I/O。

待人工處理(保留於 findings.json)

  • 核心邏輯缺乏自動化測試(需導入測試框架,如 node:test/Jest)。
  • detectConflict abort 失敗情境測試。
  • truncateDifffallbackSummaryextractResult 單元測試。
  • 傳給 opencode 子程序的 process.env 篩選(須先確認其所需環境變數集合)。

注意事項

  • GITEA_TOKEN 由 Gitea Actions 的 gitea.token 自動注入。
  • opencode 不可用或解析失敗時,會以 commit 訊息與檔案統計產生 fallback 標題/描述。
## 變更摘要 將 Docker Action 範本實作為「AI Pull Request」action:抓取來源/目標分支差異,呼叫 [opencode](https://opencode.ai) 將 git diff 總結成 PR 標題與描述(固定繁體中文),透過 Gitea token 自動建立 PR;偵測到合併衝突時改建解衝突分支並開對應 PR。並逐輪處理 AI code review findings。 ## 重點變更 - **`app/`(Node.js 應用程式)** - `index.js`:主流程(計算差異 → opencode 摘要 → 衝突偵測 → 建立 PR/解衝突 PR)。 - `lib/inputs.js`、`lib/git.js`、`lib/gitea.js`、`lib/opencode.js`、`lib/util.js`:環境變數讀取、git 操作、Gitea API、opencode 呼叫與共用工具。 - **`Dockerfile`**:基底 `node:20-bookworm-slim`,安裝 git/curl 與 opencode-ai CLI,改用 `WORKDIR /app`。 - **`action.yaml`**:定義 `source_branch`/`target_branch`/`opencode_*` inputs;`GITEA_TOKEN` 固定由 `gitea.token` 注入。 - **`entrypoint.sh`**:`set -euo pipefail`,進入點改為 `node /app/index.js`。 - **`.gitea/workflows/`**:保留正確命名的 ci/cd,移除路徑含空白的錯誤檔。 - **`README.md`**:功能、參數與使用範例。 ## AI Code Review 處理結果 逐輪處理 AI review findings: - **已修復**:錯誤訊息 token 遮蔽、opencode 暫存設定清理、解衝突分支名稱截斷、`HOME` 改用 `os.homedir()`、衝突偵測暫存分支加 PID 與 finally 清理、Dockerfile 改用 WORKDIR、解衝突 PR 加入人工檢查清單。 - **誤報歸檔**(`.gitea/ai-review/exclusions.json`,附理由):token 在 header/findOpenPull 分頁/remoteUrl 網域/max-count/maxBuffer/git config --global/maskSecrets 變體/main SRP/ahead=0 早返/PR 描述 XSS/固定 timeout/spawnSync 競態/殘留衝突標記(刻意保留)/設定檔 I/O。 ## 待人工處理(保留於 findings.json) - 核心邏輯缺乏自動化測試(需導入測試框架,如 node:test/Jest)。 - `detectConflict` abort 失敗情境測試。 - `truncateDiff`/`fallbackSummary`/`extractResult` 單元測試。 - 傳給 opencode 子程序的 `process.env` 篩選(須先確認其所需環境變數集合)。 ## 注意事項 - `GITEA_TOKEN` 由 Gitea Actions 的 `gitea.token` 自動注入。 - opencode 不可用或解析失敗時,會以 commit 訊息與檔案統計產生 fallback 標題/描述。
jiantw83 added 14 commits 2026-06-26 06:10:07 +00:00

🤖 AI Code Review 團隊

👤 角色 🎯 面向 🧠 個性
🗡️ Assassin security 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用
🎼 Bard style 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版
🧰 Leo maintainability 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來
🔮 Mage logic 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」
🧪 Maya testing 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑
Rogue efficiency 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」

🔍 服務:opencode 模型:gemini-2.5-flash

## 🤖 AI Code Review 團隊 | 👤 角色 | 🎯 面向 | 🧠 個性 | |--------|--------|--------| | **🗡️ Assassin** | security | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | **🎼 Bard** | style | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | **🧰 Leo** | maintainability | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | **🔮 Mage** | logic | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | **🧪 Maya** | testing | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | **⚡ Rogue** | efficiency | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 | > 🔍 服務:opencode 模型:gemini-2.5-flash
gitea-actions bot reviewed 2026-06-26 06:10:55 +00:00
gitea-actions bot left a comment

AI Code Review 統計

類型 🔴 嚴重 🟡 警告 🔵 建議 無法標示
新問題 2 筆 6 筆 3 筆 0 筆
舊問題 0 筆 0 筆 1 筆 0 筆

🤖 AI 助理使用量

本次審查(opencode / gemini-2.5-flash,共 20 次呼叫)

提示 token 回應 token 合計
107,470 6,874 333,836

剩餘可用

剩餘可用:無法計算百分比(自架服務,無帳號額度概念)

## AI Code Review 統計 | 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 | ⚪ 無法標示 | | --- | --- | --- | --- | --- | | 新問題 | 2 筆 | 6 筆 | 3 筆 | 0 筆 | | 舊問題 | 0 筆 | 0 筆 | 1 筆 | 0 筆 | ## 🤖 AI 助理使用量 **本次審查**(opencode / gemini-2.5-flash,共 20 次呼叫) | 提示 token | 回應 token | 合計 | | --- | --- | --- | | 107,470 | 6,874 | 333,836 | **剩餘可用** 剩餘可用:無法計算百分比(自架服務,無帳號額度概念)
@@ -2,0 +8,4 @@
# 安裝 opencode CLI(用於分析 git diff 產生 PR 標題與描述)
RUN npm install -g opencode-ai
# 複製 Node.js 應用程式

嚴重等級🟡 警告
審查員:Assassin
問題:Dockerfile 中使用全域 npm install 存在供應鏈風險。
建議:使用 lockfile(如 package-lock.json)確保依賴版本一致性,並定期審查更新。

**嚴重等級**:🟡 警告 **審查員**:Assassin **問題**:Dockerfile 中使用全域 `npm install` 存在供應鏈風險。 **建議**:使用 lockfile(如 `package-lock.json`)確保依賴版本一致性,並定期審查更新。
Ghost marked this conversation as resolved
@@ -0,0 +49,4 @@
diffStat,
diff,
});
if (!summary) {

嚴重等級🟡 警告
審查員:Mage
問題:opencode 失敗時,若相關資訊皆為空,fallback 機制產出的 PR 描述將空洞無效。
建議:增加對 fallbackSummary 輸出內容的檢查。若資訊不足,應拋出錯誤或提供更有意義的預設說明。

**嚴重等級**:🟡 警告 **審查員**:Mage **問題**:opencode 失敗時,若相關資訊皆為空,fallback 機制產出的 PR 描述將空洞無效。 **建議**:增加對 `fallbackSummary` 輸出內容的檢查。若資訊不足,應拋出錯誤或提供更有意義的預設說明。
Ghost marked this conversation as resolved
@@ -0,0 +77,4 @@
return;
}
// 5b. 有衝突:從目標分支建立解衝突分支,合併來源分支後 PR 回來源分支

嚴重等級🟡 警告
審查員:Bard
問題:分支命名格式若目標分支名稱過長,可能導致總長度超過 Git 限制。
建議:調整 stem 截斷長度,或加入總長度檢查機制,確保不超過 255 字元。

**嚴重等級**:🟡 警告 **審查員**:Bard **問題**:分支命名格式若目標分支名稱過長,可能導致總長度超過 Git 限制。 **建議**:調整 `stem` 截斷長度,或加入總長度檢查機制,確保不超過 255 字元。
Ghost marked this conversation as resolved
@@ -0,0 +173,4 @@
`### AI 變更摘要`,
``,
summary.description || '(無)',
].join('\n');

嚴重等級🔵 建議
審查員:Bard
問題:PR 已存在時僅記錄 log.info,CI 流程中可能需要更明確的提示。
建議:建議改用 log.warn 或新增 log.notice 等級,以更明確提示使用者「PR 已經存在」。

**嚴重等級**:🔵 建議 **審查員**:Bard **問題**:PR 已存在時僅記錄 `log.info`,CI 流程中可能需要更明確的提示。 **建議**:建議改用 `log.warn` 或新增 `log.notice` 等級,以更明確提示使用者「PR 已經存在」。
Ghost marked this conversation as resolved
@@ -0,0 +29,4 @@
}
return result;
}

嚴重等級🔵 建議
審查員:Leo
問題:Sensitive Token 處理耦合在 Git 類別中,且未驗證有效性。
建議:將 Token 的遮蔽邏輯交由 util.js 處理,或在 Git 初始化時驗證其有效性。

**嚴重等級**:🔵 建議 **審查員**:Leo **問題**:Sensitive Token 處理耦合在 `Git` 類別中,且未驗證有效性。 **建議**:將 Token 的遮蔽邏輯交由 `util.js` 處理,或在 `Git` 初始化時驗證其有效性。
Ghost marked this conversation as resolved
@@ -0,0 +151,4 @@
for (const candidate of findJsonObjects(text)) {
// LLM 常在字串值內輸出未跳脫的換行,先嘗試原始解析,失敗再嘗試修正
for (const variant of [candidate, escapeControlCharsInStrings(candidate)]) {
try {

嚴重等級🟡 警告
審查員:Bard
問題:錯誤訊息處理中,對 result.stderr 進行截斷,可能導致切斷關鍵錯誤上下文,除錯困難。
建議:改用 log.warn 輸出完整內容(遮蔽敏感資訊後),或將截斷訊息與「內容已截斷」提示並列。

**嚴重等級**:🟡 警告 **審查員**:Bard **問題**:錯誤訊息處理中,對 `result.stderr` 進行截斷,可能導致切斷關鍵錯誤上下文,除錯困難。 **建議**:改用 log.warn 輸出完整內容(遮蔽敏感資訊後),或將截斷訊息與「內容已截斷」提示並列。
Ghost marked this conversation as resolved
gitea-actions bot added 1 commit 2026-06-26 06:10:57 +00:00
jiantw83 added 2 commits 2026-06-26 06:14:37 +00:00

🤖 AI Code Review 團隊

👤 角色 🎯 面向 🧠 個性
🗡️ Assassin security 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用
🎼 Bard style 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版
🧰 Leo maintainability 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來
🔮 Mage logic 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」
🧪 Maya testing 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑
Rogue efficiency 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」

🔍 服務:opencode 模型:gemini-2.5-flash

## 🤖 AI Code Review 團隊 | 👤 角色 | 🎯 面向 | 🧠 個性 | |--------|--------|--------| | **🗡️ Assassin** | security | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | **🎼 Bard** | style | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | **🧰 Leo** | maintainability | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | **🔮 Mage** | logic | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | **🧪 Maya** | testing | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | **⚡ Rogue** | efficiency | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 | > 🔍 服務:opencode 模型:gemini-2.5-flash
gitea-actions bot reviewed 2026-06-26 06:15:15 +00:00
gitea-actions bot left a comment

AI Code Review 統計

類型 🔴 嚴重 🟡 警告 🔵 建議 無法標示
新問題 2 筆 2 筆 0 筆 0 筆
舊問題 0 筆 2 筆 1 筆 0 筆

🤖 AI 助理使用量

本次審查(opencode / gemini-2.5-flash,共 15 次呼叫)

提示 token 回應 token 合計
130,266 5,140 265,339

剩餘可用

剩餘可用:無法計算百分比(自架服務,無帳號額度概念)

## AI Code Review 統計 | 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 | ⚪ 無法標示 | | --- | --- | --- | --- | --- | | 新問題 | 2 筆 | 2 筆 | 0 筆 | 0 筆 | | 舊問題 | 0 筆 | 2 筆 | 1 筆 | 0 筆 | ## 🤖 AI 助理使用量 **本次審查**(opencode / gemini-2.5-flash,共 15 次呼叫) | 提示 token | 回應 token | 合計 | | --- | --- | --- | | 130,266 | 5,140 | 265,339 | **剩餘可用** 剩餘可用:無法計算百分比(自架服務,無帳號額度概念)
gitea-actions bot added 1 commit 2026-06-26 06:15:18 +00:00
jiantw83 added 2 commits 2026-06-26 07:17:54 +00:00
jiantw83 added 4 commits 2026-06-26 07:27:40 +00:00

🤖 AI Code Review 團隊

👤 角色 🎯 面向 🧠 個性
🗡️ Assassin security 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用
🎼 Bard style 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版
🧰 Leo maintainability 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來
🔮 Mage logic 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」
🧪 Maya testing 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑
Rogue efficiency 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」

🔍 服務:opencode 模型:gemini-2.5-flash

## 🤖 AI Code Review 團隊 | 👤 角色 | 🎯 面向 | 🧠 個性 | |--------|--------|--------| | **🗡️ Assassin** | security | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | **🎼 Bard** | style | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | **🧰 Leo** | maintainability | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | **🔮 Mage** | logic | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | **🧪 Maya** | testing | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | **⚡ Rogue** | efficiency | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 | > 🔍 服務:opencode 模型:gemini-2.5-flash
Some required checks failed
CI / Unit Test (pull_request) Failing after 14m6s
CI / AI Code Review (pull_request) Failing after 30m59s
Required
Details
This pull request has changes conflicting with the target branch.
  • .gitea / workflows/cd.yaml
  • .gitea / workflows/ci.yaml
  • action.yaml
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin ai-review-resolve/develop-20260626-114117:ai-review-resolve/develop-20260626-114117
git checkout ai-review-resolve/develop-20260626-114117
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: old-docker-actions/ai-pull-request#2