#!/usr/bin/env bash set -Eeuo pipefail separator() { printf '\n%s\n' '==================================================' } 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")" normal_release_json="$(jq -c '[.[] | select(((.tag_name // "") | test("-beta\\.")) | not)]' <<<"$release_json")" beta_release_json="$(jq -c '[.[] | select((.tag_name // "") | test("-beta\\."))]' <<<"$release_json")" normal_release_count="$(jq 'length' <<<"$normal_release_json")" beta_release_count="$(jq 'length' <<<"$beta_release_json")" info "RELEASE_COUNT=$release_count" info "NORMAL_RELEASE_COUNT=$normal_release_count" info "BETA_RELEASE_COUNT=$beta_release_count" info "KEEP_COUNT=$KEEP_COUNT" normal_release_to_delete='[]' if [ "$normal_release_count" -gt "$KEEP_COUNT" ]; then normal_release_to_delete="$(jq -c ".[$KEEP_COUNT:]" <<<"$normal_release_json")" fi beta_release_to_delete='[]' if [ "$beta_release_count" -gt "$KEEP_COUNT" ]; then beta_release_to_delete="$(jq -c ".[$KEEP_COUNT:]" <<<"$beta_release_json")" fi release_to_delete="$(jq -c -s 'add' <<<"$normal_release_to_delete"$'\n'"$beta_release_to_delete")" release_to_delete_count="$(jq 'length' <<<"$release_to_delete")" if [ "$release_to_delete_count" -eq 0 ]; then success "沒有需要清理的舊版本成品" else section "刪除舊版本成品" info "DELETE_RELEASE_COUNT=$release_to_delete_count" 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