runs on nv step 2

name: runs on nv step 2

on:
  workflow_call:
    inputs:
      runner:
        description: Set up the runner
        type: string
        required: false
        default: "tps-sco-ci"
      deeplink_path:
        description: ci work home
        type: string
        required: false
        default: '/mnt/cache/share/deeplinkci/github/${{ github.repository }}/'
      env_path:
        description: env file path
        type: string
        required: false
        default: '/mnt/cache/share/deeplinkci/github'
      all_coverage:
        description: all coverage
        type: string
        required: true
        default: 'false'
      require_coverage:
        description: input coverage rate
        type: string
        required: false
        default: '0'
jobs:
  Test-Cuda:
    name: Test-dipu-cuda
    runs-on: ${{ inputs.runner }}
    env:
      GETRUNNER: ${{ inputs.runner }}
      DEEPLINK_PATH: ${{ inputs.deeplink_path }}
      ENV_PATH: ${{ inputs.env_path }}
      CUDA_PARTATION: "pat_dev"
      ALL_COVERAGE: ${{ inputs.all_coverage }}
      REQUIRE_COVERAGE: ${{ inputs.require_coverage }}
    steps:
      - name: Run-test
        run: |
          if [[ "${GETRUNNER}" == *sco* ]];then
            set -e
            srun --job-name=${GITHUB_JOB} bash -c "export USE_COVERAGE=ON && cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda/dipu \
            && source ${ENV_PATH}/dipu_env  \
            && bash tests/run_nv_tests.sh"
            if [ "${ALL_COVERAGE}" = "ON" ]; then
            bash /mnt/cache/share/platform/dep/sonar/coverage_DIPU_nv.sh ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda ${GITHUB_RUN_NUMBER} || echo "get coverage fail"
            fi
          else
            ssh SH1424 """
            set -ex
            export USE_COVERAGE=ON
            cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && cd Build-Cuda/dipu
            source ${ENV_PATH}/dipu_env
            srun --job-name=${GITHUB_RUN_NUMBER}_${GITHUB_JOB} --partition=${CUDA_PARTATION} --gres=gpu:1 --cpus-per-task=5 --mem=16G --time=70 sh tests/run_nv_tests.sh
            if [ "${ALL_COVERAGE}" = "ON" ]; then
            bash /mnt/cache/share/platform/dep/sonar/coverage_DIPU_nv.sh ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda ${GITHUB_RUN_NUMBER} || echo "get coverage fail"
            fi
            """
          fi
      - name: increment coverage check
        if: ${{ contains( github.event_name, 'pull_request' ) && contains( github.base_ref, 'main' ) }}
        run: |
          if [[ "${GETRUNNER}" == *sco* ]];then
            set -e
            cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda
            ln -s ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source-main/dipu/third_party/DIOPI/scripts scripts
            source ${ENV_PATH}/dipu_env
            bash scripts/increment_coverage.sh ${REQUIRE_COVERAGE}
          else
            ssh SH1424 """
            set -e
            cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda/
            rm -rf scripts
            ln -s ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source-main/dipu/third_party/DIOPI/scripts scripts
            source /mnt/cache/share/platform/env/pt2.0_diopi
            bash scripts/increment_coverage.sh ${REQUIRE_COVERAGE}
            """
          fi

  Test-One-Iter_Cuda:
    name: Test-one-iter-cuda
    runs-on: ${{ inputs.runner }}
    env:
      GETRUNNER: ${{ inputs.runner }}
      DEEPLINK_PATH: ${{ inputs.deeplink_path }}
      ENV_PATH: ${{ inputs.env_path }}
      CUDA_PARTATION: "pat_dev"
    steps:
      - name: build some env
        run: |
          if [[ "${GETRUNNER}" == *sco* ]];then
            set -e
            export basic_path=${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda/dipu/
            srun --job-name=${GITHUB_JOB} bash -c "cd ${basic_path} \
            && export PYTHONPATH=${basic_path}/mmlab_pack:${basic_path}/mmlab_pack/mmengine:${basic_path}/mmlab_pack/mmcv:$PYTHONPATH \
            && source ${ENV_PATH}/dipu_env && cd mmlab_pack \
            && bash ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda/dipu/scripts/ci/ci_one_iter.sh build_cuda"
          else
            ssh SH1424 """
            set -ex
            cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && cd Build-Cuda/dipu
            source ${ENV_PATH}/dipu_env
            basic_path=${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda/dipu/mmlab_pack
            export PYTHONPATH=\${basic_path}/mmengine:\$PYTHONPATH
            export PYTHONPATH=\${basic_path}/mmcv:\$PYTHONPATH
            export PYTHONPATH=\$(pwd):\$PYTHONPATH
            cd mmlab_pack
            srun --job-name=${GITHUB_RUN_NUMBER}_${GITHUB_JOB} --partition=${CUDA_PARTATION} --gres=gpu:1 --time=20 bash ../scripts/ci/ci_one_iter.sh build_cuda
            """
          fi
      - name: run-one-iter-for-tradition
        run: |
          if [[ "${GETRUNNER}" == *sco* ]];then
            set -e
            cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda/dipu/ \
            && source ${ENV_PATH}/dipu_env && cd mmlab_pack \
            && rm -rf one_iter_data \
            && python ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda/dipu/scripts/ci/ci_run_one_iter.py sco  ${GITHUB_JOB} gpu sco && rm -rf one_iter_data || (rm -rf one_iter_data && exit 1)
          else
            ssh SH1424 """
              cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && cd Build-Cuda/dipu
              source ${ENV_PATH}/dipu_env
              basic_path=${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda/dipu/mmlab_pack
              source scripts/ci/ci_one_iter.sh export_pythonpath_cuda \${basic_path}
              export PYTHONPATH=\$(pwd):\$PYTHONPATH
              cd mmlab_pack
              rm -rf one_iter_data
              python ../scripts/ci/ci_run_one_iter.py cuda  ${GITHUB_RUN_NUMBER}_${GITHUB_JOB} "gpu:1" \"${CUDA_PARTATION}\" && rm -rf one_iter_data || (rm -rf one_iter_data && exit 1)
            """
          fi
      - name: run-one-iter-for-llm
        run: |
          if [[ "${GETRUNNER}" == *sco* ]];then
            set -e
            cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda/dipu/ \
            && source ${ENV_PATH}/dipu_env && cd mmlab_pack \
            && rm -rf one_iter_data \
            && python ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda/dipu/scripts/ci/ci_run_one_iter.py sco ${GITHUB_JOB} gpu sco "llm" && rm -rf one_iter_data || (rm -rf one_iter_data && exit 1)
          else
            ssh SH1424 """
            cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && cd Build-Cuda/dipu
            source ${ENV_PATH}/dipu_env
            basic_path=${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda/dipu/mmlab_pack
            source scripts/ci/ci_one_iter.sh export_pythonpath_cuda \${basic_path}
            export PYTHONPATH=\$(pwd):\$PYTHONPATH
            cd mmlab_pack
            rm -rf one_iter_data
            python ../scripts/ci/ci_run_one_iter.py cuda  ${GITHUB_RUN_NUMBER}_${GITHUB_JOB} "gpu:1" \"${CUDA_PARTATION}\" "llm" && rm -rf one_iter_data || (rm -rf one_iter_data && exit 1)
            """
          fi
      - name: Perform cleanup one iter data
        if: always()
        run: |
          if [[ "${GETRUNNER}" == *sco* ]];then
            set -e
            cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda/dipu/mmlab_pack
            rm -rf one_iter_data
            touch one_iter_data   #用于占位，防止创建新的 one_iter_data 文件夹
          else
            ssh SH1424 """
            set -ex
            echo "${GITHUB_RUN_NUMBER}_${GITHUB_JOB}"
            scancel -n "${GITHUB_RUN_NUMBER}_${GITHUB_JOB}"
            cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda/dipu/mmlab_pack
            rm -rf one_iter_data
            touch one_iter_data # 用于占位，防止创建新的 one_iter_data 文件夹
            """
          fi
      - name: Check for failure
        if: ${{ failure() }}
        run: exit 1

  Build-Cuda-Latest-Target:
    name: Build-dipu-cuda-latest-target
    runs-on: ${{ inputs.runner }}
    env:
      GETRUNNER: ${{ inputs.runner }}
      DEEPLINK_PATH: ${{ inputs.deeplink_path }}
      ENV_PATH: ${{ inputs.env_path }}
      CUDA_PARTATION: "pat_dev"
    steps:
      - name: Build dipu diopi-latest-target
        run: |
          if [[ "${GETRUNNER}" == *sco* ]];then
            set -e
            cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER} && rm -rf ${GITHUB_JOB} && cp -R source-main ${GITHUB_JOB}
            srun --job-name=${GITHUB_JOB} bash -c "export USE_COVERAGE=ON && cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/${GITHUB_JOB}/dipu \
            && source ${ENV_PATH}/dipu_env  \
            && bash scripts/ci/nv/ci_nv_script.sh build_dipu" || ( cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && exit 1 )
          else
            ssh SH1424 """
            set -ex
            cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER} && rm -rf ${GITHUB_JOB} && cp -R source-main ${GITHUB_JOB}  && cd ${GITHUB_JOB}/dipu
            source ${ENV_PATH}/dipu_env
            srun --job-name=${GITHUB_RUN_NUMBER}_${GITHUB_JOB} --partition=${CUDA_PARTATION} --gres=gpu:1 --cpus-per-task=5 --mem=16G --time=30 bash scripts/ci/nv/ci_nv_script.sh build_dipu \
            || ( cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && exit 1 )
            """
          fi

  Test-Cuda-Latest-Target:
    name: Test-dipu-cuda-latest-target
    needs: [Build-Cuda-Latest-Target]
    runs-on: ${{ inputs.runner }}
    env:
      GETRUNNER: ${{ inputs.runner }}
      DEEPLINK_PATH: ${{ inputs.deeplink_path }}
      ENV_PATH: ${{ inputs.env_path }}
      CUDA_PARTATION: "pat_dev"
    steps:
      - name: Run-test
        run: |
          if [[ "${GETRUNNER}" == *sco* ]];then
            set -e
            srun --job-name=${GITHUB_JOB} bash -c "cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda-Latest-Target/dipu \
            && source ${ENV_PATH}/dipu_env  \
            && bash tests/run_nv_tests.sh" && cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf Build-Cuda-Latest-Target
          else
            ssh SH1424 """
            set -ex
            cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && cd Build-Cuda-Latest-Target/dipu
            source ${ENV_PATH}/dipu_env
            srun --job-name=${GITHUB_RUN_NUMBER}_${GITHUB_JOB} --partition=${CUDA_PARTATION} --gres=gpu:1 --cpus-per-task=5 --mem=16G --time=60 sh tests/run_nv_tests.sh && cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf Build-Cuda-Latest-Target \
            || ( cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf Build-Cuda-Latest-Target && exit 1 )
            """
          fi

  Build-Cuda-Pt211:
    name: Build-dipu-cuda-pt211
    runs-on: ${{ inputs.runner }}
    env:
      GETRUNNER: ${{ inputs.runner }}
      DEEPLINK_PATH: ${{ inputs.deeplink_path }}
      ENV_PATH: ${{ inputs.env_path }}
      CUDA_PARTATION: "pat_dev"
    steps:
      - name: Build dipu
        run: |
          if [[ "${GETRUNNER}" == *sco* ]];then
            set -e
            cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER} && rm -rf ${GITHUB_JOB} && cp -R source ${GITHUB_JOB}
            srun --job-name=${GITHUB_JOB} bash -c "cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/${GITHUB_JOB}/dipu \
            && source ${ENV_PATH}/dipu_env 2.1.1 \
            && bash scripts/ci/nv/ci_nv_script.sh build_dipu " || ( cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && exit 1 )
          else
            ssh SH1424 """
              set -ex
              cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER} && rm -rf ${GITHUB_JOB} && cp -R source ${GITHUB_JOB} && cd ${GITHUB_JOB}/dipu
              source ${ENV_PATH}/dipu_env 2.1.1
              srun --job-name=${GITHUB_RUN_NUMBER}_${GITHUB_JOB} --partition=${CUDA_PARTATION} --gres=gpu:1 --cpus-per-task=5 --mem=16G --time=60 bash scripts/ci/nv/ci_nv_script.sh build_dipu \
              || ( cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && exit 1 )
              """
          fi

  Test-Cuda-Pt211:
    name: Test-dipu-cuda-pt211
    needs: [Build-Cuda-Pt211]
    runs-on: ${{ inputs.runner }}
    env:
      GETRUNNER: ${{ inputs.runner }}
      DEEPLINK_PATH: ${{ inputs.deeplink_path }}
      ENV_PATH: ${{ inputs.env_path }}
      CUDA_PARTATION: "pat_dev"
    steps:
      - name: Run-test
        run: |
          if [[ "${GETRUNNER}" == *sco* ]];then
            set -e
            srun --job-name=${GITHUB_JOB} bash -c "cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda-Pt211/dipu \
            && source ${ENV_PATH}/dipu_env 2.1.1 \
            && bash tests/run_nv_tests.sh" && cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf Build-Cuda-Pt211
          else
            ssh SH1424 """
            set -ex
            cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Cuda-Pt211/dipu
            source ${ENV_PATH}/dipu_env 2.1.1
            srun --job-name=${GITHUB_RUN_NUMBER}_${GITHUB_JOB} --partition=${CUDA_PARTATION} --gres=gpu:1 --cpus-per-task=5 bash tests/run_nv_tests.sh \
            || ( cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf Build-Cuda-Pt211 && exit 1 )
            """
          fi


