| 1 | name: Cake Wallet Linux |
| 2 | |
| 3 | permissions: |
| 4 | contents: read |
| 5 | packages: write |
| 6 | |
| 7 | on: [pull_request] |
| 8 | |
| 9 | defaults: |
| 10 | run: |
| 11 | shell: bash |
| 12 | |
| 13 | jobs: |
| 14 | PR_test_build: |
| 15 | # Fork PRs don't have access to repository secrets, so the generated |
| 16 | # lib/.secrets.g.dart would be empty and the build fails to compile. |
| 17 | # Skip for forks, mirroring the Android workflow's internal-build guard. |
| 18 | if: github.event.pull_request.head.repo.fork == false |
| 19 | runs-on: [Linux, amd64, forlinux] |
| 20 | container: |
| 21 | image: ghcr.io/cake-tech/cake_wallet:debian13-flutter3.41.9-ndkr28-go1.24.1-ruststablenightly |
| 22 | env: |
| 23 | STORE_PASS: test@cake_wallet |
| 24 | KEY_PASS: test@cake_wallet |
| 25 | MONEROC_CACHE_DIR_ROOT: /opt/generic_cache |
| 26 | BRANCH_NAME: ${{ github.head_ref || github.ref_name }} |
| 27 | DESKTOP_FORCE_MOBILE: Y |
| 28 | volumes: |
| 29 | - /opt/cw_cache_linux/root/.cache:/root/.cache |
| 30 | - /opt/cw_cache_linux/root/.ccache:/root/.ccache |
| 31 | - /opt/cw_cache_linux/root/.pub-cache/:/root/.pub-cache |
| 32 | - /opt/cw_cache_linux/root/go/pkg:/root/go/pkg |
| 33 | - /opt/cw_cache_linux/opt/generic_cache:/opt/generic_cache |
| 34 | - /var/run/docker.sock:/var/run/docker.sock |
| 35 | |
| 36 | steps: |
| 37 | - name: Fix github actions messing up $HOME... |
| 38 | run: "echo HOME=/root | sudo tee -a $GITHUB_ENV" |
| 39 | |
| 40 | - name: Log in to GitHub Container Registry |
| 41 | uses: docker/login-action@v3 |
| 42 | with: |
| 43 | registry: ghcr.io |
| 44 | username: ${{ github.actor }} |
| 45 | password: ${{ secrets.GITHUB_TOKEN }} |
| 46 | |
| 47 | - uses: actions/checkout@v4 |
| 48 | with: |
| 49 | ref: ${{ github.event.pull_request.head.sha }} |
| 50 | repository: ${{ github.event.pull_request.head.repo.full_name }} |
| 51 | |
| 52 | - name: Log in to GitHub Container Registry |
| 53 | uses: docker/login-action@v3 |
| 54 | with: |
| 55 | registry: ghcr.io |
| 56 | username: ${{ github.actor }} |
| 57 | password: ${{ secrets.GITHUB_TOKEN }} |
| 58 | |
| 59 | - name: configure git |
| 60 | run: | |
| 61 | git config --global --add safe.directory '*' |
| 62 | git config --global user.email "ci@cakewallet.com" |
| 63 | git config --global user.name "CakeWallet CI" |
| 64 | |
| 65 | - name: Get the full commit message |
| 66 | run: | |
| 67 | FULL_MESSAGE="$(git log -1 --pretty=%B)" |
| 68 | echo "message<<EOF" >> $GITHUB_ENV |
| 69 | echo "$FULL_MESSAGE" >> $GITHUB_ENV |
| 70 | echo "EOF" >> $GITHUB_ENV |
| 71 | |
| 72 | - name: Add secrets |
| 73 | run: | |
| 74 | touch cw_bitcoin/lib/.secrets.g.dart |
| 75 | touch cw_evm/lib/.secrets.g.dart |
| 76 | touch cw_solana/lib/.secrets.g.dart |
| 77 | touch cw_core/lib/.secrets.g.dart |
| 78 | touch cw_nano/lib/.secrets.g.dart |
| 79 | touch cw_tron/lib/.secrets.g.dart |
| 80 | |
| 81 | echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart |
| 82 | echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart |
| 83 | echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart |
| 84 | echo "const nowNodesApiKey = '${{ secrets.EVM_NOWNODES_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart |
| 85 | echo "const blinkApiKey = '${{ secrets.BLINK_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart |
| 86 | echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart |
| 87 | echo "const chainStackApiKey = '${{ secrets.CHAIN_STACK_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart |
| 88 | echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart |
| 89 | |
| 90 | echo "const nano2ApiKey = '${{ secrets.NANO2_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart |
| 91 | echo "const nanoNowNodesApiKey = '${{ secrets.NANO_NOW_NODES_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart |
| 92 | |
| 93 | echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart |
| 94 | echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart |
| 95 | |
| 96 | echo "const breezApiKey = '${{ secrets.BREEZ_API_KEY }}';" >> cw_bitcoin/lib/.secrets.g.dart |
| 97 | |
| 98 | echo "${{ secrets.MAIN_SECRETS_FILE }}" | base64 --decode > lib/.secrets.g.dart |
| 99 | |
| 100 | - name: Build dependencies utilizing ghcr cache |
| 101 | run: | |
| 102 | env \ |
| 103 | CW_DOCKER_REGISTRY=ghcr.io/cake-tech/cake_wallet \ |
| 104 | CW_DOCKER_USE_CLOUD=true \ |
| 105 | ./scripts/linux/docker/build.sh |
| 106 | |
| 107 | - name: Execute Build and Setup Commands |
| 108 | run: | |
| 109 | pushd scripts/linux |
| 110 | source ./app_env.sh cakewallet |
| 111 | ./app_config.sh |
| 112 | popd |
| 113 | |
| 114 | - name: Install Flutter dependencies |
| 115 | run: | |
| 116 | flutter pub get |
| 117 | |
| 118 | - name: Build generated code |
| 119 | run: | |
| 120 | ./model_generator.sh |
| 121 | |
| 122 | - name: Generate localization |
| 123 | run: | |
| 124 | dart run tool/generate_localization.dart |
| 125 | |
| 126 | - name: Compile graphics |
| 127 | run: | |
| 128 | ./compile_graphics.sh |
| 129 | |
| 130 | - name: Build linux |
| 131 | run: | |
| 132 | flutter build linux --dart-define=hasDevOptions=true --release |
| 133 | |
| 134 | - name: Compress release |
| 135 | run: | |
| 136 | pushd build/linux/x64/release |
| 137 | zip -r cakewallet_linux.zip bundle |
| 138 | popd |
| 139 | |
| 140 | - name: Upload Artifact to github |
| 141 | uses: actions/upload-artifact@v4 |
| 142 | with: |
| 143 | path: ${{ github.workspace }}/build/linux/x64/release/cakewallet_linux.zip |
| 144 | name: cakewallet_linux |
| 145 | |
| 146 | - name: Prepare virtual desktop |
| 147 | if: ${{ contains(env.message, 'run tests') }} |
| 148 | run: | |
| 149 | nohup Xvfb :99 -screen 0 720x1280x16 & |
| 150 | echo DISPLAY=:99 | sudo tee -a $GITHUB_ENV |
| 151 | dbus-daemon --system --fork |
| 152 | nohup NetworkManager & |
| 153 | nohup ffmpeg -framerate 60 -video_size 720x1280 -f x11grab -i :99 -c:v libx264 -c:a aac /opt/screen_grab.mkv & |
| 154 | |
| 155 | # Note for people adding tests: |
| 156 | # - Tests are ran on Linux, with some things being mocked out. |
| 157 | # - Screen recording is being provided for the entire length of the test, you can download it in github articats. |
| 158 | # - Screen recordeding is encrypted, look at step "Stop screen recording, encrypt and upload", and add your key if you want |
| 159 | # Reason for encryption is the fact that we restore the wallet from seed, and we don't want to leak that, while there |
| 160 | # isn't much in those wallets anyway, we still wouldn't like to leak it to anyone who is able to access github. |
| 161 | |
| 162 | - name: Test [confirm_seeds_flow_test] |
| 163 | if: ${{ contains(env.message, 'run tests') }} |
| 164 | timeout-minutes: 20 |
| 165 | run: | |
| 166 | xmessage -timeout 30 "confirm_seeds_flow_test" & |
| 167 | rm -rf ~/.local/share/com.example.cake_wallet/ ~/Documents/cake_wallet/ ~/cake_wallet |
| 168 | exec timeout --signal=SIGKILL 900 flutter drive --driver=test_driver/integration_test.dart --target=integration_test/test_suites/confirm_seeds_flow_test.dart |
| 169 | |
| 170 | - name: Test [create_wallet_flow_test] |
| 171 | if: ${{ contains(env.message, 'run tests') }} |
| 172 | timeout-minutes: 20 |
| 173 | run: | |
| 174 | xmessage -timeout 30 "create_wallet_flow_test" & |
| 175 | rm -rf ~/.local/share/com.example.cake_wallet/ ~/Documents/cake_wallet/ ~/cake_wallet |
| 176 | exec timeout --signal=SIGKILL 900 flutter drive --driver=test_driver/integration_test.dart --target=integration_test/test_suites/create_wallet_flow_test.dart |
| 177 | |
| 178 | # - name: Test [exchange_flow_test] |
| 179 | # if: ${{ contains(env.message, 'run tests') }} |
| 180 | # timeout-minutes: 20 |
| 181 | # run: | |
| 182 | # xmessage -timeout 30 "exchange_flow_test" & |
| 183 | # rm -rf ~/.local/share/com.example.cake_wallet/ ~/Documents/cake_wallet/ ~/cake_wallet |
| 184 | # exec timeout --signal=SIGKILL 900 flutter drive --driver=test_driver/integration_test.dart --target=integration_test/test_suites/exchange_flow_test.dart |
| 185 | |
| 186 | - name: Test [restore_wallet_through_seeds_flow_test] |
| 187 | if: ${{ contains(env.message, 'run tests') }} |
| 188 | timeout-minutes: 20 |
| 189 | run: | |
| 190 | xmessage -timeout 30 "restore_wallet_through_seeds_flow_test" & |
| 191 | rm -rf ~/.local/share/com.example.cake_wallet/ ~/Documents/cake_wallet/ ~/cake_wallet |
| 192 | exec timeout --signal=SIGKILL 900 flutter drive --driver=test_driver/integration_test.dart --target=integration_test/test_suites/restore_wallet_through_seeds_flow_test.dart |
| 193 | |
| 194 | - name: Test [cw_core] |
| 195 | timeout-minutes: 15 |
| 196 | run: cd cw_core && flutter test |
| 197 | |
| 198 | - name: Test [cw_monero] |
| 199 | timeout-minutes: 15 |
| 200 | run: cd cw_monero && flutter test |
| 201 | |
| 202 | - name: Stop screen recording, encrypt and upload |
| 203 | if: always() |
| 204 | run: | |
| 205 | if [[ ! -f "/opt/screen_grab.mkv" ]]; |
| 206 | then |
| 207 | exit 0; |
| 208 | fi |
| 209 | killall ffmpeg |
| 210 | sleep 5 |
| 211 | killall -9 ffmpeg || true |
| 212 | sleep 5 |
| 213 | # Feel free to add your own public key if you wish |
| 214 | gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys 6B3199AD9B3D23B8 # konstantin@cakewallet.com |
| 215 | gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys 35C8DBAFB8D9ACAC # cyjan@mrcyjanek.net |
| 216 | gpg --trust-model always --encrypt --output /opt/screen_grab.mkv.gpg \ |
| 217 | --recipient 6B3199AD9B3D23B8 \ |
| 218 | --recipient 35C8DBAFB8D9ACAC \ |
| 219 | /opt/screen_grab.mkv |
| 220 | rm /opt/screen_grab.mkv |
| 221 | mv /opt/screen_grab.mkv.gpg ./screen_grab.mkv.gpg |
| 222 | |
| 223 | - name: Upload Artifact to github |
| 224 | if: always() |
| 225 | continue-on-error: true |
| 226 | uses: actions/upload-artifact@v4 |
| 227 | with: |
| 228 | path: ${{ github.workspace }}/screen_grab.mkv.gpg |
| 229 | name: tests_screen_grab |