Răsfoiți Sursa

cache: replace with proven OnePlus implementation

- cache-restore: replace ~270-line debug-heavy version with lean OnePlus
  restore (aria2c-only, no gh fallback) + keep cache-hit output for
  build.yml compat (FOUND -> GITHUB_OUTPUT)
- cache-save: replace wrapper (cache-archive+cache-upload) with
  self-contained OnePlus save (tar zstd -T0, 2GB split, gh release upload
  --clobber with retry, cleanup ghost parts)
- Proven in OnePlus_KernelSU_SUSFS; keeps same interface
  (cache_path/cache_key/cache_bucket/compression_level)
TheWildJames 1 săptămână în urmă
părinte
comite
c3b270517d
2 a modificat fișierele cu 293 adăugiri și 230 ștergeri
  1. 111 211
      .github/actions/cache-restore/action.yml
  2. 182 19
      .github/actions/cache-save/action.yml

+ 111 - 211
.github/actions/cache-restore/action.yml

@@ -1,5 +1,4 @@
 name: 'Restore Cache'
-description: 'Restores cache from GitHub Releases.'
 
 inputs:
   cache_path:
@@ -19,13 +18,8 @@ inputs:
     description: 'The tag name for the release (e.g., general-cache)'
     required: false
     default: 'general-cache'
-  compression_level:
-    description: 'Compression level (0-9). Kept for compatibility with save actions.'
-    required: false
-    type: number
-    default: 6
   debug:
-    description: 'Enable debug logging'
+    description: 'Enable Logs'
     required: false
     type: boolean
     default: false
@@ -44,243 +38,149 @@ runs:
       env:
         TARGET_REPO: "${{ github.repository }}"
       run: |
-        set -euo pipefail
-
-        if [ "${{ inputs.debug }}" = "true" ]; then
-          set -x
-        fi
-
+        # Detect and Download Cache
+        if [ "${{ inputs.debug }}" = "true" ]; then set -x; fi
+        
         cd "$GITHUB_WORKSPACE"
-
-        echo "[*] DEBUG: Starting cache restore process"
-        echo "[*] DEBUG: GITHUB_WORKSPACE=$GITHUB_WORKSPACE"
-        echo "[*] DEBUG: inputs.cache_path=${{ inputs.cache_path }}"
-        echo "[*] DEBUG: inputs.cache_key=${{ inputs.cache_key }}"
-        echo "[*] DEBUG: inputs.restore_keys=${{ inputs.restore_keys }}"
-        echo "[*] DEBUG: inputs.cache_bucket=${{ inputs.cache_bucket }}"
-        echo "[*] DEBUG: inputs.debug=${{ inputs.debug }}"
-
+        
         TAG_NAME="${{ inputs.cache_bucket }}"
         BASE_URL="https://github.com/${TARGET_REPO}/releases/download/$TAG_NAME"
         ASSETS_URL="https://github.com/${TARGET_REPO}/releases/expanded_assets/$TAG_NAME"
-
-        echo "[*] DEBUG: TAG_NAME=$TAG_NAME"
-        echo "[*] DEBUG: BASE_URL=$BASE_URL"
-        echo "[*] DEBUG: ASSETS_URL=$ASSETS_URL"
-        echo "[*] DEBUG: TARGET_REPO=$TARGET_REPO"
-
+        
         ARIA2_OPTS=(
           "-x16" "-s16" "-k1M" "-j5" "--file-allocation=none"
           "--header=User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
           "--header=Accept: */*"
           "--header=Connection: keep-alive"
         )
-
+        
         if [ "${{ inputs.debug }}" != "true" ]; then
           ARIA2_OPTS+=("--quiet" "--summary-interval=0" "--console-log-level=error")
         fi
-
-        echo "[*] DEBUG: Fetching asset list from GitHub Releases..."
-        echo "[*] DEBUG: HTTP request to ASSETS_URL=$ASSETS_URL"
+        
         echo "::group:: Fetching Asset List"
         HTTP_RESPONSE=$(curl -sL -A "Mozilla/5.0" -w "%{http_code}" "$ASSETS_URL" -o assets.html || echo "404")
-        echo "[*] DEBUG: HTTP_RESPONSE=$HTTP_RESPONSE"
-
+        
         if [ "$HTTP_RESPONSE" -eq 200 ]; then
