chore: update test dependencies and normalize app version parsing #4
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 & Deploy Android (gms + foss) → Open Beta [dev] | |
| on: | |
| push: | |
| branches: [ dev ] | |
| paths: | |
| - "pubspec.yaml" | |
| - "lib/**" | |
| - "android/**" | |
| - "tools/**" | |
| - ".github/workflows/**" | |
| workflow_dispatch: | |
| concurrency: | |
| group: deploy-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # ── Detect whether this push should deploy to beta ── | |
| gate: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| should_deploy: ${{ steps.check.outputs.should_deploy }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: { fetch-depth: 1 } | |
| - name: Check for release guard | |
| id: check | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -euo pipefail | |
| DEPLOY="false" | |
| # For workflow_dispatch always deploy | |
| if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | |
| DEPLOY="true" | |
| echo "Deploying: workflow_dispatch trigger" | |
| fi | |
| # Check the first line of the head commit message | |
| if [[ "$DEPLOY" == "false" ]]; then | |
| FIRST_LINE=$(git log -1 --format='%s' HEAD) | |
| echo "Commit subject: $FIRST_LINE" | |
| if echo "$FIRST_LINE" | grep -qi '^release:'; then | |
| DEPLOY="true" | |
| echo "Deploying: commit message starts with 'release:'" | |
| fi | |
| fi | |
| # Check the PR title that produced this merge commit | |
| if [[ "$DEPLOY" == "false" ]]; then | |
| PR_TITLE=$(gh api "/repos/${{ github.repository }}/commits/${{ github.sha }}/pulls" \ | |
| --jq '.[0].title // empty' 2>/dev/null || true) | |
| echo "PR title: $PR_TITLE" | |
| if echo "$PR_TITLE" | grep -qi '^release:'; then | |
| DEPLOY="true" | |
| echo "Deploying: PR title starts with 'release:'" | |
| fi | |
| fi | |
| if [[ "$DEPLOY" == "false" ]]; then | |
| echo "No 'release:' guard found. Skipping beta upload." | |
| fi | |
| echo "should_deploy=$DEPLOY" >> "$GITHUB_OUTPUT" | |
| # ── GMS build (only when deploying) ── | |
| build-gms: | |
| needs: gate | |
| if: needs.gate.outputs.should_deploy == 'true' | |
| runs-on: ubuntu-latest | |
| env: | |
| JAVA_VERSION: "21" | |
| outputs: | |
| app_version: ${{ steps.ver.outputs.app_version }} | |
| build_number: ${{ steps.ver.outputs.build_number }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: { fetch-depth: 0 } | |
| - name: Setup Flutter (from .flutter-version) | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version-file: .flutter-version | |
| channel: stable | |
| cache: true | |
| - name: Setup Java | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: ${{ env.JAVA_VERSION }} | |
| - name: Setup Gradle | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Gradle wrapper validation | |
| uses: gradle/actions/wrapper-validation@v3 | |
| - name: Write android/local.properties | |
| shell: bash | |
| run: | | |
| set -e | |
| SDK_DIR="${ANDROID_SDK_ROOT:-$ANDROID_HOME}" | |
| FLUTTER_SDK="${FLUTTER_HOME:-$(dirname "$(dirname "$(readlink -f "$(which flutter)")")")}" | |
| { | |
| echo "sdk.dir=${SDK_DIR}" | |
| echo "flutter.sdk=${FLUTTER_SDK}" | |
| } > android/local.properties | |
| - name: Use preinstalled NDK | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| SDK_DIR="${ANDROID_SDK_ROOT:-$ANDROID_HOME}" | |
| NDK_DIR="${ANDROID_NDK_ROOT:-${ANDROID_NDK_HOME:-${ANDROID_NDK:-${ANDROID_NDK_LATEST_HOME:-}}}}" | |
| if [ -z "${NDK_DIR}" ]; then | |
| NDK_DIR=$(ls -d "${SDK_DIR}/ndk/"* 2>/dev/null | sort -V | tail -1 || true) | |
| fi | |
| [ -n "${NDK_DIR}" ] && [ -d "${NDK_DIR}" ] || { echo "::error::No preinstalled NDK found"; exit 1; } | |
| NDK_VER="$(basename "$NDK_DIR")" | |
| GP=android/gradle.properties | |
| touch "${GP}" | |
| if grep -q '^android\.ndkVersion=' "${GP}"; then | |
| sed -i "s/^android\.ndkVersion=.*/android.ndkVersion=${NDK_VER}/" "${GP}" | |
| else | |
| printf '\nandroid.ndkVersion=%s\n' "${NDK_VER}" >> "${GP}" | |
| fi | |
| - name: Read pubspec version | |
| id: ver | |
| shell: bash | |
| run: | | |
| VLINE=$(grep '^version:' pubspec.yaml | head -1 | awk '{print $2}') | |
| APP_VERSION="${VLINE%%+*}" | |
| BUILD_NUMBER="$(git rev-list --count HEAD)" | |
| echo "app_version=$APP_VERSION" >> "$GITHUB_OUTPUT" | |
| echo "build_number=$BUILD_NUMBER" >> "$GITHUB_OUTPUT" | |
| - name: Flutter pub get | |
| run: flutter pub get | |
| - name: Run build_runner | |
| run: dart run build_runner build --delete-conflicting-outputs | |
| - name: Configure Gradle performance flags | |
| run: | | |
| sed -i '/^org\.gradle\.configuration-cache/d' android/gradle.properties || true | |
| cat >> android/gradle.properties <<'EOF' | |
| org.gradle.caching=true | |
| org.gradle.parallel=true | |
| org.gradle.daemon=true | |
| org.gradle.configuration-cache=false | |
| EOF | |
| - name: Make gradlew executable | |
| run: chmod +x android/gradlew | |
| - name: Decode keystore | |
| env: | |
| ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} | |
| run: echo "$ANDROID_KEYSTORE_BASE64" | base64 -d > android/dawarich-upload.jks | |
| - name: Create keystore.properties | |
| run: | | |
| cat > android/keystore.properties <<'EOF' | |
| storePassword=${{ secrets.ANDROID_KEYSTORE_PASSWORD }} | |
| keyPassword=${{ secrets.ANDROID_KEY_PASSWORD }} | |
| keyAlias=${{ secrets.ANDROID_KEY_ALIAS }} | |
| storeFile=../dawarich-upload.jks | |
| EOF | |
| - name: Build GMS AAB (release) | |
| run: | | |
| flutter build appbundle --release --flavor gms \ | |
| --build-name=${{ steps.ver.outputs.app_version }} \ | |
| --build-number=${{ steps.ver.outputs.build_number }} | |
| - name: Upload GMS artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: gms-aab | |
| path: build/app/outputs/bundle/gmsRelease/*.aab | |
| retention-days: 30 | |
| # ── FOSS build (parallel to GMS, only when deploying) ── | |
| build-foss: | |
| needs: gate | |
| if: needs.gate.outputs.should_deploy == 'true' | |
| runs-on: ubuntu-latest | |
| env: | |
| JAVA_VERSION: "21" | |
| outputs: | |
| app_version: ${{ steps.ver.outputs.app_version }} | |
| build_number: ${{ steps.ver.outputs.build_number }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: { fetch-depth: 0 } | |
| - name: Setup Flutter (from .flutter-version) | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version-file: .flutter-version | |
| channel: stable | |
| cache: true | |
| - name: Setup Java | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: ${{ env.JAVA_VERSION }} | |
| - name: Setup Gradle | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Gradle wrapper validation | |
| uses: gradle/actions/wrapper-validation@v3 | |
| - name: Write android/local.properties | |
| shell: bash | |
| run: | | |
| set -e | |
| SDK_DIR="${ANDROID_SDK_ROOT:-$ANDROID_HOME}" | |
| FLUTTER_SDK="${FLUTTER_HOME:-$(dirname "$(dirname "$(readlink -f "$(which flutter)")")")}" | |
| { | |
| echo "sdk.dir=${SDK_DIR}" | |
| echo "flutter.sdk=${FLUTTER_SDK}" | |
| } > android/local.properties | |
| - name: Use preinstalled NDK | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| SDK_DIR="${ANDROID_SDK_ROOT:-$ANDROID_HOME}" | |
| NDK_DIR="${ANDROID_NDK_ROOT:-${ANDROID_NDK_HOME:-${ANDROID_NDK:-${ANDROID_NDK_LATEST_HOME:-}}}}" | |
| if [ -z "${NDK_DIR}" ]; then | |
| NDK_DIR=$(ls -d "${SDK_DIR}/ndk/"* 2>/dev/null | sort -V | tail -1 || true) | |
| fi | |
| [ -n "${NDK_DIR}" ] && [ -d "${NDK_DIR}" ] || { echo "::error::No preinstalled NDK found"; exit 1; } | |
| NDK_VER="$(basename "$NDK_DIR")" | |
| GP=android/gradle.properties | |
| touch "${GP}" | |
| if grep -q '^android\.ndkVersion=' "${GP}"; then | |
| sed -i "s/^android\.ndkVersion=.*/android.ndkVersion=${NDK_VER}/" "${GP}" | |
| else | |
| printf '\nandroid.ndkVersion=%s\n' "${NDK_VER}" >> "${GP}" | |
| fi | |
| - name: Read pubspec version | |
| id: ver | |
| shell: bash | |
| run: | | |
| VLINE=$(grep '^version:' pubspec.yaml | head -1 | awk '{print $2}') | |
| APP_VERSION="${VLINE%%+*}" | |
| BUILD_NUMBER="$(git rev-list --count HEAD)" | |
| echo "app_version=$APP_VERSION" >> "$GITHUB_OUTPUT" | |
| echo "build_number=$BUILD_NUMBER" >> "$GITHUB_OUTPUT" | |
| - name: Switch pubspec to FOSS | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| cp pubspec-foss.yaml pubspec.yaml | |
| cp pubspec-foss.lock pubspec.lock | |
| - name: Flutter pub get | |
| run: flutter pub get | |
| - name: Run build_runner | |
| run: dart run build_runner build --delete-conflicting-outputs | |
| - name: Configure Gradle performance flags | |
| run: | | |
| sed -i '/^org\.gradle\.configuration-cache/d' android/gradle.properties || true | |
| cat >> android/gradle.properties <<'EOF' | |
| org.gradle.caching=true | |
| org.gradle.parallel=true | |
| org.gradle.daemon=true | |
| org.gradle.configuration-cache=false | |
| EOF | |
| - name: Make gradlew executable | |
| run: chmod +x android/gradlew | |
| - name: FOSS proprietary dependency check | |
| shell: bash | |
| run: | | |
| chmod +x tools/check_proprietary_deps.sh | |
| tools/check_proprietary_deps.sh fossReleaseRuntimeClasspath | |
| - name: Decode keystore | |
| env: | |
| ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} | |
| run: echo "$ANDROID_KEYSTORE_BASE64" | base64 -d > android/dawarich-upload.jks | |
| - name: Create keystore.properties | |
| run: | | |
| cat > android/keystore.properties <<'EOF' | |
| storePassword=${{ secrets.ANDROID_KEYSTORE_PASSWORD }} | |
| keyPassword=${{ secrets.ANDROID_KEY_PASSWORD }} | |
| keyAlias=${{ secrets.ANDROID_KEY_ALIAS }} | |
| storeFile=../dawarich-upload.jks | |
| EOF | |
| - name: Build FOSS APK (release) | |
| run: | | |
| flutter build apk --release --flavor foss \ | |
| --build-name=${{ steps.ver.outputs.app_version }} \ | |
| --build-number=${{ steps.ver.outputs.build_number }} | |
| - name: Upload FOSS artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: foss-apk | |
| path: build/app/outputs/flutter-apk/app-foss-release.apk | |
| retention-days: 30 | |
| # ── Upload to open beta only when 'release:' is in the PR title or commit message ── | |
| upload-beta: | |
| needs: [gate, build-gms, build-foss] | |
| if: needs.gate.outputs.should_deploy == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download GMS artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: gms-aab | |
| path: dist | |
| - name: Ensure whatsnew directory exists | |
| run: mkdir -p distribution/whatsnew | |
| - name: Upload to Play open beta (GMS) | |
| uses: r0adkll/upload-google-play@v1 | |
| with: | |
| serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }} | |
| packageName: ${{ secrets.PACKAGE_NAME_GMS }} | |
| releaseName: ${{ needs.build-gms.outputs.app_version }}+${{ needs.build-gms.outputs.build_number }} | |
| releaseFiles: dist/*.aab | |
| whatsNewDirectory: distribution/whatsnew | |
| track: beta | |
| status: completed |