forked from unom/punktfunk
fix(ci/arch): the release-rebuild prune called a helper that cannot exist there
The v0.25.0 rebuild published perfectly — registry has punktfunk-host 0.25.0-2 with
libavcodec.so=63-64, and it resolves on a real ffmpeg-9 box — then failed its last
step with
prune_release_assets: command not found
`. scripts/ci/gitea-release.sh` sources from the CHECKED-OUT TREE, and a release
rebuild checks out the OLD TAG. So the step could only ever see the helpers that
existed when that tag was cut, and the prune is gated on exactly that path: the
helper was guaranteed absent in the only case that calls it. Adding it to a shared
script made it look available at review time while being unreachable at run time.
Only the workflow file is read from the dispatched ref, so the logic moves there,
inline. Same reasoning documented at both ends, including the corollary worth knowing
before the next rebuild: a PKGBUILD fix made after a tag does NOT reach a rebuild of
that tag either — the packaging comes from the tag too.
Verified by executing the one-liner's exact bytes out of arch.yml under /bin/sh (the
shell Gitea actually uses): keeps the new -2 set and gamescope, drops the superseded
-1 packages and their .sha256 sidecars, leaves other legs' .dmg/.deb untouched. The
`'\n'` survives the shell quoting, which was the part worth proving.
Also drops the now-dead helper from gitea-release.sh rather than leaving a function
no caller can reach, and leaves a warning there against the next one.
This commit is contained in:
@@ -420,10 +420,29 @@ jobs:
|
||||
# A rebuild bumps pkgrel, so its FILENAMES differ from the ones already attached, and
|
||||
# upsert_asset only replaces by name — the superseded set would survive untouched.
|
||||
# Drop every pacman asset (and .sha256 sidecar) this upload did not just write.
|
||||
#
|
||||
# ⚠⚠ THIS MUST LIVE IN THE WORKFLOW, NOT IN scripts/ci/gitea-release.sh. The sourced
|
||||
# script comes from the CHECKED-OUT TREE, which on a release rebuild is the OLD TAG —
|
||||
# so it can only ever offer the helpers that existed when that tag was cut. A helper
|
||||
# added for this feature is therefore guaranteed ABSENT in the one code path that
|
||||
# calls it: the first attempt failed with `prune_release_assets: command not found`
|
||||
# after publishing perfectly. Only the workflow file itself is taken from the ref you
|
||||
# dispatch. Same reason a packaging fix made after a tag does NOT reach a rebuild of
|
||||
# that tag — the PKGBUILD is the tag's too.
|
||||
if [ -n "${RELEASE_TAG:-}" ]; then
|
||||
KEEP="$(cd dist && printf '%s ' *.pkg.tar.zst)"
|
||||
# An UNMATCHED glob would come through literally and match nothing in the keep set —
|
||||
# i.e. "delete every pacman asset on the release". Empty out instead; prune refuses.
|
||||
# i.e. "delete every pacman asset on the release". Skip entirely instead.
|
||||
case "$KEEP" in *'*'*) KEEP="" ;; esac
|
||||
prune_release_assets "$RID" .pkg.tar.zst "$KEEP"
|
||||
API="$GITHUB_SERVER_URL/api/v1/repos/$GITHUB_REPOSITORY"
|
||||
if [ -n "$KEEP" ]; then
|
||||
curl -fsS "$API/releases/$RID/assets" -H "Authorization: token $GITEA_TOKEN" \
|
||||
| python3 -c "import json,sys;k=set(sys.argv[1].split());k|={n+'.sha256' for n in k};print('\n'.join('%s %s'%(a['id'],a['name']) for a in json.load(sys.stdin) if a.get('name','').endswith(('.pkg.tar.zst','.pkg.tar.zst.sha256')) and a['name'] not in k))" "$KEEP" \
|
||||
| while read -r id name; do
|
||||
[ -n "$id" ] || continue
|
||||
echo "dropping superseded release asset: $name"
|
||||
curl -fsS -o /dev/null -X DELETE "$API/releases/$RID/assets/$id" \
|
||||
-H "Authorization: token $GITEA_TOKEN" || true
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -38,18 +38,11 @@ for a in json.load(sys.stdin):
|
||||
print(a.get("id",""));break' "$1" 2>/dev/null
|
||||
}
|
||||
_urlencode() { python3 -c 'import urllib.parse,sys;print(urllib.parse.quote(sys.argv[1],safe=""))' "$1"; }
|
||||
# _json_stale_asset_ids SUFFIX KEEP_NAMES (assets JSON on stdin) -> "<id> <name>" lines
|
||||
# The assets matching SUFFIX (or its .sha256 sidecar) that are NOT in the whitespace-separated
|
||||
# KEEP_NAMES. See prune_release_assets.
|
||||
_json_stale_asset_ids() {
|
||||
python3 -c 'import json,sys
|
||||
suffix, keep = sys.argv[1], set(sys.argv[2].split())
|
||||
keep |= {n + ".sha256" for n in keep}
|
||||
for a in json.load(sys.stdin):
|
||||
n = a.get("name", "")
|
||||
if n.endswith((suffix, suffix + ".sha256")) and n not in keep:
|
||||
print(a.get("id", ""), n)' "$1" "$2" 2>/dev/null
|
||||
}
|
||||
# ⚠ Do NOT add helpers here for a workflow step that runs against a CHECKED-OUT RELEASE TAG
|
||||
# (arch.yml's release-rebuild dispatch). Callers source this file from the working tree, so such a
|
||||
# step gets the version of this file that shipped in that tag — never the one you just wrote. That
|
||||
# logic belongs in the workflow, which is always read from the dispatched ref. Cost this once
|
||||
# already: `prune_release_assets: command not found`, after the packages published fine.
|
||||
|
||||
# _release_notes_path TAG
|
||||
# Print the path of the in-repo release notes for TAG (docs/releases/<TAG>.md) IFF it exists,
|
||||
@@ -177,32 +170,6 @@ upsert_asset() {
|
||||
if _put_asset "$rid" "$sums" "$name.sha256"; then rm -f "$sums"; else rm -f "$sums"; return 1; fi
|
||||
}
|
||||
|
||||
# prune_release_assets RELEASE_ID SUFFIX KEEP_NAMES
|
||||
# Delete every asset of the release whose name ends in SUFFIX (or SUFFIX.sha256) and is not one
|
||||
# of KEEP_NAMES (whitespace-separated).
|
||||
#
|
||||
# WHY: upsert_asset replaces an asset BY NAME, which is idempotent only while the filename is
|
||||
# stable. A REBUILD of an already-published release is exactly the case where it is not — a
|
||||
# distro moved under the release, the artifact is rebuilt at a higher pkgrel, and
|
||||
# `punktfunk-host-0.25.0-2-x86_64.pkg.tar.zst` collides with nothing, so the -1 build stays
|
||||
# attached. A superseded package on a release page is not clutter; it is a live download of the
|
||||
# very build the rebuild exists to replace. Scoped by SUFFIX because a release object is shared
|
||||
# by ~8 packaging workflows running concurrently — each leg may only ever prune names it owns.
|
||||
prune_release_assets() {
|
||||
local rid="${1:?release id}" suffix="${2:?suffix}" keep="${3:-}"
|
||||
local api
|
||||
# An empty keep list means "delete every asset matching SUFFIX", which is never what a caller
|
||||
# wants and is exactly what a mis-expanded glob looks like. Refuse rather than clear a release.
|
||||
[ -n "$keep" ] || { echo "gitea-release: prune_release_assets got an empty keep list — refusing" >&2; return 0; }
|
||||
api="$(_gitea_api)"
|
||||
curl -fsS "$api/releases/$rid/assets" -H "Authorization: token ${GITEA_TOKEN:?}" \
|
||||
| _json_stale_asset_ids "$suffix" "$keep" \
|
||||
| while read -r id name; do
|
||||
echo "gitea-release: dropping superseded asset '$name'"
|
||||
curl -fsS -o /dev/null -X DELETE "$api/releases/$rid/assets/$id" \
|
||||
-H "Authorization: token ${GITEA_TOKEN:?}" || true
|
||||
done
|
||||
}
|
||||
|
||||
# apply_release_notes RELEASE_ID TAG
|
||||
# Force the release body to match docs/releases/<TAG>.md (the source of truth), if that file
|
||||
|
||||
Reference in New Issue
Block a user