You've already forked .autoupdate
The six nightly workflows each cloned a package repo and ran that repo's own
push.sh. Two problems compounded into months of silent breakage.
push.sh pushed to origin before the AUR. When the AUR push failed, origin
already carried the new version, so every later run hit "same (old) version
specified", bare-exit 0'd, and the workflow went green while the AUR rotted.
reflex-appimage sat at 1.0.11 locally against 1.0.10 published; nethlink-appimage
was never submitted at all.
The AUR pushes were failing because .SRCINFO was empty -- 0 bytes in
reflex-appimage, 1 byte in nethlink-appimage and pman-helper, against 500-2000
in the healthy ones. The AUR rejects an invalid .SRCINFO. Both PKGBUILDs verify
clean under a real Arch makepkg, so this was the CI environment, and with no
set -e the script committed and pushed the truncated file regardless.
pman-helper failed independently: the workflows queried the Gitea endpoint
/repos/{owner}/{repo}/repo/tags, which 404s -- the correct path is /tags. The
empty result fell through to an interactive read that got EOF, and it committed
pkgver="" plus the sha256 of a zero-byte download.
The replacement is a reconciler rather than a version-bump script. A new
upstream release, a manual push to origin, and a push that failed last night
all take the same path, and the AUR reconcile runs on every pass -- so a failed
push simply retries. Sync is decided by comparing tree content against the AUR,
not by whether this run happened to find something new.
pkgrel is now derived from the AUR rather than from local history, which is
what makes it idempotent: a version differing from the published one resets it
to 1, a packaging change increments it, and once published the next run sees no
difference and does nothing. Editing a PKGBUILD no longer needs a manual bump.
Checksums are computed directly instead of via makepkg -g / updpkgsums. Those
generate every arch array in one pass into a single directory, so when two
arches rename to the same target the second finds the first one's file and
emits an identical, silently wrong sum -- verified against freetube-appimage.
Downloads go to content-addressed cache paths instead. Multi-arch works for
when it is needed; single-arch is the degenerate case of the same loop.
Guards for each observed failure: a real Arch makepkg in an archlinux container
as non-root, set -euo pipefail throughout, .SRCINFO validated against the
PKGBUILD before any commit, and a failed version lookup exiting 1 so it can
never again be mistaken for a quiet "no new version" night.
Package-specific detail moves out of this repo entirely, into an .autoupdate
manifest committed to each package repo. sha256 only; sha1sums and md5sums are
removed. deskflow-bin and freetube-appimage are dropped from automation, having
been deleted from the AUR.
Covered by test.sh: 37 assertions against local bare repos and a local HTTP
server, no network and never touching the real AUR. The retry, pkgrel
idempotence and multi-arch collision tests were each verified by mutation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
80 lines
2.9 KiB
Bash
Executable File
80 lines
2.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Reconcile a package repo against its AUR counterpart.
|
|
#
|
|
# usage: sync-aur.sh [package-dir]
|
|
#
|
|
# This is the fix for the original bug. The old push.sh pushed to origin first
|
|
# and to the AUR second, so a failed AUR push left origin already carrying the
|
|
# new version; every later run then hit "same (old) version specified" and
|
|
# bare-exit 0'd, and the AUR silently rotted forever.
|
|
#
|
|
# Here the AUR is reconciled from STATE, not from events: this runs on every
|
|
# nightly pass regardless of whether a new upstream version was found, so a
|
|
# push that failed last night is simply retried tonight.
|
|
|
|
set -euo pipefail
|
|
|
|
_here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
# shellcheck source=common.sh
|
|
source "${_here}/common.sh"
|
|
|
|
pkgdir="${1:-.}"
|
|
cd "$pkgdir"
|
|
|
|
pkgname="$(pkgbuild_get pkgname)"
|
|
# pkgname may be written as "${_pkgname}-appimage"; expand it properly.
|
|
case "$pkgname" in
|
|
*'$'*) pkgname="$(pkgbuild_expand PKGBUILD 'printf %s "$pkgname"')" ;;
|
|
esac
|
|
[ -n "$pkgname" ] || die "could not determine pkgname"
|
|
|
|
aur_url="${AUR_SSH_BASE}/${pkgname}.git"
|
|
# Read over HTTPS so determining sync state needs no SSH key; only the push
|
|
# itself is authenticated. This keeps NO_GIT_PUSH dry runs working anywhere.
|
|
aur_ro_url="${AUR_HTTPS_BASE}/${pkgname}.git"
|
|
|
|
# `git remote add` fails if the remote already exists, which it does whenever
|
|
# this runs twice in one working copy.
|
|
git remote remove aur >/dev/null 2>&1 || true
|
|
git remote add aur "$aur_url"
|
|
git remote remove aur-ro >/dev/null 2>&1 || true
|
|
git remote add aur-ro "$aur_ro_url"
|
|
|
|
if git fetch --quiet aur-ro master 2>/dev/null; then
|
|
# Compare the CONTENT of the whole tree rather than commit hashes: origin
|
|
# accumulates commits the AUR never needs, and a re-derived commit has a
|
|
# different hash but an identical tree. No pathspec, because we push the
|
|
# whole tree -- restricting to PKGBUILD/.SRCINFO would report "in sync"
|
|
# while .desktop/.png/LICENSE actually differ.
|
|
if git diff --quiet FETCH_HEAD HEAD; then
|
|
log "AUR already in sync (${pkgname})"
|
|
exit 0
|
|
fi
|
|
log "AUR differs from origin; pushing (${pkgname})"
|
|
else
|
|
log "no AUR repo for ${pkgname} yet; the first push will create it"
|
|
fi
|
|
|
|
if [ -n "${NO_GIT_PUSH:-}" ]; then
|
|
log "NO_GIT_PUSH set: skipping push to ${aur_url}"
|
|
exit 0
|
|
fi
|
|
|
|
if git push aur HEAD:master; then
|
|
log "pushed ${pkgname} to the AUR"
|
|
exit 0
|
|
fi
|
|
|
|
# A rejected push here usually means the AUR has commits origin does not,
|
|
# i.e. someone pushed directly. Overwriting that silently would destroy it.
|
|
if [ -n "${AUR_FORCE:-}" ]; then
|
|
warn "AUR_FORCE set: force-pushing over the AUR history for ${pkgname}"
|
|
git push --force aur HEAD:master
|
|
exit 0
|
|
fi
|
|
|
|
die "push to the AUR was rejected for ${pkgname}.
|
|
The AUR history has probably diverged from origin (someone pushed there
|
|
directly). Inspect it, then re-run with AUR_FORCE=1 to overwrite.
|
|
This run leaves origin untouched and will be retried on the next pass."
|