Skip to content

Commit c4ca996

Browse files
committed
chore: draft
1 parent 17ccd7e commit c4ca996

File tree

7 files changed

+286
-4
lines changed

7 files changed

+286
-4
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
name: 'Fingerprint Build Check'
2+
description: 'Check fingerprint and decide between full build, repack, or skip (Android only for now)'
3+
inputs:
4+
platform:
5+
description: 'Platform to check (currently android only)'
6+
required: true
7+
build_action:
8+
description: 'Build action from needs workflow (full, check_fingerprint, skip)'
9+
required: true
10+
default: 'full'
11+
apk_path:
12+
description: 'Path to the APK/APP file to check for reuse'
13+
required: false
14+
default: ''
15+
pr_number:
16+
description: 'Pull request number for caching'
17+
required: false
18+
default: ''
19+
20+
outputs:
21+
build_method:
22+
description: 'Determined build method: full, repack, or skip'
23+
value: ${{ steps.decide.outputs.build_method }}
24+
can_repack:
25+
description: 'Whether repackaging is possible'
26+
value: ${{ steps.decide.outputs.can_repack }}
27+
28+
runs:
29+
using: 'composite'
30+
steps:
31+
- name: Restore fingerprint cache
32+
uses: actions/cache@v4
33+
with:
34+
path: .app-native-fingerprint
35+
key: fingerprint-${{ inputs.platform }}-${{ inputs.pr_number || 'main' }}-${{ github.sha }}
36+
restore-keys: |
37+
fingerprint-${{ inputs.platform }}-${{ inputs.pr_number || 'main' }}-
38+
39+
- name: Restore previous build artifacts
40+
if: ${{ inputs.build_action == 'check_fingerprint' && inputs.apk_path != '' }}
41+
uses: actions/cache@v4
42+
with:
43+
path: ${{ inputs.apk_path }}
44+
key: ${{ inputs.platform }}-artifacts-${{ inputs.pr_number || 'main' }}-${{ hashFiles('.app-native-fingerprint') }}
45+
restore-keys: |
46+
${{ inputs.platform }}-artifacts-${{ inputs.pr_number || 'main' }}-
47+
48+
- name: Check fingerprint and decide build method
49+
id: decide
50+
shell: bash
51+
run: |
52+
echo "🔍 Fingerprint Build Check for ${{ inputs.platform }}"
53+
echo "Input build action: ${{ inputs.build_action }}"
54+
55+
if [[ "${{ inputs.build_action }}" == "skip" ]]; then
56+
echo "⏭️ Build action is skip"
57+
echo "build_method=skip" >> "$GITHUB_OUTPUT"
58+
echo "can_repack=false" >> "$GITHUB_OUTPUT"
59+
exit 0
60+
fi
61+
62+
if [[ "${{ inputs.build_action }}" == "full" ]]; then
63+
echo "🏗️ Build action is full - native code likely changed"
64+
echo "build_method=full" >> "$GITHUB_OUTPUT"
65+
echo "can_repack=false" >> "$GITHUB_OUTPUT"
66+
exit 0
67+
fi
68+
69+
if [[ "${{ inputs.build_action }}" == "check_fingerprint" ]]; then
70+
echo "🔍 Checking fingerprint for potential reuse..."
71+
72+
# Check if fingerprint matches
73+
if yarn fingerprint:check; then
74+
echo "✅ Fingerprint matches! Checking for existing artifacts..."
75+
76+
# Check if we have cached artifacts
77+
if [[ "${{ inputs.apk_path }}" != "" && -f "${{ inputs.apk_path }}" ]]; then
78+
echo "📦 Found existing artifacts - can repack"
79+
echo "build_method=repack" >> "$GITHUB_OUTPUT"
80+
echo "can_repack=true" >> "$GITHUB_OUTPUT"
81+
else
82+
echo "🔍 No existing artifacts found - need full build"
83+
echo "build_method=full" >> "$GITHUB_OUTPUT"
84+
echo "can_repack=false" >> "$GITHUB_OUTPUT"
85+
fi
86+
else
87+
echo "🔄 Fingerprint differs - need full build"
88+
echo "build_method=full" >> "$GITHUB_OUTPUT"
89+
echo "can_repack=false" >> "$GITHUB_OUTPUT"
90+
fi
91+
else
92+
echo "❓ Unknown build action: ${{ inputs.build_action }}"
93+
echo "build_method=full" >> "$GITHUB_OUTPUT"
94+
echo "can_repack=false" >> "$GITHUB_OUTPUT"
95+
fi
96+
97+
echo "Decision: $(cat $GITHUB_OUTPUT | grep build_method | cut -d= -f2)"
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: 'Save Build Fingerprint'
2+
description: 'Save fingerprint and cache build artifacts after successful build (Android only for now)'
3+
inputs:
4+
platform:
5+
description: 'Platform (currently android only)'
6+
required: true
7+
artifacts_path:
8+
description: 'Path to artifacts to cache'
9+
required: true
10+
pr_number:
11+
description: 'Pull request number for caching'
12+
required: false
13+
default: ''
14+
15+
runs:
16+
using: 'composite'
17+
steps:
18+
- name: Generate and save fingerprint
19+
shell: bash
20+
run: |
21+
echo "💾 Generating fingerprint for ${{ inputs.platform }}..."
22+
yarn fingerprint:generate
23+
echo "✅ Fingerprint saved to .app-native-fingerprint"
24+
25+
- name: Cache build artifacts for future reuse
26+
uses: actions/cache@v4
27+
with:
28+
path: ${{ inputs.artifacts_path }}
29+
key: ${{ inputs.platform }}-artifacts-${{ inputs.pr_number || 'main' }}-${{ hashFiles('.app-native-fingerprint') }}
30+
31+
- name: Save fingerprint cache
32+
uses: actions/cache@v4
33+
with:
34+
path: .app-native-fingerprint
35+
key: fingerprint-${{ inputs.platform }}-${{ inputs.pr_number || 'main' }}-${{ github.sha }}

