Skip to content

Commit cf4e13e

Browse files
authored
Merge pull request #88 from v2er-app/feature/google-play-deployment
feat: add Google Play Store automated deployment pipeline
2 parents 41070a1 + b34e685 commit cf4e13e

File tree

8 files changed

+750
-23
lines changed

8 files changed

+750
-23
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
name: Fastlane Deploy
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
track:
7+
description: 'Deployment track'
8+
required: true
9+
type: choice
10+
default: 'internal'
11+
options:
12+
- internal
13+
- alpha
14+
- beta
15+
- production
16+
release_status:
17+
description: 'Release status'
18+
required: false
19+
type: choice
20+
default: 'draft'
21+
options:
22+
- draft
23+
- completed
24+
25+
jobs:
26+
deploy:
27+
name: Deploy with Fastlane
28+
runs-on: ubuntu-latest
29+
30+
steps:
31+
- name: Checkout code
32+
uses: actions/checkout@v4
33+
34+
- name: Set up JDK 17
35+
uses: actions/setup-java@v4
36+
with:
37+
java-version: '17'
38+
distribution: 'temurin'
39+
cache: gradle
40+
41+
- name: Setup Ruby
42+
uses: ruby/setup-ruby@v1
43+
with:
44+
ruby-version: '3.2'
45+
bundler-cache: true
46+
47+
- name: Grant execute permission for gradlew
48+
run: chmod +x gradlew
49+
50+
- name: Decode Keystore
51+
env:
52+
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
53+
run: |
54+
echo "$KEYSTORE_BASE64" | base64 --decode > ${{ github.workspace }}/keystore.jks
55+
echo "KEYSTORE_PATH=${{ github.workspace }}/keystore.jks" >> $GITHUB_ENV
56+
57+
- name: Setup Play Store credentials
58+
env:
59+
PLAY_STORE_SERVICE_ACCOUNT_JSON: ${{ secrets.PLAY_STORE_SERVICE_ACCOUNT_JSON }}
60+
run: |
61+
echo "$PLAY_STORE_SERVICE_ACCOUNT_JSON" > ${{ github.workspace }}/fastlane/play-store-key.json
62+
echo "PLAY_STORE_JSON_KEY_PATH=${{ github.workspace }}/fastlane/play-store-key.json" >> $GITHUB_ENV
63+
64+
- name: Install Fastlane
65+
run: |
66+
bundle install
67+
bundle exec fastlane --version
68+
69+
- name: Deploy to Play Store
70+
env:
71+
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
72+
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
73+
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
74+
SUPPLY_RELEASE_STATUS: ${{ github.event.inputs.release_status }}
75+
run: |
76+
case "${{ github.event.inputs.track }}" in
77+
internal)
78+
bundle exec fastlane android deploy_internal
79+
;;
80+
alpha)
81+
bundle exec fastlane android deploy_alpha
82+
;;
83+
beta)
84+
bundle exec fastlane android deploy_beta
85+
;;
86+
production)
87+
bundle exec fastlane android deploy_production
88+
;;
89+
esac
90+
91+
- name: Clean up sensitive files
92+
if: always()
93+
run: |
94+
rm -f ${{ github.workspace }}/keystore.jks
95+
rm -f ${{ github.workspace }}/fastlane/play-store-key.json
96+
97+
- name: Deployment Summary
98+
if: success()
99+
run: |
100+
echo "## Fastlane Deployment Complete :rocket:" >> $GITHUB_STEP_SUMMARY
101+
echo "" >> $GITHUB_STEP_SUMMARY
102+
echo "- **Track**: ${{ github.event.inputs.track }}" >> $GITHUB_STEP_SUMMARY
103+
echo "- **Status**: ${{ github.event.inputs.release_status }}" >> $GITHUB_STEP_SUMMARY
104+
echo "- **Package**: me.ghui.v2er" >> $GITHUB_STEP_SUMMARY
105+
echo "" >> $GITHUB_STEP_SUMMARY
106+
echo "[View in Play Console](https://play.google.com/console)" >> $GITHUB_STEP_SUMMARY

.github/workflows/release.yml

Lines changed: 118 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,24 @@ on:
1010
description: 'Version to release (e.g., v1.0.0)'
1111
required: true
1212
type: string
13+
track:
14+
description: 'Play Store release track'
15+
required: false
16+
type: choice
17+
default: 'internal'
18+
options:
19+
- internal
20+
- alpha
21+
- beta
22+
- production
23+
status:
24+
description: 'Play Store release status'
25+
required: false
26+
type: choice
27+
default: 'draft'
28+
options:
29+
- draft
30+
- completed
1331

