Merge pull request #538 from appdevforall/feat/K2GO-385-shared-status… #1377
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy to Firebase App Distribution | |
| # ADFA-4810: build & distribute on a push to ANY branch (not just main), so anyone gets a | |
| # Firebase build of their work without waiting for a merge. Tags (v*) are handled by | |
| # android-release-build.yml (production signing -> GitHub Release + R2) and are excluded here. | |
| # One signing key for everything on Firebase: the production keystore (same signature as the | |
| # main tester build), so testers never have to uninstall between builds. | |
| on: | |
| push: | |
| branches: | |
| - '**' | |
| tags-ignore: | |
| - 'v*' | |
| workflow_dispatch: | |
| # --- PERMITS REQUIRED FOR WIF --- | |
| permissions: | |
| contents: read | |
| id-token: write | |
| # One in-flight build per branch; a newer push cancels the previous run (saves CI, avoids stacking). | |
| concurrency: | |
| group: firebase-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| gate: | |
| name: Decide whether to build | |
| runs-on: ubuntu-latest | |
| outputs: | |
| build: ${{ steps.decide.outputs.build }} | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 # need history to diff against main | |
| - name: Decide | |
| id: decide | |
| run: | | |
| set -euo pipefail | |
| # Manual runs are always intentional. | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| echo "Manual dispatch -> build."; echo "build=true" >> "$GITHUB_OUTPUT"; exit 0 | |
| fi | |
| BRANCH="${GITHUB_REF#refs/heads/}" | |
| echo "Branch: $BRANCH" | |
| # main always builds (it distributes to the testers group). | |
| if [ "$BRANCH" = "main" ]; then | |
| echo "build=true" >> "$GITHUB_OUTPUT"; exit 0 | |
| fi | |
| # Skip branches with no real changes vs main (avoids building refs identical to main). | |
| git fetch -q origin main | |
| DIFF=$(git diff --name-only origin/main...HEAD | wc -l | tr -d ' ') | |
| echo "Files changed vs main: $DIFF" | |
| if [ "$DIFF" = "0" ]; then | |
| echo "::notice::No changes vs main; skipping build for $BRANCH." | |
| echo "build=false" >> "$GITHUB_OUTPUT"; exit 0 | |
| fi | |
| # Require a Jira ticket in the branch name (ADFA-#### or K2GO-####) or the | |
| # community/ prefix. Both keys are accepted while the Knowledge to Go tickets | |
| # move from the ADFA project to K2GO; ADFA stays valid for the work that | |
| # remains there. | |
| # Skip (with a warning) rather than fail, to avoid red X noise on ad-hoc branches. | |
| if echo "$BRANCH" | grep -qiE '(adfa|k2go)-[0-9]+' || echo "$BRANCH" | grep -q '^community/'; then | |
| echo "build=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "::warning::Branch '$BRANCH' has no Jira ticket (ADFA-#### or K2GO-####) and is not a community/ branch; skipping the Firebase build. Rename the branch or run the workflow manually to build it." | |
| echo "build=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| build-and-deploy: | |
| name: Build & Distribute | |
| needs: gate | |
| if: needs.gate.outputs.build == 'true' | |
| runs-on: ubuntu-latest | |
| # The Android code is located in the ./controller directory | |
| defaults: | |
| run: | |
| working-directory: ./controller | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v5 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 # Required to read the commit history | |
| - name: Set up JDK 17 | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'zulu' | |
| java-version: '17' | |
| cache: 'gradle' | |
| - name: Grant execute permission for gradlew | |
| run: chmod +x gradlew | |
| # --- SECRETS MANAGEMENT --- | |
| - name: Create google-services.json | |
| env: | |
| GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }} | |
| run: | | |
| # This assumes the app module folder is named 'app' inside 'controller' | |
| echo "$GOOGLE_SERVICES_JSON" > app/google-services.json | |
| - name: Decode Keystore | |
| env: | |
| ENCODED_STRING: ${{ secrets.KEYSTORE_BASE64 }} | |
| run: | | |
| echo "$ENCODED_STRING" | base64 -d > keystore.jks | |
| # --- VERSION AUDIT --- | |
| - name: Compute version suffix (short SHA) | |
| run: | | |
| # The short SHA already pins the exact commit, and the release notes below carry the | |
| # branch. A ticket key in the version name (ADFA-4810) only restated what the SHA says, | |
| # and went stale the moment the project key changed. | |
| SHORT_SHA=$(git rev-parse --short HEAD) | |
| echo "SHORT_SHA=$SHORT_SHA" >> "$GITHUB_ENV" | |
| echo "BRANCH_FULL=${GITHUB_REF#refs/heads/}" >> "$GITHUB_ENV" | |
| echo "VERSION_SUFFIX=-${SHORT_SHA}" >> "$GITHUB_ENV" | |
| - name: Log Pinned Binary Version | |
| run: | | |
| echo "==========================================" | |
| echo "Compiling with native binaries pinned to:" | |
| cat binary_version.txt | |
| echo "App Version Suffix: ${{ env.VERSION_SUFFIX }}" | |
| echo "==========================================" | |
| # --- BUILD AND SIGNING --- | |
| # assembleRelease + the production keystore for EVERY Firebase build (branches + main), so a | |
| # single signature is used and testers never uninstall between builds. Tags are the only | |
| # artifacts published to GitHub/R2 (separate workflow); this workflow never runs on tags. | |
| - name: Build and Sign APK | |
| env: | |
| # :app:syncNativeArtifacts queries the GitHub API for the pinned binaries | |
| # release; unauthenticated it gets HTTP 403 (shared-runner rate limit), so | |
| # provide the auto token for the M15 authenticated-retry fallback (build.gradle). | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} | |
| KEY_ALIAS: ${{ secrets.KEY_ALIAS }} | |
| KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }} | |
| # ADFA-4533: GlitchTip DSN for release builds distributed to testers | |
| SENTRY_DSN_RELEASE: ${{ secrets.SENTRY_DSN_RELEASE }} | |
| run: | | |
| ./gradlew assembleRelease \ | |
| -PversionSuffix="${{ env.VERSION_SUFFIX }}" \ | |
| -Pandroid.injected.signing.store.file=$(pwd)/keystore.jks \ | |
| -Pandroid.injected.signing.store.password=$KEYSTORE_PASSWORD \ | |
| -Pandroid.injected.signing.key.alias=$KEY_ALIAS \ | |
| -Pandroid.injected.signing.key.password=$KEY_PASSWORD | |
| - name: Find APK | |
| id: find_apk | |
| run: | | |
| # Distribute the Universal APK so both 32-bit and 64-bit testers can install it. | |
| apk_path=$(find . -path "*/build/outputs/apk/release/*universal*.apk" | head -n 1) | |
| if [ -z "$apk_path" ]; then | |
| echo "Error: Universal APK not found." | |
| exit 1 | |
| fi | |
| echo "APK_PATH=$apk_path" >> "$GITHUB_OUTPUT" | |
| # --- RELEASE NOTES --- | |
| - name: Prepare Release Notes | |
| id: prepare_notes | |
| run: | | |
| COMMIT_MSG=$(git log -1 --pretty=%B | head -1) | |
| COMMIT_AUTHOR=$(git log -1 --pretty=%an) | |
| NOTES_FILE=$(mktemp) | |
| echo "Branch: ${{ env.BRANCH_FULL }} (${{ env.SHORT_SHA }})" > "$NOTES_FILE" | |
| echo "Author: $COMMIT_AUTHOR" >> "$NOTES_FILE" | |
| echo "Message: $COMMIT_MSG" >> "$NOTES_FILE" | |
| echo "NOTES_FILE=$NOTES_FILE" >> "$GITHUB_OUTPUT" | |
| # --- FIREBASE DEPLOYMENT --- | |
| - name: Authenticate to Google Cloud via Workload Identity | |
| uses: google-github-actions/auth@v3 | |
| with: | |
| workload_identity_provider: ${{ secrets.WIF_PROVIDER }} | |
| service_account: ${{ secrets.IDENTITY_EMAIL }} | |
| - name: Setup Firebase CLI | |
| # Use the STANDALONE binary, not `npm install -g`. A fresh npm install floats | |
| # firebase-tools' transitive deps and (since ~2026-06-25) pulls a broken auth | |
| # sub-dependency that can't consume Workload Identity Federation (external_account) | |
| # credentials -> "Failed to authenticate". The standalone binary bundles its deps | |
| # frozen at release time (pre-regression), so WIF auth works deterministically. | |
| run: | | |
| sudo curl -fsSL \ | |
| https://github.com/firebase/firebase-tools/releases/download/v14.11.2/firebase-tools-linux \ | |
| -o /usr/local/bin/firebase | |
| sudo chmod +x /usr/local/bin/firebase | |
| firebase --version | |
| - name: Upload to Firebase App Distribution | |
| env: | |
| APK_PATH: ${{ steps.find_apk.outputs.APK_PATH }} | |
| FIREBASE_APP_ID: ${{ secrets.FIREBASE_APP_ID }} | |
| NOTES_FILE: ${{ steps.prepare_notes.outputs.NOTES_FILE }} | |
| run: | | |
| # Single Firebase App Distribution group for everything (main and all branches). | |
| firebase appdistribution:distribute "$APK_PATH" \ | |
| --app "$FIREBASE_APP_ID" \ | |
| --groups "testers" \ | |
| --release-notes-file "$NOTES_FILE" | |
| # --- SECURITY CLEANUP --- | |
| - name: Cleanup Secrets and Temp Files | |
| if: always() | |
| run: | | |
| rm -f keystore.jks | |
| rm -f app/google-services.json | |
| rm -f ${{ steps.prepare_notes.outputs.NOTES_FILE }} |