Prod deploy: build signed Android AAB and attach to Gitea release (mirror dta_webapp) #121

Open
opened 2026-10-19 03:44:52 -07:00 by westfarn · 0 comments
Owner

Summary

When Deploy Prod runs, also build a signed Play AAB from Capacitor (llm-fe/) and publish it as a Gitea release asset, same pattern as dta_webapp .gitea/workflows/deploy-prod.yml → android-release job.

Today Deploy Prod only ships web-static via server-infra/scripts/deploy.sh. Android signing is still manual (llm-fe/ANDROID.md).

This supersedes the separate-button design in #58 — do not add a standalone deploy-android.yml unless we later need a rebuild-without-web-deploy escape hatch. Prefer one prod workflow like RealPath.

Reference release shape on dta: tags android-v<versionName>-<versionCode> with asset realpath-<versionName>-<versionCode>.aab (e.g. android-v1.0.2-3).


How dta_webapp does it (copy this)

Deploy Prod Webapp (workflow_dispatch):

  1. unit-tests
  2. deploy-prod → deploy.sh --app dta_webapp --env prod
  3. android-release (needs deploy-prod):
    • checkout same ${{ gitea.sha }}
    • node scripts/android-version.mjs — looks up existing android-v* releases; reuses version for same SHA, else next patch + next versionCode
    • npm run build:android:store — store web bundle + cap sync
    • symlink host keystore into checkout:
      • /home/westfarn/.android/keystore.properties → android/keystore.properties
      • /home/westfarn/.android/realpath-upload.jks (referenced by props)
      • write android/local.properties → sdk.dir=/home/westfarn/Android/Sdk
    • ./gradlew bundleRelease with -PrealpathVersionCode / -PrealpathVersionName
    • jarsigner -verify on the AAB
    • node scripts/publish-android-gitea-release.mjs — create/reuse Gitea release + upload AAB

Uses Actions secret secrets.GITHUB_TOKEN as GITEA_TOKEN for release list/create/upload.

Scripts/docs to port (adapt names for Hesychia):

dta path Role
ditch-the-agent/scripts/android-version.mjs (+ test) Auto bump / reuse Play version from Gitea tags
ditch-the-agent/scripts/publish-android-gitea-release.mjs Create android-v* release + attach AAB
ditch-the-agent/docs/android-play-store.md Ops notes
android/app/build.gradle floors + -P overrides Avoid editing gradle on every prod run

Target for chat_web_app

1. Extend .gitea/workflows/deploy-prod.yml

Add android-release job after deploy-prod (working-directory llm-fe), same structure as dta.

2. Scripts under llm-fe/scripts/

Port/adapt:

  • android-version.mjs — baseline floors from android/app/build.gradle (today versionName "0.1.0" / versionCode 1; introduce floor props like dta’s *VersionCodeFloor / *VersionNameFloor, Hesychia-named)
  • publish-android-gitea-release.mjs — tag android-v${versionName}-${versionCode}, asset e.g. hesychia-${versionName}-${versionCode}.aab, application id ai.hesychia.chat

3. npm / Capacitor store build

Ensure a store-oriented script (dta: build:android:store). For us, prod mobile is npm run build:mobile (.env.mobile → prod API). Either:

  • use build:mobile in the job, or
  • add an explicit build:android:store alias that documents “Play binary only”

Must end with cap sync android before bundleRelease.

4. Gradle version overrides

Mirror dta: floors in build.gradle, CI passes next version via -P… so prod runs never require a manual version commit.

5. Docs

  • Update llm-fe/ANDROID.md / android/README.md: Deploy Prod publishes AAB to Gitea releases; link example dta release
  • Note relationship to #58 (close #58 as superseded when this lands)
  • Runner/secrets still tracked in server-infra#9 — prefer dta’s live layout ~/.android/ over the earlier Documents/secrets/chat_web_app/android/ proposal unless we deliberately standardize both apps

6. Out of scope

  • Auto-upload to Play Console (manual download from Gitea release → internal track is enough, same as dta today)
  • Extending deploy.sh / nginx for APK hosting
  • iOS / TestFlight
  • Changing Deploy Beta

Secrets / host setup (ops — do before first green run)

A. Host files on the self-hosted runner (not in git)

Match dta paths so the workflow can ln -sfn the same way:

/home/westfarn/.android/
  hesychia-upload.jks          # Play upload keystore (never commit)
  keystore.properties          # passwords + paths (mode 600)

keystore.properties example (paths relative to android/app/ like dta, or absolute):

storeFile=/home/westfarn/.android/hesychia-upload.jks
storePassword=...
keyAlias=aiml-chat-upload
keyPassword=...

Create keystore once if missing (alias can match docs):

keytool -genkey -v \
  -keystore /home/westfarn/.android/hesychia-upload.jks \
  -keyalg RSA -keysize 2048 -validity 10000 \
  -alias aiml-chat-upload

