name: cargo_build_common

on:
  workflow_call:
    inputs:
      run-pcc-cpu-batch:
        type: string
      run-pcc-hpu:
        type: boolean
        default: false
      run-build:
        type: boolean
        default: false
      run-build-layers:
        type: boolean
        default: false
      run-build-c-api:
        type: boolean
        default: false
      run-build-tfhe-full:
        type: boolean
        default: false
      extra-runners-to-use: # Additional runners to run builds command against
        type: string # Use comma separated values to generate an array
        default: ""
    outputs:
      builds-result:
        description: "Result of builds job"
        value: ${{ jobs.builds.outputs.result }}
    secrets:
      REPO_CHECKOUT_TOKEN:
        required: true
      SLAB_ACTION_TOKEN:
        required: true
      SLAB_BASE_URL:
        required: true
      SLAB_URL:
        required: true
      JOB_SECRET:
        required: true
      SLACK_CHANNEL:
        required: true
      BOT_USERNAME:
        required: true
      SLACK_WEBHOOK:
        required: true

env:
  CARGO_TERM_COLOR: always
  ACTION_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
  RUSTFLAGS: "-C target-cpu=native"
  RUST_BACKTRACE: "full"
  RUST_MIN_STACK: "8388608"
  SLACK_CHANNEL: ${{ secrets.SLACK_CHANNEL }}
  SLACK_ICON: https://pbs.twimg.com/profile_images/1274014582265298945/OjBKP9kn_400x400.png
  SLACK_USERNAME: ${{ secrets.BOT_USERNAME }}
  SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
  SLACKIFY_MARKDOWN: true
  CHECKOUT_TOKEN: ${{ secrets.REPO_CHECKOUT_TOKEN || secrets.GITHUB_TOKEN }}
  # Secrets will be available only to zama-ai organization members
  SECRETS_AVAILABLE: ${{ secrets.JOB_SECRET != '' }}
  EXTERNAL_CONTRIBUTION_RUNNER: "large_ubuntu_16"
  LINELINT_VERSION: 0.0.6
  LINELINT_CHECKSUM: "16b70fb7b471d6f95cbdc0b4e5dc2b0ac9e84ba9ecdc488f7bdf13df823aca4b"

permissions:
  contents: read

# zizmor: ignore[concurrency-limits] caller workflow is responsible for the concurrency

