CI PyTorchGoturn

name: CI PyTorchGoturn
on:
  # Run on manual trigger
  workflow_dispatch:

  # Run on pull requests
  pull_request:
    paths-ignore:
      - '*.md'

  # Run on merge queue
  merge_group:

  # Run when pushing to main or dev branches
  push:
    branches:
      - main
      - dev*

  # Run scheduled CI flow daily
  schedule:
    - cron: '0 8 * * 0'

jobs:
  test_pytorch_goturn:
    name: PyTorchGoturn
    runs-on: ubuntu-latest
    container: adversarialrobustnesstoolbox/art_testing_envs:goturn
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
      - name: Run Test Action
        uses: ./.github/actions/goturn
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4
        with:
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}


CI Huggingface

name: CI Huggingface
on:
  # Run on manual trigger
  workflow_dispatch:

  # Run on pull requests
  pull_request:
    paths-ignore:
      - '*.md'

  # Run on merge queue
  merge_group:

  # Run when pushing to main or dev branches
  push:
    branches:
      - main
      - dev*

  # Run scheduled CI flow daily
  schedule:
    - cron: '0 8 * * 0'

jobs:
  test:
    runs-on: ubuntu-20.04
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: Huggingface 4.30
            framework: huggingface
            python: '3.10'
            torch: 2.2.1
            torchvision: 0.17.1+cpu
            torchaudio: 2.2.1
            transformers: 4.30.2

    name: ${{ matrix.name }}
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python }}
      - name: Install Dependencies
        run: |
          sudo apt-get update
          sudo apt-get -y -q install ffmpeg libavcodec-extra
          python -m pip install --upgrade pip setuptools wheel
          pip3 install -r requirements_test.txt
          pip install tensorflow==2.14.0
          pip install keras==2.14.0
          pip install torch==${{ matrix.torch }} -f https://download.pytorch.org/whl/cpu/torch_stable.html
          pip install torchvision==${{ matrix.torchvision }} -f https://download.pytorch.org/whl/cpu/torch_stable.html
          pip install torchaudio==${{ matrix.torchaudio }} -f https://download.pytorch.org/whl/cpu/torch_stable.html
          pip install transformers==${{ matrix.transformers }}
          pip list
      - name: Run Tests
        run: ./run_tests.sh ${{ matrix.framework }}
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4
        with:
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}


CI Keras

name: CI Keras
on:
  # Run on manual trigger
  workflow_dispatch:

  # Run on pull requests
  pull_request:
    paths-ignore:
      - '*.md'

  # Run on merge queue
  merge_group:

  # Run when pushing to main or dev branches
  push:
    branches:
      - main
      - dev*

  # Run scheduled CI flow daily
  schedule:
    - cron: '0 8 * * 0'

jobs:
  test:
    runs-on: ubuntu-20.04
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: Keras 2.13.1 (TensorFlow 2.13.1 Python 3.10)
            framework: keras
            python: '3.10'
            tensorflow: 2.13.1
            keras: 2.13.1
            tf_addons: 0.19.0
          - name: Keras 2.14.0 (TensorFlow 2.14.0 Python 3.10)
            framework: keras
            python: '3.10'
            tensorflow: 2.14.0
            keras: 2.14.0
            tf_addons: 0.20.0
          - name: TensorFlow-Keras 2.14.0 (Keras 2.14.0 Python 3.10)
            framework: kerastf
            python: '3.10'
            tensorflow: 2.14.0
            keras: 2.14.0
            tf_addons: 0.20.0

    name: ${{ matrix.name }}
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python }}
      - name: Install Dependencies
        run: |
          sudo apt-get update
          sudo apt-get -y -q install ffmpeg libavcodec-extra
          python -m pip install --upgrade pip setuptools wheel
          pip install -q -r <(sed '/^tensorflow/d;/^keras/d;/^tensorflow-addons/d' requirements_test.txt)
          pip install tensorflow==${{ matrix.tensorflow }}
          pip install keras==${{ matrix.keras }}
          pip install tensorflow-addons==${{ matrix.tf_addons }}
          pip list
      - name: Run Tests
        run: ./run_tests.sh ${{ matrix.framework }}
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4
        with:
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}


CI Legacy

name: CI Legacy
on:
  # Run on manual trigger
  workflow_dispatch:

  # Run on pull requests
  pull_request:
    paths-ignore:
      - '*.md'

  # Run on merge queue
  merge_group:

  # Run when pushing to main or dev branches
  push:
    branches:
      - main
      - dev*

  # Run scheduled CI flow daily
  schedule:
    - cron: '0 8 * * 0'

jobs:
  test:
    runs-on: ubuntu-20.04
    strategy:
      fail-fast: false
      matrix:
        module: [attacks_1, attacks_2, estimators, defences, metrics, art]
        include:
          - name: legacy (TensorFlow 2.14.0 Keras 2.14.0 PyTorch 1.13.1 scikit-learn 1.1.3 Python 3.9)
            framework: legacy
            python: '3.10'
            tensorflow: 2.14.0
            keras: 2.14.0
            torch: 1.13.1+cpu
            torchvision: 0.14.1+cpu
            torchaudio: 0.13.1+cpu
            scikit-learn: 1.1.3

    name: Run ${{ matrix.module }} ${{ matrix.name }} Tests
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python }}
      - name: Install Dependencies
        run: |
          sudo apt-get update
          sudo apt-get -y -q install ffmpeg libavcodec-extra
          python -m pip install --upgrade pip setuptools wheel
          pip install -q -r requirements_test.txt
          pip install tensorflow==${{ matrix.tensorflow }}
          pip install keras==${{ matrix.keras }}
          pip install scikit-learn==${{ matrix.scikit-learn }}
          pip install torch==${{ matrix.torch }} -f https://download.pytorch.org/whl/cpu/torch_stable.html
          pip install torchvision==${{ matrix.torchvision }} -f https://download.pytorch.org/whl/cpu/torch_stable.html
          pip install torchaudio==${{ matrix.torchaudio }} -f https://download.pytorch.org/whl/cpu/torch_stable.html
          pip list
      - name: Run ${{ matrix.name }} ${{ matrix.module }} Tests
        run: ./run_tests.sh ${{ matrix.framework }} ${{ matrix.module }}
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4
        with:
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}


CI Lingvo

name: CI Lingvo
on:
  # Run on manual trigger
  workflow_dispatch:

  # Run on pull requests
  pull_request:
    paths-ignore:
      - '*.md'

  # Run on merge queue
  merge_group:

  # Run when pushing to main or dev branches
  push:
    branches:
      - main
      - dev*

  # Run scheduled CI flow daily
  schedule:
    - cron: '0 8 * * 0'

jobs:
  test:
    runs-on: ubuntu-20.04
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: TensorFlow+Lingvo 2.1.0v1 (Keras 2.3.1 Python 3.6)
            framework: tensorflow2v1
            python: 3.6
            tensorflow: 2.1.0
            tf_version: v2
            keras: 2.3.1
            lingvo: 0.6.4

    name: Run ${{ matrix.name }} Tests
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python }}
      - name: Pre-install Lingvo ASR
        # scipy beyond 1.6.0 is not available on Python 3.6, therefore we adapt the installation of requirements_test.txt
        run: |
          sudo apt-get update
          sudo apt-get -y -q install ffmpeg libavcodec-extra
          python -m pip install --upgrade pip setuptools wheel
          pip install -q -r <(sed '/^scipy/d;/^matplotlib/d;/^pandas/d;/^statsmodels/d;/^numba/d;/^jax/d;/^h5py/d;/^Pillow/d;/^pytest/d;/^pytest-mock/d;/^torch/d;/^torchaudio/d;/^torchvision/d;/^xgboost/d;/^requests/d;/^tensorflow/d;/^keras/d;/^kornia/d;/^librosa/d;/^tqdm/d;/^timm/d;/^catboost/d;/^scikit-learn/d;/^GPy/d;/^lief/d;/^ultralytics/d;/^ipython/d' requirements_test.txt)
          pip install scipy==1.5.4
          pip install matplotlib==3.3.4
          pip install pandas==1.1.5
          pip install statsmodels==0.12.2
          pip install numba==0.53.1
          pip install tensorflow==${{ matrix.tensorflow }}
          pip install keras==${{ matrix.keras }}
          pip install lingvo==${{ matrix.lingvo }}
          pip install tensorflow-addons==0.9.1
          pip install model-pruning-google-research==0.0.3
          pip install h5py==2.10.0
          pip install pytest~=7.0.1
          pip install pytest-flake8~=1.1.0
          pip install pytest-mock
          pip install pytest-cov~=3.0.0
          pip install torch==1.10.2+cpu --find-links https://download.pytorch.org/whl/cpu/torch_stable.html
          pip install torchaudio==0.10.2+cpu --find-links https://download.pytorch.org/whl/cpu/torch_stable.html
          pip install torchvision==0.11.3+cpu --find-links https://download.pytorch.org/whl/cpu/torch_stable.html
          pip install xgboost==1.5.2
          pip install requests==2.27.1
          pip install kornia==0.6.8
          pip install librosa==0.9.2
          pip install tqdm==4.64.1
          pip install catboost==1.1.1
          pip install scikit-learn==0.24.2
          pip install GPy==1.10.0
          pip install lief==0.12.3
          pip list
      - name: Run ${{ matrix.name }} Tests
        run: pytest --cov-report=xml --cov=art --cov-append -q -vv tests/estimators/speech_recognition/test_tensorflow_lingvo.py --framework=${{ matrix.framework }} --durations=0
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4
        with:
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}


CI MXNet

name: CI MXNet
on:
  # Run on manual trigger
  workflow_dispatch:

  # Run on pull requests
  pull_request:
    paths-ignore:
      - '*.md'

  # Run on merge queue
  merge_group:

  # Run when pushing to main or dev branches
  push:
    branches:
      - main
      - dev*

  # Run scheduled CI flow daily
  schedule:
    - cron: '0 8 * * 0'

jobs:
  test:
    runs-on: ubuntu-20.04
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: mxnet (Python 3.9)
            framework: mxnet
            python: 3.9

    name: Run ${{ matrix.name }} Tests
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python }}
      - name: Install Dependencies
        run: |
          sudo apt-get update
          sudo apt-get -y -q install ffmpeg libavcodec-extra
          python -m pip install --upgrade pip setuptools wheel
          pip install -q -r <(sed '/^ultralytics/d;/^ipython/d' requirements_test.txt)
          pip list
      - name: Run ${{ matrix.name }} ${{ matrix.module }} Tests
        run: ./run_tests.sh ${{ matrix.framework }} ${{ matrix.module }}
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4
        with:
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}


CI PyTorchObjectDetectors

name: CI PyTorchObjectDetectors
on:
  # Run on manual trigger
  workflow_dispatch:

  # Run on pull requests
  pull_request:
    paths-ignore:
      - '*.md'

  # Run on merge queue
  merge_group:

  # Run when pushing to main or dev branches
  push:
    branches:
      - main
      - dev*

  # Run scheduled CI flow daily
  schedule:
    - cron: '0 8 * * 0'

