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

# Dynamo Pipeline — single entry point for building the dynamo runtime image
# and running all of its associated checks (rust, mypy, pytest parallel/
# sequential/GPU).

name: Dynamo Pipeline

on:
  workflow_call:
    inputs:
      builder_name:
        description: 'BuildKit builder name'
        required: true
        type: string
      cuda_version:
        description: 'CUDA version for the runtime image (e.g. 12.9)'
        required: false
        type: string
        default: '12.9'
      fresh_builder:
        description: 'Always create a fresh K8s BuildKit builder (for nightly)'
        required: false
        type: boolean
        default: false
      build_timeout_minutes:
        required: false
        type: number
        default: 30
      no_cache:
        description: 'Disable BuildKit cache-from/to. Nightly sets true for regression detection.'
        required: false
        type: boolean
        default: false
      cpu_parallel_test_markers:
        required: true
        type: string
      cpu_sequential_test_markers:
        required: true
        type: string
      gpu_test_markers:
        required: true
        type: string
    secrets:
      AWS_DEFAULT_REGION:
        required: true
      AWS_ACCOUNT_ID:
        required: true
      AZURE_ACR_HOSTNAME:
        required: true
      AZURE_ACR_USER:
        required: true
      AZURE_ACR_PASSWORD:
        required: true
      SCCACHE_S3_BUCKET:
        required: false
      HF_TOKEN:
        required: false

