# 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:
        secrets:
            APPLE_ID:
                required: false
            APPLE_ID_PASSWORD:
                required: false
            APPLE_TEAM_ID:
                required: false
            APPLE_CSC_KEY_PASSWORD:
                required: false
            APPLE_CSC_LINK:
                required: false
        inputs:
            ref:
                type: string
                required: false
                description: "The git ref to checkout, defaults to the default branch"
            version:
                type: string
                required: false
                description: "Version string to override the one in package.json, used for non-release builds"
            sign:
                type: string
                required: false
                description: "Whether to sign & notarise the build, requires 'packages.element.io' environment"
            base-url:
                type: string
                required: false
                description: "The URL to which the output will be deployed."
            blob_report:
                type: boolean
                required: false
                description: "Whether to run the blob report"
            prepare-artifact-name:
                type: string
                required: false
                description: |
                    The name of the prepare artifact to use, defaults to 'webapp'.
                    The artifact must contain the following:
                    + webapp.asar - the asar archive of the webapp to embed in the desktop app
                    + electronVersion - the version of electron to use for cache keying
                    + hakHash - the hash of the .hak directory to use for cache keying
                    + variant.json - the variant configuration to use for the build

                    The artifact can also contain any additional files which will be applied as overrides to the checkout root before building,
                    for example icons in the `build/` directory to override the app icons.
                default: "webapp"
permissions: {} # No permissions required
jobs:
    build:
        runs-on: macos-14 # M1
        environment: ${{ inputs.sign && 'packages.element.io' || '' }}
        steps:
            - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
              with:
                  repository: element-hq/element-desktop
                  ref: ${{ inputs.ref }}

            - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5
              with:
                  name: ${{ inputs.prepare-artifact-name }}

            - name: Cache .hak
              id: cache
              uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4
              with:
                  key: ${{ runner.os }}-${{ hashFiles('hakHash', 'electronVersion') }}
                  path: |
                      ./.hak

            - name: Install Rust
              if: steps.cache.outputs.cache-hit != 'true'
              run: |
                  rustup toolchain install stable --profile minimal --no-self-update
                  rustup default stable
                  rustup target add aarch64-apple-darwin
                  rustup target add x86_64-apple-darwin

            # M1 macos-14 comes without Python preinstalled
            - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6
              with:
                  python-version: "3.13"

            - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
              with:
                  node-version-file: .node-version
                  cache: "yarn"

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

            # Python 3.12 drops distutils which keytar relies on
            - name: Install setuptools
              run: pip3 install setuptools

            - name: Build Natives
              if: steps.cache.outputs.cache-hit != 'true'
              run: yarn build:native:universal

            # We split these because electron-builder gets upset if we set CSC_LINK even to an empty string
            - name: "[Signed] Build App"
              if: inputs.sign != ''
              run: |
                  yarn build:universal --publish never
              env:
                  APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
                  APPLE_ID: ${{ secrets.APPLE_ID }}
                  APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
                  CSC_KEY_PASSWORD: ${{ secrets.APPLE_CSC_KEY_PASSWORD }}
                  CSC_LINK: ${{ secrets.APPLE_CSC_LINK }}
                  VARIANT_PATH: variant.json
                  # Only set for Nightly builds
                  VERSION: ${{ inputs.version }}

            - name: Check app was signed & notarised successfully
              if: inputs.sign != ''
              run: |
                  hdiutil attach dist/*.dmg -mountpoint /Volumes/Element
                  codesign -dv --verbose=4 /Volumes/Element/*.app
                  spctl -a -vvv -t install /Volumes/Element/*.app
                  hdiutil detach /Volumes/Element

            - name: "[Unsigned] Build App"
              if: inputs.sign == ''
              run: |
                  yarn build:universal --publish never
              env:
                  CSC_IDENTITY_AUTO_DISCOVERY: false
                  VARIANT_PATH: variant.json

            - name: Generate releases.json
              if: inputs.base-url
              run: |
                  PKG_JSON_VERSION=$(cat package.json | jq -r .version)
                  LATEST=$(find dist -type f -iname "*-mac.zip" | xargs -0 -n1 -- basename)
                  # Encode spaces in the URL as Squirrel.Mac complains about bad JSON otherwise
                  URL="${{ inputs.base-url }}/update/macos/${LATEST// /%20}"

                  jq -n --arg version "${VERSION:-$PKG_JSON_VERSION}" --arg url "$URL" '
                    {
                      currentRelease: $version,
                      releases: [{
                        version: $version,
                        updateTo: {
                          version: $version,
                          url: $url,
                        },
                      }],
                    }
                  ' > dist/releases.json
                  jq -n --arg url "$URL" '
                    { url: $url }
                  ' > dist/releases-legacy.json
              env:
                  VERSION: ${{ inputs.version }}

            # We exclude mac-universal as the unpacked app takes forever to upload and zip and dmg already contains it
            - name: Upload Artifacts
              uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
              with:
                  name: macos
                  path: |
                      dist
                      !dist/mac-universal/**
                  retention-days: 1

            - name: Assert all required files are present
              run: |
                  test -f ./dist/Element*.dmg
                  test -f ./dist/Element*-mac.zip

    test:
        needs: build
        uses: ./.github/workflows/build_test.yaml
        with:
            artifact: macos
            runs-on: macos-14
            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
            blob_report: ${{ inputs.blob_report }}
