# Expected secrets # EMULATOR_WTF_API_KEY - Optional API key for emulator.wtf # FIREBASE_TEST_LAB_SERVICE_ACCOUNT - Email address of Firebase Test Lab service account # FIREBASE_TEST_LAB_WORKLOAD_IDENTITY_PROVIDER - Workload identity provider to generate temporary service account key # Expected variables # FIREBASE_TEST_LAB_PROJECT - Firebase Test Lab project name name: Pull Request on: pull_request: paths-ignore: - '.github/ISSUE_TEMPLATE/*' - '.github/PULL_REQUEST_TEMPLATE.md' - 'LICENSE' - 'README.md' - 'docs/**' concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: validate_gradle_wrapper: runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout timeout-minutes: 1 uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # Gradle Wrapper validation can be flaky # https://github.com/gradle/wrapper-validation-action/issues/40 - name: Gradle Wrapper Validation timeout-minutes: 1 uses: gradle/wrapper-validation-action@5188e9b5527a0a094cee21e2fe9a8ca44b4629af check_firebase_secrets: runs-on: ubuntu-latest outputs: has-secrets: ${{ steps.check_firebase_secrets.outputs.defined }} steps: - id: check_firebase_secrets env: FIREBASE_TEST_LAB_PROJECT: ${{ vars.FIREBASE_TEST_LAB_PROJECT }} FIREBASE_TEST_LAB_SERVICE_ACCOUNT: ${{ secrets.FIREBASE_TEST_LAB_SERVICE_ACCOUNT }} FIREBASE_TEST_LAB_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.FIREBASE_TEST_LAB_WORKLOAD_IDENTITY_PROVIDER }} if: "${{ env.FIREBASE_TEST_LAB_PROJECT != '' && env.FIREBASE_TEST_LAB_SERVICE_ACCOUNT != '' && env.FIREBASE_TEST_LAB_WORKLOAD_IDENTITY_PROVIDER != '' }}" run: echo "defined=true" >> $GITHUB_OUTPUT check_emulator_wtf_secrets: runs-on: ubuntu-latest outputs: has-secrets: ${{ steps.check_emulator_wtf_secrets.outputs.defined }} steps: - id: check_emulator_wtf_secrets env: EMULATOR_WTF_API_KEY: ${{ secrets.EMULATOR_WTF_API_KEY }} if: "${{ env.EMULATOR_WTF_API_KEY != '' }}" run: echo "defined=true" >> $GITHUB_OUTPUT check_properties: needs: validate_gradle_wrapper runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout timeout-minutes: 1 uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f - name: Setup id: setup timeout-minutes: 10 uses: ./.github/actions/setup - name: Check properties timeout-minutes: 4 run: | ./gradlew checkProperties static_analysis_detekt: needs: validate_gradle_wrapper runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout timeout-minutes: 1 uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f - name: Setup id: setup timeout-minutes: 30 uses: ./.github/actions/setup - name: Detekt timeout-minutes: 4 run: | ./gradlew detektAll - name: Collect Artifacts timeout-minutes: 1 if: ${{ always() }} env: ARTIFACTS_DIR_PATH: ${{ format('{0}/artifacts', env.home) }} REPORTS_ZIP_PATH: ${{ format('{0}/artifacts/static_analysis_detekt.zip', env.home) }} run: | mkdir ${ARTIFACTS_DIR_PATH} zip -r ${REPORTS_ZIP_PATH} . -i build/reports/detekt/\* - name: Upload Artifacts if: ${{ always() }} uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 timeout-minutes: 1 with: name: Detekt static analysis results path: ~/artifacts static_analysis_ktlint: needs: validate_gradle_wrapper runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout timeout-minutes: 1 uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f - name: Setup id: setup timeout-minutes: 30 uses: ./.github/actions/setup - name: Ktlint timeout-minutes: 4 run: | ./gradlew ktlint - name: Collect Artifacts timeout-minutes: 1 if: ${{ always() }} env: ARTIFACTS_DIR_PATH: ${{ format('{0}/artifacts', env.home) }} REPORTS_ZIP_PATH: ${{ format('{0}/artifacts/static_analysis_ktlint.zip', env.home) }} run: | mkdir ${ARTIFACTS_DIR_PATH} zip -r ${REPORTS_ZIP_PATH} . -i build/reports/ktlint/\* - name: Upload Artifacts if: ${{ always() }} uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 timeout-minutes: 1 with: name: Ktlint static analysis results path: ~/artifacts static_analysis_android_lint: needs: validate_gradle_wrapper runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout timeout-minutes: 1 uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f - name: Setup id: setup timeout-minutes: 30 uses: ./.github/actions/setup - name: Android Lint timeout-minutes: 25 env: # Disable minify, since it makes lint run faster ORG_GRADLE_PROJECT_IS_MINIFY_APP_ENABLED: false run: | ./gradlew :sdk-lib:lintRelease :demo-app:lintZcashmainnetRelease - name: Collect Artifacts if: ${{ always() }} timeout-minutes: 1 env: ARTIFACTS_DIR_PATH: ${{ format('{0}/artifacts', env.home) }} LINT_ZIP_PATH: ${{ format('{0}/artifacts/android_lint.zip', env.home) }} run: | mkdir ${ARTIFACTS_DIR_PATH} zip -r ${LINT_ZIP_PATH} . -i \*build/reports/\* - name: Upload Artifacts if: ${{ always() }} uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 timeout-minutes: 1 with: name: Android Lint static analysis results path: ~/artifacts test_android_modules_unit: needs: [ validate_gradle_wrapper ] runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout timeout-minutes: 1 uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f - name: Setup id: setup timeout-minutes: 30 uses: ./.github/actions/setup - name: Build and test timeout-minutes: 30 run: | ./gradlew test - name: Collect Artifacts if: ${{ always() }} timeout-minutes: 1 env: ARTIFACTS_DIR_PATH: ${{ format('{0}/artifacts', env.home) }} TEST_RESULTS_ZIP_PATH: ${{ format('{0}/artifacts/test_results.zip', env.home) }} run: | mkdir ${ARTIFACTS_DIR_PATH} zip -r ${TEST_RESULTS_ZIP_PATH} . -i \*/build/test-results/\* \*/build/reports/\* - name: Upload Artifacts if: ${{ always() }} uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 timeout-minutes: 1 with: name: Test Android modules with Unit Tests path: ~/artifacts # Emulator.wtf is preferred if it has an API key. test_android_modules_ftl: if: needs.check_firebase_secrets.outputs.has-secrets == 'true' && needs.check_emulator_wtf_secrets.outputs.has-secrets == 'false' needs: [validate_gradle_wrapper, check_firebase_secrets, check_emulator_wtf_secrets] runs-on: ubuntu-latest permissions: contents: read id-token: write steps: - name: Checkout timeout-minutes: 1 uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f - name: Setup id: setup timeout-minutes: 30 uses: ./.github/actions/setup - name: Build timeout-minutes: 20 run: | ./gradlew assembleDebug assembleAndroidTest - name: Authenticate to Google Cloud for Firebase Test Lab id: auth_test_lab uses: google-github-actions/auth@55bd3a7c6e2ae7cf1877fd1ccb9d54c0503c457c with: create_credentials_file: true project_id: ${{ vars.FIREBASE_TEST_LAB_PROJECT }} service_account: ${{ secrets.FIREBASE_TEST_LAB_SERVICE_ACCOUNT }} workload_identity_provider: ${{ secrets.FIREBASE_TEST_LAB_WORKLOAD_IDENTITY_PROVIDER }} access_token_lifetime: '1200s' - name: Test timeout-minutes: 30 env: # This first environment variable is used by Flank, since the temporary token is missing the project name GOOGLE_CLOUD_PROJECT: ${{ vars.FIREBASE_TEST_LAB_PROJECT }} ORG_GRADLE_PROJECT_ZCASH_FIREBASE_TEST_LAB_API_KEY_PATH: ${{ steps.auth_test_lab.outputs.credentials_file_path }} # Because Fulladle doesn't allow Test Orchestrator to be enabled/disabled for a specific submodule, it must be enabled for all modules ORG_GRADLE_PROJECT_IS_USE_TEST_ORCHESTRATOR: true run: | ./gradlew runFlank --parallel - name: Collect Artifacts if: ${{ always() }} timeout-minutes: 1 env: ARTIFACTS_DIR_PATH: ${{ format('{0}/artifacts', env.home) }} TEST_RESULTS_ZIP_PATH: ${{ format('{0}/artifacts/test_results.zip', env.home) }} run: | mkdir ${ARTIFACTS_DIR_PATH} zip -r ${TEST_RESULTS_ZIP_PATH} . -i build/fladle/\* \*/build/outputs/androidTest-results/\* - name: Upload Artifacts if: ${{ always() }} uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 timeout-minutes: 1 with: name: Test Android modules with FTL results path: ~/artifacts test_android_modules_wtf: if: needs.check_emulator_wtf_secrets.outputs.has-secrets == 'true' needs: [ validate_gradle_wrapper, check_emulator_wtf_secrets ] runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout timeout-minutes: 1 uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f - name: Setup id: setup timeout-minutes: 30 uses: ./.github/actions/setup - name: Build and test timeout-minutes: 30 env: ORG_GRADLE_PROJECT_ZCASH_EMULATOR_WTF_API_KEY: ${{ secrets.EMULATOR_WTF_API_KEY }} run: | ./gradlew testDebugWithEmulatorWtf - name: Collect Artifacts if: ${{ always() }} timeout-minutes: 1 env: ARTIFACTS_DIR_PATH: ${{ format('{0}/artifacts', env.home) }} TEST_RESULTS_ZIP_PATH: ${{ format('{0}/artifacts/test_results.zip', env.home) }} run: | mkdir ${ARTIFACTS_DIR_PATH} zip -r ${TEST_RESULTS_ZIP_PATH} . -i \*/build/test-results/\* - name: Upload Artifacts if: ${{ always() }} uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 timeout-minutes: 1 with: name: Test Android modules with WTF results path: ~/artifacts demo_app_release_build: needs: validate_gradle_wrapper runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout timeout-minutes: 1 uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f - name: Setup id: setup timeout-minutes: 30 uses: ./.github/actions/setup # A fake signing key to satisfy creating a "release" build - name: Export Signing Key env: SIGNING_KEY_PATH: ${{ format('{0}/release.jks', env.home) }} shell: bash run: | keytool -genkey -v -keystore $SIGNING_KEY_PATH -keypass android -storepass android -alias androiddebugkey -keyalg RSA -keysize 2048 -validity 100000 -dname "CN=, OU=, O=Test, L=, S=, C=" -noprompt - name: Build timeout-minutes: 45 env: ORG_GRADLE_PROJECT_ZCASH_RELEASE_KEYSTORE_PATH: ${{ format('{0}/release.jks', env.home) }} ORG_GRADLE_PROJECT_ZCASH_RELEASE_KEYSTORE_PASSWORD: android ORG_GRADLE_PROJECT_ZCASH_RELEASE_KEY_ALIAS: androiddebugkey ORG_GRADLE_PROJECT_ZCASH_RELEASE_KEY_ALIAS_PASSWORD: android run: | ./gradlew assembleRelease - name: Collect Artifacts timeout-minutes: 1 env: ARTIFACTS_DIR_PATH: ${{ format('{0}/artifacts', env.home) }} BINARIES_ZIP_PATH: ${{ format('{0}/artifacts/binaries.zip', env.home) }} MAPPINGS_ZIP_PATH: ${{ format('{0}/artifacts/mappings.zip', env.home) }} run: | mkdir ${ARTIFACTS_DIR_PATH} zip -r ${BINARIES_ZIP_PATH} . -i demo-app/build/outputs/apk/\*/release/\*.apk demo-app/build/outputs/bundle/\*/release/\*.aab zip -r ${MAPPINGS_ZIP_PATH} . -i demo-app/build/outputs/mapping/\*/mapping.txt - name: Upload Artifacts uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 timeout-minutes: 1 with: name: Demo app release binaries path: ~/artifacts # Performs a button mash test on the release build of the demo app test_robo_demo_app: if: needs.check_firebase_secrets.outputs.has-secrets == 'true' needs: [demo_app_release_build, check_firebase_secrets] runs-on: ubuntu-latest permissions: packages: read contents: read id-token: write steps: - name: Checkout timeout-minutes: 1 uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f - name: Setup id: setup timeout-minutes: 30 uses: ./.github/actions/setup - name: Authenticate to Google Cloud for Firebase Test Lab id: auth_test_lab uses: google-github-actions/auth@55bd3a7c6e2ae7cf1877fd1ccb9d54c0503c457c with: create_credentials_file: true project_id: ${{ vars.FIREBASE_TEST_LAB_PROJECT }} service_account: ${{ secrets.FIREBASE_TEST_LAB_SERVICE_ACCOUNT }} workload_identity_provider: ${{ secrets.FIREBASE_TEST_LAB_WORKLOAD_IDENTITY_PROVIDER }} access_token_lifetime: '900s' - name: Download a single artifact uses: actions/download-artifact@9c19ed7fe5d278cd354c7dfd5d3b88589c7e2395 with: name: Demo app release binaries - name: Robo test timeout-minutes: 20 env: # Path depends on `release_build` job, plus path of `Download a single artifact` step BINARIES_ZIP_PATH: binaries.zip # This first environment variable is used by Flank, since the temporary token is missing the project name GOOGLE_CLOUD_PROJECT: ${{ vars.FIREBASE_TEST_LAB_PROJECT }} ORG_GRADLE_PROJECT_ZCASH_FIREBASE_TEST_LAB_API_KEY_PATH: ${{ steps.auth_test_lab.outputs.credentials_file_path }} run: | unzip ${BINARIES_ZIP_PATH} ./gradlew :demo-app:runFlankSanityConfig