jobs:
  setup-instance:
    name: cargo_build_common/setup-instance
    if: inputs.run-pcc-cpu-batch || inputs.run-pcc-hpu || inputs.run-build || inputs.run-build-layers || inputs.run-build-tfhe-full || inputs.run-build-c-api
    runs-on: ubuntu-latest
    outputs:
      runner-name: ${{ steps.start-remote-instance.outputs.label || steps.start-github-instance.outputs.runner_group }}
      run_attempt: ${{ github.run_attempt }} # On a re-run with a successful previous run for this job, the run_attempt will not be incremented
    steps:
      - name: Start remote instance
        id: start-remote-instance
        if: env.SECRETS_AVAILABLE == 'true'
        uses: zama-ai/slab-github-runner@973c1d22702de8d0acd2b34e83404c96ed92c264 # v1.4.2
        with:
          mode: start
          github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
          slab-url: ${{ secrets.SLAB_BASE_URL }}
          job-secret: ${{ secrets.JOB_SECRET }}
          backend: aws
          profile: cpu-small

      # This instance will be spawned especially for pull-request from forked repository
      - name: Start GitHub instance
        id: start-github-instance
        if: env.SECRETS_AVAILABLE == 'false'
        run: |
          echo "runner_group=${EXTERNAL_CONTRIBUTION_RUNNER}" >> "$GITHUB_OUTPUT"

  prepare-matrix:
    name: cargo_build_common/prepare-matrix
    runs-on: ubuntu-latest
    needs: setup-instance
    outputs:
      runners: ${{ steps.set_matrix_runners.outputs.runners }}
    steps:
      - name: Parse runners
        shell: python
        env:
          INPUTS_EXTRA_RUNNERS_TO_USE: ${{ inputs.extra-runners-to-use }}
          REMOTE_RUNNER_LABEL: ${{ needs.setup-instance.outputs.runner-name }}
        run: |
          import os
          
          inputs_extra_runners = os.environ["INPUTS_EXTRA_RUNNERS_TO_USE"]
          remote_runner_label = os.environ["REMOTE_RUNNER_LABEL"]
          env_file = os.environ["GITHUB_ENV"]
          
          runners = [remote_runner_label, ]
          if inputs_extra_runners:
            split_runners = inputs_extra_runners.replace(" ", "").split(",")
            runners.extend(split_runners)

          with open(env_file, "a") as f:
            f.write(f"""RUNNERS=["{'", "'.join(runners)}"]\n""")

      - name: Set martix runners outputs
        id: set_matrix_runners
        run: | # zizmor: ignore[template-injection] these env variable are safe
          echo "runners=${{ toJSON(env.RUNNERS) }}" >> "${GITHUB_OUTPUT}"

  builds:
    name: cargo_build_common/builds
    needs: [ setup-instance, prepare-matrix ]
    runs-on: ${{ matrix.runner }}
    strategy:
      matrix:
        runner: ${{ fromJSON(needs.prepare-matrix.outputs.runners) }}
      fail-fast: false
    outputs:
      result: ${{ steps.set_builds_result.outputs.result }}
    steps:
      - name: Checkout tfhe-rs repo
        uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
        with:
          persist-credentials: 'false'
          token: ${{ env.CHECKOUT_TOKEN }}

      - name: Install latest stable
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # zizmor: ignore[stale-action-refs] this action doesn't create releases
        with:
          toolchain: stable

      - name: Install newline linter
        if: inputs.run-build && matrix.runner == env.EXTERNAL_CONTRIBUTION_RUNNER
        run: |
          wget "https://github.com/fernandrone/linelint/releases/download/${LINELINT_VERSION}/linelint-linux-amd64"
          echo "${LINELINT_CHECKSUM} linelint-linux-amd64" > checksum
          sha256sum -c checksum
          chmod +x linelint-linux-amd64
          ln -s "$(pwd)/linelint-linux-amd64" /usr/local/bin/linelint

      - name: Run pcc checks batch
        if: inputs.run-pcc-cpu-batch
        run: |
          make "${COMMAND}"
        env:
          COMMAND: ${{ inputs.run-pcc-cpu-batch }}

      - name: Run Hpu pcc checks
        if: inputs.run-pcc-hpu
        run: |
          make pcc_hpu

      - name: Build Release tfhe full
        if: inputs.run-build-tfhe-full
        run: |
          make build_tfhe_full

      - name: Run newline linter checks
        if: inputs.run-build
        run: |
          make check_newline

      - name: Build tfhe-csprng
        if: inputs.run-build
        run: |
          make build_tfhe_csprng

      - name: Build with MSRV
        if: inputs.run-build
        run: |
          make build_tfhe_msrv

      - name: Build coverage tests
        if: inputs.run-build
        run: |
          make build_tfhe_coverage

      - name: Build Release core
        if: inputs.run-build-layers
        run: |
          make build_core AVX512_SUPPORT=ON
          make build_core_experimental AVX512_SUPPORT=ON

      - name: Build Release boolean
        if: inputs.run-build-layers
        run: |
          make build_boolean

      - name: Build Release shortint
        if: inputs.run-build-layers
        run: |
          make build_shortint

      - name: Build Release integer
        if: inputs.run-build-layers
        run: |
          make build_integer

      - name: Build Release c_api
        if: inputs.run-build-c-api
        run: |
          make build_c_api

      # The wasm build check is a bit annoying to set-up here and is done during the tests in
      # aws_tfhe_tests.yml

      - name: Set result output
        id: set_builds_result
        if: ${{ always() }}
        run: | # zizmor: ignore[template-injection] this context variable is safe
          echo "result=${{ job.status }}" >> "${GITHUB_OUTPUT}"

  teardown-instance:
    name: cargo_build_common/teardown-instance
    if: ${{ always() &&
      needs.setup-instance.result == 'success' &&
      github.run_attempt == needs.setup-instance.outputs.run_attempt }} # Only run if setup-instance has been executed during this run attempt
    needs: [setup-instance, builds]
    runs-on: ubuntu-latest
    steps:
      - name: Stop remote instance
        id: stop-instance
        if: env.SECRETS_AVAILABLE == 'true'
        uses: zama-ai/slab-github-runner@973c1d22702de8d0acd2b34e83404c96ed92c264 # v1.4.2
        with:
          mode: stop
          github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
          slab-url: ${{ secrets.SLAB_BASE_URL }}
          job-secret: ${{ secrets.JOB_SECRET }}
          label: ${{ needs.setup-instance.outputs.runner-name }}

      - name: Slack Notification
        if: ${{ failure() }}
        uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661
        env:
          SLACK_COLOR: ${{ job.status }}
          SLACK_MESSAGE: "Instance teardown (cargo-builds) finished with status: ${{ job.status }}. (${{ env.ACTION_RUN_URL }})"
