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
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.
79 lines
2.8 KiB
Bash
Executable File
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."
|