refactor(release-cleanup): 將清理邏輯由 bash 改寫為 Node.js #6

Closed
jiantw83 wants to merge 60 commits from refactor/nodejs-rewrite-20260626-103443 into develop
3 changed files with 11 additions and 2 deletions
Showing only changes of commit aa4f6364e2 - Show all commits
+7
View File
@@ -4,6 +4,9 @@
// 單一 HTTP 請求的逾時(毫秒)。避免 API 緩慢或掛起時容器永久卡死。 // 單一 HTTP 請求的逾時(毫秒)。避免 API 緩慢或掛起時容器永久卡死。
const REQUEST_TIMEOUT_MS = 30000 const REQUEST_TIMEOUT_MS = 30000
// 分頁讀取的最大頁數上限,作為安全斷點:即使 API 異常未以空陣列結尾,也不致無限迴圈耗盡資源。
const MAX_PAGES = 1000
/** /**
* 將回應內容整理成可安全寫入錯誤訊息的片段:移除控制字元(避免換行等造成的 log 注入)並限制長度。 * 將回應內容整理成可安全寫入錯誤訊息的片段:移除控制字元(避免換行等造成的 log 注入)並限制長度。
* @param {string} text 原始回應文字 * @param {string} text 原始回應文字
@@ -49,6 +52,10 @@ export class GiteaClient {
let page = 1 let page = 1
while (true) { while (true) {
if (page > MAX_PAGES) {
throw new Error(`GET ${baseUrl} exceeded MAX_PAGES (${MAX_PAGES}); aborting to avoid an unbounded loop`)
}
const url = `${baseUrl}?page=${page}` const url = `${baseUrl}?page=${page}`
const res = await fetch(url, { const res = await fetch(url, {
headers: this.headers, headers: this.headers,
1
+2 -1
View File
3
@@ -56,7 +56,8 @@ export async function cleanupReleases(client, config) {
continue continue
} }
const url = `${config.releaseApiUrl}/${id}` // 對 id 做編碼,避免非預期內容被拼接進 URL(防路徑穿越);正常數值 id 編碼後不變。
const url = `${config.releaseApiUrl}/${encodeURIComponent(id)}`
info(`DELETE ${tag} (${name})`) info(`DELETE ${tag} (${name})`)
const code = await client.deleteResource(url) const code = await client.deleteResource(url)
+2 -1
View File
4
@@ -61,7 +61,8 @@ export async function cleanupOrphanTags(client, config) {
continue continue
} }
const url = `${config.tagApiUrl}/${tag.name}` // 對 tag 名稱做編碼,避免名稱中的特殊字元被拼接進 URL(防路徑穿越);一般 tag 名編碼後不變。
const url = `${config.tagApiUrl}/${encodeURIComponent(tag.name)}`
info(`DELETE tag ${tag.name}`) info(`DELETE tag ${tag.name}`)
const code = await client.deleteResource(url) const code = await client.deleteResource(url)