ci: route Android APK through Forgejo releases
All checks were successful
Forgejo Android APK / Build signed APK (push) Successful in 1m54s

This commit is contained in:
Daniel 2026-05-11 04:21:15 +02:00
parent 2bbdb88ceb
commit 04659059d0
8 changed files with 107 additions and 10 deletions

View file

@ -3,6 +3,8 @@ name: Forgejo Android APK
on:
workflow_dispatch:
push:
branches:
- '**'
tags:
- 'v*'
@ -61,6 +63,60 @@ jobs:
-Pandroid.injected.signing.key.password="$KEY_PASS" \
--no-daemon --stacktrace
- name: Check Google Play secret
id: play_publish
run: |
if [[ "$GITHUB_REF" != refs/tags/v* ]]; then
echo "enabled=false" >> "$GITHUB_OUTPUT"
elif [ -z "${GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_B64:-}" ]; then
echo "enabled=false" >> "$GITHUB_OUTPUT"
else
echo "enabled=true" >> "$GITHUB_OUTPUT"
fi
env:
GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_B64: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_B64 }}
- name: Build signed release App Bundle
if: steps.play_publish.outputs.enabled == 'true'
working-directory: mobile/android
env:
KS_PASS: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
KEY_PASS: ${{ secrets.ANDROID_KEY_PASSWORD }}
run: |
./gradlew bundleRelease \
-Pandroid.injected.signing.store.file="$RUNNER_TEMP/pedscribe-release.jks" \
-Pandroid.injected.signing.store.password="$KS_PASS" \
-Pandroid.injected.signing.key.alias="$KEY_ALIAS" \
-Pandroid.injected.signing.key.password="$KEY_PASS" \
--no-daemon --stacktrace
- name: Install fastlane
if: steps.play_publish.outputs.enabled == 'true'
working-directory: mobile/android
run: |
gem install bundler -N
bundle install
- name: Upload bundle to Google Play (internal track)
if: steps.play_publish.outputs.enabled == 'true'
working-directory: mobile/android
env:
GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_B64: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_B64 }}
PLAY_TRACK: internal
run: |
test -n "$GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_B64"
CLEAN_PLAY_JSON_B64="${GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_B64#GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_B64=}"
printf '%s' "$CLEAN_PLAY_JSON_B64" | tr -d '\r\n' | base64 -d > fastlane/google-play-service-account.json
AAB=$(find app/build/outputs/bundle/release -name '*.aab' | head -1)
test -n "$AAB"
AAB_PATH="$AAB" bundle exec fastlane android publish_internal
rm -f fastlane/google-play-service-account.json
- name: Collect APK
run: |
mkdir -p artifacts

View file

@ -28,7 +28,7 @@ or Actions tab → **Version bump & release** → Run workflow → pick bump typ
| Workflow | Output |
|---|---|
| `android-release.yml` | signed APK on GitHub release, `make_latest=true` |
| `.forgejo/workflows/android-apk.yml` | signed APK on Forgejo release (`pedscribe-<tag>.apk`), optional Google Play internal track upload |
| `docker-publish.yml` | `danielonyejesi/pediatric-ai-scribe-v3:{version,latest}` on Docker Hub (amd64) |
## Local dev

View file

@ -64,9 +64,13 @@ mobile/ # Capacitor wrapper
src/ # launcher (server-URL picker)
android/ # generated AS project + native Java
.forgejo/workflows/
android-apk.yml # signed APK on tag push; optional Play upload
docker-build.yml # Forgejo registry Docker image build
.github/workflows/
auto-version.yml # conventional-commits → semver bump → tag
android-release.yml # signed APK on tag push
android-release.yml # legacy GitHub tag APK release path
docker-publish.yml # multi-arch image on tag push
version-bump.yml # manual dispatch override
build-apk.yml # legacy TWA APK

View file

