diff --git a/docs/WORKFLOW.md b/docs/WORKFLOW.md
index 7435f08..58cf35f 100644
--- a/docs/WORKFLOW.md
+++ b/docs/WORKFLOW.md
@@ -555,7 +555,7 @@ check-all.sh [--update | --prepare
| --verify | --publish ] [--
### 4.2 Step-by-step
1. Load `.aurtomator.conf` when it exists. In CI, `GIT_AUTHOR_NAME`, `GIT_AUTHOR_EMAIL` and `GPG_KEY_ID` come from the workflow environment.
-2. Clone `ssh://aur@aur.archlinux.org/.git` into a temporary directory, with up to 3 attempts. A clone without a PKGBUILD stops the update.
+2. Wait 2 seconds, then clone `ssh://aur@aur.archlinux.org/.git` into a temporary directory, with up to 3 attempts 5 seconds apart. A clone without a PKGBUILD stops the update.
3. When the clone lands on a detached `HEAD`, reset `master` to `origin/master`, so the push is a fast-forward.
4. Warn when the PKGBUILD has no `# Maintainer:` line.
5. Audit the PKGBUILD. Split packages, `pkgver()` with the wrong strategy and mixed checksums block the update. Patches only warn. See [SUPPORTED-PACKAGES.md](SUPPORTED-PACKAGES.md).
@@ -565,9 +565,11 @@ check-all.sh [--update | --prepare | --verify | --publish ] [--
9. Regenerate `.SRCINFO` with `makepkg --printsrcinfo`.
10. With `--dry-run`, print the PKGBUILD diff and stop.
11. Commit `PKGBUILD` and `.SRCINFO` as ` release from `, authored by `GIT_AUTHOR_NAME` and `GIT_AUTHOR_EMAIL` (default `aurtomator`). With `GPG_KEY_ID` set, the commit is amended with a signature. When signing fails, the commit is pushed unsigned.
-12. Push, with up to 3 attempts.
+12. Push, with up to 3 attempts 5 seconds apart.
13. Write `current` and `last_updated` to the package YAML.
+`AURTOMATOR_CLONE_DELAY` and `AURTOMATOR_RETRY_DELAY` change the 2 and the 5 seconds. The tests set both to 0.
+
### 4.3 Downgrade behavior
aurtomator follows upstream when it publishes a version older than the tracked one, and does **not** block it. Upstream is the source of truth: a packager that refuses a re-published older release only drifts out of sync. A downgrade is logged and shown, and it does not count as a failure.
diff --git a/scripts/lib.sh b/scripts/lib.sh
index 165cfc0..218ffa5 100644
--- a/scripts/lib.sh
+++ b/scripts/lib.sh
@@ -275,12 +275,13 @@ validate_source_urls() {
# AUR GIT
# =============================================================================
-# Clone an AUR repo, with 3 attempts
+# Clone an AUR repo, with 3 attempts. AURTOMATOR_CLONE_DELAY and
+# AURTOMATOR_RETRY_DELAY set the pauses, in seconds.
# Args: $1=url, $2=destination, $3...=options for git clone
aur_clone() {
- local attempt
+ local attempt delay="${AURTOMATOR_RETRY_DELAY:-5}"
# Brief delay to reduce AUR SSH rate-limit pressure from GitHub Actions IP pool
- sleep 2
+ sleep "${AURTOMATOR_CLONE_DELAY:-2}"
for attempt in 1 2 3; do
if git clone "${@:3}" "$1" "$2" 2>&1; then
return 0
@@ -289,9 +290,9 @@ aur_clone() {
log_err "Failed to clone AUR repo $1 after 3 attempts"
return 1
fi
- log_warn "Clone attempt $attempt failed, retrying in 5s..."
+ log_warn "Clone attempt $attempt failed, retrying in ${delay}s..."
rm -rf "$2"
- sleep 5
+ sleep "$delay"
done
}
@@ -340,10 +341,11 @@ aur_export() {
}
# Commit what the index holds, sign when GPG_KEY_ID is set, push with 3
-# attempts. The caller stages PKGBUILD and .SRCINFO.
+# attempts, AURTOMATOR_RETRY_DELAY seconds apart. The caller stages
+# PKGBUILD and .SRCINFO.
# Args: $1=clone directory, $2=version, $3=strategy (for the commit message)
aur_commit_push() {
- local dir="$1" attempt
+ local dir="$1" attempt delay="${AURTOMATOR_RETRY_DELAY:-5}"
log_info "Pushing to AUR"
git -C "$dir" config user.name "${GIT_AUTHOR_NAME:-aurtomator}"
git -C "$dir" config user.email "${GIT_AUTHOR_EMAIL:-aurtomator@users.noreply.github.com}"
@@ -369,8 +371,8 @@ aur_commit_push() {
log_err "git push to AUR failed after 3 attempts"
return 1
fi
- log_warn "Push attempt $attempt failed, retrying in 5s..."
- sleep 5
+ log_warn "Push attempt $attempt failed, retrying in ${delay}s..."
+ sleep "$delay"
done
}
diff --git a/tests/gpg-flow.bats b/tests/gpg-flow.bats
index ab4c43d..8c74db3 100644
--- a/tests/gpg-flow.bats
+++ b/tests/gpg-flow.bats
@@ -6,11 +6,10 @@
load helpers/setup.sh
-setup() {
- setup_test_env
-
- # Isolated GPG keyring for all tests
- export GNUPGHOME="$TEST_TMPDIR/gnupg"
+# The keys are generated once per file, and every test gets a copy of the
+# keyring
+setup_file() {
+ export GNUPGHOME="$BATS_FILE_TMPDIR/gnupg"
mkdir -m 0700 "$GNUPGHOME"
echo "allow-loopback-pinentry" >"$GNUPGHOME/gpg-agent.conf"
@@ -49,6 +48,17 @@ GPGEOF
withpass_fpr=$(gpg --list-secret-keys --keyid-format long 2>/dev/null | grep -B2 "Test Withpass" | grep "^sec" | head -1 | awk '{print $2}' | cut -d'/' -f2)
WITHPASS_MASTER_ID="$withpass_fpr"
WITHPASS_SUBKEY_ID=$(gpg --list-secret-keys --keyid-format long 2>/dev/null | grep -A8 "Test Withpass" | grep "^ssb" | head -1 | awk '{print $2}' | cut -d'/' -f2)
+ export NOPASS_SUBKEY_ID NOPASS_MASTER_ID WITHPASS_MASTER_ID WITHPASS_SUBKEY_ID
+
+ gpgconf --kill gpg-agent
+}
+
+setup() {
+ setup_test_env
+
+ # Isolated GPG keyring for each test
+ export GNUPGHOME="$TEST_TMPDIR/gnupg"
+ cp -a "$BATS_FILE_TMPDIR/gnupg" "$GNUPGHOME"
# Git repo for commit signing tests
AUR_DIR="$TEST_TMPDIR/aur-test-pkg"
diff --git a/tests/helpers/setup.sh b/tests/helpers/setup.sh
index 0c73bf0..c25054b 100644
--- a/tests/helpers/setup.sh
+++ b/tests/helpers/setup.sh
@@ -29,6 +29,9 @@ setup_test_env() {
# Override AURTOMATOR_DIR so all scripts use our temp workspace
export AURTOMATOR_DIR="$TEST_TMPDIR"
+
+ # No pause before an AUR clone or between attempts
+ export AURTOMATOR_CLONE_DELAY=0 AURTOMATOR_RETRY_DELAY=0
}
teardown_test_env() {
diff --git a/tests/publish.bats b/tests/publish.bats
index 85bf516..5eccfb0 100644
--- a/tests/publish.bats
+++ b/tests/publish.bats
@@ -1238,6 +1238,51 @@ make_export_clone() {
[ ! -e "$clone/PKGBUILD" ]
}
+# === aur_clone and aur_commit_push ===
+
+# Helper: a sleep on PATH that logs its argument to $TEST_TMPDIR/sleeps, and
+# a git whose clone always fails
+mock_sleep_and_clone() {
+ printf '#!/usr/bin/env bash\necho "$1" >>"%s/sleeps"\n' "$TEST_TMPDIR" >"$MOCK_DIR/sleep"
+ printf '#!/usr/bin/env bash\n[[ "$1" == clone ]] && exit 128\nexec /usr/bin/git "$@"\n' >"$MOCK_DIR/git"
+ chmod +x "$MOCK_DIR/sleep" "$MOCK_DIR/git"
+}
+
+# Helper: a repo without a remote, with a staged PKGBUILD, at $TEST_TMPDIR/clone
+make_unpushable_repo() {
+ git init -q -b master "$TEST_TMPDIR/clone"
+ echo "pkgver=1.0.0" >"$TEST_TMPDIR/clone/PKGBUILD"
+ git -C "$TEST_TMPDIR/clone" add PKGBUILD
+}
+
+@test "aur_clone: waits the pauses the environment sets" {
+ mock_sleep_and_clone
+ AURTOMATOR_CLONE_DELAY=3 AURTOMATOR_RETRY_DELAY=7 run aur_clone https://example.invalid/demo.git "$TEST_TMPDIR/clone"
+ [ "$status" -eq 1 ]
+ [ "$(cat "$TEST_TMPDIR/sleeps")" = $'3\n7\n7' ]
+ [[ "$output" == *"Clone attempt 2 failed, retrying in 7s"* ]]
+}
+
+@test "aur_commit_push: waits the pause the environment sets" {
+ mock_sleep_and_clone
+ make_unpushable_repo
+ AURTOMATOR_RETRY_DELAY=7 run aur_commit_push "$TEST_TMPDIR/clone" 1.0.0 test
+ [ "$status" -eq 1 ]
+ [ "$(cat "$TEST_TMPDIR/sleeps")" = $'7\n7' ]
+ [[ "$output" == *"Push attempt 2 failed, retrying in 7s"* ]]
+}
+
+@test "aur_clone and aur_commit_push: wait 2 s before a clone and 5 s between attempts by default" {
+ mock_sleep_and_clone
+ make_unpushable_repo
+ unset AURTOMATOR_CLONE_DELAY AURTOMATOR_RETRY_DELAY
+ run aur_clone https://example.invalid/demo.git "$TEST_TMPDIR/other"
+ [ "$status" -eq 1 ]
+ run aur_commit_push "$TEST_TMPDIR/clone" 1.0.0 test
+ [ "$status" -eq 1 ]
+ [ "$(cat "$TEST_TMPDIR/sleeps")" = $'2\n5\n5\n5\n5' ]
+}
+
# === check_prepared_pkgbuild ===
@test "check_prepared_pkgbuild: accepts new pkgver, pkgrel and checksums" {