mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-28 22:55:41 +00:00
The doctl --format output was being incorrectly parsed, causing the script to read size values (18.67 MB) as dates. This resulted in all images being deleted, including those with the 'latest' tag. Switch to --output json with jq parsing for reliable field extraction. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
93 lines
3.3 KiB
YAML
93 lines
3.3 KiB
YAML
name: Cleanup Old Container Images
|
|
|
|
on:
|
|
schedule:
|
|
# Run daily at 3am UTC
|
|
- cron: '0 3 * * *'
|
|
workflow_dispatch:
|
|
inputs:
|
|
dry_run:
|
|
description: 'Dry run (show what would be deleted without deleting)'
|
|
required: true
|
|
default: 'true'
|
|
type: boolean
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
cleanup:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Install doctl
|
|
uses: digitalocean/action-doctl@v2
|
|
with:
|
|
token: ${{ secrets.DO_REGISTRY_TOKEN }}
|
|
|
|
- name: Cleanup old images
|
|
env:
|
|
DRY_RUN: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run == 'true' }}
|
|
run: |
|
|
set -e
|
|
|
|
RETENTION_DAYS=5
|
|
CUTOFF_DATE=$(date -d "-${RETENTION_DAYS} days" +%s)
|
|
REGISTRY="eagle0"
|
|
|
|
echo "Cleaning up images older than ${RETENTION_DAYS} days"
|
|
echo "Cutoff date: $(date -d "@${CUTOFF_DATE}" -Iseconds)"
|
|
echo "Dry run: ${DRY_RUN}"
|
|
echo ""
|
|
|
|
# List of repositories to clean
|
|
# Use tail to skip header row in case --no-header doesn't work
|
|
REPOS=$(doctl registry repository list-v2 --format Name --no-header | grep -v '^Name$' | grep -v '^$')
|
|
|
|
for REPO in $REPOS; do
|
|
echo "=== Processing repository: ${REPO} ==="
|
|
|
|
# Get all manifests with their tags and dates using JSON output for reliable parsing
|
|
MANIFESTS_JSON=$(doctl registry repository list-manifests "${REPO}" --output json 2>/dev/null || echo "[]")
|
|
|
|
if [ "$MANIFESTS_JSON" = "[]" ] || [ -z "$MANIFESTS_JSON" ]; then
|
|
echo " No manifests found"
|
|
continue
|
|
fi
|
|
|
|
# Parse JSON and process each manifest
|
|
echo "$MANIFESTS_JSON" | jq -r '.[] | "\(.digest) \(.updated_at) \(.tags // [] | join(","))"' | while read -r DIGEST UPDATED_AT TAGS; do
|
|
# Skip if no digest or if it doesn't look like a valid digest (sha256:...)
|
|
if [ -z "$DIGEST" ] || ! echo "$DIGEST" | grep -q '^sha256:'; then
|
|
continue
|
|
fi
|
|
|
|
# Parse the date (ISO 8601 format from JSON)
|
|
MANIFEST_DATE=$(date -d "$UPDATED_AT" +%s 2>/dev/null || echo "0")
|
|
|
|
# Skip protected tags (latest, arm64-latest)
|
|
if echo ",$TAGS," | grep -qE ',(latest|arm64-latest),'; then
|
|
echo " KEEP: ${DIGEST:0:20}... (protected tag: $TAGS)"
|
|
continue
|
|
fi
|
|
|
|
# Check if older than cutoff
|
|
if [ "$MANIFEST_DATE" -lt "$CUTOFF_DATE" ]; then
|
|
echo " DELETE: ${DIGEST:0:20}... (updated: $UPDATED_AT, tags: $TAGS)"
|
|
if [ "$DRY_RUN" != "true" ]; then
|
|
doctl registry repository delete-manifest "${REPO}" "$DIGEST" --force
|
|
fi
|
|
else
|
|
echo " KEEP: ${DIGEST:0:20}... (updated: $UPDATED_AT, tags: $TAGS)"
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
done
|
|
|
|
- name: Run garbage collection
|
|
if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run == 'false')
|
|
run: |
|
|
echo "Starting garbage collection..."
|
|
doctl registry garbage-collection start --force
|
|
echo "Garbage collection started. It may take a few minutes to complete."
|