From 4e43f63f4b5ae001af7a88615d9409a4fe8afebb Mon Sep 17 00:00:00 2001 From: Eric Gullickson <16152721+ericgullickson@users.noreply.github.com> Date: Sun, 4 Jan 2026 20:05:17 -0600 Subject: [PATCH] feat: purge scripts for CI/CD artifacts --- scripts/ci/purge-action-runs.sh | 91 +++++++++++++ scripts/ci/purge-container-images.sh | 191 +++++++++++++++++++++++++++ 2 files changed, 282 insertions(+) create mode 100755 scripts/ci/purge-action-runs.sh create mode 100755 scripts/ci/purge-container-images.sh diff --git a/scripts/ci/purge-action-runs.sh b/scripts/ci/purge-action-runs.sh new file mode 100755 index 0000000..07ec6c9 --- /dev/null +++ b/scripts/ci/purge-action-runs.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Defaults (override via CLI flags) +GITEA_BASE_URL="https://git.motovaultpro.com" +TOKEN="" +OWNER="egullickson" +REPO="motovaultpro" +PER_PAGE=50 + +usage() { + cat </dev/null + deleted=$((deleted + 1)) + done <<< "${ids}" + + page=$((page + 1)) +done + +echo "Done. Deleted ${deleted} runs." diff --git a/scripts/ci/purge-container-images.sh b/scripts/ci/purge-container-images.sh new file mode 100755 index 0000000..9fa3d5e --- /dev/null +++ b/scripts/ci/purge-container-images.sh @@ -0,0 +1,191 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ============================================================================= +# Defaults (override via CLI flags) +# ============================================================================= +REGISTRY="https://git.motovaultpro.com" +USERNAME="egullickson" +TOKEN="" +KEEP_TAG="latest" +DRY_RUN=1 + +REPOS=( + "egullickson/frontend" + "egullickson/backend" +) +# ============================================================================= + +need() { command -v "$1" >/dev/null || { echo "ERROR: missing dependency: $1"; exit 1; }; } +need curl +need jq + +usage() { + cat </dev/null +} + +purge_repo_keep_tag() { + local repo="$1" + echo "== Purging ${repo} (keep ${KEEP_TAG}) ==" + + local auth + auth="$(auth_header_for_repo "$repo")" + + local json tags + json="$(tags_list "$repo" "$auth")" + tags="$(echo "$json" | jq -r '.tags[]?' | sort || true)" + + if [[ -z "$tags" ]]; then + echo "No tags found." + echo + return 0 + fi + + if ! echo "$tags" | grep -qx "${KEEP_TAG}"; then + echo "WARN: No '${KEEP_TAG}' tag found; refusing to purge ${repo}." + echo "$tags" | sed 's/^/ - /' + echo + return 0 + fi + + local keep_digest + keep_digest="$(digest_for_tag "$repo" "$KEEP_TAG" "$auth" || true)" + if [[ -z "$keep_digest" ]]; then + echo "ERROR: Could not resolve digest for ${repo}:${KEEP_TAG}" + echo "Tip: curl -vI -H \"$auth\" ${REGISTRY}/v2/${repo}/manifests/${KEEP_TAG}" + echo + return 1 + fi + echo "${KEEP_TAG} digest: ${keep_digest}" + + # Collect digests referenced by non-KEEP_TAG tags (skipping those equal to keep_digest) + local digests=() + while read -r tag; do + [[ -z "$tag" || "$tag" == "$KEEP_TAG" ]] && continue + + local d + d="$(digest_for_tag "$repo" "$tag" "$auth" || true)" + if [[ -z "$d" ]]; then + echo "WARN: couldn't resolve digest for tag=${tag} (skipping)" + continue + fi + + if [[ "$d" == "$keep_digest" ]]; then + echo "SKIP: tag=${tag} points to ${KEEP_TAG} digest (deleting would remove ${KEEP_TAG} too)" + continue + fi + + digests+=("$d") + done <<< "$tags" + + if [[ "${#digests[@]}" -eq 0 ]]; then + echo "Nothing to delete." + echo + return 0 + fi + + echo "Will delete (deduped) manifest(s) (and all tags pointing to them)." + printf '%s\n' "${digests[@]}" | sort -u | while read -r digest; do + [[ -z "$digest" ]] && continue + echo "Deleting digest: $digest" + if ! delete_digest "$repo" "$digest" "$auth"; then + echo "WARN: delete failed for $digest" + fi + done + + echo "Done." + echo +} + +for repo in "${REPOS[@]}"; do + purge_repo_keep_tag "$repo" +done + +echo "Complete."