feat(release): automate store publishing (fastlane supply + GitLab CI) and F-Droid recipe
- fastlane: Appfile/Fastfile/Gemfile with deploy_play lane (AAB -> Play internal track) - CI: tag-gated build:android (signed AAB/APK from CI secrets) + deploy:play jobs - F-Droid: fdroiddata build recipe at docs/fdroid/org.comunes.tane.yml - Play compliance: Data Safety / content-rating answer sheet (docs/legal/internal) - docs/release.md: automated tag-triggered flow, dedicated tane-upload keystore - pubspec: description now mentions the market, not just the inventory
This commit is contained in:
parent
dc0d18562f
commit
fd6b9d5f0d
9 changed files with 361 additions and 28 deletions
122
docs/release.md
122
docs/release.md
|
|
@ -1,7 +1,21 @@
|
|||
# Releasing Tane (manual, no CI yet)
|
||||
# Releasing Tane
|
||||
|
||||
Block 1 ships as a self-contained Android app (desktop builds also work). There
|
||||
is no release pipeline yet — this page is the by-hand checklist.
|
||||
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
|
||||
```
|
||||
|
||||
CI (`build:android` → `deploy:play` in [`../.gitlab-ci.yml`](../.gitlab-ci.yml)) builds
|
||||
the signed AAB/APK and uploads to Play's **internal** track. No passwords are typed.
|
||||
|
||||
## Versioning
|
||||
|
||||
|
|
@ -12,38 +26,92 @@ is no release pipeline yet — this page is the by-hand checklist.
|
|||
add a matching per-locale note under
|
||||
`apps/app_seeds/fastlane/metadata/android/<locale>/changelogs/<versionCode>.txt`.
|
||||
|
||||
## Android signing (one-time)
|
||||
## One-time setup
|
||||
|
||||
Release builds sign with your own 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`).
|
||||
### Android signing keystore (dedicated to Tane)
|
||||
|
||||
1. Create a keystore (keep it and its passwords safe — losing it means you can
|
||||
never update the app under the same identity):
|
||||
```bash
|
||||
keytool -genkey -v -keystore ~/tane-release.jks \
|
||||
-keyalg RSA -keysize 4096 -validity 10000 -alias tane
|
||||
```
|
||||
2. Create `apps/app_seeds/android/key.properties` (never commit it):
|
||||
```properties
|
||||
storeFile=/home/you/tane-release.jks
|
||||
storePassword=…
|
||||
keyAlias=tane
|
||||
keyPassword=…
|
||||
```
|
||||
Tane uses its **own** upload keystore, separate from other Comunes apps (Ğ1nkgo,
|
||||
Fuegos), kept in the shared Comunes signing directory:
|
||||
|
||||
## Build the beta by hand
|
||||
```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, GitLab → Settings → CI/CD → Variables)
|
||||
|
||||
Set these as **masked + protected** so releases never prompt for a password:
|
||||
|
||||
| Variable | 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 created in Google Cloud and granted release access in
|
||||
Play Console; it is what lets `fastlane supply` upload without a human. The first
|
||||
upload of a brand-new app must still be done by hand in the console (Play requires
|
||||
the app to exist before the API accepts uploads).
|
||||
|
||||
## 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 apk --release # or: flutter build appbundle --release
|
||||
flutter build appbundle --release # AAB for Play
|
||||
flutter build apk --release # APK for sideload / QA
|
||||
```
|
||||
|
||||
The APK lands at
|
||||
`apps/app_seeds/build/app/outputs/flutter-apk/app-release.apk`.
|
||||
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
|
||||
|
||||
|
|
@ -75,7 +143,7 @@ artifact, it does not replace tests):
|
|||
second install).
|
||||
5. Switch language (es / en / pt); check an RTL locale if the device offers one.
|
||||
|
||||
## Not in this release
|
||||
## Not automated
|
||||
|
||||
CI, Play Store automation, web builds (SQLCipher is unavailable on web), and
|
||||
the whole social layer (Block 2).
|
||||
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).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue