refactor(release-cleanup): 將清理邏輯由 bash 改寫為 Node.js 模組
依功能分組為 logger/validate/config/gitea-client/releases/tags 模組, entrypoint.sh 改為呼叫 node /app/index.js,Dockerfile 改用 node:20-alpine 基底。 對外行為(清理舊 release 與未指定 release 的 tag)維持不變。 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
b478872c5f
commit
b1aa8730a2
+12
-175
@@ -1,177 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
#!/usr/bin/env sh
|
||||
# =============================================================================
|
||||
# 用途: release-cleanup Action 的容器進入點 (entrypoint)。
|
||||
# 專案已由 bash 改寫為 Node.js,本腳本僅負責啟動 /app/index.js,
|
||||
# 由 Node.js 程式執行實際的 release 清理邏輯。
|
||||
# 更新日期: 2026/06/26 10:28:36
|
||||
# =============================================================================
|
||||
|
||||
separator() {
|
||||
printf '\n%s\n' '=================================================='
|
||||
}
|
||||
# set -e: 任一指令失敗即中止; set -u: 使用未定義變數即報錯。確保失敗能即時暴露。
|
||||
set -eu
|
||||
|
||||
section() {
|
||||
separator
|
||||
printf '%s\n' "$1"
|
||||
printf '%s\n' '--------------------------------------------------'
|
||||
}
|
||||
|
||||
info() {
|
||||
printf '[INFO] %s\n' "$1"
|
||||
}
|
||||
|
||||
success() {
|
||||
printf '[OK] %s\n' "$1"
|
||||
}
|
||||
|
||||
warn() {
|
||||
printf '[WARN] %s\n' "$1"
|
||||
}
|
||||
|
||||
fail() {
|
||||
printf '[ERR] %s\n' "$1" >&2
|
||||
}
|
||||
|
||||
is_empty_or_null() {
|
||||
[ -z "${1:-}" ] || [ "${1:-}" = "null" ]
|
||||
}
|
||||
|
||||
require_value() {
|
||||
local name="$1"
|
||||
local value="$2"
|
||||
|
||||
info "$name=$value"
|
||||
if is_empty_or_null "$value"; then
|
||||
fail "$name is required"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
require_integer() {
|
||||
local name="$1"
|
||||
local value="$2"
|
||||
|
||||
if ! [[ "$value" =~ ^[0-9]+$ ]]; then
|
||||
fail "$name must be a non-negative integer"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
fetch_all_pages() {
|
||||
local base_url="$1"
|
||||
local all_json='[]'
|
||||
local page=1
|
||||
local page_url page_json
|
||||
|
||||
while :; do
|
||||
page_url="$base_url?page=$page"
|
||||
page_json="$(curl -fsS "${auth_header[@]}" "$page_url")"
|
||||
|
||||
if [ "$(jq 'length' <<<"$page_json")" -eq 0 ]; then
|
||||
break
|
||||
fi
|
||||
|
||||
all_json="$(jq -s 'add' <<<"$all_json"$'\n'"$page_json")"
|
||||
page=$((page + 1))
|
||||
done
|
||||
|
||||
printf '%s' "$all_json"
|
||||
}
|
||||
|
||||
section "參數檢查"
|
||||
require_value "GITEA_SERVER_URL" "$GITEA_SERVER_URL"
|
||||
require_value "GITEA_REPOSITORY" "$GITEA_REPOSITORY"
|
||||
require_value "KEEP_COUNT" "$KEEP_COUNT"
|
||||
require_integer "KEEP_COUNT" "$KEEP_COUNT"
|
||||
|
||||
if is_empty_or_null "${GITEA_TOKEN:-}"; then
|
||||
warn "GITEA_TOKEN is empty; release API calls will be anonymous"
|
||||
else
|
||||
info "GITEA_TOKEN=[redacted]"
|
||||
fi
|
||||
|
||||
release_api_url="$GITEA_SERVER_URL/api/v1/repos/$GITEA_REPOSITORY/releases"
|
||||
auth_header=()
|
||||
|
||||
if ! is_empty_or_null "${GITEA_TOKEN:-}"; then
|
||||
auth_header=(-H "Authorization: token $GITEA_TOKEN")
|
||||
fi
|
||||
|
||||
section "取得成品資訊"
|
||||
info "GET $release_api_url"
|
||||
|
||||
release_json="$(fetch_all_pages "$release_api_url")"
|
||||
release_json="$(jq -e 'sort_by(.created_at) | reverse' <<<"$release_json")"
|
||||
release_count="$(jq 'length' <<<"$release_json")"
|
||||
|
||||
info "RELEASE_COUNT=$release_count"
|
||||
info "KEEP_COUNT=$KEEP_COUNT"
|
||||
|
||||
if [ "$release_count" -le "$KEEP_COUNT" ]; then
|
||||
success "沒有需要清理的舊版本成品"
|
||||
else
|
||||
section "刪除舊版本成品"
|
||||
|
||||
release_to_delete="$(jq -c ".[$KEEP_COUNT:]" <<<"$release_json")"
|
||||
|
||||
while IFS= read -r release_item; do
|
||||
[ -z "$release_item" ] && continue
|
||||
|
||||
release_id="$(jq -r '.id' <<<"$release_item")"
|
||||
release_tag="$(jq -r '.tag_name' <<<"$release_item")"
|
||||
release_name="$(jq -r '.name' <<<"$release_item")"
|
||||
|
||||
if is_empty_or_null "$release_id"; then
|
||||
warn "略過沒有 id 的成品: $release_tag ($release_name)"
|
||||
continue
|
||||
fi
|
||||
|
||||
delete_url="$GITEA_SERVER_URL/api/v1/repos/$GITEA_REPOSITORY/releases/$release_id"
|
||||
info "DELETE $release_tag ($release_name)"
|
||||
|
||||
delete_code="$(curl -sS -o /dev/null -w "%{http_code}" -X DELETE "${auth_header[@]}" "$delete_url")"
|
||||
|
||||
if [ "$delete_code" -eq 204 ]; then
|
||||
success "成功刪除: $release_tag ($release_name)"
|
||||
else
|
||||
fail "刪除失敗: $release_tag ($release_name), HTTP $delete_code"
|
||||
fi
|
||||
done < <(jq -c '.[]' <<<"$release_to_delete")
|
||||
fi
|
||||
|
||||
section "刪除未指定 release 的 tag"
|
||||
|
||||
# 重新取得 release 清單,得到刪除舊版本後仍指定 tag 的成品
|
||||
current_release_json="$(fetch_all_pages "$release_api_url")"
|
||||
release_tags_json="$(jq -c '[.[].tag_name]' <<<"$current_release_json")"
|
||||
|
||||
tag_api_url="$GITEA_SERVER_URL/api/v1/repos/$GITEA_REPOSITORY/tags"
|
||||
info "GET $tag_api_url"
|
||||
|
||||
tag_json="$(fetch_all_pages "$tag_api_url")"
|
||||
tag_count="$(jq 'length' <<<"$tag_json")"
|
||||
info "TAG_COUNT=$tag_count"
|
||||
|
||||
while IFS= read -r tag_item; do
|
||||
[ -z "$tag_item" ] && continue
|
||||
|
||||
tag_name="$(jq -r '.name' <<<"$tag_item")"
|
||||
|
||||
if is_empty_or_null "$tag_name"; then
|
||||
warn "略過沒有名稱的 tag"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "$(jq --arg name "$tag_name" 'any(.[]; . == $name)' <<<"$release_tags_json")" = "true" ]; then
|
||||
info "保留指定 release 的 tag: $tag_name"
|
||||
continue
|
||||
fi
|
||||
|
||||
delete_url="$tag_api_url/$tag_name"
|
||||
info "DELETE tag $tag_name"
|
||||
|
||||
delete_code="$(curl -sS -o /dev/null -w "%{http_code}" -X DELETE "${auth_header[@]}" "$delete_url")"
|
||||
|
||||
if [ "$delete_code" -eq 204 ]; then
|
||||
success "成功刪除未指定 release 的 tag: $tag_name"
|
||||
else
|
||||
fail "刪除 tag 失敗: $tag_name, HTTP $delete_code"
|
||||
fi
|
||||
done < <(jq -c '.[]' <<<"$tag_json")
|
||||
|
||||
separator
|
||||
# 進入點:實際邏輯改由 Node.js 實作,集中於 /app 目錄。
|
||||
# 以 exec 取代當前 shell process,讓 node 成為容器的 PID 1,正確接收訊號 (SIGTERM 等)。
|
||||
exec node /app/index.js
|
||||
|
||||
Reference in New Issue
Block a user