mirror of
https://github.com/tiennm99/loto.git
synced 2026-10-11 03:13:40 +00:00
Fresh Kotlin 2.2 + Jetpack Compose app at feature parity with web/ (game logic, settings contract, voice semantics ported one-to-one with twinned tests; 104 unit + 9 instrumentation tests). Fully offline: VIBRATE is the only permission; Media3's ACCESS_NETWORK_STATE is stripped. Voice clips mount from web/static/audio at build time. Same applicationId, signing env contract, and Play alpha track; versionCode 7 / 0.2.0. CI Android job is Gradle-only (lint, test, debug + R8 release APK) and the release workflow fails fast on an unbumped versionCode. BREAKING CHANGE: WebView localStorage (settings, in-progress round) is not migrated; wrapper users start clean.
117 lines
4.8 KiB
YAML
117 lines
4.8 KiB
YAML
# Tag-driven release. Builds standalone rather than consuming ci.yml
|
|
# artifacts: a tag run has no upstream run to pull from, and a release
|
|
# should be reproducible from the tagged tree alone.
|
|
|
|
name: android / release
|
|
|
|
on:
|
|
push:
|
|
tags: ['v*.*.*']
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
concurrency:
|
|
group: android-release-${{ github.ref }}
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
release:
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
with:
|
|
persist-credentials: false
|
|
# Full history + tags for the versionCode guard below.
|
|
fetch-depth: 0
|
|
|
|
# Play rejects an upload whose versionCode is not higher than the last
|
|
# one, but only after the whole build has run — fail fast instead.
|
|
# Compares this tag's versionCode against the previous v*.*.* tag,
|
|
# reading the wrapper-era path for tags that predate the native app.
|
|
- name: Guard against an unbumped versionCode
|
|
run: |
|
|
set -eu
|
|
current=$(grep -oP 'versionCode = \K\d+' android/app/build.gradle.kts)
|
|
echo "versionCode at ${GITHUB_REF_NAME}: $current"
|
|
prev_tag=$(git tag --list 'v*.*.*' --sort=-v:refname | grep -Fvx "${GITHUB_REF_NAME}" | head -n1 || true)
|
|
if [ -z "$prev_tag" ]; then
|
|
echo "No previous release tag; skipping comparison."
|
|
exit 0
|
|
fi
|
|
prev=$(git show "$prev_tag:android/app/build.gradle.kts" 2>/dev/null | grep -oP 'versionCode = \K\d+' || true)
|
|
if [ -z "$prev" ]; then
|
|
# Wrapper-era layout (Capacitor project under android/android/).
|
|
prev=$(git show "$prev_tag:android/android/app/build.gradle" 2>/dev/null | grep -oP 'versionCode \K\d+' || true)
|
|
fi
|
|
if [ -z "$prev" ]; then
|
|
echo "::warning::Could not read versionCode at $prev_tag; skipping comparison."
|
|
exit 0
|
|
fi
|
|
echo "versionCode at $prev_tag: $prev"
|
|
if [ "$current" -le "$prev" ]; then
|
|
echo "::error::versionCode $current at ${GITHUB_REF_NAME} must be greater than $prev at $prev_tag. Bump it in android/app/build.gradle.kts before tagging."
|
|
exit 1
|
|
fi
|
|
|
|
- uses: ./.github/actions/setup-android
|
|
|
|
# ci.yml does not run on tags, so this is the only gate before signing.
|
|
- name: Lint and test
|
|
run: ./gradlew :app:lint :app:test
|
|
working-directory: android
|
|
|
|
- name: Decode keystore
|
|
env:
|
|
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
|
|
run: printf '%s' "$KEYSTORE_BASE64" | base64 --decode > "$GITHUB_WORKSPACE/keystore.p12"
|
|
|
|
- name: Build signed AAB + APK
|
|
working-directory: android
|
|
env:
|
|
LOTO_KEYSTORE_PATH: ${{ github.workspace }}/keystore.p12
|
|
LOTO_KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
|
|
LOTO_KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
|
|
LOTO_KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
|
|
run: ./gradlew :app:bundleRelease :app:assembleRelease
|
|
|
|
- name: Upload to GitHub Release
|
|
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
|
|
with:
|
|
files: |
|
|
android/app/build/outputs/apk/release/*.apk
|
|
android/app/build/outputs/bundle/release/*.aab
|
|
|
|
# Auto-publish to Google Play (gated on the service-account secret).
|
|
# Skips silently if PLAY_SERVICE_ACCOUNT_JSON is not configured, so
|
|
# tagging a release before Play setup still produces a GH Release.
|
|
# Uploads to "alpha", the closed-testing track. Internal testing is a
|
|
# separate track and does not count toward the 12-tester requirement
|
|
# for production access, so releases have to land here to reach the
|
|
# testers. An unknown track name fails the step with the list of
|
|
# valid tracks rather than publishing somewhere unintended.
|
|
- name: Check Play Store config
|
|
id: play
|
|
env:
|
|
PLAY_SERVICE_ACCOUNT_JSON: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }}
|
|
run: |
|
|
if [ -n "$PLAY_SERVICE_ACCOUNT_JSON" ]; then
|
|
echo "configured=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "configured=false" >> "$GITHUB_OUTPUT"
|
|
echo "::notice::PLAY_SERVICE_ACCOUNT_JSON not set; skipping Play Store upload."
|
|
fi
|
|
|
|
- name: Upload to Google Play (closed testing track)
|
|
if: steps.play.outputs.configured == 'true'
|
|
uses: r0adkll/upload-google-play@e738b9dd8f2476ea806d921b64aacd24f34515a5 # v1.1.5
|
|
with:
|
|
serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }}
|
|
packageName: com.miti99.loto
|
|
releaseFiles: android/app/build/outputs/bundle/release/*.aab
|
|
tracks: alpha
|
|
status: completed
|
|
# versionCode is bumped manually in android/app/build.gradle.kts
|
|
# before tagging; the guard step above catches a forgotten bump.
|