tane/docs/release.md
vjrj 4cac56e3bb
Some checks failed
ci / analyze (push) Failing after 15s
ci / test-commons-core (push) Failing after 29s
ci / test-app-seeds (push) Failing after 3s
docs(release): note Forgejo Actions runner is missing on aaron + keystore alias
aaron runs forgejo + jenkins but no act_runner, so workflows queue until a runner
is registered (or CI moves to Jenkins). Record that the keystore alias is tane-upload.
2026-07-16 03:15:18 +02:00

167 lines
7.1 KiB
Markdown

# 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:
```bash
# 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`](../.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.yaml`](../apps/app_seeds/pubspec.yaml)
as `MAJOR.MINOR.PATCH+BUILD` (e.g. `0.1.0+1`). Flutter maps `+BUILD` to
Android `versionCode` and the rest to `versionName`.
- Record every user-visible change in [`../CHANGELOG.md`](../CHANGELOG.md) and
add a matching per-locale note under
`apps/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:
```bash
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):
```properties
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` (a `forgejo-runner`/`act_runner` container
registered against `git.comunes.org` with a label matching `runs-on:` — currently
`docker`). Then tag → build → publish works as designed.
- **Or move CI to Jenkins** (already running on `aaron`) via a Jenkinsfile; the build
and `fastlane deploy_play` steps 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)
```bash
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:
```bash
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`](../apps/app_seeds/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`](legal/internal/play-compliance.md).
## Publish to F-Droid (official repo)
F-Droid builds and signs from source after a merge request to `fdroiddata`. The
build recipe is kept in-repo at [`fdroid/org.comunes.tane.yml`](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. F-Droid signs
with its own key, so the F-Droid and Play builds have different signatures.
## Store metadata
F-Droid / Fastlane-style metadata lives under
`apps/app_seeds/fastlane/metadata/android/`. Descriptions are derived from
[`intro.md`](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 in [`legal/`](legal/README.md)) — 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`](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):
1. Cold start → intro carousel → home.
2. Quick-add a seed with a photo; it appears in the list.
3. Mark a lot to share; the "I share" filter and printable catalog appear.
4. Save a backup, then restore it (and test the recovery sheet + code on a
second install).
5. 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).