@Mobile • Test App End-2-End triggered by mle-gall on ref feat/LIVE-9792/LLMParentAccountError #11413
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: "@Mobile • Test App End-2-End" | |
run-name: "@Mobile • Test App End-2-End triggered by ${{ inputs.login || github.actor }} ${{ format('on ref {0}', github.ref_name) }}" | |
on: | |
push: | |
branches: | |
- main | |
- develop | |
- release | |
- hotfix | |
workflow_dispatch: | |
inputs: | |
ref: | |
description: | | |
If you run this manually, and want to run on a PR, the correct ref should be refs/pull/{PR_NUMBER}/merge to | |
have the "normal" scenario involving checking out a merge commit between your branch and the base branch. | |
If you want to run only on a branch or specific commit, you can use either the sha or the branch name instead (prefer the first verion for PRs). | |
login: | |
description: The GitHub username that triggered the workflow | |
required: false | |
base_ref: | |
description: The base branch to merge the head into when checking out the code | |
required: false | |
# Uncomment to have log-level: trace on detox run and build | |
# (cf: apps/ledger-live-mobile/detox.config.js) | |
# env: | |
# DEBUG_DETOX: true | |
concurrency: | |
group: ${{ github.workflow }}-${{ github.ref_name != 'develop' && github.ref || github.run_id }} | |
cancel-in-progress: true | |
permissions: | |
id-token: write | |
contents: read | |
jobs: | |
detox-tests-ios: | |
name: "Ledger Live Mobile - iOS Detox Tests" | |
runs-on: [m1, ARM64] | |
env: | |
NODE_OPTIONS: "--max-old-space-size=7168" | |
LANG: en_US.UTF-8 | |
LANGUAGE: en_US.UTF-8 | |
LC_ALL: en_US.UTF-8 | |
outputs: | |
status: ${{ steps.detox.outcome }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
ref: ${{ inputs.ref || github.sha }} | |
- name: Setup the toolchain | |
uses: ./tools/actions/composites/setup-toolchain | |
id: toolchain | |
with: | |
skip_pod_cache: "false" | |
skip_turbo_cache: "false" | |
accountId: ${{ secrets.AWS_ACCOUNT_ID_PROD }} | |
roleName: ${{ secrets.AWS_CACHE_ROLE_NAME }} | |
region: ${{ secrets.AWS_CACHE_REGION }} | |
turbo-server-token: ${{ secrets.TURBOREPO_SERVER_TOKEN }} | |
- name: Install applesimutils | |
run: | | |
brew update | |
brew tap wix/brew | |
brew install applesimutils | |
- name: Cache LLM pods | |
uses: actions/cache@v3 | |
with: | |
path: | | |
apps/ledger-live-mobile/ios/Pods | |
~/Library/Caches/CocoaPods | |
~/.cocoapods | |
key: ${{ runner.os }}-pods-${{ hashFiles('apps/ledger-live-mobile/ios/Podfile.lock') }} | |
- name: cache detox build | |
uses: tespkg/actions-cache@v1 | |
id: detox-build | |
with: | |
path: ${{ github.workspace }}/apps/ledger-live-mobile/ios/build/Build/Products/Release-iphonesimulator | |
key: ${{ runner.os }}-detox-${{ hashFiles('apps/ledger-live-mobile/ios/Podfile.lock', 'apps/ledger-live-mobile/ios/ledgerlivemobile.xcodeproj/project.pbxproj') }} | |
restore-keys: | | |
${{ runner.os }}-detox- | |
accessKey: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} | |
secretKey: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} | |
bucket: ll-gha-s3-cache | |
region: eu-west-1 | |
use-fallback: false | |
- name: install dependencies | |
run: | | |
pnpm i --filter="live-mobile..." --filter="ledger-live" --filter="dummy-*-app..." --no-frozen-lockfile --unsafe-perm | |
- name: Build dependencies | |
run: | | |
pnpm build:llm:deps --api="http://127.0.0.1:${{ steps.toolchain.outputs.port }}" --token="${{ secrets.TURBOREPO_SERVER_TOKEN }}" --team="foo" | |
- name: Build Dummy Live SDK and Dummy Wallet API apps for testing | |
run: | | |
pnpm build:dummy-apps | |
shell: bash | |
- name: Create iOS simulator | |
id: simulator | |
run: | | |
ID=$(xcrun simctl create "iPhone 14" "iPhone 14") | |
echo "id=$ID" >> $GITHUB_OUTPUT | |
- name: Build iOS app for Detox test run | |
if: steps.detox-build.outputs.cache-hit != 'true' | |
run: pnpm mobile e2e:ci -p ios -b | |
- name: Build JS Bundle app for Detox test run | |
if: steps.detox-build.outputs.cache-hit == 'true' | |
run: pnpm mobile e2e:ci -p ios --bundle | |
- name: Test iOS app | |
id: detox | |
timeout-minutes: 45 | |
run: pnpm mobile e2e:ci -p ios -t | |
- name: Delete iOS simulator | |
if: always() | |
run: | | |
xcrun simctl delete ${{ steps.simulator.outputs.id }} | |
- name: Upload test artifacts | |
uses: actions/upload-artifact@v3 | |
if: always() | |
with: | |
name: test-ios-artifacts | |
path: apps/ledger-live-mobile/artifacts | |
- name: Upload Allure report | |
uses: actions/upload-artifact@v3 | |
if: always() | |
with: | |
name: "allure-ios-reports" | |
path: apps/ledger-live-mobile/allure-results | |
allure-report-ios: | |
name: "Allure Reports Export on Server" | |
runs-on: [ledger-live-medium-linux] | |
if: ${{ always() && !cancelled() && github.ref_name == 'develop' }} | |
needs: [detox-tests-ios] | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
ref: ${{ (github.event_name == 'workflow_dispatch' && (inputs.ref || github.ref_name)) || github.sha }} | |
- uses: ./tools/actions/composites/upload-allure-report | |
with: | |
platform: ios | |
login: ${{ secrets.ALLURE_LOGIN }} | |
password: ${{ secrets.ALLURE_PASSWORD }} | |
path: allure-ios-reports | |
detox-tests-android: | |
name: "Ledger Live Mobile - Android Detox Tests" | |
runs-on: [ledger-live-linux-8CPU-32RAM] | |
env: | |
NODE_OPTIONS: "--max-old-space-size=7168" | |
LANG: en_US.UTF-8 | |
LANGUAGE: en_US.UTF-8 | |
LC_ALL: en_US.UTF-8 | |
outputs: | |
status: ${{ steps.detox.outcome }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
ref: ${{ inputs.ref || github.sha }} | |
- name: Setup the toolchain | |
id: toolchain | |
uses: ./tools/actions/composites/setup-toolchain | |
with: | |
skip_turbo_cache: "false" | |
accountId: ${{ secrets.AWS_ACCOUNT_ID_PROD }} | |
roleName: ${{ secrets.AWS_CACHE_ROLE_NAME }} | |
region: ${{ secrets.AWS_CACHE_REGION }} | |
turbo-server-token: ${{ secrets.TURBOREPO_SERVER_TOKEN }} | |
- name: setup JDK 11 | |
uses: actions/setup-java@v3 | |
with: | |
distribution: "zulu" | |
java-version: "11" | |
cache: "gradle" | |
- name: setup Android SDK | |
uses: android-actions/setup-android@v2.0.10 | |
- name: Gradle cache | |
uses: gradle/gradle-build-action@v2 | |
# https://github.blog/changelog/2023-02-23-hardware-accelerated-android-virtualization-on-actions-windows-and-linux-larger-hosted-runners/ | |
- name: Enable KVM group perms | |
run: | | |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules | |
sudo udevadm control --reload-rules | |
sudo udevadm trigger --name-match=kvm | |
- name: Install dependencies | |
run: | | |
pnpm i --filter="live-mobile..." --filter="ledger-live" --filter="dummy-*-app..." --no-frozen-lockfile --unsafe-perm | |
- name: Build dependencies | |
run: | | |
pnpm build:llm:deps --api="http://127.0.0.1:${{ steps.toolchain.outputs.port }}" --token="${{ secrets.TURBOREPO_SERVER_TOKEN }}" --team="foo" | |
- name: Build Dummy Live SDK and Dummy Wallet API apps for testing | |
run: | | |
pnpm build:dummy-apps --api="http://127.0.0.1:${{ steps.toolchain.outputs.port }}" --token="${{ secrets.TURBOREPO_SERVER_TOKEN }}" --team="foo" | |
shell: bash | |
- name: Build Android app for Detox test run | |
run: | | |
pnpm mobile e2e:ci -p android -b | |
- name: cache android emulator | |
uses: tespkg/actions-cache@v1 | |
id: detox-avd | |
with: | |
path: | | |
~/.android/avd/* | |
~/.android/adb* | |
key: ${{ runner.os }}-detox-avd-${{ hashFiles('~/.android/avd/*/config.ini') }} | |
restore-keys: | | |
${{ runner.os }}-detox-avd- | |
# envs set by setup-toolchain | |
accessKey: ${{ env.AWS_ACCESS_KEY_ID }} | |
secretKey: ${{ env.AWS_SECRET_ACCESS_KEY }} | |
sessionToken: ${{ env.AWS_SESSION_TOKEN }} | |
bucket: ll-gha-s3-cache | |
region: ${{ secrets.AWS_CACHE_REGION }} | |
use-fallback: false | |
- name: create AVD and generate snapshot for caching | |
if: steps.detox-avd.outputs.cache-hit != 'true' | |
uses: reactivecircus/android-emulator-runner@v2 | |
with: | |
api-level: 32 | |
arch: x86_64 | |
profile: pixel_6_pro | |
target: google_apis | |
avd-name: "Pixel_6_Pro_API_32" | |
force-avd-creation: true | |
cores: 4 | |
ram-size: 8192M | |
disable-linux-hw-accel: false | |
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none | |
script: ./tools/scripts/wait_emulator_idle.sh | |
- name: Start Emulator and Run Android Tests | |
id: detox | |
uses: reactivecircus/android-emulator-runner@v2 | |
timeout-minutes: 45 | |
env: | |
DETOX_INSTALL_TIMEOUT: 120000 | |
with: | |
api-level: 32 | |
arch: x86_64 | |
profile: pixel_6_pro | |
target: google_apis | |
avd-name: "Pixel_6_Pro_API_32" | |
force-avd-creation: false | |
cores: 4 | |
ram-size: 8192M | |
disable-linux-hw-accel: false | |
emulator-options: -read-only -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none | |
script: pnpm mobile e2e:ci -p android -t | |
- name: Upload test artifacts | |
if: always() | |
uses: actions/upload-artifact@v3 | |
with: | |
name: test-android-artifacts | |
path: apps/ledger-live-mobile/artifacts/ | |
- name: Upload Allure Report | |
uses: actions/upload-artifact@v3 | |
if: always() | |
with: | |
name: "allure-android-reports" | |
path: apps/ledger-live-mobile/allure-results | |
allure-report-android: | |
name: "Allure Reports Export on Server" | |
runs-on: [ledger-live-medium-linux] | |
if: ${{ always() && !cancelled() && github.ref_name == 'develop' }} | |
needs: [detox-tests-android] | |
steps: | |
- name: checkout | |
uses: actions/checkout@v4 | |
with: | |
ref: ${{ (github.event_name == 'workflow_dispatch' && (inputs.ref || github.ref_name)) || github.sha }} | |
- uses: ./tools/actions/composites/upload-allure-report | |
with: | |
platform: android | |
login: ${{ secrets.ALLURE_LOGIN }} | |
password: ${{ secrets.ALLURE_PASSWORD }} | |
path: allure-android-reports | |
report: | |
needs: [detox-tests-android, detox-tests-ios] | |
runs-on: ubuntu-latest | |
if: always() && !cancelled() && github.event_name == 'workflow_dispatch' | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
ref: ${{ inputs.ref || github.sha }} | |
- uses: actions/github-script@v6 | |
name: prepare status | |
id: status | |
with: | |
script: | | |
const fs = require("fs"); | |
const [ owner, repo ] = "${{ github.repository }}".split("/"); | |
const jobs = await github.paginate(github.rest.actions.listJobsForWorkflowRunAttempt, { | |
owner, | |
repo, | |
run_id: "${{ github.run_id }}", | |
attempt_number: "${{ github.run_attempt }}", | |
}); | |
const findJobUrl = os => | |
jobs.find(job => job.name == `Ledger Live Mobile - ${os} Detox Tests`)?.html_url; | |
const keys = { | |
ios: { | |
symbol: "🍏", | |
name: "iOS", | |
jobUrl: findJobUrl("iOS") | |
}, | |
android: { | |
symbol: "🤖", | |
name: "Android", | |
jobUrl: findJobUrl("Android") | |
}, | |
}; | |
const report = { | |
ios: { | |
pass: ${{ needs.detox-tests-ios.outputs.status == 'success' }}, | |
status: "${{ needs.detox-tests-ios.outputs.status }}", | |
}, | |
android: { | |
pass: ${{ needs.detox-tests-android.outputs.status == 'success'}}, | |
status: "${{ needs.detox-tests-android.outputs.status }}", | |
}, | |
}; | |
let summary = `### Detox Tests | |
` | |
summary += `|` | |
const reportKeys = Object.keys(report); | |
const detoxSuccess = Object.entries(report).every(([os, values]) => !!values.pass); | |
reportKeys.forEach((k) => { | |
summary += ` [${keys[k].symbol} ${keys[k].name}](${keys[k].jobUrl}) |`; | |
}); | |
summary += ` | |
|`; | |
for (let i = 0; i < reportKeys.length; i++) { | |
summary += ` :--: |`; | |
} | |
summary += ` | |
|`; | |
Object.entries(report).forEach(([os, values]) => { | |
summary += ` ${values.pass ? "✅" : "❌"} (${values.status}) |`; | |
}); | |
const output = { | |
summary | |
}; | |
fs.writeFileSync("summary.json", JSON.stringify(output), "utf-8"); | |
- uses: actions/upload-artifact@v3 | |
name: upload summary | |
with: | |
name: summary.json | |
path: ${{ github.workspace }}/summary.json | |
report-on-slack: | |
runs-on: ubuntu-latest | |
needs: [detox-tests-android, detox-tests-ios] | |
if: ${{ failure() && github.event_name == 'push' }} | |
steps: | |
- name: format message | |
uses: actions/github-script@v6 | |
id: message | |
with: | |
script: | | |
const fs = require("fs"); | |
const text = `❌ 🍏 Detox tests failed ❌`; | |
const iOSResult = [ | |
{ | |
"type": "header", | |
"text": { | |
"type": "plain_text", | |
"text": `❌ iOS Detox tests failed ❌`, | |
"emoji": true | |
} | |
}, | |
{ | |
"type": "divider" | |
}, | |
{ | |
"type": "section", | |
"text": { | |
"type": "mrkdwn", | |
"text": `😵 Build Failed | |
` | |
} | |
} | |
]; | |
const androidResult = [ | |
{ | |
"type": "header", | |
"text": { | |
"type": "plain_text", | |
"text": `❌ Android Detox tests failed ❌`, | |
"emoji": true | |
} | |
}, | |
{ | |
"type": "divider" | |
}, | |
{ | |
"type": "section", | |
"text": { | |
"type": "mrkdwn", | |
"text": `😵 Build Failed | |
` | |
} | |
} | |
]; | |
const infoBlock = [ | |
{ | |
"type": "divider" | |
}, | |
{ | |
"type": "section", | |
"text": { | |
"type": "mrkdwn", | |
"text": `<https://github.com/LedgerHQ/ledger-live/actions/runs/${{ github.run_id }}|Workflow run> for more informations`, | |
} | |
} | |
]; | |
const blocks = [] | |
.concat(${{ needs.detox-tests-ios.outputs.status == 'success' }} ? [] : iOSResult) | |
.concat(${{ needs.detox-tests-android.outputs.status == 'success' }} ? [] : androidResult) | |
.concat(infoBlock); | |
const result = { | |
text, | |
blocks | |
}; | |
fs.writeFileSync(`./payload-slack-content.json`, JSON.stringify(result, null, 2)); | |
- name: post to a Slack channel | |
id: slack | |
uses: slackapi/slack-github-action@v1.23.0 | |
with: | |
channel-id: "CTMQ0S5SB" | |
payload-file-path: "./payload-slack-content.json" | |
env: | |
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_USER_OAUTH_ACCESS_TOKEN }} | |
- name: post to a Slack channel | |
if: contains(fromJson('["develop", "main"]'), github.ref_name) | |
uses: slackapi/slack-github-action@v1.23.0 | |
with: | |
channel-id: "C05FKJ7DFAP" | |
payload-file-path: "./payload-slack-content.json" | |
env: | |
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_USER_OAUTH_ACCESS_TOKEN }} |