.github/workflows/build-android-e2e.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ name: Build Android E2E APKs
55

66
on:
77
workflow_call:
8+
inputs:
9+
build_action:
10+
description: 'Build action: full, repack, or check_fingerprint'
11+
required: false
12+
type: string
13+
default: 'full'
814
outputs:
915
apk-uploaded:
1016
description: 'Whether the APK was successfully uploaded'
@@ -15,6 +21,9 @@ on:
1521
sourcemap-uploaded:
1622
description: 'Whether the sourcemap was successfully uploaded'
1723
value: ${{ jobs.build-android-apks.outputs.sourcemap-uploaded }}
24+
build-method:
25+
description: 'The build method used: full, repack, or skipped'
26+
value: ${{ jobs.build-android-apks.outputs.build-method }}
1827

1928
jobs:
2029
build-android-apks:
@@ -26,6 +35,7 @@ jobs:
2635
apk-uploaded: ${{ steps.upload-apk.outcome == 'success' }}
2736
aab-uploaded: ${{ steps.upload-aab.outcome == 'success' }}
2837
sourcemap-uploaded: ${{ steps.upload-sourcemap.outcome == 'success' }}
38+
build-method: ${{ steps.build-decision.outputs.build_method }}
2939

3040
steps:
3141
- name: Checkout repo
@@ -50,7 +60,23 @@ jobs:
5060
restore-keys: |
5161
gradle-${{ runner.os }}-
5262
63+
- name: Fingerprint build check
64+
id: build-decision
65+
uses: ./.github/actions/fingerprint-build-check
66+
with:
67+
platform: android
68+
build_action: ${{ inputs.build_action }}
69+
apk_path: android/app/build/outputs/apk/prod/release/app-prod-release.apk
70+
pr_number: ${{ github.event.pull_request.number }}
71+
72+
- name: Clean Native Build Directory (expo prebuild)
73+
if: ${{ steps.build-decision.outputs.build_method == 'full' }}
74+
run: |
75+
echo "Cleaning native build directory..."
76+
yarn expo prebuild --clean --platform android
77+
5378
- name: Build Android E2E APKs
79+
if: ${{ steps.build-decision.outputs.build_method == 'full' }}
5480
run: |
5581
echo "🚀 Setting up project..."
5682
yarn setup:github-ci --no-build-ios
@@ -96,6 +122,39 @@ jobs:
96122
GOOGLE_SERVICES_B64_ANDROID: ${{ secrets.GOOGLE_SERVICES_B64_ANDROID }}
97123
MM_INFURA_PROJECT_ID: ${{ secrets.MM_INFURA_PROJECT_ID }}
98124

