Merge pull request 'chore: refine pipeline stage logs' (#119) from feat/美化輸出 into develop
Reviewed-on: #119
This commit is contained in:
@@ -329,5 +329,15 @@
|
||||
"role": "Leo",
|
||||
"location": "action.yaml:80",
|
||||
"suggestion": "在 `runs.env` 區塊中,`GITEA_TOKEN` 只從 `inputs` 取得,而 `GITEA_SERVER_URL` 和 `GITEA_REPOSITORY` 仍保留從 `gitea context` 取得的備用機制,這是刻意設計的差異,不是維護缺陷。"
|
||||
},
|
||||
{
|
||||
"role": "Rex",
|
||||
"location": "action.yaml:18",
|
||||
"suggestion": "引入 `GITEA_COMMENT_TOKEN` 是一個很好的實踐,遵循最小權限原則。請確保為此 token 配置的權限確實僅限於發布評論。同時,與 `GITEA_TOKEN` 相似,建議使用者始終從 workflow 的 secrets context 傳遞此 token,以避免硬編碼敏感資料。"
|
||||
},
|
||||
{
|
||||
"role": "Leo",
|
||||
"location": "app/log.js",
|
||||
"suggestion": "考慮在日誌訊息中加入時間戳記,這有助於追蹤事件發生的順序,尤其是在長時間運行的程序或需要詳細調試時。可以在每個日誌函式內部自動添加時間戳記。"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,23 +1,16 @@
|
||||
[
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Rex",
|
||||
"location": "action.yaml:18",
|
||||
"suggestion": "引入 GITEA_COMMENT_TOKEN 是一個很好的實踐,遵循最小權限原則。請確保為此 token 配置的權限確實僅限於發布評論。同時,與 GITEA_TOKEN 類似,建議使用者始終從 workflow 的 secrets context 傳遞此 token,以避免硬編碼敏感資料。",
|
||||
"role": "Maya",
|
||||
"location": "app/log.js",
|
||||
"suggestion": "log.js 檔案中的 ok, warn, error 函數是應用程式的日誌工具。雖然功能簡單,但為這些工具函數編寫單元測試是一個良好的實踐,以確保它們正確地呼叫 console 對應的方法(如 console.log, console.warn, console.error)並輸出預期的格式。這有助於防止未來意外的行為變更。",
|
||||
"is_new": false
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Leo",
|
||||
"location": "app/log.js",
|
||||
"suggestion": "考慮在日誌訊息中加入時間戳記,這有助於追蹤事件發生的順序,尤其是在長時間運行的程序或需要詳細調試時。可以在每個日誌函式內部自動添加時間戳記。",
|
||||
"is_new": true
|
||||
},
|
||||
{
|
||||
"level": "info",
|
||||
"role": "Leo",
|
||||
"location": "app/log.js:19",
|
||||
"suggestion": "在 `warn` 函式中使用 `console.warn` 而非 `console.log`。雖然目前功能相同,但 `console.warn` 在某些環境下(例如瀏覽器開發者工具)會以不同的樣式呈現警告訊息,有助於區分不同嚴重程度的日誌。",
|
||||
"role": "Maya",
|
||||
"location": "app/log.test.js",
|
||||
"suggestion": "`log.test.js` 的新增非常棒,提供了良好的覆蓋率。為了進一步提升測試的完整性,建議考慮為 `line`, `ok`, `warn`, `error` 函數新增測試案例,以驗證當傳入空字串時的行為。雖然這些函數的行為相對簡單,但測試空字串可以確保邊界情況下的輸出符合預期。",
|
||||
"is_new": true
|
||||
}
|
||||
]
|
||||
|
||||
+5
-1
@@ -185,12 +185,16 @@ describe('commitAndPush', () => {
|
||||
});
|
||||
const logs = [];
|
||||
const originalLog = console.log;
|
||||
console.log = (...args) => { logs.push(args.join(' ')); };
|
||||
const originalWarn = console.warn;
|
||||
const capture = (...args) => { logs.push(args.join(' ')); };
|
||||
console.log = capture;
|
||||
console.warn = capture;
|
||||
|
||||
try {
|
||||
await commitAndPush(workspace, repoDir, spawn, sourceRoot);
|
||||
} finally {
|
||||
console.log = originalLog;
|
||||
console.warn = originalWarn;
|
||||
}
|
||||
|
||||
assert.ok(logs.some(line => line.includes('Step7 commit 成功但 push 失敗')));
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ export function ok(message) {
|
||||
}
|
||||
|
||||
export function warn(message) {
|
||||
console.log(` ! ${message}`);
|
||||
console.warn(` ! ${message}`);
|
||||
}
|
||||
|
||||
export function error(message) {
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import { describe, it, afterEach, mock } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { section, step, line, ok, warn, error } from './log.js';
|
||||
|
||||
afterEach(() => mock.restoreAll());
|
||||
|
||||
describe('log helpers', () => {
|
||||
it('formats section and step messages', () => {
|
||||
const calls = [];
|
||||
mock.method(console, 'log', (...args) => {
|
||||
calls.push(args.join(' '));
|
||||
});
|
||||
|
||||
section('Pipeline');
|
||||
step('Step1', 'Start');
|
||||
|
||||
assert.deepEqual(calls, [
|
||||
'\n=== Pipeline ===',
|
||||
'\n[Step1] Start',
|
||||
]);
|
||||
});
|
||||
|
||||
it('formats line and ok messages with console.log', () => {
|
||||
const calls = [];
|
||||
mock.method(console, 'log', (...args) => {
|
||||
calls.push(args.join(' '));
|
||||
});
|
||||
|
||||
line('hello');
|
||||
ok('done');
|
||||
|
||||
assert.deepEqual(calls, [
|
||||
' - hello',
|
||||
' ✓ done',
|
||||
]);
|
||||
});
|
||||
|
||||
it('formats warn messages with console.warn', () => {
|
||||
const calls = [];
|
||||
mock.method(console, 'warn', (...args) => {
|
||||
calls.push(args.join(' '));
|
||||
});
|
||||
|
||||
warn('careful');
|
||||
|
||||
assert.deepEqual(calls, [' ! careful']);
|
||||
});
|
||||
|
||||
it('formats error messages with console.error', () => {
|
||||
const calls = [];
|
||||
mock.method(console, 'error', (...args) => {
|
||||
calls.push(args.join(' '));
|
||||
});
|
||||
|
||||
error('boom');
|
||||
|
||||
assert.deepEqual(calls, [' x boom']);
|
||||
});
|
||||
});
|
||||
+2
-4
@@ -76,7 +76,7 @@ async function main() {
|
||||
}
|
||||
ok(`Step2 完成: 新 findings 總計 ${newFindings.length} 筆`);
|
||||
|
||||
step('Step3', 'Findings 合併');
|
||||
step('Step3', 'Findings 合併與語意去重');
|
||||
let repoDir;
|
||||
try {
|
||||
repoDir = cloneRepo(WORKSPACE);
|
||||
@@ -90,11 +90,9 @@ async function main() {
|
||||
const oldFindings = loadOldFindings(repoDir || WORKSPACE);
|
||||
const mergedFindings = mergeFindings(oldFindings, newFindings);
|
||||
ok(`Step3 merged findings total=${mergedFindings.length}`);
|
||||
|
||||
step('Step3b', 'AI 語意去重');
|
||||
const deduped = await deduplicateWithAI(mergedFindings);
|
||||
const sorted = sortByLevel(deduped);
|
||||
ok(`Step3b dedup findings total=${sorted.length} (critical=${sorted.filter(f=>f.level==='critical').length} warning=${sorted.filter(f=>f.level==='warning').length} info=${sorted.filter(f=>f.level==='info').length})`);
|
||||
ok(`Step3 去重完成: ${mergedFindings.length} -> ${sorted.length} 筆 (critical=${sorted.filter(f=>f.level==='critical').length} warning=${sorted.filter(f=>f.level==='warning').length} info=${sorted.filter(f=>f.level==='info').length})`);
|
||||
|
||||
step('Step4', 'AI 排除問題過濾');
|
||||
const exclusions = loadExclusions(repoDir || WORKSPACE, repoState);
|
||||
|
||||
Reference in New Issue
Block a user