|
| 1 | +name: Deploy to Google Play |
| 2 | + |
| 3 | +# Bypasses broken Google Play Console UI by using the Developer API directly. |
| 4 | +# Requires a Google Play service account JSON added as repository secret |
| 5 | +# GOOGLE_PLAY_SERVICE_ACCOUNT_JSON (see setup instructions below). |
| 6 | +# |
| 7 | +# Setup: |
| 8 | +# 1. Play Console → Setup → API access → Link Google Cloud project |
| 9 | +# 2. Create service account → Grant "Release Manager" role in Play Console |
| 10 | +# 3. Download JSON key → add as GitHub secret GOOGLE_PLAY_SERVICE_ACCOUNT_JSON |
| 11 | + |
| 12 | +on: |
| 13 | + workflow_dispatch: |
| 14 | + inputs: |
| 15 | + track: |
| 16 | + description: 'Release track' |
| 17 | + required: true |
| 18 | + default: 'internal' |
| 19 | + type: choice |
| 20 | + options: |
| 21 | + - internal |
| 22 | + - alpha |
| 23 | + - beta |
| 24 | + - production |
| 25 | + rollout_percentage: |
| 26 | + description: 'Rollout % for production track (1-100, ignored for other tracks)' |
| 27 | + required: false |
| 28 | + default: '10' |
| 29 | + status: |
| 30 | + description: 'Release status' |
| 31 | + required: true |
| 32 | + default: 'completed' |
| 33 | + type: choice |
| 34 | + options: |
| 35 | + - completed |
| 36 | + - draft |
| 37 | + |
| 38 | +permissions: |
| 39 | + contents: read |
| 40 | + |
| 41 | +jobs: |
| 42 | + deploy: |
| 43 | + name: Build AAB & Deploy (${{ inputs.track }}) |
| 44 | + runs-on: ubuntu-latest |
| 45 | + |
| 46 | + steps: |
| 47 | + - name: Checkout code |
| 48 | + uses: actions/checkout@v4 |
| 49 | + |
| 50 | + - name: Setup Java |
| 51 | + uses: actions/setup-java@v4 |
| 52 | + with: |
| 53 | + distribution: 'temurin' |
| 54 | + java-version: '17' |
| 55 | + |
| 56 | + - name: Setup Gradle |
| 57 | + uses: gradle/actions/setup-gradle@v4 |
| 58 | + |
| 59 | + - name: Extract version info |
| 60 | + id: version |
| 61 | + run: | |
| 62 | + VERSION_NAME=$(grep 'versionName = ' android/app/build.gradle.kts | sed 's/.*versionName = "\(.*\)".*/\1/') |
| 63 | + VERSION_CODE=$(grep 'versionCode = ' android/app/build.gradle.kts | sed 's/.*versionCode = \([0-9]*\).*/\1/') |
| 64 | + echo "VERSION_NAME=$VERSION_NAME" >> $GITHUB_OUTPUT |
| 65 | + echo "VERSION_CODE=$VERSION_CODE" >> $GITHUB_OUTPUT |
| 66 | + echo "Building v$VERSION_NAME (Code: $VERSION_CODE) → track: ${{ inputs.track }}" |
| 67 | +
|
| 68 | + - name: Calculate rollout fraction (production only) |
| 69 | + id: rollout |
| 70 | + run: | |
| 71 | + if [ "${{ inputs.track }}" = "production" ]; then |
| 72 | + FRACTION=$(echo "scale=4; ${{ inputs.rollout_percentage }} / 100" | bc) |
| 73 | + echo "USER_FRACTION=$FRACTION" >> $GITHUB_OUTPUT |
| 74 | + echo "Production rollout: ${{ inputs.rollout_percentage }}% → fraction $FRACTION" |
| 75 | + else |
| 76 | + echo "USER_FRACTION=" >> $GITHUB_OUTPUT |
| 77 | + echo "Non-production track: no rollout fraction" |
| 78 | + fi |
| 79 | +
|
| 80 | + - name: Configure Android signing |
| 81 | + run: | |
| 82 | + echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > android/app/simple-notes-release.jks |
| 83 | + echo "storePassword=${{ secrets.KEYSTORE_PASSWORD }}" > android/key.properties |
| 84 | + echo "keyPassword=${{ secrets.KEY_PASSWORD }}" >> android/key.properties |
| 85 | + echo "keyAlias=${{ secrets.KEY_ALIAS }}" >> android/key.properties |
| 86 | + echo "storeFile=simple-notes-release.jks" >> android/key.properties |
| 87 | +
|
| 88 | + - name: Build release AAB (standard flavor) |
| 89 | + run: | |
| 90 | + cd android |
| 91 | + ./gradlew bundleStandardRelease --no-daemon --stacktrace |
| 92 | +
|
| 93 | + - name: Locate AAB |
| 94 | + id: aab |
| 95 | + run: | |
| 96 | + AAB_PATH=$(find android/app/build/outputs/bundle/standardRelease -name "*.aab" | head -1) |
| 97 | + echo "AAB_PATH=$AAB_PATH" >> $GITHUB_OUTPUT |
| 98 | + echo "Found AAB: $AAB_PATH ($(du -sh "$AAB_PATH" | cut -f1))" |
| 99 | +
|
| 100 | + - name: Upload to Google Play |
| 101 | + uses: r0adkll/upload-google-play@v1 |
| 102 | + with: |
| 103 | + serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON }} |
| 104 | + packageName: dev.dettmer.simplenotes |
| 105 | + releaseFiles: ${{ steps.aab.outputs.AAB_PATH }} |
| 106 | + track: ${{ inputs.track }} |
| 107 | + status: ${{ inputs.status }} |
| 108 | + inAppUpdatePriority: 0 |
| 109 | + userFraction: ${{ steps.rollout.outputs.USER_FRACTION }} |
| 110 | + whatsNewDirectory: fastlane/metadata/android |
| 111 | + mappingFile: android/app/build/outputs/mapping/standardRelease/mapping.txt |
| 112 | + |
| 113 | + - name: Summary |
| 114 | + run: | |
| 115 | + { |
| 116 | + echo "### Deployment successful" |
| 117 | + echo "" |
| 118 | + echo "| | |" |
| 119 | + echo "|---|---|" |
| 120 | + echo "| Package | \`dev.dettmer.simplenotes\` |" |
| 121 | + echo "| Version | ${{ steps.version.outputs.VERSION_NAME }} (Code ${{ steps.version.outputs.VERSION_CODE }}) |" |
| 122 | + echo "| Track | ${{ inputs.track }} |" |
| 123 | + echo "| Status | ${{ inputs.status }} |" |
| 124 | + if [ "${{ inputs.track }}" = "production" ]; then |
| 125 | + echo "| Rollout | ${{ inputs.rollout_percentage }}% |" |
| 126 | + fi |
| 127 | + } >> $GITHUB_STEP_SUMMARY |
0 commit comments