1432
permissions:
1533
contents: write
@@ -67,19 +85,18 @@ jobs:
6785
echo "Key alias configured: ${{ secrets.KEY_ALIAS != '' && 'Yes' || 'No' }}"
6886
6987
- name: Build release APK
70-
env:
71-
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
72-
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
73-
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
74-
KEYSTORE_PATH: ${{ vars.ENABLE_SIGNING == 'true' && 'keystore.jks' || '' }}
7588
run: |
7689
if [ "${{ vars.ENABLE_SIGNING }}" = "true" ] && [ -f "app/keystore.jks" ]; then
7790
echo "Building signed release APK"
78-
echo "Using key alias: ${KEY_ALIAS:-ghui}"
79-
./gradlew assembleRelease --stacktrace
91+
echo "Using key alias: ${{ secrets.KEY_ALIAS }}"
92+
./gradlew assembleRelease \
93+
-Pandroid.injected.signing.store.file=${{ github.workspace }}/app/keystore.jks \
94+
-Pandroid.injected.signing.store.password=${{ secrets.KEYSTORE_PASSWORD }} \
95+
-Pandroid.injected.signing.key.alias=${{ secrets.KEY_ALIAS }} \
96+
-Pandroid.injected.signing.key.password=${{ secrets.KEY_PASSWORD }}
8097
else
8198
echo "Building unsigned release APK"
82-
./gradlew assembleRelease --stacktrace || ./gradlew assembleDebug --stacktrace
99+
./gradlew assembleRelease --stacktrace
83100
fi
84101
85102
- name: Clean up keystore
@@ -136,19 +153,26 @@ jobs:
136153
echo "$KEYSTORE_BASE64" | base64 --decode > app/keystore.jks
137154
138155
- name: Build release bundle
139-
env:
140-
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
141-
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
142-
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
143-
KEYSTORE_PATH: ${{ vars.ENABLE_SIGNING == 'true' && 'keystore.jks' || '' }}
144156
run: |
145157
if [ "${{ vars.ENABLE_SIGNING }}" = "true" ] && [ -f "app/keystore.jks" ]; then
146158
echo "Building signed release bundle"
147-
./gradlew bundleRelease --stacktrace
159+
./gradlew bundleRelease \
160+
-Pandroid.injected.signing.store.file=${{ github.workspace }}/app/keystore.jks \
161+
-Pandroid.injected.signing.store.password=${{ secrets.KEYSTORE_PASSWORD }} \
162+
-Pandroid.injected.signing.key.alias=${{ secrets.KEY_ALIAS }} \
163+
-Pandroid.injected.signing.key.password=${{ secrets.KEY_PASSWORD }}
148164
else
149165
echo "Skipping bundle build - signing not configured"
150166
fi
151167
168+
- name: Generate debug symbols
169+
if: ${{ vars.ENABLE_SIGNING == 'true' }}
170+
run: |
171+
echo "Checking for debug symbols..."
172+
find app/build/outputs -name "*.zip" -type f | grep -i debug || echo "No debug symbol zips found"
173+
find app/build/outputs -name "*symbols*" -type f || echo "No symbol files found"
174+
ls -la app/build/outputs/bundle/release/ || true
175+
152176
- name: Clean up keystore
153177
if: always()
154178
run: |
@@ -242,24 +266,96 @@ jobs:
242266
runs-on: ubuntu-latest
243267

244268
steps:
269+
- name: Checkout code
270+
uses: actions/checkout@v4
271+
245272
- name: Download AAB artifact
246273
uses: actions/download-artifact@v4
247274
with:
248275
name: release-bundle
249276
path: release-artifacts/
250277

