on:
  workflow_call:
    inputs:
      dockerize:
        default: true
        type: boolean
      uploadJavaScriptArtifacts:
        type: boolean
        default: false
      publishLatest:
        default: false
        type: boolean
      build:
        default: true
        type: boolean
      targets:
        required: true
        type: string
      registry:
        default: ghcr.io
        type: string
      imageName:
        default: ${{ github.repository_owner }}
        type: string
      imageTag:
        required: true
        type: string
      publishSourceMaps:
        default: false
        type: boolean
      publishPrComment:
        default: true
        type: boolean

jobs:
  build-and-dockerize:
    strategy:
      matrix:
        include:
          - builder: hive-linux-x64-ubuntu2204
            platform: linux/amd64
            suffix: '-amd64'
          - builder: hive-linux-arm64-ubuntu2204
            platform: linux/arm64
            suffix: '-arm64'
    runs-on: ${{ matrix.builder }}
    name: dockerize (${{ matrix.platform }})
    permissions:
      contents: read
      packages: write
      pull-requests: write
    steps:
      - name: checkout
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
        with:
          fetch-depth: 2

      - name: setup environment
        if: ${{ inputs.build }}
        uses: ./.github/actions/setup
        with:
          actor: build-and-dockerize

      - name: build packages and applications
        if: ${{ inputs.build }}
        run: pnpm build
        env:
          NODE_OPTIONS: '--max-old-space-size=14336' # GitHub Actions gives us 16GB, it's ok to use 80%

      - name: test ESM & CJS exports integrity
        if: ${{ inputs.build }}
        run: pnpm turbo check:build

      - uses: vimtor/action-zip@5f1c4aa587ea41db1110df6a99981dbe19cee310 # v1
        name: archive javascript artifacts
        if: ${{ inputs.uploadJavaScriptArtifacts }}
        with:
          recursive: false
          files:
            packages/services/broker-worker/dist/index.worker.mjs
            packages/services/cdn-worker/dist/index.worker.mjs
            packages/services/cdn-worker/dist/index.lambda.mjs
          dest: ${{ inputs.imageTag }}.zip

      - name: upload artifact
        if: ${{ inputs.uploadJavaScriptArtifacts }}
        uses: randomairborne/r2-release@9cbc35a2039ee2ef453a6988cd2a85bb2d7ba8af # v1.0.2
        with:
          endpoint: https://6d5bc18cd8d13babe7ed321adba3d8ae.r2.cloudflarestorage.com
          accesskeyid: ${{ secrets.R2_ACCESS_KEY_ID }}
          secretaccesskey: ${{ secrets.R2_SECRET_ACCESS_KEY }}
          bucket: hive-js-build-artifacts
          file: ${{ github.workspace }}/${{ inputs.imageTag }}.zip
          destination: ${{ inputs.imageTag }}.zip

      - name: upload app persisted documents artifact
        uses: randomairborne/r2-release@9cbc35a2039ee2ef453a6988cd2a85bb2d7ba8af # v1.0.2
        with:
          endpoint: https://6d5bc18cd8d13babe7ed321adba3d8ae.r2.cloudflarestorage.com
          accesskeyid: ${{ secrets.R2_ACCESS_KEY_ID }}
          secretaccesskey: ${{ secrets.R2_SECRET_ACCESS_KEY }}
          bucket: hive-js-build-artifacts
          file: ${{ github.workspace }}/packages/web/app/src/gql/persisted-documents.json
          destination: ${{ inputs.imageTag }}.app.documents.json

      - name: upload graphql schema
        uses: randomairborne/r2-release@9cbc35a2039ee2ef453a6988cd2a85bb2d7ba8af # v1.0.2
        with:
          endpoint: https://6d5bc18cd8d13babe7ed321adba3d8ae.r2.cloudflarestorage.com
          accesskeyid: ${{ secrets.R2_ACCESS_KEY_ID }}
          secretaccesskey: ${{ secrets.R2_SECRET_ACCESS_KEY }}
          bucket: hive-js-build-artifacts
          file: ${{ github.workspace }}/schema.graphql
          destination: ${{ inputs.imageTag }}.schema.graphqls

      - name: configure docker buildx
        if: ${{ inputs.dockerize }}
        uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0

      - name: login to docker registry
        if: ${{ inputs.dockerize }}
        uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
        with:
          registry: ${{ inputs.registry }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - uses: frabert/replace-string-action@b6828c5a4cb6371753ff873b0d1c4c4fbd9a63cb # v2.5
        id: branch_name_fix
        name: sanitize branch name
        if: ${{ inputs.dockerize }}
        with:
          pattern: '[+\/><@|-]'
          flags: 'g'
          string: ${{ github.head_ref || github.ref_name }}
          replace-with: '_'

      - uses: frabert/replace-string-action@b6828c5a4cb6371753ff873b0d1c4c4fbd9a63cb # v2.5
        id: docker_cache_key
        name: build cache key
        if: ${{ inputs.dockerize }}
        with:
          pattern: '[\/,]'
          flags: 'g'
          string: ${{ github.ref }}-${{ inputs.targets }}-${{ matrix.platform }}
          replace-with: '_'

      - name: build docker images (${{ matrix.platform }})
        timeout-minutes: 60
        id: docker-bake
        if: ${{ inputs.dockerize }}
        uses: docker/bake-action@5ca506d06f70338a4968df87fd8bfee5cbfb84c7 # v6.0.0
        env:
          DOCKER_REGISTRY: ${{ inputs.registry }}/${{ inputs.imageName }}/
          COMMIT_SHA: ${{ inputs.imageTag }}
          RELEASE: ${{ inputs.imageTag }}
          BRANCH_NAME: ${{ steps.branch_name_fix.outputs.replaced }}
          BUILD_TYPE: 'publish'
          PWD: ${{ github.workspace }}
          BUILD_STABLE: ${{ inputs.publishLatest && '1' || '' }}
          BUILD_PLATFORM: ${{ matrix.platform }}
          IMAGE_SUFFIX: ${{ matrix.suffix }}
        with:
          # See https://github.com/docker/buildx/issues/1533
          provenance: false
          push: true
          files: docker/docker.hcl
          targets: ${{ inputs.targets }}
          source: .
          set: |
            *.cache-from=type=gha,ignore-error=true,scope=${{ steps.docker_cache_key.outputs.replaced }}
            *.cache-from=type=gha,ignore-error=true,scope=refs_heads_main-${{ inputs.targets }}-${{ matrix.platform == 'linux/amd64' && 'linux_amd64' || 'linux_arm64' }}
            *.cache-to=type=gha,mode=max,ignore-error=true,scope=${{ steps.docker_cache_key.outputs.replaced }}

      - name: docker details pr comment
        uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 # v2
        if:
          ${{ inputs.dockerize && github.event_name == 'pull_request' && inputs.publishPrComment }}
        with:
          header: ${{ github.workflow }}
          message: |
            🐋 This PR was built and pushed to the following [Docker images](https://github.com/graphql-hive?ecosystem=container&tab=packages&visibility=public):

            **Targets**: `${{ inputs.targets }}`

            **Platforms**: `${{ matrix.platform }}`

            **Image Tag**: `${{ inputs.imageTag }}`

      - name: upload sourcemaps to Sentry
        if: ${{ inputs.publishSourceMaps }}
        env:
          SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
          SENTRY_ORG: the-guild-z4
          SENTRY_PROJECT: graphql-hive
          SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
          SENTRY_RELEASE: ${{ inputs.imageTag }}
        run: pnpm upload-sourcemaps

  publish_docker_manifest:
    needs: build-and-dockerize
    runs-on: ubuntu-22.04
    if: ${{ inputs.dockerize }}
    name: publish multiarch manifest
    steps:
      - name: checkout
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
        with:
          fetch-depth: 2

      - name: configure docker buildx
        uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0

      - name: login to docker registry
        if: ${{ inputs.dockerize }}
        uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
        with:
          registry: ${{ inputs.registry }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: 'publish docker multiarch manifest (tag: ${{ inputs.imageTag }})'
        env:
          TARGETS: ${{ inputs.targets }}
          REGISTRY: ${{ inputs.registry }}
          IMAGE_NAME: ${{ inputs.imageName }}
          IMAGE_TAG: ${{ inputs.imageTag }}
        run: |
          targets=$(docker buildx bake -f docker/docker.hcl --print "$TARGETS" | jq -r '.group."'"$TARGETS"'".targets[]')

          for target in $targets
          do
              echo "publishing multi-arch manifest for $target"
              image_name="$REGISTRY/$IMAGE_NAME/$target:$IMAGE_TAG"
              echo "image name: $image_name"

              docker manifest create $image_name --amend "$image_name-arm64" --amend "$image_name-amd64"
              docker manifest push $image_name
          done

      - name: 'publish docker multiarch manifest (tag: latest)'
        if: ${{ inputs.publishLatest }}
        env:
          TARGETS: ${{ inputs.targets }}
          REGISTRY: ${{ inputs.registry }}
          IMAGE_NAME: ${{ inputs.imageName }}
        run: |
          targets=$(docker buildx bake -f docker/docker.hcl --print "$TARGETS" | jq -r '.group."'"$TARGETS"'".targets[]')

          for target in $targets
          do
              echo "publishing multi-arch manifest for $target"
              image_name="$REGISTRY/$IMAGE_NAME/$target:latest"
              echo "image name: $image_name"

              docker manifest create $image_name --amend "$image_name-arm64" --amend "$image_name-amd64"
              docker manifest push $image_name
          done