jobs:
  test_pytorch_fasterrcnn:
    name: PyTorchObjectDetectors
    runs-on: ubuntu-20.04
    strategy:
      fail-fast: false
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.10'
      - name: Install Dependencies
        run: |
          sudo apt-get update
          sudo apt-get -y -q install ffmpeg libavcodec-extra
          python -m pip install --upgrade pip setuptools wheel
          pip3 install -q -r requirements_test.txt
          pip list
      - name: Pre-install torch
        run: |
          pip install torch==1.12.1+cpu -f https://download.pytorch.org/whl/cpu/torch_stable.html
          pip install torchvision==0.13.1+cpu -f https://download.pytorch.org/whl/cpu/torch_stable.html
          pip install torchaudio==0.12.1+cpu -f https://download.pytorch.org/whl/cpu/torch_stable.html
      - name: Run Test Action - test_pytorch_object_detector
        run: pytest --cov-report=xml --cov=art --cov-append -q -vv tests/estimators/object_detection/test_pytorch_object_detector.py --framework=pytorch --durations=0
      - name: Run Test Action - test_pytorch_faster_rcnn
        run: pytest --cov-report=xml --cov=art --cov-append -q -vv tests/estimators/object_detection/test_pytorch_faster_rcnn.py --framework=pytorch --durations=0
      - name: Run Test Action - test_pytorch_detection_transformer
        run: pytest --cov-report=xml --cov=art --cov-append -q -vv tests/estimators/object_detection/test_pytorch_detection_transformer.py --framework=pytorch --durations=0
      - name: Run Test Action - test_pytorch_object_seeker_faster_rcnn
        run: pytest --cov-report=xml --cov=art --cov-append -q -vv tests/estimators/object_detection/test_object_seeker_faster_rcnn.py --framework=pytorch --durations=0
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4
        with:
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}


CI PyTorch

name: CI PyTorch
on:
  # Run on manual trigger
  workflow_dispatch:

  # Run on pull requests
  pull_request:
    paths-ignore:
      - '*.md'

  # Run on merge queue
  merge_group:

  # Run when pushing to main or dev branches
  push:
    branches:
      - main
      - dev*

  # Run scheduled CI flow daily
  schedule:
    - cron: '0 8 * * 0'

jobs:
  test:
    runs-on: ubuntu-20.04
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: PyTorch 1.13.1 (Python 3.10)
            framework: pytorch
            python: '3.10'
            torch: 1.13.1+cpu
            torchvision: 0.14.1+cpu
            torchaudio: 0.13.1
          - name: PyTorch 2.2.1 (Python 3.10)
            framework: pytorch
            python: '3.10'
            torch: 2.2.1
            torchvision: 0.17.1+cpu
            torchaudio: 2.2.1

    name: ${{ matrix.name }}
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python }}
      - name: Install Dependencies
        run: |
          sudo apt-get update
          sudo apt-get -y -q install ffmpeg libavcodec-extra
          python -m pip install --upgrade pip setuptools wheel
          pip3 install -r requirements_test.txt
          pip install torch==${{ matrix.torch }} -f https://download.pytorch.org/whl/cpu/torch_stable.html
          pip install torchvision==${{ matrix.torchvision }} -f https://download.pytorch.org/whl/cpu/torch_stable.html
          pip install torchaudio==${{ matrix.torchaudio }} -f https://download.pytorch.org/whl/cpu/torch_stable.html
          pip list
      - name: Run Tests
        run: ./run_tests.sh ${{ matrix.framework }}
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4
        with:
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}


CI scikit-learn

name: CI scikit-learn
on:
  # Run on manual trigger
  workflow_dispatch:

  # Run on pull requests
  pull_request:
    paths-ignore:
      - '*.md'

  # Run on merge queue
  merge_group:

  # Run when pushing to main or dev branches
  push:
    branches:
      - main
      - dev*

  # Run scheduled CI flow daily
  schedule:
    - cron: '0 8 * * 0'

jobs:
  test:
    runs-on: ubuntu-20.04
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: scikit-learn 1.3.2 (Python 3.10)
            framework: scikitlearn
            scikit-learn: 1.3.2
            python: '3.10'
          - name: scikit-learn 1.4.0 (Python 3.10)
            framework: scikitlearn
            scikit-learn: 1.4.0
            python: '3.10'

    name: ${{ matrix.name }}
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python }}
      - name: Install Dependencies
        run: |
          sudo apt-get update
          sudo apt-get -y -q install ffmpeg libavcodec-extra
          python -m pip install --upgrade pip setuptools wheel
          pip install -r requirements_test.txt
          pip install scikit-learn==${{ matrix.scikit-learn }}
          pip list
      - name: Run Tests
        run: ./run_tests.sh ${{ matrix.framework }}
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4
        with:
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}


CI Style Checks

name: CI Style Checks
on:
  # Run on manual trigger
  workflow_dispatch:

  # Run on pull requests
  pull_request:
    paths-ignore:
      - '*.md'

  # Run on merge queue
  merge_group:

  # Run when pushing to main or dev branches
  push:
    branches:
      - main
      - dev*

  # Run scheduled CI flow daily
  schedule:
    - cron: '0 8 * * 0'

jobs:
  style:
    name: Style Check
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.10'
      - name: Pre-install
        run: |
          sudo apt-get update
          sudo apt-get -y -q install ffmpeg libavcodec-extra
      - name: Install Dependencies
        run: |
          python -m pip install --upgrade pip setuptools wheel
          pip install -q pylint==2.12.2 mypy==1.7.1 pycodestyle==2.8.0 black==21.12b0
          pip install -q -r <(sed '/^numpy/d;/^pluggy/d;/^tensorflow/d;/^keras/d' requirements_test.txt)
          pip install numpy==1.22.4
          pip install pluggy==0.13.1
          pip install tensorflow==2.13.1
          pip install keras==2.13.1
          pip install types-six
          pip install types-PyYAML
          pip install types-setuptools
          pip install click==8.0.2
          pip list
      - name: pycodestyle
        run: pycodestyle --ignore=C0330,C0415,E203,E231,W503 --max-line-length=120 art
      - name: pylint
        if: ${{ always() }}
        run: pylint --disable=C0330,C0415,E203,E1136,E0401,E1102 -rn art
      - name: mypy
        if: ${{ always() }}
        run: mypy art
      - name: pytest-flake8
        if: ${{ always() }}
        run: pytest --flake8 -v -m flake8 --ignore=contrib
      - name: black
        if: ${{ always() }}
        run: |
          black --line-length 120 --check art/
          black --line-length 120 --check tests/
          black --line-length 120 --check examples/


CI TensorFlow v1

name: CI TensorFlow v1
on:
  # Run on manual trigger
  workflow_dispatch:

  # Run on pull requests
  pull_request:
    paths-ignore:
      - '*.md'

  # Run on merge queue
  merge_group:

  # Run when pushing to main or dev branches
  push:
    branches:
      - main
      - dev*

  # Run scheduled CI flow daily
  schedule:
    - cron: '0 8 * * 0'

jobs:
  test:
    runs-on: ubuntu-20.04
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: TensorFlow 1.15.5 (Keras 2.2.5 Python 3.7)
            framework: tensorflow
            python: 3.7
            tensorflow: 1.15.5
            tf_version: v1
            keras: 2.2.5

    name: ${{ matrix.name }}
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python }}
      - name: Install Dependencies
        run: |
          sudo apt-get update
          sudo apt-get -y -q install ffmpeg libavcodec-extra
          python -m pip install --upgrade pip setuptools wheel
          pip install -q -r <(sed '/^pandas/d;/^scipy/d;/^matplotlib/d;/^xgboost/d;/^tensorflow/d;/^keras/d;/^jax/d;/^torch/d;/^Pillow/d;/^h5py/d;/^kornia/d;/^scikit-learn/d;/^pytest-mock/d;/^GPy/d;/^lief/d;/^statsmodels/d;/^ultralytics/d;/^ipython/d' requirements_test.txt)
          pip install pandas==1.3.5
          pip install scipy==1.7.2
          pip install matplotlib==3.5.3
          pip install xgboost==1.6.2
          pip install protobuf==3.20.1
          pip install tensorflow==${{ matrix.tensorflow }}
          pip install keras==${{ matrix.keras }}
          pip install numpy==1.20
          pip install torch==1.13.1
          pip install torchaudio==0.13.1
          pip install torchvision==0.14.1+cpu
          pip install Pillow==9.5.0
          pip install h5py==3.8.0
          pip install kornia==0.6.12
          pip install scikit-learn==1.0.2
          pip install pytest-mock~=3.11.1
          pip install GPy~=1.10.0
          pip install lief==0.12.3
          pip install statsmodels==0.13.5
          pip list
      - name: Run Tests
        run: ./run_tests.sh ${{ matrix.framework }}
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4
        with:
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}


CI TensorFlow v2

name: CI TensorFlow v2
on:
  # Run on manual trigger
  workflow_dispatch:

  # Run on pull requests
  pull_request:
    paths-ignore:
      - '*.md'

  # Run on merge queue
  merge_group:

  # Run when pushing to main or dev branches
  push:
    branches:
      - main
      - dev*

  # Run scheduled CI flow daily
  schedule:
    - cron: '0 8 * * 0'

jobs:
  test:
    runs-on: ubuntu-20.04
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: TensorFlow 2.13.1 (Keras 2.13.1 Python 3.10)
            framework: tensorflow
            python: '3.10'
            tensorflow: 2.13.1
            tf_version: v2
            keras: 2.13.1
            tf_addons: 0.21.0
          - name: TensorFlow 2.14.0v1 (Keras 2.14.0 Python 3.10)
            framework: tensorflow2v1
            python: '3.10'
            tensorflow: 2.14.0
            tf_version: v2
            keras: 2.14.0
            tf_addons: 0.21.0
          - name: TensorFlow 2.14.0 (Keras 2.14.0 Python 3.10)
            framework: tensorflow
            python: '3.10'
            tensorflow: 2.14.0
            tf_version: v2
            keras: 2.14.0
            tf_addons: 0.21.0

    name: ${{ matrix.name }}
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python }}
      - name: Install Dependencies
        run: |
          sudo apt-get update
          sudo apt-get -y -q install ffmpeg libavcodec-extra
          python -m pip install --upgrade pip setuptools wheel
          pip install -q -r <(sed '/^tensorflow/d;/^keras/d;/^tensorflow-addons/d' requirements_test.txt)
          pip install tensorflow==${{ matrix.tensorflow }}
          pip install keras==${{ matrix.keras }}
          pip install tensorflow-addons==${{ matrix.tf_addons }}
          pip list
      - name: Run Tests
        run: ./run_tests.sh ${{ matrix.framework }}
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4
        with:
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}


CI TensorFlowFasterRCNN

name: CI TensorFlowFasterRCNN
on:
  # Run on manual trigger
  workflow_dispatch:

  # Run on pull requests
  pull_request:
    paths-ignore:
      - '*.md'

  # Run on merge queue
  merge_group:

  # Run when pushing to main or dev branches
  push:
    branches:
      - main
      - dev*

  # Run scheduled CI flow daily
  schedule:
    - cron: '0 8 * * 0'

jobs:
  test_tf_faster_rcnn:
    name: TensorFlowFasterRCNN
    runs-on: ubuntu-latest
    container: adversarialrobustnesstoolbox/art_testing_envs:tf_fasterrcnn
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
      - name: Run Test Action
        uses: ./.github/actions/tf-faster-rcnn
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4
        with:
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}


CI TensorFlowV2FasterRCNN