Also required on runner (dta already uses these):

  • /home/westfarn/Android/Sdk (Platform 35 + build-tools)
  • JDK 17+

Note: Older docs/ANDROID.md mention ~/Documents/secrets/aiml-chat-upload.jks. Either move/symlink into ~/.android/ to match dta, or point storeFile at the old path — workflow should test -f whatever path we standardize.

Note: If RealPath and Hesychia share one keystore.properties filename under ~/.android/, use separate property files (e.g. hesychia-keystore.properties vs RealPath’s keystore.properties) so the two apps do not overwrite each other’s symlink target. Ticket implementer should pick distinct filenames and document them in both workflows.

B. Gitea Actions secret on chat_web_app

Repo → Settings → Actions → Secrets:

Secret name Purpose
GITHUB_TOKEN Personal access token (or app token) with repo release write — same name dta uses; workflow maps it to GITEA_TOKEN for android-version.mjs + publish-android-gitea-release.mjs

Token must be allowed to create tags/releases and upload release assets on ai_ml_operations/chat_web_app.

No keystore passwords in Gitea secrets if we keep dta’s host-file model (preferred).

C. Optional later

  • play-service-account.json for Play Developer API upload (not required for Gitea release attachment)

Acceptance criteria

  • deploy-prod.yml has android-release after successful prod web deploy
  • Job builds signed app-release.aab for ai.hesychia.chat from the workflow SHA
  • Version auto-bumps from existing android-v* releases (reuse if same SHA)
  • Gitea release created/updated with AAB asset attached
  • Keystore / passwords never committed; loaded from runner ~/.android/ (or documented equivalent)
  • jarsigner -verify (or equivalent) on the AAB before publish
  • ANDROID.md documents the flow + secrets layout
  • #58 closed as superseded (or retargeted) when this ships

References

