# This workflow relies on actions/cache to store the hak dependency artifacts as they take a long time to build
# Due to this extra care must be taken to only ever run all build_* scripts against the same branch to ensure
# the correct cache scoping, and additional care must be taken to not run untrusted actions on the develop branch.
on:
    workflow_call:
        inputs:
            arch:
                type: string
                required: true
                description: "The architecture to build for, one of 'amd64' | 'arm64'"
            config:
                type: string
                required: true
                description: "The config directory to use"
            version:
                type: string
                required: false
                description: "Version string to override the one in package.json, used for non-release builds"
            sqlcipher:
                type: string
                required: true
                description: "How to link sqlcipher, one of 'system' | 'static'"
env:
    SQLCIPHER_BUNDLED: ${{ inputs.sqlcipher == 'static' && '1' || '' }}
jobs:
    # We build the hak files on native infrastructure as matrix-seshat fails to cross-compile properly
    # https://github.com/matrix-org/seshat/issues/135
    hak:
        runs-on: ${{ inputs.arch == 'arm64' && 'dind-l-arm64' || 'ubuntu-latest' }}
        env:
            HAK_DOCKER_IMAGE: ghcr.io/element-hq/element-desktop-dockerbuild
        outputs:
            cache-key: ${{ steps.cache-key.outputs.key }}
            arch: ${{ steps.config.outputs.arch }}
            build-args: ${{ steps.config.outputs.build-args }}
        steps:
            # Workaround for self-hosted runners lacking tools
            - name: Install missing tools
              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
                  # curl for yarn download, git for tj-actions/changed-files, zstd for actions/cache
                  sudo apt-get install -y curl git zstd
                  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

            - name: Resolve docker image tag for push
              if: github.event_name == 'push'
              run: echo "HAK_DOCKER_IMAGE=$HAK_DOCKER_IMAGE:$GITHUB_REF_NAME" >> $GITHUB_ENV
            - name: Resolve docker image tag for release
              if: github.event_name == 'release'
              run: echo "HAK_DOCKER_IMAGE=$HAK_DOCKER_IMAGE:staging" >> $GITHUB_ENV
            - name: Resolve docker image tag for other triggers
              if: github.event_name != 'push' && github.event_name != 'release'
              run: echo "HAK_DOCKER_IMAGE=$HAK_DOCKER_IMAGE:develop" >> $GITHUB_ENV

            - uses: nbucic/variable-mapper@0673f6891a0619ba7c002ecfed0f9f4f39017b6f
              id: config
              with:
                  key: "${{ inputs.arch }}"
                  export_to: output
                  map: |
                      {
                        "amd64": {
                          "target": "x86_64-unknown-linux-gnu",
                          "arch": "x86-64"
                        },
                        "arm64": {
                          "target": "aarch64-unknown-linux-gnu",
                          "arch": "aarch64",
                          "build-args": "--arm64"
                        }
                      }

            - uses: actions/checkout@v4

            - uses: actions/download-artifact@v4
              with:
                  name: webapp

            - name: Calculate cache key
              id: cache-key
              run: |
                  echo "key=$CACHE_KEY" >> $GITHUB_OUTPUT
              env:
                  CACHE_KEY: ${{ runner.os }}-${{ github.ref_name }}-${{ inputs.sqlcipher }}-${{ inputs.arch }}-${{ hashFiles('hakHash', 'electronVersion', 'dockerbuild/*') }}

            - name: Cache .hak
              id: cache
              uses: actions/cache@v4
              with:
                  key: ${{ steps.cache-key.outputs.key }}
                  path: |
                      ./.hak

            - uses: actions/setup-node@v4
              with:
                  node-version-file: package.json
                  cache: "yarn"
              env:
                  # Workaround for https://github.com/actions/setup-node/issues/317
                  FORCE_COLOR: 0

            # Does not need branch matching as only analyses this layer
            - name: Install Deps
              run: "yarn install --frozen-lockfile"

            - name: "Get modified files"
              id: changed_files
              if: steps.cache.outputs.cache-hit != 'true' && github.event_name == 'pull_request'
              uses: tj-actions/changed-files@e9772d140489982e0e3704fea5ee93d536f1e275 # v45
              with:
                  files: |
                      dockerbuild/**

            # This allows contributors to test changes to the dockerbuild image within a pull request
            - name: Build docker image
              uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85 # v6
              if: steps.changed_files.outputs.any_modified == 'true'
              with:
                  context: dockerbuild
                  load: true
                  platforms: linux/${{ inputs.arch }}
                  tags: ${{ env.HAK_DOCKER_IMAGE }}

            - name: Build Natives
              if: steps.cache.outputs.cache-hit != 'true'
              run: |
                  docker run \
                    -v ${{ github.workspace }}:/work -w /work \
                    -e SQLCIPHER_BUNDLED \
                    $HAK_DOCKER_IMAGE \
                    yarn build:native

            - name: Check native libraries
              run: |
                  shopt -s globstar

                  for filename in ./.hak/hakModules/**/*.node; do
                      ./scripts/glibc-check.sh $filename
                  done
              env:
                  MAX_VER: 2.28 # buster-era glibc

    build:
        needs: hak
        runs-on: ubuntu-latest
        steps:
            - uses: actions/checkout@v4

            - uses: actions/download-artifact@v4
              with:
                  name: webapp

            - name: Load .hak
              id: cache
              uses: actions/cache/restore@v4
              with:
                  key: ${{ needs.hak.outputs.cache-key }}
                  fail-on-cache-miss: true
                  path: |
                      ./.hak

            - uses: actions/setup-node@v4
              with:
                  node-version-file: package.json
                  cache: "yarn"
              env:
                  # Workaround for https://github.com/actions/setup-node/issues/317
                  FORCE_COLOR: 0

            # Does not need branch matching as only analyses this layer
            - name: Install Deps
              run: "yarn install --frozen-lockfile"

            - name: "[Nightly] Resolve version"
              if: inputs.version != ''
              run: |
                  echo "ED_NIGHTLY=${{ inputs.version }}" >> $GITHUB_ENV

            - name: Generate debian files and arguments
              run: |
                  if [ -f changelog.Debian ]; then
                      echo "ED_DEBIAN_CHANGELOG=changelog.Debian" >> $GITHUB_ENV
                  fi

            - name: Build App
              run: yarn build --publish never -l ${{ needs.hak.outputs.build-args }}

            - name: Check native libraries
              run: |
                  set -x
                  shopt -s globstar

                  FILES=$(file dist/**/*.node)
                  echo "$FILES"

                  if [ grep -v "$ARCH" ]; then
                      exit 1
                  fi

                  LIBS=$(readelf -d dist/**/*.node | grep NEEDED)
                  echo "$LIBS"

                  set +x
                  assert_contains_string() { [[ "$1" == *"$2"* ]]; }
                  ! assert_contains_string "$LIBS" "libcrypto.so.1.1"
                  if [ "$SQLCIPHER_BUNDLED" == "1" ]; then
                      ! assert_contains_string "$LIBS" "libsqlcipher.so.0"
                  else
                      assert_contains_string "$LIBS" "libsqlcipher.so.0"
                  fi

                  ./scripts/glibc-check.sh dist/linux-*unpacked/element-desktop*
              env:
                  ARCH: ${{ needs.hak.outputs.arch }}

            # We exclude *-unpacked as it loses permissions and the tarball contains it with correct permissions
            - name: Upload Artifacts
              uses: actions/upload-artifact@v4
              with:
                  name: linux-${{ inputs.arch }}-sqlcipher-${{ inputs.sqlcipher }}
                  path: |
                      dist
                      !dist/*-unpacked/**
                  retention-days: 1