-          ALL_ASSETS=$(grep -oP "download/$TAG_NAME/\K[^\"' ]+" assets.html | sort -u || true)
-          echo "[*] DEBUG: Parsed ALL_ASSETS count=$(echo "$ALL_ASSETS" | wc -l)"
-          echo "[*] DEBUG: First 10 assets: $(echo "$ALL_ASSETS" | head -n 10 | tr '\n' ' ')"
+          ALL_ASSETS=$(grep -oP "download/$TAG_NAME/\K[^\"' ]+" assets.html | sort -u || echo "")
         else
           echo "Status $HTTP_RESPONSE: Failed to fetch assets from scraper endpoint."
           ALL_ASSETS=""
-          echo "[*] DEBUG: No assets parsed due to HTTP failure"
         fi
         rm -f assets.html
-        echo "[*] DEBUG: assets.html removed"
-
+        
         if [ -z "$ALL_ASSETS" ]; then
-          echo "[*] DEBUG: ALL_ASSETS is empty, exiting early"
           echo "No assets found in bucket '$TAG_NAME'. Skipping search."
           echo "cache-hit=false" >> "$GITHUB_OUTPUT"
           echo "::endgroup::"
-          exit 0
-        fi
-
-        echo "Successfully fetched asset list. Has $(echo "$ALL_ASSETS" | wc -l) assets."
-        echo "[*] DEBUG: Full asset list (first 20 lines):"
-        echo "$ALL_ASSETS" | head -n 20
-        echo "::endgroup::"
-
-        SEARCH_LIST=$(printf "%s\n%s" "${{ inputs.cache_key }}" "${{ inputs.restore_keys }}" | sed '/^$/d')
-        echo "[*] DEBUG: SEARCH_LIST (keys to search):"
-        echo "$SEARCH_LIST"
-        echo "[*] DEBUG: FOUND=false initialized"
-
-        download_asset() {
-          local filename="$1"
-          local url="$2"
-          local max_retries=3
-          local attempt=1
-
-          echo "[*] DEBUG: download_asset() function called with filename=$filename, url=$url"
-          echo "[*] DEBUG: max_retries=$max_retries, current attempt=$attempt"
-          while [ "$attempt" -le "$max_retries" ]; do
-            echo "[*] DEBUG: Attempt $attempt: Downloading $filename..."
-            echo "[*] DEBUG: Removing old file $filename if exists"
-            rm -f "$filename"
-
-            if command -v gh >/dev/null 2>&1; then
-              echo "[*] DEBUG: 'gh' command available, attempting download via gh CLI"
-              if timeout 10m gh release download "$TAG_NAME" --repo "$TARGET_REPO" --pattern "$filename" -D . >/dev/null 2>&1; then
-                echo "[*] DEBUG: gh CLI download succeeded, checking file size"
-                [ -s "$filename" ] && { echo "[*] DEBUG: File $filename is non-empty, returning success"; return 0; }
-                echo "[*] DEBUG: File $filename is empty after gh download"
-              else
-                echo "[*] DEBUG: gh CLI download failed or timed out"
-              fi
-            else
-              echo "[*] DEBUG: 'gh' command not available, skipping gh CLI download"
+        else
+          echo "Successfully fetched asset list. Has $(echo "$ALL_ASSETS" | wc -l) assets."
+          echo "::endgroup::"
+          
+          SEARCH_LIST=$(printf "%s\n%s" "${{ inputs.cache_key }}" "${{ inputs.restore_keys }}" | sed '/^$/d')
+          
+          FOUND=false
+          while read -r KEY; do
+            [ -z "$KEY" ] && continue
+            echo "::group:: Searching Prefix: $KEY"
+            
+            MATCH=$(echo "$ALL_ASSETS" | grep "^cache-$KEY" | sort -r | head -n 1 || true)
+            
+            if [ -z "$MATCH" ]; then
+                echo "Not found."
+                echo "::endgroup::"
+                continue
             fi
-
-            echo "[*] DEBUG: Trying aria2c download with URL=$url"
-            echo "[*] DEBUG: aria2c options: ${ARIA2_OPTS[*]}"
-            if timeout 10m aria2c "${ARIA2_OPTS[@]}" --retry-wait=10 --max-tries=10 -o "$filename" "$url"; then
-              echo "[*] DEBUG: aria2c download succeeded, checking file size"
-              [ -s "$filename" ] && { echo "[*] DEBUG: File $filename is non-empty, returning success"; return 0; }
-              echo "  [!] Downloaded file is empty. Retrying..."
-              echo "[*] DEBUG: File $filename is empty after aria2c download"
-              rm -f "$filename"
+            
+            BASE_FILENAME=$(echo "$MATCH" | sed -E 's/\.(tzst|tar)(\.part[a-z]{2})?$//')
+            EXT=$(echo "$MATCH" | grep -oP '\.(tzst|tar)' | head -n 1)
+            
+            [[ "$MATCH" == *".part"* ]] && IS_SPLIT=true || IS_SPLIT=false
+            [ "$EXT" = ".tzst" ] && COMPRESSED=true || COMPRESSED=false
+            FOUND=true
+            
+            echo "✅ Hit! Restoring $BASE_FILENAME$EXT"
+            echo "::endgroup::"
+            
+            echo "::group:: Downloading Cache"
+            
+            download_asset() {
+              local filename="$1"
+              local url="$2"
+              local max_retries=3
+              local attempt=1
+              
+              while [ $attempt -le $max_retries ]; do
+                echo "  Attempt $attempt: Downloading $filename..."
+                
+                if timeout 10m aria2c "${ARIA2_OPTS[@]}" --retry-wait=10 --max-tries=10 -o "$filename" "$url"; then
+                  return 0
+                fi
+                
+                echo "  ⚠️ Download failed or timed out. Retrying in 5s..."
+                sleep 5
+                attempt=$((attempt + 1))
+              done
+              return 1
+            }
+            
+            if [ "$IS_SPLIT" = "true" ]; then
+              for part in {a..z}{a..z}; do
+                PART_NAME="$BASE_FILENAME$EXT.part$part"
+                if echo "$ALL_ASSETS" | grep -q "^$PART_NAME$"; then
+                  if ! download_asset "$PART_NAME" "$BASE_URL/$PART_NAME"; then
+                    echo "::error::Failed to download $PART_NAME after multiple retries."
+                    exit 1
+                  fi
+                else break; fi
+              done
             else
-              echo "[*] DEBUG: aria2c download failed or timed out"
+              if ! download_asset "$BASE_FILENAME$EXT" "$BASE_URL/$BASE_FILENAME$EXT"; then
+                echo "::error::Failed to download $BASE_FILENAME$EXT after multiple retries."
+                exit 1
+              fi
             fi
-
-            echo "  [!] Download failed or timed out. Retrying in 5s..."
-            echo "[*] DEBUG: Sleeping 5 seconds before retry"
-            sleep 5
-            attempt=$((attempt + 1))
-            echo "[*] DEBUG: Incremented attempt to $attempt"
-          done
-
-          return 1
-        }
-
-        while read -r KEY; do
-          echo "[*] DEBUG: Reading KEY from SEARCH_LIST: KEY=$KEY"
-          [ -z "$KEY" ] && { echo "[*] DEBUG: KEY is empty, skipping"; continue; }
-          echo "::group:: Searching Prefix: $KEY"
-          echo "[*] DEBUG: Searching for assets matching prefix: cache-$KEY"
-
-          MATCH=$(echo "$ALL_ASSETS" | grep -E "^cache-$KEY.*\.(tzst|tar)(\.part[a-z]{2})?$" | sort -r | head -n 1 || true)
-          echo "[*] DEBUG: MATCH result for KEY=$KEY: MATCH=$MATCH"
-
-          if [ -z "$MATCH" ]; then
-            echo "[*] DEBUG: No match found for KEY=$KEY, continuing to next key"
-            echo "Not found."
             echo "::endgroup::"
