4 Commits
Author SHA1 Message Date
dtourolleandClaude Opus 5 db974dcac1 Pin the versionCode in the config, not in a file the build overwrites
🚴 Build and Test BikeControl / Workspace tests (push) Successful in 13m33s
🚴 Build and Test BikeControl / Android compile check (push) Successful in 3m29s
The Android job died on `tauri.properties not found`. It is not found
because `cargo tauri android init` does not write it: in a clean clone
init leaves gen/android/app/ holding build.gradle.kts, proguard-rules.pro
and src/, nothing else. The generated app/.gitignore names the pattern —
tauri.properties sits with tauri.build.gradle.kts and proguard-tauri.pro,
the tauri.* files that `android build` stamps out on every run.

So the step was wrong twice and the crash was the lucky half. Had the
file existed, the build would have rewritten it from tauri.conf.json and
discarded the sed — a green build shipping the default versionCode, which
is the failure that reaches a rider's phone rather than the log.

Tauri exposes the actual input, so use it:

- tauri.conf.json gains bundle.android.versionCode, committed rather than
  conjured by CI, so the key is greppable and the sed has a fixed target.
- ci-android-version-code.sh edits the config. Formula and the 1000 floor
  are unchanged; the header comment is rewritten, since its premise (init
  writes the file, the default collides) does not hold — Tauri's default
  is major*1000000 + minor*1000 + patch, monotonic, and it puts 0.1.0 at
  exactly 1000, which is where the floor comes from. Missing key or failed
  substitution now exits 1 instead of degrading to a silent no-op.
- The step moves ahead of `android init`, next to ci-set-version.sh, since
  both edit the same config.

Verified against a clean clone: 0.1.0 -> 1100, v0.2.3 -> 1203,
v1.0.0 -> 11000, config still parses at each step. Then a real
`cargo tauri android build`, which wrote versionCode=1100 into
tauri.properties — the value reaches the APK.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 17:39:06 +02:00
dtourolleandClaude Opus 5 da56985499 Check every JNI symbol, not just the first one
🚴 Build and Test BikeControl / Workspace tests (push) Successful in 16m55s
Build & Release / Run tests (push) Successful in 6m35s
🚴 Build and Test BikeControl / Android compile check (push) Successful in 3m41s
Build & Release / Build Linux (deb + AppImage) (push) Successful in 15m18s
Build & Release / Build Arch package (push) Successful in 29m19s
Build & Release / Build Android APK (push) Failing after 29s
Build & Release / Create release (push) Skipped
The android-check job failed on a tree that is perfectly correct:
android.rs exports three `Java_..._MainActivity_*` symbols, the check
compared all three against a single expected name and called it a
mismatch.

Two bugs, both from assuming one native:

- SYM collected every export while EXPECTED was built from one method, so
  the comparison was three lines against one.
- The Kotlin side matched `external fun name()` on empty parens, which
  quietly skipped nativeSetActivity and nativeBluetoothStateChanged —
  parameters do not appear in the symbol name, so stop at the paren.

Now both sides are collected into sets and diffed, so a native declared
in Kotlin with no Rust half fails as loudly as the reverse. Verified
against the real files: passes as-is, and fails with a readable diff for
a Kotlin-only native and for a renamed Rust export.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 12:12:42 +02:00
dtourolleandClaude Opus 5 5a89433746 Cache the crates, not the 30 GB of build output
The same leak we just closed on JellyTau, fed harder from here. `target/`
is 30 GB locally (25G debug, 3.1G android, 2.9G release) and was cached
under two keys across five jobs, on the runner both repos share.

- Cache registry/index, registry/cache and git/db only. registry/src is
  left out as well: 155 MB of .crate tarballs beats 1.1 GB extracted, and
  cargo re-extracts it for free. Verified that `cargo fetch` unpacks, so
  sync-android-sources.sh — which reads btleplug's Java backend out of
  registry/src before any build has run — still finds its sources.
- Collapse cargo-host and cargo-android into one cargo-registry key. The
  split only existed to keep the two `target` dirs off each other; with
  target uncached, registry contents are target-independent. This also
  ends a silent miss: build-release's `test` and `build-linux` jobs shared
  cargo-host, so the test job claimed the key and build-linux's cache was
  never saved.
- CARGO_INCREMENTAL=0. Never reused between runs, and the bulk of the
  25 GB debug dir.
- npm: cache ~/.npm instead of ui/node_modules. `npm ci` deletes
  node_modules before installing, so that entry was restored and thrown
  away unread.
- Installer artifact retention 30d -> 7d; the tagged release carries them.

Rust jobs now compile cold every run. sccache with a hard size cap is the
way back if that starts to hurt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 12:11:11 +02:00
dtourolleandClaude Opus 5 06b4635470 Build every artifact in a pinned image, not on my laptop
Two builder images, because the jobs genuinely need two distributions:
Ubuntu for the tests, the Linux bundle and the Android APK, and Arch for
the .pkg.tar.zst, since makepkg is Arch-specific. Both are built from
this repo (NFR-12) and pinned by tag in the workflows, so a Dockerfile
change only reaches CI once it has been pushed.

libdbus-1-dev is not incidental in the Ubuntu image: btleplug's Linux
backend is bluez-async over the dbus crate, so without it the workspace
does not build at all.

The per-commit Android job is a cargo check, not an APK. The full signed
build is ~15 minutes and runs only on tags; a one-minute check catches
what actually breaks — the JNI shim, droidplug, and any desktop-only API
that has crept into a shared crate.

Two invariants a compiler cannot see are checked there too, because both
fail silently: the app builds, installs, launches, and finds no trainer.
The JNI symbol in android.rs is matched by the runtime by name, so
renaming the Kotlin package compiles fine and simply never initialises
btleplug; and gen/ must stay untracked or the sync script quietly becomes
optional.

The Android versionCode carries a 1000 floor. `tauri android init` writes
1000 for 0.1.0 today, so anyone holding a locally built APK already has
that number installed, and a bare major/minor/patch code would be 100 —
a downgrade, which Android refuses outright.

The fmt check is advisory for now. The tree predates this workflow and
`cargo fmt --all` currently rewrites ~2000 lines across 28 files; making
it a gate here would mean landing a repo-wide reformat as a side effect
of adding CI. Run fmt in its own commit, then drop the continue-on-error.
The two clippy warnings that stood between the tree and a real
`-D warnings` gate are fixed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 19:52:45 +02:00