Cleanup Interim Images #3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Cleanup Interim Images | |
| # Deletes GHCR package versions whose tags are exclusively build-* (ephemeral | |
| # per-commit images). Versions carrying any other tag (v*, edge, latest, etc.) | |
| # are never touched. Runs weekly and can be triggered manually. | |
| on: | |
| schedule: | |
| - cron: '0 8 * * 1' # Monday 08:00 UTC | |
| workflow_dispatch: | |
| # Serialise with docker-publish to avoid deleting a build-* image that a | |
| # concurrent release promotion is about to resolve. cancel-in-progress: false | |
| # makes cleanup wait rather than be killed. | |
| concurrency: | |
| group: docker-refs/heads/main | |
| cancel-in-progress: false | |
| permissions: | |
| contents: read | |
| packages: write | |
| jobs: | |
| cleanup: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Delete stale build-* package versions | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| OWNER="${{ github.repository_owner }}" | |
| PACKAGE="${{ github.event.repository.name }}" | |
| DELETED=0 | |
| KEPT=0 | |
| echo "Fetching package versions for ${OWNER}/${PACKAGE}..." | |
| # Collect all versions into a temp file (handles pagination via --paginate) | |
| gh api \ | |
| -H "Accept: application/vnd.github+json" \ | |
| "/users/${OWNER}/packages/container/${PACKAGE}/versions" \ | |
| --paginate > /tmp/versions.json | |
| TOTAL=$(jq 'length' /tmp/versions.json) | |
| echo "Found ${TOTAL} total package versions." | |
| echo "" | |
| jq -c '.[]' /tmp/versions.json | while read -r version; do | |
| VERSION_ID=$(echo "$version" | jq -r '.id') | |
| TAGS=$(echo "$version" | jq -r '.metadata.container.tags // [] | .[]') | |
| # Skip untagged versions — never delete them (likely referenced by a manifest list) | |
| if [ -z "$TAGS" ]; then | |
| echo "KEEP [${VERSION_ID}] (untagged)" | |
| continue | |
| fi | |
| TAG_LIST=$(echo "$TAGS" | tr '\n' ' ' | sed 's/ $//') | |
| # Guard: keep if ANY tag does not match build-[0-9a-f]+ | |
| PROTECTED=false | |
| while IFS= read -r tag; do | |
| if [[ ! "$tag" =~ ^build-[0-9a-f]+$ ]]; then | |
| PROTECTED=true | |
| break | |
| fi | |
| done <<< "$TAGS" | |
| if [ "$PROTECTED" = true ]; then | |
| echo "KEEP [${VERSION_ID}] tags: ${TAG_LIST}" | |
| else | |
| echo "DELETE [${VERSION_ID}] tags: ${TAG_LIST}" | |
| gh api \ | |
| --method DELETE \ | |
| -H "Accept: application/vnd.github+json" \ | |
| "/users/${OWNER}/packages/container/${PACKAGE}/versions/${VERSION_ID}" | |
| fi | |
| done | |
| echo "" | |
| echo "Cleanup complete." |