Adjust workflow to allow external contributors to run CI on maintainers approval (#2718)
Omar Hatem committed
Dec 11, 2025 at 02:12 UTC
9b706263a88f61c5cc2614a9a23834cfce3dd53d
2 files changed
+382
-338
.github/workflows/pr_test_build_android.yml
+31
-338
@@ -1,344 +1,37 @@
1
name: Cake Wallet Android
2
3
-on: [pull_request_target]
3
+on:
4
+ # Trigger 1: For Maintainers (Automatic, No Approval)
5
+ pull_request:
6
+ types: [opened, synchronize, reopened]
7
+
8
+ # Trigger 2: For Forks (Manual Approval via Environment)
9
+ pull_request_target:
10
+ types: [opened, synchronize, reopened]
11
5
-defaults:
6
- run:
7
- shell: bash
12
jobs:
9
- PR_test_build:
10
- runs-on: [Linux, amd64, android]
13
+ # PATH A: Internal PRs (Runs immediately)
14
+ internal-build:
15
+ if: |
16
+ github.event_name == 'pull_request' &&
17
+ github.event.pull_request.head.repo.full_name == github.repository
18
+ uses: ./.github/workflows/reusable-build.yml
19
+ with:
20
+ ref: ${{ github.event.pull_request.head.sha }}
21
+ pr_number: ${{ github.head_ref || github.ref_name }}
22
+ secrets: inherit # Passes all secrets automatically
23
+
24
+ # PATH B: External Forks (Waits for Approval)
25
+ external-build:
26
+ if: |
27
+ github.event_name == 'pull_request_target' &&
28
+ github.event.pull_request.head.repo.full_name != github.repository
29
+
30
+ # This applies the specific environment rule ONLY to forks
31
environment: external_contributors
12
- container:
13
- image: ghcr.io/cake-tech/cake_wallet:debian13-flutter3.32.0-ndkr28-go1.24.1-ruststablenightly
14
- env:
15
- STORE_PASS: test@cake_wallet
16
- KEY_PASS: test@cake_wallet
17
- MONEROC_CACHE_DIR_ROOT: /opt/generic_cache
18
- BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
19
- ANDROID_AVD_HOME: /root/.android/avd
20
- volumes:
21
- - /opt/cw_cache_android/root/.cache:/root/.cache
22
- - /opt/cw_cache_android/root/.android/avd/:/root/.android/avd
23
- - /opt/cw_cache_android/root/.ccache:/root/.ccache
24
- - /opt/cw_cache_android/root/.pub-cache/:/root/.pub-cache
25
- - /opt/cw_cache_android/root/.gradle/:/root/.gradle
26
- - /opt/cw_cache_android/root/.android/:/root/.android
27
- - /opt/cw_cache_android/root/go/pkg:/root/go/pkg
28
- - /opt/cw_cache_android/opt/generic_cache:/opt/generic_cache
29
- - /dev/kvm:/dev/kvm
30
- strategy:
31
- matrix:
32
- api-level: [29]
33
-
34
- steps:
35
- - name: Fix github actions messing up $HOME...
36
- run: 'echo HOME=/root | sudo tee -a $GITHUB_ENV'
37
- - uses: actions/checkout@v4
38
- with:
39
- ref: ${{ github.event.pull_request.head.sha }}
40
- - name: configure git
41
- run: |
42
- git config --global --add safe.directory '*'
43
- git config --global user.email "ci@cakewallet.com"
44
- git config --global user.name "CakeWallet CI"
45
- - name: Get the full commit message
46
- run: |
47
- FULL_MESSAGE="$(git log -1 --pretty=%B)"
48
- echo "message<<EOF" >> $GITHUB_ENV
49
- echo "$FULL_MESSAGE" >> $GITHUB_ENV
50
- echo "EOF" >> $GITHUB_ENV
51
-
52
- - name: Add secrets
53
- run: |
54
- touch lib/.secrets.g.dart
55
- touch cw_evm/lib/.secrets.g.dart
56
- touch cw_solana/lib/.secrets.g.dart
57
- touch cw_core/lib/.secrets.g.dart
58
- touch cw_nano/lib/.secrets.g.dart
59
- touch cw_tron/lib/.secrets.g.dart
60
- if [[ "x${{ secrets.SALT }}" == "x" ]];
61
- then
62
- echo "const salt = '954f787f12622067f7e548d9450c3832';" > lib/.secrets.g.dart
63
- else
64
- echo "const salt = '${{ secrets.SALT }}';" > lib/.secrets.g.dart
65
- fi
66
- if [[ "x${{ secrets.KEY_CHAIN_SALT }}" == "x" ]];
67
- then
68
- echo "const keychainSalt = '2d2beba777dbf7dff7013b7a';" >> lib/.secrets.g.dart
69
- else
70
- echo "const keychainSalt = '${{ secrets.KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
71
- fi
72
- if [[ "x${{ secrets.KEY }}" == "x" ]];
73
- then
74
- echo "const key = '638e98820ec10a2945e968435c9397a3';" >> lib/.secrets.g.dart
75
- else
76
- echo "const key = '${{ secrets.KEY }}';" >> lib/.secrets.g.dart
77
- fi
78
- if [[ "x${{ secrets.WALLET_SALT }}" == "x" ]];
79
- then
80
- echo "const walletSalt = '8f7f1b70';" >> lib/.secrets.g.dart
81
- else
82
- echo "const walletSalt = '${{ secrets.WALLET_SALT }}';" >> lib/.secrets.g.dart
83
- fi
84
- if [[ "x${{ secrets.SHORT_KEY }}" == "x" ]];
85
- then
86
- echo "const shortKey = '653f270c2c152bc7ec864afe';" >> lib/.secrets.g.dart
87
- else
88
- echo "const shortKey = '${{ secrets.SHORT_KEY }}';" >> lib/.secrets.g.dart
89
- fi
90
- if [[ "x${{ secrets.BACKUP_SALT }}" == "x" ]];
91
- then
92
- echo "const backupSalt = 'bf630d24ff0b6f60';" >> lib/.secrets.g.dart
93
- else
94
- echo "const backupSalt = '${{ secrets.BACKUP_SALT }}';" >> lib/.secrets.g.dart
95
- fi
96
- if [[ "x${{ secrets.BACKUP_KEY_CHAIN_SALT }}" == "x" ]];
97
- then
98
- echo "const backupKeychainSalt = 'bf630d24ff0b6f60';" >> lib/.secrets.g.dart
99
- else
100
- echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
101
- fi
102
- echo "const changeNowCakeWalletApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
103
- echo "const changeNowMoneroApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
104
- echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart
105
- echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart
106
- echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart
107
- echo "const moonPayApiKey = '${{ secrets.MOON_PAY_API_KEY }}';" >> lib/.secrets.g.dart
108
- echo "const moonPaySecretKey = '${{ secrets.MOON_PAY_SECRET_KEY }}';" >> lib/.secrets.g.dart
109
- echo "const sideShiftAffiliateId = '${{ secrets.SIDE_SHIFT_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
110
- echo "const simpleSwapApiKey = '${{ secrets.SIMPLE_SWAP_API_KEY }}';" >> lib/.secrets.g.dart
111
- echo "const simpleSwapApiKeyDesktop = '${{ secrets.SIMPLE_SWAP_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
112
- echo "const onramperApiKey = '${{ secrets.ONRAMPER_API_KEY }}';" >> lib/.secrets.g.dart
113
- echo "const anypayToken = '${{ secrets.ANY_PAY_TOKEN }}';" >> lib/.secrets.g.dart
114
- echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
115
- echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
116
- echo "const trocadorApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
117
- echo "const trocadorMoneroApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
118
- echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
119
- echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
120
- echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
121
- echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> lib/.secrets.g.dart
122
- echo "const chainStackApiKey = '${{ secrets.CHAIN_STACK_API_KEY }}';" >> lib/.secrets.g.dart
123
- echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
124
- echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
125
- echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
126
- echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
127
- echo "const nowNodesApiKey = '${{ secrets.EVM_NOWNODES_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
128
- echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
129
- echo "const exolixCakeWalletApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
130
- echo "const exolixMoneroApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
131
- echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
132
- echo "const exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
133
- echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
134
- echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
135
- echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
136
- echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
137
- echo "const chainStackApiKey = '${{ secrets.CHAIN_STACK_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
138
- echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
139
- echo "const testCakePayApiKey = '${{ secrets.TEST_CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
140
- echo "const cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
141
- echo "const authorization = '${{ secrets.CAKE_PAY_AUTHORIZATION }}';" >> lib/.secrets.g.dart
142
- echo "const CSRFToken = '${{ secrets.CSRF_TOKEN }}';" >> lib/.secrets.g.dart
143
- echo "const swapTradeExchangeMarkup = '${{ secrets.SWAPTRADE_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
144
- echo "const nano2ApiKey = '${{ secrets.NANO2_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
145
- echo "const nanoNowNodesApiKey = '${{ secrets.NANO_NOW_NODES_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
146
- echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
147
- echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
148
- echo "const meldTestApiKey = '${{ secrets.MELD_TEST_API_KEY }}';" >> lib/.secrets.g.dart
149
- echo "const meldTestPublicKey = '${{ secrets.MELD_TEST_PUBLIC_KEY}}';" >> lib/.secrets.g.dart
150
- echo "const letsExchangeBearerToken = '${{ secrets.LETS_EXCHANGE_TOKEN }}';" >> lib/.secrets.g.dart
151
- echo "const letsExchangeAffiliateId = '${{ secrets.LETS_EXCHANGE_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
152
- echo "const stealthExBearerToken = '${{ secrets.STEALTH_EX_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
153
- echo "const stealthExAdditionalFeePercent = '${{ secrets.STEALTH_EX_ADDITIONAL_FEE_PERCENT }}';" >> lib/.secrets.g.dart
154
- # for tests
155
- echo "const moneroTestWalletSeeds ='${{ secrets.MONERO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
156
- echo "const moneroLegacyTestWalletSeeds = '${{ secrets.MONERO_LEGACY_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
157
- echo "const bitcoinTestWalletSeeds = '${{ secrets.BITCOIN_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
158
- echo "const ethereumTestWalletSeeds = '${{ secrets.ETHEREUM_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
159
- echo "const litecoinTestWalletSeeds = '${{ secrets.LITECOIN_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
160
- echo "const bitcoinCashTestWalletSeeds = '${{ secrets.BITCOIN_CASH_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
161
- echo "const polygonTestWalletSeeds = '${{ secrets.POLYGON_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
162
- echo "const baseTestWalletSeeds = '${{ secrets.BASE_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
163
- echo "const arbitrumTestWalletSeeds = '${{ secrets.ARBITRUM_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
164
- echo "const solanaTestWalletSeeds = '${{ secrets.SOLANA_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
165
- echo "const tronTestWalletSeeds = '${{ secrets.TRON_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
166
- echo "const nanoTestWalletSeeds = '${{ secrets.NANO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
167
- echo "const wowneroTestWalletSeeds = '${{ secrets.WOWNERO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
168
- echo "const zanoTestWalletSeeds = '${{ secrets.ZANO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
169
- echo "const moneroTestWalletReceiveAddress = '${{ secrets.MONERO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
170
- echo "const bitcoinTestWalletReceiveAddress = '${{ secrets.BITCOIN_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
171
- echo "const ethereumTestWalletReceiveAddress = '${{ secrets.ETHEREUM_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
172
- echo "const litecoinTestWalletReceiveAddress = '${{ secrets.LITECOIN_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
173
- echo "const bitcoinCashTestWalletReceiveAddress = '${{ secrets.BITCOIN_CASH_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
174
- echo "const polygonTestWalletReceiveAddress = '${{ secrets.POLYGON_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
175
- echo "const baseTestWalletReceiveAddress = '${{ secrets.BASE_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
176
- echo "const arbitrumTestWalletReceiveAddress = '${{ secrets.ARBITRUM_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
177
- echo "const solanaTestWalletReceiveAddress = '${{ secrets.SOLANA_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
178
- echo "const tronTestWalletReceiveAddress = '${{ secrets.TRON_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
179
- echo "const nanoTestWalletReceiveAddress = '${{ secrets.NANO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
180
- echo "const wowneroTestWalletReceiveAddress = '${{ secrets.WOWNERO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
181
- echo "const moneroTestWalletBlockHeight = '${{ secrets.MONERO_TEST_WALLET_BLOCK_HEIGHT }}';" >> lib/.secrets.g.dart
182
- # end of test secrets
183
- echo "const chainflipApiKey = '${{ secrets.CHAINFLIP_API_KEY }}';" >> lib/.secrets.g.dart
184
- echo "const chainflipAffiliateFee = '${{ secrets.CHAINFLIP_AFFILIATE_FEE }}';" >> lib/.secrets.g.dart
185
- echo "const kryptonimApiKey = '${{ secrets.KRYPTONIM_API_KEY }}';" >> lib/.secrets.g.dart
186
- echo "const walletGroupSalt = '${{ secrets.WALLET_GROUP_SALT }}';" >> lib/.secrets.g.dart
187
- echo "const swapsXyzApiKey = '${{ secrets.SWAPSXYZ_API_KEY }}';" >> lib/.secrets.g.dart
188
-
189
- - name: Generate KeyStore
190
- run: |
191
- pushd /opt/generic_cache
192
- if [[ ! -f key.jks ]];
193
- then
194
- keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" -storepass $STORE_PASS -keypass $KEY_PASS
195
- else
196
- echo "$PWD/key.jks exist, not generating"
197
- fi
198
- popd
199
- cp /opt/generic_cache/key.jks android/app
200
-
201
- - name: Fetch prebuilt Torch
202
- run: |
203
- set -x -e
204
- pushd scripts
205
- wget https://github.com/MrCyjaneK/torch_dart/releases/download/v1.0.17/torch_dart-v1.0.17.tar.gz -O torch_dart.tar.gz
206
- mkdir torch_dart
207
- pushd torch_dart
208
- tar -xzf ../torch_dart.tar.gz
209
- popd
210
- rm ./torch_dart.tar.gz
211
- popd
212
-
213
- - name: Fetch prebuilt Reown
214
- run: |
215
- set -x -e
216
- pushd scripts
217
- # cleaning
218
- rm -rf reown_flutter
219
- rm -f reown_flutter.tar.gz
220
-
221
- wget https://github.com/cake-tech/reown_flutter/releases/download/v0.0.4/reown_flutter-v0.0.4.tar.gz -O reown_flutter.tar.gz
222
- mkdir reown_flutter
223
- pushd reown_flutter
224
- tar -xzf ../reown_flutter.tar.gz
225
- popd
226
- rm ./reown_flutter.tar.gz
227
- popd
228
-
229
- - name: Execute Build and Setup Commands
230
- run: |
231
- pushd scripts/android
232
- source ./app_env.sh cakewallet
233
- ./app_config.sh
234
- popd
235
-
236
- - name: Build monero_c
237
- run: |
238
- mkdir -p scripts/monero_c
239
- pushd scripts/monero_c
240
- wget https://github.com/MrCyjaneK/monero_c/releases/download/v0.18.4.0-RC9/release-bundle.zip
241
- unzip release-bundle.zip
242
- rm release-bundle.zip
243
- unxz -fv release/*/*.xz
244
- popd
245
-
246
- - name: Build Bitbox Flutter
247
- run: |
248
- set -x -e
249
- pushd scripts
250
- ./build_bitbox_flutter.sh
251
- popd
252
-
253
- - name: Install Flutter dependencies
254
- run: |
255
- flutter pub get
256
-
257
- - name: Build mwebd
258
- run: |
259
- set -x -e
260
- export MWEBD_HASH=$(cat scripts/android/build_mwebd.sh | grep 'git reset --hard' | xargs | awk '{ print $4 }')
261
- echo MWEBD_HASH=$MWEBD_HASH >> /etc/environment
262
- pushd scripts/android
263
- ./build_mwebd.sh
264
- popd
265
-
266
- - name: Build Decred
267
- run: |
268
- set -x -e
269
- pushd scripts/android
270
- ./build_decred.sh
271
- popd
272
-
273
- - name: Build generated code
274
- run: |
275
- flutter --version
276
- flutter clean
277
- rm -rf .dart_tool
278
- rm pubspec.lock
279
- flutter pub get
280
- ./model_generator.sh async
281
-
282
- - name: Generate key properties
283
- run: |
284
- dart run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=$STORE_PASS keyPassword=$KEY_PASS
285
-
286
- - name: Generate localization
287
- run: |
288
- dart run tool/generate_localization.dart
289
-
290
- - name: Rename app
291
- run: |
292
- sanitized_branch_name=${BRANCH_NAME#origin/} # Remove 'origin/' prefix if it exists
293
- sanitized_branch_name=${sanitized_branch_name:0:16} # Take only the first 16 characters
294
- sanitized_branch_name=$(echo "$sanitized_branch_name" | tr '[:upper:]' '[:lower:]') # Convert to lowercase
295
- sanitized_branch_name=$(echo "$sanitized_branch_name" | sed 's/[^a-z0-9]//g') # Remove all special characters
296
-
297
- echo -e "id=com.cakewallet.test_${sanitized_branch_name}\nname=${BRANCH_NAME}" > android/app.properties
298
-
299
- - name: Build
300
- run: |
301
- flutter build apk --dart-define=hasDevOptions=true --release --split-per-abi
302
-
303
- - name: Rename apk file
304
- run: |
305
- cd build/app/outputs/flutter-apk
306
- mkdir test-apk
307
- cp app-arm64-v8a-release.apk test-apk/${BRANCH_NAME}.apk
308
- cp app-x86_64-release.apk test-apk/${BRANCH_NAME}_x86.apk
309
-
310
- - name: Find APK file
311
- id: find_apk
312
- run: |
313
- set -x
314
- apk_file=$(ls build/app/outputs/flutter-apk/test-apk/${BRANCH_NAME}.apk || exit 1)
315
- echo "APK_FILE=$apk_file" >> $GITHUB_ENV
316
- - name: Write BRANCH_NAME to env
317
- run: echo "BRANCH_NAME=${BRANCH_NAME}" >> $GITHUB_ENV
318
-
319
- - name: Upload to slack step
320
- uses: vaporif/slack-file-upload-action@v1
321
- with:
322
- token: ${{ secrets.SLACK_APP_TOKEN }}
323
- initial_comment: ${{ env.message }}
324
- files: >
325
- [
326
- {"file": "${{ env.APK_FILE }}", "filename": "${{ env.BRANCH_NAME }}.apk"}
327
- ]
328
- channel_id: ${{ secrets.SLACK_APK_CHANNEL }}
329
-
330
- - name: cleanup
331
- run: rm -rf build/app/outputs/flutter-apk/test-apk/
32
333
- - name: Upload Artifact to github
334
- uses: actions/upload-artifact@v4
335
- with:
336
- path: ${{ github.workspace }}/build/app/outputs/flutter-apk
337
- name: "android apk"
338
-
339
- - name: 16KB align
340
- run: |
341
- cd build/app/outputs/flutter-apk
342
- for i in arm64-v8a x86_64; do
343
- ../../../../scripts/android/check_16kb_align.sh app-$i-release.apk
344
- done
\ No newline at end of file
33
+ uses: ./.github/workflows/reusable-build.yml
34
+ with:
35
+ ref: ${{ github.event.pull_request.head.sha }}
36
+ pr_number: ${{ github.head_ref || github.ref_name }}
37
+ secrets: inherit
\ No newline at end of file
.github/workflows/reusable-build.yml
new
+351
@@ -0,0 +1,351 @@
1
+name: Reusable Build Logic
2
+
3
+on:
4
+ workflow_call:
5
+ inputs:
6
+ ref:
7
+ required: true
8
+ type: string
9
+ pr_number:
10
+ required: true
11
+ type: string
12
+
13
+defaults:
14
+ run:
15
+ shell: bash
16
+jobs:
17
+ PR_test_build:
18
+ runs-on: [Linux, amd64, android]
19
+ container:
20
+ image: ghcr.io/cake-tech/cake_wallet:debian13-flutter3.32.0-ndkr28-go1.24.1-ruststablenightly
21
+ env:
22
+ STORE_PASS: test@cake_wallet
23
+ KEY_PASS: test@cake_wallet
24
+ MONEROC_CACHE_DIR_ROOT: /opt/generic_cache
25
+ BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
26
+ ANDROID_AVD_HOME: /root/.android/avd
27
+ volumes:
28
+ - /opt/cw_cache_android/root/.cache:/root/.cache
29
+ - /opt/cw_cache_android/root/.android/avd/:/root/.android/avd
30
+ - /opt/cw_cache_android/root/.ccache:/root/.ccache
31
+ - /opt/cw_cache_android/root/.pub-cache/:/root/.pub-cache
32
+ - /opt/cw_cache_android/root/.gradle/:/root/.gradle
33
+ - /opt/cw_cache_android/root/.android/:/root/.android
34
+ - /opt/cw_cache_android/root/go/pkg:/root/go/pkg
35
+ - /opt/cw_cache_android/opt/generic_cache:/opt/generic_cache
36
+ - /dev/kvm:/dev/kvm
37
+ strategy:
38
+ matrix:
39
+ api-level: [29]
40
+
41
+ steps:
42
+ - name: Fix github actions messing up $HOME...
43
+ run: 'echo HOME=/root | sudo tee -a $GITHUB_ENV'
44
+ - uses: actions/checkout@v4
45
+ with:
46
+ ref: ${{ inputs.ref }}
47
+ - name: configure git
48
+ run: |
49
+ git config --global --add safe.directory '*'
50
+ git config --global user.email "ci@cakewallet.com"
51
+ git config --global user.name "CakeWallet CI"
52
+ - name: Get the full commit message
53
+ run: |
54
+ FULL_MESSAGE="$(git log -1 --pretty=%B)"
55
+ echo "message<<EOF" >> $GITHUB_ENV
56
+ echo "$FULL_MESSAGE" >> $GITHUB_ENV
57
+ echo "EOF" >> $GITHUB_ENV
58
+
59
+ - name: Add secrets
60
+ run: |
61
+ touch lib/.secrets.g.dart
62
+ touch cw_evm/lib/.secrets.g.dart
63
+ touch cw_solana/lib/.secrets.g.dart
64
+ touch cw_core/lib/.secrets.g.dart
65
+ touch cw_nano/lib/.secrets.g.dart
66
+ touch cw_tron/lib/.secrets.g.dart
67
+ if [[ "x${{ secrets.SALT }}" == "x" ]];
68
+ then
69
+ echo "const salt = '954f787f12622067f7e548d9450c3832';" > lib/.secrets.g.dart
70
+ else
71
+ echo "const salt = '${{ secrets.SALT }}';" > lib/.secrets.g.dart
72
+ fi
73
+ if [[ "x${{ secrets.KEY_CHAIN_SALT }}" == "x" ]];
74
+ then
75
+ echo "const keychainSalt = '2d2beba777dbf7dff7013b7a';" >> lib/.secrets.g.dart
76
+ else
77
+ echo "const keychainSalt = '${{ secrets.KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
78
+ fi
79
+ if [[ "x${{ secrets.KEY }}" == "x" ]];
80
+ then
81
+ echo "const key = '638e98820ec10a2945e968435c9397a3';" >> lib/.secrets.g.dart
82
+ else
83
+ echo "const key = '${{ secrets.KEY }}';" >> lib/.secrets.g.dart
84
+ fi
85
+ if [[ "x${{ secrets.WALLET_SALT }}" == "x" ]];
86
+ then
87
+ echo "const walletSalt = '8f7f1b70';" >> lib/.secrets.g.dart
88
+ else
89
+ echo "const walletSalt = '${{ secrets.WALLET_SALT }}';" >> lib/.secrets.g.dart
90
+ fi
91
+ if [[ "x${{ secrets.SHORT_KEY }}" == "x" ]];
92
+ then
93
+ echo "const shortKey = '653f270c2c152bc7ec864afe';" >> lib/.secrets.g.dart
94
+ else
95
+ echo "const shortKey = '${{ secrets.SHORT_KEY }}';" >> lib/.secrets.g.dart
96
+ fi
97
+ if [[ "x${{ secrets.BACKUP_SALT }}" == "x" ]];
98
+ then
99
+ echo "const backupSalt = 'bf630d24ff0b6f60';" >> lib/.secrets.g.dart
100
+ else
101
+ echo "const backupSalt = '${{ secrets.BACKUP_SALT }}';" >> lib/.secrets.g.dart
102
+ fi
103
+ if [[ "x${{ secrets.BACKUP_KEY_CHAIN_SALT }}" == "x" ]];
104
+ then
105
+ echo "const backupKeychainSalt = 'bf630d24ff0b6f60';" >> lib/.secrets.g.dart
106
+ else
107
+ echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
108
+ fi
109
+ echo "const changeNowCakeWalletApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
110
+ echo "const changeNowMoneroApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
111
+ echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart
112
+ echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart
113
+ echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart
114
+ echo "const moonPayApiKey = '${{ secrets.MOON_PAY_API_KEY }}';" >> lib/.secrets.g.dart
115
+ echo "const moonPaySecretKey = '${{ secrets.MOON_PAY_SECRET_KEY }}';" >> lib/.secrets.g.dart
116
+ echo "const sideShiftAffiliateId = '${{ secrets.SIDE_SHIFT_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
117
+ echo "const simpleSwapApiKey = '${{ secrets.SIMPLE_SWAP_API_KEY }}';" >> lib/.secrets.g.dart
118
+ echo "const simpleSwapApiKeyDesktop = '${{ secrets.SIMPLE_SWAP_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
119
+ echo "const onramperApiKey = '${{ secrets.ONRAMPER_API_KEY }}';" >> lib/.secrets.g.dart
120
+ echo "const anypayToken = '${{ secrets.ANY_PAY_TOKEN }}';" >> lib/.secrets.g.dart
121
+ echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
122
+ echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
123
+ echo "const trocadorApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
124
+ echo "const trocadorMoneroApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
125
+ echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
126
+ echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
127
+ echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
128
+ echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> lib/.secrets.g.dart
129
+ echo "const chainStackApiKey = '${{ secrets.CHAIN_STACK_API_KEY }}';" >> lib/.secrets.g.dart
130
+ echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
131
+ echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
132
+ echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
133
+ echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
134
+ echo "const nowNodesApiKey = '${{ secrets.EVM_NOWNODES_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
135
+ echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
136
+ echo "const exolixCakeWalletApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
137
+ echo "const exolixMoneroApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
138
+ echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
139
+ echo "const exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
140
+ echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
141
+ echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
142
+ echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
143
+ echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
144
+ echo "const chainStackApiKey = '${{ secrets.CHAIN_STACK_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
145
+ echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
146
+ echo "const testCakePayApiKey = '${{ secrets.TEST_CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
147
+ echo "const cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
148
+ echo "const authorization = '${{ secrets.CAKE_PAY_AUTHORIZATION }}';" >> lib/.secrets.g.dart
149
+ echo "const CSRFToken = '${{ secrets.CSRF_TOKEN }}';" >> lib/.secrets.g.dart
150
+ echo "const swapTradeExchangeMarkup = '${{ secrets.SWAPTRADE_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
151
+ echo "const nano2ApiKey = '${{ secrets.NANO2_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
152
+ echo "const nanoNowNodesApiKey = '${{ secrets.NANO_NOW_NODES_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
153
+ echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
154
+ echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
155
+ echo "const meldTestApiKey = '${{ secrets.MELD_TEST_API_KEY }}';" >> lib/.secrets.g.dart
156
+ echo "const meldTestPublicKey = '${{ secrets.MELD_TEST_PUBLIC_KEY}}';" >> lib/.secrets.g.dart
157
+ echo "const letsExchangeBearerToken = '${{ secrets.LETS_EXCHANGE_TOKEN }}';" >> lib/.secrets.g.dart
158
+ echo "const letsExchangeAffiliateId = '${{ secrets.LETS_EXCHANGE_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
159
+ echo "const stealthExBearerToken = '${{ secrets.STEALTH_EX_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
160
+ echo "const stealthExAdditionalFeePercent = '${{ secrets.STEALTH_EX_ADDITIONAL_FEE_PERCENT }}';" >> lib/.secrets.g.dart
161
+ # for tests
162
+ echo "const moneroTestWalletSeeds ='${{ secrets.MONERO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
163
+ echo "const moneroLegacyTestWalletSeeds = '${{ secrets.MONERO_LEGACY_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
164
+ echo "const bitcoinTestWalletSeeds = '${{ secrets.BITCOIN_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
165
+ echo "const ethereumTestWalletSeeds = '${{ secrets.ETHEREUM_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
166
+ echo "const litecoinTestWalletSeeds = '${{ secrets.LITECOIN_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
167
+ echo "const bitcoinCashTestWalletSeeds = '${{ secrets.BITCOIN_CASH_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
168
+ echo "const polygonTestWalletSeeds = '${{ secrets.POLYGON_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
169
+ echo "const baseTestWalletSeeds = '${{ secrets.BASE_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
170
+ echo "const arbitrumTestWalletSeeds = '${{ secrets.ARBITRUM_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
171
+ echo "const solanaTestWalletSeeds = '${{ secrets.SOLANA_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
172
+ echo "const tronTestWalletSeeds = '${{ secrets.TRON_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
173
+ echo "const nanoTestWalletSeeds = '${{ secrets.NANO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
174
+ echo "const wowneroTestWalletSeeds = '${{ secrets.WOWNERO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
175
+ echo "const zanoTestWalletSeeds = '${{ secrets.ZANO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
176
+ echo "const moneroTestWalletReceiveAddress = '${{ secrets.MONERO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
177
+ echo "const bitcoinTestWalletReceiveAddress = '${{ secrets.BITCOIN_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
178
+ echo "const ethereumTestWalletReceiveAddress = '${{ secrets.ETHEREUM_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
179
+ echo "const litecoinTestWalletReceiveAddress = '${{ secrets.LITECOIN_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
180
+ echo "const bitcoinCashTestWalletReceiveAddress = '${{ secrets.BITCOIN_CASH_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
181
+ echo "const polygonTestWalletReceiveAddress = '${{ secrets.POLYGON_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
182
+ echo "const baseTestWalletReceiveAddress = '${{ secrets.BASE_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
183
+ echo "const arbitrumTestWalletReceiveAddress = '${{ secrets.ARBITRUM_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
184
+ echo "const solanaTestWalletReceiveAddress = '${{ secrets.SOLANA_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
185
+ echo "const tronTestWalletReceiveAddress = '${{ secrets.TRON_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
186
+ echo "const nanoTestWalletReceiveAddress = '${{ secrets.NANO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
187
+ echo "const wowneroTestWalletReceiveAddress = '${{ secrets.WOWNERO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
188
+ echo "const moneroTestWalletBlockHeight = '${{ secrets.MONERO_TEST_WALLET_BLOCK_HEIGHT }}';" >> lib/.secrets.g.dart
189
+ # end of test secrets
190
+ echo "const chainflipApiKey = '${{ secrets.CHAINFLIP_API_KEY }}';" >> lib/.secrets.g.dart
191
+ echo "const chainflipAffiliateFee = '${{ secrets.CHAINFLIP_AFFILIATE_FEE }}';" >> lib/.secrets.g.dart
192
+ echo "const kryptonimApiKey = '${{ secrets.KRYPTONIM_API_KEY }}';" >> lib/.secrets.g.dart
193
+ echo "const walletGroupSalt = '${{ secrets.WALLET_GROUP_SALT }}';" >> lib/.secrets.g.dart
194
+ echo "const swapsXyzApiKey = '${{ secrets.SWAPSXYZ_API_KEY }}';" >> lib/.secrets.g.dart
195
+
196
+ - name: Generate KeyStore
197
+ run: |
198
+ pushd /opt/generic_cache
199
+ if [[ ! -f key.jks ]];
200
+ then
201
+ keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" -storepass $STORE_PASS -keypass $KEY_PASS
202
+ else
203
+ echo "$PWD/key.jks exist, not generating"
204
+ fi
205
+ popd
206
+ cp /opt/generic_cache/key.jks android/app
207
+
208
+ - name: Fetch prebuilt Torch
209
+ run: |
210
+ set -x -e
211
+ pushd scripts
212
+ wget https://github.com/MrCyjaneK/torch_dart/releases/download/v1.0.17/torch_dart-v1.0.17.tar.gz -O torch_dart.tar.gz
213
+ mkdir torch_dart
214
+ pushd torch_dart
215
+ tar -xzf ../torch_dart.tar.gz
216
+ popd
217
+ rm ./torch_dart.tar.gz
218
+ popd
219
+
220
+ - name: Fetch prebuilt Reown
221
+ run: |
222
+ set -x -e
223
+ pushd scripts
224
+ # cleaning
225
+ rm -rf reown_flutter
226
+ rm -f reown_flutter.tar.gz
227
+
228
+ wget https://github.com/cake-tech/reown_flutter/releases/download/v0.0.4/reown_flutter-v0.0.4.tar.gz -O reown_flutter.tar.gz
229
+ mkdir reown_flutter
230
+ pushd reown_flutter
231
+ tar -xzf ../reown_flutter.tar.gz
232
+ popd
233
+ rm ./reown_flutter.tar.gz
234
+ popd
235
+
236
+ - name: Execute Build and Setup Commands
237
+ run: |
238
+ pushd scripts/android
239
+ source ./app_env.sh cakewallet
240
+ ./app_config.sh
241
+ popd
242
+
243
+ - name: Build monero_c
244
+ run: |
245
+ mkdir -p scripts/monero_c
246
+ pushd scripts/monero_c
247
+ wget https://github.com/MrCyjaneK/monero_c/releases/download/v0.18.4.0-RC9/release-bundle.zip
248
+ unzip release-bundle.zip
249
+ rm release-bundle.zip
250
+ unxz -fv release/*/*.xz
251
+ popd
252
+
253
+ - name: Build Bitbox Flutter
254
+ run: |
255
+ set -x -e
256
+ pushd scripts
257
+ ./build_bitbox_flutter.sh
258
+ popd
259
+
260
+ - name: Install Flutter dependencies
261
+ run: |
262
+ flutter pub get
263
+
264
+ - name: Build mwebd
265
+ run: |
266
+ set -x -e
267
+ export MWEBD_HASH=$(cat scripts/android/build_mwebd.sh | grep 'git reset --hard' | xargs | awk '{ print $4 }')
268
+ echo MWEBD_HASH=$MWEBD_HASH >> /etc/environment
269
+ pushd scripts/android
270
+ ./build_mwebd.sh
271
+ popd
272
+
273
+ - name: Build Decred
274
+ run: |
275
+ set -x -e
276
+ pushd scripts/android
277
+ ./build_decred.sh
278
+ popd
279
+
280
+ - name: Build generated code
281
+ run: |
282
+ flutter --version
283
+ flutter clean
284
+ rm -rf .dart_tool
285
+ rm pubspec.lock
286
+ flutter pub get
287
+ ./model_generator.sh async
288
+
289
+ - name: Generate key properties
290
+ run: |
291
+ dart run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=$STORE_PASS keyPassword=$KEY_PASS
292
+
293
+ - name: Generate localization
294
+ run: |
295
+ dart run tool/generate_localization.dart
296
+
297
+ - name: Rename app
298
+ run: |
299
+ sanitized_branch_name=${BRANCH_NAME#origin/} # Remove 'origin/' prefix if it exists
300
+ sanitized_branch_name=${sanitized_branch_name:0:16} # Take only the first 16 characters
301
+ sanitized_branch_name=$(echo "$sanitized_branch_name" | tr '[:upper:]' '[:lower:]') # Convert to lowercase
302
+ sanitized_branch_name=$(echo "$sanitized_branch_name" | sed 's/[^a-z0-9]//g') # Remove all special characters
303
+
304
+ echo -e "id=com.cakewallet.test_${sanitized_branch_name}\nname=${BRANCH_NAME}" > android/app.properties
305
+
306
+ - name: Build
307
+ run: |
308
+ flutter build apk --dart-define=hasDevOptions=true --release --split-per-abi
309
+
310
+ - name: Rename apk file
311
+ run: |
312
+ cd build/app/outputs/flutter-apk
313
+ mkdir test-apk
314
+ cp app-arm64-v8a-release.apk test-apk/${BRANCH_NAME}.apk
315
+ cp app-x86_64-release.apk test-apk/${BRANCH_NAME}_x86.apk
316
+
317
+ - name: Find APK file
318
+ id: find_apk
319
+ run: |
320
+ set -x
321
+ apk_file=$(ls build/app/outputs/flutter-apk/test-apk/${BRANCH_NAME}.apk || exit 1)
322
+ echo "APK_FILE=$apk_file" >> $GITHUB_ENV
323
+ - name: Write BRANCH_NAME to env
324
+ run: echo "BRANCH_NAME=${BRANCH_NAME}" >> $GITHUB_ENV
325
+
326
+ - name: Upload to slack step
327
+ uses: vaporif/slack-file-upload-action@v1
328
+ with:
329
+ token: ${{ secrets.SLACK_APP_TOKEN }}
330
+ initial_comment: ${{ env.message }}
331
+ files: >
332
+ [
333
+ {"file": "${{ env.APK_FILE }}", "filename": "${{ env.BRANCH_NAME }}.apk"}
334
+ ]
335
+ channel_id: ${{ secrets.SLACK_APK_CHANNEL }}
336
+
337
+ - name: cleanup
338
+ run: rm -rf build/app/outputs/flutter-apk/test-apk/
339
+
340
+ - name: Upload Artifact to github
341
+ uses: actions/upload-artifact@v4
342
+ with:
343
+ path: ${{ github.workspace }}/build/app/outputs/flutter-apk
344
+ name: "android apk"
345
+
346
+ - name: 16KB align
347
+ run: |
348
+ cd build/app/outputs/flutter-apk
349
+ for i in arm64-v8a x86_64; do
350
+ ../../../../scripts/android/check_16kb_align.sh app-$i-release.apk
351
+ done
\ No newline at end of file