jobs:
  image:
    uses: ./.github/workflows/shared-build-image.yml
    with:
      framework: dynamo
      target: runtime
      cuda_version: '["${{ inputs.cuda_version }}"]'
      platform: 'linux/amd64,linux/arm64'
      builder_name: ${{ inputs.builder_name }}
      fresh_builder: ${{ inputs.fresh_builder }}
      no_cache: ${{ inputs.no_cache }}
      build_timeout_minutes: ${{ inputs.build_timeout_minutes }}
    secrets: inherit

  # rust-gpu-checks + mypy run inside the built images because they depend on
  # native libs (NIXL, ffmpeg, CUDA) and pinned Python package versions that
  # aren't reproducible on plain ubuntu-latest runners.
  rust-gpu:
    needs: image
    runs-on: prod-tester-amd-gpu-v1
    timeout-minutes: 30
    env:
      CONTAINER_ID: test_${{ github.run_id }}_${{ github.run_attempt }}_rust_dynamo
    steps:
      - name: Checkout repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd  # v6.0.2
      - name: Calculate runtime image tag
        id: image
        shell: bash
        env:
          ECR_REPOSITORY: ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.${{ secrets.AWS_DEFAULT_REGION }}.amazonaws.com/ai-dynamo/dynamo
        run: |
          CUDA_VERSION="${{ inputs.cuda_version }}"
          CUDA_MAJOR=${CUDA_VERSION%%.*}
          IMAGE_TAG=${{ github.sha }}-${{ needs.image.outputs.target_tag_plain }}-cuda${CUDA_MAJOR}
          echo "runtime_image=${ECR_REPOSITORY}:${IMAGE_TAG}" >> $GITHUB_OUTPUT
      - name: Docker Login
        uses: ./.github/actions/docker-login
        with:
          aws_default_region: ${{ secrets.AWS_DEFAULT_REGION }}
          aws_account_id: ${{ secrets.AWS_ACCOUNT_ID }}
      - name: Pull runtime image
        run: |
          source ./.github/scripts/retry_docker.sh
          retry_pull ${{ steps.image.outputs.runtime_image }}
      - name: Run Rust checks (block-manager + media-ffmpeg + integration tests)
        env:
          SCCACHE_S3_BUCKET: ${{ secrets.SCCACHE_S3_BUCKET }}
          AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}
        run: |
          docker run --rm --runtime=nvidia --gpus all --user root -w /workspace/lib/llm \
            --name ${{ env.CONTAINER_ID }}_rust_checks \
            -e SCCACHE_BUCKET="${SCCACHE_S3_BUCKET}" \
            -e SCCACHE_REGION="${AWS_DEFAULT_REGION}" \
            -e AWS_ROLE_ARN \
            -e AWS_WEB_IDENTITY_TOKEN_FILE=/run/secrets/aws-token \
            -v "${AWS_WEB_IDENTITY_TOKEN_FILE}:/run/secrets/aws-token:ro" \
            ${{ steps.image.outputs.runtime_image }} \
            bash -ec 'ARCH_ALT=x86_64 /workspace/container/use-sccache.sh install && \
                      eval $(/workspace/container/use-sccache.sh setup-env) && \
                      rustup component add rustfmt clippy && \
                      cargo fmt -- --check && \
                      cargo clippy --features block-manager,media-ffmpeg,testing-nixl,integration --no-deps --all-targets -- -D warnings && \
                      cargo test --locked --all-targets --features=block-manager,media-ffmpeg,testing-nixl,integration -- --nocapture && \
                      cargo clippy -p kvbm-physical --no-deps --all-targets -- -D warnings && \
                      cargo test --locked -p kvbm-physical --features testing-kvbm -- --nocapture --test-threads=4 && \
                      /workspace/container/use-sccache.sh show-stats "Rust Checks"'

  mypy:
    needs: image
    runs-on: prod-tester-amd-v1
    timeout-minutes: 15
    steps:
      - name: Checkout repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd  # v6.0.2
      - name: Calculate test image tag
        id: image
        shell: bash
        env:
          ECR_REPOSITORY: ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.${{ secrets.AWS_DEFAULT_REGION }}.amazonaws.com/ai-dynamo/dynamo
        run: |
          CUDA_VERSION="${{ inputs.cuda_version }}"
          CUDA_MAJOR=${CUDA_VERSION%%.*}
          IMAGE_TAG=${{ github.sha }}-${{ needs.image.outputs.target_tag_plain }}-cuda${CUDA_MAJOR}-test
          echo "test_image=${ECR_REPOSITORY}:${IMAGE_TAG}" >> $GITHUB_OUTPUT
      - name: Docker Login
        uses: ./.github/actions/docker-login
        with:
          aws_default_region: ${{ secrets.AWS_DEFAULT_REGION }}
          aws_account_id: ${{ secrets.AWS_ACCOUNT_ID }}
      - name: Pull test image
        run: |
          source ./.github/scripts/retry_docker.sh
          retry_pull ${{ steps.image.outputs.test_image }}
      - name: Run mypy (components)
        run: |
          docker run --rm -w /workspace \
            --name mypy_${{ github.run_id }}_${{ github.run_attempt }} \
            ${{ steps.image.outputs.test_image }} \
            bash -c '
              MYPYPATH=components/src:lib/bindings/python/src
              TARGETS=$(find components/src/dynamo -maxdepth 1 -mindepth 1 -type d | sort | tr "\n" " ")
              MYPYPATH=$MYPYPATH mypy --explicit-package-bases $TARGETS
            '
      - name: Run mypy (bindings)
        run: |
          docker run --rm -w /workspace \
            --name mypy_bindings_${{ github.run_id }}_${{ github.run_attempt }} \
            ${{ steps.image.outputs.test_image }} \
            bash -c 'MYPYPATH=lib/bindings/python/src mypy -p dynamo'

  # TODO: real xdist parallelism port conflicts. cpu_parallel_mode='none'
  # below runs -n 0, so this job is NOT actually parallel right now.
  parallel:
    name: test
    needs: image
    uses: ./.github/workflows/shared-test.yml
    with:
      test_suite_name: dynamo
      test_type: parallel
      amd_runner: prod-tester-amd-v1
      target_tag_plain: ${{ needs.image.outputs.target_tag_plain }}
      cuda_version: '["${{ inputs.cuda_version }}"]'
      platform: '["amd64", "arm64"]'
      run_sanity_check: false
      run_cpu_only_tests: true
      cpu_only_test_markers: ${{ inputs.cpu_parallel_test_markers }}
      cpu_only_test_timeout_minutes: 30
      cpu_parallel_mode: 'none'
      run_gpu_tests: false
    secrets: inherit

  sequential:
    name: test
    needs: image
    uses: ./.github/workflows/shared-test.yml
    with:
      test_suite_name: dynamo
      test_type: sequential
      amd_runner: prod-tester-amd-v1
      target_tag_plain: ${{ needs.image.outputs.target_tag_plain }}
      cuda_version: '["${{ inputs.cuda_version }}"]'
      platform: '["amd64", "arm64"]'
      run_sanity_check: false
      run_cpu_only_tests: true
      cpu_only_test_markers: ${{ inputs.cpu_sequential_test_markers }}
      cpu_only_test_timeout_minutes: 30
      cpu_parallel_mode: 'none'
      run_gpu_tests: false
    secrets: inherit

  gpu:
    name: test
    needs: image
    uses: ./.github/workflows/shared-test.yml
    with:
      test_suite_name: dynamo
      test_type: gpu
      amd_runner: prod-tester-amd-gpu-v1
      target_tag_plain: ${{ needs.image.outputs.target_tag_plain }}
      cuda_version: '["${{ inputs.cuda_version }}"]'
      platform: '["amd64"]'
      run_sanity_check: false
      run_cpu_only_tests: false
      run_gpu_tests: true
      gpu_test_markers: ${{ inputs.gpu_test_markers }}
      gpu_test_timeout_minutes: 30
    secrets: inherit