runs on topsrider

name: runs on topsrider

on:
  workflow_call:
    inputs:
      machine:
        description: If set to other value, the job need ssh
        type: string
        required: false
        default: "TOPSRIDER"
      runner:
        description: Set up the build environment
        type: string
        required: false
        default: "tps-topsrider-dicp"

jobs:
  checkout_code:
    name: checkout code
    runs-on: ${{ inputs.runner }}
    steps:
      - name: Checkout Code
        uses: DeepLink-org/deeplink.framework/.github/actions/checkout-code@main

  build_test:
    runs-on: ${{ inputs.runner }}
    needs: checkout_code
    steps:
      - name: build on topsrider
        uses: DeepLink-org/deeplink.framework/.github/actions/code-build-test@main
        with:
          build_shell: "
                       source dicp/scripts/ci/tops/ci_tops_build_env.sh && \
                       pip uninstall torch_dipu -y && \
                       pip uninstall dicp -y && \
                       cd dipu && python setup.py install --user && \
                       cd ../dicp && python setup.py install --user
                       "
          job_name: "build_test"
          cover_job: "0"

      - name: test ops on topsrider
        uses: DeepLink-org/deeplink.framework/.github/actions/code-build-test@main
        with:
          build_shell: "
                       source dicp/scripts/ci/tops/ci_tops_test_env.sh && \
                       export TEST_DIR=$(pwd)/dicp/test && \
                       bash ${TEST_DIR}/tops_scripts/ops/run_test_ops.sh false
                       "
          job_name: "build_test"
          cover_job: "1"


dipu ce

name: dipu ce
on:
  workflow_dispatch:
#  push:
#    branches:
#      - "wgs/**"
  schedule:
    - cron: '30 11 * * 6'
env:
  target_file: "/home/autolink/rsync/train_flag"
  source_file: "/artifacts/train_flag"

concurrency:
  group: ${{ github.head_ref || github.ref }}
  cancel-in-progress: true

jobs:
  Archive_Results:
    name: archive train results
    runs-on: github-tps-ce
    outputs:
      results: ${{ steps.step1.outputs.results }}
    steps:
      - name: Check if collected
        id: step1
        run: |
          diff_output=$(diff -q --ignore-all-space  "$target_file" "$source_file" ) && export to_archive=false || export to_archive=true
          echo "to_archive=$to_archive" >> "$GITHUB_ENV"
          if [ $to_archive == "false" ]; then
            echo "The file content is the same,results have been collected"
          fi
      - name: Archive results
        if: ${{ env.to_archive == 'true' }}
        uses: actions/upload-artifact@v3
        with:
          name: train-results
          path: /artifacts/**
      - name: Flag override
        if: ${{ env.to_archive == 'true' }}
        run: |
          echo "strat to override target_file"
          cp -r ${source_file} ${target_file}


dicp ci

name: dicp ci
on:
  workflow_dispatch:
  schedule:
    - cron: '10 23 * * *'
  pull_request:
    paths:
      - ".github/workflows/dicp.yml"
      - ".github/workflows/_runs-on-ascend.yml"
      - ".github/workflows/_runs-on-topsrider.yml"
      - "dicp/**"

env:
  ENV_PATH: '/mnt/cache/share/platform/env'
  DEEPLINK_PATH: '/mnt/cache/share/deeplinkci/github/${{ github.repository }}'

concurrency:
  group: dicp-${{ github.head_ref || github.ref }}
  cancel-in-progress: true

jobs:
  runs-on-topsrider:
    name: runs on topsrider
    uses: ./.github/workflows/_runs-on-topsrider.yml

  runs-on-ascend:
    name: runs on ascend
    uses: ./.github/workflows/_runs-on-ascend.yml


format

name: format

on:
  workflow_dispatch:
  pull_request:
  push:
    branches:
      - main

jobs:
  markdownlint:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
      with:
        fetch-depth: 16
    - name: Collect changed files
      uses: tj-actions/changed-files@v40
      id: changed-files
      with:
        files: '**/*.md'
        separator: ','
    - name: MarkdownLint
      if: steps.changed-files.outputs.any_changed == 'true'
      uses: DavidAnson/markdownlint-cli2-action@v14
      with:
        globs: ${{ steps.changed-files.outputs.all_changed_files }}
        separator: ','

  clang-format:
    needs: markdownlint
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: cpp-linter/cpp-linter-action@v2
      id: cpp-lint
      with:
        style: file
        tidy-checks: '-*' # disable clang tidy at this stage
        version: 17
    - name: Fail test
      if: steps.cpp-lint.outputs.checks-failed > 0
      run: echo "Some files failed the linting checks!" && exit 1

  python-black:
    needs: markdownlint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: psf/black@stable
        with: # see: https://black.readthedocs.io/en/stable/getting_started.html
          src: "dipu"
          version: "~= 24.3.0"


dipu  ci

name: dipu  ci
on:
  workflow_dispatch:
  push:
    branches:
      - main
      - dev_v0.25
    tags:
      - 'v*'
  pull_request:
    paths-ignore:
      -  "dicp/**"

env:
  CAMB_CI_PATH: '/mnt/lustre/share/parrotsci/github/cibuild/${{ github.repository }}'
  CAMB_PARTATION: ${{ vars.CAMB_SLURM_PAR != '' && vars.CAMB_SLURM_PAR || 'camb_mlu370_m8' }}
  CAMB_CLUSTER: CAMB
  CUDA_CI_PATH: '/mnt/cache/share/parrotsci/github/cibuild/${{ github.repository }}'
  CUDA_PARTATION: ${{ vars.SH1988_SLURM_PAR != '' && vars.SH1988_SLURM_PAR || 'pat_rd' }}
  CUDA_CLUSTER: SCO
  CUDA_ENV_PATH: '/mnt/cache/share/deeplinkci/github'
  DEEPLINK_PATH: '/mnt/cache/share/deeplinkci/github/${{ github.repository }}'
  ASCEND_CLUSTER: ASCEND
  CLUSTER_ASCEND_910B: ASCEND-910B
  ASCEND_TORCH_DIR: '/mnt/cache/share/platform/cienv/pytorch'
  CI_BUILD_FLAG: "ci_build_flag"
  # need deprecated but ascend still use it, PYTORCH_COMMIT not support multi-version torch
  PYTORCH_COMMIT: ${{ vars.PYTORCH_COMMIT != '' && vars.PYTORCH_COMMIT || 'c263bd43e8e8502d4726643bc6fd046f0130ac0e' }} # pytorch tag 2.0
  ALL_COVERAGE: ${{ (contains( github.ref, 'main') || startsWith(github.ref, 'refs/heads/v') || startsWith(github.ref, 'refs/heads/dev')) && 'ON' || 'OFF' }}
  REQUIRE_COVERAGE: ${{ vars.REQUIRE_COVERAGE != '' && vars.REQUIRE_COVERAGE || '0' }}
  REPO: ${{ github.event.repository.name }}

concurrency:
  group: dipu-${{ github.head_ref || github.ref }}
  cancel-in-progress: true

