Build the shared F-Droid publishing tooling: sign, index, publish
Adds sign-apk.sh (align-check + apksigner), fdroid-update.sh (fdroid update over a binary repo, signing the index with its own separate key), publish.sh (S3-compatible upload) and the composite action tying them together, matching weblib-ci's shape. zipalign is not a standalone nixpkgs attribute; resolved by measurement rather than assumption that Gradle/AGP already aligns its output (Android's own docs, corroborated by fdroidserver never shelling out to zipalign) and added check_zip_alignment.py as the safety net, since apksigner itself does not check alignment at all. nixpkgs is pinned via a committed nixpkgs-pin revision, since this repo has no flake.lock of its own for with-nixpkgs.sh to read (fdroid-repo-ci#1, weblib-ci#9) -- a missing or malformed pin fails loudly rather than degrading to an unpinned nix shell. No consumer repo, bucket, hostname or channel name is hard-coded: which repo holds the keys and runs the publish has already changed once during this issue and may again, so every example uses a placeholder. 42 offline/local-only test assertions across five suites (run_tests.sh), including fault injection on the alignment check, the password/argument validation, and the with-nixpkgs.sh fail-loud paths. Co-authored-by: bit <bit@das-labor.org>
This commit is contained in:
Executable
+70
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Runs every test in this repo and prints one passed/skipped/failed total.
|
||||
# Not wired to any `.gitea/workflows` -- see the README for why, the same
|
||||
# reasoning weblib-ci#9 recorded for that repo: run it by hand before
|
||||
# pushing.
|
||||
#
|
||||
# bash run_tests.sh
|
||||
#
|
||||
# check_zip_alignment.py's own suite needs only python3 (via with-nixpkgs.sh,
|
||||
# since none is assumed to be on PATH); everything else additionally needs
|
||||
# apksigner/fdroidserver/jdk21/awscli2, resolved through the same pin. All of
|
||||
# it stays on loopback/local-store -- nothing here reaches a real host,
|
||||
# bucket or key.
|
||||
set -uo pipefail
|
||||
here=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
|
||||
total_pass=0
|
||||
total_skip=0
|
||||
total_fail=0
|
||||
any_hard_fail=0
|
||||
|
||||
run_python_suite() {
|
||||
echo "=== test_check_zip_alignment.py ==="
|
||||
local out
|
||||
if out=$(bash "$here/with-nixpkgs.sh" python3 python3 "$here/test_check_zip_alignment.py" -v 2>&1); then
|
||||
local n
|
||||
n=$(echo "$out" | grep -oE '^Ran [0-9]+ test' | grep -oE '[0-9]+')
|
||||
total_pass=$((total_pass + ${n:-0}))
|
||||
echo "$out" | tail -3
|
||||
else
|
||||
total_fail=$((total_fail + 1))
|
||||
any_hard_fail=1
|
||||
echo "$out"
|
||||
fi
|
||||
echo
|
||||
}
|
||||
|
||||
run_shell_suite() {
|
||||
local script=$1
|
||||
echo "=== $script ==="
|
||||
local out rc=0
|
||||
out=$(bash "$here/$script" 2>&1) || rc=$?
|
||||
echo "$out"
|
||||
local p s f
|
||||
p=$(echo "$out" | grep -oE '^passed=[0-9]+' | grep -oE '[0-9]+' | tail -1)
|
||||
s=$(echo "$out" | grep -oE 'skipped=[0-9]+' | grep -oE '[0-9]+' | tail -1)
|
||||
f=$(echo "$out" | grep -oE 'failed=[0-9]+' | grep -oE '[0-9]+' | tail -1)
|
||||
if [ -z "$p" ] && [ -z "$f" ]; then
|
||||
# the script itself crashed before reaching report_and_exit
|
||||
total_fail=$((total_fail + 1))
|
||||
any_hard_fail=1
|
||||
else
|
||||
total_pass=$((total_pass + ${p:-0}))
|
||||
total_skip=$((total_skip + ${s:-0}))
|
||||
total_fail=$((total_fail + ${f:-0}))
|
||||
[ "${f:-0}" -ne 0 ] && any_hard_fail=1
|
||||
fi
|
||||
echo
|
||||
}
|
||||
|
||||
run_python_suite
|
||||
run_shell_suite test_with_nixpkgs.sh
|
||||
run_shell_suite test_sign_apk.sh
|
||||
run_shell_suite test_fdroid_update.sh
|
||||
run_shell_suite test_publish.sh
|
||||
|
||||
echo "===================================="
|
||||
echo "TOTAL: passed=$total_pass skipped=$total_skip failed=$total_fail"
|
||||
exit "$any_hard_fail"
|
||||
Reference in New Issue
Block a user