Merge pull request #503 from off-grid-ai/chore/beta-distribution #52
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: Build and Release Android | |
| # NOTE: The iOS workflow (release-ios.yml) triggers via workflow_run on this workflow. | |
| # If you rename this workflow, update the workflow_run trigger in release-ios.yml. | |
| on: | |
| push: | |
| branches: [main] # every merge to main cuts a release | |
| workflow_dispatch: {} # manual fallback | |
| permissions: | |
| contents: write | |
| jobs: | |
| release: | |
| runs-on: ubuntu-latest | |
| # Lift store secrets to job-level env so the `if:` guards on the Play steps can test | |
| # for their presence (if: conditions can read env, not secrets directly). Absent | |
| # secrets => empty => Play upload steps skip, GitHub Release path still runs. | |
| env: | |
| ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} | |
| PLAY_STORE_JSON_KEY: ${{ secrets.PLAY_STORE_JSON_KEY }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| fetch-depth: 0 # Fetch all history for changelog | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| - name: Setup Java | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '17' | |
| - name: Setup Android SDK | |
| uses: android-actions/setup-android@v3 | |
| - name: Setup Ruby (fastlane) | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: '3.3' | |
| bundler-cache: true | |
| - name: Cache Gradle | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.gradle/caches | |
| ~/.gradle/wrapper | |
| key: gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} | |
| restore-keys: gradle- | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Bump patch version | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| npm version patch --no-git-tag-version | |
| NEW_VERSION=$(node -p "require('./package.json').version") | |
| echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV | |
| # Update Android versionCode and versionName | |
| VERSION_CODE=$(date +%s) | |
| echo "VERSION_CODE=$VERSION_CODE" >> $GITHUB_ENV | |
| # Update build.gradle | |
| sed -i "s/versionCode .*/versionCode $VERSION_CODE/" android/app/build.gradle | |
| sed -i "s/versionName .*/versionName \"$NEW_VERSION\"/" android/app/build.gradle | |
| git add package.json package-lock.json android/app/build.gradle | |
| git commit -m "chore: bump version to $NEW_VERSION [skip ci]" | |
| git push | |
| - name: Generate release notes | |
| run: | | |
| # Get commits since last tag (or all commits if no tags) | |
| LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") | |
| if [ -z "$LAST_TAG" ]; then | |
| COMMITS=$(git log --pretty=format:"- %s (%h)" --no-merges -20) | |
| else | |
| COMMITS=$(git log ${LAST_TAG}..HEAD --pretty=format:"- %s (%h)" --no-merges) | |
| fi | |
| # Write release notes | |
| echo "## What's Changed" > release-notes.md | |
| echo "" >> release-notes.md | |
| echo "$COMMITS" >> release-notes.md | |
| echo "" >> release-notes.md | |
| echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${LAST_TAG:-v0.0.0}...v${{ env.NEW_VERSION }}" >> release-notes.md | |
| cat release-notes.md | |
| - name: Build Android Release APK | |
| run: | | |
| cd android | |
| ./gradlew assembleRelease | |
| - name: Rename APK | |
| run: | | |
| mv android/app/build/outputs/apk/release/app-release.apk \ | |
| android/app/build/outputs/apk/release/OffgridMobile-v${{ env.NEW_VERSION }}.apk | |
| - name: Create GitHub Release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| gh release create v${{ env.NEW_VERSION }} \ | |
| android/app/build/outputs/apk/release/OffgridMobile-v${{ env.NEW_VERSION }}.apk \ | |
| --title "Off Grid v${{ env.NEW_VERSION }}" \ | |
| --notes-file release-notes.md | |
| - name: Upload APK artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: OffgridMobile-v${{ env.NEW_VERSION }} | |
| # No product flavors, so the APK lives under apk/release/ (not apk/standard/release/). | |
| path: android/app/build/outputs/apk/release/OffgridMobile-v${{ env.NEW_VERSION }}.apk | |
| if-no-files-found: error | |
| # ── Play Store upload (in addition to the GitHub Release above) ────────── | |
| # Decodes the production keystore + Play service-account key from secrets, builds | |
| # a signed AAB, and uploads to the Play production track as a DRAFT (a human | |
| # confirms rollout in the Play Console). Skipped automatically if the secrets are | |
| # absent, so the GitHub Release path still works without them. | |
| - name: Decode signing secrets | |
| if: ${{ env.ANDROID_KEYSTORE_BASE64 != '' && env.PLAY_STORE_JSON_KEY != '' }} | |
| run: | | |
| echo "$ANDROID_KEYSTORE_BASE64" | base64 --decode > "$RUNNER_TEMP/release.keystore" | |
| # PLAY_STORE_JSON_KEY may be stored raw-JSON or base64 — handle both (matches uat-dev.yml). | |
| echo "$PLAY_STORE_JSON_KEY" | base64 --decode > "$RUNNER_TEMP/play-key.json" \ | |
| || printf '%s' "$PLAY_STORE_JSON_KEY" > "$RUNNER_TEMP/play-key.json" | |
| echo "PLAY_UPLOAD=1" >> $GITHUB_ENV | |
| - name: Build signed AAB + upload to Play (draft) | |
| if: ${{ env.PLAY_UPLOAD == '1' }} | |
| env: | |
| PLAY_STORE_JSON_KEY_PATH: ${{ runner.temp }}/play-key.json | |
| # build.gradle gates release signing on project.hasProperty(...), so these must be | |
| # Gradle PROJECT properties (ORG_GRADLE_PROJECT_<name>), not plain env — otherwise | |
| # the AAB falls back to debug signing and Play rejects it. | |
| ORG_GRADLE_PROJECT_OFFGRID_UPLOAD_STORE_FILE: ${{ runner.temp }}/release.keystore | |
| ORG_GRADLE_PROJECT_OFFGRID_UPLOAD_STORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} | |
| ORG_GRADLE_PROJECT_OFFGRID_UPLOAD_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} | |
| ORG_GRADLE_PROJECT_OFFGRID_UPLOAD_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} | |
| run: bundle exec fastlane android release |