name: CI TensorFlowV2FasterRCNN
on:
  # Run on manual trigger
  workflow_dispatch:

  # Run on pull requests
  pull_request:
    paths-ignore:
      - '*.md'

  # Run on merge queue
  merge_group:

  # Run when pushing to main or dev branches
  push:
    branches:
      - main
      - dev*

  # Run scheduled CI flow daily
  schedule:
    - cron: '0 8 * * 0'

jobs:
  test_tf_v2_faster_rcnn:
    name: TensorFlowV2FasterRCNN
    runs-on: ubuntu-latest
    container: adversarialrobustnesstoolbox/art_testing_envs:tfv2-faster-rcnn
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
      - name: Run Test Action
        uses: ./.github/actions/tfv2-faster-rcnn
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4
        with:
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}


CI PyTorchYolo

name: CI PyTorchYolo
on:
  # Run on manual trigger
  workflow_dispatch:

  # Run on pull requests
  pull_request:
    paths-ignore:
      - '*.md'

  # Run on merge queue
  merge_group:

  # Run when pushing to main or dev branches
  push:
    branches:
      - main
      - dev*

  # Run scheduled CI flow daily
  schedule:
    - cron: '0 8 * * 0'

jobs:
  test_deepspeech_v3_torch_1_10:
    name: PyTorchYolo
    runs-on: ubuntu-latest
    container: adversarialrobustnesstoolbox/art_testing_envs:yolo
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
      - name: Run Test Action
        uses: ./.github/actions/yolo
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4
        with:
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}


CodeQL

# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
name: "CodeQL"

on:
  push:
    branches: [main, dev_*]
  pull_request:
    # The branches below must be a subset of the branches above
    branches: [main, dev_*]
  # Run on merge queue
  merge_group:
  schedule:
    - cron: '0 7 * * 0'

jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        # Override automatic language detection by changing the below list
        # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
        language: ['python']
        # Learn more...
        # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection

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

    # Initializes the CodeQL tools for scanning.
    - name: Initialize CodeQL
      uses: github/codeql-action/init@v3
      with:
        languages: ${{ matrix.language }}
        # If you wish to specify custom queries, you can do so here or in a config file.
        # By default, queries listed here will override any specified in a config file.
        # Prefix the list here with "+" to use these queries and those in the config file.
        # queries: ./path/to/local/query, your-org/your-repo/queries@main
        queries: +security-and-quality, security-extended

    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
    # If this step fails, then you should remove it and run the build manually (see below)
    - name: Autobuild
      uses: github/codeql-action/autobuild@v3

    # ℹ Command-line programs to run using the OS shell.
    # 📚 https://git.io/JvXDl

    # ✏ If the Autobuild fails above, remove it and uncomment the following three lines
    #    and modify them (or add more) to build your code if your project
    #    uses a compiled language

    #- run: |
    #   make bootstrap
    #   make release

    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@v3


Publish Docker image

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

# GitHub recommends pinning actions to a commit SHA.
# To get a newer version, you will need to update the SHA.
# You can also reference a tag or branch, but the action may change without warning.
name: Publish Docker image

on:
  # Run on manual trigger
  workflow_dispatch:

  release:
    types: [published]

jobs:
  push_to_registry:
    name: Push Docker image to Docker Hub
    runs-on: ubuntu-latest
    steps:
      - name: Check out the repo
        uses: actions/checkout@v4

      - name: Log in to Docker Hub
        uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20
        with:
          username: ${{ secrets.DOCKER_HUB_USERNAME }}
          password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81
        with:
          images: adversarialrobustnesstoolbox/releases
          tags: |
            type=raw,value={{branch}}-1.18.0-{{sha}}
            type=semver,pattern={{version}}

      - name: Build and push Docker image
        uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}


Helm diff

# This workflow provides a diff of the rendered Helm chart's templates with the
# latest released dev version of the chart.
#
name: Helm diff

on:
  pull_request:
    paths:
      - ".github/workflows/diff.yml"
      - "helm-chart/binderhub/**"
  push:
    paths:
      - ".github/workflows/diff.yml"
      - "helm-chart/binderhub/**"
    branches-ignore:
      - "dependabot/**"
      - "pre-commit-ci-update-config"
      - "update-*"
  workflow_dispatch:

jobs:
  diff-rendered-templates:
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: jupyterhub/action-k3s-helm@v4
        with:
          k3s-channel: stable
          metrics-enabled: false
          traefik-enabled: false
          docker-enabled: true

      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: Install helm diff plugin, update local chart dependencies
        run: |
          helm plugin install https://github.com/databus23/helm-diff
          helm dependency update ./helm-chart/binderhub

      - name: "Install latest released dev chart"
        run: |
          UPGRADE_FROM_VERSION=$(curl -sSL https://jupyterhub.github.io/helm-chart/info.json | jq -er '.binderhub.dev')

          # NOTE: We change the directory so binderhub the chart name won't be
          #       misunderstood as the local folder name.
          # validation is disabled, because the config is for a different version!
          cd testing

          old_config="../testing/k8s-binder-k8s-hub/binderhub-chart-config-old.yaml"
          if [ -f "$old_config" ]; then
            echo "using old config"
          else
            old_config="../testing/k8s-binder-k8s-hub/binderhub-chart-config.yaml"
          fi

          helm install binderhub-test binderhub \
              --values "$old_config" \
              --repo https://jupyterhub.github.io/helm-chart/ \
              --disable-openapi-validation \
              --version=$UPGRADE_FROM_VERSION

      - name: "Helm diff latest released dev chart with local chart"
        run: |
          echo "NOTE: For the helm diff, we have not updated the Chart.yaml"
          echo "      version or image tags using chartpress."
          echo

          helm diff upgrade binderhub-test helm-chart/binderhub \
              --values testing/k8s-binder-k8s-hub/binderhub-chart-config.yaml \
              --context=3


eslint

# Lints the binderhub/static/js folders content with eslint, influenced by
# ".eslintrc.js", by running "npm run lint" where "lint" is a command defined in
# package.json.
#
name: eslint

on:
  pull_request:
    paths:
      - ".github/workflows/eslint.yml"
      - ".eslintrc.js"
      - "package.json"
      - "binderhub/static/js/**"
      - "js/**"
  push:
    paths:
      - ".github/workflows/eslint.yml"
      - ".eslintrc.js"
      - "package.json"
      - "binderhub/static/js/**"
      - "js/**"
    branches-ignore:
      - "dependabot/**"
      - "pre-commit-ci-update-config"
      - "update-*"
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - run: npm install

      - run: npm run lint


JS Unit tests

# Runs jest based unit tests for frontend javascript and @jupyterhub/binderhub-client
name: "JS Unit tests"

on:
  pull_request:
    paths:
      - "binderhub/static/js/**"
      - "js/packages/binderhub-client/**"
      - ".github/workflows/jest.yml"
  push:
    paths:
      - "binderhub/static/js/**"
      - "js/packages/binderhub-client/**"
      - ".github/workflows/jest.yml"
    branches-ignore:
      - "dependabot/**"
      - "pre-commit-ci-update-config"
      - "update-*"
  workflow_dispatch:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: "Setup dependencies"
        run: |
          npm install

      - name: "Run all unit tests"
        run: |
          npm test

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4


Publish helm chart and docker images

name: Publish helm chart and docker images

on:
  pull_request:
    paths-ignore:
      - "**.md"
      - "**.rst"
      - "docs/**"
      - "examples/**"
      - ".github/workflows/**"
      - "!.github/workflows/publish.yml"
  push:
    paths-ignore:
      - "**.md"
      - "**.rst"
      - "docs/**"
      - "examples/**"
      - ".github/workflows/**"
      - "!.github/workflows/publish.yml"
    branches-ignore:
      - "dependabot/**"
      - "pre-commit-ci-update-config"
      - "update-*"
  workflow_dispatch:

jobs:
  # Builds and pushes docker images to quay.io, packages the Helm chart and
  # pushes it to jupyterhub/helm-chart@gh-pages where index.yaml represents the
  # JupyterHub organization Helm chart repository.
  #
  # ref: https://github.com/jupyterhub/helm-chart
  # ref: https://quay.io/organization/jupyterhub
  #
  Publish:
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/') || (github.ref == 'refs/heads/main')
    steps:
      - uses: actions/checkout@v4
        with:
          # chartpress requires the full history
          fetch-depth: 0

      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - uses: actions/setup-node@v4
        # node required to build wheel
        with:
          node-version: "16"

      - name: Set up QEMU (for docker buildx)
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx (for chartpress multi-arch builds)
        uses: docker/setup-buildx-action@v3

      - name: Setup helm
        uses: azure/setup-helm@v4
        with:
          version: "v3.5.4"

      - name: Install chart publishing dependencies (chartpress, etc)
        run: |
          pip install --no-cache-dir chartpress>=2.1 pyyaml build

      - name: Build binderhub wheel
        run: python3 -m build --wheel .

      - name: Setup push rights to jupyterhub/helm-chart
        # This was setup by...
        # 1. Generating a private/public key pair:
        #    ssh-keygen -t ed25519 -C "jupyterhub/binderhub" -f /tmp/id_ed25519
        # 2. Registering the private key (/tmp/id_ed25519) as a secret for this
        #    repo:
        #    https://github.com/jupyterhub/binderhub/settings/secrets/actions
        # 3. Registering the public key (/tmp/id_ed25519.pub) as a deploy key
        #    with push rights for the jupyterhub/helm chart repo:
        #    https://github.com/jupyterhub/helm-chart/settings/keys
        #
        run: |
          mkdir -p ~/.ssh
          ssh-keyscan github.com >> ~/.ssh/known_hosts
          echo "${{ secrets.JUPYTERHUB_HELM_CHART_DEPLOY_KEY }}" > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519

      - name: Setup push rights to Quay.io
        # This was setup by...
        # 1. Creating a [Robot Account](https://quay.io/organization/jupyterhub?tab=robots) in the JupyterHub
        # .  quay.io org
        # 2. Giving it enough permissions to push to the binderhub image
        # 3. Putting the robot account's username and password in GitHub actions environment
        run: |
          docker login -u "${{ secrets.QUAY_USERNAME }}" -p "${{ secrets.QUAY_PASSWORD }}" quay.io
          docker login -u "${{ secrets.DOCKER_USERNAME }}" -p "${{ secrets.DOCKER_PASSWORD }}" docker.io

      - name: Configure a git user
        # Having a user.email and user.name configured with git is required to
        # make commits, which is something chartpress does when publishing.
        # While Travis CI had a dummy user by default, GitHub Actions doesn't
        # and require this explicitly setup.
        run: |
          git config --global user.email "github-actions@example.local"
          git config --global user.name "GitHub Actions user"

      - name: Publish images and chart with chartpress
        env:
          GITHUB_REPOSITORY: "${{ github.repository }}"
        run: |
          ./tools/generate-json-schema.py
          ./ci/publish

  PyPI-testbuild:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          # Versioneer requires past tags
          fetch-depth: 0
      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"
      - name: Install pypa/build
        run: python -mpip install build
      - name: Build a sdist, and a binary wheel from the sdist
        run: python -mbuild .
      # ref: https://github.com/actions/upload-artifact#readme
      - uses: actions/upload-artifact@v4
        with:
          name: pypi-dist
          path: "dist/*"
          if-no-files-found: error


Test docker multiarch build

# This is a GitHub workflow defining a set of jobs with a set of steps.
# ref: https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions
#
name: Test docker multiarch build

# Trigger the workflow's on all PRs and pushes so that other contributors can
# run tests in their own forks. Avoid triggering this tests on changes not
# influencing the image notably.
on:
  pull_request:
    paths:
      - "helm-chart/images/**"
      - "helm-chart/chartpress.yaml"
      - ".github/workflows/test-docker-build.yaml"
  push:
    paths:
      - "helm-chart/images/**"
      - "helm-chart/chartpress.yaml"
      - ".github/workflows/test-docker-build.yaml"
    branches-ignore:
      - "dependabot/**"
      - "pre-commit-ci-update-config"
      - "update-*"
  workflow_dispatch:

jobs:
  # This is a quick test to check the arm64 docker images based on:
  # - https://github.com/docker/build-push-action/blob/v2.3.0/docs/advanced/local-registry.md
  # - https://github.com/docker/build-push-action/blob/v2.3.0/docs/advanced/multi-platform.md
  build_images:
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4
        with:
          # chartpress requires git history to set chart version and image tags
          # correctly
          fetch-depth: 0

      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - uses: actions/setup-node@v4
        # node required to build wheel
        with:
          node-version: "16"

      - name: Install chartpress
        run: pip install chartpress build

      - name: Build binderhub wheel
        run: python3 -m build --wheel .

      - name: Set up QEMU (for docker buildx)
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx (for chartpress multi-arch builds)
        uses: docker/setup-buildx-action@v3

      - name: Build a multiple architecture Docker image
        run: |
          cd helm-chart
          chartpress \
              --builder docker-buildx \
              --platform linux/amd64 --platform linux/arm64


Tests

# This is a GitHub workflow defining a set of jobs with a set of steps.
# ref: https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions
#
name: Tests

on:
  pull_request:
    paths-ignore:
      - "**.md"
      - "**.rst"
      - "docs/**"
      - "examples/**"
      - ".github/workflows/**"
      - "!.github/workflows/test.yml"
  push:
    paths-ignore:
      - "**.md"
      - "**.rst"
      - "docs/**"
      - "examples/**"
      - ".github/workflows/**"
      - "!.github/workflows/test.yml"
    branches-ignore:
      - "dependabot/**"
      - "pre-commit-ci-update-config"
      - "update-*"
  workflow_dispatch:

jobs:
  lint:
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4

      - name: install requirements
        run: pip install ruamel.yaml

      - name: check embedded chart code
        run: ./ci/check_embedded_chart_code.py

  # Most of the "main", "auth" and "helm" jobs are the same and only differ
  # in small things. Unfortunately there is no easy way to share steps between
  # jobs or have "template" jobs, so we use `if` conditions on steps
  tests:
    runs-on: ubuntu-22.04
    timeout-minutes: 10

    permissions:
      contents: read
    env:
      GITHUB_ACCESS_TOKEN: "${{ secrets.github_token }}"

    strategy:
      # keep running so we can see if tests with other k3s/k8s/helm versions pass
      fail-fast: false
      matrix:
        k3s-channel:
          # Available channels: https://github.com/k3s-io/k3s/blob/HEAD/channel.yaml
          # Don't use "latest", instead bump it using a PR so we know when a new version breaks BinderHub
          - v1.29
        test:
          - main
          - auth
        test-variation:
          - ""
        include:
          # Chart.yaml contains the chart's oldest supported k8s version, we
          # test against that and the oldest known supported helm cli version
          # which isn't documented anywhere, but is currently at 3.5.0. We also
          # test with the latest k8s and helm versions.
          #
          - k3s-channel: v1.23
            helm-version: v3.5.0
            test: helm
            test-variation: dind
            local-chart-extra-args: >-
              --values testing/k8s-binder-k8s-hub/binderhub-chart+dind.yaml
              --set config.BinderHub.image_prefix=$REGISTRY_HOST/test/
              --set registry.url=http://$REGISTRY_HOST
          - k3s-channel: v1.29
            test: helm
            test-variation: pink
            local-chart-extra-args: >-
              --values testing/k8s-binder-k8s-hub/binderhub-chart+pink.yaml
              --set config.BinderHub.image_prefix=$REGISTRY_HOST/test/
              --set registry.url=http://$REGISTRY_HOST
          - k3s-channel: v1.29
            test: helm
            test-variation: upgrade
            # upgrade-from represents a release channel, see: https://jupyterhub.github.io/helm-chart/info.json
            upgrade-from: dev
            upgrade-from-extra-args: ""

    services:
      registry:
        image: docker.io/library/registry:latest
        ports:
          - 5000:5000

    steps:
      - uses: actions/checkout@v4
        with:
          # chartpress requires the full history
          fetch-depth: 0

      - name: Set registry host
        if: matrix.test-variation == 'dind' || matrix.test-variation == 'pink'
        run: |
          REGISTRY_HOST=$(hostname -I | awk '{print $1}'):5000
          echo REGISTRY_HOST="$REGISTRY_HOST" >> $GITHUB_ENV

          # Allow k3s to pull from private registry
          # https://docs.k3s.io/installation/private-registry
          sudo mkdir -p /etc/rancher/k3s/
          cat << EOF | sudo tee /etc/rancher/k3s/registries.yaml
          mirrors:
            "$REGISTRY_HOST":
              endpoint:
                - "http://$REGISTRY_HOST"
          EOF

      - uses: jupyterhub/action-k3s-helm@v4
        with:
          k3s-channel: ${{ matrix.k3s-channel }}
          helm-version: ${{ matrix.helm-version }}
          metrics-enabled: false
          traefik-enabled: false
          docker-enabled: ${{ matrix.test-variation != 'dind' && matrix.test-variation != 'pink' }}

      - name: Setup OS level dependencies
        run: |
          sudo apt-get update
          sudo apt-get install --yes \
            build-essential \
            curl \
            libcurl4-openssl-dev \
            libssl-dev

      - uses: actions/setup-node@v4
        id: setup-node
        with:
          node-version: "18"

      - name: Cache npm
        uses: actions/cache@v4
        with:
          path: ~/.npm
          key: node-${{ steps.setup-node.outputs.node-version }}-${{ hashFiles('**/package.json') }}-${{ github.job }}

      - name: Run webpack to build static assets
        run: |
          npm install
          npm run webpack

      - uses: actions/setup-python@v5
        id: setup-python
        with:
          python-version: "3.11"

      - name: Cache pip
        uses: actions/cache@v4
        with:
          path: ~/.cache/pip
          key: python-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/*requirements.txt') }}-${{ github.job }}

      - name: Update pip
        run: |
          pip install --upgrade pip
          pip install --upgrade setuptools wheel

      - name: Setup Python package dependencies
        run: |
          pip install --no-binary pycurl -r dev-requirements.txt -r helm-chart/images/binderhub/requirements.txt
          pip install -e .

      - name: Install JupyterHub chart for main tests
        if: matrix.test == 'main'
        run: |
          ./testing/local-binder-k8s-hub/install-jupyterhub-chart

      - name: Install JupyterHub chart for auth tests
        if: matrix.test == 'auth'
        run: |
          ./testing/local-binder-k8s-hub/install-jupyterhub-chart --auth

      - name: Build binderhub wheel
        if: matrix.test == 'helm'
        run: |
          python3 -m build .

      - name: Use chartpress to create the helm chart
        if: matrix.test == 'helm'
        run: |
          export DOCKER_BUILDKIT=1

          CHARTPRESS_ARGS=
          if [ "${{ matrix.test-variation }}" = "dind" -o "${{ matrix.test-variation }}" = "pink" ]; then
            CHARTPRESS_ARGS="--image-prefix localhost:5000/binderhub- --push"

            # Allow the pods to push to the non-https GitHub workflow registry
            envsubst < testing/k8s-binder-k8s-hub/cm-insecure-registries-${{ matrix.test-variation }}.yaml | kubectl apply -f -
          fi

          # Use chartpress to create the helm chart and build its images
          helm dependency update ./helm-chart/binderhub
          (cd helm-chart && chartpress $CHARTPRESS_ARGS)
          git --no-pager diff --color=always

      - name: Generate values.schema.json from schema.yaml
        if: matrix.test == 'helm'
        run: |
          tools/generate-json-schema.py

      - name: "Helm template --validate (with lint-and-validate-values.yaml)"
        if: matrix.test == 'helm'
        run: |
          helm template --validate binderhub-test helm-chart/binderhub \
              --values tools/templates/lint-and-validate-values.yaml

      - name: "Helm template --validate for dind (with lint-and-validate-values.yaml)"
        if: matrix.test == 'helm'
        run: |
          helm template --validate binderhub-test helm-chart/binderhub \
              --values tools/templates/lint-and-validate-values.yaml \
              --set imageBuilderType=dind

      - name: "Helm template --validate for pink (with lint-and-validate-values.yaml)"
        if: matrix.test == 'helm'
        run: |
          helm template --validate binderhub-test helm-chart/binderhub \
              --values tools/templates/lint-and-validate-values.yaml \
              --set imageBuilderType=pink

      - name: Validate the chart against the k8s API
        if: matrix.test == 'helm'
        run: |
          helm template --validate binderhub-test helm-chart/binderhub \
              --values testing/k8s-binder-k8s-hub/binderhub-chart-config.yaml \
              --set config.BinderHub.hub_url=http://localhost:30902 \
              --set config.GitHubRepoProvider.access_token=$GITHUB_ACCESS_TOKEN

      - name: "(Upgrade) Install ${{ matrix.upgrade-from }} chart"
        if: matrix.test-variation == 'upgrade'
        run: |
          # NOTE: We change the directory so binderhub the chart name won't be
          #       misunderstood as the local folder name.
          #
          #       https://github.com/helm/helm/issues/9244
          cd ci

          if [ ${{ matrix.upgrade-from }} = stable ]; then
            UPGRADE_FROM_VERSION=$(helm show chart --repo=https://hub.jupyter.org/helm-chart/ binderhub | yq e '.version' -)
          elif [ ${{ matrix.upgrade-from }} = dev ]; then
            UPGRADE_FROM_VERSION=$(helm show chart --devel --repo=https://hub.jupyter.org/helm-chart/ binderhub | yq e '.version' -)
          else
            UPGRADE_FROM_VERSION=${{ matrix.upgrade-from }}
          fi
          echo "UPGRADE_FROM_VERSION=$UPGRADE_FROM_VERSION" >> $GITHUB_ENV

          echo ""
          echo "Installing already released binderhub version $UPGRADE_FROM_VERSION"

          old_config="../testing/k8s-binder-k8s-hub/binderhub-chart-config-old.yaml"
          if [ -f "$old_config" ]; then
            echo "using old config"
          else
            old_config="../testing/k8s-binder-k8s-hub/binderhub-chart-config.yaml"
          fi

          helm install binderhub-test \
              --repo https://jupyterhub.github.io/helm-chart/ binderhub \
              --disable-openapi-validation \
              --version=$UPGRADE_FROM_VERSION \
              --values "$old_config" \
              --set config.BinderHub.hub_url=http://localhost:30902 \
              --set config.BinderHub.hub_url_local=http://proxy-public \
              --set config.GitHubRepoProvider.access_token=$GITHUB_ACCESS_TOKEN \
              ${{ matrix.upgrade-from-extra-args }}

      - name: "(Upgrade) Install helm diff"
        if: matrix.test-variation == 'upgrade'
        run: |
          helm plugin install https://github.com/databus23/helm-diff

      - name: "(Upgrade) Helm diff ${{ matrix.upgrade-from }} chart with local chart"
        if: matrix.test-variation == 'upgrade'
        run: |
          helm diff upgrade binderhub-test ./helm-chart/binderhub \
              --values testing/k8s-binder-k8s-hub/binderhub-chart-config.yaml \
              --set config.BinderHub.hub_url=http://localhost:30902 \
              --set config.BinderHub.hub_url_local=http://proxy-public \
              --set config.GitHubRepoProvider.access_token=$GITHUB_ACCESS_TOKEN \
              ${{ matrix.local-chart-extra-args }}

      - name: "(Upgrade) Await ${{ matrix.upgrade-from }} chart"
        if: matrix.test-variation == 'upgrade'
        uses: jupyterhub/action-k8s-await-workloads@v3
        with:
          timeout: 150
          max-restarts: 1

      - name: Test the workaround for an incorrect docker.sock directory
        if: matrix.test-variation == 'dind'
        run: |
          # {{ .Values.dind.hostSocketDir }}/{{ .Values.dind.hostSocketName }}
          sudo mkdir -p /var/run/dind/docker.sock

      - name: Install the chart
        if: matrix.test == 'helm'
        run: |
          helm upgrade --install binderhub-test helm-chart/binderhub \
              --values testing/k8s-binder-k8s-hub/binderhub-chart-config.yaml \
              --set config.BinderHub.hub_url=http://localhost:30902 \
              --set config.BinderHub.hub_url_local=http://proxy-public \
              --set config.GitHubRepoProvider.access_token=$GITHUB_ACCESS_TOKEN \
              ${{ matrix.local-chart-extra-args }}

      - name: Await and curl JupyterHub
        run: |
          . ci/common
          await_jupyterhub

          echo curl http://localhost:30902/hub/api/ should print the JupyterHub version
          curl http://localhost:30902/hub/api/ --max-time 5 --retry 5 --retry-delay 1 --retry-connrefused --fail-with-body --retry-all-errors

      - name: Await and curl BinderHub
        if: matrix.test == 'helm'
        run: |
          . ci/common
          await_binderhub binderhub-test

          echo curl http://localhost:30901/health to check BinderHub\'s health
          curl http://localhost:30901/health --max-time 5 --retry 5 --retry-delay 1 --retry-connrefused --fail-with-body --retry-all-errors

      - name: Run main tests
        if: matrix.test == 'main'
        # running the "main" tests means "all tests that aren't auth"
        run: pytest -m "not auth" --cov=binderhub

      - name: Run auth tests
        if: matrix.test == 'auth'
        # running the "auth" tests means "all tests that are marked as auth"
        run: pytest -m "auth" --cov=binderhub

      - name: Run helm tests
        if: matrix.test == 'helm'
        run: |
          export BINDER_URL=http://localhost:30901
          pytest --helm -m "remote" --cov=binderhub

      - name: Get BinderHub health and metrics outputs
        if: always()
        run: |
          if [ "${{ matrix.test }}" = "helm" ]; then
            for endpoint in versions health metrics; do
              echo -e "\n${endpoint}"
              curl http://localhost:30901/$endpoint --fail-with-body
            done
          fi

      # GitHub Action reference: https://github.com/jupyterhub/action-k8s-namespace-report
      - name: Kubernetes namespace report
        uses: jupyterhub/action-k8s-namespace-report@v1
        if: always()
        with:
          important-workloads: >
            deploy/binder
            deploy/hub
            deploy/proxy
            daemonset/binderhub-test-dind
            daemonset/binderhub-test-pink

      # GitHub action reference: https://github.com/codecov/codecov-action
      - uses: codecov/codecov-action@v4

  test-local:
    runs-on: ubuntu-22.04
    timeout-minutes: 5

    permissions:
      contents: read
    env:
      GITHUB_ACCESS_TOKEN: "${{ secrets.github_token }}"

    steps:
      - uses: actions/checkout@v4

      - name: Setup OS level dependencies
        run: |
          sudo apt-get update
          sudo apt-get install --yes \
            build-essential \
            curl \
            libcurl4-openssl-dev \
            libssl-dev

      - uses: actions/setup-node@v4
        id: setup-node
        with:
          node-version: "18"

      - name: Cache npm
        uses: actions/cache@v4
        with:
          path: ~/.npm
          key: node-${{ steps.setup-node.outputs.node-version }}-${{ hashFiles('**/package.json') }}-${{ github.job }}

      - uses: actions/setup-python@v5
        id: setup-python
        with:
          python-version: "3.11"

      - name: Cache pip
        uses: actions/cache@v4
        with:
          path: ~/.cache/pip
          key: python-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/*requirements.txt') }}-${{ github.job }}

      - name: Update pip
        run: |
          pip install --upgrade pip
          pip install --upgrade setuptools wheel

      - name: Setup Python package dependencies
        # FIXME: We do "pip install ." before "pip install -e ." to ensure
        #        binderhub/static/dist/bundle.js is built, and use "-e" to
        #        ensure code coverage is captured.
        #
        # https://discourse.jupyter.org/t/suddenly-getting-oath-cert-error/24217/4
        # pycurl wheels fail to pick up the system CA certs, so install from source
        # until https://github.com/pycurl/pycurl/issues/834 resolves
        run: |
          pip install -r dev-requirements.txt -r testing/local-binder-local-hub/requirements.txt
          pip install ".[pycurl]" --no-binary pycurl
          pip install -e ".[pycurl]" --no-binary pycurl

      - name: Setup JupyterHub NPM dependencies
        run: npm install -g configurable-http-proxy

      - name: Await and curl JupyterHub
        run: |
          cd testing/local-binder-local-hub
          jupyterhub --config=jupyterhub_config.py > jupyterhub.log 2>&1 &
          sleep 5

          echo curl http://localhost:8000/hub/api/ should print the JupyterHub version
          curl http://localhost:8000/hub/api/ --max-time 5 --retry 5 --retry-delay 1 --retry-connrefused --fail-with-body --retry-all-errors

      - name: Run remote tests
        run: |
          export BINDER_URL=http://localhost:8000/services/binder/
          pytest -m remote --cov=binderhub

      - name: Show hub logs
        if: always()
        run: cat testing/local-binder-local-hub/jupyterhub.log

      # GitHub action reference: https://github.com/codecov/codecov-action
      - uses: codecov/codecov-action@v4


Watch dependencies

# This is a GitHub workflow defining a set of jobs with a set of steps.
# ref: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
#
# - Watch multiple images tags referenced in values.yaml to match the latest
#   stable image tag (ignoring pre-releases).
# - Refreeze helm-chart/images/binderhub/requirements.txt based on
#   helm-chart/images/binderhub/requirements.in
#
name: Watch dependencies

on:
  pull_request:
    paths:
      - ".github/workflows/watch-dependencies.yaml"
  push:
    paths:
      - "helm-chart/images/*/requirements.in"
      - ".github/workflows/watch-dependencies.yaml"
    branches: ["main"]
  schedule:
    # Run at 05:00 on day-of-month 1, ref: https://crontab.guru/#0_5_1_*_*
    - cron: "0 5 1 * *"
  workflow_dispatch:

jobs:
  update-image-dependencies:
    # Don't run this job on forks
    if: github.repository == 'jupyterhub/binderhub'
    runs-on: ubuntu-22.04

    strategy:
      fail-fast: false
      matrix:
        include:
          - name: docker
            registry: docker.io
            repository: library/docker
            values_path: dind.daemonset.image.tag
            tag_prefix: ""
            tag_suffix: -dind
          - name: podman
            registry: quay.io
            repository: podman/stable
            values_path: pink.daemonset.image.tag
            tag_prefix: v
            tag_suffix: ""

          # FIXME: After docker-image-cleaner 1.0.0 is released, we can enable
          #        this. So far, there isn't any available stable release, and
          #        due to that our regexp fails to match anything at all.
          #
          # - name: docker-image-cleaner
          #   registry: quay.io
          #   repository: jupyterhub/docker-image-cleaner
          #   values_path: imageCleaner.image.tag

    steps:
      - uses: actions/checkout@v4

      - name: Get values.yaml pinned tag of ${{ matrix.registry }}/${{ matrix.repository }}
        id: local
        run: |
          local_tag=$(cat helm-chart/binderhub/values.yaml | yq e '.${{ matrix.values_path }}' -)
          echo "tag=$local_tag" >> $GITHUB_OUTPUT

      - name: Get latest tag of ${{ matrix.registry }}/${{ matrix.repository }}
        id: latest
        # The skopeo image helps us list tags consistently from different docker
        # registries. We identify the latest docker image tag based on the
        # version numbers of format x.y.z included in a pattern with an optional
        # prefix and suffix, like the tags "v4.5.0" (v prefix) and "23.0.4-dind"
        # (-dind suffix).
        run: |
          latest_tag=$(
              docker run --rm quay.io/skopeo/stable list-tags docker://${{ matrix.registry }}/${{ matrix.repository }} \
            | jq -r '[.Tags[] | select(. | match("^${{ matrix.tag_prefix }}\\d+\\.\\d+\\.\\d+${{ matrix.tag_suffix }}$") | .string)] | sort_by(split(".") | map(ltrimstr("${{ matrix.tag_prefix }}") | rtrimstr("${{ matrix.tag_suffix }}") | tonumber)) | last'
          )
          echo "tag=$latest_tag" >> $GITHUB_OUTPUT

      - name: Update values.yaml pinned tag
        run: |
          sed --in-place 's/tag: "${{ steps.local.outputs.tag }}"/tag: "${{ steps.latest.outputs.tag }}"/g' helm-chart/binderhub/values.yaml

      - name: git diff
        run: git --no-pager diff --color=always

      # ref: https://github.com/peter-evans/create-pull-request
      - name: Create a PR
        if: github.event_name != 'pull_request'
        uses: peter-evans/create-pull-request@v6
        with:
          token: "${{ secrets.jupyterhub_bot_pat }}"
          author: JupterHub Bot Account <105740858+jupyterhub-bot@users.noreply.github.com>
          committer: JupterHub Bot Account <105740858+jupyterhub-bot@users.noreply.github.com>
          branch: update-image-${{ matrix.name }}
          labels: maintenance,dependencies
          commit-message: Update ${{ matrix.repository }} version from ${{ steps.local.outputs.tag }} to ${{ steps.latest.outputs.tag }}
          title: Update ${{ matrix.repository }} version from ${{ steps.local.outputs.tag }} to ${{ steps.latest.outputs.tag }}
          body: >-
            A new ${{ matrix.repository }} image version has been detected, version
            `${{ steps.latest.outputs.tag }}`.

  refreeze-dockerfile-requirements-txt:
    # Don't run this job on forks, but also not on the daily schedule to reduce
    # noise. If we could run this weekly that would be reasonable, but updating
    # these dependencies every day is too much noise.
    #
    if: github.repository == 'jupyterhub/binderhub' && github.event_name != 'schedule'
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Refreeze helm-chart/images/binderhub/requirements.txt based on requirements.in
        run: ci/refreeze

      - name: git diff
        run: git --no-pager diff --color=always

      # ref: https://github.com/peter-evans/create-pull-request
      - name: Create a PR
        if: github.event_name != 'pull_request'
        uses: peter-evans/create-pull-request@v6
        with:
          token: "${{ secrets.jupyterhub_bot_pat }}"
          author: JupyterHub Bot Account <105740858+jupyterhub-bot@users.noreply.github.com>
          committer: JupyterHub Bot Account <105740858+jupyterhub-bot@users.noreply.github.com>
          branch: update-image-requirements
          labels: dependencies
          commit-message: "binderhub image: refreeze requirements.txt"
          title: "binderhub image: refreeze requirements.txt"
          body: >-
            The binderhub image's requirements.txt has been refrozen based on
            requirements.in.


premerge

# Jenkinsfile.monai-premerge
name: premerge

on:
  # quick tests for pull requests and the releasing branches
  push:
    branches:
      - dev
      - main
      - releasing/*
  pull_request:
    head_ref-ignore:
      - dev

concurrency:
  # automatically cancel the previously triggered workflows when there's a newer version
  group: build-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

jobs:
  # caching of these jobs:
  #   - docker-py3-pip- (shared)
  #   - ubuntu py37 pip-
  #   - os-latest-pip- (shared)
  flake8-py3:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        opt: ["codeformat", "pytype", "mypy"]
    steps:
    - uses: actions/checkout@v4
    - name: Set up Python 3.8
      uses: actions/setup-python@v5
      with:
        python-version: '3.8'
    - name: cache weekly timestamp
      id: pip-cache
      run: |
        echo "datew=$(date '+%Y-%V')" >> $GITHUB_OUTPUT
    - name: cache for pip
      uses: actions/cache@v4
      id: cache
      with:
        path: ~/.cache/pip
        key: ${{ runner.os }}-pip-${{ steps.pip-cache.outputs.datew }}
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip wheel
        python -m pip install -r requirements-dev.txt
    - name: Lint and type check
      run: |
        # clean up temporary files
        $(pwd)/runtests.sh --build --clean
        # Github actions have 2 cores, so parallelize pytype
        $(pwd)/runtests.sh --build --${{ matrix.opt }} -j 2

  quick-py3:  # full dependencies installed tests for different OS
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [windows-latest, macOS-latest, ubuntu-latest]
    timeout-minutes: 120
    steps:
    - if: runner.os == 'windows'
      name: Config pagefile (Windows only)
      uses: al-cheb/configure-pagefile-action@v1.4
      with:
        minimum-size: 8GB
        maximum-size: 16GB
        disk-root: "D:"
    - uses: actions/checkout@v4
    - name: Set up Python 3.9
      uses: actions/setup-python@v5
      with:
        python-version: '3.9'
    - name: Prepare pip wheel
      run: |
        which python
        python -m pip install --upgrade pip wheel
    - name: cache weekly timestamp
      id: pip-cache
      run: |
        echo "datew=$(date '+%Y-%V')" >> $GITHUB_OUTPUT
        echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT
      shell: bash
    - name: cache for pip
      uses: actions/cache@v4
      id: cache
      with:
        path: ${{ steps.pip-cache.outputs.dir }}
        key: ${{ matrix.os }}-latest-pip-${{ steps.pip-cache.outputs.datew }}
    - if: runner.os == 'windows'
      name: Install torch cpu from pytorch.org (Windows only)
      run: |
        python -m pip install torch==1.13.1+cpu torchvision==0.14.1+cpu -f https://download.pytorch.org/whl/torch_stable.html
    - if: runner.os == 'Linux'
      name: Install itk pre-release (Linux only)
      run: |
        python -m pip install --pre -U itk
    - name: Install the dependencies
      run: |
        python -m pip install --user --upgrade pip wheel
        python -m pip install torch==1.13.1 torchvision==0.14.1
        cat "requirements-dev.txt"
        python -m pip install -r requirements-dev.txt
        python -m pip list
        python setup.py develop  # test no compile installation
      shell: bash
    - name: Run compiled (${{ runner.os }})
      run: |
        python setup.py develop --uninstall
        BUILD_MONAI=1 python setup.py develop  # compile the cpp extensions
      shell: bash
    - name: Run quick tests (CPU ${{ runner.os }})
      run: |
        python -c 'import torch; print(torch.__version__); print(torch.rand(5,3))'
        python -c "import monai; monai.config.print_config()"
        python -m unittest -v
      env:
        QUICKTEST: True
        PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION: python  # https://github.com/Project-MONAI/MONAI/issues/4354

  packaging:
    runs-on: ubuntu-latest
    env:
      QUICKTEST: True
      shell: bash
    steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0
    - name: Set up Python 3.8
      uses: actions/setup-python@v5
      with:
        python-version: '3.8'
    - name: cache weekly timestamp
      id: pip-cache
      run: |
        echo "datew=$(date '+%Y-%V')" >> $GITHUB_OUTPUT
    - name: cache for pip
      uses: actions/cache@v4
      id: cache
      with:
        path: |
          ~/.cache/pip
          ~/.cache/torch
        key: ${{ runner.os }}-pip-${{ steps.pip-cache.outputs.datew }}
    - name: Install dependencies
      run: |
        python -m pip install --user --upgrade pip setuptools wheel twine
        # install the latest pytorch for testing
        # however, "pip install monai*.tar.gz" will build cpp/cuda with an isolated
        # fresh torch installation according to pyproject.toml
        python -m pip install torch>=1.9 torchvision
    - name: Check packages
      run: |
        pip uninstall monai
        pip list | grep -iv monai
        git fetch --depth=1 origin +refs/tags/*:refs/tags/*
        set -e

        # build tar.gz and wheel
        python setup.py check -m -s
        python setup.py sdist bdist_wheel
        python -m twine check dist/*
    - run: echo "pwd=$PWD" >> $GITHUB_OUTPUT
      id: root
    - run: echo "tmp_dir=$(mktemp -d)" >> $GITHUB_OUTPUT
      id: mktemp
    - name: Move packages
      run: |
        printf ${{ steps.root.outputs.pwd }}
        printf ${{ steps.mktemp.outputs.tmp_dir }}
        # move packages to a temp dir
        cp dist/monai* "${{ steps.mktemp.outputs.tmp_dir }}"
        rm -r build dist monai.egg-info
        cd "${{ steps.mktemp.outputs.tmp_dir }}"
        ls -al
    - name: Install wheel file
      working-directory: ${{ steps.mktemp.outputs.tmp_dir }}
      run: |
        # install from wheel
        python -m pip install monai*.whl
        python -c 'import monai; monai.config.print_config()' 2>&1 | grep -iv "unknown"
        python -c 'import monai; print(monai.__file__)'
        python -m pip uninstall -y monai
        rm monai*.whl
    - name: Install source archive
      working-directory: ${{ steps.mktemp.outputs.tmp_dir }}
      run: |
        # install from tar.gz
        name=$(ls *.tar.gz | head -n1)
        echo $name
        python -m pip install $name[all]
        python -c 'import monai; monai.config.print_config()' 2>&1 | grep -iv "unknown"
        python -c 'import monai; print(monai.__file__)'
    - name: Quick test
      working-directory: ${{ steps.mktemp.outputs.tmp_dir }}
      run: |
        # run min tests
        cp ${{ steps.root.outputs.pwd }}/requirements*.txt .
        cp -r ${{ steps.root.outputs.pwd }}/tests .
        ls -al
        python -m pip install -r requirements-dev.txt
        python -m unittest -v
      env:
        PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION: python  # https://github.com/Project-MONAI/MONAI/issues/4354

  build-docs:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Set up Python 3.8
      uses: actions/setup-python@v5
      with:
        python-version: '3.8'
    - name: cache weekly timestamp
      id: pip-cache
      run: |
        echo "datew=$(date '+%Y-%V')" >> $GITHUB_OUTPUT
    - name: cache for pip
      uses: actions/cache@v4
      id: cache
      with:
        path: |
          ~/.cache/pip
          ~/.cache/torch
        key: ${{ runner.os }}-pip-${{ steps.pip-cache.outputs.datew }}
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip wheel
        python -m pip install -r docs/requirements.txt
    - name: Make html
      run: |
        cd docs/
        make clean
        make html 2>&1 | tee tmp_log
        if [[ $(grep -c "ERROR:" tmp_log) != 0 ]]; then echo "found errors"; grep "ERROR:" tmp_log; exit 1; fi
        sed '/WARNING.*pip/d' tmp_log > tmp_log1; mv tmp_log1 tmp_log  # monai#7133
        if [[ $(grep -c "WARNING:" tmp_log) != 0 ]]; then echo "found warnings"; grep "WARNING:" tmp_log; exit 1; fi
      shell: bash


deploy

# Jenkinsfile.monai-postmerge
name: deploy

on:
  # full tests for all the important branches
  push:
    branches:
      - main
      - releasing/*
      - feature/*
      - dev

concurrency:
  # automatically cancel the previously triggered workflows when there's a newer version
  group: deploy-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

jobs:
  # caching of these jobs:
  #   - docker-py3-pip- (shared)
  #   - ubuntu 37 38 39 310-pip-
  #   - os-latest-pip (shared)
  coverage-py3:
    # if: github.repository == 'Project-MONAI/MONAI'
    if: ${{ false }}  # disable self-hosted job project-monai/monai#7039
    container:
      image: nvcr.io/nvidia/pytorch:22.04-py3
      options: --gpus all
    runs-on: [self-hosted, linux, x64, integration]
    steps:
    - uses: actions/checkout@v4
    - name: cache weekly timestamp
      id: pip-cache
      run: |
        echo "datew=$(date '+%Y-%V')" >> $GITHUB_OUTPUT
    - name: cache for pip
      if: ${{ startsWith(github.ref, 'refs/heads/dev') }}
      uses: actions/cache@v4
      id: cache
      with:
        path: |
          ~/.cache/pip
          ~/.cache/torch
        key: docker-py3-pip-${{ steps.pip-cache.outputs.datew }}
    - name: Install the dependencies
      run: |
        which python
        python -m pip install --upgrade pip wheel
        python -m pip install --upgrade torch torchvision
        python -m pip install -r requirements-dev.txt
    - name: Run unit tests report coverage
      run: |
        python -m pip list
        git config --global --add safe.directory /__w/MONAI/MONAI
        git clean -ffdx
        df -h
        # python -m pip cache info
        nvidia-smi
        export CUDA_VISIBLE_DEVICES=$(python -m tests.utils | tail -n 1)
        echo $CUDA_VISIBLE_DEVICES
        trap 'if pgrep python; then pkill python; fi;' ERR
        python -c $'import torch\na,b=torch.zeros(1,device="cuda:0"),torch.zeros(1,device="cuda:1");\nwhile True:print(a,b)' > /dev/null &
        python -c "import torch; print(torch.__version__); print('{} of GPUs available'.format(torch.cuda.device_count()))"
        python -c 'import torch; print(torch.rand(5, 3, device=torch.device("cuda:0")))'
        BUILD_MONAI=1 ./runtests.sh --build --coverage --unittests --disttests  # unit tests with coverage report
        BUILD_MONAI=1 ./runtests.sh --build --coverage --net  # integration tests with coverage report
        coverage xml --ignore-errors
        if pgrep python; then pkill python; fi
      shell: bash
    - name: Upload coverage
      uses: codecov/codecov-action@v4
      with:
        fail_ci_if_error: false
        files: ./coverage.xml

  test-py3x:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.8', '3.9', '3.10']
    steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v5
      with:
        python-version: ${{ matrix.python-version }}
    - name: cache weekly timestamp
      id: pip-cache
      run: |
        echo "datew=$(date '+%Y-%V')" >> $GITHUB_OUTPUT
    - name: cache for pip
      uses: actions/cache@v4
      id: cache
      with:
        path: |
          ~/.cache/pip
          ~/.cache/torch
        key: ${{ runner.os }}-${{ matrix.python-version }}-pip-${{ steps.pip-cache.outputs.datew }}
    - name: Install the dependencies
      run: |
        find  /opt/hostedtoolcache/* -maxdepth 0 ! -name 'Python' -exec rm -rf {} \;
        python -m pip install --upgrade pip wheel
        python -m pip install -r requirements-dev.txt
    - name: Run quick tests CPU ubuntu
      run: |
        python -m pip list
        python -c 'import torch; print(torch.__version__); print(torch.rand(5,3))'
        BUILD_MONAI=0 ./runtests.sh --build --quick --unittests
        BUILD_MONAI=1 ./runtests.sh --build --quick --min
        coverage xml --ignore-errors
    - name: Upload coverage
      uses: codecov/codecov-action@v4
      with:
        fail_ci_if_error: false
        files: ./coverage.xml

  install:  # pip install from github url, the default branch is dev
    runs-on: ubuntu-latest
    steps:
    - name: Set up Python 3.8
      uses: actions/setup-python@v5
      with:
        python-version: '3.8'
    - name: cache weekly timestamp
      id: pip-cache
      run: |
        echo "datew=$(date '+%Y-%V')" >> $GITHUB_OUTPUT
    - name: cache for pip
      uses: actions/cache@v4
      id: cache
      with:
        path: |
          ~/.cache/pip
          ~/.cache/torch
        key: ${{ runner.os }}-pip-${{ steps.pip-cache.outputs.datew }}
    - name: Install the default branch no build (dev branch only)
      if: github.ref == 'refs/heads/dev'
      run: |
        BUILD_MONAI=0 pip install git+https://github.com/Project-MONAI/MONAI#egg=MONAI
        python -c 'import monai; monai.config.print_config()'
        cd $(python -c 'import monai; import os; print(os.path.dirname(monai.__file__))')
        ls .
        pip uninstall -y monai
    - name: Install the default branch with build (dev branch only)
      if: github.ref == 'refs/heads/dev'
      run: |
        find  /opt/hostedtoolcache/* -maxdepth 0 ! -name 'Python' -exec rm -rf {} \;
        BUILD_MONAI=1 pip install git+https://github.com/Project-MONAI/MONAI#egg=MONAI
        python -c 'import monai; monai.config.print_config()'
    - name: Get the test cases (dev branch only)
      if: github.ref == 'refs/heads/dev'
      uses: actions/checkout@v4
      with:
        ref: dev
    - name: Quick test installed (dev branch only)
      if: github.ref == 'refs/heads/dev'
      run: |
        cd $GITHUB_WORKSPACE
        rm -rf monai/
        ls -al .
        python -m pip install -r requirements-min.txt
        python -m tests.min_tests
      env:
        QUICKTEST: True


release

name: release
# generating and testing package artefacts from the main branch

on:
  push:
    branches:
      - main
    tags:
      - '*'

jobs:
  packaging:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.9', '3.10', '3.11']
    steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v5
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install setuptools
      run: |
        python -m pip install --user --upgrade setuptools wheel
    - name: Build and test source archive and wheel file
      run: |
        find  /opt/hostedtoolcache/* -maxdepth 0 ! -name 'Python' -exec rm -rf {} \;
        git fetch --depth=1 origin +refs/tags/*:refs/tags/*
        root_dir=$PWD
        echo "$root_dir"
        set -e

        # build tar.gz and wheel
        python setup.py sdist bdist_wheel --build-number $(date +'%Y%m%d%H%M')
        tmp_dir=$(mktemp -d)
        cp dist/monai* "$tmp_dir"
        cd "$tmp_dir"
        ls -al

        # install from tar.gz
        python -m pip install monai*.tar.gz
        python -c 'import monai; monai.config.print_config()' 2>&1 | grep -iv "unknown"
        python -c 'import monai; print(monai.__file__)'
        python -m pip uninstall -y monai
        rm monai*.tar.gz

        # install from wheel
        python -m pip install monai*.whl
        python -c 'import monai; monai.config.print_config()' 2>&1 | grep -iv "unknown"
        python -c 'import monai; print(monai.__file__)'

        # clean up
        cd "$root_dir"
        rm -r "$tmp_dir"
        rm -rf monai/
        ls -al .
    - name: Quick test installed
      run: |
        python -m pip install -r requirements-min.txt
        python -m tests.min_tests
      env:
        QUICKTEST: True

    - if: matrix.python-version == '3.9' && startsWith(github.ref, 'refs/tags/')
      name: Upload artifacts
      uses: actions/upload-artifact@v4
      with:
        name: dist
        path: dist/

    - if: matrix.python-version == '3.9' && startsWith(github.ref, 'refs/tags/')
      name: Check artifacts
      run: |
        ls -al dist/
        rm dist/monai*.tar.gz
        ls -al dist/

    - if: matrix.python-version == '3.9' && startsWith(github.ref, 'refs/tags/')
      name: Publish to Test PyPI
      uses: pypa/gh-action-pypi-publish@release/v1
      with:
        password: ${{ secrets.TEST_PYPI }}
        repository-url: https://test.pypi.org/legacy/

  versioning:
    # compute versioning file from python setup.py
    # upload as artifact
    if: github.repository == 'Project-MONAI/MONAI'
    needs: packaging
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        # full history so that we can git describe
        with:
          fetch-depth: 0
      - name: Set up Python 3.9
        uses: actions/setup-python@v5
        with:
          python-version: '3.9'
      - shell: bash
        run: |
          find  /opt/hostedtoolcache/* -maxdepth 0 ! -name 'Python' -exec rm -rf {} \;
          git describe
          python -m pip install --user --upgrade setuptools wheel
          python setup.py build
          cat build/lib/monai/_version.py
      - name: Upload version
        uses: actions/upload-artifact@v4
        with:
          name: _version.py
          path: build/lib/monai/_version.py
      - name: Clean up directory
        shell: bash
        run: |
          ls -al
          rm -rf {*,.[^.]*}

  release_tag_docker:
    # if: github.repository == 'Project-MONAI/MONAI'
    if: ${{ false }}
    needs: versioning
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Download version
        uses: actions/download-artifact@v4
        with:
          name: _version.py
      - name: Set tag
        id: versioning
        run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
      - name: Check tag
        env:
          RELEASE_VERSION: ${{ steps.versioning.outputs.tag }}
        run: |
          echo "$RELEASE_VERSION"
          cat _version.py
      - if: startsWith(github.ref, 'refs/tags/')
        name: build with the tag
        env:
          RELEASE_VERSION: ${{ steps.versioning.outputs.tag }}
        shell: bash
        run: |
          find  /opt/hostedtoolcache/* -maxdepth 0 ! -name 'Python' -exec rm -rf {} \;
          # get tag info for versioning
          mv _version.py monai/
          # version checks
          target=" \"version\": \"$RELEASE_VERSION\""
          local=`grep "\"version\"" monai/_version.py`
          echo "$target"
          echo "$local"
          if [[ "$local" == "$target" ]]; then
            echo "matched version string"
          else
            echo "unmatched version string, please check the tagging branch."
            exit 1
          fi
          # remove flake package as it is not needed on hub.docker.com
          sed -i '/flake/d' requirements-dev.txt
          docker build -t projectmonai/monai:"$RELEASE_VERSION" -f Dockerfile .
          # distribute with a tag to hub.docker.com
          echo "${{ secrets.DOCKER_PW }}" | docker login -u projectmonai --password-stdin
          docker push projectmonai/monai:"$RELEASE_VERSION"
          docker logout


chatops

# triggering the workflows by commenting `/black` and `/integration-test`
name: chatops

# currently dispatches /black command to project-monai/monai-code-formatter
on:
  issue_comment:
    types: [created, edited]
jobs:
  dispatch_command:
    runs-on: ubuntu-latest
    steps:
      - name: dispatch
        uses: peter-evans/slash-command-dispatch@v4.0.0
        with:
          token: ${{ secrets.PR_MAINTAIN }}
          reaction-token: ${{ secrets.GITHUB_TOKEN }}
          reactions: false
          config: >
            [
              {
                "command": "black",
                "permission": "none",
                "issue_type": "pull-request",
                "allow_edits": true,
                "repository": "project-monai/monai-code-formatter"
              },
              {
                "command": "integration-test",
                "permission": "none",
                "issue_type": "pull-request",
                "allow_edits": true
              }
            ]


integration

# manually trigger integration with the latest pytorch
name: integration

on:
  repository_dispatch:
    type: [integration-test-command]

jobs:
  integration-auto3dseg:
    container:
      image: nvcr.io/nvidia/pytorch:22.04-py3  # CUDA 11.6 py38
      options: --gpus "device=1" --ipc host  # shm-size 4g works fine
    runs-on: [self-hosted, linux, x64, command]
    steps:
    # checkout the pull request branch
    - uses: actions/checkout@v4
      with:
        token: ${{ secrets.PR_MAINTAIN }}
        repository: ${{ github.event.client_payload.pull_request.head.repo.full_name }}
        ref: ${{ github.event.client_payload.pull_request.head.ref }}
    - name: cache weekly timestamp
      id: pip-cache
      run: echo "datew=$(date '+%Y-%V')" >> $GITHUB_OUTPUT
    - name: cache for pip
      uses: actions/cache@v4
      id: cache
      with:
        path: |
          ~/.cache/pip
          ~/.cache/torch
        key: docker-py3-pip-${{ steps.pip-cache.outputs.datew }}
    - name: Install the dependencies
      run: |
        pwd && git log -1 && which python
        python -m pip install --upgrade pip wheel
        pip uninstall -y monai
        pip uninstall -y monai
        pip uninstall -y monai-weekly
        pip uninstall -y monai-weekly
        python -m pip install --upgrade torch torchvision torchaudio torchtext
        python -m pip install -r requirements-dev.txt
        rm -rf /github/home/.cache/torch/hub/mmars/
    - name: Clean directory
      run: |
        python -m pip list
        git config --global --add safe.directory /__w/MONAI/MONAI
        git clean -ffdx && git reset --hard HEAD
        nvidia-smi
        export CUDA_VISIBLE_DEVICES=$(python -m tests.utils -c 1 | tail -n 1)
        echo $CUDA_VISIBLE_DEVICES
        python -c "import torch; print(torch.__version__); print('{} of GPUs available'.format(torch.cuda.device_count()))"
        python -c 'import torch; print(torch.rand(5,3, device=torch.device("cuda:0")))'

    - name: Auto3dseg tag algo
      shell: bash
      env:
        BUILD_MONAI: 0
      run: |
        pwd && git log -1 && which python
        ./runtests.sh -b
        export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python
        python -m tests.test_auto3dseg_bundlegen
        python -m tests.test_auto3dseg_ensemble
        python -m tests.test_auto3dseg_hpo
        python -m tests.test_integration_autorunner
        python -m tests.test_integration_gpu_customization
    - name: Integration tests
      shell: bash
      env:
        BUILD_MONAI: 1
      run: ./runtests.sh --build --net

    - name: Add reaction
      uses: peter-evans/create-or-update-comment@v4
      with:
        token: ${{ secrets.PR_MAINTAIN }}
        repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
        comment-id: ${{ github.event.client_payload.github.payload.comment.id }}
        reactions: rocket

  integration-unit:
    container:
      image: nvcr.io/nvidia/pytorch:22.04-py3  # CUDA 11.6 py38
      options: --gpus "device=2" --ipc host  # shm-size 4g works fine
    runs-on: [self-hosted, linux, x64, command1]
    steps:
    # checkout the pull request branch
    - uses: actions/checkout@v4
      with:
        token: ${{ secrets.PR_MAINTAIN }}
        repository: ${{ github.event.client_payload.pull_request.head.repo.full_name }}
        ref: ${{ github.event.client_payload.pull_request.head.ref }}
    - name: cache weekly timestamp
      id: pip-cache
      run: echo "datew=$(date '+%Y-%V')" >> $GITHUB_OUTPUT
    - name: cache for pip
      uses: actions/cache@v4
      id: cache
      with:
        path: |
          ~/.cache/pip
          ~/.cache/torch
        key: docker-py3-pip-${{ steps.pip-cache.outputs.datew }}
    - name: Install the dependencies
      run: |
        pwd && git log -1 && which python
        python -m pip install --upgrade pip wheel
        pip uninstall -y monai
        pip uninstall -y monai
        pip uninstall -y monai-weekly
        pip uninstall -y monai-weekly
        python -m pip install --upgrade torch torchvision torchaudio torchtext
        python -m pip install -r requirements-dev.txt
        rm -rf /github/home/.cache/torch/hub/mmars/
    - name: Clean directory
      run: |
        python -m pip list
        git config --global --add safe.directory /__w/MONAI/MONAI
        git clean -ffdx && git reset --hard HEAD
        nvidia-smi
        export CUDA_VISIBLE_DEVICES=$(python -m tests.utils -c 1 | tail -n 1)
        echo $CUDA_VISIBLE_DEVICES
        python -c "import torch; print(torch.__version__); print('{} of GPUs available'.format(torch.cuda.device_count()))"
        python -c 'import torch; print(torch.rand(5,3, device=torch.device("cuda:0")))'

    - name: Auto3dseg latest algo
      shell: bash
      env:
        BUILD_MONAI: 0
      run: |
        pwd
        cd ../
        rm -rf research-contributions
        rm -rf algorithm_templates
        git clone --depth 1 --branch main --single-branch https://github.com/Project-MONAI/research-contributions.git
        ls research-contributions/
        cp -r research-contributions/auto3dseg/algorithm_templates MONAI/
        cd research-contributions && git log -1 && cd ../MONAI
        pwd
        ls -ll
        export OMP_NUM_THREADS=4
        export MKL_NUM_THREADS=4
        export MONAI_TESTING_ALGO_TEMPLATE=algorithm_templates
        pwd && git log -1 && which python
        ./runtests.sh -b
        export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python
        python -m tests.test_auto3dseg_ensemble
        python -m tests.test_auto3dseg_hpo
        python -m tests.test_integration_autorunner
        python -m tests.test_integration_gpu_customization

    - name: Add reaction
      uses: peter-evans/create-or-update-comment@v4
      with:
        token: ${{ secrets.PR_MAINTAIN }}
        repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
        comment-id: ${{ github.event.client_payload.github.payload.comment.id }}
        reactions: +1


weekly-preview

name: weekly-preview

on:
  schedule:
  - cron: "0 2 * * 0"  # 02:00 of every Sunday

jobs:
  packaging:
    if: github.repository == 'Project-MONAI/MONAI'
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
      with:
        ref: dev
        fetch-depth: 0
    - name: Set up Python 3.9
      uses: actions/setup-python@v5
      with:
        python-version: '3.9'
    - name: Install setuptools
      run: |
        python -m pip install --user --upgrade setuptools wheel
    - name: Build distribution
      run: |
        export HEAD_COMMIT_ID=$(git rev-parse HEAD)
        sed -i 's/name\ =\ monai$/name\ =\ monai-weekly/g' setup.cfg
        echo "__commit_id__ = \"$HEAD_COMMIT_ID\"" >> monai/__init__.py
        git diff setup.cfg monai/__init__.py
        git config user.name "CI Builder"
        git config user.email "monai.contact@gmail.com"
        git add setup.cfg monai/__init__.py
        git commit -m "Weekly build at $HEAD_COMMIT_ID"
        export YEAR_WEEK=$(date +'%y%U')
        echo "Year week for tag is ${YEAR_WEEK}"
        if ! [[ $YEAR_WEEK =~ ^[0-9]{4}$ ]] ; then echo "Wrong 'year week' format.  Should be 4 digits."; exit 1 ; fi
        git tag "1.4.dev${YEAR_WEEK}"
        git log -1
        git tag --list
        python setup.py sdist bdist_wheel

    - name: Publish to PyPI
      uses: pypa/gh-action-pypi-publish@release/v1
      with:
        user: __token__
        password: ${{ secrets.PYPI_TOKEN }}


docker

# this is the docker image releasing pipeline, pushing to https://hub.docker.com/r/projectmonai/monai
name: docker
# versioning: compute a static version file
# local_docker: use the version file to build docker images
# docker_test_latest: test the latest internal docker image (has flake)
# docker_test_dockerhub: test the latest dockerhub release (no flake)
on:
  # dev only docker deployment and quick tests
  push:
    branches:
      - dev
  # Allows you to run this workflow manually from the Actions tab
  # This is to trigger building/testing docker image from dev only.
  workflow_dispatch:

jobs:
  versioning_dev:
    # compute versioning file from python setup.py
    # upload as artifact
    # if: github.repository == 'Project-MONAI/MONAI'
    if: ${{ false }}  # disable docker build job  project-monai/monai#7450
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        # full history so that we can git describe
        with:
          ref: dev
          fetch-depth: 0
      - name: Set up Python 3.9
        uses: actions/setup-python@v5
        with:
          python-version: '3.9'
      - shell: bash
        run: |
          git describe
          python -m pip install -U pip wheel setuptools
          python setup.py build
          cat build/lib/monai/_version.py
      - name: Upload version
        uses: actions/upload-artifact@v4
        with:
          name: _version.py
          path: build/lib/monai/_version.py
      - name: Clean up directory
        shell: bash
        run: |
          ls -al
          rm -rf {*,.[^.]*}

  docker_build_dev:
    # if: github.repository == 'Project-MONAI/MONAI'
    if: ${{ false }}  # disable docker build job  project-monai/monai#7450
    needs: versioning_dev
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
      with:
        ref: dev
    - name: Download version
      uses: actions/download-artifact@v4
      with:
        name: _version.py
    - name: docker_build
      shell: bash
      run: |
        find /opt/hostedtoolcache/* -maxdepth 0 ! -name 'Python' -exec rm -rf {} \;
        docker --version
        # get tag info for versioning
        cat _version.py
        mv _version.py monai/

        # build "latest": remove flake package as it is not needed on hub.docker.com
        sed -i '/flake/d' requirements-dev.txt
        docker build -t projectmonai/monai:latest -f Dockerfile .

        # distribute as always w/ tag "latest" to hub.docker.com
        echo "${{ secrets.DOCKER_PW }}" | docker login -u projectmonai --password-stdin

        docker push projectmonai/monai:latest
        docker logout
        docker image prune -f

  docker_test_dockerhub:
    # if: github.repository == 'Project-MONAI/MONAI'
    if: ${{ false }}  # disable self-hosted job  project-monai/monai#7039
    needs: docker_build_dev
    container:
      image: docker://projectmonai/monai:latest
      options: "--shm-size=4g --ipc=host"
    runs-on: [self-hosted, linux, X64, docker]
    steps:
    - name: Import
      run: |
        export OMP_NUM_THREADS=4 MKL_NUM_THREADS=4 CUDA_VISIBLE_DEVICES=  # cpu-only
        python -c 'import monai; monai.config.print_debug_info()'
        cd /opt/monai
        ls -al
        ngc --version
        ./runtests.sh --min
      shell: bash
      env:
        QUICKTEST: True


Blossom-CI

# A workflow to trigger ci on hybrid infra (github + self hosted runner)
name: Blossom-CI
on:
  issue_comment:
    types: [created]
  workflow_dispatch:
      inputs:
          platform:
            description: 'runs-on argument'
            required: false
          args:
            description: 'argument'
            required: false

permissions:
  actions: write
  checks: write
  contents: write
  issues: write
  pull-requests: write
  repository-projects: write
  statuses: write

jobs:
  Authorization:
    name: Authorization
    runs-on: blossom
    outputs:
      args: ${{ env.args }}

    # This job only runs for pull request comments
    if: |
      github.event.comment.body == '/build' &&
      (
        github.actor == 'Nic-Ma' ||
        github.actor == 'wyli' ||
        github.actor == 'pxLi' ||
        github.actor == 'YanxuanLiu' ||
        github.actor == 'KumoLiu'
      )
    steps:
      - name: Check if comment is issued by authorized person
        run: blossom-ci
        env:
          OPERATION: 'AUTH'
          REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          REPO_KEY_DATA: ${{ secrets.BLOSSOM_KEY }}

  Vulnerability-scan:
    name: Vulnerability scan
    needs: [Authorization]
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          repository: ${{ fromJson(needs.Authorization.outputs.args).repo }}
          ref: ${{ fromJson(needs.Authorization.outputs.args).ref }}
          lfs: 'true'

      # repo specific steps
      #- name: Setup java
      #  uses: actions/setup-java@v1
      #  with:
      #    java-version: '1.8'

      # add blackduck properties https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/631308372/Methods+for+Configuring+Analysis#Using-a-configuration-file
      #- name: Setup blackduck properties
      #  run: |
      #       PROJECTS=$(mvn -am dependency:tree | grep maven-dependency-plugin | awk '{ out="com.nvidia:"$(NF-1);print out }' | grep rapids | xargs | sed -e 's/ /,/g')
      #       echo detect.maven.build.command="-pl=$PROJECTS -am" >> application.properties
      #       echo detect.maven.included.scopes=compile >> application.properties
      - name: Setup blackduck properties
        run: |
             echo detect.excluded.detector.types=PIP >> application.properties

      - name: Run blossom action
        uses: NVIDIA/blossom-action@main
        env:
          REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          REPO_KEY_DATA: ${{ secrets.BLOSSOM_KEY }}
        with:
          args1: ${{ fromJson(needs.Authorization.outputs.args).args1 }}
          args2: ${{ fromJson(needs.Authorization.outputs.args).args2 }}
          args3: ${{ fromJson(needs.Authorization.outputs.args).args3 }}

  Job-trigger:
    name: Start ci job
    needs: [Vulnerability-scan]
    runs-on: blossom
    steps:
      - name: Start ci job
        run: blossom-ci
        env:
          OPERATION: 'START-CI-JOB'
          CI_SERVER: ${{ secrets.CI_SERVER }}
          REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  Post-processing:
    name: Post processing
    runs-on: blossom
    if : github.event_name == 'workflow_dispatch'
    steps:
      - name: Start post processing
        run: blossom-ci
        env:
          OPERATION: 'POST-PROCESSING'
          CI_SERVER: ${{ secrets.CI_SERVER }}
          REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}