1- # Build the FOLLOWER apk, and only ever the follower.
1+ # Build the follower app .
22#
3- # WHAT THIS MUST NEVER BUILD: the `full` flavour. That is the app that drives an
4- # insulin pump, and this repository does not distribute it — see the README.
5- # Every gradle invocation here names `Aapsclient` explicitly for that reason,
6- # and the check job fails the run if a `full` artifact appears anyway.
3+ # ONE REPOSITORY, NO ANDROIDAPS. The follower used to be a flavour of AAPS with
4+ # the dosing stripped out, which meant this workflow checked out a second repo,
5+ # built a whole loop app, and had to actively refuse to publish the pump variant.
6+ # The follower is now its own application containing no AAPS code at all, so
7+ # none of that applies: there is nothing here that could build a loop.
78#
8- # The follower is a different proposition: a separate `applicationId`, no pump
9- # drivers compiled in, and structurally unable to dose (decision D22). It is a
10- # viewer for somebody else's glucose. Handing that to a person as a file they
11- # can install is reasonable in a way that handing them a loop is not.
12- #
13- # The APK contains AndroidAPS, which is AGPL-3.0. Distributing a binary
14- # therefore obliges us to publish the corresponding source: the fork and branch
15- # it was built from are recorded in the release notes, at the exact commit.
9+ # That is also what makes it publishable. F-Droid builds one repository from
10+ # source, and this is one repository whose only unusual need is a Rust toolchain
11+ # to compile the record core into a .so — which is built here, never committed.
1612
1713name : follower apk
1814
1915on :
2016 workflow_dispatch :
21- inputs :
22- aaps_ref :
23- description : " Branch or commit of the AAPS fork to build against"
24- default : diaswarm-addon
2517 push :
2618 tags : ["follower-v*"]
19+ pull_request :
20+ paths : ["follower/**", "crates/**", ".github/workflows/follower.yml"]
2721
2822permissions :
2923 contents : write # only to attach the apk to a release
3024
31- env :
32- AAPS_REPO : alex-poor/AndroidAPS
33- NDK_VERSION : " 28.2.13676358"
34-
3525jobs :
3626 build :
3727 runs-on : ubuntu-latest
38- # Whether a signing key is configured, decided once. A step's own `env:`
39- # block is NOT visible to that step's `if:`, so testing the secret there
40- # silently never fires and every build comes out unsigned.
4128 env :
4229 HAS_KEY : ${{ secrets.FOLLOWER_KEYSTORE_B64 != '' }}
4330 steps :
44- - name : Check out diaswarm
45- uses : actions/checkout@v4
46- with :
47- path : diaswarm
48-
49- # The follower is a build of this fork of AAPS, not of upstream: the
50- # screen it draws comes from the fork's own overview. AGPL means whatever
51- # is built here has to be publicly readable, so this checkout failing is
52- # a licence problem, not just a build problem.
53- - name : Check out the AAPS fork
54- uses : actions/checkout@v4
55- with :
56- repository : ${{ env.AAPS_REPO }}
57- ref : ${{ github.event.inputs.aaps_ref || 'diaswarm-addon' }}
58- path : aaps
31+ - uses : actions/checkout@v4
5932
60- - name : JDK 21
61- uses : actions/setup-java@v4
33+ - uses : actions/setup-java@v4
6234 with :
6335 distribution : temurin
6436 java-version : " 21"
6537
6638 - name : NDK
6739 run : |
6840 set -euo pipefail
69- # Prefer whatever the runner already ships: an NDK is ~1 GB and the
70- # version matters only to cargo-ndk, which is not fussy.
7141 NDK="${ANDROID_NDK_LATEST_HOME:-}"
72- if [ -z "$NDK" ] || [ ! -d "$NDK" ]; then
73- SDKM="$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager"
74- # `yes |` dies of SIGPIPE the moment sdkmanager stops reading, and
75- # under `pipefail` that fails the step even though the licences were
76- # accepted. Feed it a fixed number of yeses instead.
77- printf 'y\n%.0s' {1..50} | "$SDKM" --licenses >/dev/null 2>&1 || true
78- "$SDKM" "ndk;${NDK_VERSION}" >/dev/null
79- NDK="$ANDROID_HOME/ndk/${NDK_VERSION}"
80- fi
42+ [ -n "$NDK" ] && [ -d "$NDK" ] || { echo "::error::no NDK on the runner"; exit 1; }
8143 echo "using NDK at $NDK"
8244 echo "ANDROID_NDK_HOME=$NDK" >> "$GITHUB_ENV"
8345
84- # Pinned by rust-toolchain.toml in the diaswarm repo; the targets and
85- # cargo-ndk are what turn the record core into the .so the plugin packages.
8646 - name : Rust for Android
87- working-directory : diaswarm
8847 run : |
8948 set -euo pipefail
90- rustup show active-toolchain
9149 rustup target add aarch64-linux-android armv7-linux-androideabi
9250 cargo install cargo-ndk --locked
9351
94- - name : Cache gradle and cargo
95- uses : actions/cache@v4
52+ - uses : actions/cache@v4
9653 with :
9754 path : |
9855 ~/.gradle/caches
9956 ~/.gradle/wrapper
10057 ~/.cargo/registry
10158 ~/.cargo/git
102- diaswarm/ crates/*/target
103- key : follower-${{ runner.os }}-${{ hashFiles('diaswarm/ **/Cargo.lock', 'aaps /**/*.gradle*') }}
59+ crates/*/target
60+ key : follower-${{ runner.os }}-${{ hashFiles('**/Cargo.lock', 'follower /**/*.gradle*') }}
10461 restore-keys : follower-${{ runner.os }}-
10562
63+ # The record core is asserted byte-identical to tools/canon.py over real
64+ # data; if that is broken there is no point building an app around it.
10665 - name : Test the record core
107- working-directory : diaswarm/ crates/diaswarm-core
66+ working-directory : crates/diaswarm-core
10867 run : cargo test
10968
110- # Unsigned on purpose: the `release` build type carries no signingConfig,
111- # so nothing here can accidentally reuse the debug keystore that the loop
112- # build depends on.
113- - name : Build the follower
114- working-directory : aaps
115- env :
116- DIASWARM_PLUGIN_DIR : ${{ github.workspace }}/diaswarm/plugin
117- run : ./gradlew :app:assembleAapsclientRelease -PappVersionSuffix=follower --console=plain
118-
119- - name : Refuse to ship a pump build
120- run : |
121- set -euo pipefail
122- if compgen -G "aaps/app/build/outputs/apk/full/**/*.apk" > /dev/null; then
123- echo "::error::a 'full' (pump) APK was produced — this workflow must build the follower only"
124- exit 1
125- fi
126- ls -la aaps/app/build/outputs/apk/aapsclient/release/
69+ - name : Build
70+ working-directory : follower
71+ run : ./gradlew assembleRelease --console=plain
12772
12873 # Signed only when a key is configured. Without one the run still produces
129- # an unsigned artifact, which is installable by nobody and reviewable by
130- # anybody — the right outcome for a fork or a pull request.
74+ # an artifact — unsigned, so installable by nobody and reviewable by
75+ # anybody, which is right for a fork or a pull request.
13176 - name : Sign
132- id : sign
13377 if : env.HAS_KEY == 'true'
13478 env :
13579 KEYSTORE_B64 : ${{ secrets.FOLLOWER_KEYSTORE_B64 }}
@@ -140,22 +84,21 @@ jobs:
14084 set -euo pipefail
14185 BT=$(ls -1d "$ANDROID_HOME"/build-tools/*/ | sort -V | tail -1)
14286 echo "$KEYSTORE_B64" | base64 -d > /tmp/follower.jks
143- IN=aaps/app/build/outputs/apk/aapsclient/release/app-aapsclient-release-unsigned.apk
144- [ -f "$IN" ] || IN=$(ls aaps/app/build/outputs/apk/aapsclient/release/*.apk | head -1)
145- "${BT}zipalign" -p 4 "$IN" /tmp/follower-aligned.apk
87+ IN=$(ls follower/build/outputs/apk/release/*.apk | head -1)
88+ "${BT}zipalign" -f -p 4 "$IN" /tmp/aligned.apk
14689 "${BT}apksigner" sign \
14790 --ks /tmp/follower.jks --ks-pass "env:KS_PASS" \
14891 --ks-key-alias "$KEY_ALIAS" --key-pass "env:KEY_PASS" \
149- --out diaswarm-follower.apk /tmp/follower- aligned.apk
92+ --out diaswarm-follower.apk /tmp/aligned.apk
15093 shred -u /tmp/follower.jks
15194 "${BT}apksigner" verify --print-certs diaswarm-follower.apk | tee signer.txt
95+ ls -l diaswarm-follower.apk
15296
15397 - name : Name the unsigned build for what it is
15498 if : env.HAS_KEY != 'true'
155- run : cp $(ls aaps/app/ build/outputs/apk/aapsclient /release/*.apk | head -1) diaswarm-follower-UNSIGNED.apk
99+ run : cp $(ls follower/ build/outputs/apk/release/*.apk | head -1) diaswarm-follower-UNSIGNED.apk
156100
157- - name : Upload
158- uses : actions/upload-artifact@v4
101+ - uses : actions/upload-artifact@v4
159102 with :
160103 name : diaswarm-follower
161104 path : |
@@ -168,21 +111,14 @@ jobs:
168111 GH_TOKEN : ${{ github.token }}
169112 run : |
170113 set -euo pipefail
171- AAPS_SHA=$(git -C aaps rev-parse HEAD)
172114 cat > notes.md <<EOF
173- Follower app — shows somebody else's glucose. **It cannot dose.**
174-
175- Separate \`applicationId\` (\`info.nightscout.aapsclient\`), no pump drivers
176- compiled in, installs alongside AAPS rather than over it.
177-
178- **This is not the loop app, and this repository does not distribute one.**
115+ Shows somebody else's glucose. **It cannot dose, and contains no loop code.**
179116
180- Built from:
181- * diaswarm \`${GITHUB_SHA}\`
182- * AndroidAPS \`${AAPS_REPO}@${AAPS_SHA}\`
117+ This is not AndroidAPS and does not contain it. To share your own data you
118+ need the AAPS add-on, which you build yourself — this repository does not
119+ distribute a loop and never will.
183120
184- AndroidAPS is AGPL-3.0. The corresponding source for this binary is the
185- two commits above; both repositories are public.
121+ Built from \`${GITHUB_SHA}\`.
186122 EOF
187123 gh release create "${GITHUB_REF_NAME}" diaswarm-follower*.apk \
188124 --repo "${GITHUB_REPOSITORY}" --title "${GITHUB_REF_NAME}" --notes-file notes.md
0 commit comments