1
-name: Automated Integration Tests
1
3
-on:
4
- # pull_request:
5
- # branches: [main, CW-659-Transaction-History-Automated-Tests]
6
- workflow_dispatch:
7
- inputs:
8
- branch:
9
- description: "Branch name to build"
10
- required: true
11
- default: "main"
2
+name: Automated Integration Tests
3
4
+# Temporarily disabled - uncomment to re-enable
5
+on:
6
+ # push:
7
+ # pull_request:
8
+ # branches: [main]
9
+ workflow_dispatch: # This is to manually trigger if needed
10
+defaults:
11
+ run:
12
+ shell: bash
13
jobs:
14
- Automated_integration_test:
15
- runs-on: ubuntu-24.04
16
- strategy:
17
- fail-fast: false
18
- matrix:
19
- api-level: [29]
20
- # arch: [x86, x86_64]
21
- env:
22
- STORE_PASS: test@cake_wallet
23
- KEY_PASS: test@cake_wallet
24
- PR_NUMBER: ${{ github.event.number }}
14
+ Automated_integration_test:
15
+ runs-on: linux-amd64
16
+ timeout-minutes: 90
17
+ container:
18
+ image: ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly
19
+ env:
20
+ STORE_PASS: test@cake_wallet
21
+ KEY_PASS: test@cake_wallet
22
+ MONEROC_CACHE_DIR_ROOT: /opt/generic_cache
23
+ BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
24
+ ANDROID_AVD_HOME: /root/.android/avd
25
+ volumes:
26
+ - /opt/cw_cache_android/root/.cache:/root/.cache
27
+ - /opt/cw_cache_android/root/.android/avd/:/root/.android/avd
28
+ - /opt/cw_cache_android/root/.ccache:/root/.ccache
29
+ - /opt/cw_cache_android/root/.pub-cache/:/root/.pub-cache
30
+ - /opt/cw_cache_android/root/.gradle/:/root/.gradle
31
+ - /opt/cw_cache_android/root/.android/:/root/.android
32
+ - /opt/cw_cache_android/root/go/pkg:/root/go/pkg
33
+ - /opt/cw_cache_android/opt/generic_cache:/opt/generic_cache
34
+ - /dev/kvm:/dev/kvm
35
+ strategy:
36
+ matrix:
37
+ api-level: [29]
38
26
- steps:
27
- - name: is pr
28
- if: github.event_name == 'pull_request'
29
- run: echo "BRANCH_NAME=${GITHUB_HEAD_REF}" >> $GITHUB_ENV
39
+ steps:
40
+ - name: Fix github actions messing up $HOME...
41
+ run: 'echo HOME=/root | sudo tee -a $GITHUB_ENV'
42
+ - uses: actions/checkout@v4
43
+ with:
44
+ ref: ${{ github.event.pull_request.head.sha || github.sha }}
45
+ - name: configure git
46
+ run: |
47
+ git config --global --add safe.directory '*'
48
+ git config --global user.email "ci@cakewallet.com"
49
+ git config --global user.name "CakeWallet CI"
50
+ - name: Get the full commit message
51
+ run: |
52
+ FULL_MESSAGE="$(git log -1 --pretty=%B)"
53
+ echo "message<<EOF" >> $GITHUB_ENV
54
+ echo "$FULL_MESSAGE" >> $GITHUB_ENV
55
+ echo "EOF" >> $GITHUB_ENV
56
31
- - name: is not pr
32
- if: github.event_name != 'pull_request'
33
- run: echo "BRANCH_NAME=${{ github.event.inputs.branch }}" >> $GITHUB_ENV
57
+ - name: Add secrets
58
+ run: |
59
+ touch lib/.secrets.g.dart
60
+ touch cw_evm/lib/.secrets.g.dart
61
+ touch cw_solana/lib/.secrets.g.dart
62
+ touch cw_core/lib/.secrets.g.dart
63
+ touch cw_nano/lib/.secrets.g.dart
64
+ touch cw_tron/lib/.secrets.g.dart
65
+ if [[ "x${{ secrets.SALT }}" == "x" ]];
66
+ then
67
+ echo "const salt = '954f787f12622067f7e548d9450c3832';" > lib/.secrets.g.dart
68
+ else
69
+ echo "const salt = '${{ secrets.SALT }}';" > lib/.secrets.g.dart
70
+ fi
71
+ if [[ "x${{ secrets.KEY_CHAIN_SALT }}" == "x" ]];
72
+ then
73
+ echo "const keychainSalt = '2d2beba777dbf7dff7013b7a';" >> lib/.secrets.g.dart
74
+ else
75
+ echo "const keychainSalt = '${{ secrets.KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
76
+ fi
77
+ if [[ "x${{ secrets.KEY }}" == "x" ]];
78
+ then
79
+ echo "const key = '638e98820ec10a2945e968435c9397a3';" >> lib/.secrets.g.dart
80
+ else
81
+ echo "const key = '${{ secrets.KEY }}';" >> lib/.secrets.g.dart
82
+ fi
83
+ if [[ "x${{ secrets.WALLET_SALT }}" == "x" ]];
84
+ then
85
+ echo "const walletSalt = '8f7f1b70';" >> lib/.secrets.g.dart
86
+ else
87
+ echo "const walletSalt = '${{ secrets.WALLET_SALT }}';" >> lib/.secrets.g.dart
88
+ fi
89
+ if [[ "x${{ secrets.SHORT_KEY }}" == "x" ]];
90
+ then
91
+ echo "const shortKey = '653f270c2c152bc7ec864afe';" >> lib/.secrets.g.dart
92
+ else
93
+ echo "const shortKey = '${{ secrets.SHORT_KEY }}';" >> lib/.secrets.g.dart
94
+ fi
95
+ if [[ "x${{ secrets.BACKUP_SALT }}" == "x" ]];
96
+ then
97
+ echo "const backupSalt = 'bf630d24ff0b6f60';" >> lib/.secrets.g.dart
98
+ else
99
+ echo "const backupSalt = '${{ secrets.BACKUP_SALT }}';" >> lib/.secrets.g.dart
100
+ fi
101
+ if [[ "x${{ secrets.BACKUP_KEY_CHAIN_SALT }}" == "x" ]];
102
+ then
103
+ echo "const backupKeychainSalt = 'bf630d24ff0b6f60';" >> lib/.secrets.g.dart
104
+ else
105
+ echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
106
+ fi
107
+ echo "const changeNowCakeWalletApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
108
+ echo "const changeNowMoneroApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
109
+ echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart
110
+ echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart
111
+ echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart
112
+ echo "const moonPayApiKey = '${{ secrets.MOON_PAY_API_KEY }}';" >> lib/.secrets.g.dart
113
+ echo "const moonPaySecretKey = '${{ secrets.MOON_PAY_SECRET_KEY }}';" >> lib/.secrets.g.dart
114
+ echo "const sideShiftAffiliateId = '${{ secrets.SIDE_SHIFT_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
115
+ echo "const simpleSwapApiKey = '${{ secrets.SIMPLE_SWAP_API_KEY }}';" >> lib/.secrets.g.dart
116
+ echo "const simpleSwapApiKeyDesktop = '${{ secrets.SIMPLE_SWAP_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
117
+ echo "const onramperApiKey = '${{ secrets.ONRAMPER_API_KEY }}';" >> lib/.secrets.g.dart
118
+ echo "const anypayToken = '${{ secrets.ANY_PAY_TOKEN }}';" >> lib/.secrets.g.dart
119
+ echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
120
+ echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
121
+ echo "const trocadorApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
122
+ echo "const trocadorMoneroApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
123
+ echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
124
+ echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
125
+ echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
126
+ echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> lib/.secrets.g.dart
127
+ echo "const chainStackApiKey = '${{ secrets.CHAIN_STACK_API_KEY }}';" >> lib/.secrets.g.dart
128
+ echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
129
+ echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
130
+ echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
131
+ echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
132
+ echo "const nowNodesApiKey = '${{ secrets.EVM_NOWNODES_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
133
+ echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
134
+ echo "const exolixCakeWalletApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
135
+ echo "const exolixMoneroApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
136
+ echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
137
+ echo "const exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
138
+ echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
139
+ echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
140
+ echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
141
+ echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
142
+ echo "const chainStackApiKey = '${{ secrets.CHAIN_STACK_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
143
+ echo "const testCakePayApiKey = '${{ secrets.TEST_CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
144
+ echo "const cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
145
+ echo "const authorization = '${{ secrets.CAKE_PAY_AUTHORIZATION }}';" >> lib/.secrets.g.dart
146
+ echo "const CSRFToken = '${{ secrets.CSRF_TOKEN }}';" >> lib/.secrets.g.dart
147
+ echo "const swapTradeExchangeMarkup = '${{ secrets.SWAPTRADE_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
148
+ echo "const nano2ApiKey = '${{ secrets.NANO2_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
149
+ echo "const nanoNowNodesApiKey = '${{ secrets.NANO_NOW_NODES_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
150
+ echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
151
+ echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
152
+ echo "const meldTestApiKey = '${{ secrets.MELD_TEST_API_KEY }}';" >> lib/.secrets.g.dart
153
+ echo "const meldTestPublicKey = '${{ secrets.MELD_TEST_PUBLIC_KEY}}';" >> lib/.secrets.g.dart
154
+ echo "const letsExchangeBearerToken = '${{ secrets.LETS_EXCHANGE_TOKEN }}';" >> lib/.secrets.g.dart
155
+ echo "const letsExchangeAffiliateId = '${{ secrets.LETS_EXCHANGE_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
156
+ echo "const stealthExBearerToken = '${{ secrets.STEALTH_EX_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
157
+ echo "const stealthExAdditionalFeePercent = '${{ secrets.STEALTH_EX_ADDITIONAL_FEE_PERCENT }}';" >> lib/.secrets.g.dart
158
+ # for tests
159
+ echo "const moneroTestWalletSeeds ='${{ secrets.MONERO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
160
+ echo "const moneroLegacyTestWalletSeeds = '${{ secrets.MONERO_LEGACY_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
161
+ echo "const bitcoinTestWalletSeeds = '${{ secrets.BITCOIN_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
162
+ echo "const ethereumTestWalletSeeds = '${{ secrets.ETHEREUM_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
163
+ echo "const litecoinTestWalletSeeds = '${{ secrets.LITECOIN_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
164
+ echo "const bitcoinCashTestWalletSeeds = '${{ secrets.BITCOIN_CASH_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
165
+ echo "const polygonTestWalletSeeds = '${{ secrets.POLYGON_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
166
+ echo "const solanaTestWalletSeeds = '${{ secrets.SOLANA_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
167
+ echo "const solanaTestWalletSeeds2 = '${{ secrets.SOLANA_TEST_WALLET_SEEDS2 }}';" >> lib/.secrets.g.dart
168
+ echo "const tronTestWalletSeeds = '${{ secrets.TRON_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
169
+ echo "const nanoTestWalletSeeds = '${{ secrets.NANO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
170
+ echo "const wowneroTestWalletSeeds = '${{ secrets.WOWNERO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
171
+ echo "const zanoTestWalletSeeds = '${{ secrets.ZANO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
172
+ echo "const decredTestWalletSeeds = '${{ secrets.DECRED_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
173
+ echo "const moneroTestWalletReceiveAddress = '${{ secrets.MONERO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
174
+ echo "const bitcoinTestWalletReceiveAddress = '${{ secrets.BITCOIN_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
175
+ echo "const ethereumTestWalletReceiveAddress = '${{ secrets.ETHEREUM_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
176
+ echo "const litecoinTestWalletReceiveAddress = '${{ secrets.LITECOIN_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
177
+ echo "const bitcoinCashTestWalletReceiveAddress = '${{ secrets.BITCOIN_CASH_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
178
+ echo "const polygonTestWalletReceiveAddress = '${{ secrets.POLYGON_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
179
+ echo "const solanaTestWalletReceiveAddress = '${{ secrets.SOLANA_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
180
+ echo "const tronTestWalletReceiveAddress = '${{ secrets.TRON_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
181
+ echo "const nanoTestWalletReceiveAddress = '${{ secrets.NANO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
182
+ echo "const wowneroTestWalletReceiveAddress = '${{ secrets.WOWNERO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
183
+ echo "const zanoTestWalletReceiveAddress = '${{ secrets.ZANO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
184
+ echo "const decredTestWalletReceiveAddress = '${{ secrets.DECRED_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
185
+ echo "const moneroTestWalletBlockHeight = '${{ secrets.MONERO_TEST_WALLET_BLOCK_HEIGHT }}';" >> lib/.secrets.g.dart
186
+ # end of test secrets
187
+ echo "const chainflipApiKey = '${{ secrets.CHAINFLIP_API_KEY }}';" >> lib/.secrets.g.dart
188
+ echo "const chainflipAffiliateFee = '${{ secrets.CHAINFLIP_AFFILIATE_FEE }}';" >> lib/.secrets.g.dart
189
+ echo "const kryptonimApiKey = '${{ secrets.KRYPTONIM_API_KEY }}';" >> lib/.secrets.g.dart
190
+ echo "const walletGroupSalt = '${{ secrets.WALLET_GROUP_SALT }}';" >> lib/.secrets.g.dart
191
35
- - name: Free Disk Space (Ubuntu)
36
- uses: insightsengineering/disk-space-reclaimer@v1
37
- with:
38
- tools-cache: true
39
- android: false
40
- dotnet: true
41
- haskell: true
42
- large-packages: true
43
- swap-storage: true
44
- docker-images: true
192
+ - name: prepare monero_c and cache
193
+ run: |
194
+ export MONEROC_HASH=$(cat scripts/prepare_moneroc.sh | grep 'git checkout' | xargs | awk '{ print $3 }')
195
+ echo MONEROC_HASH=$MONEROC_HASH >> /etc/environment
196
+ mkdir -p "$MONEROC_CACHE_DIR_ROOT/moneroc-$MONEROC_HASH/monero_c"
197
+ pushd scripts
198
+ ln -s "$MONEROC_CACHE_DIR_ROOT/moneroc-$MONEROC_HASH/monero_c"
199
+ ./prepare_moneroc.sh
200
+ popd
201
+ pushd scripts/monero_c
202
+ mkdir -p "$MONEROC_CACHE_DIR_ROOT/_cache/contrib/depends/built" || true
203
+ mkdir -p "$MONEROC_CACHE_DIR_ROOT/_cache/monero/contrib/depends/built" || true
204
+ mkdir -p "$MONEROC_CACHE_DIR_ROOT/_cache/wownero/contrib/depends/built" || true
205
+ mkdir -p "$MONEROC_CACHE_DIR_ROOT/_cache/contrib/depends/sources" || true
206
+ mkdir -p "$MONEROC_CACHE_DIR_ROOT/_cache/monero/contrib/depends/sources" || true
207
+ mkdir -p "$MONEROC_CACHE_DIR_ROOT/_cache/wownero/contrib/depends/sources" || true
208
46
- - uses: actions/checkout@v2
47
- - uses: actions/setup-java@v2
48
- with:
49
- distribution: "temurin"
50
- java-version: "17"
51
- - name: Configure placeholder git details
52
- run: |
53
- git config --global user.email "CI@cakewallet.com"
54
- git config --global user.name "Cake Github Actions"
55
- - name: Flutter action
56
- uses: subosito/flutter-action@v1
57
- with:
58
- flutter-version: "3.27.0"
59
- channel: stable
209
+ rm -rf "$PWD/contrib/depends/built" "$PWD/monero/contrib/depends/built" "$PWD/wownero/contrib/depends/built"
210
+ rm -rf "$PWD/contrib/depends/sources" "$PWD/monero/contrib/depends/sources" "$PWD/wownero/contrib/depends/sources"
211
+ mkdir -p contrib/depends || true
212
+ ln -sf "$MONEROC_CACHE_DIR_ROOT/_cache/contrib/depends/built" "$PWD/contrib/depends/built"
213
+ ln -sf "$MONEROC_CACHE_DIR_ROOT/_cache/monero/contrib/depends/built" "$PWD/monero/contrib/depends/built"
214
+ ln -sf "$MONEROC_CACHE_DIR_ROOT/_cache/wownero/contrib/depends/built" "$PWD/wownero/contrib/depends/built"
215
+ ln -sf "$MONEROC_CACHE_DIR_ROOT/_cache/contrib/depends/sources" "$PWD/contrib/depends/sources"
216
+ ln -sf "$MONEROC_CACHE_DIR_ROOT/_cache/monero/contrib/depends/sources" "$PWD/monero/contrib/depends/sources"
217
+ ln -sf "$MONEROC_CACHE_DIR_ROOT/_cache/wownero/contrib/depends/sources" "$PWD/wownero/contrib/depends/sources"
218
+ popd
219
61
- - name: Install package dependencies
62
- run: |
63
- sudo apt update
64
- sudo apt-get install -y curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake clang
220
+ - name: Generate KeyStore
221
+ run: |
222
+ pushd /opt/generic_cache
223
+ if [[ ! -f key.jks ]];
224
+ then
225
+ 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
226
+ else
227
+ echo "$PWD/key.jks exist, not generating"
228
+ fi
229
+ popd
230
+ cp /opt/generic_cache/key.jks android/app
231
66
- - name: Execute Build and Setup Commands
67
- run: |
68
- sudo mkdir -p /opt/android
69
- sudo chown $USER /opt/android
70
- cd /opt/android
71
- -y curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
72
- cargo install cargo-ndk
73
- git clone https://github.com/cake-tech/cake_wallet.git --branch ${{ env.BRANCH_NAME }}
74
- cd cake_wallet/scripts/android/
75
- ./install_ndk.sh
76
- source ./app_env.sh cakewallet
77
- chmod +x pubspec_gen.sh
78
- ./app_config.sh
232
+ - name: Execute Build and Setup Commands
233
+ run: |
234
+ pushd scripts/android
235
+ source ./app_env.sh cakewallet
236
+ ./app_config.sh
237
+ popd
238
80
- - name: Cache Externals
81
- id: cache-externals
82
- uses: actions/cache@v3
83
- with:
84
- path: |
85
- /opt/android/cake_wallet/cw_haven/android/.cxx
86
- /opt/android/cake_wallet/scripts/monero_c/release
87
- key: ${{ hashFiles('**/prepare_moneroc.sh' ,'**/build_monero_all.sh' ,'**/cache_dependencies.yml') }}
239
+ - name: Build monero_c
240
+ run: |
241
+ pushd scripts/android/
242
+ source ./app_env.sh cakewallet
243
+ ./build_monero_all.sh
244
+ popd
245
89
- - if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }}
90
- name: Generate Externals
91
- run: |
92
- cd /opt/android/cake_wallet/scripts/android/
93
- source ./app_env.sh cakewallet
94
- ./build_monero_all.sh
246
+ - name: Install Flutter dependencies
247
+ run: |
248
+ flutter pub get
249
96
- - name: Install Flutter dependencies
97
- run: |
98
- cd /opt/android/cake_wallet
99
- flutter pub get
250
+ - name: Build mwebd
251
+ run: |
252
+ set -x -e
253
+ export MWEBD_HASH=$(cat scripts/android/build_mwebd.sh | grep 'git reset --hard' | xargs | awk '{ print $4 }')
254
+ echo MWEBD_HASH=$MWEBD_HASH >> /etc/environment
255
+ pushd scripts/android
256
+ gomobile init;
257
+ ./build_mwebd.sh --dont-install
258
+ popd
259
260
+ - name: Build Decred
261
+ run: |
262
+ set -x -e
263
+ pushd scripts/android
264
+ ./build_decred.sh
265
+ popd
266
102
- - name: Install go and gomobile
103
- run: |
104
- # install go > 1.23:
105
- wget https://go.dev/dl/go1.23.1.linux-amd64.tar.gz
106
- sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.23.1.linux-amd64.tar.gz
107
- export PATH=$PATH:/usr/local/go/bin
108
- export PATH=$PATH:~/go/bin
109
- go install golang.org/x/mobile/cmd/gomobile@latest
110
- gomobile init
267
+ - name: Build generated code
268
+ run: |
269
+ flutter --version
270
+ flutter clean
271
+ rm -rf .dart_tool
272
+ rm pubspec.lock
273
+ flutter pub get
274
+ ./model_generator.sh async
275
112
- - name: Build mwebd
113
- run: |
114
- # paths are reset after each step, so we need to set them again:
115
- export PATH=$PATH:/usr/local/go/bin
116
- export PATH=$PATH:~/go/bin
117
- cd /opt/android/cake_wallet/scripts/android/
118
- ./build_mwebd.sh --dont-install
276
+ - name: Generate key properties
277
+ run: |
278
+ dart run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=$STORE_PASS keyPassword=$KEY_PASS
279
120
- - name: Generate KeyStore
121
- run: |
122
- cd /opt/android/cake_wallet/android/app
123
- 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
280
+ - name: Generate localization
281
+ run: |
282
+ dart run tool/generate_localization.dart
283
125
- - name: Generate key properties
126
- run: |
127
- cd /opt/android/cake_wallet
128
- flutter packages pub run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=$STORE_PASS keyPassword=$KEY_PASS
284
+ - name: Rename app
285
+ run: |
286
+ sanitized_branch_name=${BRANCH_NAME#origin/} # Remove 'origin/' prefix if it exists
287
+ sanitized_branch_name=${sanitized_branch_name:0:16} # Take only the first 16 characters
288
+ sanitized_branch_name=$(echo "$sanitized_branch_name" | tr '[:upper:]' '[:lower:]') # Convert to lowercase
289
+ sanitized_branch_name=$(echo "$sanitized_branch_name" | sed 's/[^a-z0-9]//g') # Remove all special characters
290
130
- - name: Generate localization
131
- run: |
132
- cd /opt/android/cake_wallet
133
- flutter packages pub run tool/generate_localization.dart
291
+ echo -e "id=com.cakewallet.test_${sanitized_branch_name}\nname=${BRANCH_NAME}" > android/app.properties
292
+
293
+ - name: Build
294
+ run: |
295
+ flutter build apk --dart-define=hasDevOptions=true --release --split-per-abi
296
135
- - name: Build generated code
136
- run: |
137
- cd /opt/android/cake_wallet
138
- ./model_generator.sh
297
+ - name: Rename apk file
298
+ run: |
299
+ sanitized_branch_name=$(grep '^id=' android/app.properties | cut -d'=' -f2 | sed 's/com\.cakewallet\.test_//')
300
+ cd build/app/outputs/flutter-apk
301
+ mkdir test-apk
302
+
303
+ cp app-arm64-v8a-release.apk test-apk/${sanitized_branch_name}.apk
304
+ cp app-x86_64-release.apk test-apk/${sanitized_branch_name}_x86.apk
305
+ echo "APK files created: test-apk/${sanitized_branch_name}.apk and test-apk/${sanitized_branch_name}_x86.apk"
306
140
- - name: Add secrets
141
- run: |
142
- cd /opt/android/cake_wallet
143
- touch lib/.secrets.g.dart
144
- touch cw_evm/lib/.secrets.g.dart
145
- touch cw_solana/lib/.secrets.g.dart
146
- touch cw_core/lib/.secrets.g.dart
147
- touch cw_nano/lib/.secrets.g.dart
148
- touch cw_tron/lib/.secrets.g.dart
149
- echo "const salt = '${{ secrets.SALT }}';" > lib/.secrets.g.dart
150
- echo "const keychainSalt = '${{ secrets.KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
151
- echo "const key = '${{ secrets.KEY }}';" >> lib/.secrets.g.dart
152
- echo "const walletSalt = '${{ secrets.WALLET_SALT }}';" >> lib/.secrets.g.dart
153
- echo "const shortKey = '${{ secrets.SHORT_KEY }}';" >> lib/.secrets.g.dart
154
- echo "const backupSalt = '${{ secrets.BACKUP_SALT }}';" >> lib/.secrets.g.dart
155
- echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
156
- echo "const changeNowCakeWalletApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
157
- echo "const changeNowMoneroApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
158
- echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart
159
- echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart
160
- echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart
161
- echo "const moonPayApiKey = '${{ secrets.MOON_PAY_API_KEY }}';" >> lib/.secrets.g.dart
162
- echo "const moonPaySecretKey = '${{ secrets.MOON_PAY_SECRET_KEY }}';" >> lib/.secrets.g.dart
163
- echo "const sideShiftAffiliateId = '${{ secrets.SIDE_SHIFT_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
164
- echo "const simpleSwapApiKey = '${{ secrets.SIMPLE_SWAP_API_KEY }}';" >> lib/.secrets.g.dart
165
- echo "const simpleSwapApiKeyDesktop = '${{ secrets.SIMPLE_SWAP_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
166
- echo "const onramperApiKey = '${{ secrets.ONRAMPER_API_KEY }}';" >> lib/.secrets.g.dart
167
- echo "const anypayToken = '${{ secrets.ANY_PAY_TOKEN }}';" >> lib/.secrets.g.dart
168
- echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
169
- echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
170
- echo "const trocadorApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
171
- echo "const trocadorMoneroApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
172
- echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
173
- echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
174
- echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
175
- echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> lib/.secrets.g.dart
176
- echo "const chainStackApiKey = '${{ secrets.CHAIN_STACK_API_KEY }}';" >> lib/.secrets.g.dart
177
- echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
178
- echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
179
- echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
180
- echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
181
- echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
182
- echo "const exolixCakeWalletApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
183
- echo "const exolixMoneroApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
184
- echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
185
- echo "const exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
186
- echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
187
- echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
188
- echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
189
- echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
190
- echo "const chainStackApiKey = '${{ secrets.CHAIN_STACK_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
191
- echo "const testCakePayApiKey = '${{ secrets.TEST_CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
192
- echo "const cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
193
- echo "const authorization = '${{ secrets.CAKE_PAY_AUTHORIZATION }}';" >> lib/.secrets.g.dart
194
- echo "const CSRFToken = '${{ secrets.CSRF_TOKEN }}';" >> lib/.secrets.g.dart
195
- echo "const swapTradeExchangeMarkup = '${{ secrets.SWAPTRADE_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
196
- echo "const nano2ApiKey = '${{ secrets.NANO2_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
197
- echo "const nanoNowNodesApiKey = '${{ secrets.NANO_NOW_NODES_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
198
- echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
199
- echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
200
- echo "const meldTestApiKey = '${{ secrets.MELD_TEST_API_KEY }}';" >> lib/.secrets.g.dart
201
- echo "const meldTestPublicKey = '${{ secrets.MELD_TEST_PUBLIC_KEY}}';" >> lib/.secrets.g.dart
202
- echo "const letsExchangeBearerToken = '${{ secrets.LETS_EXCHANGE_TOKEN }}';" >> lib/.secrets.g.dart
203
- echo "const letsExchangeAffiliateId = '${{ secrets.LETS_EXCHANGE_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
204
- echo "const stealthExBearerToken = '${{ secrets.STEALTH_EX_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
205
- echo "const stealthExAdditionalFeePercent = '${{ secrets.STEALTH_EX_ADDITIONAL_FEE_PERCENT }}';" >> lib/.secrets.g.dart
206
- echo "const moneroTestWalletSeeds ='${{ secrets.MONERO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
207
- echo "const moneroLegacyTestWalletSeeds = '${{ secrets.MONERO_LEGACY_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
208
- echo "const bitcoinTestWalletSeeds = '${{ secrets.BITCOIN_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
209
- echo "const ethereumTestWalletSeeds = '${{ secrets.ETHEREUM_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
210
- echo "const litecoinTestWalletSeeds = '${{ secrets.LITECOIN_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
211
- echo "const bitcoinCashTestWalletSeeds = '${{ secrets.BITCOIN_CASH_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
212
- echo "const polygonTestWalletSeeds = '${{ secrets.POLYGON_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
213
- echo "const solanaTestWalletSeeds = '${{ secrets.SOLANA_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
214
- echo "const tronTestWalletSeeds = '${{ secrets.TRON_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
215
- echo "const nanoTestWalletSeeds = '${{ secrets.NANO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
216
- echo "const wowneroTestWalletSeeds = '${{ secrets.WOWNERO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart
217
- echo "const moneroTestWalletReceiveAddress = '${{ secrets.MONERO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
218
- echo "const bitcoinTestWalletReceiveAddress = '${{ secrets.BITCOIN_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
219
- echo "const ethereumTestWalletReceiveAddress = '${{ secrets.ETHEREUM_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
220
- echo "const litecoinTestWalletReceiveAddress = '${{ secrets.LITECOIN_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
221
- echo "const bitcoinCashTestWalletReceiveAddress = '${{ secrets.BITCOIN_CASH_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
222
- echo "const polygonTestWalletReceiveAddress = '${{ secrets.POLYGON_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
223
- echo "const solanaTestWalletReceiveAddress = '${{ secrets.SOLANA_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
224
- echo "const tronTestWalletReceiveAddress = '${{ secrets.TRON_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
225
- echo "const nanoTestWalletReceiveAddress = '${{ secrets.NANO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
226
- echo "const wowneroTestWalletReceiveAddress = '${{ secrets.WOWNERO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart
227
- echo "const moneroTestWalletBlockHeight = '${{ secrets.MONERO_TEST_WALLET_BLOCK_HEIGHT }}';" >> lib/.secrets.g.dart
228
- # end of test secrets
229
- echo "const chainflipApiKey = '${{ secrets.CHAINFLIP_API_KEY }}';" >> lib/.secrets.g.dart
230
- echo "const chainflipAffiliateFee = '${{ secrets.CHAINFLIP_AFFILIATE_FEE }}';" >> lib/.secrets.g.dart
231
- echo "const walletGroupSalt = '${{ secrets.WALLET_GROUP_SALT }}';" >> lib/.secrets.g.dart
307
+ - name: Find APK file
308
+ id: find_apk
309
+ run: |
310
+ set -x
311
+ # Read the sanitized branch name from the app.properties file
312
+ sanitized_branch_name=$(grep '^id=' android/app.properties | cut -d'=' -f2 | sed 's/com\.cakewallet\.test_//')
313
+
314
+ echo "Looking for APK file: build/app/outputs/flutter-apk/test-apk/${sanitized_branch_name}.apk"
315
+ ls -la build/app/outputs/flutter-apk/test-apk/ || echo "test-apk directory not found"
316
+ apk_file=$(ls build/app/outputs/flutter-apk/test-apk/${sanitized_branch_name}.apk || exit 1)
317
+ echo "APK_FILE=$apk_file" >> $GITHUB_ENV
318
+ echo "APK file found: $apk_file"
319
+ ls -la "$apk_file"
320
233
- - name: Rename app
234
- run: |
235
- echo -e "id=com.cakewallet.test_${{ env.PR_NUMBER }}\nname=${{ env.BRANCH_NAME }}" > /opt/android/cake_wallet/android/app.properties
321
+ - name: 🔍 Debug System Environment
322
+ run: |
323
+ echo "=== System Information ==="
324
+ uname -a
325
+ echo "=== Container Info ==="
326
+ cat /proc/version || echo "Cannot read /proc/version"
327
+ echo "=== KVM Device Check ==="
328
+ ls -la /dev/kvm || echo "KVM device not found"
329
+ echo "=== udev Status ==="
330
+ which udevadm || echo "udevadm not found"
331
+ echo "=== Current User ==="
332
+ whoami
333
+ echo "=== Groups ==="
334
+ groups
335
+ echo "=== Environment ==="
336
+ env | grep -E "(HOME|USER|PATH)" | sort
337
237
- - name: Build
238
- run: |
239
- cd /opt/android/cake_wallet
240
- flutter build apk --release --split-per-abi
338
+ - name: 🧹 Clean up existing emulators
339
+ run: |
340
+ echo "=== Cleaning up existing emulators ==="
341
+ # Kill any existing emulator processes
342
+ pkill -f emulator || echo "No emulator processes found"
343
+ # Kill any existing adb processes
344
+ pkill -f adb || echo "No adb processes found"
345
+ # Wait a moment for processes to terminate
346
+ sleep 2
347
+ # Start adb server fresh
348
+ adb start-server || echo "Failed to start adb server"
349
+ # Kill adb server to ensure clean state
350
+ adb kill-server || echo "Failed to kill adb server"
351
+ echo "=== Cleanup complete ==="
352
242
- # - name: Rename apk file
243
- # run: |
244
- # cd /opt/android/cake_wallet/build/app/outputs/flutter-apk
245
- # mkdir test-apk
246
- # cp app-arm64-v8a-release.apk test-apk/${{env.BRANCH_NAME}}.apk
247
- # cp app-x86_64-release.apk test-apk/${{env.BRANCH_NAME}}_x86.apk
353
+ - name: 🔍 Verify AVD Configuration
354
+ run: |
355
+ echo "=== AVD Configuration Check ==="
356
+
357
+ # Check if AVD directory exists
358
+ echo "Checking AVD directory..."
359
+ ls -la ~/.android/avd/ || echo "AVD directory not found"
360
+
361
+ # List available AVDs
362
+ echo "Available AVDs:"
363
+ emulator -list-avds || echo "Failed to list AVDs"
364
+
365
+ # Check Android SDK location
366
+ echo "Android SDK location:"
367
+ echo $ANDROID_HOME
368
+ echo $ANDROID_SDK_ROOT
369
+
370
+ # Check emulator binary
371
+ echo "Emulator binary:"
372
+ which emulator || echo "Emulator not found in PATH"
373
+ emulator -version || echo "Failed to get emulator version"
374
+
375
+ echo "=== AVD Check Complete ==="
376
249
- # - name: Upload Artifact
250
- # uses: kittaakos/upload-artifact-as-is@v0
251
- # with:
252
- # path: /opt/android/cake_wallet/build/app/outputs/flutter-apk/test-apk/
377
+ - name: 🦾 Enable KVM
378
+ run: |
379
+ echo "=== KVM Setup and Verification ==="
380
+
381
+ # Check if KVM device exists
382
+ if [ -e /dev/kvm ]; then
383
+ echo "✅ KVM device found at /dev/kvm"
384
+
385
+ # Check current permissions
386
+ echo "Current KVM permissions:"
387
+ ls -la /dev/kvm
388
+
389
+ # Set proper permissions
390
+ sudo chmod 666 /dev/kvm || echo "⚠️ Failed to set KVM permissions"
391
+
392
+ # Verify permissions were set
393
+ if [ -r /dev/kvm ] && [ -w /dev/kvm ]; then
394
+ echo "✅ KVM is readable and writable"
395
+ else
396
+ echo "⚠️ KVM permissions may not be optimal"
397
+ fi
398
+
399
+ # Test KVM functionality
400
+ echo "Testing KVM functionality..."
401
+ if command -v kvm-ok >/dev/null 2>&1; then
402
+ if kvm-ok 2>/dev/null; then
403
+ echo "✅ KVM is working properly"
404
+ else
405
+ echo "⚠️ KVM check failed, but continuing..."
406
+ fi
407
+ else
408
+ echo "ℹ️ kvm-ok command not available, testing manually..."
409
+ # Manual KVM test
410
+ if [ -r /dev/kvm ] && [ -w /dev/kvm ]; then
411
+ echo "✅ KVM device is accessible"
412
+ fi
413
+ fi
414
+
415
+ # Try to create udev rules (may fail in container, that's OK)
416
+ echo "Setting up udev rules..."
417
+ sudo mkdir -p /etc/udev/rules.d || echo "⚠️ Could not create udev directory"
418
+ echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules || echo "⚠️ Could not create udev rule"
419
+
420
+ # Try to reload udev rules (will likely fail in container, that's OK)
421
+ sudo udevadm control --reload-rules || echo "ℹ️ udevadm control failed (expected in container)"
422
+ sudo udevadm trigger --name-match=kvm || echo "ℹ️ udevadm trigger failed (expected in container)"
423
+
424
+ else
425
+ echo "❌ KVM device not found at /dev/kvm"
426
+ echo "This will cause the emulator to run in software mode (slower)"
427
+ fi
428
+
429
+ # Check system resources
430
+ echo "=== System Resources ==="
431
+ echo "Memory:"
432
+ free -h
433
+ echo "Disk space:"
434
+ df -h
435
+ echo "CPU cores:"
436
+ nproc
437
+ echo "KVM module loaded:"
438
+ lsmod | grep kvm || echo "KVM module not loaded (may be built-in)"
439
+
440
+ echo "=== KVM Setup Complete ==="
441
254
- # - name: Send Test APK
255
- # continue-on-error: true
256
- # uses: adrey/slack-file-upload-action@1.0.5
257
- # with:
258
- # token: ${{ secrets.SLACK_APP_TOKEN }}
259
- # path: /opt/android/cake_wallet/build/app/outputs/flutter-apk/test-apk/${{env.BRANCH_NAME}}.apk
260
- # channel: ${{ secrets.SLACK_APK_CHANNEL }}
261
- # title: "${{ env.BRANCH_NAME }}.apk"
262
- # filename: ${{ env.BRANCH_NAME }}.apk
263
- # initial_comment: ${{ github.event.head_commit.message }}
442
+ - name: 🦾 Cache gradle
443
+ uses: gradle/actions/setup-gradle@v3
444
265
- - name: 🦾 Enable KVM
266
- run: |
267
- echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
268
- sudo udevadm control --reload-rules
269
- sudo udevadm trigger --name-match=kvm
445
+ - name: 🦾 Cache AVD
446
+ uses: actions/cache@v4
447
+ id: avd-cache
448
+ with:
449
+ path: |
450
+ ~/.android/avd/*
451
+ ~/.android/adb*
452
+ key: avd-${{ matrix.api-level }}
453
271
- - name: 🦾 Cache gradle
272
- uses: gradle/actions/setup-gradle@v3
454
+ - name: 🔧 Prepare emulator utilities
455
+ run: |
456
+ # Create a helper script for emulator readiness checks
457
+ cat > /tmp/emulator_ready.sh << 'EOF'
458
+ #!/bin/bash
459
+
460
+ echo "=== Emulator Readiness Check ==="
461
+
462
+ # Wait for boot completion
463
+ echo "1. Checking boot completion..."
464
+ timeout 300 bash -c 'until adb shell getprop sys.boot_completed 2>/dev/null | grep -q "1"; do sleep 5; echo " Waiting for boot completion..."; done'
465
+ if [ $? -eq 0 ]; then
466
+ echo "✅ Boot completed"
467
+ else
468
+ echo "❌ Boot completion timeout"
469
+ echo "⚠️ Continuing anyway..."
470
+ fi
471
+
472
+ # Wait for input service
473
+ echo "2. Checking input service..."
474
+ timeout 60 bash -c 'until adb shell service list 2>/dev/null | grep -q "input"; do sleep 2; echo " Waiting for input service..."; done'
475
+ if [ $? -eq 0 ]; then
476
+ echo "✅ Input service ready"
477
+ else
478
+ echo "❌ Input service timeout"
479
+ echo "⚠️ Continuing anyway..."
480
+ fi
481
+
482
+ # Wait for package manager
483
+ echo "3. Checking package manager..."
484
+ timeout 60 bash -c 'until adb shell pm list packages 2>/dev/null >/dev/null; do sleep 2; echo " Waiting for package manager..."; done'
485
+ if [ $? -eq 0 ]; then
486
+ echo "✅ Package manager ready"
487
+ else
488
+ echo "❌ Package manager timeout"
489
+ echo "⚠️ Continuing anyway..."
490
+ fi
491
+
492
+ # Wait for settings service
493
+ echo "4. Checking settings service..."
494
+ timeout 60 bash -c 'until adb shell settings get global window_animation_scale 2>/dev/null >/dev/null; do sleep 2; echo " Waiting for settings service..."; done'
495
+ if [ $? -eq 0 ]; then
496
+ echo "✅ Settings service ready"
497
+ else
498
+ echo "❌ Settings service timeout"
499
+ echo "⚠️ Continuing anyway..."
500
+ fi
501
+
502
+ echo "✅ Emulator readiness check completed"
503
+ EOF
504
+
505
+ chmod +x /tmp/emulator_ready.sh
506
274
- - name: 🦾 Cache AVD
275
- uses: actions/cache@v4
276
- id: avd-cache
277
- with:
278
- path: |
279
- ~/.android/avd/*
280
- ~/.android/adb*
281
- key: avd-${{ matrix.api-level }}
507
+ - name: 🦾 Create AVD and generate snapshot for caching
508
+ if: steps.avd-cache.outputs.cache-hit != 'true'
509
+ uses: reactivecircus/android-emulator-runner@v2
510
+ with:
511
+ api-level: ${{ matrix.api-level }}
512
+ force-avd-creation: false
513
+ # arch: ${{ matrix.arch }}
514
+ emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -read-only -memory 1024 -no-snapshot-save
515
+ working-directory: ${{ github.workspace }}
516
+ disable-animations: false
517
+ script: |
518
+ echo "=== AVD Snapshot Generation ==="
519
+
520
+ # Use the helper script to ensure emulator is fully ready
521
+ /tmp/emulator_ready.sh
522
+
523
+ # Manually disable animations with error handling
524
+ echo "Disabling animations manually..."
525
+ adb shell settings put global window_animation_scale 0.0 || echo "Failed to disable window animations"
526
+ adb shell settings put global transition_animation_scale 0.0 || echo "Failed to disable transition animations"
527
+ adb shell settings put global animator_duration_scale 0.0 || echo "Failed to disable animator duration"
528
+
529
+ echo "=== Checking emulator status before termination ==="
530
+ adb devices || echo "ADB devices check failed"
531
+ echo "=== AVD snapshot generation complete ==="
532
283
- - name: 🦾 Create AVD and generate snapshot for caching
284
- if: steps.avd-cache.outputs.cache-hit != 'true'
285
- uses: reactivecircus/android-emulator-runner@v2
286
- with:
287
- api-level: ${{ matrix.api-level }}
288
- force-avd-creation: false
289
- # arch: ${{ matrix.arch }}
290
- emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
291
- working-directory: /opt/android/cake_wallet
292
- disable-animations: false
293
- script: echo "Generated AVD snapshot for caching."
533
+ - name: 🚀 Integration tests on Android Emulator
534
+ timeout-minutes: 60
535
+ uses: reactivecircus/android-emulator-runner@v2
536
+ with:
537
+ api-level: ${{ matrix.api-level }}
538
+ force-avd-creation: false
539
+ emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -read-only -memory 1024 -no-snapshot-save
540
+ disable-animations: false
541
+ working-directory: ${{ github.workspace }}
542
+ script: |
543
+ echo "=== Pre-test Environment Check ==="
544
+ pwd
545
+ ls -la integration_test_runner.sh || echo "integration_test_runner.sh not found"
546
+
547
+ echo "=== Emulator Status Check ==="
548
+ adb devices
549
+
550
+ echo "=== Emulator Info ==="
551
+ adb shell getprop ro.build.version.release || echo "Failed to get Android version"
552
+ adb shell getprop ro.product.model || echo "Failed to get device model"
553
+
554
+ echo "=== Checking Emulator Performance ==="
555
+ adb shell cat /proc/cpuinfo | grep -i "model name" | head -1 || echo "Could not check CPU info"
556
+ adb shell cat /proc/meminfo | grep -i "memtotal" || echo "Could not check memory info"
557
+
558
+ echo "=== Checking Emulator Process ==="
559
+ ps aux | grep emulator | grep -v grep || echo "Emulator process not found in ps output"
560
+
561
+ echo "=== Making script executable ==="
562
+ chmod a+rx integration_test_runner.sh
563
+
564
+ echo "=== Running integration tests ==="
565
+
566
+ echo "Final emulator readiness check..."
567
+ /tmp/emulator_ready.sh || echo "Emulator readiness check failed, but continuing..."
568
+
569
+ echo "Disabling animations for test performance..."
570
+ adb shell settings put global window_animation_scale 0.0 || echo "Failed to disable window animations"
571
+ adb shell settings put global transition_animation_scale 0.0 || echo "Failed to disable transition animations"
572
+ adb shell settings put global animator_duration_scale 0.0 || echo "Failed to disable animator duration"
573
+
574
+ echo "Starting integration test runner..."
575
+ ./integration_test_runner.sh
576
+ TEST_EXIT_CODE=$?
577
+
578
+ if [ $TEST_EXIT_CODE -eq 0 ]; then
579
+ echo "Integration tests completed successfully"
580
+ else
581
+ echo "Integration tests failed with exit code $TEST_EXIT_CODE"
582
+ fi
583
295
- - name: 🚀 Integration tests on Android Emulator
296
- uses: reactivecircus/android-emulator-runner@v2
297
- with:
298
- api-level: ${{ matrix.api-level }}
299
- force-avd-creation: false
300
- emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
301
- disable-animations: true
302
- working-directory: /opt/android/cake_wallet
303
- script: |
304
- chmod a+rx integration_test_runner.sh
305
- ./integration_test_runner.sh
584
+ - name: 🧹 Post-test cleanup
585
+ if: always()
586
+ run: |
587
+ echo "=== Post-test cleanup ==="
588
+ # Kill any remaining emulator processes
589
+ pkill -f emulator || echo "No emulator processes to kill"
590
+ # Kill any remaining adb processes
591
+ pkill -f adb || echo "No adb processes to kill"
592
+ # Wait for processes to terminate
593
+ sleep 2
594
+ # Check for any remaining processes
595
+ ps aux | grep -E "(emulator|adb)" | grep -v grep || echo "No remaining emulator/adb processes"
596
+ echo "=== Cleanup complete ==="
597
+ - name: cleanup
598
+ run: rm -rf build/app/outputs/flutter-apk/test-apk/