Files
.autoupdate/test.sh
Bryan Joshua Pedini 2565c193e6
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
fix: fail safely when AUR synchronization fails
2026-07-27 00:17:01 +02:00

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