From 834b219c3f38d68a6f69bb53ddf6dcf6c1fae8b9 Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Tue, 25 Aug 2026 23:38:20 +0200 Subject: [PATCH] Publish the Android APK as a build artefact The android job proved the app links for aarch64 and then threw the result away. There was no APK anywhere in CI and no upload step in the repo at all, so a green run left nothing anybody could install -- the artefact list was empty by construction, not by failure. It now assembles the APK with the script package.sh uses and uploads it. The .so comes from the build the API-level check already ran; -o only adds a copy of it where the packaging step looks, so this costs one copy rather than a second twenty-minute cross-compile. The signing key is the part worth being careful about. KEYSTORE points at a mktemp directory rather than its default under target-android, because that directory is precisely what actions/cache saves and restores -- the default would have written a private key into the build cache and kept it there. Nothing but the .apk is uploaded. A fresh debug key each run is the right trade for an artefact meant to reach a test device: the only thing a stable key buys is installing over a previous build without uninstalling first, and a key that survives in cache storage to buy it is a bad exchange. if-no-files-found: error because the failure being guarded against is a green run with an empty artefact list, which reads as success right up until somebody goes looking for the file. Debug-signed, arm64-v8a only -- the ABI the job already builds. Neither is a release story; this is a build you can install. Co-Authored-By: Claude Opus 5 --- .gitea/workflows/build-and-test.yml | 38 ++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/build-and-test.yml b/.gitea/workflows/build-and-test.yml index 509f3fc..8c8d17e 100644 --- a/.gitea/workflows/build-and-test.yml +++ b/.gitea/workflows/build-and-test.yml @@ -223,7 +223,8 @@ jobs: # It is also the honest artefact to check: the .so this names is the # one that ships in the APK, so the API level verified here is the # API level a device will refuse to install against. - cargo ndk -t arm64-v8a build -p darkroom-android --release + cargo ndk -t arm64-v8a -o target-android/jniLibs \ + build -p darkroom-android --release MIN_API=$(sed -n 's/^ARG MIN_API=\([0-9]*\).*/\1/p' docker/android/Dockerfile) # Empty on both sides would compare equal and pass, so neither side # is allowed to be the result of a failed parse. @@ -244,6 +245,41 @@ jobs: exit 1 fi + # The APK itself, so a run leaves something installable behind rather + # than only the knowledge that it would have linked. The assembly is + # `docker/android/assemble-apk.sh`, shared with `package.sh` so the file + # a device gets from `package.sh --install` and the file published here + # are built by the same code — see that script's header. + # + # `KEYSTORE` deliberately points at a throwaway directory instead of its + # default under `target-android`: that directory is what `actions/cache` + # restores and saves, and a signing key has no business in a build cache + # or in anything this job uploads. A fresh debug key per run is the right + # trade for an artefact whose purpose is getting the app onto a test + # device; nothing upgrades in place over it, which is the one thing a + # stable key would buy. + - name: Package the APK + env: + CARGO_TARGET_DIR: target-android + run: | + set -e + KEYDIR="$(mktemp -d)" + trap 'rm -rf "$KEYDIR"' EXIT + REPO="$PWD" \ + TARGET_DIR="$PWD/target-android" \ + KEYSTORE="$KEYDIR/debug.keystore" \ + bash docker/android/assemble-apk.sh + + # `if-no-files-found: error` because the failure this guards against is + # a green run with an empty artefact list, which reads as success until + # somebody goes looking for the file. + - name: Upload the APK + uses: actions/upload-artifact@v4 + with: + name: darkroom-arm64-v8a-apk + path: target-android/apk/darkroom.apk + if-no-files-found: error + layering: runs-on: linux/amd64 name: Layer separation