ci: publish a rolling latest APK on every push to master
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 25m52s
🏗️ Build and Test JellyTau / Supply Chain (push) Successful in 46s
📱 Test APK / Build test APK (push) Failing after 1m14s
Publish Documentation / Build & publish docs to gitea-pages (push) Successful in 7m54s
Traceability Validation / Check Requirement Traces (push) Successful in 18s
🏗️ Build and Test JellyTau / Android Compile Check (push) Successful in 6m26s

The test-APK workflow was dispatch-only, so merging to master produced no
APK at all -- there was nothing to hand a tester without pressing a button
first, which is not what a "latest build" means.

Pushes to master now refresh a `latest` pre-release in place. Both the tag
and the asset name are stable, so the download URL never changes and a
link given to a tester once keeps serving the current build. Release
assets are public; Actions artifacts need an account, which is what made
them useless for this.

It stays the side-by-side variant: R8-minified like a real release, so it
still exercises the minification that has broken Android builds here
before, but signed with the debug keystore under the `.debug`
applicationId. A bad master commit therefore cannot replace anyone's
working install, and the production signing key stays in the tag-driven
release workflow.

Event handling is resolved in one step rather than read raw at each use.
A push carries no dispatch inputs -- every `github.event.inputs.*` is
empty on that event -- so the variant and ABI need real defaults, and the
publish decision differs by event. Doing it once means the build, collect
and publish steps cannot disagree about what the run is.

Known gap, documented rather than hidden: this builds in parallel with
build-and-test.yml, so `latest` can carry a commit whose tests later fail.
Cross-workflow dependencies are not reliably available here and
duplicating the test job would double an already hour-long queue on a
single-slot runner.
This commit is contained in:
2026-09-05 13:42:33 +02:00
parent b5a3a3b427
commit 5fb9c1ff3b
2 changed files with 178 additions and 99 deletions
+41 -25
View File
@@ -94,40 +94,56 @@ Follow the right log stream with `./scripts/logcat.sh [debug|release]`
### Getting a test APK out of CI
`.gitea/workflows/build-test-apk.yml` builds one from **any branch, on demand**
— run it from Gitea's Actions tab (`workflow_dispatch`) against the ref you want.
It is not a release: nothing is tagged, published, or signed with the real key.
`.gitea/workflows/build-test-apk.yml` produces installable APKs that are **not
releases**. Two ways in:
Two variants, both installing into the `com.dtourolle.jellytau.debug` slot:
| Trigger | Result |
|---------|--------|
| **push to `master`** | Refreshes the rolling **`latest`** pre-release automatically |
| **`workflow_dispatch`** | Builds any branch on demand; optionally publishes it as `test-<branch>` |
#### The rolling `latest` build
Every push to `master` (bar doc-only ones) rebuilds and replaces the APK on the
`latest` pre-release. Both the tag and the asset name are stable, so the
download URL never changes:
```
https://gitea.tourolle.paris/dtourolle/jellytau/releases/download/latest/jellytau-latest.apk
```
Send that link to a tester once and it keeps serving the current build. No
account needed — release assets are public, unlike Actions artifacts.
#### What you get, and why it is safe
Both variants install into the `com.dtourolle.jellytau.debug` slot:
| Variant | What it is | When |
|---------|-----------|------|
| `side-by-side-release` (default) | R8-minified, exactly what ships, signed with the debug keystore | Almost always — a plain debug build cannot catch R8 stripping JNI-loaded classes, which has broken release APKs here before |
| `side-by-side-release` (default, and what `latest` always is) | R8-minified, exactly what ships, signed with the **debug** keystore | Almost always — a plain debug build cannot catch R8 stripping JNI-loaded classes, which has broken release APKs here before |
| `debug` | Unminified | When you need readable stack traces |
There is deliberately **no push trigger**: the runner has one slot shared with
two other projects, so building on every feature-branch commit would starve
them. The APK lands as the `jellytau-test-apk` artifact (7-day retention), named
for the branch and short SHA, with its size and SHA256 in the run summary.
Three properties make an automatic build on every master push safe:
#### Sending a build to an outside tester
- **It cannot replace a real install.** The applicationId is suffixed `.debug`,
so it sits beside the store build with its own data. A broken master commit
can never take out somebody's working app.
- **The production signing key is not involved.** That stays in the tag-driven
`build-release.yml`. This workflow needs no secrets beyond the API token.
- **The tag is `latest`/`test-*`, never `v*`.** Only `v*` triggers
`build-release.yml`. And the desktop updater reads a static `latest.json` from
the `updater` branch rather than the release list, so nothing here is offered
to existing users.
Gitea **artifacts require an account** with read access to download, so an
artifact is no use to someone outside the project. Tick **`publish`** on the
dispatch and the APK is also attached to a **pre-release**, whose assets are a
plain public URL on a public repo — no account, no MR, no merge to `master`.
**Known gap:** the APK builds in parallel with `build-and-test.yml`, not after
it, so `latest` can carry a commit whose tests later fail. Cross-workflow
dependencies are not reliably available here, and duplicating the test job would
double an already hour-long queue on a single-slot runner. Check the commit's
CI status before handing the link to somebody.
Two things make that safe to do from a feature branch:
- The tag is `test-<branch>`, **not** `v*`. Only `v*` triggers
`build-release.yml`, so nothing else reacts to it.
- It cannot reach existing users. The desktop updater reads a static
`latest.json` from the `updater` branch, not the release list, so a
pre-release published this way is invisible to anyone without the link.
Re-dispatching for the same branch replaces the APK on the existing
pre-release rather than piling up one release per attempt. Delete the release
when testing is over.
Runs are serialised and `cancel-in-progress` is on, so a burst of pushes to
master collapses into one build rather than one per commit.
### Key Files