Files
bootc-images/prune-registry.sh
T
Misthios 357bf16479
Build containers / Compute changes (push) Successful in 3s
Build containers / fedora-cosmic (rawhide) (push) Failing after 58s
Build containers / fedora-remote (44) (push) Successful in 10m43s
Build containers / fedora-cosmic (44) (push) Successful in 13m20s
Build containers / Prune old releases and tags (push) Successful in 27s
prune: don't abort when a distro has no versioned tags
fedora-remote has no rawhide.* tags yet, so grep exited non-zero and, under
set -e/pipefail, killed prune-registry.sh before it reported anything. Tolerate
an empty match.
2026-09-28 17:59:50 +02:00

79 lines
2.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Prune old container image versions (tags) for an image in the Gitea registry.
#
# Keeps the moving tag (e.g. "44") and the newest versioned tag per distro,
# plus the cosign signature tag (sha256-<digest>.sig) for each kept image.
#
# Usage:
# REGISTRY_TOKEN=<write:package> REGISTRY_USERNAME=<user> \
# ./prune-registry.sh [image] [owner] [distro...]
set -euo pipefail
IMAGE="${1:-fedora-cosmic}"; shift || true
OWNER="${1:-Misthios}"; shift || true
DISTROS=("$@"); [[ ${#DISTROS[@]} -gt 0 ]] || DISTROS=(44 rawhide)
GITEA_URL="${GITEA_URL:-https://git.plabble.org}"
REGISTRY_HOST="${REGISTRY_HOST:-$(printf '%s' "${GITEA_URL}" | sed -E 's#https?://##')}"
TOKEN="${REGISTRY_TOKEN:?REGISTRY_TOKEN (write:package) is required}"
AUTHFILE="${AUTHFILE:-${HOME}/.docker/config.json}"
API="${GITEA_URL%/}/api/v1/packages/${OWNER}/container/${IMAGE}"
# Registry paths are lowercase (the Gitea API owner is not).
IMAGE_REF="${REGISTRY_HOST}/$(printf '%s' "${OWNER}" | tr '[:upper:]' '[:lower:]')/${IMAGE}"
# Collect all versions (paginated).
versions=""
page=1
while :; do
page_json="$(curl -fsSL -H "Authorization: token ${TOKEN}" \
"${API}?limit=50&page=${page}")" || break
[[ "$(jq 'length' <<< "${page_json}")" -eq 0 ]] && break
versions+="$(jq -r '.[].version' <<< "${page_json}")"$'\n'
page=$((page + 1))
[[ "${page}" -gt 40 ]] && break
done
# Decide what to keep.
declare -A keep=()
for d in "${DISTROS[@]}"; do
keep["${d}"]=1
# A distro that has no versioned tags yet is fine; don't let grep's non-zero
# exit status abort the script under set -e/pipefail.
newest="$(grep -E "^${d}\.[0-9]+\.[0-9]+$" <<< "${versions}" \
| sort -t. -k2,2n -k3,3n | tail -1 || true)"
[[ -n "${newest}" ]] && keep["${newest}"]=1
done
# Keep the cosign signature of each kept image tag. If no digest could be
# resolved, keep every signature tag rather than risk deleting a needed one.
resolved=0
for tag in "${!keep[@]}"; do
[[ "${tag}" == sha256-* ]] && continue
digest="$(skopeo inspect --authfile "${AUTHFILE}" --format '{{.Digest}}' \
"docker://${IMAGE_REF}:${tag}" 2>/dev/null || true)"
if [[ -n "${digest}" ]]; then
keep["sha256-${digest#sha256:}.sig"]=1
resolved=1
fi
done
if [[ "${resolved}" -eq 0 ]]; then
echo "WARNING: could not resolve any image digest; keeping all signature tags"
while IFS= read -r v; do
[[ "${v}" == sha256-* ]] && keep["${v}"]=1
done <<< "${versions}"
fi
# Delete everything else.
while IFS= read -r v; do
[[ -z "${v}" ]] && continue
if [[ -n "${keep[${v}]:-}" ]]; then
echo "keep ${v}"
else
echo "remove ${v}"
curl -fsSL -X DELETE -H "Authorization: token ${TOKEN}" \
"${API}/${v}" >/dev/null || echo " (failed to delete ${v})"
fi
done <<< "${versions}"
echo "Pruned ${IMAGE} registry versions."