docs(release-cleanup): 補齊 config/gitea-client/releases/tags 的 JSDoc
為 loadConfig、GiteaClient(含 fetchAllPages/deleteResource)、 selectReleasesToDelete/cleanupReleases、categorizeTags/cleanupOrphanTags 補上完整 JSDoc(參數、回傳、例外、行為說明)。僅註解變更。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
7082fd7311
commit
7e6f9ef3f6
+11
-3
@@ -5,9 +5,17 @@ import { isEmptyOrNull, requireValue, requireInteger } from './validate.js'
|
|||||||
import { section, info, warn } from './logger.js'
|
import { section, info, warn } from './logger.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 從環境變數載入設定並完成驗證。
|
* 從環境變數載入設定並完成驗證,作為整個清理流程的設定來源。
|
||||||
* @param {NodeJS.ProcessEnv} env 環境變數來源,預設為 process.env
|
*
|
||||||
* @returns 包含 API 位址、token、保留數量等資訊的設定物件
|
* 讀取 `GITEA_SERVER_URL`、`GITEA_REPOSITORY`、`KEEP_COUNT`、`GITEA_TOKEN`,
|
||||||
|
* 其中前三者為必填(`KEEP_COUNT` 另須為非負整數);`GITEA_TOKEN` 為選填,
|
||||||
|
* 為空時改以匿名方式呼叫 API。驗證過程會將參數印出(token 以 `[redacted]` 遮蔽)。
|
||||||
|
*
|
||||||
|
* @param {NodeJS.ProcessEnv} env 環境變數來源,預設為 `process.env`,可於測試時注入假值
|
||||||
|
* @returns {{serverUrl: string, repository: string, token: string|null, keepCount: number, releaseApiUrl: string, tagApiUrl: string}}
|
||||||
|
* 設定物件:`token` 在環境變數為空時為 `null`;`keepCount` 為數值;
|
||||||
|
* `releaseApiUrl`/`tagApiUrl` 為依 server 與 repository 組出的 API 位址。
|
||||||
|
* @throws {Error} 任一必填項缺漏,或 `KEEP_COUNT` 非非負整數時拋出(由 [[validate]] 的檢查函式丟出)
|
||||||
*/
|
*/
|
||||||
export function loadConfig(env = process.env) {
|
export function loadConfig(env = process.env) {
|
||||||
section('參數檢查')
|
section('參數檢查')
|
||||||
|
|||||||
+17
-6
@@ -1,9 +1,15 @@
|
|||||||
// 與 Gitea API 溝通的 HTTP 客戶端,封裝認證標頭、分頁讀取與刪除請求。
|
// 與 Gitea API 溝通的 HTTP 客戶端,封裝認證標頭、分頁讀取與刪除請求。
|
||||||
// 對應原本 entrypoint.sh 的 fetch_all_pages 與 curl DELETE 呼叫。
|
// 對應原本 entrypoint.sh 的 fetch_all_pages 與 curl DELETE 呼叫。
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 與 Gitea REST API 溝通的輕量 HTTP 客戶端,負責帶上認證標頭、分頁讀取清單與發出刪除請求。
|
||||||
|
* 取代原 bash 版本以 `curl`/`jq` 進行的 API 操作。
|
||||||
|
*/
|
||||||
export class GiteaClient {
|
export class GiteaClient {
|
||||||
/**
|
/**
|
||||||
* @param {{ token?: string | null }} options 認證設定;有 token 時帶上 Authorization 標頭
|
* 建立客戶端;有 token 時於後續所有請求帶上 `Authorization: token <token>` 標頭,
|
||||||
|
* 無 token(或為 `null`)時以匿名方式呼叫。
|
||||||
|
* @param {{ token?: string | null }} [options] 認證設定
|
||||||
*/
|
*/
|
||||||
constructor({ token = null } = {}) {
|
constructor({ token = null } = {}) {
|
||||||
this.headers = {}
|
this.headers = {}
|
||||||
@@ -13,9 +19,14 @@ export class GiteaClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 逐頁讀取分頁式清單 API,直到回傳空陣列為止,合併成單一陣列。
|
* 逐頁讀取分頁式清單 API(每頁以 `?page=N` 由 1 遞增),直到某頁回傳空陣列(或非陣列)為止,
|
||||||
* @param {string} baseUrl 不含 query string 的 API 位址
|
* 將所有頁面項目合併成單一陣列回傳。
|
||||||
* @returns {Promise<any[]>} 所有頁面合併後的項目
|
*
|
||||||
|
* 注意:終止條件依賴「空陣列代表最後一頁」的假設;若 API 不以空陣列結尾則迴圈不會自然停止。
|
||||||
|
*
|
||||||
|
* @param {string} baseUrl 不含 query string 的 API 位址(本方法會自行附加 `?page=N`)
|
||||||
|
* @returns {Promise<any[]>} 所有頁面合併後的項目陣列;無資料時為空陣列
|
||||||
|
* @throws {Error} 任一頁回應 HTTP 非 2xx(`!res.ok`)時拋出,訊息含 URL 與狀態碼
|
||||||
*/
|
*/
|
||||||
async fetchAllPages(baseUrl) {
|
async fetchAllPages(baseUrl) {
|
||||||
const all = []
|
const all = []
|
||||||
@@ -42,9 +53,9 @@ export class GiteaClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 對指定資源發出 DELETE 請求。
|
* 對指定資源發出 DELETE 請求,僅回傳 HTTP 狀態碼供呼叫端判斷成敗(不檢查 ok、不解析回應內容)。
|
||||||
* @param {string} url 目標資源位址
|
* @param {string} url 目標資源位址
|
||||||
* @returns {Promise<number>} HTTP 狀態碼
|
* @returns {Promise<number>} 回應的 HTTP 狀態碼(成功刪除通常為 204)
|
||||||
*/
|
*/
|
||||||
async deleteResource(url) {
|
async deleteResource(url) {
|
||||||
const res = await fetch(url, { method: 'DELETE', headers: this.headers })
|
const res = await fetch(url, { method: 'DELETE', headers: this.headers })
|
||||||
|
|||||||
+14
-8
@@ -5,11 +5,11 @@ import { section, info, success, fail, warn } from './logger.js'
|
|||||||
import { isEmptyOrNull } from './validate.js'
|
import { isEmptyOrNull } from './validate.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 依建立時間由新到舊排序,保留最新的 keepCount 筆,回傳其餘待刪除的成品。
|
* 依 `created_at` 建立時間由新到舊排序,保留最新的 `keepCount` 筆,回傳其餘(較舊)待刪除的成品。
|
||||||
* 純函式,方便單元測試。
|
* 以展開運算子複製陣列後再排序,不會改動傳入的原陣列。為純函式,方便單元測試。
|
||||||
* @param {any[]} releases 成品清單
|
* @param {any[]} releases 成品清單,每個元素預期含有 `created_at` 欄位
|
||||||
* @param {number} keepCount 要保留的筆數
|
* @param {number} keepCount 要保留的最新筆數;為 0 時代表全部刪除
|
||||||
* @returns {any[]} 需要刪除的成品(較舊者)
|
* @returns {any[]} 需要刪除的成品陣列(較舊者),依新到舊排序
|
||||||
*/
|
*/
|
||||||
export function selectReleasesToDelete(releases, keepCount) {
|
export function selectReleasesToDelete(releases, keepCount) {
|
||||||
const sorted = [...releases].sort(
|
const sorted = [...releases].sort(
|
||||||
@@ -19,9 +19,15 @@ export function selectReleasesToDelete(releases, keepCount) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 讀取成品清單,刪除超出保留數量的舊版本成品。
|
* 讀取全部成品清單,刪除超出保留數量的舊版本成品。
|
||||||
* @param {import('./gitea-client.js').GiteaClient} client
|
*
|
||||||
* @param {ReturnType<import('./config.js').loadConfig>} config
|
* 流程:取得所有 release → 若總數不超過 `keepCount` 則直接結束(無需清理)→
|
||||||
|
* 否則以 [[selectReleasesToDelete]] 取出待刪除清單,逐筆刪除(略過沒有 `id` 的項目),
|
||||||
|
* 依回應狀態碼 204 判定成功與否並輸出結果。
|
||||||
|
*
|
||||||
|
* @param {import('./gitea-client.js').GiteaClient} client 用於讀取與刪除的 Gitea 客戶端
|
||||||
|
* @param {ReturnType<import('./config.js').loadConfig>} config 設定物件,使用其 `releaseApiUrl` 與 `keepCount`
|
||||||
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
export async function cleanupReleases(client, config) {
|
export async function cleanupReleases(client, config) {
|
||||||
section('取得成品資訊')
|
section('取得成品資訊')
|
||||||
|
|||||||
+17
-9
@@ -5,12 +5,14 @@ import { section, info, success, fail, warn } from './logger.js'
|
|||||||
import { isEmptyOrNull } from './validate.js'
|
import { isEmptyOrNull } from './validate.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 將 tag 分類為保留、刪除或略過(無名稱)。
|
* 將每個 tag 分類為保留、刪除或略過三類,判斷優先序為:無名稱 → skip、仍被指定 → keep、其餘 → delete。
|
||||||
* 仍被任一 release 指定的 tag 予以保留,其餘視為孤立 tag 待刪除。
|
*
|
||||||
* 純函式,方便單元測試。
|
* 先把 `releaseTagNames` 收進 `Set` 以利 O(1) 比對;名稱經 [[isEmptyOrNull]] 判定為空者標為 `skip`,
|
||||||
* @param {any[]} tags tag 清單
|
* 仍被任一 release 指定者標為 `keep`,其餘視為孤立 tag 標為 `delete`。為純函式,無副作用,方便單元測試。
|
||||||
* @param {Iterable<string>} releaseTagNames 仍被 release 指定的 tag 名稱
|
*
|
||||||
* @returns {{ tag: any, action: 'keep' | 'delete' | 'skip' }[]}
|
* @param {any[]} tags tag 清單,每個元素預期含有 `name` 欄位
|
||||||
|
* @param {Iterable<string>} releaseTagNames 仍被 release 指定的 tag 名稱集合
|
||||||
|
* @returns {{ tag: any, action: 'keep' | 'delete' | 'skip' }[]} 與輸入等長且保持原順序的分類結果
|
||||||
*/
|
*/
|
||||||
export function categorizeTags(tags, releaseTagNames) {
|
export function categorizeTags(tags, releaseTagNames) {
|
||||||
const keep = new Set(releaseTagNames)
|
const keep = new Set(releaseTagNames)
|
||||||
@@ -27,9 +29,15 @@ export function categorizeTags(tags, releaseTagNames) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重新讀取成品清單以取得仍被指定的 tag,再刪除未指定 release 的孤立 tag。
|
* 重新讀取成品清單以取得仍被指定的 tag,再刪除未被任何 release 指定的孤立 tag。
|
||||||
* @param {import('./gitea-client.js').GiteaClient} client
|
*
|
||||||
* @param {ReturnType<import('./config.js').loadConfig>} config
|
* 流程:重新抓取全部 release(反映刪除舊版本後的最新狀態)並取出其 `tag_name` 集合 →
|
||||||
|
* 抓取全部 tag → 以 [[categorizeTags]] 分類,對 `skip` 警告略過、`keep` 保留,
|
||||||
|
* 對 `delete` 發出刪除並依狀態碼 204 判定成功與否。
|
||||||
|
*
|
||||||
|
* @param {import('./gitea-client.js').GiteaClient} client 用於讀取與刪除的 Gitea 客戶端
|
||||||
|
* @param {ReturnType<import('./config.js').loadConfig>} config 設定物件,使用其 `releaseApiUrl` 與 `tagApiUrl`
|
||||||
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
export async function cleanupOrphanTags(client, config) {
|
export async function cleanupOrphanTags(client, config) {
|
||||||
section('刪除未指定 release 的 tag')
|
section('刪除未指定 release 的 tag')
|
||||||
|
|||||||
Reference in New Issue
Block a user