Skip to content

Schedule cleanup of stale julia caches on long-lived branches #242

Schedule cleanup of stale julia caches on long-lived branches

Schedule cleanup of stale julia caches on long-lived branches #242

Workflow file for this run

name: Cleanup github runner caches
on:
# pull_request_target is required so fork PRs can delete their own caches on close.
# pull_request from a fork ships a read-only GITHUB_TOKEN regardless of the
# permissions: block, causing gh cache delete to fail with HTTP 403.
# Safe here: no PR code is checked out, the workflow only calls gh cache list/delete.
pull_request_target:
types:
- closed
# Daily cleanup of stale julia caches on long-lived branches. julia-actions/cache@v3
# does not run delete-old-caches on the default branch (by design, to avoid races
# between concurrent runs), so caches accumulate. This job keeps only the newest
# cache per (workflow, os) tuple.
schedule:
- cron: "0 4 * * *"
workflow_dispatch:
jobs:
cleanup-pr:
if: github.event_name == 'pull_request_target'
runs-on: ubuntu-latest
permissions:
actions: write
steps:
- name: Cleanup
run: |
echo "::group::Fetching cache list for PR #${{ github.event.pull_request.number }}"
echo "Branch ref: $BRANCH"
# Get full cache list with details for logging
cacheList=$(gh cache list --ref $BRANCH --limit 100 --json id,key,sizeInBytes)
cacheCount=$(echo "$cacheList" | jq '. | length')
echo "Found $cacheCount cache(s) for this PR"
if [ "$cacheCount" -gt 0 ]; then
echo "Cache details:"
echo "$cacheList" | jq -r '.[] | " - ID: \(.id) | Key: \(.key) | Size: \(.sizeInBytes | tonumber / 1024 / 1024 | floor)MB"'
fi
echo "::endgroup::"
if [ "$cacheCount" -eq 0 ]; then
echo "No caches to delete"
exit 0
fi
# Extract just the IDs for deletion
cacheKeysForPR=$(echo "$cacheList" | jq -r '.[].id')
## Setting this to not fail the workflow while deleting cache keys.
set +e
echo "::group::Deleting caches"
deleted=0
failed=0
for cacheKey in $cacheKeysForPR
do
echo "Deleting cache ID: $cacheKey"
if gh cache delete $cacheKey; then
echo " ✓ Successfully deleted cache $cacheKey"
((deleted++))
else
echo " ✗ Failed to delete cache $cacheKey"
((failed++))
fi
done
echo "::endgroup::"
echo "::notice::Cache cleanup complete: $deleted deleted, $failed failed out of $cacheCount total"
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge
cleanup-branches:
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
actions: write
strategy:
fail-fast: false
matrix:
ref:
- refs/heads/main
- refs/heads/v1.9
steps:
- name: Cleanup stale julia caches on ${{ matrix.ref }}
run: |
echo "::group::Julia cache list for $REF"
# Filter at source with --key (prefix match) so non-julia caches
# don't push stale julia entries past the --limit window.
caches=$(gh cache list --ref "$REF" --key julia-cache --limit 100 --json id,key,createdAt,sizeInBytes)
total=$(echo "$caches" | jq 'length')
echo "Found $total julia cache(s) on $REF"
if [ "$total" -eq 0 ]; then
echo "::endgroup::"
echo "::notice::No julia caches on $REF"
exit 0
fi
# Group key is the cache key with run_id=... onwards stripped.
# Sort by createdAt descending so the newest cache per group comes first;
# awk keeps the first occurrence of each group (newest) and prints the rest.
toDelete=$(echo "$caches" \
| jq -r '.[] | "\(.createdAt)|\(.id)|\(.sizeInBytes)|\(.key | split(";run_id=") | .[0])"' \
| sort -r \
| awk -F'|' 'seen[$4]++ { print $2 "|" $3 "|" $4 }')
deleteCount=$(echo "$toDelete" | grep -c '|' || true)
keepCount=$((total - deleteCount))
echo "Will delete $deleteCount stale cache(s), keep $keepCount newest per (workflow, os)"
echo "::endgroup::"
if [ "$deleteCount" -eq 0 ]; then
echo "::notice::Nothing to delete on $REF - all caches are already the newest per (workflow, os)"
exit 0
fi
## Do not fail the workflow on a single delete error.
set +e
echo "::group::Deleting stale caches"
deleted=0
failed=0
freedMb=0
while IFS='|' read -r id size group; do
[ -z "$id" ] && continue
mb=$((size / 1024 / 1024))
echo "Deleting cache $id (${mb}MB) - group: $group"
if gh cache delete "$id"; then
echo " ✓ deleted"
deleted=$((deleted + 1))
freedMb=$((freedMb + mb))
else
echo " ✗ failed"
failed=$((failed + 1))
fi
done <<< "$toDelete"
echo "::endgroup::"
echo "::notice::Cleanup complete on $REF: $deleted deleted (${freedMb}MB freed), $failed failed"
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
REF: ${{ matrix.ref }}