-            continue
-          fi
-
-          BASE_FILENAME=$(echo "$MATCH" | sed -E 's/\.(tzst|tar)(\.part[a-z]{2})?$//')
-          EXT=$(echo "$MATCH" | grep -oE '\.(tzst|tar)' | head -n 1)
-          IS_SPLIT=false
-          COMPRESSED=false
-          echo "[*] DEBUG: Parsed MATCH: BASE_FILENAME=$BASE_FILENAME, EXT=$EXT"
-
-          case "$MATCH" in
-            *.part*) IS_SPLIT=true ;;
-          esac
-          echo "[*] DEBUG: IS_SPLIT=$IS_SPLIT (based on .part* suffix)"
-
-          [ "$EXT" = ".tzst" ] && COMPRESSED=true
-          echo "[*] DEBUG: COMPRESSED=$COMPRESSED (EXT=$EXT)"
-
-          FOUND=true
-          echo "[+] Hit! Restoring $BASE_FILENAME$EXT"
-          echo "::endgroup::"
-
-          echo "::group:: Downloading Cache"
-          echo "[*] DEBUG: Download mode: IS_SPLIT=$IS_SPLIT, COMPRESSED=$COMPRESSED"
-          if [ "$IS_SPLIT" = "true" ]; then
-            echo "[*] DEBUG: Downloading split archive parts"
-            for part in {a..z}{a..z}; do
-              PART_NAME="$BASE_FILENAME$EXT.part$part"
-              echo "[*] DEBUG: Checking if PART_NAME=$PART_NAME exists in ALL_ASSETS"
-              if echo "$ALL_ASSETS" | grep -q "^$PART_NAME$"; then
-                echo "[*] DEBUG: PART_NAME=$PART_NAME found, downloading..."
-                if ! download_asset "$PART_NAME" "$BASE_URL/$PART_NAME"; then
-                  echo "::error::Failed to download $PART_NAME after multiple retries."
-                  echo "[*] DEBUG: CRITICAL: Failed to download $PART_NAME"
-                  exit 1
-                fi
-                echo "[*] DEBUG: Successfully downloaded $PART_NAME"
+            
+            echo "::group:: Extracting Cache"
+            mkdir -p "${{ inputs.cache_path }}"
+            FINAL_ARCHIVE="$BASE_FILENAME$EXT"
+            EXTRACT_DIR="$(dirname "${{ inputs.cache_path }}")"
+            
+            extract_cache() {
+              local cmd="$1"
+              if [ "${{ inputs.debug }}" = "true" ]; then
+                sh -c "$cmd"
               else
-                echo "[*] DEBUG: PART_NAME=$PART_NAME not found, breaking loop"
-                break
+                sh -c "$cmd" > /dev/null 2>&1
               fi
-            done
-          else
-            echo "[*] DEBUG: Downloading single file: $BASE_FILENAME$EXT"
-            if ! download_asset "$BASE_FILENAME$EXT" "$BASE_URL/$BASE_FILENAME$EXT"; then
-              echo "::error::Failed to download $BASE_FILENAME$EXT after multiple retries."
-              echo "[*] DEBUG: CRITICAL: Failed to download $BASE_FILENAME$EXT"
-              exit 1
-            fi
-            echo "[*] DEBUG: Successfully downloaded $BASE_FILENAME$EXT"
-          fi
-          echo "::endgroup::"
-
-          echo "::group:: Extracting Cache"
-          echo "[*] DEBUG: Starting extraction process"
-          echo "[*] DEBUG: cache_path=${{ inputs.cache_path }}"
-          mkdir -p "${{ inputs.cache_path }}"
-          echo "[*] DEBUG: Created/verified cache_path directory"
-          FINAL_ARCHIVE="$BASE_FILENAME$EXT"
-          EXTRACT_DIR="$(dirname "${{ inputs.cache_path }}")"
-          echo "[*] DEBUG: FINAL_ARCHIVE=$FINAL_ARCHIVE"
-          echo "[*] DEBUG: EXTRACT_DIR=$EXTRACT_DIR"
-          echo "[*] DEBUG: IS_SPLIT=$IS_SPLIT, COMPRESSED=$COMPRESSED"
-
-          if [ "$IS_SPLIT" = "true" ]; then
-            echo "[*] DEBUG: Extracting split archive"
-            PARTS=$(ls "$FINAL_ARCHIVE.part"* | sort)
-            echo "[*] DEBUG: Found parts: $PARTS"
-            echo "[*] DEBUG: Parts list size: $(echo "$PARTS" | wc -w)"
-            if [ "$COMPRESSED" = "true" ]; then
-              echo "[*] DEBUG: Using zstd decompression"
-              cat $PARTS | tar -I 'zstd -d -T0' -xf - -C "$EXTRACT_DIR"
+            }
+            
+            if [ "$IS_SPLIT" = "true" ]; then
+              PARTS=$(ls "$FINAL_ARCHIVE.part"* | sort | tr '\n' ' ')
+              if [ "$COMPRESSED" = "true" ]; then
+                extract_cache "cat $PARTS | tar -I 'zstd -d -T0' -xvf - -C '$EXTRACT_DIR'"
+              else
+                extract_cache "cat $PARTS | tar -xvf - -C '$EXTRACT_DIR'"
+              fi
+              rm -f $PARTS
             else
