From 177416c85deff352f947b19015946209d9cdc221 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Thu, 18 Sep 2025 14:28:37 +0800 Subject: [PATCH] first commit --- .gitea/workflows/master.yaml | 28 ++++++++ action.yml | 127 +++++++++++++++++++++++++++++++++++ readme.md | 118 ++++++++++++++++++++++++++++++++ 3 files changed, 273 insertions(+) create mode 100644 .gitea/workflows/master.yaml create mode 100644 action.yml create mode 100644 readme.md diff --git a/.gitea/workflows/master.yaml b/.gitea/workflows/master.yaml new file mode 100644 index 0000000..4a53e4b --- /dev/null +++ b/.gitea/workflows/master.yaml @@ -0,0 +1,28 @@ +on: + push: + branches: + - master +jobs: + cd: + name: "CD > 發布專案" + runs-on: docker + env: + RUNNER_TOOL_CACHE: /toolcache + steps: + - name: 計算版本號 + id: version + uses: https://gitea.jsc.idv.tw/jiantw83/calculate-version-action@v${{ vars.CALCULATE_VERSION }} + with: + gitea-server: ${{ gitea.server_url }} + repository: ${{ gitea.repository }} + token: ${{ secrets.GITEA_TOKEN }} + - name: 發布專案 + uses: akkuman/gitea-release-action@v1 + with: + tag_name: "v${{ steps.version.outputs.VERSION }}" + - name: 清理舊版本 (保留最新2個) + uses: https://gitea.jsc.idv.tw/jiantw83/cleanup-release-action@v${{ vars.CLEANUP_RELEASE_VERSION }} + with: + gitea-server: ${{ gitea.server_url }} + repository: ${{ gitea.repository }} + token: ${{ secrets.GITEA_TOKEN }} \ No newline at end of file diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..4dc1a8b --- /dev/null +++ b/action.yml @@ -0,0 +1,127 @@ +name: 'Cleanup Old Releases' +description: '自動清理舊版本的 releases,保留指定數量的最新版本' +inputs: + gitea-server: + description: 'Gitea 伺服器 URL' + required: true + repository: + description: '儲存庫名稱 (格式: owner/repo)' + required: true + token: + description: 'Gitea API Token' + required: true + keep-count: + description: '保留的最新版本數量' + required: false + default: '2' + dry-run: + description: '是否為模擬執行 (只顯示會刪除的版本,不實際刪除)' + required: false + default: 'false' +outputs: + deleted-count: + description: '已刪除的版本數量' + value: ${{ steps.cleanup.outputs.deleted-count }} + deleted-releases: + description: '已刪除的版本列表 (JSON 格式)' + value: ${{ steps.cleanup.outputs.deleted-releases }} +runs: + using: 'composite' + steps: + - name: 清理舊版本 + id: cleanup + shell: bash + run: | + echo "開始清理舊版本,保留最新 ${{ inputs.keep-count }} 個版本" + + # 獲取所有 releases 並按創建時間排序 + RELEASES_JSON=$(curl -s "${{ inputs.gitea-server }}/api/v1/repos/${{ inputs.repository }}/releases" \ + -H "Authorization: token ${{ inputs.token }}" \ + -H "Accept: application/json") + + # 檢查是否成功獲取 releases + if [ $? -ne 0 ] || [ -z "$RELEASES_JSON" ]; then + echo "錯誤:無法獲取 releases 列表" + exit 1 + fi + + # 計算總數量 + TOTAL_COUNT=$(echo "$RELEASES_JSON" | jq 'length') + echo "目前總共有 $TOTAL_COUNT 個 releases" + + # 如果總數量小於等於保留數量,則無需清理 + if [ $TOTAL_COUNT -le ${{ inputs.keep-count }} ]; then + echo "releases 數量 ($TOTAL_COUNT) 未超過保留數量 (${{ inputs.keep-count }}),無需清理" + echo "deleted-count=0" >> $GITHUB_OUTPUT + echo "deleted-releases=[]" >> $GITHUB_OUTPUT + exit 0 + fi + + # 計算需要刪除的數量 + DELETE_COUNT=$((TOTAL_COUNT - ${{ inputs.keep-count }})) + echo "需要刪除 $DELETE_COUNT 個舊版本" + + # 獲取要刪除的 releases (跳過前 keep-count 個) + TO_DELETE=$(echo "$RELEASES_JSON" | jq -r ".[${{ inputs.keep-count }}:] | .[] | {id: .id, tag: .tag_name, name: .name}") + + # 初始化刪除計數器和列表 + DELETED_COUNT=0 + DELETED_LIST="[]" + + # 處理每個要刪除的 release + echo "$TO_DELETE" | jq -c '.' | while read -r release; do + if [ -z "$release" ] || [ "$release" = "null" ]; then + continue + fi + + RELEASE_ID=$(echo "$release" | jq -r '.id') + RELEASE_TAG=$(echo "$release" | jq -r '.tag') + RELEASE_NAME=$(echo "$release" | jq -r '.name') + + if [ -z "$RELEASE_ID" ] || [ "$RELEASE_ID" = "null" ]; then + continue + fi + + echo "準備刪除: ID=$RELEASE_ID, Tag=$RELEASE_TAG, Name=$RELEASE_NAME" + + if [ "${{ inputs.dry-run }}" = "true" ]; then + echo "🔍 [模擬執行] 會刪除 release: $RELEASE_TAG ($RELEASE_NAME)" + DELETED_COUNT=$((DELETED_COUNT + 1)) + else + # 實際刪除 + DELETE_RESPONSE=$(curl -s -w "HTTP_STATUS:%{http_code}" \ + -X DELETE "${{ inputs.gitea-server }}/api/v1/repos/${{ inputs.repository }}/releases/$RELEASE_ID" \ + -H "Authorization: token ${{ inputs.token }}") + + HTTP_STATUS=$(echo "$DELETE_RESPONSE" | grep -o "HTTP_STATUS:[0-9]*" | cut -d: -f2) + + if [ "$HTTP_STATUS" = "204" ] || [ "$HTTP_STATUS" = "200" ]; then + echo "✅ 成功刪除 release: $RELEASE_TAG ($RELEASE_NAME)" + DELETED_COUNT=$((DELETED_COUNT + 1)) + + # 更新已刪除列表 + DELETED_LIST=$(echo "$DELETED_LIST" | jq ". + [{\"id\": \"$RELEASE_ID\", \"tag\": \"$RELEASE_TAG\", \"name\": \"$RELEASE_NAME\"}]") + else + echo "❌ 刪除失敗 release: $RELEASE_TAG ($RELEASE_NAME), HTTP狀態: $HTTP_STATUS" + fi + fi + done + + # 由於 while 迴圈在子 shell 中執行,需要重新計算 + if [ "${{ inputs.dry-run }}" = "true" ]; then + FINAL_DELETE_COUNT=$(echo "$TO_DELETE" | jq -s 'length') + echo "deleted-count=$FINAL_DELETE_COUNT" >> $GITHUB_OUTPUT + echo "deleted-releases=[]" >> $GITHUB_OUTPUT + echo "🔍 [模擬執行] 總共會刪除 $FINAL_DELETE_COUNT 個版本" + else + # 重新獲取並計算實際刪除的數量 + NEW_RELEASES_JSON=$(curl -s "${{ inputs.gitea-server }}/api/v1/repos/${{ inputs.repository }}/releases" \ + -H "Authorization: token ${{ inputs.token }}" \ + -H "Accept: application/json") + NEW_TOTAL_COUNT=$(echo "$NEW_RELEASES_JSON" | jq 'length') + ACTUAL_DELETED=$((TOTAL_COUNT - NEW_TOTAL_COUNT)) + + echo "deleted-count=$ACTUAL_DELETED" >> $GITHUB_OUTPUT + echo "deleted-releases=$DELETED_LIST" >> $GITHUB_OUTPUT + echo "✅ 清理完成,實際刪除了 $ACTUAL_DELETED 個版本" + fi diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..f3350d8 --- /dev/null +++ b/readme.md @@ -0,0 +1,118 @@ +# Cleanup Old Releases Action + +這是一個自動清理舊版本 releases 的 GitHub Action,可以保留指定數量的最新版本,刪除多餘的舊版本。 + +## 功能特色 + +- 🗑️ 自動清理舊版本 releases +- 🔢 可配置保留的版本數量 +- 🔍 支援模擬執行模式 +- 📊 詳細的執行報告 +- 🛡️ 安全的錯誤處理 + +## 輸入參數 + +| 參數名稱 | 必要 | 預設值 | 描述 | +|---------|------|--------|------| +| `gitea-server` | ✅ | - | Gitea 伺服器 URL | +| `repository` | ✅ | - | 儲存庫名稱 (格式: owner/repo) | +| `token` | ✅ | - | Gitea API Token | +| `keep-count` | ❌ | `2` | 保留的最新版本數量 | +| `dry-run` | ❌ | `false` | 是否為模擬執行 (只顯示會刪除的版本,不實際刪除) | + +## 輸出參數 + +| 參數名稱 | 描述 | +|---------|------| +| `deleted-count` | 已刪除的版本數量 | +| `deleted-releases` | 已刪除的版本列表 (JSON 格式) | + +## 使用範例 + +### 基本用法 (保留最新2個版本) + +```yaml +- name: 清理舊版本 + uses: ./.gitea/actions/cleanup-releases + with: + gitea-server: ${{ gitea.server_url }} + repository: ${{ gitea.repository }} + token: ${{ secrets.GITEA_TOKEN }} +``` + +### 自定義保留數量 + +```yaml +- name: 清理舊版本 (保留最新5個) + uses: ./.gitea/actions/cleanup-releases + with: + gitea-server: ${{ gitea.server_url }} + repository: ${{ gitea.repository }} + token: ${{ secrets.GITEA_TOKEN }} + keep-count: '5' +``` + +### 模擬執行模式 + +```yaml +- name: 檢查要清理的版本 + id: check-cleanup + uses: ./.gitea/actions/cleanup-releases + with: + gitea-server: ${{ gitea.server_url }} + repository: ${{ gitea.repository }} + token: ${{ secrets.GITEA_TOKEN }} + keep-count: '3' + dry-run: 'true' + +- name: 顯示模擬結果 + run: | + echo "模擬執行會刪除 ${{ steps.check-cleanup.outputs.deleted-count }} 個版本" +``` + +### 使用輸出結果 + +```yaml +- name: 清理舊版本 + id: cleanup + uses: ./.gitea/actions/cleanup-releases + with: + gitea-server: ${{ gitea.server_url }} + repository: ${{ gitea.repository }} + token: ${{ secrets.GITEA_TOKEN }} + keep-count: '2' + +- name: 報告清理結果 + run: | + echo "清理完成,刪除了 ${{ steps.cleanup.outputs.deleted-count }} 個舊版本" + echo "刪除的版本詳情: ${{ steps.cleanup.outputs.deleted-releases }}" +``` + +## 運作邏輯 + +1. **獲取版本列表**:從 Gitea API 獲取所有 releases,按創建時間排序 +2. **計算刪除範圍**:保留最新的 `keep-count` 個版本,標記其餘版本為待刪除 +3. **執行清理**: + - 模擬模式:只顯示會刪除的版本,不實際執行 + - 正常模式:逐一刪除標記的版本 +4. **回報結果**:提供刪除數量和詳細列表 + +## 安全特性 + +- ✅ **防護機制**:如果總版本數 ≤ 保留數量,則不執行任何刪除 +- ✅ **錯誤處理**:API 請求失敗時會顯示錯誤訊息並停止執行 +- ✅ **模擬模式**:可以先模擬執行,確認要刪除的版本無誤 +- ✅ **詳細日誌**:每個步驟都有清楚的日誌輸出 + +## 注意事項 + +- 需要有 `GITEA_TOKEN` secret 且具備刪除 releases 的權限 +- 刪除操作是不可逆的,建議先使用模擬模式確認 +- Action 按照創建時間排序,保留最新的版本 +- 建議在 release 創建之後執行此 action + +## 錯誤處理 + +- 如果無法連接到 Gitea API,action 會失敗並顯示錯誤訊息 +- 如果某個版本刪除失敗,會記錄錯誤但繼續處理其他版本 +- 如果 token 權限不足,會顯示相應的 HTTP 錯誤狀態