Closes #52. Adds `scripts/prune-release-assets.sh` and a best-effort step at the end of `build-binaries.yml`. - Lists every release page, sorts by creation date, skips the newest two published releases, deletes the rest's attachments via `DELETE /releases/{id}/assets/{asset_id}`. - Drafts never consume a keep slot, so a draft cannot strip the newest real release. - Releases, tags, source archives and release notes are never touched. - Nothing is excluded: SHA256SUMS and the wrappers go with the binaries. Checksums are only meaningful next to the files they cover, and the consumer drift-check reads the wrappers from the latest release, which stays complete. - Failures warn and the step has `continue-on-error: true` — a stale asset is cheaper than a blocked publish. `tests/prune-release-assets.sh` drives the script with a stub `curl`: keep window, out-of-order responses, drafts, no non-asset DELETE, short-page pagination stop, and both failure paths. Wired into `make check`. v0.2.0 still needs its 9 assets cleared by hand in the web UI, as the issue notes. 🤖 Generated with [Claude Code](https://claude.com/claude-code)Reviewed-on: #70 Co-authored-by: vickydotbat <vickydotbat@tutamail.com>
This commit was merged in pull request #70.
This commit is contained in:
Executable
+67
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env bash
|
||||
# Delete the binary assets of every release except the newest KEEP ones.
|
||||
#
|
||||
# Gitea has no asset retention, so 9 assets x ~57 MB per tag pile up forever on
|
||||
# the host disk (sow-tools #52). Nothing consumes an old asset: CI takes the
|
||||
# Crucible binary from the Nix flake, and every deleted file is reproducible
|
||||
# from its tag. Tags, source archives, release notes and the releases
|
||||
# themselves are never touched — only attachments.
|
||||
#
|
||||
# Nothing is excluded, SHA256SUMS and the wrappers included: the checksums are
|
||||
# only meaningful next to the binaries they cover, and the drift-check reads
|
||||
# the wrappers from the latest release, which always stays complete.
|
||||
#
|
||||
# Best-effort by design: a stale asset is cheaper than a blocked release, so
|
||||
# every API failure is a warning, never a non-zero exit.
|
||||
#
|
||||
# Env:
|
||||
# API repo API base, e.g. https://git.example/api/v1/repos/owner/repo [required]
|
||||
# TOKEN Gitea token with releases:write [required]
|
||||
# KEEP how many newest releases stay complete (default 2)
|
||||
set -uo pipefail
|
||||
|
||||
: "${API:?set API}"
|
||||
: "${TOKEN:?set TOKEN}"
|
||||
keep="${KEEP:-2}"
|
||||
auth="Authorization: token ${TOKEN}"
|
||||
per_page=50
|
||||
|
||||
warn() { echo "prune-release-assets: $*" >&2; }
|
||||
|
||||
# Walk every page so an old backlog is cleared, not only the tag that fell out
|
||||
# of the window on this run. Each page already embeds its releases' assets, so
|
||||
# no follow-up request per release is needed.
|
||||
releases='[]'
|
||||
page=1
|
||||
while :; do
|
||||
body="$(curl -fsS -H "$auth" "${API}/releases?limit=${per_page}&page=${page}&draft=false")" || {
|
||||
warn "listing releases failed on page ${page}; pruning what was listed so far"
|
||||
break
|
||||
}
|
||||
count="$(jq 'length' <<<"$body")" || { warn "unreadable release page ${page}"; break; }
|
||||
releases="$(jq -s 'add' <(printf '%s' "$releases") <(printf '%s' "$body"))"
|
||||
# A short page is the last one; this also stops a server that ignores `page`.
|
||||
(( count < per_page )) && break
|
||||
page=$(( page + 1 ))
|
||||
done
|
||||
|
||||
# Sort here rather than trusting the response order, and skip drafts in case
|
||||
# the server ignored `draft=false` — a draft must not consume a keep slot and
|
||||
# strip the binaries off the newest real release.
|
||||
mapfile -t stale < <(jq -r --argjson keep "$keep" '
|
||||
[.[] | select(.draft != true)]
|
||||
| sort_by(.created_at) | reverse | .[$keep:]
|
||||
| .[] | "\(.id) \(.assets // [] | map(.id) | join(","))"
|
||||
' <<<"$releases")
|
||||
|
||||
(( ${#stale[@]} )) || { echo "prune-release-assets: nothing older than the newest ${keep} releases"; exit 0; }
|
||||
|
||||
for line in "${stale[@]}"; do
|
||||
id="${line%% *}"
|
||||
assets="${line#* }"
|
||||
for asset in ${assets//,/ }; do
|
||||
echo "deleting asset ${asset} of release ${id}"
|
||||
curl -fsS -X DELETE -H "$auth" "${API}/releases/${id}/assets/${asset}" >/dev/null \
|
||||
|| warn "deleting asset ${asset} of release ${id} failed"
|
||||
done
|
||||
done
|
||||
Reference in New Issue
Block a user