Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f1c21beed5 | |||
| 3c3019d1ab | |||
| 41a8fe100f | |||
| c1c00449af | |||
| ef3654b091 | |||
| 5d0c9fd691 | |||
| 5860588588 | |||
| 53a7ec7a3e | |||
| 42241c5000 | |||
| 1a12ec4e2e | |||
| a90886e924 |
+122
-45
@@ -1,72 +1,149 @@
|
||||
[
|
||||
{
|
||||
"level": "critical",
|
||||
"role": "Leo",
|
||||
"location": "app/config.js:7",
|
||||
"suggestion": "請確保 EXCLUSIONS_PATH 的值不包含敏感資訊,並使用環境變數來管理敏感資料。",
|
||||
"is_new": true
|
||||
},
|
||||
{
|
||||
"level": "critical",
|
||||
"role": "Maya",
|
||||
"location": "app/git.js:1",
|
||||
"suggestion": "缺少對 commitAndPush 函數的單元測試,應該為其添加測試以確保其正確性。",
|
||||
"is_new": true
|
||||
},
|
||||
{
|
||||
"level": "warning",
|
||||
"role": "Zara",
|
||||
"location": "app/findings.js:40",
|
||||
"suggestion": "在 applyExclusions 函數中,使用 filter 和 some 方法的組合可能會導致效能問題,特別是當 findings 和 exclusions 的數量很大時。考慮使用更有效的資料結構(如 HashSet)來加速查詢。",
|
||||
"role": "Rex",
|
||||
"location": "app/git.js:14",
|
||||
"suggestion": "請避免將敏感資料(如 GITEA_TOKEN)直接寫入程式碼,應使用安全的秘密管理工具來管理這些敏感資訊。",
|
||||
"is_new": true
|
||||
},
|
||||
{
|
||||
"level": "warning",
|
||||
"role": "Rex",
|
||||
"location": "app/findings.js:40",
|
||||
"suggestion": "在讀取排除問題檔案時,建議加入對檔案內容的驗證,以防止不正確的格式導致潛在的錯誤或漏洞。",
|
||||
"location": "app/git.js:14",
|
||||
"suggestion": "在 cloneRepo 函數中,請確保 GIT_TOKEN 不會被寫入到檔案系統中,避免敏感資訊洩漏。",
|
||||
"is_new": true
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Leo",
|
||||
"location": "app/findings.js:1",
|
||||
"suggestion": "建議在檔案開頭添加檔案的功能描述,以提高可讀性。",
|
||||
"is_new": true
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Leo",
|
||||
"location": "app/findings.js:40",
|
||||
"suggestion": "建議為 loadExclusions 函式添加詳細的文件說明,以便未來的開發者能更快理解其功能。",
|
||||
"is_new": true
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"level": "warning",
|
||||
"role": "Leo",
|
||||
"location": "app/findings.js:93",
|
||||
"suggestion": "建議為 deduplicateWithAI 函式添加詳細的文件說明,以便未來的開發者能更快理解其功能。",
|
||||
"is_new": true
|
||||
"suggestion": "建議在 loadExclusions 函式中增加對於 JSON 格式的驗證,確保讀取的資料符合預期格式,避免潛在的錯誤。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "warning",
|
||||
"role": "Leo",
|
||||
"location": "app/findings.js:40",
|
||||
"suggestion": "在 applyExclusions 函式中,建議增加對於 findings 和 exclusions 參數的有效性檢查,以提高程式的健壯性。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "warning",
|
||||
"role": "Zara",
|
||||
"location": "app/findings.js:40",
|
||||
"suggestion": "在 applyExclusions 函數中,使用 Array.prototype.some 進行過濾時,可能會導致性能問題,特別是當 findings 和 exclusions 的數量都很大時。建議使用更高效的資料結構(如 HashSet)來加速查詢。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "warning",
|
||||
"role": "Aria",
|
||||
"location": "README.md:4",
|
||||
"suggestion": "建議將「讀取排除問題檔案,用來過濾PR問題表格中不需要處理的問題」的描述改為「讀取排除問題檔案,過濾 PR 問題表格中不需要處理的問題」,以保持一致性。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "warning",
|
||||
"role": "Maya",
|
||||
"location": "app/findings.js:40",
|
||||
"suggestion": "建議在 applyExclusions 函數中增加對 findings 內容的驗證,確保其格式正確,以提高測試的穩定性和可靠性。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Leo",
|
||||
"location": "README.md",
|
||||
"suggestion": "建議在 README 中增加對於新功能(如排除問題過濾)的詳細說明,以便未來的維護者能快速了解其功能。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Leo",
|
||||
"location": "app/main.js",
|
||||
"suggestion": "建議在 main 函式中增加對於每個步驟的詳細註解,讓未來的維護者能更容易理解程式邏輯。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Zara",
|
||||
"location": "app/findings.js:39",
|
||||
"suggestion": "在過濾 findings 時,建議將過濾條件的邏輯提取為獨立函數,以提高可讀性和可維護性。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Zara",
|
||||
"location": "app/main.js:64",
|
||||
"suggestion": "在讀取排除問題檔案時,建議考慮使用非同步方法(如 fs.promises.readFile)來避免阻塞事件循環,提升效能。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Aria",
|
||||
"location": "README.md:10",
|
||||
"suggestion": "建議在每個步驟後添加簡短的描述,以提高可讀性和理解性。",
|
||||
"is_new": true
|
||||
"location": "README.md:8",
|
||||
"suggestion": "建議將「如果PR問題表格中有嚴重問題,則不要讓 workflow 執行成功(exit 1)」的描述改為「如果 PR 問題表格中有嚴重問題,則不要讓 workflow 執行成功(exit 1)」以提高可讀性。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Aria",
|
||||
"location": "app/config.js:7",
|
||||
"suggestion": "建議在常數命名中使用全大寫字母和底線分隔,以提高可讀性。",
|
||||
"is_new": true
|
||||
"location": "TODO.md:4",
|
||||
"suggestion": "建議將「階段四:findings 寫入與 comment 發布」的標題改為「階段四:排除問題過濾」,以更清楚地反映內容。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Aria",
|
||||
"location": "TODO.md:6",
|
||||
"suggestion": "建議將「階段五:findings 寫入與 comment 發布」的標題改為「階段五:findings 寫入與 comment 發布」,以保持一致性。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Aria",
|
||||
"location": "TODO.md:8",
|
||||
"suggestion": "建議將「階段六:記憶區 commit/push 與錯誤處理」的標題改為「階段六:記憶區 commit/push 與錯誤處理」,以保持一致性。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Aria",
|
||||
"location": "TODO.md:10",
|
||||
"suggestion": "建議將「階段七:阻擋嚴重問題 PR(第 8 點)」的標題改為「階段七:阻擋嚴重問題 PR(第 8 點)」以保持一致性。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Aria",
|
||||
"location": "app/config.js",
|
||||
"suggestion": "建議在 EXCLUSIONS_PATH 的定義上方添加註解,說明該常數的用途,以提高可讀性。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Aria",
|
||||
"location": "app/findings.js",
|
||||
"suggestion": "建議在 loadExclusions 函數的開頭添加註解,說明該函數的用途,以提高可讀性。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Aria",
|
||||
"location": "app/findings.js",
|
||||
"suggestion": "建議在 applyExclusions 函數的開頭添加註解,說明該函數的用途,以提高可讀性。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Maya",
|
||||
"location": "app/main.js:50",
|
||||
"suggestion": "建議在發佈 comment 失敗時,記錄具體的錯誤原因,以便後續調試。",
|
||||
"is_new": true
|
||||
"location": "app/findings.js:7",
|
||||
"suggestion": "建議為 loadExclusions 和 applyExclusions 函數撰寫單元測試,以確保其功能正確並能處理邊界條件。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Maya",
|
||||
"location": "app/main.js:48",
|
||||
"suggestion": "建議在每個主要步驟之後增加測試用例,以驗證每個步驟的輸出是否符合預期。",
|
||||
"is_new": false
|
||||
}
|
||||
]
|
||||
+2
-2
@@ -124,8 +124,8 @@ export function applyExclusions(findings, exclusions) {
|
||||
const before = findings.length;
|
||||
const filtered = findings.filter(f => !exclusions.some(ex =>
|
||||
(!ex.role || ex.role === f.role) &&
|
||||
(!ex.location || ex.location === f.location) &&
|
||||
(!ex.suggestion || String(f.suggestion).startsWith(String(ex.suggestion).slice(0, 50)))
|
||||
(!ex.location || String(f.location).includes(ex.location)) &&
|
||||
(!ex.suggestion || String(f.suggestion).includes(String(ex.suggestion).slice(0, 20)))
|
||||
));
|
||||
console.log(` 排除過濾: ${before} -> ${filtered.length} 筆(排除 ${before - filtered.length} 筆)`);
|
||||
return filtered;
|
||||
|
||||
+28
@@ -14,6 +14,34 @@ function makeRunner(spawn) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone PR head branch to workspace/repo (idempotent)
|
||||
*/
|
||||
export function cloneRepo(workspace, _spawnSync = spawnSync) {
|
||||
const run = makeRunner(_spawnSync);
|
||||
const baseUrl = GITEA_SERVER_URL.replace(/\/$/, '');
|
||||
const remoteUrl = `${baseUrl}/${GITEA_REPOSITORY}.git`;
|
||||
const repoDir = path.join(workspace, 'repo');
|
||||
|
||||
const askpassScript = path.join(workspace, '.git-askpass.sh');
|
||||
fs.writeFileSync(askpassScript, '#!/bin/sh\necho "$GIT_TOKEN"\n', { mode: 0o700 });
|
||||
const credEnv = { ...process.env, GIT_ASKPASS: askpassScript, GIT_USERNAME: 'x-token', GIT_TOKEN: GITEA_TOKEN };
|
||||
|
||||
try {
|
||||
if (!fs.existsSync(repoDir)) {
|
||||
run(['clone', '--depth=1', '--branch', PR_HEAD_BRANCH, remoteUrl, repoDir], workspace, credEnv);
|
||||
console.log(` ✅ repo cloned to ${repoDir}`);
|
||||
} else {
|
||||
run(['fetch', 'origin', PR_HEAD_BRANCH], repoDir, credEnv);
|
||||
run(['checkout', PR_HEAD_BRANCH], repoDir);
|
||||
console.log(` ✅ repo already exists, fetched latest`);
|
||||
}
|
||||
} finally {
|
||||
try { fs.unlinkSync(askpassScript); } catch {}
|
||||
}
|
||||
return repoDir;
|
||||
}
|
||||
|
||||
export async function commitAndPush(workspace, _spawnSync = spawnSync) {
|
||||
const run = makeRunner(_spawnSync);
|
||||
|
||||
|
||||
+10
-3
@@ -3,7 +3,7 @@ import { loadRoles, getRoleIntro } from './roles.js';
|
||||
import { getPRDiff, postComment } from './gitea.js';
|
||||
import { analyzeWithRole, loadOldFindings, mergeFindings, sortByLevel, deduplicateWithAI, loadExclusions, applyExclusions } from './findings.js';
|
||||
import { saveFindings, postOldFindingsComment, postNewNonCriticalComment, postNewCriticalComments } from './comments.js';
|
||||
import { commitAndPush } from './git.js';
|
||||
import { cloneRepo, commitAndPush } from './git.js';
|
||||
|
||||
const WORKSPACE = process.env.GITHUB_WORKSPACE || '/workspace';
|
||||
|
||||
@@ -65,7 +65,14 @@ async function main() {
|
||||
|
||||
// Step3: 讀取舊 findings,合併去重(含 AI 語意去重)
|
||||
console.log('\n🔀 Step3: Findings 合併');
|
||||
const oldFindings = loadOldFindings(WORKSPACE);
|
||||
// Clone repo 以讀取舊 findings 與排除清單
|
||||
let repoDir;
|
||||
try {
|
||||
repoDir = cloneRepo(WORKSPACE);
|
||||
} catch (e) {
|
||||
console.log(` ⚠️ clone repo 失敗(繼續執行): ${e.message}`);
|
||||
}
|
||||
const oldFindings = loadOldFindings(repoDir || WORKSPACE);
|
||||
const mergedFindings = mergeFindings(oldFindings, newFindings);
|
||||
console.log(` Step3 merged findings total=${mergedFindings.length}`);
|
||||
|
||||
@@ -76,7 +83,7 @@ async function main() {
|
||||
|
||||
// Step4: 讀取排除問題檔案,過濾 PR 問題表格
|
||||
console.log('\n🚫 Step4: 排除問題過濾');
|
||||
const exclusions = loadExclusions(WORKSPACE);
|
||||
const exclusions = loadExclusions(repoDir || WORKSPACE);
|
||||
const filtered = applyExclusions(sorted, exclusions);
|
||||
console.log(` Step4 完成: findings total=${filtered.length}`);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user