name: Docker
on:
    workflow_dispatch: {}
    push:
        tags: [v*]
    pull_request: {}
    schedule:
        # This job can take a while, and we have usage limits, so just publish develop only twice a day
        - cron: "0 7/12 * * *"
concurrency: ${{ github.workflow }}-${{ github.ref_name }}
permissions: {}
jobs:
    buildx:
        name: Docker Buildx
        runs-on: ubuntu-24.04
        environment: ${{ github.event_name != 'pull_request' && 'dockerhub' || '' }}
        permissions:
            id-token: write # needed for signing the images with GitHub OIDC Token
            packages: write # needed for publishing packages to GHCR
        env:
            TEST_TAG: vectorim/element-web:test
        steps:
            - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
              with:
                  fetch-depth: 0 # needed for docker-package to be able to calculate the version

            - name: Install Cosign
              uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3
              if: github.event_name != 'pull_request'

            - name: Set up QEMU
              uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3

            - name: Set up Docker Buildx
              uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3
              with:
                  install: true

            - name: Login to Docker Hub
              uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3
              if: github.event_name != 'pull_request'
              with:
                  username: ${{ secrets.DOCKERHUB_USERNAME }}
                  password: ${{ secrets.DOCKERHUB_TOKEN }}

            - name: Login to GitHub Container Registry
              uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3
              if: github.event_name != 'pull_request'
              with:
                  registry: ghcr.io
                  username: ${{ github.repository_owner }}
                  password: ${{ secrets.GITHUB_TOKEN }}

            - name: Build and load
              id: test-build
              uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
              with:
                  context: .
                  load: true

            - name: Test the image
              env:
                  IMAGEID: ${{ steps.test-build.outputs.imageid }}
              timeout-minutes: 2
              run: |
                  set -x

                  # Make a fake module to test the image
                  MODULE_PATH="modules/module_name/index.js"
                  mkdir -p $(dirname $MODULE_PATH)
                  echo 'alert("Testing");' > $MODULE_PATH

                  # Spin up a container of the image
                  ELEMENT_WEB_PORT=8181
                  CONTAINER_ID=$(
                      docker run \
                          --rm \
                          -e "ELEMENT_WEB_PORT=$ELEMENT_WEB_PORT" \
                          -dp "$ELEMENT_WEB_PORT:$ELEMENT_WEB_PORT" \
                          -v $(pwd)/modules:/modules \
                          "$IMAGEID" \
                  )

                  # Run some smoke tests
                  wget --retry-connrefused --tries=5 -q --wait=3 --spider "http://localhost:$ELEMENT_WEB_PORT/modules/module_name/index.js"
                  MODULE_0=$(curl "http://localhost:$ELEMENT_WEB_PORT/config.json" | jq -r .modules[0])
                  test "$MODULE_0" = "/${MODULE_PATH}"

                  # Check healthcheck
                  until test "$(docker inspect -f {{.State.Health.Status}} $CONTAINER_ID)" == "healthy"; do
                      sleep 1
                  done

                  # Clean up
                  docker stop "$CONTAINER_ID"

            - name: Docker meta
              id: meta
              uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5
              if: github.event_name != 'pull_request'
              with:
                  images: |
                      vectorim/element-web
                      ghcr.io/element-hq/element-web
                  tags: |
                      type=ref,event=branch
                      type=ref,event=tag
                  flavor: |
                      latest=${{ contains(github.ref_name, '-rc.') && 'false' || 'auto' }}

            - name: Build and push
              id: build-and-push
              uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
              if: github.event_name != 'pull_request'
              with:
                  context: .
                  push: true
                  platforms: linux/amd64,linux/arm64
                  tags: ${{ steps.meta.outputs.tags }}
                  labels: ${{ steps.meta.outputs.labels }}

            - name: Sign the images with GitHub OIDC Token
              env:
                  DIGEST: ${{ steps.build-and-push.outputs.digest }}
                  TAGS: ${{ steps.meta.outputs.tags }}
              if: github.event_name != 'pull_request'
              run: |
                  images=""
                  for tag in ${TAGS}; do
                      images+="${tag}@${DIGEST} "
                  done
                  cosign sign --yes ${images}

            - name: Update repo description
              uses: peter-evans/dockerhub-description@432a30c9e07499fd01da9f8a49f0faf9e0ca5b77 # v4
              if: github.event_name != 'pull_request'
              continue-on-error: true
              with:
                  username: ${{ secrets.DOCKERHUB_USERNAME }}
                  password: ${{ secrets.DOCKERHUB_TOKEN }}
                  repository: vectorim/element-web

            - name: Repository Dispatch
              uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3
              if: github.event_name != 'pull_request'
              with:
                  repository: element-hq/element-web-pro
                  token: ${{ secrets.ELEMENT_BOT_TOKEN }}
                  event-type: image-built
                  # Stable way to determine the :version
                  client-payload: |-
                      {
                          "base-ref": "${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}"
                      }