## Summary When **Deploy Prod** runs, also build a **signed Play AAB** from Capacitor (`llm-fe/`) and publish it as a **Gitea release asset**, same pattern as [dta_webapp](https://git.aimloperations.com/Ditch_The_Agent/dta_webapp) `.gitea/workflows/deploy-prod.yml` → `android-release` job. Today Deploy Prod only ships web-static via `server-infra/scripts/deploy.sh`. Android signing is still manual (`llm-fe/ANDROID.md`). This **supersedes the separate-button design in [#58](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/58)** — do not add a standalone `deploy-android.yml` unless we later need a rebuild-without-web-deploy escape hatch. Prefer one prod workflow like RealPath. Reference release shape on dta: tags `android-v<versionName>-<versionCode>` with asset `realpath-<versionName>-<versionCode>.aab` (e.g. [android-v1.0.2-3](https://git.aimloperations.com/Ditch_The_Agent/dta_webapp/releases/tag/android-v1.0.2-3)). --- ## How dta_webapp does it (copy this) `Deploy Prod Webapp` (`workflow_dispatch`): 1. `unit-tests` 2. `deploy-prod` → `deploy.sh --app dta_webapp --env prod` 3. `android-release` (needs `deploy-prod`): - checkout same `${{ gitea.sha }}` - `node scripts/android-version.mjs` — looks up existing `android-v*` releases; reuses version for same SHA, else next patch + next `versionCode` - `npm run build:android:store` — store web bundle + `cap sync` - symlink host keystore into checkout: - `/home/westfarn/.android/keystore.properties` → `android/keystore.properties` - `/home/westfarn/.android/realpath-upload.jks` (referenced by props) - write `android/local.properties` → `sdk.dir=/home/westfarn/Android/Sdk` - `./gradlew bundleRelease` with `-PrealpathVersionCode` / `-PrealpathVersionName` - `jarsigner -verify` on the AAB - `node scripts/publish-android-gitea-release.mjs` — create/reuse Gitea release + upload AAB Uses Actions secret `secrets.GITHUB_TOKEN` as `GITEA_TOKEN` for release list/create/upload. Scripts/docs to port (adapt names for Hesychia): | dta path | Role | |----------|------| | `ditch-the-agent/scripts/android-version.mjs` (+ test) | Auto bump / reuse Play version from Gitea tags | | `ditch-the-agent/scripts/publish-android-gitea-release.mjs` | Create `android-v*` release + attach AAB | | `ditch-the-agent/docs/android-play-store.md` | Ops notes | | `android/app/build.gradle` floors + `-P` overrides | Avoid editing gradle on every prod run | --- ## Target for chat_web_app ### 1. Extend `.gitea/workflows/deploy-prod.yml` Add `android-release` job after `deploy-prod` (working-directory `llm-fe`), same structure as dta. ### 2. Scripts under `llm-fe/scripts/` Port/adapt: - `android-version.mjs` — baseline floors from `android/app/build.gradle` (today `versionName "0.1.0"` / `versionCode 1`; introduce floor props like dta’s `*VersionCodeFloor` / `*VersionNameFloor`, Hesychia-named) - `publish-android-gitea-release.mjs` — tag `android-v${versionName}-${versionCode}`, asset e.g. `hesychia-${versionName}-${versionCode}.aab`, application id `ai.hesychia.chat` ### 3. npm / Capacitor store build Ensure a store-oriented script (dta: `build:android:store`). For us, prod mobile is `npm run build:mobile` (`.env.mobile` → prod API). Either: - use `build:mobile` in the job, or - add an explicit `build:android:store` alias that documents “Play binary only” Must end with `cap sync android` before `bundleRelease`. ### 4. Gradle version overrides Mirror dta: floors in `build.gradle`, CI passes next version via `-P…` so prod runs never require a manual version commit. ### 5. Docs - Update `llm-fe/ANDROID.md` / `android/README.md`: Deploy Prod publishes AAB to Gitea releases; link example dta release - Note relationship to [#58](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/58) (close #58 as superseded when this lands) - Runner/secrets still tracked in [server-infra#9](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/9) — **prefer dta’s live layout** `~/.android/` over the earlier `Documents/secrets/chat_web_app/android/` proposal unless we deliberately standardize both apps ### 6. Out of scope - Auto-upload to Play Console (manual download from Gitea release → internal track is enough, same as dta today) - Extending `deploy.sh` / nginx for APK hosting - iOS / TestFlight - Changing Deploy Beta --- ## Secrets / host setup (ops — do before first green run) ### A. Host files on the self-hosted runner (not in git) Match dta paths so the workflow can `ln -sfn` the same way: ```text /home/westfarn/.android/ hesychia-upload.jks # Play upload keystore (never commit) keystore.properties # passwords + paths (mode 600) ``` `keystore.properties` example (paths relative to `android/app/` like dta, or absolute): ```properties storeFile=/home/westfarn/.android/hesychia-upload.jks storePassword=... keyAlias=aiml-chat-upload keyPassword=... ``` Create keystore once if missing (alias can match docs): ```bash keytool -genkey -v \ -keystore /home/westfarn/.android/hesychia-upload.jks \ -keyalg RSA -keysize 2048 -validity 10000 \ -alias aiml-chat-upload ``` Also required on runner (dta already uses these): - `/home/westfarn/Android/Sdk` (Platform 35 + build-tools) - JDK 17+ **Note:** Older docs/`ANDROID.md` mention `~/Documents/secrets/aiml-chat-upload.jks`. Either move/symlink into `~/.android/` to match dta, or point `storeFile` at the old path — workflow should `test -f` whatever path we standardize. **Note:** If RealPath and Hesychia share one `keystore.properties` filename under `~/.android/`, use **separate property files** (e.g. `hesychia-keystore.properties` vs RealPath’s `keystore.properties`) so the two apps do not overwrite each other’s symlink target. Ticket implementer should pick distinct filenames and document them in both workflows. ### B. Gitea Actions secret on `chat_web_app` Repo → Settings → Actions → Secrets: | Secret name | Purpose | |-------------|---------| | `GITHUB_TOKEN` | Personal access token (or app token) with **repo release write** — same name dta uses; workflow maps it to `GITEA_TOKEN` for `android-version.mjs` + `publish-android-gitea-release.mjs` | Token must be allowed to create tags/releases and upload release assets on `ai_ml_operations/chat_web_app`. No keystore passwords in Gitea secrets if we keep dta’s host-file model (preferred). ### C. Optional later - `play-service-account.json` for Play Developer API upload (not required for Gitea release attachment) --- ## Acceptance criteria - [ ] `deploy-prod.yml` has `android-release` after successful prod web deploy - [ ] Job builds signed `app-release.aab` for `ai.hesychia.chat` from the workflow SHA - [ ] Version auto-bumps from existing `android-v*` releases (reuse if same SHA) - [ ] Gitea release created/updated with AAB asset attached - [ ] Keystore / passwords never committed; loaded from runner `~/.android/` (or documented equivalent) - [ ] `jarsigner -verify` (or equivalent) on the AAB before publish - [ ] ANDROID.md documents the flow + secrets layout - [ ] [#58](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/58) closed as superseded (or retargeted) when this ships ## References - Pattern: https://git.aimloperations.com/Ditch_The_Agent/dta_webapp/src/branch/main/.gitea/workflows/deploy-prod.yml - Scripts: `ditch-the-agent/scripts/android-version.mjs`, `publish-android-gitea-release.mjs` - Docs: `ditch-the-agent/docs/android-play-store.md` - Local Capacitor: `llm-fe/ANDROID.md`, `llm-fe/android/README.md` - Prior tickets: #58 (separate Deploy Android), #57 (debug CI), [server-infra#9](https://git.aimloperations.com/ai_ml_operations/server-infra/issues/9)
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ai_ml_operations/chat_web_app#121