You've already forked .autoupdate
Replace per-package push scripts with a self-healing AUR reconciler
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.
This commit is contained in:
@@ -1,34 +0,0 @@
|
||||
---
|
||||
name: Update deskflow-bin Package
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
update:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: |
|
||||
apt-get --quiet update && apt-get --quiet --assume-yes install makepkg
|
||||
git config --global user.name "${GIT_NAME}"
|
||||
git config --global user.email "${GIT_EMAIL}"
|
||||
git config --global credential.helper store
|
||||
echo "https://${GIT_EMAIL//@/%40}:${GIT_TOKEN}@${GIT_HOST}" > ~/.git-credentials
|
||||
git clone --depth 1 https://${GIT_HOST}/aur/deskflow-bin
|
||||
cd deskflow-bin
|
||||
source PKGBUILD
|
||||
./push.sh $(curl -L -H "Accept: application/vnd.github+json" \
|
||||
https://api.github.com/repos/${_srcmntr}/${_srcname}/releases/latest | jq -r ".tag_name" | sed 's|v||')
|
||||
env:
|
||||
GIT_NAME: ${{ vars.GIT_NAME }}
|
||||
GIT_EMAIL: ${{ vars.GIT_EMAIL }}
|
||||
GIT_HOST: ${{ vars.GIT_HOST }}
|
||||
GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
|
||||
@@ -1,34 +0,0 @@
|
||||
---
|
||||
name: Update nethlink-appimage Package
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
update:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: |
|
||||
apt-get --quiet update && apt-get --quiet --assume-yes install makepkg
|
||||
git config --global user.name "${GIT_NAME}"
|
||||
git config --global user.email "${GIT_EMAIL}"
|
||||
git config --global credential.helper store
|
||||
echo "https://${GIT_EMAIL//@/%40}:${GIT_TOKEN}@${GIT_HOST}" > ~/.git-credentials
|
||||
git clone --depth 1 https://${GIT_HOST}/aur/nethlink-appimage
|
||||
cd nethlink-appimage
|
||||
source PKGBUILD
|
||||
./push.sh $(curl -L -H "Accept: application/vnd.github+json" \
|
||||
https://api.github.com/repos/${_srcmntr}/${_srcname}/releases/latest | jq -r ".tag_name" | sed 's|v||')
|
||||
env:
|
||||
GIT_NAME: ${{ vars.GIT_NAME }}
|
||||
GIT_EMAIL: ${{ vars.GIT_EMAIL }}
|
||||
GIT_HOST: ${{ vars.GIT_HOST }}
|
||||
GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
|
||||
@@ -1,34 +0,0 @@
|
||||
---
|
||||
name: Update open-video-downloader-appimage Package
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
update:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: |
|
||||
apt-get --quiet update && apt-get --quiet --assume-yes install makepkg
|
||||
git config --global user.name "${GIT_NAME}"
|
||||
git config --global user.email "${GIT_EMAIL}"
|
||||
git config --global credential.helper store
|
||||
echo "https://${GIT_EMAIL//@/%40}:${GIT_TOKEN}@${GIT_HOST}" > ~/.git-credentials
|
||||
git clone --depth 1 https://${GIT_HOST}/aur/open-video-downloader-appimage
|
||||
cd open-video-downloader-appimage
|
||||
source PKGBUILD
|
||||
./push.sh $(curl -L -H "Accept: application/vnd.github+json" \
|
||||
https://api.github.com/repos/${_srcmntr}/${_srcname}/releases/latest | jq -r ".tag_name" | sed 's|app-v||')
|
||||
env:
|
||||
GIT_NAME: ${{ vars.GIT_NAME }}
|
||||
GIT_EMAIL: ${{ vars.GIT_EMAIL }}
|
||||
GIT_HOST: ${{ vars.GIT_HOST }}
|
||||
GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
|
||||
@@ -1,34 +0,0 @@
|
||||
---
|
||||
name: Update open-video-downloader-bin Package
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
update:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: |
|
||||
apt-get --quiet update && apt-get --quiet --assume-yes install makepkg
|
||||
git config --global user.name "${GIT_NAME}"
|
||||
git config --global user.email "${GIT_EMAIL}"
|
||||
git config --global credential.helper store
|
||||
echo "https://${GIT_EMAIL//@/%40}:${GIT_TOKEN}@${GIT_HOST}" > ~/.git-credentials
|
||||
git clone --depth 1 https://${GIT_HOST}/aur/open-video-downloader-bin
|
||||
cd open-video-downloader-bin
|
||||
source PKGBUILD
|
||||
./push.sh $(curl -L -H "Accept: application/vnd.github+json" \
|
||||
https://api.github.com/repos/${_srcmntr}/${_srcname}/releases/latest | jq -r ".tag_name" | sed 's|app-v||')
|
||||
env:
|
||||
GIT_NAME: ${{ vars.GIT_NAME }}
|
||||
GIT_EMAIL: ${{ vars.GIT_EMAIL }}
|
||||
GIT_HOST: ${{ vars.GIT_HOST }}
|
||||
GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
|
||||
@@ -1,34 +0,0 @@
|
||||
---
|
||||
name: Update pman-helper Package
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
update:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: |
|
||||
apt-get --quiet update && apt-get --quiet --assume-yes install makepkg
|
||||
git config --global user.name "${GIT_NAME}"
|
||||
git config --global user.email "${GIT_EMAIL}"
|
||||
git config --global credential.helper store
|
||||
echo "https://${GIT_EMAIL//@/%40}:${GIT_TOKEN}@${GIT_HOST}" > ~/.git-credentials
|
||||
git clone --depth 1 https://${GIT_HOST}/aur/pman-helper
|
||||
cd pman-helper
|
||||
source PKGBUILD
|
||||
./push.sh $(curl -L -H "Accept: application/json" \
|
||||
https://git.bjphoster.com/api/v1/repos/${_srcmntr}/${_srcname}/repo/tags | jq -r ".[].name" | sort -V | tail -n 1)
|
||||
env:
|
||||
GIT_NAME: ${{ vars.GIT_NAME }}
|
||||
GIT_EMAIL: ${{ vars.GIT_EMAIL }}
|
||||
GIT_HOST: ${{ vars.GIT_HOST }}
|
||||
GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
|
||||
@@ -1,34 +0,0 @@
|
||||
---
|
||||
name: Update reflex-appimage Package
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
update:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: |
|
||||
apt-get --quiet update && apt-get --quiet --assume-yes install makepkg
|
||||
git config --global user.name "${GIT_NAME}"
|
||||
git config --global user.email "${GIT_EMAIL}"
|
||||
git config --global credential.helper store
|
||||
echo "https://${GIT_EMAIL//@/%40}:${GIT_TOKEN}@${GIT_HOST}" > ~/.git-credentials
|
||||
git clone --depth 1 https://${GIT_HOST}/aur/reflex-appimage
|
||||
cd reflex-appimage
|
||||
source PKGBUILD
|
||||
./push.sh $(curl -L -H "Accept: application/vnd.github+json" \
|
||||
https://api.github.com/repos/${_srcmntr}/${_srcname}/releases/latest | jq -r ".tag_name" | sed 's|v||')
|
||||
env:
|
||||
GIT_NAME: ${{ vars.GIT_NAME }}
|
||||
GIT_EMAIL: ${{ vars.GIT_EMAIL }}
|
||||
GIT_HOST: ${{ vars.GIT_HOST }}
|
||||
GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
|
||||
122
.gitea/workflows/update.yaml
Normal file
122
.gitea/workflows/update.yaml
Normal file
@@ -0,0 +1,122 @@
|
||||
---
|
||||
name: Update AUR Packages
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
package:
|
||||
description: "Single package to update (blank = all)"
|
||||
required: false
|
||||
type: string
|
||||
force_rebuild:
|
||||
description: "Bump pkgrel even with no detected change"
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
force_refresh:
|
||||
description: "Re-download remote sources even without a version change"
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
no_git_push:
|
||||
description: "Dry run: do everything except push"
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
update:
|
||||
runs-on: ubuntu-latest
|
||||
# A real Arch makepkg is required. Ubuntu's build environment silently
|
||||
# emits an empty .SRCINFO, which the AUR then rejects -- that is what broke
|
||||
# reflex-appimage, nethlink-appimage and pman-helper. regen_srcinfo() in
|
||||
# common.sh fails loudly if this ever regresses.
|
||||
container:
|
||||
image: archlinux:base-devel
|
||||
|
||||
strategy:
|
||||
# One broken package must not cancel the rest of the matrix.
|
||||
fail-fast: false
|
||||
matrix:
|
||||
package:
|
||||
- nethlink-appimage
|
||||
- open-video-downloader-appimage
|
||||
- open-video-downloader-bin
|
||||
- pman-helper
|
||||
- reflex-appimage
|
||||
- tsparams
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pacman -Syu --noconfirm --needed \
|
||||
git openssh jq curl pacman-contrib namcap fuse2 python
|
||||
|
||||
- name: Configure git and SSH
|
||||
env:
|
||||
GIT_NAME: ${{ vars.GIT_NAME }}
|
||||
GIT_EMAIL: ${{ vars.GIT_EMAIL }}
|
||||
GIT_HOST: ${{ vars.GIT_HOST }}
|
||||
GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
|
||||
AUR_SSH_KEY: ${{ secrets.AUR_SSH_KEY }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
git config --global user.name "${GIT_NAME}"
|
||||
git config --global user.email "${GIT_EMAIL}"
|
||||
git config --global credential.helper store
|
||||
echo "https://${GIT_EMAIL//@/%40}:${GIT_TOKEN}@${GIT_HOST}" > ~/.git-credentials
|
||||
chmod 600 ~/.git-credentials
|
||||
|
||||
mkdir -p ~/.ssh && chmod 700 ~/.ssh
|
||||
printf '%s\n' "${AUR_SSH_KEY}" > ~/.ssh/aur
|
||||
chmod 600 ~/.ssh/aur
|
||||
ssh-keyscan -t rsa,ecdsa,ed25519 aur.archlinux.org >> ~/.ssh/known_hosts 2>/dev/null
|
||||
cat >> ~/.ssh/config <<'EOF'
|
||||
Host aur.archlinux.org
|
||||
User aur
|
||||
IdentityFile ~/.ssh/aur
|
||||
IdentitiesOnly yes
|
||||
EOF
|
||||
chmod 600 ~/.ssh/config
|
||||
|
||||
# makepkg refuses to run as root, and CI containers are root by default.
|
||||
- name: Create build user
|
||||
run: |
|
||||
set -euo pipefail
|
||||
useradd --create-home --shell /bin/bash builder
|
||||
chown -R builder:builder "${GITHUB_WORKSPACE}"
|
||||
cp -r /root/.ssh /root/.gitconfig /root/.git-credentials /home/builder/ 2>/dev/null || true
|
||||
chown -R builder:builder /home/builder
|
||||
|
||||
- name: Update ${{ matrix.package }}
|
||||
env:
|
||||
GIT_HOST: ${{ vars.GIT_HOST }}
|
||||
# Compared against both `true` and 'true' on purpose. A bare
|
||||
# `${{ inputs.x && '1' || '' }}` is wrong if the runner hands the
|
||||
# input over as the STRING "false", which is truthy -- that would
|
||||
# silently enable the flag on every run.
|
||||
FORCE_REBUILD: ${{ (inputs.force_rebuild == true || inputs.force_rebuild == 'true') && '1' || '' }}
|
||||
FORCE_REFRESH: ${{ (inputs.force_refresh == true || inputs.force_refresh == 'true') && '1' || '' }}
|
||||
NO_GIT_PUSH: ${{ (inputs.no_git_push == true || inputs.no_git_push == 'true') && '1' || '' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# workflow_dispatch with a package name runs only that one.
|
||||
want="${{ inputs.package }}"
|
||||
if [ -n "${want}" ] && [ "${want}" != "${{ matrix.package }}" ]; then
|
||||
echo "skipping ${{ matrix.package }} (dispatch asked for ${want})"
|
||||
exit 0
|
||||
fi
|
||||
runuser -u builder -- env \
|
||||
GIT_HOST="${GIT_HOST}" \
|
||||
FORCE_REBUILD="${FORCE_REBUILD}" \
|
||||
FORCE_REFRESH="${FORCE_REFRESH}" \
|
||||
NO_GIT_PUSH="${NO_GIT_PUSH}" \
|
||||
./autoupdate.sh "${{ matrix.package }}"
|
||||
Reference in New Issue
Block a user