251-
- name: Find AAB file
252-
id: find-aab
278+
- name: Find bundle and symbols
279+
id: find-files
253280
run: |
254281
AAB_PATH=$(find release-artifacts -name "*.aab" | head -1)
255282
echo "aab_path=$AAB_PATH" >> $GITHUB_OUTPUT
256283
257-
- name: Upload to Play Store
284+
# Look for debug symbols
285+
SYMBOLS_PATH=$(find release-artifacts -name "native-debug-symbols.zip" 2>/dev/null | head -1)
286+
if [ -n "$SYMBOLS_PATH" ]; then
287+
echo "symbols_path=$SYMBOLS_PATH" >> $GITHUB_OUTPUT
288+
echo "Found debug symbols at: $SYMBOLS_PATH"
289+
else
290+
echo "No debug symbols found"
291+
fi
292+
293+
- name: Determine release track and status
294+
id: release-config
295+
run: |
296+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
297+
TRACK="${{ github.event.inputs.track }}"
298+
STATUS="${{ github.event.inputs.status }}"
299+
else
300+
# Default for tag pushes
301+
TRACK="internal"
302+
STATUS="draft"
303+
fi
304+
echo "track=$TRACK" >> $GITHUB_OUTPUT
305+
echo "status=$STATUS" >> $GITHUB_OUTPUT
306+
echo "Deploying to track: $TRACK with status: $STATUS"
307+
308+
- name: Create whatsnew directory
309+
run: |
310+
mkdir -p whatsnew
311+
312+
# Generate release notes
313+
echo "Release ${{ needs.prepare.outputs.version }}" > whatsnew/whatsnew-en-US
314+
echo "" >> whatsnew/whatsnew-en-US
315+
316+
# Get recent commits
317+
git log --pretty=format:"• %s" -5 >> whatsnew/whatsnew-en-US
318+
319+
# Chinese version
320+
echo "版本 ${{ needs.prepare.outputs.version }}" > whatsnew/whatsnew-zh-CN
321+
echo "" >> whatsnew/whatsnew-zh-CN
322+
git log --pretty=format:"• %s" -5 >> whatsnew/whatsnew-zh-CN
323+
324+
- name: Upload to Play Store (with debug symbols)
325+
if: steps.find-files.outputs.symbols_path != ''
326+
uses: r0adkll/upload-google-play@v1
327+
with:
328+
serviceAccountJsonPlainText: ${{ secrets.PLAY_STORE_SERVICE_ACCOUNT_JSON }}
329+
packageName: me.ghui.v2er
330+
releaseFiles: ${{ steps.find-files.outputs.aab_path }}
331+
track: ${{ steps.release-config.outputs.track }}
332+
status: ${{ steps.release-config.outputs.status }}
333+
debugSymbols: ${{ steps.find-files.outputs.symbols_path }}
334+
whatsNewDirectory: whatsnew/
335+
changesNotSentForReview: true
336+
continue-on-error: true
337+
id: upload-with-symbols
338+
339+
- name: Upload to Play Store (without debug symbols)
340+
if: steps.find-files.outputs.symbols_path == '' || steps.upload-with-symbols.outcome == 'failure'
258341
uses: r0adkll/upload-google-play@v1
259342
with:
260-
serviceAccountJsonPlainText: ${{ secrets.SERVICE_ACCOUNT_JSON }}
343+
serviceAccountJsonPlainText: ${{ secrets.PLAY_STORE_SERVICE_ACCOUNT_JSON }}
261344
packageName: me.ghui.v2er
262-
releaseFiles: ${{ steps.find-aab.outputs.aab_path }}
263-
track: internal
264-
status: completed
265-
whatsNewDirectory: whatsnew/
345+
releaseFiles: ${{ steps.find-files.outputs.aab_path }}
346+
track: ${{ steps.release-config.outputs.track }}
347+
status: ${{ steps.release-config.outputs.status }}
348+
whatsNewDirectory: whatsnew/
349+
changesNotSentForReview: true
350+
351+
- name: Play Store Upload Summary
352+
if: success()
353+
run: |
354+
echo "## Play Store Upload Complete :rocket:" >> $GITHUB_STEP_SUMMARY
355+
echo "" >> $GITHUB_STEP_SUMMARY
356+
echo "- **Version**: ${{ needs.prepare.outputs.version }}" >> $GITHUB_STEP_SUMMARY
357+
echo "- **Track**: ${{ steps.release-config.outputs.track }}" >> $GITHUB_STEP_SUMMARY
358+
echo "- **Status**: ${{ steps.release-config.outputs.status }}" >> $GITHUB_STEP_SUMMARY
359+
echo "- **Package**: me.ghui.v2er" >> $GITHUB_STEP_SUMMARY
360+
echo "" >> $GITHUB_STEP_SUMMARY
361+
echo "[View in Play Console](https://play.google.com/console/u/0/app/me.ghui.v2er)" >> $GITHUB_STEP_SUMMARY

.gitignore

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,18 @@
1111
*.keystore
1212
*.base64.txt
1313
keystore.jks
14-
app/keystore.jks
14+
app/keystore.jks
15+
16+
# Fastlane
17+
fastlane/report.xml
18+
fastlane/Preview.html
19+
fastlane/screenshots
20+
fastlane/test_output
21+
fastlane/readme.md
22+
fastlane/play-store-key.json
23+
fastlane/*.json
24+
25+
# Bundle
26+
vendor/bundle/
27+
.bundle/
28+
Gemfile.lock

.gitignore.fastlane

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Fastlane specific
2+
fastlane/report.xml
3+
fastlane/Preview.html
4+
fastlane/screenshots
5+
fastlane/test_output
6+
fastlane/readme.md
7+
fastlane/play-store-key.json
8+
fastlane/*.json
9+
10+
# Bundle
11+
vendor/bundle/
12+
.bundle/
13+
14+
# Ruby
15+
*.gem
16+
*.rbc
17+
/.config
18+
/coverage/
19+
/InstalledFiles
20+
/pkg/
21+
/spec/reports/
22+
/spec/examples.txt
23+
/test/tmp/
24+
/test/version_tmp/
25+
/tmp/
26+
Gemfile.lock

Gemfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
source "https://rubygems.org"
2+
3+
gem "fastlane"
4+
gem "fastlane-plugin-firebase_app_distribution", "~> 0.7.0" # Optional: for Firebase distribution

0 commit comments

Comments
 (0)