name: Docker images

on:
  # On release events (also when a published release is converted from/to prerelease), push all patterns
  release:
    types: [released, prereleased]

  # On workflow_dispatch, allow publishing 3-latest images or a specific tag
  workflow_dispatch:
    inputs:
      publish_3_latest:
        description: 'Publish 3-latest images'
        required: false
        type: boolean
        default: false
      tag:
        description: 'Build dev images for a specific tag (e.g., 3.6.6.dev5)'
        required: false
        type: string

jobs:
  publish-docker-images:
    name: Build and publish to DockerHub
    runs-on: ubuntu-latest
    environment: ${{ github.event_name == 'release' && github.event.release.prerelease && 'pre-release' || github.event_name == 'release' && 'prod' || 'dev' }}
    strategy:
      fail-fast: false
      matrix:
        image:
          - "prefecthq/prefect"
          - "prefecthq/prefect-client"
        python-version:
          - "3.10"
          - "3.11"
          - "3.12"
          - "3.13"
          - "3.14"
        flavor:
        - ""
        - "-conda"
        - "-kubernetes"
        exclude:
        - image: "prefecthq/prefect-client"
          flavor: "-conda"
        - image: "prefecthq/prefect-client"
          flavor: "-kubernetes"

    steps:
      - name: Validate Prerelease Tag
        if: ${{ github.event_name == 'release' && github.event.release.prerelease == true }}
        run: |
          TAG_NAME=${{ github.ref }}
          if [[ ! "$TAG_NAME" =~ ^refs/tags/[0-9]+\.[0-9]+\.[0-9]+([a-zA-Z0-9]+|\.dev[0-9]+)$ ]]; then
            echo "Error: Tag $TAG_NAME does not match prerelease version pattern."
            exit 1
          fi
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to DockerHub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0
          ref: ${{ github.event.inputs.tag || github.ref }}

      - name: Generate tags for ${{ matrix.image }}-dev
        id: metadata-dev
        uses: docker/metadata-action@v5
        # generate dev tags on pre-releases or when manually triggered with a tag input
        if: ${{ (github.event_name == 'release' && github.event.release.prerelease == true) || (github.event_name == 'workflow_dispatch' && github.event.inputs.tag != '') }}
        with:
          images: ${{ matrix.image }}-dev
          tags: |
            type=raw,value=${{ github.event.inputs.tag || github.ref_name }},suffix=-python${{ matrix.python-version }}${{ matrix.flavor }}
            type=sha,suffix=-python${{ matrix.python-version }}${{ matrix.flavor }}
          flavor: |
            latest=false

      - name: Determine latest tag
        # https://stackoverflow.com/a/75079768/5511061
        run: |
          echo "LATEST_TAG=$(curl -qsSL \
            -H "Accept: application/vnd.github+json" \
            -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
            -H "X-GitHub-Api-Version: 2022-11-28" \
            "${{ github.api_url }}/repos/${{ github.repository }}/releases/latest" \
          | jq -r .tag_name)" >> $GITHUB_ENV

      - name: Generate tags for ${{ matrix.image }}
        id: metadata-prod
        uses: docker/metadata-action@v5
        # generate the production tags on release events or when manually triggered for 3-latest
        if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.publish_3_latest == 'true') }}
        with:
          images: ${{ matrix.image }}
          # push `latest`, `X.Y` and `X` tags only when the release is not marked as prerelease
          # push `latest` and `X` tags only when the release is marked as latest
          # push `3-latest` tags on latest release or manual trigger
          tags: |
            type=pep440,pattern={{version}},suffix=-python${{ matrix.python-version }}${{ matrix.flavor }},enable=${{ github.event_name == 'release' }}
            type=pep440,pattern={{major}}.{{minor}},suffix=-python${{ matrix.python-version }}${{ matrix.flavor }},enable=${{ github.event_name == 'release' && github.event.release.prerelease == false }}
            type=pep440,pattern={{major}},suffix=-python${{ matrix.python-version }}${{ matrix.flavor }},enable=${{ github.event_name == 'release' && github.event.release.prerelease == false && github.ref_name == env.LATEST_TAG }}
            type=raw,value=3-latest${{ matrix.flavor }},enable=${{ (github.event_name == 'release' && github.event.release.prerelease == false && github.ref_name == env.LATEST_TAG && matrix.python-version == '3.12') || (github.event_name == 'workflow_dispatch' && github.event.inputs.publish_3_latest == 'true') }}
            type=raw,value=3-latest-python${{ matrix.python-version }}${{ matrix.flavor }},enable=${{ github.event_name == 'workflow_dispatch' && github.event.inputs.publish_3_latest == 'true' }}
          flavor: |
            latest=false

      - name: Get node version
        id: get_node_version
        run: |
          echo "NODE_VERSION=$(cat .nvmrc)" >> $GITHUB_OUTPUT

      - name: Build and push image
        uses: docker/build-push-action@v6
        with:
          context: .
          file: ${{ (matrix.image == 'prefecthq/prefect-client') && 'client/Dockerfile' || 'Dockerfile' }}
          platforms: linux/amd64,linux/arm64
          build-args: |
            PYTHON_VERSION=${{ matrix.python-version }}
            NODE_VERSION=${{ steps.get_node_version.outputs.NODE_VERSION }}
            ${{ ( endsWith(matrix.flavor, 'conda') && 'BASE_IMAGE=prefect-conda' ) || '' }}
            ${{ ( endsWith(matrix.flavor, 'kubernetes') && 'PREFECT_EXTRAS=[redis,kubernetes]' ) || '' }}
          tags: ${{ join(steps.metadata-dev.outputs.tags) }},${{ join(steps.metadata-prod.outputs.tags) }}
          labels: ${{ steps.metadata-dev.outputs.labels }}
          push: true
          pull: true
          provenance: false
          cache-from: type=gha,scope=${{ matrix.image }}-${{ matrix.python-version }}${{ matrix.flavor }},ignore-error=true
          cache-to: type=gha,mode=max,scope=${{ matrix.image }}-${{ matrix.python-version }}${{ matrix.flavor }},ignore-error=true

  get-prefect-aws-version:
    name: Get latest prefect-aws version
    needs: publish-docker-images
    runs-on: ubuntu-latest
    # Only trigger on actual releases (not workflow_dispatch)
    if: github.event_name == 'release'
    outputs:
      PREFECT_AWS_VERSION: ${{ steps.get_version.outputs.PREFECT_AWS_VERSION }}
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: Get latest prefect-aws version from tags
        id: get_version
        run: |
          PREFECT_AWS_VERSION=$(git tag --list 'prefect-aws-*' --sort=-version:refname | head -1 | sed 's/^prefect-aws-//')
          echo "PREFECT_AWS_VERSION=$PREFECT_AWS_VERSION" >> $GITHUB_OUTPUT

  trigger-prefect-aws-build:
    name: Build prefect-aws Docker images
    needs: [publish-docker-images, get-prefect-aws-version]
    if: github.event_name == 'release' && needs.get-prefect-aws-version.outputs.PREFECT_AWS_VERSION != ''
    uses: ./.github/workflows/prefect-aws-docker-images.yaml
    with:
      prefect_version: ${{ github.ref_name }}
      prefect_aws_version: ${{ needs.get-prefect-aws-version.outputs.PREFECT_AWS_VERSION }}
    secrets: inherit

  trigger-oss-testbed-update:
    name: Trigger OSS testbed image update
    needs: publish-docker-images
    runs-on: ubuntu-latest
    steps:
      - name: Trigger cluster-deployment workflow
        run: |
          # Construct the Kubernetes image tag (e.g., 3.4.16-python3.11-kubernetes)
          IMAGE_TAG="${{ github.ref_name }}-python3.11-kubernetes"
          
          gh workflow run update-prefect-image-version.yaml \
            --repo PrefectHQ/cluster-deployment \
            --ref main \
            --field image_tag="$IMAGE_TAG"
        env:
          GH_TOKEN: ${{ secrets.CLUSTER_DEPLOYMENT_ACTIONS_RW }}
