#!/usr/bin/env bash # Run Android wallet smoke against several build / published variants. # # Default order: # 1) stable-self — rebuild STABLE_TAG (always WARN on fail) # 2) published — current F-Droid suggested APK # 3) older-* — previous release tags (APK and/or self-build) if available # 4) master — tip (always WARN on fail) # # Severity (released apps): # Age ≤ BLOCKER_MAX_AGE_DAYS (default **14**) → **BLOCKER** on fail (FAIL_FAST) # Age > 14 days (or unknown) → **WARN** only # master / pure self-builds without release age → WARN # # Env: # STABLE_TAG, STABLE_APK_URL, STABLE_APK_NAME # MASTER_BRANCH, FIX_BRANCH # VARIANTS default: stable-self,published,older,master # INCLUDE_OLDER=1 expand token "older" (default 1) # OLDER_TAG_COUNT how many recent wallet-* tags to consider (default 4) # BLOCKER_MAX_AGE_DAYS default 14 # PUBLISHED_FORCE_BLOCKER=1 always treat current published as blocker (default 0 = age rule) # FAIL_FAST=1, GUI=0, STACK=… # set -euo pipefail ROOT=$(cd "$(dirname "$0")" && pwd) # shellcheck source=lib_android_env.sh . "$ROOT/lib_android_env.sh" # shellcheck source=lib_release_age.sh . "$ROOT/lib_release_age.sh" : "${STABLE_TAG:=wallet-1.6.1}" : "${STABLE_APK_URL:=https://f-droid.org/repo/net.taler.wallet.fdroid_854.apk}" : "${STABLE_APK_NAME:=net.taler.wallet.fdroid_854.apk}" : "${MASTER_BRANCH:=master}" : "${FIX_BRANCH:=dev/hernani-inference/fix-bank-withdraw-auto-exchange}" : "${VARIANTS:=stable-self,published,older,master}" : "${INCLUDE_OLDER:=1}" : "${OLDER_TAG_COUNT:=4}" : "${BLOCKER_MAX_AGE_DAYS:=14}" : "${PUBLISHED_FORCE_BLOCKER:=0}" : "${FAIL_FAST:=1}" : "${GUI:=0}" : "${STACK:=auto}" : "${TALER_ANDROID_SRC:=$HOME/taler/taler-android}" export TALER_ANDROID_SRC BLOCKER_MAX_AGE_DAYS TS=$(date +%Y%m%d-%H%M%S) MATRIX_OUT="${MATRIX_OUT:-$ROOT/out-matrix-$TS}" mkdir -p "$MATRIX_OUT" SUMMARY="$MATRIX_OUT/SUMMARY.txt" : >"$SUMMARY" echo "=== Android variant matrix ===" | tee -a "$SUMMARY" echo "STACK=$STACK GUI=$GUI headless=${EMULATOR_HEADLESS} variants=$VARIANTS" | tee -a "$SUMMARY" echo "STABLE_TAG=$STABLE_TAG BLOCKER_MAX_AGE_DAYS=$BLOCKER_MAX_AGE_DAYS OLDER_TAG_COUNT=$OLDER_TAG_COUNT" | tee -a "$SUMMARY" echo "out: $MATRIX_OUT" | tee -a "$SUMMARY" android_ensure_device || { echo "no adb device — start ./start-android-emulator.sh --wait" >&2 exit 3 } export SERIAL ANDROID_SERIAL echo "device: $SERIAL" | tee -a "$SUMMARY" # --- expand VARIANTS (token "older" → concrete older-pub / older-self entries) --- expand_variants() { local raw="$1" local -a out=() local v tag vn age sev stable_vn stable_vn="${STABLE_TAG#wallet-}" IFS=',' read -r -a toks <<<"$raw" for v in "${toks[@]}"; do v=$(echo "$v" | tr -d '[:space:]') [ -n "$v" ] || continue if [ "$v" = "older" ] || [ "$v" = "older-releases" ]; then [ "$INCLUDE_OLDER" = "1" ] || continue local -a tags=() mapfile -t tags < <(list_wallet_release_tags "$OLDER_TAG_COUNT" 2>/dev/null || true) local t for t in "${tags[@]}"; do [ -n "$t" ] || continue # skip current stable tag (already covered by published / stable-self) [ "$t" = "$STABLE_TAG" ] && continue vn="${t#wallet-}" age=$(release_age_days "$t" 2>/dev/null || echo "") sev=$(severity_from_age_days "$age") echo " older candidate $t age_days=${age:-?} severity=$sev" | tee -a "$SUMMARY" # Prefer published APK when downloadable; always also allow self-build token local meta apk_vc apk_url meta=$(fdroid_apk_for_version_name "$vn" 2>/dev/null || true) if [ -n "$meta" ]; then apk_vc="${meta%%|*}" apk_url="${meta#*|}" if fdroid_apk_exists "$apk_url"; then out+=("older-pub:${vn}:${apk_vc}:${sev}") else echo " (no F-Droid APK for $vn at $apk_url — self-build only)" | tee -a "$SUMMARY" out+=("older-self:${t}:${sev}") fi else out+=("older-self:${t}:${sev}") fi done else out+=("$v") fi done printf '%s\n' "${out[@]}" } mapfile -t VLIST < <(expand_variants "$VARIANTS") echo "expanded variants: ${VLIST[*]}" | tee -a "$SUMMARY" declare -a RESULTS=() declare -a WARNINGS=() overall=0 severity_for_published_current() { if [ "${PUBLISHED_FORCE_BLOCKER}" = "1" ]; then echo blocker return fi local days days=$(release_age_days "$STABLE_TAG" 2>/dev/null || true) severity_from_age_days "$days" } run_published_apk() { local label="$1" local apk_url="$2" local apk_name="$3" local sev="$4" local out="$MATRIX_OUT/$label" mkdir -p "$out" echo "" | tee -a "$SUMMARY" echo "-------- variant: $label (F-Droid APK) [$(echo "$sev" | tr 'a-z' 'A-Z')] --------" | tee -a "$SUMMARY" echo " url=$apk_url" | tee -a "$SUMMARY" local smoke="$ROOT/run-android-pay-smoke.sh" [ "$GUI" = "1" ] && smoke="$ROOT/run-android-gui-smoke.sh" local strict=1 [ "$sev" = "warn" ] && strict="${SMOKE_STRICT_WARN:-0}" [ "$sev" = "blocker" ] && strict="${SMOKE_STRICT:-1}" set +e env STACK="$STACK" \ APK_URL="$apk_url" \ APK_NAME="$apk_name" \ APK_PATH="" \ PKG=net.taler.wallet.fdroid \ OUT_DIR="$out" \ SERIAL="$SERIAL" \ AUTO_START_EMULATOR=0 \ SMOKE_STRICT="$strict" \ "$smoke" local rc=$? set -e echo "$label exit=$rc severity=$sev" | tee -a "$SUMMARY" echo "$label $rc $sev $apk_url" >>"$MATRIX_OUT/results.tsv" return "$rc" } run_selfbuild() { local label="$1" local ref="$2" local sev="${3:-warn}" local out="$MATRIX_OUT/$label" mkdir -p "$out" echo "" | tee -a "$SUMMARY" echo "-------- variant: $label (self-build ref=$ref) [$(echo "$sev" | tr 'a-z' 'A-Z')] --------" | tee -a "$SUMMARY" local strict="${SMOKE_STRICT:-1}" [ "$sev" = "warn" ] && strict="${SMOKE_STRICT_SELF:-0}" [ "$sev" = "blocker" ] && strict="${SMOKE_STRICT:-1}" set +e env STACK="$STACK" \ BRANCH="$ref" \ LABEL="$label" \ GUI="$GUI" \ OUT_DIR="$out" \ SERIAL="$SERIAL" \ ANDROID_SERIAL="$SERIAL" \ AUTO_START_EMULATOR=0 \ PKG=net.taler.wallet.fdroid.debug \ SMOKE_STRICT="$strict" \ TALER_ANDROID_SRC="$TALER_ANDROID_SRC" \ "$ROOT/run-android-build-and-smoke.sh" local rc=$? set -e echo "$label (ref=$ref) exit=$rc severity=$sev" | tee -a "$SUMMARY" echo "$label $rc $ref $sev" >>"$MATRIX_OUT/results.tsv" if [ -f "$out/build-meta.txt" ]; then echo "build-meta:" | tee -a "$SUMMARY" cat "$out/build-meta.txt" | tee -a "$SUMMARY" fi return "$rc" } record_result() { local v="$1" rc="$2" sev="$3" if [ "$rc" -eq 0 ]; then RESULTS+=("$v:OK($sev)") return fi case "$sev" in warn) echo "WARN: $v failed rc=$rc — not a blocker; continuing" | tee -a "$SUMMARY" WARNINGS+=("$v:$rc") RESULTS+=("$v:WARN($rc)") ;; blocker) echo "BLOCKER: $v failed rc=$rc (release within ${BLOCKER_MAX_AGE_DAYS}d window)" | tee -a "$SUMMARY" RESULTS+=("$v:BLOCKER($rc)") overall=1 if [ "$FAIL_FAST" = "1" ]; then echo "FAIL_FAST: stopping after blocker $v" | tee -a "$SUMMARY" return 2 fi ;; soft) echo "FAIL: $v rc=$rc" | tee -a "$SUMMARY" RESULTS+=("$v:FAIL($rc)") overall=1 if [ "$FAIL_FAST" = "1" ]; then echo "FAIL_FAST: stopping after $v" | tee -a "$SUMMARY" return 2 fi ;; esac return 0 } for raw in "${VLIST[@]}"; do v=$(echo "$raw" | tr -d '[:space:]') [ -n "$v" ] || continue rc=0 sev=warn stop=0 case "$v" in published|fdroid|stable-published) sev=$(severity_for_published_current) age=$(release_age_days "$STABLE_TAG" 2>/dev/null || echo "?") echo "published current: tag=$STABLE_TAG age_days=$age → severity=$sev" | tee -a "$SUMMARY" run_published_apk "published" "$STABLE_APK_URL" "$STABLE_APK_NAME" "$sev" || rc=$? ;; stable-self|stable|self-stable|release-self) # rebuild of stable: always warn (toolchain), age does not make self-build a blocker sev=warn run_selfbuild "stable-self" "$STABLE_TAG" warn || rc=$? ;; master|main) sev=warn run_selfbuild "master" "$MASTER_BRANCH" warn || rc=$? ;; fix|fix-branch|inference) sev=soft run_selfbuild "fix" "$FIX_BRANCH" soft || rc=$? ;; older-pub:*) # older-pub:VERSION:VC:SEV IFS=':' read -r _ vn apk_vc sev <<<"$v" : "${sev:=warn}" label="older-pub-${vn}" url="https://f-droid.org/repo/net.taler.wallet.fdroid_${apk_vc}.apk" name="net.taler.wallet.fdroid_${apk_vc}.apk" age=$(release_age_days "wallet-${vn}" 2>/dev/null || echo "?") echo "older published $vn age_days=$age severity=$sev" | tee -a "$SUMMARY" run_published_apk "$label" "$url" "$name" "$sev" || rc=$? v="$label" ;; older-self:*) # older-self:TAG:SEV or older-self:TAG IFS=':' read -r _ tag sev <<<"$v" : "${sev:=$(severity_for_tag "$tag")}" label="older-self-${tag}" age=$(release_age_days "$tag" 2>/dev/null || echo "?") echo "older self-build $tag age_days=$age severity=$sev" | tee -a "$SUMMARY" run_selfbuild "$label" "$tag" "$sev" || rc=$? v="$label" ;; *) # raw git ref — warn unless looks like wallet-X.Y and young if [[ "$v" =~ ^wallet-[0-9] ]]; then sev=$(severity_for_tag "$v") run_selfbuild "ref-${v}" "$v" "$sev" || rc=$? else sev=warn run_selfbuild "ref-${v//\//-}" "$v" warn || rc=$? fi ;; esac record_result "$v" "$rc" "$sev" || stop=$? [ "$stop" = "2" ] && break done echo "" | tee -a "$SUMMARY" echo "=== matrix done (overall=$overall) ===" | tee -a "$SUMMARY" echo "rule: released app age ≤ ${BLOCKER_MAX_AGE_DAYS}d → BLOCKER on fail; older → WARN" | tee -a "$SUMMARY" for r in "${RESULTS[@]}"; do echo " $r" | tee -a "$SUMMARY" done if [ "${#WARNINGS[@]}" -gt 0 ]; then echo "warnings (non-blocking):" | tee -a "$SUMMARY" for w in "${WARNINGS[@]}"; do echo " WARN $w" | tee -a "$SUMMARY" done fi echo "" echo "Artifacts: $MATRIX_OUT" exit "$overall"