action.yml 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. name: 'Save Cache'
  2. inputs:
  3. cache_path:
  4. description: 'Path where cache is saved'
  5. required: true
  6. type: string
  7. cache_key:
  8. description: 'Unique key for the cache'
  9. required: true
  10. type: string
  11. cache_bucket:
  12. description: 'The tag name for the release (e.g., general-cache)'
  13. required: true
  14. default: 'general-cache'
  15. github_token:
  16. description: 'GitHub Token'
  17. required: true
  18. compression_level:
  19. description: 'Compression level (0-9). 0 = No compression, 1 = Fast, 19 = Best.'
  20. required: false
  21. type: number
  22. default: 6
  23. working_dir:
  24. description: 'Path where .git folder exists (use only if you clone multiple repos)'
  25. required: false
  26. type: string
  27. debug:
  28. description: 'Enable Logs'
  29. required: false
  30. type: boolean
  31. default: false
  32. runs:
  33. using: 'composite'
  34. steps:
  35. - name: Archive, Split, and Upload Cache
  36. shell: bash
  37. env:
  38. GH_TOKEN: ${{ inputs.github_token }}
  39. TARGET_REPO: "${{ github.repository }}"
  40. run: |
  41. # Archive, Split, and Upload Cache
  42. if [ "${{ inputs.debug }}" = "true" ]; then set -x; fi
  43. if [ "${{ inputs.working_dir }}" != "" ]; then
  44. cd "${{ inputs.working_dir }}"
  45. fi
  46. git config user.name "github-actions[bot]"
  47. git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
  48. TAG_NAME="${{ inputs.cache_bucket }}"
  49. BASE_FILENAME="cache-${{ inputs.cache_key }}"
  50. if [ "${{ inputs.compression_level }}" -eq 0 ]; then
  51. FILENAME="$BASE_FILENAME.tar"
  52. else
  53. FILENAME="$BASE_FILENAME.tzst"
  54. fi
  55. echo "::group:: Checking Release State"
  56. git fetch --tags --force
  57. if ! git rev-parse "$TAG_NAME" >/dev/null 2>&1; then
  58. echo "Tag '$TAG_NAME' not found. Creating backdated release..."
  59. GIT_COMMITTER_DATE="2015-01-01T12:00:00" git tag -a "$TAG_NAME" -m "General Cache Storage"
  60. if git push origin "$TAG_NAME" --force; then
  61. gh release create "$TAG_NAME" --title "General Cache" --notes "Automated storage for build assets" --repo "$TARGET_REPO" || true
  62. else
  63. echo "Push failed, tag might have been created by a parallel job. Continuing..."
  64. fi
  65. else
  66. echo "Release '$TAG_NAME' already exists. Ready for upload."
  67. fi
  68. echo "::endgroup::"
  69. echo "::group:: Archiving Path"
  70. echo "Target: ${{ inputs.cache_path }}"
  71. if [ ! -d "${{ inputs.cache_path }}" ] && [ ! -f "${{ inputs.cache_path }}" ]; then
  72. echo "⚠️ Target path not found. Skipping cache save."
  73. echo "::endgroup::"
  74. else
  75. DIR_NAME=$(dirname "${{ inputs.cache_path }}")
  76. BASE_NAME=$(basename "${{ inputs.cache_path }}")
  77. if [ "${{ inputs.debug }}" = "true" ]; then
  78. if [ "${{ inputs.compression_level }}" -eq 0 ]; then
  79. tar --posix -h -cvf "$FILENAME" -C "$DIR_NAME" "$BASE_NAME"
  80. else
  81. tar --posix -h -I "zstd -T0 -${{ inputs.compression_level }}" -cvf "$FILENAME" -C "$DIR_NAME" "$BASE_NAME"
  82. fi
  83. else
  84. if [ "${{ inputs.compression_level }}" -eq 0 ]; then
  85. tar --posix -h -cvf "$FILENAME" -C "$DIR_NAME" "$BASE_NAME" > /dev/null 2>&1
  86. else
  87. tar --posix -h -I "zstd -T0 -${{ inputs.compression_level }}" -cvf "$FILENAME" -C "$DIR_NAME" "$BASE_NAME" > /dev/null 2>&1
  88. fi
  89. fi
  90. FILE_SIZE=$(stat -c%s "$FILENAME")
  91. echo "Archive created: $FILENAME ($FILE_SIZE bytes)"
  92. echo "::endgroup::"
  93. echo "::group:: Uploading Assets"
  94. MAX_SIZE=2000000000 # ~1.86GB
  95. upload_with_retry() {
  96. local file=$1
  97. local max_attempts=3
  98. for ((i=1; i<=max_attempts; i++)); do
  99. echo " Attempt $i for $file..."
  100. local upload_log
  101. upload_log=$(mktemp)
  102. if [ "${{ inputs.debug }}" = "true" ]; then
  103. if timeout 10m gh release upload "$TAG_NAME" "$file" --clobber --repo "$TARGET_REPO" > >(tee "$upload_log") 2> >(tee -a "$upload_log" >&2); then
  104. rm -f "$upload_log"
  105. echo " Successfully uploaded $file"
  106. return 0
  107. fi
  108. else
  109. if timeout 10m gh release upload "$TAG_NAME" "$file" --clobber --repo "$TARGET_REPO" > "$upload_log" 2>&1; then
  110. rm -f "$upload_log"
  111. echo " Successfully uploaded $file"
  112. return 0
  113. fi
  114. fi
  115. local exit_code=$?
  116. echo " ⚠ Attempt $i failed with exit code $exit_code."
  117. echo " └─ Upload output for $file:"
  118. sed 's/^/ /' "$upload_log" || true
  119. rm -f "$upload_log"
  120. if [ "$exit_code" -eq 124 ]; then
  121. echo " ⚠ Attempt $i timed out after 10m. Retrying..."
  122. else
  123. echo " ⚠ Attempt $i failed. Retrying..."
  124. fi
  125. sleep 5
  126. done
  127. return 1
  128. }
  129. if [ "$FILE_SIZE" -gt "$MAX_SIZE" ]; then
  130. echo "⚠ File > 2GB. Splitting..."
  131. split -b 1500M -a 2 "$FILENAME" "${FILENAME}.part"
  132. for part in "${FILENAME}".part*; do
  133. echo "Uploading $part..."
  134. if ! upload_with_retry "$part"; then
  135. echo "::error::Failed to upload part $part after multiple attempts."
  136. exit 1
  137. fi
  138. rm -f "$part"
  139. done
  140. rm -rf "$FILENAME"
  141. else
  142. echo "Uploading $FILENAME..."
  143. if ! upload_with_retry "$FILENAME"; then
  144. echo "::error::Failed to upload $FILENAME after multiple attempts."
  145. exit 1
  146. fi
  147. rm -f "$FILENAME"
  148. fi
  149. echo "::endgroup::"
  150. fi