# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

name: Build Frontend Image

on:
  push:
    branches:
    - main
    - "pull-request/[0-9]+"
    # Note: release/* branches are handled by release.yml which calls this workflow
  workflow_call:
    inputs:
      skip_change_detection:
        description: 'Skip changed-files detection and always build (used by release pipeline)'
        required: false
        type: boolean
        default: false
      image_prefix:
        description: 'Optional prefix for image tags (e.g., release-0.9.0). When set, images are also tagged as {prefix}-frontend-{arch}.'
        required: false
        type: string
        default: ''
    secrets:
      AWS_ACCOUNT_ID:
        required: true
      AWS_DEFAULT_REGION:
        required: true
      AWS_ACCESS_KEY_ID:
        required: true
      AWS_SECRET_ACCESS_KEY:
        required: true
      AZURE_ACR_HOSTNAME:
        required: true
      AZURE_ACR_USER:
        required: true
      AZURE_ACR_PASSWORD:
        required: true
      SCCACHE_S3_BUCKET:
        required: true

concurrency:
  group: ${{ github.workflow }}-${{ github.ref_name == 'main' && github.run_id || github.ref_name }}
  cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

env:
  BUILDER_NAME: b-${{ github.run_id }}-${{ github.run_attempt }}

jobs:
  changed-files:
    runs-on: ubuntu-slim
    outputs:
      frontend: ${{ steps.changes.outputs.frontend }}
      builder_name: ${{ steps.export-builder-name.outputs.builder_name }}
    steps:
      - name: Checkout code
        uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955  # v4.3.0
        with:
          fetch-depth: 0
      - name: Check for changes
        id: changes
        uses: ./.github/actions/changed-files
        with:
          gh_token: ${{ github.token }}
      - name: Export builder name
        id: export-builder-name
        run: |
          echo "builder_name=${{ env.BUILDER_NAME }}" >> $GITHUB_OUTPUT

  build-epp-image:
    name: Build EPP Image
    needs: changed-files
    if: needs.changed-files.outputs.frontend == 'true' || inputs.skip_change_detection == true
    runs-on: prod-builder-v3
    outputs:
      epp_image_ref: ${{ steps.build-epp-image.outputs.epp_image_ref }}
    env:
      ECR_HOSTNAME: ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.${{ secrets.AWS_DEFAULT_REGION }}.amazonaws.com
      IMAGE_REGISTRY: ai-dynamo
      IMAGE_REPOSITORY: dynamo/dynamo-epp
    steps:
      - name: Checkout repository
        uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955  # v4.3.0
      - name: Initialize Dynamo Builder
        uses: ./.github/actions/init-dynamo-builder
        with:
          builder_name: ${{ needs.changed-files.outputs.builder_name }}
          flavor: general
          all_arch: 'true'
      - name: Docker Login
        uses: ./.github/actions/docker-login
        with:
          aws_default_region: ${{ secrets.AWS_DEFAULT_REGION }}
          aws_account_id: ${{ secrets.AWS_ACCOUNT_ID }}
          azure_acr_hostname: ${{ secrets.AZURE_ACR_HOSTNAME }}
          azure_acr_user: ${{ secrets.AZURE_ACR_USER }}
          azure_acr_password: ${{ secrets.AZURE_ACR_PASSWORD }}
      - name: Build EPP Image
        id: build-epp-image
        shell: bash
        timeout-minutes: 20
        run: |
          set -x
          EPP_IMAGE_REPO="${{ env.ECR_HOSTNAME }}/${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_REPOSITORY }}"
          EPP_IMAGE_TAG="${{ github.sha }}"
          EPP_IMAGE_REF="${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_REPOSITORY }}:${EPP_IMAGE_TAG}"
          echo "epp_image_ref=${EPP_IMAGE_REF}" >> $GITHUB_OUTPUT

          CACHE_ARGS=""
          CACHE_ARGS+="--cache-from type=registry,ref=${ECR_HOSTNAME}/${IMAGE_REGISTRY}/${IMAGE_REPOSITORY}:cache "
          if [[ "$GITHUB_REF_NAME" == "main" ]]; then
            CACHE_ARGS+="--cache-to type=registry,ref=${ECR_HOSTNAME}/${IMAGE_REGISTRY}/${IMAGE_REPOSITORY}:cache,mode=max "
          fi

          make -C deploy/inference-gateway/epp image-multiarch-push \
            IMAGE_REPO="${EPP_IMAGE_REPO}" \
            GIT_TAG="${EPP_IMAGE_TAG}" \
            DOCKER_PROXY="${ECR_HOSTNAME}/dockerhub/" \
            EXTRA_BUILD_ARGS="${CACHE_ARGS}"


  build-frontend-image:
    name: Build Frontend Image
    needs: [changed-files, build-epp-image]
    if: needs.changed-files.outputs.frontend == 'true' || inputs.skip_change_detection == true
    strategy:
      fail-fast: false
      matrix:
        arch: [amd64, arm64]
    runs-on: prod-builder-v3
    env:
      IMAGE_REGISTRY: ai-dynamo
      IMAGE_REPOSITORY: dynamo
      ECR_HOSTNAME: ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.${{ secrets.AWS_DEFAULT_REGION }}.amazonaws.com
      TARGET: frontend
      CUDA_VERSION: "12.9"
      FRAMEWORK: dynamo
    steps:
      - name: Checkout repository
        uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955  # v4.3.0
      - name: Generate Dockerfile
        shell: bash
        run: |
          echo "Generating Dockerfile for target: ${{ env.TARGET }} and framework: ${{ env.FRAMEWORK }} "
          python ./container/render.py \
              --target=${{ env.TARGET }} \
              --framework=${{ env.FRAMEWORK }} \
              --platform=${{ matrix.arch }} \
              --cuda-version=${{ env.CUDA_VERSION }} \
              --show-result \
              --output-short-filename
      - name: Calculate target tag
        id: calculate-target-tag
        shell: bash
        run: |
          ECR_IMAGE_BASE="${{ env.ECR_HOSTNAME }}/${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_REPOSITORY }}"
          TARGET_TAG="${{ github.sha }}-${{ env.TARGET }}-${{ matrix.arch }}"
          echo "ecr_image_base=${ECR_IMAGE_BASE}" >> $GITHUB_OUTPUT
          echo "default_target_image_uri=${ECR_IMAGE_BASE}:${TARGET_TAG}" >> $GITHUB_OUTPUT
          echo "epp_image_uri=${{ env.ECR_HOSTNAME }}/${{ needs.build-epp-image.outputs.epp_image_ref }}" >> $GITHUB_OUTPUT
          echo "target_tag=${TARGET_TAG}" >> $GITHUB_OUTPUT
          echo "azure_target_image_uri=${{ secrets.AZURE_ACR_HOSTNAME }}/${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_REPOSITORY }}:${TARGET_TAG}" >> $GITHUB_OUTPUT
      - name: Print Build Container parameters
        run: |
          echo "=== Build Container Parameters ==="
          echo "image_tag: ${{ steps.calculate-target-tag.outputs.default_target_image_uri }}"
          echo "framework: ${{ env.FRAMEWORK }}"
          echo "target: ${{ env.TARGET }}"
          echo "platform: ${{ matrix.arch }}"
          echo "cuda_version: ${{ env.CUDA_VERSION }}"
          echo "extra_tags: ${{ steps.calculate-target-tag.outputs.azure_target_image_uri }}"
          echo "epp_image_uri: ${{ steps.calculate-target-tag.outputs.epp_image_uri }}"
          echo "push_image: true"
      - name: Docker Login
        uses: ./.github/actions/docker-login
        with:
          aws_default_region: ${{ secrets.AWS_DEFAULT_REGION }}
          aws_account_id: ${{ secrets.AWS_ACCOUNT_ID }}
          azure_acr_hostname: ${{ secrets.AZURE_ACR_HOSTNAME }}
          azure_acr_user: ${{ secrets.AZURE_ACR_USER }}
          azure_acr_password: ${{ secrets.AZURE_ACR_PASSWORD }}
      - name: Initialize Dynamo Builder
        uses: ./.github/actions/init-dynamo-builder
        with:
          builder_name: ${{ needs.changed-files.outputs.builder_name }}
          flavor: general
          arch: ${{ matrix.arch }}
      - name: Build Frontend Container
        id: build-image
        timeout-minutes: 30
        uses: ./.github/actions/docker-remote-build
        with:
          image_tag: ${{ steps.calculate-target-tag.outputs.default_target_image_uri }}
          framework: ${{ env.FRAMEWORK }}
          target: ${{ env.TARGET }}
          platform: ${{ matrix.arch }}
          cuda_version: ${{ env.CUDA_VERSION }}
          aws_default_region: ${{ secrets.AWS_DEFAULT_REGION }}
          sccache_s3_bucket: ${{ secrets.SCCACHE_S3_BUCKET }}
          aws_account_id: ${{ secrets.AWS_ACCOUNT_ID }}
          aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          push_image: true
          extra_build_args: |
            EPP_IMAGE=${{ steps.calculate-target-tag.outputs.epp_image_uri }}
          extra_tags: |
            ${{ matrix.arch == 'amd64' && steps.calculate-target-tag.outputs.azure_target_image_uri || '' }}
            ${{ github.ref_name == 'main' && format('{0}:main-frontend-{1}', steps.calculate-target-tag.outputs.ecr_image_base, matrix.arch) || '' }}
            ${{ github.ref_name == 'main' && format('{0}:main-frontend-{1}-{2}', steps.calculate-target-tag.outputs.ecr_image_base, github.sha, matrix.arch) || '' }}
            ${{ inputs.image_prefix != '' && format('{0}:{1}-frontend-{2}', steps.calculate-target-tag.outputs.ecr_image_base, inputs.image_prefix, matrix.arch) || '' }}

      - name: Show summary
        shell: bash
        run: |
          echo "### 🐳 ${{ env.FRAMEWORK }}-cuda${{ env.CUDA_VERSION }}-${{ matrix.arch }} Default Image" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "| Image URI |" >> $GITHUB_STEP_SUMMARY
          echo "|-----|" >> $GITHUB_STEP_SUMMARY
          echo "| \`${{ steps.calculate-target-tag.outputs.default_target_image_uri }}\` |" >> $GITHUB_STEP_SUMMARY
          echo "| \`${{ steps.calculate-target-tag.outputs.azure_target_image_uri }}\` |" >> $GITHUB_STEP_SUMMARY

  frontend-status-check:
    runs-on: ubuntu-latest
    needs: [changed-files, build-frontend-image, build-epp-image]
    if: always()
    steps:
      - name: "Check all dependent jobs"
        run: |
          echo '${{ toJson(needs) }}' | jq -e 'to_entries | map(.value.result) | all(. as $result | ["success", "skipped"] | any($result == .))'

  clean-k8s-builder:
    name: Clean K8s builder if exists
    runs-on: prod-default-small-v2
    if: always()
    needs: [build-frontend-image, changed-files]
    steps:
    - name: Checkout repository
      uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955  # v4.3.0
    - name: Create K8s builders (skip bootstrap)
      uses: ./.github/actions/bootstrap-buildkit
      continue-on-error: true
      with:
        builder_name: ${{ needs.changed-files.outputs.builder_name }}
        buildkit_worker_addresses: '' # k8s builder
        skip_bootstrap: true
    - name: Builder Cleanup in case of k8s builder
      shell: bash
      run: |
        docker buildx rm ${{ needs.changed-files.outputs.builder_name }} || true
