嚴重等級:🔴 嚴重 審查員:Maya 問題:新增的異常處理邏輯截斷了 text 為 200 字元,但在 text 為極大值或無法轉為字串時未進行防禦性檢查,且截斷點可能將多位元組字元拆分導致亂碼。 建議:請確保 text 是字串後再截斷,並使用正確處理多位元組字元的方式(如 Array.from(text).slice(0, 200).join(''))以避免亂碼。
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
變更摘要
修正
calculate-version重複且部分無法執行的單元測試目錄(PR #5 合入後遺留)。app/package.json的npm test(node --test,工作目錄為app/)只會探索app/test/;但 repo 根目錄另有一份test/,其中包含main的整合測試(index.test.js,以依賴注入驗證成功/失敗路徑),這些測試實際上從未被執行。內容
config/index/releases/version測試收斂到app/test/,並修正require路徑(../app/x→../x)。app/test/output.test.js。test/。影響
require路徑。cd app && npm test由 30 筆增為 34 筆且全數通過(含原本未被執行的main整合測試)。🤖 AI Code Review 團隊
AI Code Review 統計
🤖 AI 助理使用量
本次審查(opencode / gemini-2.5-flash,共 14 次呼叫)
剩餘可用
剩餘可用:無法計算百分比(自架服務,無帳號額度概念)
@@ -11,3 +12,3 @@test('isUnset 對未設定值回傳 true', () => {test('isUnset 將 undefined/空字串/null 字面值視為未設定', () => {assert.equal(isUnset(undefined), true);嚴重等級:🟡 警告
審查員:Leo
問題:測試案例名稱與內容不符,將相反行為寫在同一個 test 中,且移除了對 null 與 "false" 的特定檢查。
建議:將斷言拆分為獨立的測試案例,並補回對 null 與字串 "false" 的邊界測試。
@@ -27,2 +21,4 @@assert.throws(() => requireEnv('FOO', ''), /FOO 未設定/);assert.equal(requireEnv('FOO', 'bar'), 'bar');});嚴重等級:🟡 警告
審查員:Leo
問題:測試案例同時包含「錯誤處理」與「成功回傳」兩種行為。測試應遵循單一職責原則,若邏輯調整導致其中一項失敗,目前寫法會使得錯誤定位變得困難。
建議:建議將 requireEnv 的拋錯測試與成功回傳測試拆分為兩個獨立的測試案例。
@@ -14,1 +8,3 @@return { ok: true, text: async () => JSON.stringify(items) };// 以可控的假回應替換全域 fetch,並於結束後還原function withFetch(handler, run) {const original = globalThis.fetch;嚴重等級:🔵 建議
審查員:Leo
問題:withFetch 為全域 fetch 的通用封裝工具,目前定義在特定測試檔案內。若後續專案中其他測試檔案也需要模擬 fetch,將導致測試工具邏輯重複分散。
建議:建議將此類通用的測試輔助函式提取至獨立的測試工具檔案(例如 app/test/test-utils.js),以提升測試程式碼的重用性與維護一致性。
@@ -16,0 +16,4 @@const rel = (tag) => ({ tag_name: tag });test('compareVersionArrays 逐區段比較且較短者較小', () => {assert.ok(compareVersionArrays([1, 10], [1, 2, 3]) > 0);嚴重等級:🟡 警告
審查員:Maya
問題:新的
compareVersionArrays測試雖增加了案例,但移除了compareVersionArrays([2, 0, 0], [1, 9, 9]) > 0,這對 Major 版本進位的跨區段比較極為重要。建議:建議補回對大版本變更的比較測試,確保版本排序邏輯正確。
🤖 AI Code Review 團隊
AI Code Review 統計
🤖 AI 助理使用量
本次審查(opencode / gemini-2.5-flash,共 14 次呼叫)
剩餘可用
剩餘可用:無法計算百分比(自架服務,無帳號額度概念)
@@ -58,0 +58,4 @@// 驗證 repository 為 owner/repo 格式(僅允許字母數字與 . _ -,且拒絕 . 與 .. 路徑穿越段)function assertRepository(name, value) {const parts = value.split('/');const valid = parts.length === 2嚴重等級:🟡 警告
審查員:Maya
問題:新增的
assertRepository函式缺乏對 owner/repo 字串長度的邊界檢查,且變數名稱valid過於通用,語義不夠明確。建議:建議在
assertRepository中加入長度限制檢查,並將valid更名為isRepoFormatValid或類似具備明確語義的命名。@@ -65,2 +65,3 @@} catch {throw new Error(`release API 回傳資料無法解析 (page=${page})`);// 附上截斷的回傳內容片段,便於除錯回傳格式異常const snippet = text.slice(0, 200);嚴重等級:🔵 建議
審查員:Bard
問題:將截斷字串直接串接在 Error 訊息中若處理不當易造成混淆,變數名稱
snippet語義不明確。建議:建議在錯誤訊息中對片段內容進行適當標記,並將變數更名為
contentSnippet。@@ -66,1 +66,3 @@throw new Error(`release API 回傳資料無法解析 (page=${page})`);// 附上截斷的回傳內容片段,便於除錯回傳格式異常const snippet = text.slice(0, 200);throw new Error(`release API 回傳資料無法解析 (page=${page}): ${snippet}`);嚴重等級:🔴 嚴重
審查員:Maya
問題:新增的異常處理邏輯截斷了
text為 200 字元,但在text為極大值或無法轉為字串時未進行防禦性檢查,且截斷點可能將多位元組字元拆分導致亂碼。建議:請確保
text是字串後再截斷,並使用正確處理多位元組字元的方式(如Array.from(text).slice(0, 200).join(''))以避免亂碼。@@ -68,0 +81,4 @@assert.throws(() => loadConfig({GITEA_SERVER_URL: 'ftp://gitea.example.com',GITEA_REPOSITORY: 'owner/repo',}), /必須使用 http 或 https/);嚴重等級:🟡 警告
審查員:Maya
問題:缺少針對
assertRepository邊界條件(如空字串、異常格式)的測試。建議:補上
assert.throws測試案例以涵蓋上述邊界條件,確保驗證邏輯完整。@@ -0,0 +5,4 @@const logger = require('../logger');// 暫時攔截 process.stdout.write,回傳期間內寫出的內容嚴重等級:🟡 警告
審查員:Leo
問題:在測試中使用 monkey-patch 直接覆蓋
process.stdout.write或process.stderr.write是極度危險的模式,可能導致狀態污染;且針對logger.error的測試不夠全面。建議:建議重構
logger使其支援依賴注入;並增加針對錯誤內容包含情況及非字串參數的斷言測試。@@ -0,0 +7,4 @@// 暫時攔截 process.stdout.write,回傳期間內寫出的內容function captureStdout(fn) {const original = process.stdout.write;嚴重等級:🔵 建議
審查員:Bard
問題:測試工具函式
captureStdout與captureStderr邏輯高度重複,不符合 DRY 原則。建議:建議抽取出通用的
captureStream(stream, fn)函式以提升可維護性。Pull request closed