Closes the physical↔digital loop the labels opened: the QR on a printed envelope (tane://seed, already encoded by seed_label_codec) can now be scanned from the inventory bar. A known label opens its variety; an unknown one asks before adding anything, then creates the variety (species linked by exact scientific name when bundled) with a lot carrying the label's year and origin. Scanner is pure ZXing (zxing_barcode_scanner, MIT) — no ML Kit, no Play Services, F-Droid-safe, the stack Ğ1nkgo ships. Mobile-only; other platforms don't show the button (OCR precedent). The post-scan flow is a plain function (handleScannedPayload) so it's widget-tested without a camera.
8.1 KiB
Releasing Tane
Tane ships as a self-contained Android app (desktop builds also work). Releases are automated and password-free: pushing a signed git tag triggers CI, which builds a signed AAB and publishes it to Google Play. This page covers the one-time setup, the automated flow, and the by-hand fallback.
TL;DR — cut a release
Once the one-time setup below is done:
# bump version in apps/app_seeds/pubspec.yaml, update CHANGELOG + changelogs/<code>.txt
git tag v0.1.0 && git push origin v0.1.0
Forgejo Actions (../.forgejo/workflows/release.yml)
builds the signed AAB/APK and uploads to Play's internal track. No passwords are typed.
Versioning
- Semantic version in
apps/app_seeds/pubspec.yamlasMAJOR.MINOR.PATCH+BUILD(e.g.0.1.0+1). Flutter maps+BUILDto AndroidversionCodeand the rest toversionName. - Record every user-visible change in
../CHANGELOG.mdand add a matching per-locale note underapps/app_seeds/fastlane/metadata/android/<locale>/changelogs/<versionCode>.txt.
One-time setup
Android signing keystore (dedicated to Tane)
Tane uses its own upload keystore, separate from other Comunes apps (Ğ1nkgo, Fuegos), kept in the shared Comunes signing directory:
keytool -genkey -v \
-keystore /home/vjrj/proyectos/sync/comunes/shared-l2/apkSigning/tane-upload.jks \
-keyalg RSA -keysize 4096 -validity 10000 -alias tane-upload
Release builds sign with this keystore when a gitignored
apps/app_seeds/android/key.properties exists; without it they fall back to debug
keys (so contributors can still flutter run --release). For local signed
builds, create apps/app_seeds/android/key.properties (never commit it):
storeFile=/home/vjrj/proyectos/sync/comunes/shared-l2/apkSigning/tane-upload.jks
storePassword=…
keyAlias=tane-upload
keyPassword=…
With Play App Signing (recommended, enabled once in the console) this is the upload key; Google holds the app signing key and can help rotate the upload key if it is ever lost.
CI secrets (one-time, Forgejo → repo Settings → Actions → Secrets)
Set these so releases never prompt for a password:
| Secret | What |
|---|---|
TANE_KEYSTORE_BASE64 |
base64 -w0 tane-upload.jks |
TANE_KEYSTORE_PASSWORD |
store password |
TANE_KEY_ALIAS |
tane-upload |
TANE_KEY_PASSWORD |
key password |
SUPPLY_JSON_KEY_DATA |
Google Play service-account JSON (raw file contents) |
The Play service account is reused from Ğ1nkgo (ginkgo-play-uploader@…,
/home/vjrj/etc/ginkgo_play_api_key.json) — it belongs to the Comunes Play account,
not to one app, so it just needs access granted to org.comunes.tane in Play Console.
fastlane supply uses it to upload without a human. The first upload of the brand-new
app must still be done by hand in the console (Play requires the app to exist before
the API accepts uploads).
CI runner (Forgejo Actions) — action needed
The release + gate workflows (.forgejo/workflows/*.yml) run on Forgejo Actions,
which needs a registered runner. As of 2026-07-16 the aaron host runs the
forgejo and jenkins containers but no Forgejo Actions runner — so the
workflows will queue and never start until one is registered. Two options:
- Register an act_runner on
aaron(aforgejo-runner/act_runnercontainer registered againstgit.comunes.orgwith a label matchingruns-on:— currentlydocker). Then tag → build → publish works as designed. - Or move CI to Jenkins (already running on
aaron) via a Jenkinsfile; the build andfastlane deploy_playsteps are the same shell commands.
Also: the keystore's real alias is tane-upload, so the Forgejo secret
TANE_KEY_ALIAS and local key.properties must both use tane-upload.
Build by hand (fallback / first Play upload)
cd apps/app_seeds
dart run slang # i18n (if strings changed)
dart run build_runner build --delete-conflicting-outputs # Drift (if schema changed)
flutter test # must be green
flutter build appbundle --release # AAB for Play
flutter build apk --release # APK for sideload / QA
Artifacts:
- AAB →
apps/app_seeds/build/app/outputs/bundle/release/app-release.aab - APK →
apps/app_seeds/build/app/outputs/flutter-apk/app-release.apk
Verify the signature is Tane's key (not another app's):
apksigner verify --print-certs app-release.apk → alias tane-upload.
Publish to Google Play (fastlane)
CI does this on tag, but you can run it locally too:
cd apps/app_seeds
bundle install
SUPPLY_JSON_KEY_DATA="$(cat play-service-account.json)" bundle exec fastlane deploy_play
Lanes live in fastlane/Fastfile; the store
listing (titles, descriptions, changelogs, screenshots) is read straight from
fastlane/metadata/android/. Data Safety and content-rating answers:
legal/internal/play-compliance.md.
Publish to F-Droid (official repo)
F-Droid builds from source after a merge request to fdroiddata. The build recipe
is kept in-repo at fdroid/org.comunes.tane.yml.
Copy it to metadata/org.comunes.tane.yml in a fork of fdroiddata, validate with
fdroid lint / fdroid build -l org.comunes.tane, then open the MR
(43144).
Reproducible, developer-signed. The recipe pins AllowedAPKSigningKeys (the
SHA-256 of the tane-upload certificate) and a binary: URL per ABI. F-Droid
rebuilds each split, and if its output matches our signed reference APK
byte-for-byte it publishes our APK — so F-Droid and Play share the same
signature and users can move between stores without reinstalling. The reference
APKs are the per-ABI splits the release workflow attaches to the Forgejo release
on git.comunes.org (.forgejo/workflows/release.yml).
To (re)compute the fingerprint from the keystore:
keytool -list -v -keystore .../tane-upload.jks -alias tane-upload \
| sed -n 's/.*SHA256: //p' | tr -d ':' | tr 'A-Z' 'a-z'
Before pushing the MR, confirm reproducibility in the fdroiddata fork:
fdroid build -l org.comunes.tane then fdroid verify org.comunes.tane must be
green against the Forgejo binary:. If a split is not reproducible, fall back to
F-Droid-signing that version (drop AllowedAPKSigningKeys/binary:) until fixed.
Store metadata
F-Droid / Fastlane-style metadata lives under
apps/app_seeds/fastlane/metadata/android/. Descriptions are derived from
intro.md; icon and splash are generated by
flutter_launcher_icons / flutter_native_splash (see pubspec.yaml).
Legal & Play compliance (before any store submission)
- The privacy policy must be live at
https://tane.comunes.org/legal/privacy(sources inlegal/) — Play Console requires the URL. - Fill the Data Safety form and the UGC/content-rating questionnaires from the
answer sheet in
legal/internal/play-compliance.md. - The in-app requirements (community-rules acceptance on market entry, report and block) ship with the app; keep them working — Play's UGC policy review looks for them.
Manual smoke test before shipping
Automated tests cover behaviour; a release build still gets a human pass on a real device (the one place we allow manual testing — it validates the packaged artifact, it does not replace tests):
- Cold start → intro carousel → home.
- Quick-add a seed with a photo; it appears in the list.
- Mark a lot to share; the "I share" filter and printable catalog appear.
- Save a backup, then restore it (and test the recovery sheet + code on a second install).
- Switch language (es / en / pt); check an RTL locale if the device offers one.
Not automated
Web builds (SQLCipher is unavailable on web) and iOS (no Apple developer setup yet). The F-Droid MR is opened by hand (F-Droid builds on its own infra, not ours).