jobs:
  Rsync:
    name: Rsync code
    runs-on: github-poc-ci
    outputs:
      getrunner: ${{ steps.set-run-vars.outputs.GETRUNNER }}
    steps:
      - name: clone repo
        run: |
          set -ex
          cd ${GITHUB_WORKSPACE} && rm -rf DIPU ${REPO}_DIOPI ${REPO} ${REPO}.dev
          if [ -n "${{ github.event.pull_request.head.repo.full_name }}" ] && [[ ! "${{ github.event.pull_request.head.repo.full_name }}" == "${{ github.repository }}" ]]; then
            git clone ${{ github.event.pull_request.head.repo.ssh_url }} ${REPO}
            cd ${GITHUB_WORKSPACE}/${REPO} && git checkout ${{ github.event.pull_request.head.sha }}
            git remote add mainrepo git@github.com:${GITHUB_REPOSITORY}.git
            git fetch  mainrepo && git merge --no-edit mainrepo/${{ github.base_ref }}
          else
            git clone https://github.com/DeepLink-org/${REPO}.git && cd ${REPO}
            if [ $GITHUB_EVENT_NAME == "pull_request" ]; then
              echo "${{ github.base_ref }} "
              git checkout ${{ github.event.pull_request.head.sha }} && git merge --no-edit origin/${{ github.base_ref }}
            else
              echo $GITHUB_EVENT_NAME
              git checkout ${{ github.sha }}
            fi
          fi
          cd ${GITHUB_WORKSPACE}/${REPO}/dipu && rm -rf third_party/kineto
          git clone --reference /home/autolink/rsync/sourcecode/DeepLink-org/kineto https://github.com/DeepLink-org/kineto.git third_party/kineto
          git submodule update --init && cd third_party/kineto && git submodule update --init
          cd ${GITHUB_WORKSPACE} && cp -R ${REPO} ${REPO}_DIOPI
          cd ${REPO}/dipu && bash /home/autolink/rsync/sourcecode/update_code.sh
          rsync -a /home/autolink/rsync/sourcecode/mmlab_pack . && cd mmlab_pack
          bash ../scripts/ci/ci_one_iter.sh clone
          #  dipu_diopi depend on latest target diopi branch, not diopi in submodule. here assume diopi and dipu use same  'target branch' " github.base_ref "
          cd ${GITHUB_WORKSPACE}/${REPO}_DIOPI/dipu/third_party && rm -rf DIOPI && git clone https://github.com/DeepLink-org/DIOPI.git
          if [ $GITHUB_EVENT_NAME == "pull_request" ]; then
            cd ./DIOPI && git checkout ${{ github.base_ref }}
          fi
      - name: set output and Rsync to Server
        id: set-run-vars
        run: |
          GETRUNNER=$(cat ~/rsync/cuda_runner_dipu)
          if [[ ${GETRUNNER} == *diopi* ]]; then
              CUDA_CLUSTER="SH1424"
          fi
          echo "GETRUNNER=$GETRUNNER" >> "$GITHUB_OUTPUT"
          ssh ${CAMB_CLUSTER} "mkdir -p ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/source ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/source-main" \
          && rsync -a --delete ${GITHUB_WORKSPACE}/${REPO}/ ${CAMB_CLUSTER}:${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/source/ \
          && rsync -a --delete ${GITHUB_WORKSPACE}/${REPO}_DIOPI/ ${CAMB_CLUSTER}:${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/source-main/ || echo "failure to connect to camb"
          ssh ${CUDA_CLUSTER} "mkdir -p ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source-main" \
          && rsync -a --delete ${GITHUB_WORKSPACE}/${REPO}/ ${CUDA_CLUSTER}:${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source/ \
          && rsync -a --delete ${GITHUB_WORKSPACE}/${REPO}_DIOPI/ ${CUDA_CLUSTER}:${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source-main/ || echo "failure to connect to cuda"
          # ssh ${CLUSTER_ASCEND_910B} "mkdir -p ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source-main" \
          # && rsync -a --delete ${GITHUB_WORKSPACE}/${REPO}/ ${CLUSTER_ASCEND_910B}:${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source/ \
          # && rsync -a --delete ${GITHUB_WORKSPACE}/${REPO}_DIOPI/ ${CLUSTER_ASCEND_910B}:${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source-main/ || echo "failure to connect to ascend"
          source ~/Aoss_env.sh
          ads-cli cp ${GITHUB_WORKSPACE}/${REPO}/ s3://${Platform_ci_aoss_name}:${Platform_ci_aoss_url}@platform.aoss.cn-sh-01c.sensecoreapi-oss.cn${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source/
          ads-cli cp ${GITHUB_WORKSPACE}/${REPO}_DIOPI/ s3://${Platform_ci_aoss_name}:${Platform_ci_aoss_url}@platform.aoss.cn-sh-01c.sensecoreapi-oss.cn${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source-main/

  Deploy_on_tag:
    runs-on: tps-sco-ci
    if: startsWith(github.ref, 'refs/tags/v')
    steps:
      - name: Run script on tag
        run: |
          TAG=${GITHUB_REF#refs/tags/} # Extract the tag name
          echo $TAG
          bash /mnt/cache/share/platform/dep/Deploy_DIPU_trigger.sh "$TAG"

  Build-Camb:
    name: Build-dipu-camb
    needs: [Runs-On-Nv-Step1]
    runs-on: github-poc-ci
    env:
      MLU_REQUESTS: 1
    steps:
      - name: Build dipu
        run: |
          ssh ${CAMB_CLUSTER} """
          set -ex
          export USE_COVERAGE=ON
          cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && cp -R source ${GITHUB_JOB}  && cd ${GITHUB_JOB}/dipu
          source scripts/ci/camb/ci_camb_env.sh
          rsync -a /mnt/lustre/share_data/PAT/datasets/huggingface mmlab_pack/
          srun --job-name=${GITHUB_JOB} --partition=${CAMB_PARTATION} --time=40 \
          --gres=mlu:${MLU_REQUESTS} bash scripts/ci/camb/ci_camb_script.sh build_dipu \
          || ( cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && exit 1 )
          """

  Test-Camb:
    name: Test-dipu-camb
    needs: [Build-Camb]
    runs-on: github-poc-ci
    env:
      MLU_REQUESTS: 1
    steps:
      - name: Run-test
        run: |
          ssh ${CAMB_CLUSTER} """
          set -ex
          export USE_COVERAGE=ON
          cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/ && cd Build-Camb/dipu
          source scripts/ci/camb/ci_camb_env.sh
          srun --job-name=${GITHUB_JOB} --partition=${CAMB_PARTATION} --time=40 --gres=mlu:${MLU_REQUESTS} sh tests/run_camb_tests.sh
          if [ "${ALL_COVERAGE}" = "ON" ]; then
          sh /mnt/lustre/share/platform/dep/sonar/coverage_DIPU_camb.sh ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/Build-Camb ${GITHUB_RUN_NUMBER} || echo "get coverage fail"
          fi
          """
      - name: increment coverage check
        if: ${{ contains( github.event_name, 'pull_request' ) && contains( github.base_ref, 'main' ) }}
        run: |
          ssh ${CAMB_CLUSTER} """
          set -e
          cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/Build-Camb
          rm -rf scripts
          ln -s ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/source-main/dipu/third_party/DIOPI/scripts scripts
          source /mnt/cache/share/platform/env/pt2.0_diopi
          bash scripts/increment_coverage.sh ${REQUIRE_COVERAGE}
          """

  Build-Camb-Pt210:
    name: Build-dipu-camb-pt210
    needs: [Runs-On-Nv-Step1]
    runs-on: github-poc-ci
    env:
      MLU_REQUESTS: 1
    steps:
      - name: Build dipu
        run: |
          ssh ${CAMB_CLUSTER} """
          set -ex
          cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && cp -R source ${GITHUB_JOB}  && cd ${GITHUB_JOB}/dipu
          source scripts/ci/camb/ci_camb_env.sh  2.1
          srun --job-name=${GITHUB_JOB} --partition=${CAMB_PARTATION} --time=40 \
          --gres=mlu:${MLU_REQUESTS} bash scripts/ci/camb/ci_camb_script.sh build_dipu \
          || ( cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && exit 1 )
          """

  # torch2.1.0 in camb ci is not a complete one, no test dir.
  # Test-Camb-Pt210:
  #   name: Test-dipu-camb-pt210
  #   needs: [Build-Camb-Pt210]
  #   runs-on: github-poc-ci
  #   env:
  #     MLU_REQUESTS: 1
  #   steps:
  #     - name: Run-test
  #       run: |
  #         ssh ${CAMB_CLUSTER} """
  #         set -ex
  #         cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/ && cd Build-Camb-Pt210/dipu
  #         source scripts/ci/camb/ci_camb_env.sh 2.1
  #         srun --job-name=${GITHUB_JOB} --partition=${CAMB_PARTATION} --time=40 --gres=mlu:${MLU_REQUESTS} sh tests/run_camb_tests.sh && \
  #         cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf Build-Camb-Pt210
  #         """

  Build-Camb-Pt211:
    name: Build-dipu-camb-pt211
    needs: [Runs-On-Nv-Step1]
    runs-on: github-poc-ci
    env:
      MLU_REQUESTS: 1
    steps:
      - name: Build dipu
        run: |
          ssh ${CAMB_CLUSTER} """
          set -ex
          cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && cp -R source ${GITHUB_JOB}  && cd ${GITHUB_JOB}/dipu
          source scripts/ci/camb/ci_camb_env.sh  2.1.1
          srun --job-name=${GITHUB_JOB} --partition=${CAMB_PARTATION} --time=40 \
          --gres=mlu:${MLU_REQUESTS} bash scripts/ci/camb/ci_camb_script.sh build_dipu \
          || ( cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && exit 1 )
          """

  Test-Camb-Pt211:
    name: Test-dipu-camb-pt211
    needs: [Build-Camb-Pt211]
    runs-on: github-poc-ci
    env:
      MLU_REQUESTS: 1
    steps:
      - name: Run-test
        run: |
          ssh ${CAMB_CLUSTER} """
          set -ex
          cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/ && cd Build-Camb-Pt211/dipu
          source scripts/ci/camb/ci_camb_env.sh 2.1.1
          srun --job-name=${GITHUB_JOB} --partition=${CAMB_PARTATION} --time=40 --gres=mlu:${MLU_REQUESTS} sh tests/run_camb_tests.sh && \
          cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf Build-Camb-Pt211
          """

  Test-One-Iter-Camb:
    name: Test-one-iter-camb
    needs: [Build-Camb]
    runs-on: github-poc-ci
    env:
      MLU_REQUESTS: 1
    steps:
      - name: build-some-env
        run: |
          ssh ${CAMB_CLUSTER} """
          set -ex
          cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/Build-Camb/dipu
          source scripts/ci/camb/ci_camb_env.sh
          basic_path=${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/Build-Camb/dipu/mmlab_pack
          export PYTHONPATH=\${basic_path}/mmengine:\$PYTHONPATH
          export PYTHONPATH=\${basic_path}/mmcv:\$PYTHONPATH
          export PYTHONPATH=\$(pwd):\$PYTHONPATH
          cd mmlab_pack
          srun --job-name=${GITHUB_RUN_NUMBER}_${GITHUB_JOB} --partition=${CAMB_PARTATION} --gres=mlu:${MLU_REQUESTS} sh ../scripts/ci/ci_one_iter.sh build_camb
          """
      - name: run-one-iter-for-tradition
        run: |
          ssh ${CAMB_CLUSTER} """
          set -ex
          cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/Build-Camb/dipu
          source scripts/ci/camb/ci_camb_env.sh
          basic_path=${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/Build-Camb/dipu/mmlab_pack
          source scripts/ci/ci_one_iter.sh export_pythonpath_camb \${basic_path}
          export PYTHONPATH=\$(pwd):\$PYTHONPATH
          cd mmlab_pack
          rm -rf one_iter_data
          python ../scripts/ci/ci_run_one_iter.py camb ${GITHUB_JOB} "mlu:${MLU_REQUESTS}" \"${CAMB_PARTATION}\" && rm -rf one_iter_data || (rm -rf one_iter_data && exit 1)
          """
      - name: run-one-iter-for-llm
        run: |
          ssh ${CAMB_CLUSTER} """
          set -ex
          cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/Build-Camb/dipu
          source scripts/ci/camb/ci_camb_env.sh
          basic_path=${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/Build-Camb/dipu/mmlab_pack
          source scripts/ci/ci_one_iter.sh export_pythonpath_camb \${basic_path}
          export PYTHONPATH=\$(pwd):\$PYTHONPATH
          cd mmlab_pack
          rm -rf one_iter_data
          python ../scripts/ci/ci_run_one_iter.py camb ${GITHUB_JOB} "mlu:${MLU_REQUESTS}" \"${CAMB_PARTATION}\" "llm" && rm -rf one_iter_data || (rm -rf one_iter_data && exit 1)
          """
      - name: Perform cleanup one iter data
        if: always()
        run: |
          ssh ${CAMB_CLUSTER} """
              set -ex
              echo "${GITHUB_RUN_NUMBER}_${GITHUB_JOB}"
              scancel -n "${GITHUB_RUN_NUMBER}_${GITHUB_JOB}"
              cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/Build-Camb/dipu/mmlab_pack
              rm -rf one_iter_data
              touch one_iter_data # 用于占位，防止创建新的 one_iter_data 文件夹
          """

      - name: Check for failure
        if: ${{ failure() }}
        run: exit 1

  Build-Camb-Latest-Target:
    name: Build-dipu-camb-latest-target
    needs: [Runs-On-Nv-Step1]
    runs-on: github-poc-ci
    env:
      MLU_REQUESTS: 1
    steps:
      - name: Build dipu diopi-latest-target
        run: |
          ssh ${CAMB_CLUSTER} """
          set -ex
          cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && cp -R source-main ${GITHUB_JOB}  && cd ${GITHUB_JOB}/dipu
          source scripts/ci/camb/ci_camb_env.sh
          srun --job-name=${GITHUB_JOB} --partition=${CAMB_PARTATION} --time=40 \
          --gres=mlu:${MLU_REQUESTS} bash scripts/ci/camb/ci_camb_script.sh build_dipu \
          || ( cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && exit 1 )
          """

  Test-Camb-Latest-Target:
    name: Test-dipu-camb-latest-target
    needs: [Build-Camb-Latest-Target]
    runs-on: github-poc-ci
    env:
      MLU_REQUESTS: 1
    steps:
      - name: Run-test
        run: |
          ssh ${CAMB_CLUSTER} """
          set -ex
          cd ${CAMB_CI_PATH}/${GITHUB_RUN_NUMBER}/ && cd Build-Camb-Latest-Target/dipu
          source scripts/ci/camb/ci_camb_env.sh
          srun --job-name=${GITHUB_JOB} --partition=${CAMB_PARTATION} --time=40 --gres=mlu:${MLU_REQUESTS} sh tests/run_camb_tests.sh
          """

  Runs-On-Nv-Step1:
    name: runs on nv step1
    needs: [Rsync]
    uses: ./.github/workflows/_runs-on-nv-step1.yml
    with:
      runner: ${{ needs.Rsync.outputs.getrunner }}

  Runs-On-Nv-Step2:
    name: runs on nv step2
    needs: [Rsync,Runs-On-Nv-Step1]
    uses: ./.github/workflows/_runs-on-nv-step2.yml
    with:
      runner: ${{ needs.Rsync.outputs.getrunner }}
      all_coverage: ${{ (contains( github.ref, 'main') || startsWith(github.ref, 'refs/heads/v') || startsWith(github.ref, 'refs/heads/dev')) && 'ON' || 'OFF' }}
      require_coverage: ${{ vars.REQUIRE_COVERAGE != '' && vars.REQUIRE_COVERAGE || '0' }}

  Build-PyTorch-For-Ascend-910b:
    name: Build-dipu-pytorch-for-ascend-910b
    needs: [Runs-On-Nv-Step1]
    runs-on: tps-ascend-ci-910b
    steps:
      - name: COPY Source
        run: |
          set -ex
          source ~/Aoss_env.sh
          ads-cli cp s3://${Platform_ci_aoss_name}:${Platform_ci_aoss_url}@platform.aoss-internal.cn-sh-01c.sensecoreapi-oss.cn${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source/ ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source/
          ads-cli cp s3://${Platform_ci_aoss_name}:${Platform_ci_aoss_url}@platform.aoss-internal.cn-sh-01c.sensecoreapi-oss.cn${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source-main/ ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source-main/
          ads-cli  --dryrun --deleteSrc cp  s3://${Platform_ci_aoss_name}:${Platform_ci_aoss_url}@platform.aoss-internal.cn-sh-01c.sensecoreapi-oss.cn${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source/ /dev/null 2>&1 >/dev/null
          ads-cli  --dryrun --deleteSrc cp  s3://${Platform_ci_aoss_name}:${Platform_ci_aoss_url}@platform.aoss-internal.cn-sh-01c.sensecoreapi-oss.cn${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source-main/ /dev/null 2>&1 >/dev/null
          find ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source -type f -name "*.sh" -exec chmod +x {} \;
          find ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source-main -type f -name "*.sh" -exec chmod +x {} \;
      - name: Build PyTorch
        run: |
          set -ex
          cd ${ASCEND_TORCH_DIR}
          if [ "$(git rev-parse HEAD)" != "${PYTORCH_COMMIT}" ]; then
            rm -rf build
          fi
          if [ ! -d "build" ]; then
            source ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source/dipu/scripts/ci/ascend/ci_ascend_env.sh
            export CMAKE_PREFIX_PATH=${CONDA_PREFIX:-"$(dirname $(which conda))/../"}
            BUILD_BINARY=0 USE_PRECOMPILED_HEADERS=1 BUILD_TEST=0 USE_CUDA=0 python setup.py build_ext -i || (rm -rf build && exit 1)
          fi

  Build-Ascend-910b:
    name: Build-dipu-ascend-910b
    needs: [Build-PyTorch-For-Ascend-910b]
    runs-on: tps-ascend-ci-910b
    steps:
      - name: Build dipu
        run: |
          set -ex
          export USE_COVERAGE=ON
          cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && cp -R source ${GITHUB_JOB}  && cd ${GITHUB_JOB}/dipu
          source scripts/ci/ascend/ci_ascend_env.sh
          bash scripts/ci/ascend/ci_ascend_script.sh build_dipu \
          || ( cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && exit 1 )

  Test-Ascend-910b:
    name: Test-dipu-ascend-910b
    needs: [Build-Ascend-910b]
    runs-on: tps-ascend-ci-910b
    steps:
      - name: Run a test
        run: |
          set -ex
          cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Ascend-910b/dipu
          source scripts/ci/ascend/ci_ascend_env.sh
          bash tests/run_ascend_tests.sh
          if [ "${ALL_COVERAGE}" = "ON" ]; then
          bash /mnt/cache/share/platform/dep/sonar/coverage_DIPU.sh ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Ascend-910b/dipu || echo "get coverage fail"
          fi
      - name: increment coverage check
        if: ${{ contains( github.event_name, 'pull_request' ) && contains( github.base_ref, 'main' ) }}
        run: |
          set -ex
          cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Ascend-910b/
          rm -rf scripts
          ln -s ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source-main/dipu/third_party/DIOPI/scripts scripts
          source dipu/scripts/ci/ascend/ci_ascend_env.sh
          bash scripts/increment_coverage.sh ${REQUIRE_COVERAGE}

  Build-Dicp-On-Dipu-Ascend:
    name: Build-dicp-on-dipu-ascend
    needs: [Build-PyTorch-For-Ascend-910b]
    runs-on: tps-ascend-ci-910b
    steps:
      - name: Build dipu
        run: |
          set -ex
          export PYTHONUSERBASE=${HOME}/.local.dicp
          cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && cp -R source ${GITHUB_JOB}  && cd ${GITHUB_JOB}/
          source dicp/scripts/ci/ascend/ci_runs_on_dipu_env.sh
          cd dipu && bash scripts/ci/ascend/ci_ascend_script.sh build_dipu_without_diopi \
          || ( cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && exit 1 )
  Test-Dicp-On-Dipu-Ascend:
    name: Test-dicp-on-dipu-ascend
    needs: [Build-Dicp-On-Dipu-Ascend]
    runs-on: tps-ascend-ci-910b
    steps:
      - name: Run dicp test
        run: |
          set -ex
          export PYTHONUSERBASE=${HOME}/.local.dicp
          rm -rf /tmp/dicp_ascend/*
          cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Dicp-On-Dipu-Ascend
          source dicp/scripts/ci/ascend/ci_runs_on_dipu_env.sh
          export PYTHONPATH=${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Dicp-On-Dipu-Ascend/dipu:${PYTHONPATH}
          pip uninstall dicp -y
          cd dicp && python setup.py clean && python setup.py install --user
          export TEST_DIR=$(pwd)/test
          source scripts/ci/ascend/test_env.sh /mnt/cache/share/deeplinkci/dicp_env/llama_models
          bash ${TEST_DIR}/ascend_scripts/ops/run_test_ops.sh false && \
          pytest test/model/test_llama.py --backend ascendgraph --dynamic false \
          || ( cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf Build-Dicp-On-Dipu-Ascend && exit 1 )

  Test-One-Iter-Ascend-910b:
    name: Test-one-iter-ascend-910b
    needs: [Build-Ascend-910b]
    runs-on: tps-ascend-ci-910b
    steps:
      - name: Build some env
        run: |
          set -ex
          cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Ascend-910b/dipu
          source scripts/ci/ascend/ci_ascend_env.sh
          basic_path=${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Ascend-910b/dipu/mmlab_pack
          source scripts/ci/ci_one_iter.sh export_pythonpath_ascend ${basic_path}
          cd mmlab_pack
          bash ../scripts/ci/ci_one_iter.sh build_ascend910b

      - name: run-one-iter-for-tradition
        run: |
          set -ex
          cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Ascend-910b/dipu
          source scripts/ci/ascend/ci_ascend_env.sh
          basic_path=${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Ascend-910b/dipu/mmlab_pack
          source scripts/ci/ci_one_iter.sh export_pythonpath_ascend ${basic_path}
          cd mmlab_pack
          rm -rf one_iter_data
          python ../scripts/ci/ci_run_one_iter.py ascend "" "" "" && rm -rf one_iter_data || (rm -rf one_iter_data && exit 1)

      - name: run-one-iter-for-llm
        run: |
          set -ex
          cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Ascend-910b/dipu
          source scripts/ci/ascend/ci_ascend_env.sh
          basic_path=${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Ascend-910b/dipu/mmlab_pack
          source scripts/ci/ci_one_iter.sh export_pythonpath_ascend ${basic_path}
          cd mmlab_pack
          rm -rf one_iter_data
          python ../scripts/ci/ci_run_one_iter.py ascend "" "" "" "llm" && rm -rf one_iter_data || (rm -rf one_iter_data && exit 1)

      - name: Perform cleanup one iter data
        if: always()
        run: |
          set -ex
          cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Ascend-910b/dipu/mmlab_pack
          rm -rf one_iter_data
          touch one_iter_data # 用于占位，防止创建新的 one_iter_data 文件夹

      - name: Check for failure
        if: ${{ failure() }}
        run: exit 1

  Build-Ascend-Latest-Target-910b:
    name: Build-dipu-ascend-latest-target-910b
    needs: [Build-PyTorch-For-Ascend-910b]
    runs-on: tps-ascend-ci-910b
    steps:
      - name: Build dipu diopi-latest-target
        run: |
          set -ex
          cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && cp -R source-main ${GITHUB_JOB}  && cd ${GITHUB_JOB}/dipu
          source scripts/ci/ascend/ci_ascend_env.sh
          bash scripts/ci/ascend/ci_ascend_script.sh build_dipu \
          || ( cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && exit 1 )

  Test-Ascend-Latest-Target-910b:
    name: Test-dipu-ascend-latest-target-910b
    needs: [Build-Ascend-Latest-Target-910b]
    runs-on: tps-ascend-ci-910b
    steps:
      - name: Run a test
        run: |
          set -ex
          cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Ascend-Latest-Target-910b/dipu
          source scripts/ci/ascend/ci_ascend_env.sh
          bash tests/run_ascend_tests.sh && cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf Build-Ascend-Latest-Target \
          || ( cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf Build-Ascend-Latest-Target && exit 1 )


dipu ci on klx

name: dipu ci on klx
on:
  workflow_dispatch:
  # schedule:
  #   - cron: '10 22 * * *'
  # pull_request:
  #   paths:
  #     - ".github/workflows/runs_on_klx.yml"
  #     - "dipu/torch_dipu/csrc_dipu/vendor/kunlunxin/**"
env:
  DEEPLINK_PATH: '/mnt/cache/share/deeplinkci/github/${{ github.repository }}'
  CLUSTER_KLX: KUNLUNXIN
  ALL_COVERAGE: ${{ (contains( github.ref, 'main') || startsWith(github.ref, 'refs/heads/v') || startsWith(github.ref, 'refs/heads/dev')) && 'ON' || 'OFF' }}
  REQUIRE_COVERAGE: ${{ vars.REQUIRE_COVERAGE != '' && vars.REQUIRE_COVERAGE || '0' }}

jobs:
  Checkout-code:
    name: Checkout code
    runs-on: github-poc-ci
    steps:
      - name: clone repo
        run: |
          set -ex
          cd ${GITHUB_WORKSPACE} && rm -rf source
          if [ -n "${{ github.event.pull_request.head.repo.full_name }}" ] && [[ ! "${{ github.event.pull_request.head.repo.full_name }}" == "${{ github.repository }}" ]]; then
            git clone ${{ github.event.pull_request.head.repo.ssh_url }} source
            cd ${GITHUB_WORKSPACE}/source && git checkout ${{ github.event.pull_request.head.sha }}
            git remote add mainrepo git@github.com:${GITHUB_REPOSITORY}.git
            git fetch  mainrepo && git merge --no-edit mainrepo/${{ github.base_ref }}
          else
            git clone ${{ github.event.repository.clone_url }} source && cd source
            if [ $GITHUB_EVENT_NAME == "pull_request" ]; then
              echo "${{ github.base_ref }} "
              git checkout ${{ github.event.pull_request.head.sha }} && git merge --no-edit origin/${{ github.base_ref }}
            else
              echo $GITHUB_EVENT_NAME
              git checkout ${{ github.sha }}
            fi
          fi
          cd ${GITHUB_WORKSPACE}/source/dipu/third_party && rm -rf DIOPI && git clone https://github.com/DeepLink-org/DIOPI.git
          rm -rf kineto && git clone --reference /home/autolink/rsync/sourcecode/DeepLink-org/kineto https://github.com/DeepLink-org/kineto.git kineto
          cd ../.. && git submodule update --init && cd dipu/third_party/kineto && git submodule update --init
          cd ${GITHUB_WORKSPACE}/source/dipu && bash /home/autolink/rsync/sourcecode/update_code.sh
          rsync -a /home/autolink/rsync/sourcecode/mmlab_pack . && cd mmlab_pack
          bash ../scripts/ci/ci_one_iter.sh clone
      - name: Rsync to Server
        run: |
          ssh ${CLUSTER_KLX} "mkdir -p ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source" \
          && rsync -a --delete ${GITHUB_WORKSPACE}/source/ ${CLUSTER_KLX}:${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source/ || echo "failure to connect to kunlunxin"

  Build-Kunlunxin:
    name: Build-Kunlunxin
    needs: [Checkout-code]
    runs-on: tps-klx-ci
    steps:
      - name: Build dipu
        run: |
          set -ex
          export USE_COVERAGE=ON
          cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && cp -R source ${GITHUB_JOB}  && cd ${GITHUB_JOB}/dipu
          source scripts/ci/kunlunxin/ci_kunlunxin_env.sh
          python setup.py build_ext -i \
          || ( cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/ && rm -rf ${GITHUB_JOB} && exit 1 )

  Test-Kunlunxin:
    name: Test-Kunlunxin
    needs: [Build-Kunlunxin]
    runs-on: tps-klx-ci
    steps:
      - name: Run a test
        run: |
          set -ex
          cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Kunlunxin/dipu
          bash tests/run_kunlunxin_tests.sh
          if [ "${ALL_COVERAGE}" = "ON" ]; then
              bash /mnt/cache/share/platform/dep/sonar/coverage_DIPU.sh ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Kunlunxin/dipu || echo "get coverage fail"
          fi
      - name: increment coverage check
        if: ${{ contains( github.event_name, 'pull_request' ) && contains( github.base_ref, 'main' ) }}
        run: |
          set -ex
          cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Kunlunxin
          rm -rf scripts
          ln -s ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/source/dipu/third_party/DIOPI/scripts scripts
          bash scripts/increment_coverage.sh ${REQUIRE_COVERAGE}

  Test-One-Iter-Kunlunxin:
    name: Test-One-Iter-Kunlunxin
    needs: [Build-Kunlunxin]
    runs-on: tps-klx-ci
    steps:
      - name: Build some env
        run: |
          set -ex
          cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Kunlunxin/dipu/mmlab_pack
          bash ../scripts/ci/ci_one_iter.sh build_kunlunxin

      - name: Run one iter tools
        run: |
          set -ex
          cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Kunlunxin/dipu
          source scripts/ci/kunlunxin/ci_kunlunxin_env.sh
          basic_path=${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Kunlunxin/dipu/mmlab_pack
          source scripts/ci/ci_one_iter.sh export_pythonpath_kunlunxin ${basic_path}
          cd mmlab_pack
          rm -rf one_iter_data
          XDNN_CONV_GEMM_DTYPE=int16 XPUAPI_DEBUG_CUSTOM_OP_LEVEL="broadcast_add,0x11" \
          python ../scripts/ci/ci_run_one_iter.py kunlunxin "" "" "" && rm -rf one_iter_data || (rm -rf one_iter_data && exit 1)

      - name: Perform cleanup one iter data
        if: always()
        run: |
          set -ex
          cd ${DEEPLINK_PATH}/${GITHUB_RUN_NUMBER}/Build-Kunlunxin/dipu/mmlab_pack
          rm -rf one_iter_data
          touch one_iter_data # 用于占位，防止创建新的 one_iter_data 文件夹

      - name: Check for failure
        if: ${{ failure() }}
        run: exit 1


pypi

name: pypi

on:
  release:
    types: [created]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.x'
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install setuptools wheel twine build
    - name: Check consistency between the package version and release tag
      run: |
        pip install .
        RELEASE_VER=${GITHUB_REF#refs/*/}
        PACKAGE_VER="v`python -c 'import optax; print(optax.__version__)'`"
        if [ $RELEASE_VER != $PACKAGE_VER ]
        then
          echo "package ver. ($PACKAGE_VER) != release ver. ($RELEASE_VER)"; exit 1
        fi
    - name: Build and publish
      env:
        TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
        TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
      run: |
        python -m build
        twine upload dist/*


tests

name: tests

on:
  push:
    branches: ["main"]
  pull_request:
    branches: ["main"]
  schedule:
    - cron: '0 3 * * *'

jobs:
  build-and-test:
    name: "Python ${{ matrix.python-version }} on ${{ matrix.os }} jax=${{ matrix.jax-version }}"
    runs-on: "${{ matrix.os }}"

    strategy:
      matrix:
        python-version: ["3.9", "3.10", "3.11"]
        os: [ubuntu-latest]
        jax-version: [newest]
        include:
          - python-version: "3.9"
            os: "ubuntu-latest"
            jax-version: "0.4.27"  # Keep version in sync with pyproject.toml and copy.bara.sky!

    steps:
      - uses: "actions/checkout@v2"
      - uses: "actions/setup-python@v4"
        with:
            python-version: "${{ matrix.python-version }}"
            cache: "pip"
            cache-dependency-path: 'pyproject.toml'
      - name: Run CI tests
        run: JAX_VERSION="${{ matrix.jax-version }}" bash test.sh
        shell: bash
  markdown-link-check:
    name: "Check links in markdown files"
    runs-on: "ubuntu-latest"
    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Check links
      uses: gaurav-nelson/github-action-markdown-link-check@v1
      with:
        use-quiet-mode: yes
        use-verbose-mode: yes


Post coverage comment

name: Post coverage comment

on:
  workflow_run:
    workflows: ["Run linters and tests"]
    types:
      - completed

jobs:
  test:
    name: Run tests & display coverage
    runs-on: ubuntu-latest
    if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
    permissions:
      pull-requests: write
      actions: read
    steps:
      # DO NOT run actions/checkout here, for security reasons
      # For details, refer to https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
      - name: Post comment
        uses: py-cov-action/python-coverage-comment-action@44f4df022ec3c3cbb61e56e0b550a490bde8aa73
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GITHUB_PR_RUN_ID: ${{ github.event.workflow_run.id }}


Run linters and tests

name: Run linters and tests

on:
  push:
    branches-ignore:
      - "2.x/*"
  pull_request:
    branches-ignore:
      - "2.x/*"
  workflow_dispatch:

permissions:
  contents: read

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  linting:
    name: Linting
    runs-on: ubuntu-latest
    timeout-minutes: 3

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python 3.11
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: Install Just
        uses: extractions/setup-just@dd310ad5a97d8e7b41793f8ef055398d51ad4de6
        with:
          just-version: 1.14.0

      - name: Setup environment to run tox
        run:
          just setup-runner

      - name: Run linters
        run:
          just lint

  testing:
    name: Testing (${{ matrix.python_version.tox }}, ${{ matrix.os }})
    runs-on: ${{ matrix.os }}
    needs: linting

    strategy:
      fail-fast: true
      matrix:
        python_version:
          - { setup: '3.8',      tox: 'py38',    cov: true  }
          - { setup: '3.9',      tox: 'py39',    cov: true  }
          - { setup: '3.10',     tox: 'py310',   cov: true  }
          - { setup: '3.11',     tox: 'py311',   cov: true  }
          - { setup: '3.12',     tox: 'py312',   cov: true  }
          - { setup: 'pypy3.8',  tox: 'pypy38',  cov: false }
          - { setup: 'pypy3.9',  tox: 'pypy39',  cov: false }
          - { setup: 'pypy3.10', tox: 'pypy310', cov: false }

        os: ['ubuntu-latest']

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python 3.11
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python_version.setup }}

      - name: Install Just
        uses: extractions/setup-just@dd310ad5a97d8e7b41793f8ef055398d51ad4de6
        with:
          just-version: 1.14.0

      - name: Setup environment to run tox
        run:
          just setup-runner

      - name: Run tests with coverage
        if: ${{  (matrix.python_version.cov && github.event_name == 'pull_request') }}
        run:
          just inv test-on-ci
            --py-target ${{ matrix.python_version.tox }}
            --cov-output .coverage.${{ matrix.python_version.tox }}

      - name: Store coverage file
        uses: actions/upload-artifact@v4
        if: ${{  (matrix.python_version.cov && github.event_name == 'pull_request') }}
        with:
          name: coverage-${{ matrix.python_version.tox }}
          path: .coverage.${{ matrix.python_version.tox }}
          if-no-files-found: error

      - name: Run tests without coverage
        if: ${{ !(matrix.python_version.cov && github.event_name == 'pull_request') }}
        run:
          just inv test-on-ci
            --py-target ${{ matrix.python_version.tox }}

  coverage:
    name: Coverage
    runs-on: ubuntu-latest
    needs: testing
    permissions:
      pull-requests: write

    if: ${{ github.event_name == 'pull_request' }}

    steps:
      - uses: actions/checkout@v4

      - uses: actions/download-artifact@v4
        id: download
        with:
          pattern: coverage-*
          merge-multiple: true

      - name: Coverage comment
        id: coverage_comment
        uses: py-cov-action/python-coverage-comment-action@44f4df022ec3c3cbb61e56e0b550a490bde8aa73
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          MERGE_COVERAGE_FILES: true
          MINIMUM_GREEN: 90

      - name: Store Pull Request comment to be posted (for external pr)
        uses: actions/upload-artifact@v4
        if: steps.coverage_comment.outputs.COMMENT_FILE_WRITTEN == 'true'
        with:
          name: python-coverage-comment-action
          path: python-coverage-comment-action.txt


Run tests on all operating systems

name: Run tests on all operating systems

on:
  workflow_dispatch:

permissions:
  contents: read

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  testing:
    name: Testing (${{ matrix.python_version.tox }}, ${{ matrix.os }})
    runs-on: ${{ matrix.os }}

    strategy:
      fail-fast: false
      matrix:
        python_version:
          - { setup: '3.8',      tox: 'py38'    }
          - { setup: '3.9',      tox: 'py39'    }
          - { setup: '3.10',     tox: 'py310'   }
          - { setup: '3.11',     tox: 'py311'   }
          - { setup: '3.12',     tox: 'py312'   }
          - { setup: 'pypy3.8',  tox: 'pypy38'  }
          - { setup: 'pypy3.9',  tox: 'pypy39'  }
          - { setup: 'pypy3.10', tox: 'pypy310' }

        os: ['ubuntu-latest', 'windows-latest', 'macos-latest']

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python 3.11
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python_version.setup }}

      - name: Install Just
        uses: extractions/setup-just@dd310ad5a97d8e7b41793f8ef055398d51ad4de6
        with:
          just-version: 1.14.0

      - name: Setup environment to run tox
        run:
          just setup-runner

      - name: Run tests
        run:
          just inv test-on-ci
            --py-target ${{ matrix.python_version.tox }}
            --cov-output .coverage.${{ matrix.python_version.tox }}


Mirror to Ebrains

name: Mirror to Ebrains

# Configure the events that are going to trigger tha automated update of the mirror
on:
  push:
    branches: [ master ]

# Configure what will be updated
jobs:
  # set the job name
  to_ebrains:
    runs-on: ubuntu-latest
    steps:
      # this task will push the master branch of the source_repo (github) to the
      # destination_repo (ebrains gitlab)
      - name: syncmaster
        uses: wei/git-sync@v3
        # component owners need to set their own variables
        # the destination_repo format is
        # https://gitlab_service_account_name:${{ secrets.EBRAINS_GITLAB_ACCESS_TOKEN }}@gitlab.ebrains.eu/name_of_mirror.git
        with:
          source_repo: "suny-downstate-medical-center/netpyne"
          source_branch: "master"
          destination_repo: "https://github-pusher:${{ secrets.EBRAINS_GITLAB_ACCESS_TOKEN }}@gitlab.ebrains.eu/vbragin/netpyne.git"
          destination_branch: "master"
      # this task will push all tags from the source_repo to the destination_repo
      - name: synctags
        uses: wei/git-sync@v3
        with:
          source_repo: "suny-downstate-medical-center/netpyne"
          source_branch: "refs/tags/*"
          destination_repo: "https://github-pusher:${{ secrets.EBRAINS_GITLAB_ACCESS_TOKEN }}@gitlab.ebrains.eu/vbragin/netpyne.git"
          destination_branch: "refs/tags/*"


Tests

name: Tests
on: [push, pull_request]
jobs:
  Run-Tests:
    runs-on: ${{ matrix.os }}

    strategy:
      matrix:
        os: [ubuntu-latest]
        #python-version: [2.7, 3.7]
        python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
      fail-fast: false

    steps:
      - name: Check out repository code
        uses: actions/checkout@v4

      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}

      - name: Update apt-get
        run: sudo apt-get update

      - name: Install packages
        run: sudo apt-get install python-tk python3-tables

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
          pip install -e .

      - name: Info on installed package versons
        run: |
          pip list

      - name: Test with pytest
        run: |
          source tests/test.sh


Run unittest, black and autoflake

# This workflow will install Python dependencies, run tests and black

name: Run unittest, black and autoflake

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

permissions:
  contents: read

jobs:
  check:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - name: Set up Python 3.10
      uses: actions/setup-python@v3
      with:
        python-version: "3.10"

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
        python -m pip install -U multiprocess
        python -m pip freeze

    - name: Black code style check
      if: success() || failure()
      uses: psf/black@stable
      with:
        options: "--check --diff"
        src: "."
        jupyter: true
        version: "23.1.0"

    - name: Unused imports and variables check
      if: success() || failure()
      run: |
        python -m autoflake --remove-all-unused-imports -r . --exclude venv,archived_code -c --quiet

    - name: Run unittest
      if: success() || failure()
      run: |
        python -m unittest discover
      env:
        NEPTUNE_API_TOKEN: ${{ secrets.NEPTUNE_API_TOKEN }}
        WANDB_API_KEY: ${{ secrets.WANDB_API_KEY }}


Build and Test Workflow

name: Build and Test Workflow

on:
  workflow_dispatch:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  tests-and-coverage:
    name: Tests with latest BoTorch
    uses: ./.github/workflows/reusable_test.yml
    with:
      pinned_botorch: false
    secrets: inherit

  lint:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: "3.10"
    - name: Install dependencies
      # Pin ufmt deps so they match intermal pyfmt.
      run: |
        pip install black==24.2.0
        pip install usort==1.0.8
        pip install libcst==1.1.0
        pip install ufmt
        pip install flake8
    - name: ufmt
      run: |
        ufmt diff .
    - name: Flake8
      # run even if previous step (ufmt) failed
      if: ${{ always() }}
      run: |
        flake8

  docs:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: "3.10"
    - name: Install dependencies
      env:
        ALLOW_BOTORCH_LATEST: true
        ALLOW_LATEST_GPYTORCH_LINOP: true
      run: |
        # use latest Botorch
        pip install git+https://github.com/cornellius-gp/gpytorch.git
        pip install git+https://github.com/pytorch/botorch.git
        pip install -e ".[unittest]"
    - name: Validate Sphinx
      run: |
        python scripts/validate_sphinx.py -p "${pwd}"
    - name: Run Sphinx
      # run even if previous step (validate Sphinx) failed
      if: ${{ always() }}
      run: |
        # warnings no longer treated as errors.
        sphinx-build -T --keep-going sphinx/source sphinx/build


Nightly Cron

name: Nightly Cron

on:
  schedule:
    # midnight EST
    - cron:  '0 5 * * *'
  # allow this to be scheduled manually in addition to cron
  workflow_dispatch:
  push:
    branches: [ main ]
    paths:
      - "tutorials/**"

jobs:

  tests-and-coverage-minimal:
    name: Tests with latest BoTorch & minimal dependencies
    uses: ./.github/workflows/reusable_test.yml
    with:
      pinned_botorch: false
      minimal_dependencies: true
    secrets: inherit

  tests-and-coverage-full:
    name: Tests with latest BoTorch & full dependencies
    uses: ./.github/workflows/reusable_test.yml
    with:
      pinned_botorch: false
      minimal_dependencies: false
    secrets: inherit

  build-tutorials:
    name: Build tutorials with latest BoTorch
    uses: ./.github/workflows/reusable_tutorials.yml
    with:
      smoke_test: false
      pinned_botorch: false

  publish-latest-website:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: "3.10"
    - name: Install dependencies
      env:
        ALLOW_BOTORCH_LATEST: true
        ALLOW_LATEST_GPYTORCH_LINOP: true
      run: |
        # use latest BoTorch
        pip install git+https://github.com/cornellius-gp/gpytorch.git
        pip install git+https://github.com/pytorch/botorch.git
        pip install -e ".[tutorial]"
    - name: Publish latest website
      env:
        DOCUSAURUS_PUBLISH_TOKEN: ${{ secrets.DOCUSAURUS_PUBLISH_TOKEN }}
      run: |
        bash scripts/publish_site.sh -d

  deploy-test-pypi:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4
    - name: Fetch all history for all tags and branches
      run: git fetch --prune --unshallow
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: "3.10"
    - name: Install dependencies
      env:
        ALLOW_BOTORCH_LATEST: true
        ALLOW_LATEST_GPYTORCH_LINOP: true
      run: |
        # use latest BoTorch
        pip install git+https://github.com/cornellius-gp/gpytorch.git
        pip install git+https://github.com/pytorch/botorch.git
        pip install -e ".[dev,mysql,notebook]"
        pip install wheel
    - name: Build wheel
      run: |
        python setup.py sdist bdist_wheel
    - name: Deploy to Test PyPI
      uses: pypa/gh-action-pypi-publish@release/v1
      with:
        user: __token__
        password: ${{ secrets.TEST_PYPI_TOKEN }}
        repository_url: https://test.pypi.org/legacy/
        skip_existing: true
        verbose: true


name: Replicate Nightly Cron with Pinned BoTorch

on:

  workflow_dispatch:

jobs:

  tests-and-coverage-minimal:
    name: Tests with pinned BoTorch & minimal dependencies
    uses: ./.github/workflows/reusable_test.yml
    with:
      pinned_botorch: true
      minimal_dependencies: true
    secrets: inherit

  tests-and-coverage-full:
    name: Tests with pinned BoTorch & full dependencies
    uses: ./.github/workflows/reusable_test.yml
    with:
      pinned_botorch: true
      minimal_dependencies: false
    secrets: inherit

  build-tutorials:
    name: Build tutorials with pinned BoTorch
    uses: ./.github/workflows/reusable_tutorials.yml
    with:
      smoke_test: false
      pinned_botorch: true


Deploy

# This workflows will upload a Python Package using Twine when a release is created
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries

name: Deploy

on:
  release:
    types: [created]

jobs:
  tests-and-coverage-latest:
    name: Tests with latest BoTorch
    uses: ./.github/workflows/reusable_test.yml
    with:
      pinned_botorch: false
    secrets: inherit

  tests-and-coverage-pinned:
    name: Tests with pinned BoTorch
    uses: ./.github/workflows/reusable_test.yml
    with:
      pinned_botorch: true
    secrets: inherit

  publish-stable-website:

    needs: tests-and-coverage-pinned # only run if test step succeeds
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: "3.10"
    - name: Install dependencies
      run: |
        # use stable Botorch
        pip install -e ".[tutorial]"
    - name: Publish latest website
      env:
        DOCUSAURUS_PUBLISH_TOKEN: ${{ secrets.DOCUSAURUS_PUBLISH_TOKEN }}
      run: |
        bash scripts/publish_site.sh -d -v ${{ github.event.release.tag_name }}

  deploy:

    needs: tests-and-coverage-pinned # only run if test step succeeds
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: "3.10"
    - name: Install dependencies
      run: |
        # use stable Botorch
        pip install -e ".[dev,mysql,notebook]"
        pip install wheel
    - name: Fetch all history for all tags and branches
      run: git fetch --prune --unshallow
    - name: Build wheel
      run: |
        python setup.py sdist bdist_wheel
    - name: Deploy to PyPI
      uses: pypa/gh-action-pypi-publish@release/v1
      with:
        user: __token__
        password: ${{ secrets.PYPI_TOKEN }}
        verbose: true


Reusable Test Workflow

name: Reusable Test Workflow

on:
  workflow_dispatch:
    inputs:
      pinned_botorch:
        required: true
        type: boolean
      minimal_dependencies:
        required: false
        type: boolean
        default: false
  workflow_call:
    inputs:
      pinned_botorch:
        required: true
        type: boolean
      minimal_dependencies:
        required: false
        type: boolean
        default: false

jobs:
  tests-and-coverage:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.10", "3.12"]
      fail-fast: false

    steps:
    - uses: actions/checkout@v4
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v5
      with:
        python-version: ${{ matrix.python-version }}

    - if: ${{ inputs.pinned_botorch }}
      name: Install dependencies with pinned BoTorch (minimal dependencies ${{ inputs.minimal_dependencies }})
      run: |
        # The brackets returns '.[unittest_minimal]' if using minimal dependencies and '.[unittest]'
        # otherwise. This saves us from needing 4 install dependencies blocks by supporting two
        # different installation options in one line.
        pip install -e ${{ ((inputs.minimal_dependencies) && '.[unittest_minimal]') || '.[unittest]' }}

    - if: ${{ !inputs.pinned_botorch }}
      name: Install dependencies with latest BoTorch (minimal dependencies ${{ inputs.minimal_dependencies }})
      env:
        ALLOW_BOTORCH_LATEST: true
        ALLOW_LATEST_GPYTORCH_LINOP: true
      run: |
        pip install git+https://github.com/cornellius-gp/gpytorch.git
        pip install git+https://github.com/pytorch/botorch.git
        pip install -e ${{ ((inputs.minimal_dependencies) && '.[unittest_minimal]') || '.[unittest]' }}

    - name: Import Ax
      run: |
        python scripts/import_ax.py
    - if: ${{ !inputs.minimal_dependencies }}
      # Only run with full dependencies. Minimal does not include pytest.
      name: Tests and coverage
      run: |
        pytest -ra --cov=ax
    - if: ${{ !inputs.minimal_dependencies && matrix.python-version == 3.10 }}
      # Only upload codecov once per workflow.
      name: Upload coverage
      uses: codecov/codecov-action@v4
      with:
        fail_ci_if_error: true
        token: ${{ secrets.CODECOV_TOKEN }}
        version: v0.6.0  # TODO: Unpin after codecov issue with 0.7.0 is resolved: https://github.com/codecov/codecov-cli/issues/460#issuecomment-2183042570


Reusable Tutorials Workflow

name: Reusable Tutorials Workflow

on:
  workflow_dispatch:
    inputs:
      smoke_test:
        required: true
        type: boolean
      pinned_botorch:
        required: true
        type: boolean
  workflow_call:
    inputs:
      smoke_test:
        required: true
        type: boolean
      pinned_botorch:
        required: true
        type: boolean

jobs:

  build-tutorials:
    name: Tutorials
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: "3.10"

    - if: ${{ inputs.pinned_botorch }}
      name: Install dependencies with pinned BoTorch
      run: |
        pip install -e ".[tutorial]"

    - if: ${{ !inputs.pinned_botorch }}
      name: Install dependencies with latest BoTorch
      env:
        ALLOW_BOTORCH_LATEST: true
        ALLOW_LATEST_GPYTORCH_LINOP: true
      run: |
        pip install git+https://github.com/cornellius-gp/gpytorch.git
        pip install git+https://github.com/pytorch/botorch.git
        pip install -e ".[tutorial]"

    - if: ${{ inputs.smoke_test }}
      name: Build tutorials with smoke test
      run: |
        python scripts/make_tutorials.py -w $(pwd) -e -s
    - if: ${{ !inputs.smoke_test }}
      name: Build tutorials without smoke test
      run: |
        python scripts/make_tutorials.py -w $(pwd) -e


Tutorials

name: Tutorials

on:
  workflow_dispatch:
  push:
    branches: [ main ]
    paths:
      - "tutorials/**"
  pull_request:
    branches: [ main ]
    paths:
      - "tutorials/**"

jobs:

  build-tutorials-with-latest-botorch:
    name: Tutorials with latest BoTorch
    uses: ./.github/workflows/reusable_tutorials.yml
    with:
      smoke_test: true
      pinned_botorch: false


⛔ Security auditing (Matrix)

---
# This workflow will install Python dependencies
# run tests and lint with a variety of Python versions
# For more information see:
# https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: "⛔ Security auditing (Matrix)"

# yamllint disable-line rule:truthy
on:
  workflow_dispatch:
  pull_request:
    types: [opened, reopened, edited, synchronize]
    branches:
      - "*"
      - "!update-devops-tooling"

jobs:

  parse-project-metadata:
    name: "Determine Python versions"
    # yamllint disable-line rule:line-length
    uses: os-climate/devops-reusable-workflows/.github/workflows/pyproject-toml-fetch-matrix.yaml@main

  build:
    name: "Audit Python dependencies"
    needs: [parse-project-metadata]
    runs-on: ubuntu-latest
    # Don't run when pull request is merged
    if: github.event.pull_request.merged == false
    strategy:
      fail-fast: false
      matrix: ${{ fromJson(needs.parse-project-metadata.outputs.matrix) }}

    steps:
      - name: "Checkout repository"
        uses: actions/checkout@v4

      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}

      - name: "Setup PDM for build commands"
        uses: pdm-project/setup-pdm@v4
        with:
          python-version: ${{ matrix.python-version }}

      - name: "Install dependencies"
        run: |
          pip install --upgrade pip
          pdm lock
          pdm export -o requirements.txt
          python -m pip install -r requirements.txt
          python -m pip install .
          pip install --upgrade setuptools
          pdm list --graph

      - name: "Run: pip-audit"
        uses: pypa/gh-action-pip-audit@v1.0.8


🧪 Unit tests (Matrix)

---
name: "🧪 Unit tests (Matrix)"

# yamllint disable-line rule:truthy
on:
  workflow_dispatch:
  pull_request:
    types: [opened, reopened, edited, synchronize]
    branches:
      - "*"
      - "!update-devops-tooling"

jobs:

  parse-project-metadata:
    name: "Determine Python versions"
    # yamllint disable-line rule:line-length
    uses: os-climate/devops-reusable-workflows/.github/workflows/pyproject-toml-fetch-matrix.yaml@main

  testing:
    name: "Run unit tests"
    needs: [parse-project-metadata]
    runs-on: ubuntu-latest
    # Don't run when pull request is merged
    if: github.event.pull_request.merged == false
    strategy:
      fail-fast: false
      matrix: ${{ fromJson(needs.parse-project-metadata.outputs.matrix) }}

    steps:
      - name: "Checkout repository"
        uses: actions/checkout@v4

      - name: "Setup Python ${{ matrix.python-version }}"
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}

      - name: "Setup PDM for build commands"
        uses: pdm-project/setup-pdm@v4
        with:
          python-version: ${{ matrix.python-version }}

      - name: "Install dependencies"
        run: |
          python -m pip install --upgrade pip
          pdm export -o requirements.txt
          pip install -r requirements.txt
          pip install --upgrade pytest pytest-cov
          pip install .

      - name: "Run unit tests: pytest"
        run: |
          if [ -d test ]; then
            python -m pytest test
          elif [ -d tests ]; then
            python -m pytest tests
          else
            echo "No test/tests directory could be found"
            echo "Aborting testing without error"; exit 0
          fi


📘 Documentation build/publish

---
name: "📘 Documentation build/publish"

# yamllint disable-line rule:truthy
on:
  workflow_dispatch:
  pull_request:
    types: [closed]
    branches:
      - "*"
      - "!update-devops-tooling"

jobs:
  build_and_deploy:
    # Only run when pull request is merged
    if: github.event.pull_request.merged == true
    name: "Rebuild documentation"
    runs-on: ubuntu-latest
    continue-on-error: true

    permissions:
      # IMPORTANT: mandatory for documentation updates; used in final step
      id-token: write
      pull-requests: write
      contents: write
      repository-projects: write

    steps:
      - name: "Checkout repository"
        uses: actions/checkout@v4

      - name: "Set up Python"
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: "Setup PDM for build commands"
        uses: pdm-project/setup-pdm@v4

      - name: "Install dependencies"
        run: |
          python -m pip install --upgrade pip
          pdm lock
          pdm export -o requirements.txt
          if [ -f docs/requirements.txt ]; then
          pip install -r docs/requirements.txt; fi

      - name: "Build documentation: (tox/sphinx)"
        run: |
          pip install --upgrade tox
          tox -e docs

      - name: "Publish documentation"
        if: success()
        uses: peaceiris/actions-gh-pages@v4
        with:
          publish_branch: gh-pages
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: docs/_build/html/
          keep_files: true


🧱 Builds (Matrix)

---
name: "🧱 Builds (Matrix)"

# yamllint disable-line rule:truthy
on:
  workflow_dispatch:
  pull_request:
    types: [opened, reopened, edited, synchronize]
    branches:
      - "*"
      - "!update-devops-tooling"

jobs:
  parse-project-metadata:
    name: "Determine Python versions"
    # yamllint disable-line rule:line-length
    uses: os-climate/devops-reusable-workflows/.github/workflows/pyproject-toml-fetch-matrix.yaml@main

  test-builds:
    name: "Build: Python"
    needs: [parse-project-metadata]
    runs-on: "ubuntu-latest"
    continue-on-error: true
    # Don't run when pull request is merged
    if: github.event.pull_request.merged == false
    strategy:
      fail-fast: false
      matrix: ${{ fromJson(needs.parse-project-metadata.outputs.matrix) }}

    steps:
      - name: "Populate environment variables"
        id: setenv
        run: |
          echo "Action triggered by user: ${GITHUB_TRIGGERING_ACTOR}"
          set -x
          datetime=$(date +'%Y%m%d%H%M')
          export datetime
          echo "datetime=${datetime}" >> "$GITHUB_OUTPUT"
          vernum="${{ matrix.python-version }}.${datetime}"
          echo "vernum=${vernum}" >> "$GITHUB_OUTPUT"

      - name: "Checkout repository"
        uses: actions/checkout@v4

      - name: "Set up Python ${{ matrix.python-version }}"
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}

      - name: "Setup PDM for build commands"
        uses: pdm-project/setup-pdm@v4
        with:
          python-version: ${{ matrix.python-version }}

      - name: "Tag for test release"
        # Delete all local tags, then create a synthetic tag for testing
        # Use the date/time to avoid conflicts uploading to Test PyPI
        run: |
          scripts/dev-versioning.sh "${{ steps.setenv.outputs.vernum }}"
          git tag | xargs -L 1 | xargs git tag --delete
          git tag "v${{ steps.setenv.outputs.vernum }}"
          git checkout "tags/v${{ steps.setenv.outputs.vernum }}"
          grep version pyproject.toml

      - name: "Performing build"
        run: |
          python -m pip install --upgrade pip
          if [ -f tox.ini ]; then
            pip install tox tox-gh-actions
            echo "Found file: tox.ini"
            echo "Building with command: tox -e build"
            tox -e build
          elif [ -f pyproject.toml ]; then
            echo "Found file: pyproject.toml"
            echo "Building with command: pdm build"
            pdm build
          else
            echo "Neither file found: tox.ini/pyproject.toml"
            pip install --upgrade build
            echo "Attempting build with: python -m build"
            python -m build
          fi

      - name: "Validating Artefacts with Twine"
        run: |
          echo "Validating artefacts with: twine check dist/*"
          pip install --upgrade twine
          twine check dist/*


🐍📦 Production build and release

---
name: "🐍📦 Production build and release"

# GitHub/PyPI trusted publisher documentation:
# https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/

# yamllint disable-line rule:truthy
on:
  # workflow_dispatch:
  push:
    # Only invoked on release tag pushes
    branches:
      - 'main'
      - 'master'
    tags:
      - 'v*.*.*'

env:
  python-version: "3.10"

### BUILD ###

jobs:

  build:
    name: "🐍 Build packages"
    # Only publish on tag pushes
    if: startsWith(github.ref, 'refs/tags/')
    runs-on: ubuntu-latest
    permissions:
      # IMPORTANT: mandatory for Sigstore
      id-token: write
    steps:
      ### BUILDING ###

      - name: "Checkout repository"
        uses: actions/checkout@v4

      - name: "Setup Python"
        uses: actions/setup-python@v5
        with:
          python-version: ${{ env.python-version }}

      - name: "Setup PDM for build commands"
        uses: pdm-project/setup-pdm@v4

      - name: "Update version from tags for production release"
        run: |
          echo "Github versioning: ${{ github.ref_name }}"
          scripts/release-versioning.sh

      - name: "Build with PDM backend"
        run: |
          pdm build

      ### SIGNING ###

      - name: "Sign packages with Sigstore"
        uses: sigstore/gh-action-sigstore-python@v2.1.1
        with:
          inputs: >-
            ./dist/*.tar.gz
            ./dist/*.whl

      - name: Store the distribution packages
        uses: actions/upload-artifact@v4
        with:
          name: ${{ github.ref_name }}
          path: dist/

  ### PUBLISH GITHUB ###

  github:
    name: "📦 Publish to GitHub"
    # Only publish on tag pushes
    if: startsWith(github.ref, 'refs/tags/')
    needs:
      - build
    runs-on: ubuntu-latest
    permissions:
      # IMPORTANT: mandatory to publish artefacts
      contents: write
    steps:
      - name: "⬇ Download build artefacts"
        uses: actions/download-artifact@v4
        with:
          name: ${{ github.ref_name }}
          path: dist/

      - name: "📦 Publish artefacts to GitHub"
        # https://github.com/softprops/action-gh-release
        uses: softprops/action-gh-release@v2
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          prerelease: false
          tag_name: ${{ github.ref_name }}
          name: "Test/Development Build \
            ${{ github.ref_name }}"
          # body_path: ${{ github.workspace }}/CHANGELOG.rst
          files: |
            dist/*.tar.gz
            dist/*.whl
            dist/*.sigstore

  ### PUBLISH PYPI TEST ###

  testpypi:
    name: "📦 Publish to PyPi Test"
    # Only publish on tag pushes
    if: startsWith(github.ref, 'refs/tags/')
    needs:
      - build
    runs-on: ubuntu-latest
    environment:
      name: testpypi
    permissions:
      # IMPORTANT: mandatory for trusted publishing
      id-token: write
    steps:
      - name: "⬇ Download build artefacts"
        uses: actions/download-artifact@v4
        with:
          name: ${{ github.ref_name }}
          path: dist/

      - name: "Remove files unsupported by PyPi"
        run: |
          if [ -f dist/buildvars.txt ]; then
            rm dist/buildvars.txt
          fi
          rm dist/*.sigstore

      - name: Publish distribution to Test PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          repository-url: https://test.pypi.org/legacy/
          verbose: true

  ### PUBLISH PYPI ###

  pypi:
    name: "📦 Publish to PyPi"
    # Only publish on tag pushes
    if: startsWith(github.ref, 'refs/tags/')
    needs:
      - testpypi
    runs-on: ubuntu-latest
    environment:
      name: pypi
    permissions:
      # IMPORTANT: mandatory for trusted publishing
      id-token: write
    steps:
      - name: "⬇ Download build artefacts"
        uses: actions/download-artifact@v4
        with:
          name: ${{ github.ref_name }}
          path: dist/

      - name: "Remove files unsupported by PyPi"
        run: |
          if [ -f dist/buildvars.txt ]; then
            rm dist/buildvars.txt
          fi
          rm dist/*.sigstore

      - name: "Setup PDM for build commands"
        uses: pdm-project/setup-pdm@v4

      - name: "Publish release to PyPI"
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          verbose: true


🐍📦 Test build and release

---
name: "🐍📦 Test build and release"

# GitHub/PyPI trusted publisher documentation:
# https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/

# yamllint disable-line rule:truthy
on:
  workflow_dispatch:

env:
  python-version: "3.10"

### BUILD ###

jobs:
  build:
    name: "🐍 Build packages"
    runs-on: ubuntu-latest
    permissions:
      # IMPORTANT: mandatory for Sigstore
      id-token: write
    steps:
      ### BUILDING ###

      - name: "Checkout repository"
        uses: actions/checkout@v4

      - name: "Setup Python 3.10"
        uses: actions/setup-python@v5
        with:
          python-version: ${{ env.python-version }}

      - name: "Setup PDM for build commands"
        uses: pdm-project/setup-pdm@v4
        with:
          python-version: ${{ env.python-version }}

      - name: "Populate environment variables"
        id: setenv
        run: |
          vernum="${{ env.python-version }}.$(date +'%Y%m%d%H%M')"
          echo "vernum=${vernum}" >> "$GITHUB_OUTPUT"
          echo "vernum=${vernum}" >> buildvars.txt

      - name: "Tag for test release"
        # Delete all local tags, then create a synthetic tag for testing
        # Use the date/time to avoid conflicts uploading to Test PyPI
        run: |
          scripts/dev-versioning.sh "${{ steps.setenv.outputs.vernum }}"
          git tag | xargs -L 1 | xargs git tag --delete
          git tag "v${{ steps.setenv.outputs.vernum }}"
          git checkout "tags/v${{ steps.setenv.outputs.vernum }}"
          grep version pyproject.toml

      - name: "Build with PDM backend"
        run: |
          pdm build
          # Need to save the build environment for subsequent steps
          mv buildvars.txt dist/buildvars.txt

      ### SIGNING ###

      - name: "Sign packages with Sigstore"
        uses: sigstore/gh-action-sigstore-python@v2.1.1

        with:
          inputs: >-
            ./dist/*.tar.gz
            ./dist/*.whl

      - name: Store the distribution packages
        uses: actions/upload-artifact@v4
        with:
          name: Development
          path: dist/

  ### PUBLISH GITHUB ###

  github:
    name: "📦 Test publish to GitHub"
    needs:
      - build
    runs-on: ubuntu-latest
    permissions:
      # IMPORTANT: mandatory to publish artefacts
      contents: write
    steps:
      - name: "⬇ Download build artefacts"
        uses: actions/download-artifact@v4
        with:
          name: Development
          path: dist/

      - name: "Source environment variables"
        id: setenv
        run: |
          if [ -f dist/buildvars.txt ]; then
            source dist/buildvars.txt
            echo "vernum=${vernum}" >> "$GITHUB_OUTPUT"
          else
            echo "Build environment variables could not be sourced"
          fi
          echo "tarball=$(ls dist/*.tgz)" >> "$GITHUB_OUTPUT"
          echo "wheel=$(ls dist/*.whl)" >> "$GITHUB_OUTPUT"

      - name: "📦 Publish artefacts to GitHub"
        # https://github.com/softprops/action-gh-release
        uses: softprops/action-gh-release@v2
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          prerelease: true
          tag_name: ${{ steps.setenv.outputs.vernum }}
          name: "Test/Development Build \
            ${{ steps.setenv.outputs.vernum }}"
          # body_path: ${{ github.workspace }}/CHANGELOG.rst
          files: |
            dist/*.tar.gz
            dist/*.whl
            dist/*.sigstore

  ### PUBLISH TEST PYPI ###

  testpypi:
    name: "📦 Test publish to PyPi"
    needs:
      - build
    runs-on: ubuntu-latest
    environment:
      name: testpypi
    permissions:
      # IMPORTANT: mandatory for trusted publishing
      id-token: write
    steps:
      - name: "⬇ Download build artefacts"
        uses: actions/download-artifact@v4
        with:
          name: Development
          path: dist/

      - name: "Remove files unsupported by PyPi"
        run: |
          if [ -f dist/buildvars.txt ]; then
            rm dist/buildvars.txt
          fi
          rm dist/*.sigstore

      - name: Publish distribution to Test PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          verbose: true
          repository-url: https://test.pypi.org/legacy/


♻ Update dependencies

---
name: "♻ Update dependencies"

# yamllint disable-line rule:truthy
on:
  workflow_dispatch:
  schedule:
    - cron: "0 8 1 * *"

jobs:
  update-dependencies:
    name: "Update dependencies"
    runs-on: ubuntu-latest
    permissions:
      # IMPORTANT: mandatory to raise the PR
      id-token: write
      pull-requests: write
      repository-projects: write
      contents: write

    env:
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

    steps:
      - name: "Checkout repository"
        uses: actions/checkout@v4

      - name: "Set up Python"
        uses: actions/setup-python@v5

      - name: "Update Python dependencies"
        uses: pdm-project/update-deps-action@v1
        with:
          sign-off-commit: "true"
          token: ${{ secrets.GH_TOKEN }}
          commit-message: "Chore: Update dependencies and pdm.lock [skip ci]"
          pr-title: "Update Python module dependencies"
          update-strategy: eager
          # Whether to install PDM plugins before update
          install-plugins: "false"

      - name: "Export dependencies"
        run: |
          pdm export --without-hashes -o requirements.txt

      # Ideally, we should export requirements.txt then amend the earlier PR
      # update-deps-action could be modified to export PR number as as output
      # Or we add the option to export the requirements.txt in that action