@ -146,11 +146,11 @@ Container marked unhealthy after 5 failures.
## CI / CD
Four workflows fire on tag push:
On push (and tag push), these workflows run (depending on runner/site):
| Workflow | Output | Runtime |
|---|---|---|
| `android-release.yml` | Signed APK attached to the GitHub release | ~8 min |
| `.forgejo/workflows/android-apk.yml` | Signed APK attached to the Forgejo release, plus optional Google Play internal track upload | ~8 min |
| `docker-publish.yml` | Multi-arch image (amd64 + arm64 via native runners) on Docker Hub | ~4 min |
| `build-apk.yml` | Legacy TWA APK (optional second artifact) | ~2 min |

View file

@ -26,8 +26,12 @@ npx cap open android
## CI build (preferred)
Tag-triggered. Push any `vX.Y.Z` tag → `.github/workflows/android-release.yml`
builds a signed APK on a GitHub runner and attaches it to the matching release.
Push-triggered. Any push to `main`/feature branches and any `vX.Y.Z` tag push
`.forgejo/workflows/android-apk.yml` builds a signed APK on the Forgejo
runner.
Tagged builds additionally publish the artifact to the matching Forgejo release
as `pedscribe-<tag>.apk` so Obtainium can track updates.
Required repo secrets (set once, via Settings → Secrets and variables → Actions
or `gh secret set`):
@ -36,6 +40,14 @@ or `gh secret set`):
- `ANDROID_KEYSTORE_PASSWORD`
- `ANDROID_KEY_ALIAS``pedscribe`
- `ANDROID_KEY_PASSWORD`
- `GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_B64` — base64 of your Google Play service
account JSON (optional). If present, the same tag build also runs `bundleRelease`
and uploads the AAB to Play's `internal` track.
Optional Play Store flow:
- Service account must have permissions to edit releases on the app in Play.
- Build task is `bundleRelease`, tracked as `com.pedshub.scribe`.
- Upload lane is `fastlane/android publish_internal` (under `mobile/android/fastlane`).
Tag a release:
@ -48,9 +60,10 @@ git commit -m "fix: ..." && git push # auto-version workflow bumps patch
scripts/release.sh X.Y.Z --push
```
APK lands at the GitHub release; `/releases/latest` link in the login page
resolves to it automatically. Obtanium subscribers (`github.com/<owner>/<repo>`)
pick up the update on next poll.
APK lands on the Forgejo release. Obtainium can still track
`git.danvics.com/danvics/pediatric-ai-scribe-v3` releases automatically.
Play Store upload is handled automatically for tagged builds only when
`GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_B64` is configured.
## Local build (fallback / debugging)
@ -116,4 +129,5 @@ user to uninstall + reinstall.
| `mobile/android/app/src/main/java/com/pedshub/scribe/MainActivity.java` | JS bridge + WebView mic permission |
| `mobile/android/app/src/main/java/com/pedshub/scribe/AudioRecordingService.java` | foreground service for background recording |
| `mobile/android/app/src/main/AndroidManifest.xml` | permissions, intents, backup rules |
| `.github/workflows/android-release.yml` | CI build |
| `.forgejo/workflows/android-apk.yml` | CI build |
| `mobile/android/fastlane/Fastfile` | internal Play track upload lane |

View file

@ -0,0 +1,2 @@
json_key_file('fastlane/google-play-service-account.json')
package_name('com.pedshub.scribe')

View file

@ -0,0 +1,18 @@
default_platform(:android)
platform :android do
desc "Upload a signed release AAB to Google Play internal track"
lane :publish_internal do
upload_to_play_store(
package_name: 'com.pedshub.scribe',
json_key: 'fastlane/google-play-service-account.json',
aab: ENV['AAB_PATH'] || 'app/build/outputs/bundle/release/app-release.aab',
track: ENV['PLAY_TRACK'] || 'internal',
skip_upload_changelogs: true,
skip_upload_metadata: true,
skip_upload_images: true,
skip_upload_screenshots: true,
release_status: 'completed',
)
end
end

View file

@ -0,0 +1,3 @@
source 'https://rubygems.org'
gem 'fastlane'