diff --git a/.github/actions/check-files/action.yml b/.github/actions/check-files/action.yml new file mode 100644 index 0000000000..8ae96a11e8 --- /dev/null +++ b/.github/actions/check-files/action.yml @@ -0,0 +1,34 @@ +name: 'Check Files' +description: 'Checks modified files to determine if tests should be run' +outputs: + run_tests: + description: 'Whether tests should be run based on modified files' + value: ${{ steps.check-files.outputs.run_tests }} +runs: + using: "composite" + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: Check modified files + id: check-files + shell: bash + run: | + echo "=============== list modified files ===============" + files=`git diff --name-only HEAD^ HEAD` + echo "$files" + for file in $files; do + if [[ $file != packages/* ]] && ! [[ $file =~ .*\.(lock|yml)$ ]]; then + # if not in packages/ and does not end with .lock or .yml + echo "run_tests=false" >> $GITHUB_OUTPUT + elif [[ $file == .github/ISSUE_TEMPLATE/* ]]; then + echo "run_tests=false" >> $GITHUB_OUTPUT + elif [[ $file =~ .*\.(md|svg|png|webp|gif|txt)$ ]]; then + echo "run_tests=false" >> $GITHUB_OUTPUT + else + echo "run_tests=true" >> $GITHUB_OUTPUT + break + fi + done \ No newline at end of file diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 297edfeb95..00a3a4f2cd 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -14,8 +14,6 @@ on: # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency concurrency: - # github.workflow: name of the workflow - # github.event.pull_request.number || github.ref: pull request number or branch name if not a pull request group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true @@ -24,57 +22,22 @@ env: NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID: ${{ secrets.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID }} THE_GRAPH_NETWORK_API_KEY: ${{ secrets.THE_GRAPH_NETWORK_API_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - IS_HOTFIX: ${{ contains(github.event.pull_request.title, 'hotfix') }} jobs: - check-is-hotfix: - name: Check if PR is hotfix - runs-on: ubuntu-latest - outputs: - is_hotfix: ${{ steps.check-is-hotfix.outputs.is_hotfix }} - - steps: - - name: Make IS_HOTFIX env var global - id: check-is-hotfix - run: | - echo "is_hotfix=${{ env.IS_HOTFIX }}" >> $GITHUB_OUTPUT - check-files: name: Check files + runs-on: ubuntu-latest outputs: run_tests: ${{ steps.check-files.outputs.run_tests }} - runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 2 - - # run tests only if specific files are changed - - name: Check modified files + - uses: actions/checkout@v4 + - uses: ./.github/actions/check-files id: check-files - run: | - echo "=============== list modified files ===============" - files=`git diff --name-only HEAD^ HEAD` - echo "$files" - for file in $files; do - if [[ $file != packages/* ]] && ! [[ $file =~ .*\.(lock|yml)$ ]]; then - # if not in packages/ and does not end with .lock or .yml - echo "run_tests=false" >> $GITHUB_OUTPUT - elif [[ $file == .github/ISSUE_TEMPLATE/* ]]; then - echo "run_tests=false" >> $GITHUB_OUTPUT - elif [[ $file =~ .*\.(md|svg|png|webp|gif|txt)$ ]]; then - echo "run_tests=false" >> $GITHUB_OUTPUT - else - echo "run_tests=true" >> $GITHUB_OUTPUT - break - fi - done - shell: bash build: name: "Build" runs-on: ubuntu-latest + if: needs.check-files.outputs.run_tests == 'true' && ${{ !contains(github.event.pull_request.title, 'hotfix') }} steps: - name: Checkout uses: actions/checkout@v4 @@ -142,145 +105,24 @@ jobs: - name: Check formatting with ESLint run: yarn lint - load-e2e-files: - name: "Load e2e files" - runs-on: ubuntu-latest - needs: [check-is-hotfix] - if: needs.check-is-hotfix.outputs.is_hotfix == 'false' - outputs: - matrix: ${{ steps.set-matrix.outputs.e2eFiles }} - steps: - - name: Checkout - uses: actions/checkout@v4 - - - id: set-matrix - run: echo "e2eFiles=$(node .github/workflows/formatSpecfiles.js | jq . --compact-output)" >> $GITHUB_OUTPUT - - test-e2e: - name: "Test E2E ${{ (matrix.test.type == 'cctp' && 'CCTP') || (matrix.test.orbitTest == '1' && 'with L3') || '' }} - ${{ matrix.test.name }}" - runs-on: ubuntu-latest - needs: [build, check-files, check-is-hotfix, load-e2e-files] - if: needs.check-files.outputs.run_tests == 'true' && needs.check-is-hotfix.outputs.is_hotfix == 'false' - strategy: - fail-fast: false # If one test fails, let the other tests run - matrix: - test: ${{ fromJson(needs.load-e2e-files.outputs.matrix) }} - - steps: - - name: Free Disk Space (Ubuntu) - uses: jlumbroso/free-disk-space@main - with: - # this might remove tools that are actually needed, - # if set to "true" but frees about 6 GB - tool-cache: false - - # all of these default to true, but feel free to set to - # "false" if necessary for your workflow - android: true - dotnet: true - haskell: true - large-packages: true - docker-images: false - swap-storage: true - - - name: Checkout - uses: actions/checkout@v4 - - - name: Install node_modules - uses: OffchainLabs/actions/node-modules/install@main - - - name: Restore build artifacts - uses: ./.github/actions/build-artifacts/restore - - - name: Install cypress - run: yarn cypress install - - - name: Install linux dependencies - run: | - sudo apt-get install --no-install-recommends -y \ - fluxbox \ - xvfb - - - name: Run xvfb and fluxbox - run: | - Xvfb :0 -screen 0 1366x768x24 -listen tcp -ac & - fluxbox & - env: - DISPLAY: :0.0 - - - name: Run nitro testnode - if: matrix.test.type == 'regular' - uses: OffchainLabs/actions/run-nitro-test-node@a20a76172ce524832ac897bef2fa10a62ed81c29 - with: - nitro-testnode-ref: aab133aceadec2e622f15fa438f6327e3165392d - l3-node: ${{ matrix.test.orbitTest == '1' }} - no-l3-token-bridge: ${{ matrix.test.orbitTest == '0' }} - - - name: Run e2e tests via cypress-io/github-action - uses: cypress-io/github-action@8d3918616d8ac34caa2b49afc8b408b6a872a6f5 # pin@v6.7.1 - with: - start: yarn start - command: "yarn test:e2e${{ (matrix.test.type == 'cctp' && ':cctp') || (matrix.test.orbitTest == '1' && ':orbit') || '' }} --browser chromium" - wait-on: http://127.0.0.1:3000 - wait-on-timeout: 120 - spec: ./packages/arb-token-bridge-ui/tests/e2e/specs/* - env: - DISPLAY: :0.0 - TEST_FILE: ${{ matrix.test.file }} - SKIP_METAMASK_SETUP: true - CYPRESS_RECORD_VIDEO: ${{ matrix.test.recordVideo }} - PRIVATE_KEY_CUSTOM: ${{ secrets.E2E_PRIVATE_KEY }} - PRIVATE_KEY_USER: ${{ secrets.E2E_PRIVATE_KEY_USER }} - PRIVATE_KEY_CCTP: ${{ secrets.E2E_PRIVATE_KEY_CCTP }} - NEXT_PUBLIC_IS_E2E_TEST: true - NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} - NEXT_PUBLIC_LOCAL_ETHEREUM_RPC_URL: http://127.0.0.1:8545 - NEXT_PUBLIC_LOCAL_ARBITRUM_RPC_URL: http://127.0.0.1:8547 - NEXT_PUBLIC_LOCAL_L3_RPC_URL: http://127.0.0.1:3347 + e2e-tests: + name: "E2E Tests" + needs: [build, check-files] + uses: ./.github/workflows/e2e-tests.yml + with: + test_type: 'regular' + secrets: inherit - - name: Archive e2e artifacts - uses: actions/upload-artifact@v4 - if: always() - with: - name: e2e-artifacts-pull-request-${{ github.event.pull_request.number }}-commit-${{ github.sha }}-${{ matrix.test.name }}-${{ matrix.test.type }}-${{ matrix.test.orbitTest }} - path: | - ./packages/arb-token-bridge-ui/cypress/videos - ./packages/arb-token-bridge-ui/cypress/screenshots - if-no-files-found: 'ignore' - continue-on-error: true - - name: Throw error if tests failed - if: steps.e2e-run.outputs.status == 'failed' - run: exit 1 - test-e2e-success: name: "Test E2E Success" runs-on: ubuntu-latest - needs: [test-e2e] + needs: [e2e-tests] if: always() steps: - - name: E2E Succeeded - if: needs.test-e2e.result == 'success' || needs.test-e2e.result == 'skipped' - run: echo "nice" + - name: Regular E2E Succeeded + if: needs.e2e-tests.result == 'success' || needs.e2e-tests.result == 'skipped' + run: echo "Regular E2E tests passed" - - name: E2E Failed - if: needs.test-e2e.result != 'success' && needs.test-e2e.result != 'skipped' + - name: Regular E2E Failed + if: needs.e2e-tests.result != 'success' && needs.e2e-tests.result != 'skipped' run: exit 1 - clean-up: - name: "Clean Up" - runs-on: ubuntu-latest - needs: [test-ui] - if: always() - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install gh-actions-cache - run: gh extension install actions/gh-actions-cache - - - name: Delete build artifacts - run: | - if gh actions-cache list | grep build-artifacts-${{ github.run_id }}-${{ github.run_attempt }} - then - gh actions-cache delete build-artifacts-${{ github.run_id }}-${{ github.run_attempt }} --confirm - fi - shell: bash diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml new file mode 100644 index 0000000000..18c1e0c855 --- /dev/null +++ b/.github/workflows/e2e-tests.yml @@ -0,0 +1,120 @@ +name: E2E tests + +on: + workflow_call: + inputs: + test_type: + required: true + type: string + +env: + NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID: ${{ secrets.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID }} + THE_GRAPH_NETWORK_API_KEY: ${{ secrets.THE_GRAPH_NETWORK_API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +jobs: + load-e2e-files: + name: "Load e2e files" + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set-matrix.outputs.e2eFiles }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - id: set-matrix + run: echo "e2eFiles=$(node .github/workflows/formatSpecfiles.js ${{ inputs.test_type }} | jq . --compact-output)" >> $GITHUB_OUTPUT + + test-e2e: + name: "Test E2E - ${{ matrix.test.name }}${{ matrix.test.type == 'orbit' && ' with L3' || ''}}" + needs: [load-e2e-files] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + test: ${{ fromJson(needs.load-e2e-files.outputs.matrix) }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install node_modules + uses: OffchainLabs/actions/node-modules/install@main + + - name: Restore build artifacts + uses: ./.github/actions/build-artifacts/restore + + - name: Install cypress + run: yarn cypress install + + - name: Install linux dependencies + run: | + sudo apt-get install --no-install-recommends -y \ + fluxbox \ + xvfb + + - name: Run xvfb and fluxbox + run: | + Xvfb :0 -screen 0 1366x768x24 -listen tcp -ac & + fluxbox & + env: + DISPLAY: :0.0 + + - name: Run nitro testnode + if: inputs.test_type != 'cctp' + uses: OffchainLabs/actions/run-nitro-test-node@a20a76172ce524832ac897bef2fa10a62ed81c29 + with: + nitro-testnode-ref: aab133aceadec2e622f15fa438f6327e3165392d + l3-node: ${{ matrix.test.type == 'orbit' }} + no-l3-token-bridge: ${{ matrix.test.type != 'orbit' }} + + - name: Run e2e tests via cypress-io/github-action + uses: cypress-io/github-action@8d3918616d8ac34caa2b49afc8b408b6a872a6f5 # pin@v6.7.1 + with: + start: yarn start + command: "yarn test:e2e${{ (matrix.test.type == 'cctp' && ':cctp') || (matrix.test.type == 'orbit' && ':orbit') || '' }} --browser chromium" + wait-on: http://127.0.0.1:3000 + wait-on-timeout: 120 + spec: ./packages/arb-token-bridge-ui/tests/e2e/specs/* + env: + DISPLAY: :0.0 + TEST_FILE: ${{ matrix.test.file }} + SKIP_METAMASK_SETUP: true + CYPRESS_RECORD_VIDEO: ${{ matrix.test.recordVideo }} + PRIVATE_KEY_CUSTOM: ${{ secrets.E2E_PRIVATE_KEY }} + PRIVATE_KEY_USER: ${{ secrets.E2E_PRIVATE_KEY_USER }} + PRIVATE_KEY_CCTP: ${{ secrets.E2E_PRIVATE_KEY_CCTP }} + NEXT_PUBLIC_IS_E2E_TEST: true + NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_LOCAL_ETHEREUM_RPC_URL: http://127.0.0.1:8545 + NEXT_PUBLIC_LOCAL_ARBITRUM_RPC_URL: http://127.0.0.1:8547 + NEXT_PUBLIC_LOCAL_L3_RPC_URL: http://127.0.0.1:3347 + + - name: Archive e2e artifacts + uses: actions/upload-artifact@v4 + if: always() + with: + name: e2e-artifacts-${{ github.sha }}-${{ matrix.test.name }}-${{ inputs.test_type }} + path: | + ./packages/arb-token-bridge-ui/cypress/videos + ./packages/arb-token-bridge-ui/cypress/screenshots + if-no-files-found: 'ignore' + continue-on-error: true + + clean-up: + name: "Clean Up" + runs-on: ubuntu-latest + needs: [test-e2e] + if: always() + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install gh-actions-cache + run: gh extension install actions/gh-actions-cache + - name: Delete build artifacts + run: | + if gh actions-cache list | grep build-artifacts-${{ github.run_id }}-${{ github.run_attempt }} + then + gh actions-cache delete build-artifacts-${{ github.run_id }}-${{ github.run_attempt }} --confirm + fi + shell: bash \ No newline at end of file diff --git a/.github/workflows/formatSpecfiles.js b/.github/workflows/formatSpecfiles.js index 70bd38a3f6..cb7e382bbd 100644 --- a/.github/workflows/formatSpecfiles.js +++ b/.github/workflows/formatSpecfiles.js @@ -1,28 +1,33 @@ #!/usr/bin/env node -const specFiles = require('../../packages/arb-token-bridge-ui/tests/e2e/specfiles.json') -const cctpFiles = require('../../packages/arb-token-bridge-ui/tests/e2e/cctp.json') +const specFiles = require("../../packages/arb-token-bridge-ui/tests/e2e/specfiles.json"); +const cctpFiles = require("../../packages/arb-token-bridge-ui/tests/e2e/cctp.json"); -// For each test in specFiles, add an orbit test -const tests = [] -specFiles.forEach(spec => { - tests.push({ +const tests = []; + +const testType = process.argv[2]; +switch (testType) { + case "regular": { + specFiles.forEach((spec) => { + tests.push({ ...spec, - type: 'regular', - orbitTest: '0', - }) - tests.push({ + type: "regular", + }); + tests.push({ ...spec, - type: 'regular', - orbitTest: '1', - }) -}) - -cctpFiles.forEach(spec => { - tests.push({ + type: "orbit", + }); + }); + break; + } + case "cctp": { + cctpFiles.forEach((spec) => { + tests.push({ ...spec, type: 'cctp', - orbitTest: null, + }) }) -}) + break; + } +} -console.log(JSON.stringify(tests)) \ No newline at end of file +console.log(JSON.stringify(tests)); diff --git a/.github/workflows/run-cctp-tests.yml b/.github/workflows/run-cctp-tests.yml new file mode 100644 index 0000000000..d0be8d5b0f --- /dev/null +++ b/.github/workflows/run-cctp-tests.yml @@ -0,0 +1,82 @@ +name: PR approved workflow + +on: + issue_comment: + types: + - created + pull_request_review: + types: + - submitted + push: + branches: ["master"] + merge_group: + +# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}-cctp + cancel-in-progress: true + +env: + NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID: ${{ secrets.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID }} + THE_GRAPH_NETWORK_API_KEY: ${{ secrets.THE_GRAPH_NETWORK_API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +jobs: + check-files: + name: Check files + runs-on: ubuntu-latest + outputs: + run_tests: ${{ steps.check-files.outputs.run_tests }} + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/check-files + id: check-files + + build: + name: "Build" + runs-on: ubuntu-latest + needs: [check-files] + if: | + (needs.check-files.outputs.run_tests == 'true' && ${{ !contains(github.event.pull_request.title, 'hotfix') }}) || + (contains(github.event.comment.html_url, '/pull/') && github.event.comment.body == '/run-cctp-tests') + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install node_modules + uses: OffchainLabs/actions/node-modules/install@main + + - name: Build + run: yarn build + env: + NEXT_PUBLIC_IS_E2E_TEST: true + NEXT_PUBLIC_INFURA_KEY: ${{ secrets.NEXT_PUBLIC_INFURA_KEY }} + NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID: ${{ secrets.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID }} + THE_GRAPH_NETWORK_API_KEY: ${{ secrets.THE_GRAPH_NETWORK_API_KEY }} + + - name: Cache build artifacts + uses: ./.github/actions/build-artifacts/cache + + cctp-e2e-tests: + name: "CCTP E2E Tests" + needs: [build, check-files] + # Only run CCTP tests when the PR was just approved + uses: ./.github/workflows/e2e-tests.yml + with: + test_type: 'cctp' + secrets: inherit + + test-e2e-success: + name: "Test E2E Success" + runs-on: ubuntu-latest + needs: [cctp-e2e-tests] + if: always() + steps: + - name: Regular E2E Succeeded + if: needs.cctp-e2e-tests.result == 'success' || needs.cctp-e2e-tests.result == 'skipped' + run: echo "Regular E2E tests passed" + + - name: Regular E2E Failed + if: needs.cctp-e2e-tests.result != 'success' && needs.cctp-e2e-tests.result != 'skipped' + run: exit 1