Files
claudeandbit 3f14c01b00 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>
2026-09-09 06:34:36 +00:00

67 lines
1.6 KiB
Bash

# Shared assertion helpers for the shell test scripts. Sourced, not run.
#
# Each test_*.sh increments PASS_COUNT/FAIL_COUNT/SKIP_COUNT as it goes and
# prints one line per check, so a caller sees passed/skipped/failed as
# separate numbers rather than a single pass/fail verdict -- a skip must
# never read as a pass.
PASS_COUNT=0
FAIL_COUNT=0
SKIP_COUNT=0
pass() { PASS_COUNT=$((PASS_COUNT + 1)); echo "PASS: $1"; }
fail() { FAIL_COUNT=$((FAIL_COUNT + 1)); echo "FAIL: $1" >&2; }
skip() { SKIP_COUNT=$((SKIP_COUNT + 1)); echo "SKIP: $1"; }
assert_success() {
# assert_success <label> <command...>
local label=$1; shift
if "$@" >/tmp/assert_out.$$ 2>&1; then
pass "$label"
else
fail "$label (exit $?, see /tmp/assert_out.$$)"
cat /tmp/assert_out.$$ >&2
fi
rm -f /tmp/assert_out.$$
}
assert_failure() {
# assert_failure <label> <command...> -- must exit non-zero
local label=$1; shift
if "$@" >/tmp/assert_out.$$ 2>&1; then
fail "$label (expected non-zero exit, got 0)"
cat /tmp/assert_out.$$ >&2
else
pass "$label"
fi
rm -f /tmp/assert_out.$$
}
assert_file_exists() {
local label=$1 path=$2
if [ -s "$path" ]; then
pass "$label"
else
fail "$label (missing or empty: $path)"
fi
}
assert_contains() {
# assert_contains <label> <haystack-file-or-string> <needle>
local label=$1 haystack=$2 needle=$3
if [ -f "$haystack" ]; then
haystack=$(cat "$haystack")
fi
if [[ "$haystack" == *"$needle"* ]]; then
pass "$label"
else
fail "$label (expected to find '$needle')"
fi
}
report_and_exit() {
echo
echo "passed=$PASS_COUNT skipped=$SKIP_COUNT failed=$FAIL_COUNT"
[ "$FAIL_COUNT" -eq 0 ]
}