name: Build and Test
on:
    pull_request: {}
    push:
        branches: [develop, staging, master]
concurrency:
    group: ${{ github.workflow }}-${{ github.ref }}
    cancel-in-progress: true
permissions: {} # No permissions required
jobs:
    fetch:
        uses: ./.github/workflows/build_prepare.yaml
        permissions:
            contents: read
        with:
            config: ${{ github.event.pull_request.base.ref == 'develop' && 'element.io/nightly' || 'element.io/release' }}
            version: ${{ github.event.pull_request.base.ref == 'develop' && 'develop' || '' }}

    windows:
        needs: fetch
        name: Windows
        uses: ./.github/workflows/build_windows.yaml
        strategy:
            matrix:
                arch: [x64, ia32]
        with:
            arch: ${{ matrix.arch }}

    linux:
        needs: fetch
        name: "Linux (${{ matrix.arch }}) (sqlcipher: ${{ matrix.sqlcipher }})"
        uses: ./.github/workflows/build_linux.yaml
        strategy:
            matrix:
                sqlcipher: [system, static]
                arch: [amd64, arm64]
        with:
            config: ${{ github.event.pull_request.base.ref == 'develop' && 'element.io/nightly' || 'element.io/release' }}
            sqlcipher: ${{ matrix.sqlcipher }}
            arch: ${{ matrix.arch }}

    macos:
        needs: fetch
        name: macOS
        uses: ./.github/workflows/build_macos.yaml

    test:
        needs:
            - macos
            - linux
            - windows
        strategy:
            matrix:
                include:
                    - name: macOS Universal
                      os: macos-14
                      artifact: macos
                      executable: "/Users/runner/Applications/Element.app/Contents/MacOS/Element"
                      # We need to mount the DMG and copy the app to the Applications folder as a mounted DMG is
                      # read-only and thus would not allow us to override the fuses as is required for Playwright.
                      prepare_cmd: |
                          hdiutil attach ./dist/*.dmg -mountpoint /Volumes/Element &&
                          rsync -a /Volumes/Element/Element.app ~/Applications/ &&
                          hdiutil detach /Volumes/Element
                    - name: "Linux (amd64) (sqlcipher: system)"
                      os: ubuntu-22.04
                      artifact: linux-amd64-sqlcipher-system
                      executable: "/opt/Element/element-desktop"
                      prepare_cmd: "sudo apt-get -qq update && sudo apt install ./dist/*.deb"
                    - name: "Linux (amd64) (sqlcipher: static)"
                      os: ubuntu-22.04
                      artifact: linux-amd64-sqlcipher-static
                      executable: "/opt/Element/element-desktop"
                      prepare_cmd: "sudo apt-get -qq update && sudo apt install ./dist/*.deb"
                    - name: "Linux (arm64) (sqlcipher: system)"
                      os: dind-l-arm64
                      artifact: linux-arm64-sqlcipher-system
                      executable: "/opt/Element/element-desktop"
                      prepare_cmd: "sudo apt-get -qq update && sudo apt install -y ./dist/*.deb"
                    - name: "Linux (arm64) (sqlcipher: static)"
                      os: dind-l-arm64
                      artifact: linux-arm64-sqlcipher-static
                      executable: "/opt/Element/element-desktop"
                      prepare_cmd: "sudo apt-get -qq update && sudo apt install -y ./dist/*.deb"
                    - name: Windows (x86)
                      os: windows-2022
                      artifact: win-ia32
                      executable: "./dist/win-ia32-unpacked/Element.exe"
                    - name: Windows (x64)
                      os: windows-2022
                      artifact: win-x64
                      executable: "./dist/win-unpacked/Element.exe"
        name: Test ${{ matrix.name }}
        runs-on: ${{ matrix.os }}
        steps:
            # Workaround for self-hosted runners lacking yarn
            - name: Install Yarn
              if: runner.environment == 'self-hosted'
              run: |
                  # Sanity check that the arch is arm64 as we expect
                  [[ $(uname -p) == "aarch64" ]] || exit 1

                  sudo apt-get -qq update
                  sudo apt-get install -y curl
                  curl -fsSL --create-dirs -o $HOME/bin/yarn https://github.com/yarnpkg/yarn/releases/download/v1.22.19/yarn-1.22.19.js
                  chmod +x $HOME/bin/yarn
                  echo "$HOME/bin" >> $GITHUB_PATH

            - uses: actions/checkout@v4

            - uses: actions/setup-node@v4
              with:
                  node-version-file: package.json
                  cache: "yarn"

            - name: Install Deps
              run: "yarn install --frozen-lockfile"

            - uses: actions/download-artifact@v4
              with:
                  name: ${{ matrix.artifact }}
                  path: dist

            - name: Prepare for tests
              run: ${{ matrix.prepare_cmd }}
              if: matrix.prepare_cmd

            # We previously disabled the `EnableNodeCliInspectArguments` fuse, but Playwright requires
            # it to be enabled to test Electron apps, so turn it back on.
            - name: Set EnableNodeCliInspectArguments fuse enabled
              run: $RUN_AS npx @electron/fuses write --app ${{ matrix.executable }} EnableNodeCliInspectArguments=on
              shell: bash
              env:
                  # We need sudo on Linux as it is installed in /opt/
                  RUN_AS: ${{ runner.os == 'Linux' && 'sudo' || '' }}

            - name: Workaround macOS GHA permission issues
              if: runner.os == 'macOS'
              run: |
                  sqlite3 $HOME/Library/Application\ Support/com.apple.TCC/TCC.db "INSERT OR IGNORE INTO access VALUES ('kTCCServiceMicrophone','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159,NULL,NULL,'UNUSED',1687786159);"
                  sqlite3 $HOME/Library/Application\ Support/com.apple.TCC/TCC.db "INSERT OR IGNORE INTO access VALUES ('kTCCServiceMicrophone','/opt/off/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159,NULL,NULL,'UNUSED',1687786159);"

            - name: Run tests
              uses: coactions/setup-xvfb@6b00cf1889f4e1d5a48635647013c0508128ee1a
              timeout-minutes: 5
              with:
                  run: "yarn test ${{ runner.os != 'Linux' && '--ignore-snapshots' || '' }}"
              env:
                  ELEMENT_DESKTOP_EXECUTABLE: ${{ matrix.executable }}

            - name: Upload HTML report
              if: always()
              uses: actions/upload-artifact@v4
              with:
                  name: ${{ matrix.artifact }}-test
                  path: playwright/html-report
                  retention-days: 14