From 04659059d02601f1dd1cacb40caae4ffbb567586 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 11 May 2026 04:21:15 +0200 Subject: [PATCH] ci: route Android APK through Forgejo releases --- .forgejo/workflows/android-apk.yml | 56 ++++++++++++++++++++++++++++++ CONTRIBUTING.md | 2 +- docs/architecture.md | 6 +++- docs/deployment.md | 4 +-- docs/mobile-build.md | 26 ++++++++++---- mobile/android/fastlane/Appfile | 2 ++ mobile/android/fastlane/Fastfile | 18 ++++++++++ mobile/android/fastlane/Gemfile | 3 ++ 8 files changed, 107 insertions(+), 10 deletions(-) create mode 100644 mobile/android/fastlane/Appfile create mode 100644 mobile/android/fastlane/Fastfile create mode 100644 mobile/android/fastlane/Gemfile diff --git a/.forgejo/workflows/android-apk.yml b/.forgejo/workflows/android-apk.yml index 75835ac..fcb1274 100644 --- a/.forgejo/workflows/android-apk.yml +++ b/.forgejo/workflows/android-apk.yml @@ -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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 327da43..7785ad8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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-.apk`), optional Google Play internal track upload | | `docker-publish.yml` | `danielonyejesi/pediatric-ai-scribe-v3:{version,latest}` on Docker Hub (amd64) | ## Local dev diff --git a/docs/architecture.md b/docs/architecture.md index 3038401..710f162 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -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 diff --git a/docs/deployment.md b/docs/deployment.md index ce4b097..e67208e 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -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 | diff --git a/docs/mobile-build.md b/docs/mobile-build.md index 8b93836..e704205 100644 --- a/docs/mobile-build.md +++ b/docs/mobile-build.md @@ -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-.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//`) -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 | diff --git a/mobile/android/fastlane/Appfile b/mobile/android/fastlane/Appfile new file mode 100644 index 0000000..0e40cf1 --- /dev/null +++ b/mobile/android/fastlane/Appfile @@ -0,0 +1,2 @@ +json_key_file('fastlane/google-play-service-account.json') +package_name('com.pedshub.scribe') diff --git a/mobile/android/fastlane/Fastfile b/mobile/android/fastlane/Fastfile new file mode 100644 index 0000000..1c561a4 --- /dev/null +++ b/mobile/android/fastlane/Fastfile @@ -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 diff --git a/mobile/android/fastlane/Gemfile b/mobile/android/fastlane/Gemfile new file mode 100644 index 0000000..a627214 --- /dev/null +++ b/mobile/android/fastlane/Gemfile @@ -0,0 +1,3 @@ +source 'https://rubygems.org' + +gem 'fastlane'