-              echo "[*] DEBUG: Using plain tar extraction"
-              cat $PARTS | tar -xf - -C "$EXTRACT_DIR"
+              if [ "$COMPRESSED" = "true" ]; then
+                extract_cache "tar -I 'zstd -d -T0' -xvf '$FINAL_ARCHIVE' -C '$EXTRACT_DIR'"
+              else
+                extract_cache "tar -xvf '$FINAL_ARCHIVE' -C '$EXTRACT_DIR'"
+              fi
+              rm -f "$FINAL_ARCHIVE"
             fi
-            echo "[*] DEBUG: Removing part files"
-            rm -f $PARTS
+            echo "✅ Restore complete."
+            echo "::endgroup::"
+            break
+          done <<< "$SEARCH_LIST"
+          
+          if [ "$FOUND" = "false" ]; then
+              echo "⚠️ No cache matches found. Proceeding with fresh run."
+              echo "cache-hit=false" >> "$GITHUB_OUTPUT"
           else
-            echo "[*] DEBUG: Extracting single archive"
-            if [ "$COMPRESSED" = "true" ]; then
-              echo "[*] DEBUG: Using zstd decompression for single file"
-              tar -I 'zstd -d -T0' -xf "$FINAL_ARCHIVE" -C "$EXTRACT_DIR"
-            else
-              echo "[*] DEBUG: Using plain tar extraction for single file"
-              tar -xf "$FINAL_ARCHIVE" -C "$EXTRACT_DIR"
-            fi
-            echo "[*] DEBUG: Removing archive file"
-            rm -f "$FINAL_ARCHIVE"
+              echo "cache-hit=true" >> "$GITHUB_OUTPUT"
           fi