125+
- name: Update JS and Assets (expo export)
126+
if: ${{ steps.build-decision.outputs.build_method == 'repack' }}
127+
run: |
128+
echo "🔧 Updating JS and assets with expo export..."
129+
yarn setup:github-ci --no-build-ios --no-build-android
130+
yarn expo export --platform android
131+
echo "✅ JS and assets exported!"
132+
133+
- name: Repackage App Binary using @expo/repack-app
134+
if: ${{ steps.build-decision.outputs.build_method == 'repack' }}
135+
run: |
136+
echo "📦 Repackaging Android APK with updated JavaScript bundle..."
137+
138+
# Repackage the APK with the exported bundle
139+
echo "📱 Repackaging APK..."
140+
npx @expo/repack-app \
141+
--input android/app/build/outputs/apk/prod/release/app-prod-release.apk \
142+
--output android/app/build/outputs/apk/prod/release/app-prod-release.apk \
143+
--bundle dist/_expo/static/js/android/index.js
144+
145+
echo "✅ Repackaging complete!"
146+
147+
- name: Save fingerprint and cache artifacts
148+
if: ${{ steps.build-decision.outputs.build_method == 'full' }}
149+
uses: ./.github/actions/save-build-fingerprint
150+
with:
151+
platform: android
152+
artifacts_path: |
153+
android/app/build/outputs/apk/prod/release/app-prod-release.apk
154+
android/app/build/outputs/apk/androidTest/prod/release/app-prod-release-androidTest.apk
155+
android/app/build/outputs/bundle/prodRelease/app-prod-release.aab
156+
sourcemaps/android/index.android.bundle.map
157+
pr_number: ${{ github.event.pull_request.number }}
99158

100159
- name: Upload Android APK
101160
id: upload-apk

.github/workflows/ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ jobs:
177177
id-token: write
178178
needs: [needs_e2e_build]
179179
uses: ./.github/workflows/build-android-e2e.yml
180+
with:
181+
build_action: ${{ needs.needs_e2e_build.outputs.android_build_action }}
180182
secrets: inherit
181183

182184
e2e-smoke-tests-android:

.github/workflows/needs-e2e-build.yml

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ on:
1919
builds:
2020
description: 'Whether any builds will happen'
2121
value: ${{ jobs.needs-e2e-build.outputs.builds }}
22+
android_build_action:
23+
description: 'Android build action: full, repack, or skip'
24+
value: ${{ jobs.needs-e2e-build.outputs.android_build_action }}
25+
ios_build_action:
26+
description: 'iOS build action: full, repack, or skip'
27+
value: ${{ jobs.needs-e2e-build.outputs.ios_build_action }}
2228

2329
jobs:
2430
needs-e2e-build:
@@ -28,6 +34,8 @@ jobs:
2834
android: ${{ steps.set-outputs.outputs.android_final }}
2935
ios: ${{ steps.set-outputs.outputs.ios_final }}
3036
builds: ${{ steps.set-outputs.outputs.builds }}
37+
android_build_action: ${{ steps.set-outputs.outputs.android_build_action }}
38+
ios_build_action: ${{ steps.set-outputs.outputs.ios_build_action }}
3139
env:
3240
# For a `pull_request` event, the head commit hash is `github.event.pull_request.head.sha`.
3341
# For a `push` event, the head commit hash is `github.sha`.
@@ -111,6 +119,7 @@ jobs:
111119
- '**/*' # Matches everything for conservative fallback
112120
list-files: 'shell' # Output lists for comparison
113121

