You've already forked .autoupdate
All checks were successful
Update AUR Packages / update (nethlink-appimage) (push) Successful in 13s
Update AUR Packages / update (open-video-downloader-appimage) (push) Successful in 13s
Update AUR Packages / update (open-video-downloader-bin) (push) Successful in 14s
Update AUR Packages / update (pman-helper) (push) Successful in 13s
Update AUR Packages / update (reflex-appimage) (push) Successful in 13s
Update AUR Packages / update (tsparams) (push) Successful in 12s
539 lines
20 KiB
Bash
Executable File
539 lines
20 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Hermetic tests for the autoupdater.
|
|
#
|
|
# usage: ./test.sh [name-filter]
|
|
#
|
|
# Runs against local bare repos standing in for origin and the AUR, with a
|
|
# stubbed version lookup, so nothing here touches the network or the real AUR.
|
|
# Needs a genuine Arch makepkg (same requirement as the CI job).
|
|
|
|
set -uo pipefail
|
|
|
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
FILTER="${1:-}"
|
|
|
|
PASS=0; FAIL=0; FAILED_NAMES=()
|
|
|
|
pass() { printf ' \033[32mok\033[0m %s\n' "$1"; PASS=$((PASS+1)); }
|
|
fail() { printf ' \033[31mFAIL\033[0m %s\n %s\n' "$1" "${2-}"; FAIL=$((FAIL+1)); FAILED_NAMES+=("$1"); }
|
|
|
|
assert_eq() { # expected actual label
|
|
if [ "$1" = "$2" ]; then pass "$3"; else fail "$3" "expected '$1', got '$2'"; fi
|
|
}
|
|
assert_ne() {
|
|
if [ "$1" != "$2" ]; then pass "$3"; else fail "$3" "expected something other than '$1'"; fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------- sandbox ---
|
|
|
|
SANDBOX=""
|
|
setup() {
|
|
SANDBOX="$(mktemp -d)"
|
|
mkdir -p "$SANDBOX"/{origin,aur,work}
|
|
|
|
cat > "$SANDBOX/fake-version.sh" <<'EOS'
|
|
#!/usr/bin/env bash
|
|
# Stands in for latest-version.sh. FAKE_VERSION_FAIL=1 simulates a broken
|
|
# upstream query; FAKE_VERSION="" simulates one that returns nothing.
|
|
if [ -n "${FAKE_VERSION_FAIL:-}" ]; then
|
|
echo "ERROR: simulated upstream lookup failure" >&2
|
|
exit 1
|
|
fi
|
|
printf '%s\n' "${FAKE_VERSION-1.0.0}"
|
|
EOS
|
|
chmod +x "$SANDBOX/fake-version.sh"
|
|
|
|
# A local HTTP server so remote-source paths can be tested without network.
|
|
mkdir -p "$SANDBOX/www"
|
|
printf 'x86_64 binary payload\n' > "$SANDBOX/www/x86.bin"
|
|
printf 'aarch64 binary payload\n' > "$SANDBOX/www/arm.bin"
|
|
# -u: without it the "Serving HTTP on ... port N" line stays buffered and the
|
|
# port can never be read back.
|
|
( cd "$SANDBOX/www" && exec python3 -u -m http.server 0 --bind 127.0.0.1 ) \
|
|
> "$SANDBOX/www.log" 2>&1 &
|
|
WWW_PID=$!
|
|
for _ in $(seq 1 50); do
|
|
PORT="$(sed -n -E 's/.*http:\/\/127\.0\.0\.1:([0-9]+).*/\1/p' "$SANDBOX/www.log" | head -1)"
|
|
[ -n "$PORT" ] && break
|
|
sleep 0.1
|
|
done
|
|
[ -n "${PORT:-}" ] || { echo "could not start test http server" >&2; exit 1; }
|
|
|
|
# A git shim used by one test to simulate an SSH auth rejection on push.
|
|
# Everything else passes straight through to the real git.
|
|
REAL_GIT="$(command -v git)"
|
|
mkdir -p "$SANDBOX/bin"
|
|
cat > "$SANDBOX/bin/git" <<EOS
|
|
#!/usr/bin/env bash
|
|
if [ "\${FAKE_PUSH_AUTH_FAIL:-}" = "1" ] && [ "\$1" = "push" ] && [ "\$2" = "aur" ]; then
|
|
echo "aur@aur.archlinux.org: Permission denied (publickey)." >&2
|
|
echo "fatal: Could not read from remote repository." >&2
|
|
exit 128
|
|
fi
|
|
exec "$REAL_GIT" "\$@"
|
|
EOS
|
|
chmod +x "$SANDBOX/bin/git"
|
|
|
|
export PKG_REPO_BASE="file://$SANDBOX/origin"
|
|
export AUR_HTTPS_BASE="file://$SANDBOX/aur"
|
|
export AUR_SSH_BASE="file://$SANDBOX/aur"
|
|
export LATEST_VERSION_CMD="$SANDBOX/fake-version.sh"
|
|
export GIT_AUTHOR_NAME=test GIT_AUTHOR_EMAIL=test@test
|
|
export GIT_COMMITTER_NAME=test GIT_COMMITTER_EMAIL=test@test
|
|
}
|
|
|
|
teardown() {
|
|
[ -n "${WWW_PID:-}" ] && kill "$WWW_PID" 2>/dev/null
|
|
[ -n "$SANDBOX" ] && rm -rf "$SANDBOX"
|
|
return 0
|
|
}
|
|
|
|
# A multi-arch package whose arches download DIFFERENT files that both rename to
|
|
# the SAME target -- freetube-appimage's exact shape, and the case that makes
|
|
# `makepkg -g` emit identical sums for both arches.
|
|
make_pkg_colliding_remote() {
|
|
local pkg="$1"
|
|
local src="$SANDBOX/build/$pkg"
|
|
rm -rf "$src"; mkdir -p "$src"
|
|
|
|
cat > "$src/PKGBUILD" <<EOF
|
|
pkgname="$pkg"
|
|
pkgver="1.0.0"
|
|
pkgrel="1"
|
|
pkgdesc="colliding multi-arch test package"
|
|
url="https://example.invalid/$pkg"
|
|
arch=("x86_64" "aarch64")
|
|
license=("MIT")
|
|
source_x86_64=("payload.bin::http://127.0.0.1:${PORT}/x86.bin")
|
|
sha256sums_x86_64=("SKIP")
|
|
source_aarch64=("payload.bin::http://127.0.0.1:${PORT}/arm.bin")
|
|
sha256sums_aarch64=("SKIP")
|
|
|
|
package() {
|
|
install -Dm644 "\${srcdir}/payload.bin" "\${pkgdir}/usr/share/$pkg/payload.bin"
|
|
}
|
|
EOF
|
|
cat > "$src/.autoupdate" <<'EOF'
|
|
srchost="gitea"
|
|
srcmntr="test"
|
|
srcname="test"
|
|
verstrip=""
|
|
gui="false"
|
|
EOF
|
|
|
|
( cd "$src" && "$HERE/update-checksums.sh" --remote . >/dev/null \
|
|
&& makepkg --printsrcinfo > .SRCINFO )
|
|
|
|
git init --quiet --bare --initial-branch=main "$SANDBOX/origin/$pkg"
|
|
git init --quiet --bare --initial-branch=master "$SANDBOX/aur/${pkg}.git"
|
|
( cd "$src" && git init --quiet --initial-branch=main && git add -A \
|
|
&& git commit --quiet -m "initial" \
|
|
&& git push --quiet "file://$SANDBOX/origin/$pkg" main \
|
|
&& git push --quiet "file://$SANDBOX/aur/${pkg}.git" main:master )
|
|
}
|
|
|
|
# Create a package repo (origin) plus its AUR counterpart.
|
|
# make_pkg <name> [multiarch]
|
|
make_pkg() {
|
|
local pkg="$1" multi="${2:-}"
|
|
local src="$SANDBOX/build/$pkg"
|
|
rm -rf "$src"; mkdir -p "$src"
|
|
|
|
echo "payload for $pkg" > "$src/local.txt"
|
|
|
|
if [ -n "$multi" ]; then
|
|
echo "x86 payload" > "$src/pay-x86_64.txt"
|
|
echo "arm payload" > "$src/pay-aarch64.txt"
|
|
cat > "$src/PKGBUILD" <<EOF
|
|
pkgname="$pkg"
|
|
pkgver="1.0.0"
|
|
pkgrel="1"
|
|
pkgdesc="multi-arch test package"
|
|
url="https://example.invalid/$pkg"
|
|
arch=("x86_64" "aarch64")
|
|
license=("MIT")
|
|
source=("local.txt")
|
|
sha256sums=("SKIP")
|
|
source_x86_64=("pay-x86_64.txt")
|
|
sha256sums_x86_64=("SKIP")
|
|
source_aarch64=("pay-aarch64.txt")
|
|
sha256sums_aarch64=("SKIP")
|
|
|
|
package() {
|
|
install -Dm644 "\${srcdir}/local.txt" "\${pkgdir}/usr/share/$pkg/local.txt"
|
|
}
|
|
EOF
|
|
else
|
|
cat > "$src/PKGBUILD" <<EOF
|
|
pkgname="$pkg"
|
|
pkgver="1.0.0"
|
|
pkgrel="1"
|
|
pkgdesc="test package"
|
|
url="https://example.invalid/$pkg"
|
|
arch=("any")
|
|
license=("MIT")
|
|
source=("local.txt")
|
|
sha256sums=("SKIP")
|
|
|
|
package() {
|
|
install -Dm644 "\${srcdir}/local.txt" "\${pkgdir}/usr/share/$pkg/local.txt"
|
|
}
|
|
EOF
|
|
fi
|
|
|
|
cat > "$src/.autoupdate" <<'EOF'
|
|
srchost="gitea"
|
|
srcmntr="test"
|
|
srcname="test"
|
|
verstrip=""
|
|
gui="false"
|
|
EOF
|
|
echo "readme" > "$src/README.md"
|
|
|
|
# Fix up the SKIP placeholders and generate a valid .SRCINFO.
|
|
( cd "$src" && "$HERE/update-checksums.sh" . >/dev/null \
|
|
&& makepkg --printsrcinfo > .SRCINFO )
|
|
|
|
git init --quiet --bare --initial-branch=main "$SANDBOX/origin/$pkg"
|
|
git init --quiet --bare --initial-branch=master "$SANDBOX/aur/${pkg}.git"
|
|
|
|
( cd "$src" && git init --quiet --initial-branch=main && git add -A \
|
|
&& git commit --quiet -m "initial" \
|
|
&& git push --quiet "file://$SANDBOX/origin/$pkg" main \
|
|
&& git push --quiet "file://$SANDBOX/aur/${pkg}.git" main:master )
|
|
}
|
|
|
|
# Run the updater. Any extra env goes in front of the call by the caller.
|
|
run_update() {
|
|
local pkg="$1"; shift
|
|
WORKDIR="$SANDBOX/work/$(date +%s%N)" \
|
|
"$HERE/autoupdate.sh" "$pkg" "$@" >"$SANDBOX/last.log" 2>&1
|
|
}
|
|
|
|
# Read a field from a bare repo's tip.
|
|
field_at() { # <bare-repo> <ref> <var>
|
|
git -C "$1" show "$2:PKGBUILD" 2>/dev/null \
|
|
| sed -n -E "s/^$3=[\"']?([^\"']*)[\"']?$/\1/p" | head -n1
|
|
}
|
|
aur_field() { field_at "$SANDBOX/aur/$1.git" master "$2"; }
|
|
origin_field() { field_at "$SANDBOX/origin/$1" main "$2"; }
|
|
aur_head() { git -C "$SANDBOX/aur/$1.git" rev-parse master 2>/dev/null; }
|
|
|
|
should_run() { [ -z "$FILTER" ] || [[ "$1" == *"$FILTER"* ]]; }
|
|
|
|
# ------------------------------------------------------------------ tests ---
|
|
|
|
test_new_version() {
|
|
make_pkg p1
|
|
FAKE_VERSION=2.0.0 run_update p1
|
|
assert_eq "0" "$?" "new version: exits 0"
|
|
assert_eq "2.0.0" "$(aur_field p1 pkgver)" "new version: pkgver reaches the AUR"
|
|
assert_eq "1" "$(aur_field p1 pkgrel)" "new version: pkgrel resets to 1"
|
|
}
|
|
|
|
test_noop_is_quiet_and_green() {
|
|
make_pkg p2
|
|
FAKE_VERSION=1.0.0 run_update p2
|
|
local rc=$? before after
|
|
before="$(aur_head p2)"
|
|
FAKE_VERSION=1.0.0 run_update p2
|
|
after="$(aur_head p2)"
|
|
assert_eq "0" "$rc" "no-op: exits 0"
|
|
assert_eq "$before" "$after" "no-op: second run pushes nothing"
|
|
grep -q "AUR already in sync" "$SANDBOX/last.log" \
|
|
&& pass "no-op: reports already in sync" \
|
|
|| fail "no-op: reports already in sync" "$(tail -3 "$SANDBOX/last.log")"
|
|
}
|
|
|
|
# The headline regression: origin ahead of the AUR, nothing new upstream.
|
|
# The old script aborted with "same (old) version" and exit 0, forever.
|
|
# Reproduces the exact reported failure: a previous run published to origin but
|
|
# its AUR push failed. Origin is therefore fully consistent -- correct sums,
|
|
# correct .SRCINFO, pkgrel already bumped -- so this run computes NO local
|
|
# changes at all. The only thing wrong is that the AUR is behind. The old
|
|
# script hit "same (old) version specified", bare-exit 0'd, and never retried.
|
|
#
|
|
# The pkgrel is pre-bumped deliberately: otherwise the pkgrel rule would itself
|
|
# produce a local change and the run would push for that reason instead,
|
|
# leaving the actual retry path untested.
|
|
test_failed_push_is_retried() {
|
|
make_pkg p3
|
|
local clone="$SANDBOX/manual-p3"
|
|
git clone --quiet "file://$SANDBOX/origin/p3" "$clone"
|
|
( cd "$clone" \
|
|
&& sed -i 's/^pkgdesc=.*/pkgdesc="changed out of band"/;s/^pkgrel=.*/pkgrel="2"/' PKGBUILD \
|
|
&& makepkg --printsrcinfo > .SRCINFO \
|
|
&& git commit --quiet -am "published to origin; AUR push failed" \
|
|
&& git push --quiet origin main )
|
|
|
|
assert_ne "changed out of band" "$(aur_field p3 pkgdesc)" "retry: AUR starts out of date"
|
|
|
|
FAKE_VERSION=1.0.0 run_update p3
|
|
local rc=$?
|
|
assert_eq "0" "$rc" "retry: exits 0"
|
|
|
|
grep -q "no local changes" "$SANDBOX/last.log" \
|
|
&& pass "retry: run produced no local changes (exercises the reconcile path)" \
|
|
|| fail "retry: run produced no local changes" \
|
|
"the run committed something, so this is not the retry path: $(tail -5 "$SANDBOX/last.log")"
|
|
|
|
assert_eq "changed out of band" "$(aur_field p3 pkgdesc)" \
|
|
"retry: reconciles to the AUR with nothing new locally or upstream"
|
|
}
|
|
|
|
test_manual_edit_bumps_pkgrel() {
|
|
make_pkg p4
|
|
local clone="$SANDBOX/manual-p4"
|
|
git clone --quiet "file://$SANDBOX/origin/p4" "$clone"
|
|
( cd "$clone" && sed -i 's/^pkgdesc=.*/pkgdesc="fixed package() bug"/' PKGBUILD \
|
|
&& makepkg --printsrcinfo > .SRCINFO \
|
|
&& git commit --quiet -am "fix package()" && git push --quiet origin main )
|
|
|
|
FAKE_VERSION=1.0.0 run_update p4
|
|
assert_eq "2" "$(aur_field p4 pkgrel)" "manual edit: pkgrel auto-bumped 1 -> 2"
|
|
|
|
# The important one: re-running must not ratchet pkgrel upward.
|
|
FAKE_VERSION=1.0.0 run_update p4
|
|
assert_eq "2" "$(aur_field p4 pkgrel)" "manual edit: pkgrel stable on re-run (idempotent)"
|
|
FAKE_VERSION=1.0.0 run_update p4
|
|
assert_eq "2" "$(aur_field p4 pkgrel)" "manual edit: pkgrel still stable on third run"
|
|
}
|
|
|
|
test_hand_bumped_pkgrel_respected() {
|
|
make_pkg p5
|
|
local clone="$SANDBOX/manual-p5"
|
|
git clone --quiet "file://$SANDBOX/origin/p5" "$clone"
|
|
( cd "$clone" && sed -i 's/^pkgdesc=.*/pkgdesc="edited"/;s/^pkgrel=.*/pkgrel="7"/' PKGBUILD \
|
|
&& makepkg --printsrcinfo > .SRCINFO \
|
|
&& git commit --quiet -am "edit + own pkgrel" && git push --quiet origin main )
|
|
|
|
FAKE_VERSION=1.0.0 run_update p5
|
|
assert_eq "7" "$(aur_field p5 pkgrel)" "hand-bumped pkgrel is left alone"
|
|
}
|
|
|
|
test_readme_only_edit() {
|
|
make_pkg p6
|
|
local clone="$SANDBOX/manual-p6"
|
|
git clone --quiet "file://$SANDBOX/origin/p6" "$clone"
|
|
( cd "$clone" && echo "more docs" >> README.md \
|
|
&& git commit --quiet -am "docs" && git push --quiet origin main )
|
|
|
|
FAKE_VERSION=1.0.0 run_update p6
|
|
local rc=$? # must be captured before any other command clobbers $?
|
|
assert_eq "0" "$rc" "README-only edit: still exits 0"
|
|
assert_eq "1" "$(aur_field p6 pkgrel)" "README-only edit: no pkgrel bump"
|
|
assert_eq "more docs" "$(git -C "$SANDBOX/aur/p6.git" show master:README.md | tail -1)" \
|
|
"README-only edit: still reconciled to the AUR"
|
|
}
|
|
|
|
test_local_source_edit_bumps_pkgrel() {
|
|
make_pkg p7
|
|
local clone="$SANDBOX/manual-p7"
|
|
git clone --quiet "file://$SANDBOX/origin/p7" "$clone"
|
|
( cd "$clone" && echo "changed payload" > local.txt \
|
|
&& git commit --quiet -am "edit local source" && git push --quiet origin main )
|
|
|
|
FAKE_VERSION=1.0.0 run_update p7
|
|
assert_eq "2" "$(aur_field p7 pkgrel)" "local source edit: re-hashed and pkgrel bumped"
|
|
}
|
|
|
|
test_force_rebuild() {
|
|
make_pkg p8
|
|
FAKE_VERSION=1.0.0 run_update p8
|
|
FORCE_REBUILD=1 FAKE_VERSION=1.0.0 run_update p8
|
|
assert_eq "2" "$(aur_field p8 pkgrel)" "FORCE_REBUILD: pkgrel +1 with no other change"
|
|
}
|
|
|
|
test_lookup_failure_is_loud() {
|
|
make_pkg p9
|
|
local before; before="$(aur_head p9)"
|
|
FAKE_VERSION_FAIL=1 run_update p9
|
|
local rc=$?
|
|
assert_eq "1" "$rc" "broken upstream lookup: exits 1, not mistaken for 'no new version'"
|
|
assert_eq "$before" "$(aur_head p9)" "broken upstream lookup: nothing pushed"
|
|
|
|
# Assert the REASON, not just the exit code. This previously passed even with
|
|
# the lookup failure being swallowed: the run carried on with an empty version
|
|
# and exited 1 several steps later when .SRCINFO generation rejected it, which
|
|
# is the pman-helper pkgver="" bug wearing a different hat.
|
|
grep -q "upstream version lookup failed" "$SANDBOX/last.log" \
|
|
&& pass "broken upstream lookup: fails AT the lookup, not later" \
|
|
|| fail "broken upstream lookup: fails AT the lookup, not later" \
|
|
"expected the lookup-failure message; got: $(tail -3 "$SANDBOX/last.log")"
|
|
}
|
|
|
|
test_empty_version_aborts_before_commit() {
|
|
make_pkg p10
|
|
local before; before="$(aur_head p10)"
|
|
FAKE_VERSION="" run_update p10
|
|
assert_eq "1" "$?" "empty version: exits 1"
|
|
assert_eq "$before" "$(aur_head p10)" "empty version: aborts before committing"
|
|
assert_eq "1.0.0" "$(origin_field p10 pkgver)" "empty version: origin left unpoisoned"
|
|
}
|
|
|
|
# reflex-appimage's real state: local ahead of the AUR carrying a stale pkgrel
|
|
# that the old script never reset.
|
|
test_stale_pkgrel_repaired() {
|
|
make_pkg p11
|
|
local clone="$SANDBOX/manual-p11"
|
|
git clone --quiet "file://$SANDBOX/origin/p11" "$clone"
|
|
( cd "$clone" && sed -i 's/^pkgver=.*/pkgver="1.5.0"/;s/^pkgrel=.*/pkgrel="4"/' PKGBUILD \
|
|
&& makepkg --printsrcinfo > .SRCINFO \
|
|
&& git commit --quiet -am "version bumped without resetting pkgrel" \
|
|
&& git push --quiet origin main )
|
|
|
|
FAKE_VERSION=1.5.0 run_update p11
|
|
assert_eq "1.5.0" "$(aur_field p11 pkgver)" "stale pkgrel: version published"
|
|
assert_eq "1" "$(aur_field p11 pkgrel)" "stale pkgrel: reset to 1 against the AUR"
|
|
}
|
|
|
|
test_multiarch_distinct_sums() {
|
|
make_pkg p12 multi
|
|
FAKE_VERSION=1.0.0 run_update p12
|
|
|
|
local x a
|
|
x="$(git -C "$SANDBOX/aur/p12.git" show master:PKGBUILD \
|
|
| sed -n '/^sha256sums_x86_64=/,/)/p' | grep -oE '[0-9a-f]{64}')"
|
|
a="$(git -C "$SANDBOX/aur/p12.git" show master:PKGBUILD \
|
|
| sed -n '/^sha256sums_aarch64=/,/)/p' | grep -oE '[0-9a-f]{64}')"
|
|
|
|
assert_eq "$(sha256sum "$SANDBOX/build/p12/pay-x86_64.txt" | awk '{print $1}')" "$x" \
|
|
"multi-arch: x86_64 sum correct"
|
|
assert_eq "$(sha256sum "$SANDBOX/build/p12/pay-aarch64.txt" | awk '{print $1}')" "$a" \
|
|
"multi-arch: aarch64 sum correct"
|
|
assert_ne "$x" "$a" "multi-arch: arches get distinct sums (the makepkg -g failure mode)"
|
|
}
|
|
|
|
# The regression that rules out `makepkg -g`: two arches downloading different
|
|
# files that rename to the same target must not end up sharing a checksum.
|
|
test_multiarch_colliding_downloads() {
|
|
make_pkg_colliding_remote p15
|
|
FAKE_VERSION=1.0.0 FORCE_REFRESH=1 run_update p15
|
|
|
|
local pb x a
|
|
pb="$(git -C "$SANDBOX/aur/p15.git" show master:PKGBUILD)"
|
|
x="$(printf '%s' "$pb" | sed -n '/^sha256sums_x86_64=/,/)/p' | grep -oE '[0-9a-f]{64}')"
|
|
a="$(printf '%s' "$pb" | sed -n '/^sha256sums_aarch64=/,/)/p' | grep -oE '[0-9a-f]{64}')"
|
|
|
|
assert_eq "$(sha256sum "$SANDBOX/www/x86.bin" | awk '{print $1}')" "$x" \
|
|
"colliding downloads: x86_64 hashed its own file"
|
|
assert_eq "$(sha256sum "$SANDBOX/www/arm.bin" | awk '{print $1}')" "$a" \
|
|
"colliding downloads: aarch64 hashed its own file, not x86_64's"
|
|
assert_ne "$x" "$a" "colliding downloads: sums differ despite the shared :: target"
|
|
}
|
|
|
|
# The ordering guarantee: if the AUR push fails, origin must NOT be pushed.
|
|
#
|
|
# This regressed in production. `( update_one ) || ...` disables set -e for the
|
|
# whole subshell body, so a failed sync-aur.sh did not stop the run and origin
|
|
# ended up ahead of the AUR -- the exact state the tool exists to prevent.
|
|
test_aur_failure_leaves_origin_unpushed() {
|
|
make_pkg p16
|
|
local clone="$SANDBOX/manual-p16"
|
|
git clone --quiet "file://$SANDBOX/origin/p16" "$clone"
|
|
( cd "$clone" && sed -i 's/^pkgdesc=.*/pkgdesc="needs publishing"/' PKGBUILD \
|
|
&& makepkg --printsrcinfo > .SRCINFO \
|
|
&& git commit --quiet -am "change to publish" && git push --quiet origin main )
|
|
|
|
local origin_before aur_before
|
|
origin_before="$(git -C "$SANDBOX/origin/p16" rev-parse main)"
|
|
aur_before="$(aur_head p16)"
|
|
|
|
# Push target does not exist -> the AUR push fails, the fetch still works.
|
|
AUR_SSH_BASE="file://$SANDBOX/nonexistent" FAKE_VERSION=1.0.0 run_update p16
|
|
local rc=$?
|
|
|
|
assert_eq "1" "$rc" "aur failure: run exits 1"
|
|
assert_eq "$aur_before" "$(aur_head p16)" "aur failure: AUR unchanged"
|
|
assert_eq "$origin_before" "$(git -C "$SANDBOX/origin/p16" rev-parse main)" \
|
|
"aur failure: origin NOT pushed (the ordering guarantee)"
|
|
|
|
# It must not blame divergence for what is a plain push failure.
|
|
grep -q "has commits origin does not" "$SANDBOX/last.log" \
|
|
&& fail "aur failure: not misreported as divergence" "blamed divergence for a non-divergence failure" \
|
|
|| pass "aur failure: not misreported as divergence"
|
|
}
|
|
|
|
# A real non-fast-forward must be named as such -- and must NOT suggest forcing,
|
|
# since the AUR refuses force pushes from non-administrators.
|
|
test_genuine_divergence_is_reported() {
|
|
make_pkg p17
|
|
local clone="$SANDBOX/manual-p17"
|
|
git clone --quiet "file://$SANDBOX/aur/p17.git" "$clone"
|
|
( cd "$clone" && echo "edited directly on the AUR" >> README.md \
|
|
&& git commit --quiet -am "out-of-band AUR commit" \
|
|
&& git push --quiet origin HEAD:master )
|
|
|
|
FAKE_VERSION=1.0.0 run_update p17
|
|
local rc=$?
|
|
assert_eq "1" "$rc" "divergence: exits 1"
|
|
grep -q "has commits origin does not" "$SANDBOX/last.log" \
|
|
&& pass "divergence: reported as divergence" \
|
|
|| fail "divergence: reported as divergence" "$(tail -4 "$SANDBOX/last.log")"
|
|
grep -qi "AUR_FORCE" "$SANDBOX/last.log" \
|
|
&& fail "divergence: does not suggest forcing" "AUR_FORCE is gone; nothing should mention it" \
|
|
|| pass "divergence: does not suggest forcing"
|
|
}
|
|
|
|
test_auth_failure_is_reported_as_auth() {
|
|
make_pkg p18
|
|
local clone="$SANDBOX/manual-p18"
|
|
git clone --quiet "file://$SANDBOX/origin/p18" "$clone"
|
|
( cd "$clone" && sed -i 's/^pkgdesc=.*/pkgdesc="publish me"/' PKGBUILD \
|
|
&& makepkg --printsrcinfo > .SRCINFO \
|
|
&& git commit --quiet -am "change" && git push --quiet origin main )
|
|
|
|
PATH="$SANDBOX/bin:$PATH" FAKE_PUSH_AUTH_FAIL=1 FAKE_VERSION=1.0.0 run_update p18
|
|
local rc=$?
|
|
assert_eq "1" "$rc" "auth failure: exits 1"
|
|
grep -q "rejected the SSH key" "$SANDBOX/last.log" \
|
|
&& pass "auth failure: reported as an SSH key problem" \
|
|
|| fail "auth failure: reported as an SSH key problem" "$(tail -4 "$SANDBOX/last.log")"
|
|
grep -q "has commits origin does not" "$SANDBOX/last.log" \
|
|
&& fail "auth failure: not misreported as divergence" "this is the production bug" \
|
|
|| pass "auth failure: not misreported as divergence"
|
|
}
|
|
|
|
test_srcinfo_guard() {
|
|
make_pkg p13
|
|
local clone="$SANDBOX/manual-p13"
|
|
git clone --quiet "file://$SANDBOX/origin/p13" "$clone"
|
|
# pkgver that makepkg rejects -> .SRCINFO cannot be generated.
|
|
( cd "$clone" && sed -i 's/^pkgdesc=.*/pkgdesc="x"/' PKGBUILD \
|
|
&& git commit --quiet -am "touch" && git push --quiet origin main )
|
|
local before; before="$(aur_head p13)"
|
|
FAKE_VERSION="not a version!" run_update p13
|
|
assert_eq "1" "$?" ".SRCINFO guard: invalid version rejected"
|
|
assert_eq "$before" "$(aur_head p13)" ".SRCINFO guard: nothing reached the AUR"
|
|
}
|
|
|
|
test_no_git_push_dry_run() {
|
|
make_pkg p14
|
|
local before_aur before_origin
|
|
before_aur="$(aur_head p14)"
|
|
before_origin="$(git -C "$SANDBOX/origin/p14" rev-parse main)"
|
|
NO_GIT_PUSH=1 FAKE_VERSION=3.0.0 run_update p14
|
|
assert_eq "0" "$?" "NO_GIT_PUSH: exits 0"
|
|
assert_eq "$before_aur" "$(aur_head p14)" "NO_GIT_PUSH: AUR untouched"
|
|
assert_eq "$before_origin" "$(git -C "$SANDBOX/origin/p14" rev-parse main)" \
|
|
"NO_GIT_PUSH: origin untouched"
|
|
}
|
|
|
|
# ------------------------------------------------------------------- main ---
|
|
|
|
trap teardown EXIT
|
|
setup
|
|
|
|
for t in $(declare -F | awk '{print $3}' | grep '^test_' | sort); do
|
|
should_run "$t" || continue
|
|
printf '\n\033[1m%s\033[0m\n' "$t"
|
|
"$t"
|
|
done
|
|
|
|
printf '\n────────────────────────\n'
|
|
printf 'passed: %d failed: %d\n' "$PASS" "$FAIL"
|
|
if [ "$FAIL" -gt 0 ]; then
|
|
printf 'failing: %s\n' "${FAILED_NAMES[*]}"
|
|
exit 1
|
|
fi
|