-
-          echo "[*] DEBUG: Verifying extracted contents"
-          ls -la "${{ inputs.cache_path }}" || true
-          echo "[+] Restore complete."
-          echo "::endgroup::"
-          break
-        done <<< "$SEARCH_LIST"
-
-        echo "[*] DEBUG: Final check - FOUND=$FOUND"
-        if [ "$FOUND" = "false" ]; then
-          echo "[!] No cache matches found. Proceeding with fresh run."
-          echo "[*] DEBUG: Setting cache-hit=false"
-          echo "cache-hit=false" >> "$GITHUB_OUTPUT"
-        else
-          echo "[*] DEBUG: Cache was found and restored"
-          echo "cache-hit=true" >> "$GITHUB_OUTPUT"
         fi
-        echo "[*] DEBUG: Cache restore process finished. cache-hit=$(cat $GITHUB_OUTPUT | grep cache-hit | cut -d= -f2)"

+ 182 - 19
.github/actions/cache-save/action.yml

@@ -1,5 +1,5 @@
 name: 'Save Cache'
-description: 'Archive and upload cache to GitHub Releases'
+
 inputs:
   cache_path:
     description: 'Path where cache is saved'
@@ -25,6 +25,11 @@ inputs:
     description: 'Path where .git folder exists (use only if you clone multiple repos)'
     required: false
     type: string
+  delete_after_upload:
+    description: 'Delete Source files after uploading'
+    required: false
+    type: boolean
+    default: false
   debug:
     description: 'Enable Logs'
     required: false
@@ -34,21 +39,179 @@ inputs:
 runs:
   using: 'composite'
   steps:
-    - name: Archive Cache
-      uses: ./.github/actions/cache-archive
-      with:
-        cache_path: ${{ inputs.cache_path }}
-        cache_key: ${{ inputs.cache_key }}
-        cache_bucket: ${{ inputs.cache_bucket }}
-        compression_level: ${{ inputs.compression_level }}
-        working_dir: ${{ inputs.working_dir }}
-        debug: ${{ inputs.debug }}
-
-    - name: Upload Cache
-      uses: ./.github/actions/cache-upload
-      with:
-        cache_key: ${{ inputs.cache_key }}
-        cache_bucket: ${{ inputs.cache_bucket }}
-        github_token: ${{ inputs.github_token }}
-        compression_level: ${{ inputs.compression_level }}
-        debug: ${{ inputs.debug }}
+    - name: Archive, Split, and Upload Cache
+      shell: bash
+      env:
+        GH_TOKEN: ${{ inputs.github_token }}
+        TARGET_REPO: "${{ github.repository }}"
+      run: |
+        # Archive, Split, and Upload Cache
+        if [ "${{ inputs.debug }}" = "true" ]; then set -x; fi
+        
+        if [ "${{ inputs.working_dir }}" != "" ]; then 
+          cd "${{ inputs.working_dir }}"
+        fi
+        git config user.name "github-actions[bot]"
+        git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
+        
+        TAG_NAME="${{ inputs.cache_bucket }}"
+        BASE_FILENAME="cache-${{ inputs.cache_key }}"
+        
+        if [ "${{ inputs.compression_level }}" -eq 0 ]; then
+          FILENAME="$BASE_FILENAME.tar"
+        else
+          FILENAME="$BASE_FILENAME.tzst"
+        fi
+        
+        echo "::group:: Checking Release State"
+        
+        git fetch --tags --force
+        
+        if ! git rev-parse "$TAG_NAME" >/dev/null 2>&1; then
+          echo "Tag '$TAG_NAME' not found. Creating backdated release..."
+          GIT_COMMITTER_DATE="2015-01-01T12:00:00" git tag -a "$TAG_NAME" -m "General Cache Storage"
+          if git push origin "$TAG_NAME" --force; then
+            gh release create "$TAG_NAME" --title "General Cache" --notes "Automated storage for build assets" --repo "$TARGET_REPO" || true
+          else
+            echo "Push failed, tag might have been created by a parallel job. Continuing..."
+          fi
+        else
+          echo "Release '$TAG_NAME' already exists. Ready for upload."
+        fi
+        echo "::endgroup::"
+        
+        echo "::group:: Archiving Path"
+        echo "Target: ${{ inputs.cache_path }}"
+        
+        if [ ! -d "${{ inputs.cache_path }}" ] && [ ! -f "${{ inputs.cache_path }}" ]; then
+          echo "⚠️ Target path not found. Skipping cache save."
+          echo "::endgroup::"
+        else
+          DIR_NAME=$(dirname "${{ inputs.cache_path }}")
+          BASE_NAME=$(basename "${{ inputs.cache_path }}")
+          
+          if [ "${{ inputs.debug }}" = "true" ]; then
+            if [ "${{ inputs.compression_level }}" -eq 0 ]; then
+              tar --posix -h -cvf "$FILENAME" -C "$DIR_NAME" "$BASE_NAME"
+            else
+              tar --posix -h -I "zstd -T0 -${{ inputs.compression_level }}" -cvf "$FILENAME" -C "$DIR_NAME" "$BASE_NAME"
+            fi
+          else
+            if [ "${{ inputs.compression_level }}" -eq 0 ]; then
+              tar --posix -h -cvf "$FILENAME" -C "$DIR_NAME" "$BASE_NAME" > /dev/null 2>&1
+            else
+              tar --posix -h -I "zstd -T0 -${{ inputs.compression_level }}" -cvf "$FILENAME" -C "$DIR_NAME" "$BASE_NAME" > /dev/null 2>&1
+            fi
+          fi
+          
+          FILE_SIZE=$(stat -c%s "$FILENAME")
+          echo "Archive created: $FILENAME ($FILE_SIZE bytes)"
+          echo "::endgroup::"
+          
+          ASSETS_URL="https://github.com/${TARGET_REPO}/releases/expanded_assets/$TAG_NAME"
+          echo "::group:: Fetching Asset List"
+          HTTP_RESPONSE=$(curl -sL -A "Mozilla/5.0" -w "%{http_code}" "$ASSETS_URL" -o assets.html || echo "404")
+          
+          if [ "$HTTP_RESPONSE" -eq 200 ]; then
+            ALL_ASSETS=$(grep -oP "download/$TAG_NAME/\K[^\"' ]+" assets.html | sort || echo "")
+            if [ "${{ inputs.debug }}" = "true" ]; then
+              echo "Assets Found: $ALL_ASSETS"
+            fi
+          else
+            echo "Status $HTTP_RESPONSE: Failed to fetch assets from scraper endpoint."
+            ALL_ASSETS=""
+          fi
+          rm -f assets.html
+          
+          echo "::endgroup::"
+          
+          echo "::group:: Uploading Assets"
+          MAX_SIZE=2000000000 # ~1.86GB
+          
+          upload_with_retry() {
+            local file=$1
+            local max_attempts=3
+            for ((i=1; i<=max_attempts; i++)); do
+              echo "  Attempt $i for $file..."
+              
+              if [ "${{ inputs.debug }}" = "true" ]; then
+                if timeout 10m gh release upload "$TAG_NAME" "$file" --clobber --repo "$TARGET_REPO"; then
+                  echo "  Successfully uploaded $file"
+                  return 0
+                fi
+              else
+                if timeout 10m gh release upload "$TAG_NAME" "$file" --clobber --repo "$TARGET_REPO" > /dev/null 2>&1; then
+                  echo "  Successfully uploaded $file"
+                  return 0
+                fi
+              fi
+              
+              echo "  ⚠ Attempt $i failed or timed out. Retrying..."
+              sleep 5
+            done
+            return 1
+          }
+          
+          if [ "$FILE_SIZE" -gt "$MAX_SIZE" ]; then
+            echo "⚠ File > 2GB. Splitting..."
+            split -b 1500M -a 2 "$FILENAME" "${FILENAME}.part"
+            
+            NEW_PARTS=(${FILENAME}.part*)
+            NEW_PARTS_COUNT=${#NEW_PARTS[@]}
+            
+            if echo "$ALL_ASSETS" | grep -xF "${FILENAME}" >/dev/null 2>&1; then
+              echo "Removing old single asset to make way for split parts: ${FILENAME}"
+              gh release delete-asset "$TAG_NAME" "${FILENAME}" --repo "$TARGET_REPO" -y || true
+            fi
+            
+            OLD_PARTS=$(echo "$ALL_ASSETS" | grep -F "${FILENAME}.part" || echo "")
+            
+            if [ -n "$OLD_PARTS" ]; then
+              OLD_PARTS_COUNT=$(echo "$OLD_PARTS" | wc -l)
+            else
+              OLD_PARTS_COUNT=0
+            fi
+            
+            if [ "$OLD_PARTS_COUNT" -gt "$NEW_PARTS_COUNT" ]; then
+              echo "Old build had $OLD_PARTS_COUNT parts, new has $NEW_PARTS_COUNT. Cleaning up excess parts..."
+              EXT_PARTS=$(echo "$OLD_PARTS" | awk -v skip="$NEW_PARTS_COUNT" 'NR>skip')
+              for asset in $EXT_PARTS; do
+                echo "Removing leftover trailing part: $asset"
+                gh release delete-asset "$TAG_NAME" "$asset" --repo "$TARGET_REPO" -y || true
+              done
+            fi
+            
+            for part in "${FILENAME}".part*; do
+              echo "Uploading $part..."
+              if ! upload_with_retry "$part"; then
+                echo "::error::Failed to upload part $part after multiple attempts."
+                exit 1
+              fi
+              rm -f "$part"
+            done
+            rm -rf "$FILENAME"
+          else
+            OLD_PARTS=$(echo "$ALL_ASSETS" | grep -F "${FILENAME}.part" || echo "")
+            if [ -n "$OLD_PARTS" ]; then
+              echo "New build shrunk to single file. Cleaning up old split parts for ${FILENAME}..."
+              while read -r asset; do
+                [ -z "$asset" ] && continue
+                echo "Removing ghost split part: $asset"
+                gh release delete-asset "$TAG_NAME" "$asset" --repo "$TARGET_REPO" -y || true
+              done <<< "$OLD_PARTS"
+            fi
+            
+            echo "Uploading $FILENAME..."
+            if ! upload_with_retry "$FILENAME"; then
+              echo "::error::Failed to upload $FILENAME after multiple attempts."
+              exit 1
+            fi
+            rm -f "$FILENAME"
+          fi
+          
+          if [ "${{ inputs.delete_after_upload }}" = "true" ]; then
+            rm -rf "${{ inputs.cache_path }}"
+          fi
+          
+          echo "::endgroup::"
+        fi