122+
114123
- name: Set final outputs
115124
id: set-outputs
116125
run: |
@@ -121,6 +130,8 @@ jobs:
121130
echo "android_final=false"
122131
echo "ios_final=false"
123132
echo "builds=false"
133+
echo "android_build_action=skip"
134+
echo "ios_build_action=skip"
124135
} >> "${GITHUB_OUTPUT}"
125136
echo "-> Skipping build+E2E tests due to 'skip-e2e' tag"
126137
exit 0
@@ -136,6 +147,7 @@ jobs:
136147
ignore_files="${{ steps.filter.outputs.ignore_files }}"
137148
catch_all_files="${{ steps.filter.outputs.catch_all_files }}"
138149
150+
139151
# Use Cases for State Machine:
140152
# 1. Purely ignored changes -> Skip both
141153
# 2. Shared changes -> Build both
@@ -144,7 +156,7 @@ jobs:
144156
# 5. Android-only changes -> Android only
145157
# 6. iOS-only changes -> iOS only
146158
147-
# State Machine
159+
# State Machine for determining which platforms need attention
148160
if [[ "$android" == 'true' && "$ios" != 'true' ]]; then
149161
state="ANDROID_ONLY"
150162
elif [[ "$ios" == 'true' && "$android" != 'true' ]]; then
@@ -155,31 +167,46 @@ jobs:
155167
state="SHARED"
156168
fi
157169
170+
# Determine build actions based on path changes + fingerprint
158171
case "$state" in
159172
"PURE_IGNORE")
160173
echo "Ignoring - no mobile code changes"
161174
android_final="false"
162175
ios_final="false"
176+
android_build_action="skip"
177+
ios_build_action="skip"
163178
;;
164179
"SHARED")
165-
echo "Building both platforms"
180+
echo "Both platforms affected by changes"
166181
android_final="true"
167182
ios_final="true"
183+
# Fingerprint check will happen in Android build workflow
184+
android_build_action="check_fingerprint"
185+
# iOS not using fingerprint optimization yet
186+
ios_build_action="full"
168187
;;
169188
"ANDROID_ONLY")
170-
echo "Building Android only"
189+
echo "Android-only changes"
171190
android_final="true"
172191
ios_final="false"
192+
ios_build_action="skip"
193+
# For platform-specific changes, always do full build (native code likely changed)
194+
android_build_action="full"
173195
;;
174196
"IOS_ONLY")
175-
echo "Building iOS only"
197+
echo "iOS-only changes"
176198
android_final="false"
177199
ios_final="true"
200+
android_build_action="skip"
201+
# iOS not using fingerprint optimization yet
202+
ios_build_action="full"
178203
;;
179204
esac
180205
181206
echo "android_final=$android_final" >> "${GITHUB_OUTPUT}"
182207
echo "ios_final=$ios_final" >> "${GITHUB_OUTPUT}"
208+
echo "android_build_action=$android_build_action" >> "${GITHUB_OUTPUT}"
209+
echo "ios_build_action=$ios_build_action" >> "${GITHUB_OUTPUT}"
183210
184211
# Check if any builds will happen
185212
if [[ "$android_final" == 'true' || "$ios_final" == 'true' ]]; then
@@ -188,3 +215,7 @@ jobs:
188215
builds="false"
189216
fi
190217
echo "builds=$builds" >> "${GITHUB_OUTPUT}"
218+
219+
echo "Build decisions:"
220+
echo " Android: $android_build_action (build=$android_final)"
221+
echo " iOS: $ios_build_action (build=$ios_final)"

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
"build:android:main:test": "./scripts/build.sh android main test",
4848
"build:android:main:e2e": "./scripts/build.sh android main e2e",
4949
"build:android:flask:prod": "./scripts/build.sh android flask production",
50+
"fingerprint:generate": "expo-fingerprint prebuild > .app-native-fingerprint",
51+
"fingerprint:check": "node scripts/check-fingerprint.js",
5052
"build:android:flask:local": "./scripts/build.sh android flask local",
5153
"build:android:flask:test": "./scripts/build.sh android flask test",
5254
"build:android:flask:e2e": "./scripts/build.sh android flask e2e",
@@ -498,7 +500,9 @@
498500
"devDependencies": {
499501
"@babel/core": "^7.25.2",
500502
"@babel/eslint-parser": "^7.25.1",
503+
"@expo/repack-app": "^1.0.0",
501504
"@babel/preset-env": "^7.25.3",
505+
"expo-fingerprint": "^1.0.0",
502506
"@babel/register": "^7.24.6",
503507
"@babel/runtime": "^7.25.0",
504508
"@cucumber/message-streams": "^4.0.1",

0 commit comments

Comments
 (0)