重新整理 cleanup-release 動作與文件 #1

Merged
admin merged 18 commits from ai-review-resolve/develop-20260711-131608 into develop 2026-07-15 02:38:32 +00:00
Showing only changes of commit bfeea4c2a9 - Show all commits
+14 -4
View File
1
@@ -12,6 +12,8 @@ const taipeiFormatter = new Intl.DateTimeFormat('en-CA', {
}); });
admin marked this conversation as resolved Outdated
Outdated
Review

嚴重等級🟡 警告
審查員:Rogue
問題formatTaipeiTimestamp() 每次 log 都重新建立 Intl.DateTimeFormat 並跑 formatToParts,這在 release/tag 迴圈裡會被反覆觸發,等於把本來可重用的格式器成本重算 N 次。
建議:把 Intl.DateTimeFormat 提到函式外快取成單例,讓每次只做時間格式化,不要重建 formatter。

**嚴重等級**:🟡 警告 **審查員**:Rogue **問題**:`formatTaipeiTimestamp()` 每次 log 都重新建立 `Intl.DateTimeFormat` 並跑 `formatToParts`,這在 release/tag 迴圈裡會被反覆觸發,等於把本來可重用的格式器成本重算 N 次。 **建議**:把 `Intl.DateTimeFormat` 提到函式外快取成單例,讓每次只做時間格式化,不要重建 formatter。
let currentStage = ''; let currentStage = '';
let cachedTimestampKey = '';
let cachedTimestampValue = '';
/** /**
* 格式化台灣時區時間,供 log 使用。 * 格式化台灣時區時間,供 log 使用。
@@ -20,6 +22,11 @@ let currentStage = '';
* @returns {string} `yyyy/MM/dd HH:mm:ss` 格式時間字串。 * @returns {string} `yyyy/MM/dd HH:mm:ss` 格式時間字串。
*/ */
function formatTaipeiTimestamp(date = new Date()) { function formatTaipeiTimestamp(date = new Date()) {
const timestampKey = date.toISOString().slice(0, 19);
admin marked this conversation as resolved Outdated
Outdated
Review

嚴重等級🟡 警告
審查員:Rogue
問題:每次輸出一條 log 都要跑 Intl.DateTimeFormat.formatToParts(),還額外建立 lookup 物件再組字串;這條熱路徑會在每個 release、tag 與錯誤訊息上重複消耗 CPU,訊息一多就很浪費。
建議:把時間格式改成可快取的字串產生方式,例如同一秒共用結果,或改用較便宜的 formatter,不要每條 log 都做 formatToParts() 拆解。

**嚴重等級**:🟡 警告 **審查員**:Rogue **問題**:每次輸出一條 log 都要跑 `Intl.DateTimeFormat.formatToParts()`,還額外建立 `lookup` 物件再組字串;這條熱路徑會在每個 release、tag 與錯誤訊息上重複消耗 CPU,訊息一多就很浪費。 **建議**:把時間格式改成可快取的字串產生方式,例如同一秒共用結果,或改用較便宜的 formatter,不要每條 log 都做 `formatToParts()` 拆解。
if (timestampKey === cachedTimestampKey) {
return cachedTimestampValue;
}
const parts = taipeiFormatter.formatToParts(date); const parts = taipeiFormatter.formatToParts(date);
const lookup = {}; const lookup = {};
@@ -29,7 +36,9 @@ function formatTaipeiTimestamp(date = new Date()) {
} }
} }
return `${lookup.year}/${lookup.month}/${lookup.day} ${lookup.hour}:${lookup.minute}:${lookup.second}`; cachedTimestampKey = timestampKey;
cachedTimestampValue = `${lookup.year}/${lookup.month}/${lookup.day} ${lookup.hour}:${lookup.minute}:${lookup.second}`;
return cachedTimestampValue;
} }
/** /**
40
@@ -348,6 +357,10 @@ async function main() {
}); });
} }
if (hadFailure) {
throw new Error('至少有一筆 release 或 tag 刪除失敗');
}
admin marked this conversation as resolved Outdated
Outdated
Review

嚴重等級🟡 警告
審查員:Rogue
問題releaseJson.sort(...) 先把所有 release 做完整排序,成本是 O(n log n),但後面其實只用前 KEEP_COUNT 筆。當 release 很多時,這段排序就是多花 CPU 在不必要的全量比較上。
建議:改用固定大小的 top-K 選擇策略,例如維持一個大小為 KEEP_COUNT 的最小堆,或在 API 已經有新到舊順序時直接取前 KEEP_COUNT 筆,避免整體排序。

**嚴重等級**:🟡 警告 **審查員**:Rogue **問題**:`releaseJson.sort(...)` 先把所有 release 做完整排序,成本是 O(n log n),但後面其實只用前 `KEEP_COUNT` 筆。當 release 很多時,這段排序就是多花 CPU 在不必要的全量比較上。 **建議**:改用固定大小的 top-K 選擇策略,例如維持一個大小為 `KEEP_COUNT` 的最小堆,或在 API 已經有新到舊順序時直接取前 `KEEP_COUNT` 筆,避免整體排序。
section('刪除未指定 release 的 tag'); section('刪除未指定 release 的 tag');
const releaseTags = new Set( const releaseTags = new Set(
1
@@ -388,9 +401,6 @@ async function main() {
} }
}); });
if (hadFailure) {
throw new Error('至少有一筆 release 或 tag 刪除失敗');
}
} }
main().catch((error) => { main().catch((error) => {
1