name: 🚀 Publish Trigger.dev Docker

on:
  workflow_dispatch:
  workflow_call:
    inputs:
      image_tag:
        description: The image tag to publish
        required: true
        type: string
    secrets:
      DOCKERHUB_USERNAME:
        required: false
      DOCKERHUB_TOKEN:
        required: false
      SENTRY_AUTH_TOKEN:
        required: false
      CROSS_REPO_PAT:
        required: false
  push:
    branches:
      - main
    tags:
      - "v.docker.*"
      - "build-*"
    paths:
      - ".github/actions/**/*.yml"
      - ".github/workflows/publish.yml"
      - ".github/workflows/typecheck.yml"
      - ".github/workflows/unit-tests.yml"
      - ".github/workflows/e2e.yml"
      - ".github/workflows/publish-webapp.yml"
      - "packages/**"
      - "!packages/**/*.md"
      - "!packages/**/*.eslintrc"
      - "internal-packages/**"
      - "apps/**"
      - "!apps/**/*.md"
      - "!apps/**/*.eslintrc"
      - "pnpm-lock.yaml"
      - "pnpm-workspace.yaml"
      - "turbo.json"
      - "docker/Dockerfile"
      - "docker/scripts/**"
      - "tests/**"

permissions:
  contents: read

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}

env:
  AWS_REGION: us-east-1

jobs:
  typecheck:
    uses: ./.github/workflows/typecheck.yml

  units:
    uses: ./.github/workflows/unit-tests.yml
    secrets:
      DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
      DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}

  publish-webapp:
    needs: [typecheck]
    permissions:
      contents: read
      packages: write
      id-token: write
      attestations: write
    uses: ./.github/workflows/publish-webapp.yml
    secrets:
      SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
    with:
      image_tag: ${{ inputs.image_tag }}
      # Target registry namespace. Defaults to ghcr.io/<owner> so a fork publishes
      # to its own namespace; set the IMAGE_REGISTRY repository variable to override.
      image_registry: ${{ vars.IMAGE_REGISTRY || format('ghcr.io/{0}', github.repository_owner) }}

  publish-worker-v4:
    needs: [typecheck]
    permissions:
      contents: read
      packages: write
      id-token: write
    uses: ./.github/workflows/publish-worker-v4.yml
    with:
      image_tag: ${{ inputs.image_tag }}
      image_registry: ${{ vars.IMAGE_REGISTRY || format('ghcr.io/{0}', github.repository_owner) }}

  # OS-level CVE scan of the image just published above. Report-only (writes to
  # the run summary); runs alongside the worker publishes and never blocks them.
  scan-webapp:
    needs: [publish-webapp]
    permissions:
      contents: read
      packages: read # pull the just-published image from GHCR
    uses: ./.github/workflows/trivy-image-webapp.yml
    with:
      image-ref: ${{ needs.publish-webapp.outputs.image_repo }}:${{ needs.publish-webapp.outputs.version }}

  # Announce the freshly published mutable `main` webapp image to subscriber
  # repos via repository_dispatch, handing them a digest-pinned ref to build or
  # deploy from. The repo, ref prefix, and dispatch target all default to the
  # canonical values and can be overridden by repository variables.
  #
  # `push` only: release builds reach publish.yml via workflow_call (from
  # release.yml) with an explicit image_tag while github.ref_name is still
  # `main`, so gate on the event to avoid dispatching — and failing on the
  # absent CROSS_REPO_PAT — during a release.
  dispatch-main-image:
    name: 📣 Dispatch main image
    needs: [publish-webapp]
    if: github.repository == (vars.MAIN_IMAGE_DISPATCH_REPO || 'triggerdotdev/trigger.dev') && github.event_name == 'push' && startsWith(github.ref_name, vars.MAIN_IMAGE_DISPATCH_REF_PREFIX || 'main')
    runs-on: warp-ubuntu-latest-x64-2x
    permissions: {}
    steps:
      - name: Build dispatch payload
        id: payload
        env:
          IMAGE_REPO: ${{ needs.publish-webapp.outputs.image_repo }}
          DIGEST: ${{ needs.publish-webapp.outputs.digest }}
          COMMIT: ${{ github.sha }}
        run: |
          set -euo pipefail
          # Pin to the exact multi-arch index just pushed so subscribers resolve a
          # single immutable artifact rather than chasing the moving `main` tag.
          if [[ -z "${DIGEST}" ]]; then
            echo "::error::publish-webapp produced no image digest; refusing to dispatch"
            exit 1
          fi
          image="${IMAGE_REPO}@${DIGEST}"
          # jq --arg JSON-escapes every value, so the ref/commit can't break out of
          # or inject into the client payload.
          payload=$(jq -nc \
            --arg img "$image" \
            --arg c "$COMMIT" \
            '{image: $img, commit: $c}')
          echo "client_payload=$payload" >> "$GITHUB_OUTPUT"

      - name: Send repository_dispatch
        uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 # v4.0.1
        with:
          token: ${{ secrets.CROSS_REPO_PAT }}
          repository: ${{ vars.MAIN_IMAGE_DISPATCH_TARGET || 'triggerdotdev/cloud' }}
          event-type: main-image-published
          client-payload: ${{ steps.payload.outputs.client_payload }}
