Docker Image CI

name: Docker Image CI

on:
  push:
    branches: [ master ]
    tags: [ '*.*.*' ]
  pull_request:
    branches: [ master ]
  workflow_dispatch:
    inputs:
      versionTag:
        description: 'Version tag to push to Docker Hub (lowercase, alphanumeric)'
        required: true
        type: string

jobs:

  build_test_push:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      id-token: write
    strategy:
      fail-fast: false # So that remaining jobs don't instantly quit if one fails (e.g, CPU/ROCm don't upload if CUDA just fails to push to ghcr...)
      matrix:
        include: # Platform locates Dockerfile ("Dockerfile-{PLATFORM}"), docker tag has to be all lowercase alphanumeric for mysterious docker reasons
          - platform: CUDA12.1
            dockertag: cuda121
          - platform: CUDA11.8
            dockertag: cuda118
          - platform: CPU
            dockertag: cpu
          # - platform: ROCm
          #   dockertag: rocm

    steps:
    - name: Check out the repository
      uses: actions/checkout@v2
      with:
        lfs: true
        submodules: 'recursive'

    - name: Log in to Docker Hub (docker.io)
      uses: docker/login-action@v2
      if: github.event_name != 'pull_request'
      with:
        username: ${{ secrets.DOCKER_HUB_USER }} # These two fields need to be set on GitHub under Secrets.
        password: ${{ secrets.DOCKER_HUB_TOKEN }} # Recommend using a revokable token here.

    - name: Docker prune to save space # If you switch to self-hosted runners, this should be removed.
      run: echo y | docker system prune -a

    # Below steps are for GitHub Packages integration, metadata and signing
    # See https://github.com/mlcommons/GaNDLF/new/master?filename=.github%2Fworkflows%2Fdocker-publish.yml&workflow_template=docker-publish

    # Install the cosign tool except on PR
    # https://github.com/sigstore/cosign-installer
    - name: Install cosign
      uses: sigstore/cosign-installer@v3.2.0

    - name: Log into GitHub Packages registry (ghcr.io)
      if: github.event_name != 'pull_request'
      uses: docker/login-action@v2
      with:
        registry: ghcr.io
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}

    # Extract metadata (tags, labels) for Docker
    # https://github.com/docker/metadata-action
    - name: Extract Docker metadata
      id: meta
      uses: docker/metadata-action@v3
      with:
        images: docker.io/mlcommons/gandlf, ghcr.io/mlcommons/gandlf # Push to both registries
        flavor: | # Handle prefixing and "latest" generation -- use "tags" property to specify events/tags further
          latest=true
          suffix=-${{ matrix.dockertag }},onlatest=true
        tags: |
          type=semver,pattern={{version}}
          type=ref,event=branch
          type=ref,event=pr
          type=ref,event=tag

    # Build Docker Image (but don't push yet -- wait for the test step first).
    # https://github.com/docker/build-push-action
    - name: Build Docker images
      id: build
      uses: docker/build-push-action@v2
      with:
        context: .
        file: ./Dockerfile-${{ matrix.platform }}
        push: false
        load: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}

    # Run the image from the base entrypoint as a test
    - name: Test container with entrypoint
      # Run a tag we generated from the metadata extraction above -- they're all the same image, but echo it regardless just so we know.
      run: echo "Running docker.io/mlcommons/gandlf:latest-${{ matrix.dockertag }} ..." && docker run --rm docker.io/mlcommons/gandlf:latest-${{ matrix.dockertag }}

    # Push Docker image with Buildx (but don't push on PR)
    # https://github.com/docker/build-push-action
    # This won't re-build the images fully or anything, they should already exist from the build step and use the cache.
    - name: Upload to Docker Hub (docker.io) and GitHub Packages (ghcr.io)
      id: upload
      if: github.event_name != 'pull_request'
      uses: docker/build-push-action@v2
      with:
        context: .
        file: ./Dockerfile-${{ matrix.platform }}
        push: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}

    # Below is for signing images (keyless) with cosign. But this adds confusing sha256-digest.sig tags to the container registry.
    # Leave this commented if container signing is not required.
    # # Sign the resulting Docker image digest except on PRs.
    # # Uses cosign keyless signing: https://github.com/sigstore/cosign/blob/main/KEYLESS.md
    # # This will only write to the public Rekor transparency log when the Docker
    # # repository is public to avoid leaking data.  If you would like to publish
    # # transparency data even for private images, pass --force to cosign below.
    # # https://github.com/sigstore/cosign
    #- name: Sign published Docker image (ghcr.io)
    #  if: ${{ github.event_name != 'pull_request' }}
    #  env:
    #    COSIGN_EXPERIMENTAL: "true"
    #  # This step uses the identity token to provision an ephemeral certificate
    #  # against the sigstore community Fulcio instance.
    #  run: cosign sign ghcr.io/cbica/gandlf@${{ steps.upload.outputs.digest }}


docs-ci

name: docs-ci
on:
  push:
    branches:
      - master

permissions:
  contents: write
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-python@v4
        with:
          python-version: 3.x
      - run: pip install -r docs/requirements.txt
      - run: git config --global user.email "github-actions[bot]@users.noreply.github.com"
      - run: git config --global user.name "github-actions[bot]"
      - run: mkdocs gh-deploy --force


Upload Python Package

# This workflow will upload a Python Package using Twine when a release is created
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries

# 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.

name: Upload Python Package

on:
  release:
    types: [published]
  workflow_dispatch:

permissions:
  contents: read

jobs:
  deploy:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: 3.9
    # This second step is unnecessary but highly recommended because
    # It will cache database and saves time re-downloading it if database isn't stale.
    - name: Cache pip
      uses: actions/cache@v3
      with:
        path: ~/.cache/pip
        key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }}
        restore-keys: |
          ${{ runner.os }}-pip-
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install scikit-build
        pip install -e .
        pip install build
    - name: Build package
      run: python -m build
    - name: Publish package
      uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
      with:
        user: __token__
        password: ${{ secrets.PYPI_API_TOKEN }}


MLCube-Test

# This workflow will test gandlf_deploy for model and metrics MLCubes

name: MLCube-Test

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  test-deploy:

    runs-on: ubuntu-latest

    steps:
    - name: Free space
      run: |
        df -h
        sudo rm -rf /opt/ghc
        sudo rm -rf "/usr/local/share/boost"
        sudo rm -rf "$AGENT_TOOLSDIRECTORY"
        sudo rm -rf "$ANDROID_SDK_ROOT"
        df -h
    - name: Checkout
      uses: actions/checkout@v3

    # Use changed-files-specific action to collect file changes.
    # The following commented condition applied to a step will run that step only if non-docs files have changed.
    # It should be applied to all functionality-related steps.
    # if: steps.changed-files-specific.outputs.only_modified == 'false'
    - name: Detect and screen file changes
      id: changed-files-specific
      uses: tj-actions/changed-files@v41
      with:
          files: |
            .github/*.md
            .github/ISSUE_TEMPLATE/*.md
            .github/workflows/devcontainer.yml
            .github/workflows/docker-image.yml
            .devcontainer/**
            docs/**
            mlcube/**
            *.md
            LICENSE
            Dockerfile-*

    - name: Summarize docs and non-docs modifications
      run: |
        echo "List of docs files that have changed: ${{ steps.changed-files-specific.outputs.all_modified_files }}"
        echo "Changed non-docs files: ${{ steps.changed-files-specific.outputs.other_modified_files }}"

    # This second step is unnecessary but highly recommended because
    # It will cache database and saves time re-downloading it if database isn't stale.
    - name: Cache pip
      uses: actions/cache@v3
      with:
        path: ~/.cache/pip
        key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }}
        restore-keys: |
          ${{ runner.os }}-pip-
    - name: Set up Python 3.9
      if: steps.changed-files-specific.outputs.only_modified == 'false' # Run on any non-docs change
      uses: actions/setup-python@v4
      with:
        python-version: 3.9
    - name: Install dependencies and package
      if: steps.changed-files-specific.outputs.only_modified == 'false' # Run on any non-docs change
      run: |
        sudo apt-get update
        sudo apt-get install libvips libvips-tools -y
        python -m pip install --upgrade pip
        python -m pip install wheel
        python -m pip install openvino-dev==2023.0.1 mlcube_docker
        pip install torch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 --index-url https://download.pytorch.org/whl/cpu
        pip install -e .
    - name: Run mlcube deploy tests
      working-directory: ./testing
      if: steps.changed-files-specific.outputs.only_modified == 'false' # Run on any non-docs change
      run: |
        sh test_deploy.sh


OpenFL-Test

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

name: OpenFL-Test

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  openfl-test:

    runs-on: ubuntu-latest

    steps:
    - name: Free space
      run: |
        df -h
        sudo rm -rf /opt/ghc
        sudo rm -rf "/usr/local/share/boost"
        sudo rm -rf "$AGENT_TOOLSDIRECTORY"
        sudo rm -rf "$ANDROID_SDK_ROOT"
        df -h
    - name: Checkout
      uses: actions/checkout@v3

    # Use changed-files-specific action to collect file changes.
    # The following commented condition applied to a step will run that step only if non-docs files have changed.
    # It should be applied to all functionality-related steps.
    # if: steps.changed-files-specific.outputs.only_modified == 'false'
    - name: Detect and screen file changes
      id: changed-files-specific
      uses: tj-actions/changed-files@v41
      with:
          files: |
            .github/*.md
            .github/ISSUE_TEMPLATE/*.md
            .github/workflows/devcontainer.yml
            .github/workflows/docker-image.yml
            .devcontainer/**
            docs/**
            mlcube/**
            *.md
            LICENSE
            Dockerfile-*

    - name: Summarize docs and non-docs modifications
      run: |
        echo "List of docs files that have changed: ${{ steps.changed-files-specific.outputs.all_modified_files }}"
        echo "Changed non-docs files: ${{ steps.changed-files-specific.outputs.other_modified_files }}"

    # This second step is unnecessary but highly recommended because
    # It will cache database and saves time re-downloading it if database isn't stale.
    - name: Cache pip
      uses: actions/cache@v3
      with:
        path: ~/.cache/pip
        key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }}
        restore-keys: |
          ${{ runner.os }}-pip-
    - name: Set up Python 3.9
      if: steps.changed-files-specific.outputs.only_modified == 'false' # Run on any non-docs change
      uses: actions/setup-python@v4
      with:
        python-version: 3.9
    - name: Install dependencies and package
      if: steps.changed-files-specific.outputs.only_modified == 'false' # Run on any non-docs change
      run: |
        sudo apt-get update
        sudo apt-get install libvips libvips-tools -y
        python -m pip install --upgrade pip
        python -m pip install wheel
        pip install torch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 --index-url https://download.pytorch.org/whl/cpu
        pip install -e .
    - name: Run generic unit tests to download data and construct CSVs
      if: steps.changed-files-specific.outputs.only_modified == 'false' # Run on any non-docs change
      run: |
        pytest --cov=. --cov-report=xml -k "prepare_data_for_ci"
    # openfl tests start here
    - name: Run OpenFL tests
      if: steps.changed-files-specific.outputs.only_modified == 'false' # Run on any non-docs change
      run: |
        echo "Removing onnx because of protobuf version conflict"
        pip uninstall onnx -y
        echo "Installing OpenFL"
        git clone --depth=1 https://github.com/securefederatedai/openfl.git
        cd openfl
        git fetch --tags
        # echo "Checkout the latest OpenFL tag"
        # latestTag=$(git describe --tags "$(git rev-list --tags --max-count=1)")
        # git checkout $latestTag
        # sed -i -e 's/protobuf==3.19.6/protobuf/g' setup.py ## this should NOT be there
        pip install -e .
        cd ..
        echo "Copying files to appropriate directories and updated headers"
        head -n 1 testing/data/train_2d_rad_segmentation.csv > /home/runner/work/GaNDLF/GaNDLF/openfl/valid.csv
        tail -n +9 testing/data/train_2d_rad_segmentation.csv >> /home/runner/work/GaNDLF/GaNDLF/openfl/valid.csv
        head -n 8 testing/data/train_2d_rad_segmentation.csv > /home/runner/work/GaNDLF/GaNDLF/openfl/train.csv
        sed -i 's/# n_channels: 3/num_channels: 3/g' testing/config_segmentation.yaml
        config_to_use=$(pwd)/testing/config_segmentation.yaml
        cd openfl
        python -m tests.github.test_gandlf --template gandlf_seg_test --fed_workspace aggregator --col1 one --col2 two --rounds-to-train 1 --gandlf_config $config_to_use


OSSAR

# This workflow integrates a collection of open source static analysis tools
# with GitHub code scanning. For documentation, or to provide feedback, visit
# https://github.com/github/ossar-action
name: OSSAR

on:
  push:
    branches: [ master ]
  pull_request:
    # The branches below must be a subset of the branches above
    branches: [ master ]
  schedule:
    - cron: '32 20 * * 3'

jobs:
  OSSAR-Scan:
    # OSSAR runs on windows-latest.
    # ubuntu-latest and macos-latest support coming soon
    runs-on: windows-latest

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

    # Ensure a compatible version of dotnet is installed.
    # The [Microsoft Security Code Analysis CLI](https://aka.ms/mscadocs) is built with dotnet v3.1.201.
    # A version greater than or equal to v3.1.201 of dotnet must be installed on the agent in order to run this action.
    # GitHub hosted runners already have a compatible version of dotnet installed and this step may be skipped.
    # For self-hosted runners, ensure dotnet version 3.1.201 or later is installed by including this action:
    # - name: Install .NET
    #   uses: actions/setup-dotnet@v1
    #   with:
    #     dotnet-version: '3.1.x'

      # Run open source static analysis tools
    - name: Run OSSAR
      uses: github/ossar-action@v1
      id: ossar

      # Upload results to the Security tab
    - name: Upload OSSAR results
      uses: github/codeql-action/upload-sarif@v1
      with:
        sarif_file: ${{ steps.ossar.outputs.sarifFile }}


Nightly Prerelease Publishing

# This workflow will upload a Python Package using Twine when a release is created
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries

# 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.

name: Nightly Prerelease Publishing

on:
  workflow_dispatch:  # Allow manual triggers
  schedule:
    # Runs every day at 3:07am UTC.
    - cron: '7 3 * * *'

permissions:
  contents: read

jobs:
  deploy:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
      with:
          ref: master

    # This second step is unnecessary but highly recommended because
    # It will cache database and saves time re-downloading it if database isn't stale.
    - name: Cache pip
      uses: actions/cache@v3
      with:
        path: ~/.cache/pip
        key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }}
        restore-keys: |
          ${{ runner.os }}-pip-
    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: 3.9
    - name: Check dev version
      run: | # Get current canonical version, append current date as an identifier
        currentVer=$(python -c "from GANDLF import version; print(version)")
        if [[ $currentVer == *"dev"* ]]; then
          echo "publish_nightly=true" >> $GITHUB_ENV
        else
          echo "publish_nightly=false" >> $GITHUB_ENV
        fi
    - name: Install dependencies
      if: env.publish_nightly
      run: |
        python -m pip install --upgrade pip
        pip install scikit-build
        pip install -e .
        pip install build
    - name: Annotate version
      if: env.publish_nightly
      run: | # Get current canonical version, append current date as an identifier
        currentVer=$(python -c "from GANDLF import version; print(version)")
        datestampnow=$(date +'%Y%m%d')
        echo __version__ = \"$currentVer$datestampnow\" > ./GANDLF/version.py

    - name: Build package
      if: env.publish_nightly
      run: python -m build
    - name: Publish package
      if: env.publish_nightly
      uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
      with:
        user: __token__
        password: ${{ secrets.PYPI_API_TOKEN }}


Install across python versions

name: Install across python versions

on: [push, pull_request]

jobs:
  pyversion_install:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.9", "3.10", "3.11"]
    steps:
      - uses: actions/checkout@v2

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

      - name: Install dependencies
        run: |
          # all good if installation finishes
          python -m pip install -e .


CI-PyTest

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

name: CI-PyTest

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  full-test:

    runs-on: ubuntu-latest

    steps:
    - name: Free space
      run: |
        df -h
        sudo rm -rf /opt/ghc
        sudo rm -rf "/usr/local/share/boost"
        sudo rm -rf "$AGENT_TOOLSDIRECTORY"
        sudo rm -rf "$ANDROID_SDK_ROOT"
        df -h
    - name: Checkout
      uses: actions/checkout@v3

    # Use changed-files-specific action to collect file changes.
    # The following commented condition applied to a step will run that step only if non-docs files have changed.
    # It should be applied to all functionality-related steps.
    # if: steps.changed-files-specific.outputs.only_modified == 'false'
    - name: Detect and screen file changes
      id: changed-files-specific
      uses: tj-actions/changed-files@v41
      with:
          files: |
            .github/*.md
            .github/ISSUE_TEMPLATE/*.md
            .github/workflows/devcontainer.yml
            .github/workflows/docker-image.yml
            .devcontainer/**
            docs/**
            mlcube/**
            *.md
            LICENSE
            Dockerfile-*

    - name: Summarize docs and non-docs modifications
      run: |
        echo "List of docs files that have changed: ${{ steps.changed-files-specific.outputs.all_modified_files }}"
        echo "Changed non-docs files: ${{ steps.changed-files-specific.outputs.other_modified_files }}"

    # This second step is unnecessary but highly recommended because
    # It will cache database and saves time re-downloading it if database isn't stale.
    - name: Cache pip
      uses: actions/cache@v3
      with:
        path: ~/.cache/pip
        key: ${{ runner.os }}-pip-${{ hashFiles('**/setup.py') }}
        restore-keys: |
          ${{ runner.os }}-pip-
    - name: Set up Python 3.9
      if: steps.changed-files-specific.outputs.only_modified == 'false' # Run on any non-docs change
      uses: actions/setup-python@v4
      with:
        python-version: 3.9
    - name: Install dependencies and package
      if: steps.changed-files-specific.outputs.only_modified == 'false' # Run on any non-docs change
      run: |
        sudo apt-get update
        sudo apt-get install libvips libvips-tools -y
        python -m pip install --upgrade pip
        python -m pip install wheel
        python -m pip install openvino-dev==2023.0.1 mlcube_docker
        pip install torch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 --index-url https://download.pytorch.org/whl/cpu
        pip install -e .
    - name: Run generic unit tests
      if: steps.changed-files-specific.outputs.only_modified == 'false' # Run on any non-docs change
      run: |
        pytest --cov=. --cov-report=xml -k "generic"
    - name: Run classification unit tests with histology
      if: steps.changed-files-specific.outputs.only_modified == 'false' # Run on any non-docs change
      run: |
        pytest --cov=. --cov-report=xml --cov-append -k "classification and histology"
    - name: Run classification unit tests
      if: steps.changed-files-specific.outputs.only_modified == 'false' # Run on any non-docs change
      run: |
        pytest --cov=. --cov-report=xml --cov-append -k "classification and not histology"
    - name: Run segmentation unit tests
      if: steps.changed-files-specific.outputs.only_modified == 'false' # Run on any non-docs change
      run: |
        pytest --cov=. --cov-report=xml --cov-append -k "segmentation and not transunet"
    - name: Run regression unit tests
      if: steps.changed-files-specific.outputs.only_modified == 'false' # Run on any non-docs change
      run: |
        pytest --cov=. --cov-report=xml --cov-append -k "regression"
    - name: Run transunet unit tests
      if: steps.changed-files-specific.outputs.only_modified == 'false' # Run on any non-docs change
      run: |
        pytest --cov=. --cov-report=xml --cov-append -k "transunet"

    - name: Upload coverage
      if: steps.changed-files-specific.outputs.only_modified == 'false' # Run on any non-docs change
      uses: codecov/codecov-action@v1
      with:
        token: ${{ secrets.CODECOV_TOKEN }}
        file: ./coverage.xml
        flags: unittests


Mark stale issues and pull requests

# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
#
# You can adjust the behavior by modifying this file.
# For more information, see:
# https://github.com/actions/stale
name: Mark stale issues and pull requests

on:
  schedule:
  - cron: '45 19 * * *'

jobs:
  stale:

    runs-on: ubuntu-latest
    permissions:
      issues: write
      pull-requests: write

    steps:
    - uses: actions/stale@v3
      with:
        repo-token: ${{ secrets.GITHUB_TOKEN }}
        stale-issue-message: 'Stale issue message'
        stale-pr-message: 'Stale pull request message'
        stale-issue-label: 'no-issue-activity'
        stale-pr-label: 'no-pr-activity'


DirectX

name: "DirectX"

# Test that DirectX 11 and 12 build work on Windows
on:
  workflow_dispatch:
  pull_request:
  push:

jobs:
  build:
    name: DirectX
    runs-on: windows-latest
    strategy:
      fail-fast: false
      matrix:
        directx_version: [11, 12]

    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true

      - name: Build
        shell: bash
        run: |
          mkdir build
          cd build
          if [ "${{ matrix.directx_version }}" = "11" ]; then
            cmake .. -DHELLOIMGUI_USE_SDL_DIRECTX11=ON  -DCMAKE_BUILD_TYPE=Release;
          fi
          if [ "${{ matrix.directx_version }}" = "12" ]; then
            cmake .. -DHELLOIMGUI_USE_SDL_DIRECTX12=ON  -DCMAKE_BUILD_TYPE=Release;
          fi
          cmake --build . -j 3


Metal

name: "Metal"

# Test that Metal build works on Apple
on:
  workflow_dispatch:
  pull_request:
  push:

jobs:
  build:
    name: Metal
    runs-on: macos-latest
    strategy:
      fail-fast: false

    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true

      - name: Install glfw2 and sdl2
        shell: bash
        run: |
          brew install glfw sdl2

      - name: Build and install
        shell: bash
        run: |
          mkdir build
          cd build
          cmake .. -DHELLOIMGUI_USE_GLFW_METAL=ON -DHELLOIMGUI_USE_SDL_METAL=ON -DCMAKE_BUILD_TYPE=Release
          cmake --build . -j 3


Vulkan

name: "Vulkan"

# Test that Vulkan builds work
on:
  workflow_dispatch:
  pull_request:
  push:

# https://sdk.lunarg.com/sdk/download/1.3.268.0/windows/VulkanSDK-1.3.268.0-Installer.exe

jobs:
  build:
    name: Vulkan
    runs-on: ${{ matrix.platform }}
    strategy:
      fail-fast: false
      matrix:
        platform: [windows-latest, macos-latest, ubuntu-latest]

    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true

      - name: apt install xorg-dev  libglfw3-dev libsdl2-dev (ubuntu only)
        if: ${{ matrix.platform == 'ubuntu-latest' }}
        run: sudo apt-get update && sudo apt-get install -y xorg-dev  libglfw3-dev libsdl2-dev

      - name: Install Vulkan Sdk Win
        if: ${{ matrix.platform == 'windows-latest' }}
        shell: powershell
        run: |
          Invoke-WebRequest -Uri "https://github.com/ocornut/imgui/files/3789205/vulkan-sdk-1.1.121.2.zip" -OutFile vulkan-sdk-1.1.121.2.zip
          Expand-Archive -Path vulkan-sdk-1.1.121.2.zip
          echo "VULKAN_SDK=$(pwd)\vulkan-sdk-1.1.121.2\" >>${env:GITHUB_ENV}

      - name: Install Vulkan Sdk macOS
        if: ${{ matrix.platform == 'macos-latest' }}
        shell: bash
        run: |
          wget -q https://github.com/pthom/hello_imgui/releases/download/v1.0.0/VulkanSDK_1.3.268.1_macos.tgz
          tar xfz VulkanSDK_1.3.268.1_macos.tgz
          echo "VULKAN_SDK=$(pwd)/VulkanSDK/1.3.268.1/macOS" >> $GITHUB_ENV

      - name: Build and install
        shell: bash
        run: |
          mkdir build
          cd build
          cmake .. -DHELLOIMGUI_USE_GLFW_VULKAN=ON -DHELLOIMGUI_USE_SDL_VULKAN=ON -DCMAKE_BUILD_TYPE=Release -DHELLOIMGUI_DOWNLOAD_FREETYPE_IF_NEEDED=ON
          cmake --build . -j 3


android

name: android

# Builds _example_integration for Android

on:
  push:
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@master
    - name: Checkout submodules
      run: git submodule update --init --recursive

    - name: Set up JDK 17
      uses: actions/setup-java@v4
      with:
        java-version: '17'
        distribution: 'temurin'

#    - name: Setup interactive tmate session
#      uses: mxschmitt/action-tmate@v3

    - name: invoke cmake to create gradle / android studio project
      # This will create the project
      # build_android/hello_imgui_demodocking_AndroidStudio
      run: |
        cd _example_integration
        mkdir -p external
        cd external
        ln -s ../../ imgui_bundle
        cd ..
        mkdir build_android
        cd build_android
        export ANDROID_HOME=/usr/local/lib/android/sdk
        ../external/imgui_bundle/external/hello_imgui/hello_imgui/tools/android/cmake_arm-android.sh ..

    - name: gradlew build
      # This will build for all android architectures
      run: |
          export ANDROID_HOME=/usr/local/lib/android/sdk
          cd _example_integration/build_android/imgui_bundle_example_integration_AndroidStudio
          ./gradlew build


name: "ci_automation_test"

# Run an app with automation thanks to imgui_test_engine / ensure it works

on:
  workflow_dispatch:
  pull_request:
  push:

jobs:
  build:
    name: Automation Test
    runs-on: ${{ matrix.platform }}
    strategy:
      fail-fast: false
      matrix:
        platform: [ubuntu-latest]
        # platform: [windows-latest, ubuntu-latest]
        # this does not work under macos-latest (may be "Off-screen Mesa" could help)

    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true

      - name: install libglfw3-dev xorg-dev & start Xvfb (ubuntu only)
        if: ${{ matrix.platform == 'ubuntu-latest' }}
        run: |
          sudo apt-get update && sudo apt-get install -y xorg-dev
          sudo apt-get install -y xvfb
          sudo apt-get install -y libglfw3-dev
          Xvfb :99 &
          echo "DISPLAY=:99.0" >> $GITHUB_ENV

      #      - name: Setup interactive tmate session
      #        uses: mxschmitt/action-tmate@v3

      - name: Build C++ automation app
        shell: bash
        run: |
          cd .github/ci_automation_tests
          mkdir build
          cd build
          cmake ..  -DCMAKE_BUILD_TYPE=Release -DHELLOIMGUI_WIN32_NO_CONSOLE=OFF -DHELLOIMGUI_WIN32_AUTO_WINMAIN=OFF -DHELLOIMGUI_DOWNLOAD_FREETYPE_IF_NEEDED=ON
          cmake --build . -j 3 --config Release

#      - name: install mesa OpenGL software renderer (windows only)
#        shell: bash
#        if: ${{ matrix.platform == 'windows-latest' }}
#        run: |
#          # Download the archive
#          curl -L -O https://github.com/pal1000/mesa-dist-win/releases/download/23.1.9/mesa3d-23.1.9-release-msvc.7z
#
#          # Extract the archive using 7-zip which is preinstalled on the GitHub Actions Windows runner
#          7z x mesa3d-23.1.9-release-msvc.7z -omesa3d
#
#          # Optionally move/copy the required DLLs to the directory of your executable
#          # For this example, I'll assume your executable is in '.github/ci_automation_tests/build'
#          # Copy the opengl32.dll to your executable directory
#          cp mesa3d/x64/*.* .github/ci_automation_tests/build/Release

#      - name: Run C++ Automation Test (windows)
#        shell: bash
#        if: ${{ matrix.platform == 'windows-latest' }}
#        run: |
#          cd .github/ci_automation_tests/build/Release
#
#          # Run the application, but don't exit the script even if it fails
#          # Under windows, the app works well a local machine and on GitHub CI
#          # However it ends with a segfault on Github CI, althought it did run to the end.
#          # Let's detect this via an old-style hack.
#          ./ci_automation_test_app_bundle.exe || true
#
#          # Now check for the success file
#          if [[ ! -f ci_automation_test_app_success.txt ]]; then
#            echo "Error: ci_automation_test_app_success.txt not found!"
#            exit 1
#          fi

      - name: Run C++ Automation Test (nixes)
        shell: bash
        if: ${{ matrix.platform != 'windows-latest' }}
        run: |
          cd .github/ci_automation_tests/build
          ./ci_automation_test_app_bundle


CppLib

name: "CppLib"

on:
  workflow_dispatch:
  pull_request:
  push:

env:
  MACOSX_DEPLOYMENT_TARGET: "11.0"

jobs:
  build:
    name: CppLib
    runs-on: ${{ matrix.platform }}
    strategy:
      fail-fast: false
      matrix:
        platform: [windows-latest, macos-latest, ubuntu-latest]

    steps:
    - uses: actions/checkout@v4
      with:
        submodules: true

#    - name: Setup interactive tmate session
#      if: ${{ matrix.platform == 'ubuntu-latest' }}
#      uses: mxschmitt/action-tmate@v3

    - name: apt install xorg-dev  libglfw3-dev libsdl2-dev (ubuntu only)
      if: ${{ matrix.platform == 'ubuntu-latest' }}
      run: sudo apt-get update && sudo apt-get install -y xorg-dev  libglfw3-dev libsdl2-dev

    - name: Build and install
      shell: bash
      run: |
        mkdir build
        cd build
        cmake .. -DHELLOIMGUI_USE_GLFW3=ON -DHELLOIMGUI_USE_SDL2=ON  -DHELLOIMGUI_HAS_OPENGL3=ON -DCMAKE_BUILD_TYPE=Release -DHELLOIMGUI_DOWNLOAD_FREETYPE_IF_NEEDED=ON
        cmake --build . --config Release -j 3


name: "CppLib_WithBindings"

on:
  workflow_dispatch:
  pull_request:
  push:

env:
  MACOSX_DEPLOYMENT_TARGET: "11.0"

jobs:
  build:
    name: CppLib_WithBindings
    runs-on: ${{ matrix.platform }}
    strategy:
      fail-fast: false
      matrix:
        platform: [windows-latest, macos-latest, ubuntu-latest]

    steps:
    - uses: actions/checkout@v4
      with:
        submodules: true

    - name: install xorg-dev on ubuntu
      run: ./ci_scripts/install_xorg_dev.sh

#    - name: Setup interactive tmate session
#      uses: mxschmitt/action-tmate@v3

    - name: Build and install (*nixes)
      if: ${{ matrix.platform != 'windows-latest' }}
      shell: bash
      run: |
        python3 -m venv venv
        source venv/bin/activate
        pip install pybind11
        mkdir build && cd build
        cmake .. -DIMGUI_BUNDLE_BUILD_PYTHON=ON -DCMAKE_BUILD_TYPE=Release
        cmake --build . --config Release -j 3

    - name: Build and install (Windows)
      if: ${{ matrix.platform == 'windows-latest' }}
      shell: bash
      run: |
        python3 -m venv venv
        source venv/Scripts/activate # only difference from *nixes...
        pip install pybind11
        mkdir build && cd build
        cmake .. -DIMGUI_BUNDLE_BUILD_PYTHON=ON -DCMAKE_BUILD_TYPE=Release
        cmake --build . --config Release -j 3


Emscripten

name: "Emscripten"

on:
  workflow_dispatch:
  pull_request:
  push:

jobs:
  build:
    name: Emscripten
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true

#      - name: Setup interactive tmate session
#        uses: mxschmitt/action-tmate@v3

      - name: Build and install
        shell: bash
        run: |
          ./external/hello_imgui/hello_imgui/tools/emscripten/install_emscripten.sh
          mkdir build_ems
          cd build_ems
          source ~/emsdk/emsdk_env.sh
          emcmake cmake .. -DCMAKE_BUILD_TYPE=Release
          make -j 4


ios

name: "ios"

# Builds _example_integration for iOS simulator

on:
  workflow_dispatch:
  pull_request:
  push:

jobs:
  build:
    name: "ios"
    runs-on: macos-latest
    strategy:
      fail-fast: false

    steps:
    - uses: actions/checkout@v4
    - name: Checkout submodules
      run: git submodule update --init --recursive

#    - name: Setup interactive tmate session
#      uses: mxschmitt/action-tmate@v3

    - name: CMake
      run: |
        cd _example_integration
        mkdir -p external
        cd external
        ln -s ../.. imgui_bundle
        cd ..
        mkdir build-ios
        cd build-ios
        cmake .. \
          -GXcode \
          -DCMAKE_TOOLCHAIN_FILE=../external/imgui_bundle/external/hello_imgui/hello_imgui/hello_imgui_cmake/ios-cmake/ios.toolchain.cmake \
          -DPLATFORM=SIMULATOR64

    - name: Build for simulator
      working-directory: _example_integration/build-ios
      run: |
        xcodebuild -configuration Release -project imgui_bundle_example_integration.xcodeproj -target ALL_BUILD -arch x86_64 -sdk iphonesimulator


Pip

name: "Pip"

on:
  workflow_dispatch:
  pull_request:
  push:

env:
  MACOSX_DEPLOYMENT_TARGET: "11.0"
  DISPLAY: ":0"

jobs:
  build:
    name: Pip
    runs-on: ${{ matrix.platform }}
    strategy:
      fail-fast: false
      matrix:
        platform: [windows-latest, macos-latest, ubuntu-latest]
        python-version: ["3.11", "3.12"]

    steps:
    - uses: actions/checkout@v4
      with:
        submodules: true

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

    - name: install xorg-dev & start Xvfb (ubuntu only)
      if: ${{ matrix.platform == 'ubuntu-latest' }}
      run: |
        sudo apt-get update && sudo apt-get install -y xorg-dev
        sudo apt-get install -y xvfb
        Xvfb :99 &
        echo "DISPLAY=:99.0" >> $GITHUB_ENV

    - name: install mesa OpenGL software renderer (windows only)
      shell: bash
      if: ${{ matrix.platform == 'windows-latest' }}
      run: |
        # Download the archive
        curl -L -O https://github.com/pal1000/mesa-dist-win/releases/download/23.1.9/mesa3d-23.1.9-release-msvc.7z

        # Extract the archive using 7-zip which is preinstalled on the GitHub Actions Windows runner
        7z x mesa3d-23.1.9-release-msvc.7z -omesa3d

        # copy the mesa DLLs to the python directory
        python_dir=$(dirname $(which python))
        cp mesa3d/x64/*.* $python_dir

#    - name: Setup interactive tmate session
#      uses: mxschmitt/action-tmate@v3

    - name: Build and install
      shell: bash
      run: |
        # optionally: export IMMVISION_FETCH_OPENCV=OFF
        pip install --verbose .[test]

    - name: pytest
      run: pytest

    - name: CI Automation python test (ubuntu)
      shell: bash
      if: ${{ matrix.platform == 'ubuntu-latest' }}
      run: |
        cd .github/ci_automation_tests
        python ci_automation_test_app_bundle.py


Wheels

name: Wheels

# Note: the cibuildwheel options are inside pyproject.toml

on:
  workflow_dispatch:
  pull_request:
  release:
    types:
      - published
  push:
    branches:
      - master
      - main

jobs:
  build_sdist:
    name: Build SDist
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
      with:
        submodules: true

    - name: Build SDist
      run: pipx run build --sdist

    - name: Check metadata
      run: pipx run twine check dist/*

    - uses: actions/upload-artifact@v4
      with:
        name: dist-sdist
        path: dist/*.tar.gz

  build_wheels:
    name: Wheels on ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]

    steps:
    - uses: actions/checkout@v4
      with:
        submodules: true

    - uses: pypa/cibuildwheel@v2.19.1

    - name: Verify clean directory
      run: git diff --exit-code
      shell: bash

    - name: Upload wheels
      uses: actions/upload-artifact@v4
      with:
        name: dist-${{ matrix.os }}
        path: wheelhouse/*.whl

  upload_all:
    name: Upload if release
    needs: [build_wheels, build_sdist]
    runs-on: ubuntu-latest
    if: github.event_name == 'release' && github.event.action == 'published'

    steps:
    - uses: actions/setup-python@v5
      with:
        python-version: "3.x"

    - uses: actions/download-artifact@v4
      with:
        pattern: dist-*
        merge-multiple: true
        path: dist

    - uses: pypa/gh-action-pypi-publish@v1.9.0
      with:
        user: __token__
        password: ${{ secrets.pypi_password }}


Upload Python Package

# This workflow will upload a Python Package using Twine when a release is created
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries

# 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.

name: Upload Python Package

on:
  release:
    types: [published]

permissions:
  contents: read

jobs:
  deploy:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4
    - name: Set up Python
      uses: actions/setup-python@v3
      with:
        python-version: '3.x'
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install build
    - name: Build package
      run: python -m build
    - name: Publish package
      uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
      with:
        user: __token__
        password: ${{ secrets.PYPI_API_TOKEN }}


identify merge conflicts

# This workflow will check pull requests for merge conflicts and
# automatically add (and remove) a relevant label

name: identify merge conflicts
on:
  # So that PRs touching the same files as the push are updated
  push:
  # So that the `dirtyLabel` is removed if conflicts are resolved
  pull_request:
    types: [synchronize]

jobs:
  label:
    runs-on: ubuntu-20.04

    steps:
    - name: Label Conflicting Pull Requests
      uses: eps1lon/actions-label-merge-conflict@72a2cf9eb9640428abbd99bc0aa6dd522073b9d3
            # This is tagged version v1.2.3, but do not use version tags
            # https://julienrenaux.fr/2019/12/20/github-actions-security-risk/
      with:
        dirtyLabel: 'PR: merge conflicts'
        removeOnDirtyLabel: 'PR: ready to ship'
        repoToken: ${{ secrets.GITHUB_TOKEN }}


Newsfragments

name: Newsfragments

on:
  pull_request_target:
    types: [opened, synchronize, reopened, ready_for_review]
    branches-ignore:
    - dials-?.*

jobs:
  rename-news:
    name: Newsfragment
    runs-on: ubuntu-20.04
    if: github.event.pull_request.draft == false
    steps:
    - name: Check out the repository
      uses: actions/checkout@v2
      with:
        ref: ${{ github.event.pull_request.head.sha }}
        token: ${{ secrets.USER_TOKEN }}
    - name: Added a newsfragment
      run: |
        set -x
        echo "Triggering commit: ${GITHUB_REF} ${GITHUB_SHA}"
        git fetch --unshallow
        git log HEAD -n 1
        commit_merge_base="$(git merge-base ${{ github.event.pull_request.head.sha }} ${{ github.event.pull_request.base.sha }})"
        if ! git diff --name-status $commit_merge_base ${{ github.event.pull_request.head.sha }} -- newsfragments/ | grep '^A'; then
          echo "::error ::PR Branch is missing a newsfragment. Please add one with a number or named XXX.<type>."
          exit 1
        else
          echo "✅  Newsfragment entry present"
        fi
    - name: Rename placeholder newsfragments
      run: |
        rename_candidates="$(find newsfragments -regex 'newsfragments/[xX]+\..*')"
        if [[ -n "$rename_candidates" ]]; then
          git config user.name "DiamondLightSource-build-server"
          git config user.email "DiamondLightSource-build-server@users.noreply.github.com"
          HEAD_REPO="${{github.event.pull_request.head.repo.full_name}}"
          HEAD_BRANCH="${{ github.event.pull_request.head.ref }}"
          message=""
          git remote add fork https://x-access-token:${USER_TOKEN}@github.com/$HEAD_REPO.git
          for fragment in ${rename_candidates}; do
            target_file="$(echo "${fragment}" | sed -E "s/[xX]+/${{github.event.number}}/")"
            if [[ -f "${target_file}" ]]; then
              echo "::error ::Cannot rename ${fragment} to ${target_file} as it already exists. Merge manually."
              exit 1
            fi
            git mv $fragment $target_file
            git add $target_file
            if [[ -z "${message}" ]]; then
              message="Rename ${fragment} to ${target_file}"
            else
              message="Rename XXX.* to ${{github.event.number}}.*"
            fi
          done
          git commit -m "${message}"
          git push fork HEAD:"${HEAD_BRANCH}"
        else
          echo "No Newsfragments need to be renamed."
        fi


test

name: test
on: [push, pull_request]
jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        python-version: [3.8, 3.9, '3.10', 3.11, 3.12, 3.13, pypy3.9-nightly, pypy3.10-nightly]
        coverage: [false]
        nogmpy: [false]
        default: [false]
        include:
          - python-version: 3.11
            coverage: true
            nogmpy: true
          - python-version: 3.12
            coverage: true
            default: true
    env:
      PYTEST_ADDOPTS: -n auto
    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 }}
        allow-prereleases: true
    - name: Install libs
      run: |
        sudo apt update
        sudo apt install latexmk texlive-xetex
    - name: Install dependencies
      run: |
        pip install --upgrade setuptools pip
        pip install --upgrade .[develop,gmpy,docs,ci]
    - name: Remove gmpy (for coverage tests)
      if: matrix.nogmpy
      run: pip uninstall -y gmpy2
    - name: Install ~/.python_history
      run: touch ~/.python_history
    - name: Linting with flake8, etc
      if: matrix.default
      run: |
        python -We:invalid -m compileall -f mpmath -q
        flake518 mpmath
    - name: Tests
      if: ${{ ! matrix.coverage }}
      run: pytest
    - name: Run coverage tests
      env:
        PYTEST_ADDOPTS: --cov mpmath --cov-append --cov-report=xml -n auto
      if: matrix.coverage
      run: |
        pytest
        pip uninstall -y ipython
        pytest mpmath/tests/test_cli.py
        coverage html
        coverage xml
        diff-cover coverage.xml --fail-under=100 --compare-branch=origin/master
    - name: Upload coverage data
      if: matrix.coverage
      uses: codecov/codecov-action@v4
      with:
        files: ./coverage.xml
        fail_ci_if_error: false
    - name: Building docs
      if: matrix.default
      run: |
        sphinx-build --color -W --keep-going -b html docs build/sphinx/html
        sphinx-build --color -W --keep-going -b latex docs build/sphinx/latex
        make -C build/sphinx/latex all-pdf
    - name: Make packages
      if: matrix.default
      run: python -m build
    - name: Archive production artifacts
      uses: actions/upload-artifact@v4
      if: matrix.default
      with:
        path: |
          dist/
          build/sphinx/html/
          build/sphinx/latex/mpmath.pdf
          coverage.xml
          build/coverage/html/
    - name: Publish package on PyPI
      if: matrix.default && github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
      uses: pypa/gh-action-pypi-publish@release/v1
      with:
        user: __token__
        password: ${{ secrets.PYPI_API_TOKEN }}


# Run the workflow that adds new tickets that are either:
# - labelled "DEPR"
# - title starts with "[DEPR]"
# - body starts with "Proposal Date" (this is the first template field)
# to the org-wide DEPR project board

name: Add newly created DEPR issues to the DEPR project board

on:
  issues:
    types: [opened]

jobs:
  routeissue:
    uses: openedx/.github/.github/workflows/add-depr-ticket-to-depr-board.yml@master
    secrets:
      GITHUB_APP_ID: ${{ secrets.GRAPHQL_AUTH_APP_ID }}
      GITHUB_APP_PRIVATE_KEY: ${{ secrets.GRAPHQL_AUTH_APP_PEM }}
      SLACK_BOT_TOKEN: ${{ secrets.SLACK_ISSUE_BOT_TOKEN }}


# This workflow runs when a comment is made on the ticket
# If the comment starts with "label: " it tries to apply
# the label indicated in rest of comment.
# If the comment starts with "remove label: ", it tries
# to remove the indicated label.
# Note: Labels are allowed to have spaces and this script does
# not parse spaces (as often a space is legitimate), so the command
# "label: really long lots of words label" will apply the
# label "really long lots of words label"

name: Allows for the adding and removing of labels via comment

on:
  issue_comment:
    types: [created]

jobs:
  add_remove_labels:
    uses: openedx/.github/.github/workflows/add-remove-label-on-comment.yml@master


Python CI

name: Python CI

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - '**'

jobs:
  run_tests:
    name: Tests
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os:
          - ubuntu-20.04
        python-version:
          - "3.11"

    steps:
    - uses: actions/checkout@v1
    - name: setup python
      uses: actions/setup-python@v2
      with:
        python-version: ${{ matrix.python-version }}

    - name: Install dependencies
      run: pip install -r requirements/test.txt

    - name: Run Tests
      run: |
        make test
        cd docs && make html

    - name: Run Coverage
      uses: codecov/codecov-action@v4
      with:
        token: ${{ secrets.CODECOV_TOKEN }}
        fail_ci_if_error: true


Lint Commit Messages

# Run commitlint on the commit messages in a pull request.

name: Lint Commit Messages

on:
  - pull_request

jobs:
  commitlint:
    uses: openedx/.github/.github/workflows/commitlint.yml@master


# This workflow runs when a comment is made on the ticket
# If the comment starts with "assign me" it assigns the author to the
# ticket (case insensitive)

name: Assign comment author to ticket if they say "assign me"
on:
  issue_comment:
    types: [created]

jobs:
  self_assign_by_comment:
    uses: openedx/.github/.github/workflows/self-assign-issue.yml@master


Build

name: Build

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

jobs:
  build:

    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.9', '3.10', '3.11']

    # Skip CI if 'skip ci' is contained in latest commit message
    if: "!contains(github.event.head_commit.message, 'skip ci')"

    steps:

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

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

    - name: Test with pytest
      run: |
        python setup.py test

    - name: Upload coverage to Codecov
      uses: codecov/codecov-action@v4
      with:
        file: ./coverage.xml
        flags: unittests


Documentation

name: Documentation

on:
  push:
    branches:
      - main

jobs:
  build:

    runs-on: ubuntu-latest

    # Skip docs if 'skip docs' is contained in latest commit message
    if: "!contains(github.event.head_commit.message, 'skip docs')"

    steps:

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

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -e .[dev]

    - name: Set up Pandoc
      uses: r-lib/actions/setup-pandoc@v2

    - name: Build documentation
      run: |
        cd docs
        make clean
        make html

    - name: Commit documentation changes to gh-pages
      run: |
        cd docs
        git clone https://github.com/rs-station/reciprocalspaceship.git --branch gh-pages --single-branch gh-pages
        cd gh-pages
        cp -r ../_build/html/* .
        git config --local user.email "action@github.com"
        git config --local user.name "GitHub Action"
        git add .
        git diff --quiet && git diff --staged --quiet || git commit -m "Upload documentation from latest commit"

    - name: Push changes to gh-pages
      uses: ad-m/github-push-action@master
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        branch: "gh-pages"
        directory: "docs/gh-pages"


Publish to PyPI

# heavily based on https://github.com/jupyterlab/jupyterlab-git/blob/v0.22.2/.github/workflows/publish.yml
name: Publish to PyPI

on:
  release:
    types: [published]
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Install Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.11'
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install matplotlib packaging setuptools twine wheel typing-extensions
    - name: Publish the Python package
      env:
        TWINE_USERNAME: __token__
        TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
      run: |
        python setup.py sdist bdist_wheel
        twine upload dist/*


Test Documentation

name: Test Documentation

on:
  pull_request:
    branches:
      - main

jobs:
  build:

    runs-on: ubuntu-latest

    # Skip docs if 'skip docs' is contained in latest commit message
    if: "!contains(github.event.head_commit.message, 'skip docs')"

    steps:

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

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -e .[dev]

    - name: Set up Pandoc
      uses: r-lib/actions/setup-pandoc@v2

    - name: Build documentation
      run: |
        cd docs
        make clean
        make html


black-check-latest

name: black-check-latest
on: [pull_request, push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python 3.11
        uses: actions/setup-python@v5
        with:
          python-version: 3.11
      - name: Install latest Black version
        run: pip install black
      - name: Run black --check --diff .
        run: black --check --diff .


Python Package using Conda

name: Python Package using Conda

on: [push, workflow_dispatch]

jobs:
  build-all:
    name: scqubits testing (${{ matrix.python-version }}, ${{ matrix.os }})
    runs-on: ${{ matrix.os }}
    defaults:
      run:
        shell: bash -el {0}
    strategy:
      fail-fast: false
      matrix:
        os: ["ubuntu-latest", "macos-latest", "windows-latest"]
        python-version: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12']
    steps:
      - uses: actions/checkout@v4
        name: Checkout repository
      - name: Python setup for macos-latest with python 3.7
        if: ${{matrix.python-version == '3.7' && matrix.os == 'macos-latest'}}
        uses: conda-incubator/setup-miniconda@v3
        with:
            miniforge-variant: Mambaforge
            use-mamba: true
            auto-update-conda: true
            python-version: ${{ matrix.python-version }}
            architecture: x64
            channels: conda-forge

      - name: Python setup for the rest of the jobs
        if: ${{!(matrix.python-version == '3.7' && matrix.os == 'macos-latest')}}
        uses: conda-incubator/setup-miniconda@v3
        with:
            miniforge-variant: Mambaforge
            use-mamba: true
            auto-update-conda: true
            python-version: ${{ matrix.python-version }}
            channels: conda-forge

      - name: conda info
        run: conda info

      - name: Add conda to system path
        run: |
          # $CONDA is an environment variable pointing to the root of the miniconda directory
          echo $CONDA/bin >> $GITHUB_PATH

      - name: Lint with flake8
        run: |
          mamba install flake8
          # stop the build if there are Python syntax errors or undefined names
          flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
          # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
          flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics

      - name: Build with conda and run tests
        run: |
          mamba install boa
          conda mambabuild .


Upload Python Package to PyPi

name: Upload Python Package to PyPi

on:
  release:
    types: [created]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.x'
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install setuptools wheel twine
    - name: Build and publish
      env:
        TWINE_USERNAME: __token__
        TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
      run: |
        python setup.py sdist bdist_wheel
        twine upload dist/*


CI

name: CI
on:
    push:
      paths-ignore:
        - "README.md"
        - "**/docs/**"
        - ".github/workflows/docs.yml"

    pull_request:
      branches:
        - master
        - dev

    schedule:
        - cron: "0 11 * * *"

jobs:
    skip_duplicate:
        runs-on: ubuntu-latest
        outputs:
            should_skip: ${{ steps.skip_check.outputs.should_skip }}
        steps:
            - id: skip_check
              uses: fkirc/skip-duplicate-actions@master
              with:
                  github_token: ${{ github.token }}
                  concurrent_skipping: never
                  skip_after_successful_duplicate: true
                  paths_ignore: '["**/README.md", "**/docs/**"]'
                  do_not_skip: '["pull_request",  "schedule"]'

    test-pip:
        name: Test on Pip
        needs: skip_duplicate
        if: ${{ needs.skip_duplicate.outputs.should_skip == 'false' }}
        strategy:
            fail-fast: false
            matrix:
                python-version: ["3.9","3.10","3.11"]
                os: ["ubuntu-latest", "macos-latest", "macos-12"]
        runs-on:  ${{ matrix.os }}
        steps:
            - name: Checkout
              uses: actions/checkout@v4
            - name: Set up Python ${{ matrix.python-version }}
              uses: actions/setup-python@v5
              with:
                  python-version: ${{ matrix.python-version }}
            - name: Install dependencies
              run: |
                  python -m pip install --upgrade pip wheel setuptools numpy

                  # Temp fix due to speclite not supporting the latest version
                  pip install "matplotlib<3.9"

                  if [[ ${{matrix.os}} == macos-latest ]];
                  then
                    brew update
                    brew install hdf5
                  fi

                  if [[ "${ISDEV}" == "true" ]]; then
                    pip install --upgrade --pre astromodels
                  else
                    pip install --upgrade astromodels
                  fi

                  pip install --upgrade flake8 coverage pytest-cov cython

                  pip install -e .
              env:
                  ISDEV: ${{contains(github.ref, 'dev') || contains(github.base_ref, 'dev')}}
            - name: Lint with flake8
              run: |
                  # stop the build if there are Python syntax errors or undefined names
                  flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
                  # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
                  flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics

            - name: Test pip on ${{ matrix.python-version }}
              run: |
                  python -m pytest -vv --cov=threeML --cov-report=xml
              env:
                  PYTEST_ADDOPTS: "--color=yes"
                  OMP_NUM_THREADS: 1
                  MKL_NUM_THREADS: 1
                  NUMEXPR_NUM_THREADS: 1
                  MPLBACKEND: "Agg"

    test-dev:
        name: Test on Pip against astromodels-dev
        needs: skip_duplicate
        if: ${{ needs.skip_duplicate.outputs.should_skip == 'false' }}
        strategy:
            fail-fast: false
            matrix:
                python-version: ["3.9","3.10","3.11"]
                os: [ "ubuntu-latest", "macos-latest", "macos-12"]
        runs-on: ${{ matrix.os }}
        steps:
            - name: Checkout
              uses: actions/checkout@v4
            - name: Set up Python ${{ matrix.python-version }}
              uses: actions/setup-python@v5
              with:
                  python-version: ${{ matrix.python-version }}
            - name: Install dependencies
              run: |
                  python -m pip install --upgrade pip wheel

                  # Temp fix due to speclite not supporting the latest version
                  pip install "matplotlib<3.9"

                  if [[ ${{matrix.os}} == macos-latest ]];
                  then
                    brew update
                    brew install hdf5
                  fi

                  git clone https://github.com/threeML/astromodels
                  cd astromodels
                  git checkout dev

                  python -m pip install -e .

                  cd ..

                  pip install --upgrade flake8 coverage pytest-cov cython

                  pip install -e .
            - name: Lint with flake8
              run: |
                  # stop the build if there are Python syntax errors or undefined names
                  flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
                  # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
                  flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics

            - name: Test pip on ${{ matrix.python-version }}
              run: |
                  python -m pytest -vv --cov=threeML --cov-report=xml
              env:
                  PYTEST_ADDOPTS: "--color=yes"
                  OMP_NUM_THREADS: 1
                  MKL_NUM_THREADS: 1
                  NUMEXPR_NUM_THREADS: 1
                  MPLBACKEND: "Agg"

    test-conda:
        name: Test on Conda
        needs: skip_duplicate
        if: ${{ needs.skip_duplicate.outputs.should_skip == 'false' }}
        strategy:
            fail-fast: false
            matrix:
                os: ["ubuntu-latest", "macos-12"]
                python-version: [3.9]
        runs-on: ${{ matrix.os }}
        steps:
            - name: Checkout
              uses: actions/checkout@v4
            - name: XCode
              uses: maxim-lobanov/setup-xcode@v1
              with:
                  xcode-version: latest
              if: runner.os == 'macOS'
            #- name: Cache conda
            #  uses: actions/cache@v2
            #  env:
                # Increase this value to reset cache if etc/example-environment.yml has not changed
            #    CACHE_NUMBER: 0
            #  with:
            #      path: ~/conda_pkgs_dir
            #      key: conda-${{ matrix.os }}-python-${{ matrix.python-version }}-${{ hashFiles('ci/environment.yml') }}
            - name: Setup Miniconda
              uses: conda-incubator/setup-miniconda@v3
              with:
                  auto-update-conda: true
                  auto-activate-base: false
                  #miniforge-variant: Mambaforge
                  miniforge-version: latest
                  activate-environment: test_env
                  python-version: ${{ matrix.python-version }}
                  channels: conda-forge, xspecmodels, threeml, fermi, defaults
                  environment-file: ci/environment.yml
                  use-only-tar-bz2: true

            - name: Init Env
              shell: bash -l {0}
              run: |

                  export PKG_VERSION=$(python -c "import versioneer;print(versioneer.get_version())")

                  echo "HOME= ${HOME}"
                  echo "Building ${PKG_VERSION} ..."
                  echo "Python version: ${{matrix.python-version}}"
                  echo "Running on development branch: ${ISDEV} "

                  if [[ "${ISDEV}" == "true" ]]; then

                  mamba install -c conda-forge -c threeml/label/dev "threeml/label/dev::astromodels"

                  fi
                  pip install --upgrade speclite
                  pip install fermipy "matplotlib<3.9"
              env:
                  ISDEV: ${{contains(github.ref, 'dev') || contains(github.base_ref, 'dev')}}
            - name: Conda list
              shell: bash -l {0}
              run: |
                  conda list
            - name: install it
              shell: bash -l {0}
              run: |
                  pip install -e .
            - name: Lint with flake8
              shell: bash -l {0}
              run: |
                  # stop the build if there are Python syntax errors or undefined names
                  flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
                  # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
                  flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics

            - name: test it
              shell: bash -l {0}
              run: |
                  wget https://raw.githubusercontent.com/fermi-lat/pyBurstAnalysisGUI/master/python/GtBurst/updater.py -O $CONDA_PREFIX/lib/python${{ matrix.python-version }}/site-packages/fermitools/GtBurst/updater.py
                  python $CONDA_PREFIX/lib/python${{ matrix.python-version }}/site-packages/fermitools/GtBurst/updater.py
                  python -m pytest -vv --cov=threeML --cov-report=xml

              env:
                  PYTEST_ADDOPTS: "--color=yes"
                  OMP_NUM_THREADS: 1
                  MKL_NUM_THREADS: 1
                  NUMEXPR_NUM_THREADS: 1
                  MPLBACKEND: "Agg"

            - name: Upload coverage to Codecov
              uses: codecov/codecov-action@v1
              with:
                  file: ./coverage.xml
                  files: ./coverage1.xml,./coverage2.xml
                  Directory: ./coverage/reports/

    publish-pypi:
        name: Publish to PyPi
        if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
        runs-on: ubuntu-latest
        permissions:
            # IMPORTANT: this permission is mandatory for trusted publishing
            id-token: write
        steps:
            - name: Checkout source
              uses: actions/checkout@v4
            - name: Set up Python
              uses: actions/setup-python@v1
              with:
                  python-version: 3.9
            - name: Build package
              run: |
                  pip install wheel setuptools -U
                  python setup.py sdist bdist_wheel
            - name: Publish
              uses: pypa/gh-action-pypi-publish@release/v1
              with:
                  skip-existing: true

    test-publish-pypi:
        name: Build & verify package
        runs-on: ubuntu-latest

        steps:
            - uses: actions/checkout@v4
            - uses: actions/setup-python@v5
              with:
                  python-version: 3.9

            - name: Install twine
              run: |
                  python -m pip install twine
                  pip install wheel setuptools -U
            - name: Build package
              run: |
                  python setup.py sdist bdist_wheel
            - name: List result
              run: |
                  ls -lh dist
            - name: Check long_description
              run: |
                  python -m twine check dist/*


Conda Build and Publish

name: Conda Build and Publish
on:
    push:
    pull_request:
    schedule:
        - cron: "0 11 * * *"

jobs:
    build-conda:
        name: Build and verify with Conda
        if: startsWith(github.ref, 'refs/tags') == false
        runs-on: ${{ matrix.os }}
        strategy:
            fail-fast: false
            matrix:
                os: ["ubuntu-latest", "macos-latest", "macos-12"]
                python-version: [3.9]

        steps:
            - name: Checkout
              uses: actions/checkout@v4
              with:
                  fetch-depth: 0
            - name: XCode
              uses: maxim-lobanov/setup-xcode@v1
              with:
                  xcode-version: latest
              if: runner.os == 'macOS'
            - name: Set up Python
              uses: actions/setup-python@v5
              with:
                  python-version: ${{ matrix.python-version }}
              #- name: Cache conda
              #uses: actions/cache@v4
              #with:
              #    path: ~/conda_pkgs_dir
              #    key: conda-${{ matrix.os }}-python-${{ matrix.python-version }}-${{ hashFiles('ci/environment.yml') }}
            - name: Add conda ${{ matrix.python-version }} to system path
              uses: conda-incubator/setup-miniconda@v3
              with:
                  activate-environment: "test_env"
                  auto-activate-base: false
                  miniforge-variant: Mambaforge
                  architecture: "x64"
                  #conda-build-version: "*"
                  python-version: ${{ matrix.python-version }}
                  auto-update-conda: true
                  environment-file: ci/environment.yml
                  channels: conda-forge, xspecmodels, threeml, fermi, defaults
                  use-only-tar-bz2: true

            - name: Init Env
              shell: bash -l {0}
              run: |

                  export PKG_VERSION=$(python -c "import versioneer;print(versioneer.get_version())")
                  echo "PKG_VERSION=$PKG_VERSION" >> $GITHUB_ENV

                  echo "HOME= ${HOME}"
                  echo "Conda installation path ${CONDA}"
                  echo "Building ${PKG_VERSION} ..."
                  echo "Python version: ${{matrix.python-version}}"
                  echo "Running on development branch: ${ISDEV} "

                  if [[ "${ISDEV}" == "true" ]]; then

                  mamba install -c conda-forge -c threeml/label/dev "threeml/label/dev::astromodels"

                  fi
                  pip install --upgrade speclite
                  pip install fermipy "matplotlib<3.9"
              env:
                  ISDEV: ${{contains(github.ref, 'dev') || contains(github.base_ref, 'dev')}}
            - name: Conda list
              shell: bash -l {0}
              run: |
                  conda list
            - name: Build the Distribution
              shell: bash -l {0}
              run: |
                  # Build package

                  #conda install conda-build -n base
                  mamba install -c conda-forge boa

                  conda mambabuild --python=${{matrix.python-version}} conda-dist/recipes/threeml

                  #conda install --use-local -c conda-forge threeml
                  conda install -c ${CONDA}/envs/test_env/conda-bld/ threeml

            - name: Test conda build
              shell: bash -l {0}
              run: |
                #wget https://raw.githubusercontent.com/fermi-lat/pyBurstAnalysisGUI/master/python/GtBurst/updater.py -O $CONDA_PREFIX/lib/python${{ matrix.python-version }}/site-packages/fermitools/GtBurst/updater.py
                #python $CONDA_PREFIX/lib/python${{ matrix.python-version }}/site-packages/fermitools/GtBurst/updater.py
                python -m pytest -vv --cov=threeML --cov-report=xml

              env:
                  PYTEST_ADDOPTS: "--color=yes"
                  OMP_NUM_THREADS: 1
                  MKL_NUM_THREADS: 1
                  NUMEXPR_NUM_THREADS: 1
                  MPLBACKEND: "Agg"

    publish-conda:
        name: Publish to Conda
        if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
        runs-on: ${{ matrix.os }}
        strategy:
            matrix:
                os: [ubuntu-latest, macos-latest]
                python-version: [3.9]

        steps:
            - name: Checkout
              uses: actions/checkout@v4
              with:
                  fetch-depth: 0
            #- name: Set up Python
            #  uses: actions/setup-python@v5
            #  with:
            #      python-version: ${{ matrix.python-version }}
            #- name: Cache conda
            #  uses: actions/cache@v4
            #  with:
            #      path: ~/conda_pkgs_dir
            #      key: conda-${{ matrix.os }}-python-${{ matrix.python-version }}-${{ hashFiles('ci/environment.yml') }}
            - name: Add conda ${{ matrix.python-version }} to system path
              uses: conda-incubator/setup-miniconda@v3
              with:
                  activate-environment: "test_env"
                  auto-activate-base: false
                  miniforge-variant: Mambaforge
                  architecture: "x64"
                  #conda-build-version: "*"
                  python-version: ${{ matrix.python-version }}
                  auto-update-conda: true
                  environment-file: ci/environment.yml
                  channels: conda-forge, xspecmodels, threeml, fermi, defaults
                  use-only-tar-bz2: true

            - name: Init Env
              shell: bash -l {0}
              run: |

                  export PKG_VERSION=$(python -c "import versioneer;print(versioneer.get_version())")
                  echo "PKG_VERSION=$PKG_VERSION" >> $GITHUB_ENV

                  echo "HOME= ${HOME}"
                  echo "Conda installation path ${CONDA}"
                  echo "Building ${PKG_VERSION} ..."
                  echo "Python version: ${{matrix.python-version}}"

            - name: Build the Distribution
              shell: bash -l {0}
              run: |
                  # Build package

                  #conda install conda-build -n base
                  mamba install -c conda-forge boa

                  conda mambabuild --python=${{matrix.python-version}} conda-dist/recipes/threeml

            - name: Publish to Conda
              shell: bash -l {0}
              run: |

                  conda install -c conda-forge anaconda-client
                  echo "Uploading ${{matrix.os}} IsDev: ${ISDEV} "

                  if [[ "${ISDEV}" == "true" ]]; then

                  LABEL="--label dev"

                  fi

                  if [[ "${{matrix.os}}" == "ubuntu-latest" ]]; then

                  anaconda -v --show-traceback -t $UPLOAD_TOKEN upload -u threeml ${CONDA}/envs/test_env/conda-bld/linux-64/*.tar.bz2 --force $LABEL

                  else

                  anaconda -v --show-traceback -t $UPLOAD_TOKEN upload -u threeml ${CONDA}/envs/test_env/conda-bld/osx-64/*.tar.bz2 --force $LABEL

                  fi

              env:
                  UPLOAD_TOKEN: ${{secrets.CONDA_TOKEN}}
                  CURRENT_OS: ${{matrix.os}}
                  ISDEV: ${{contains(github.ref, 'dev')}}


Docker Image CI

name: Docker Image CI

on:
  release:
    types:
      [published]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
        - name: Get the docker file
          run: |
            git clone https://github.com/threeML/docker_base.git
            cd docker_base

        - name: Login to DockerHub Registry
          run: echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
        - name: Get the version
          id: vars
          run: echo ::set-output name=tag::$(echo ${GITHUB_REF:11})
        - name: Build the tagged Docker image for ${{steps.vars.outputs.tag}}
          run: |
            cd docker_base
            docker build . --file Dockerfile --tag threeml/base:${{steps.vars.outputs.tag}}
        - name: Push the tagged Docker image
          run: docker push threeml/base:${{steps.vars.outputs.tag}}
        - name: Build the latest Docker image
          run: |
            cd docker_base
            docker build . --file Dockerfile --tag threeml/base:latest
        - name: Push the latest Docker image
          run: docker push threeml/base:latest


Docs

name: Docs
on: [push, release]

jobs:
  fast_notebooks:
    name: "Build the fast notebooks"
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: 3.9
      - name: install latex
        uses: xu-cheng/texlive-action/small@v1

      - name: Init Environment
        shell: bash -l {0}
        run: |
          set -e
          # brew update
          # brew install --cask basictex

          pip install -U cython
          pip install -U numpy scipy matplotlib
          pip install -U jupytext jupyterthemes jupyter_latex_envs
          pip install -U astropy
          pip install emcee ultranest

          pip install zeus-mcmc
          #pip install git+https://github.com/desihub/speclite.git
          pip install --upgrade speclite
          pip install "black<24"
          pip install astromodels

      - name: Install the package
        shell: bash -l {0}
        run: |
          if [[ "${ISDEV}" == "true" ]]; then
            pip install --upgrade --pre astromodels
            #pip install git+https://github.com/threeML/astromodels.git@dev
          else
            pip install --upgrade astromodels
          fi
          pip install -e .
        env:
          ISDEV: ${{contains(github.ref, 'dev') || contains(github.base_ref, 'dev')}}

      - name: Execute the notebooks
        shell: bash -l {0}
        run: |
          # Make sure we fail in case of error
          set -e
          # copy the doc configuration over
          mkdir -p ~/.config/threeML
          cp threeML/data/doc_config.yml ~/.config/threeML/

          jupytext --to ipynb --pipe black --execute docs/md_docs/fast_execute/*.md

          mv docs/md_docs/fast_execute/*.ipynb docs/notebooks/

          ls docs/notebooks

        env:
          OMP_NUM_THREADS: 1
          MKL_NUM_THREADS: 1
          NUMEXPR_NUM_THREADS: 1
          MPLBACKEND: "Agg"

      - uses: actions/upload-artifact@v4
        with:
          name: notebooks-for-fast-${{ github.sha }}
          path: docs/notebooks

  hal_notebooks:
    name: "Build the HAL notebooks"
    runs-on: macos-12
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Cache conda
        uses: actions/cache@v4
        env:
          # Increase this value to reset cache if etc/example-environment.yml has not changed
          CACHE_NUMBER: 0
        with:
          path: ~/conda_pkgs_dir
          key: conda-hal_notebooks-python-3.9-${{ hashFiles('ci/environment_hal.yml') }}

      - name: Setup Miniconda
        uses: conda-incubator/setup-miniconda@v3
        with:
          auto-update-conda: true
          auto-activate-base: false
          #mamba-version: "*"
          activate-environment: test_env
          python-version: 3.9
          channels: conda-forge, threeml, defaults
          environment-file: ci/environment_hal.yml
          use-only-tar-bz2: true

      - name: Init Environment
        shell: bash -l {0}
        run: |
          # Make sure we fail in case of error
          set -e

          # miniconda_os=Linux
          # compilers="gcc_linux-64 gxx_linux-64 gfortran_linux-64"

          miniconda_os=MacOSX
          compilers="clang_osx-64 clangxx_osx-64 gfortran_osx-64"

          brew update
          brew install --cask basictex

          eval "$(/usr/libexec/path_helper)"
          #sudo apt-get install texlive

          conda install ${compilers} jupytext jupyterthemes jupyter_latex_envs emcee pymultinest ultranest

      - name: Install the package
        shell: bash -l {0}
        run: |
          pip install "black<24"
          pip install --upgrade speclite
          pip install git+https://github.com/threeml/hawc_hal.git
          if [[ "${ISDEV}" == "true" ]]; then
            pip install --upgrade --pre astromodels
            #pip install git+https://github.com/threeML/astromodels.git@dev
          else
            pip install --upgrade astromodels
          fi
          pip install -e .
        env:
          ISDEV: ${{contains(github.ref, 'dev') || contains(github.base_ref, 'dev')}}
      - name: Execute the notebooks
        shell: bash -l {0}
        run: |
          # Make sure we fail in case of error
          set -e
          # copy the doc configuration over
          mkdir -p ~/.config/threeML
          cp threeML/data/doc_config.yml ~/.config/threeML/

          jupytext --to ipynb --pipe black --execute docs/md_docs/slow_execute/hal_example.md
          mv docs/md_docs/slow_execute/hal_example.ipynb docs/notebooks/
          ls docs/notebooks
        env:
          OMP_NUM_THREADS: 1
          MKL_NUM_THREADS: 1
          NUMEXPR_NUM_THREADS: 1
          MPLBACKEND: "Agg"

      - uses: actions/upload-artifact@v4
        with:
          name: notebooks-for-hal-${{ github.sha }}
          path: docs/notebooks

  fermi_notebooks:
    name: "Build the Fermi notebooks"
    runs-on: macos-12
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Cache conda
        uses: actions/cache@v4
        env:
          # Increase this value to reset cache if etc/example-environment.yml has not changed
          CACHE_NUMBER: 0
        with:
          path: ~/conda_pkgs_dir
          key: conda-fermi_notebooks-python-3.7-${{ hashFiles('ci/environment_fermi.yml') }}

      - name: Setup Miniconda
        uses: conda-incubator/setup-miniconda@v3
        with:
          auto-update-conda: true
          auto-activate-base: false
          #mamba-version: "*"
          activate-environment: test_env
          python-version: 3.9
          channels: conda-forge, fermi, threeml, defaults
          environment-file: ci/environment_fermi.yml
          use-only-tar-bz2: true

      - name: Init Environment
        shell: bash -l {0}
        run: |
          # Make sure we fail in case of error
          set -e
          # miniconda_os=Linux
          # compilers="gcc_linux-64 gxx_linux-64 gfortran_linux-64"

          miniconda_os=MacOSX
          compilers="clang_osx-64 clangxx_osx-64 gfortran_osx-64"

          brew update
          brew install --cask basictex

          eval "$(/usr/libexec/path_helper)"
          #sudo apt-get install texlive

          conda install ${compilers} jupytext jupyterthemes jupyter_latex_envs emcee pymultinest ultranest

      - name: Install the package
        shell: bash -l {0}
        run: |
          pip install "black<24" fermipy
          pip install --upgrade speclite

          if [[ "${ISDEV}" == "true" ]]; then
            pip install --upgrade --pre astromodels
            #pip install git+https://github.com/threeML/astromodels.git@dev
          else
            pip install --upgrade astromodels
          fi
          pip install -e .
        env:
          ISDEV: ${{contains(github.ref, 'dev') || contains(github.base_ref, 'dev')}}

      - name: Execute the notebooks
        shell: bash -l {0}
        run: |
          # Make sure we fail in case of error
          set -e
          # copy the doc configuration over
          mkdir -p ~/.config/threeML
          cp threeML/data/doc_config.yml ~/.config/threeML/

          jupytext --to ipynb --pipe black --execute docs/md_docs/slow_execute/Fermipy_LAT.md

          jupytext --to ipynb --pipe black --execute docs/md_docs/slow_execute/LAT_Transient_Builder_Example.md

          #jupytext --to ipynb --pipe black --execute docs/md_docs/slow_execute/optimizer_docs.md

          mv docs/md_docs/slow_execute/*.ipynb docs/notebooks/
          ls docs/notebooks

        env:
          OMP_NUM_THREADS: 1
          MKL_NUM_THREADS: 1
          NUMEXPR_NUM_THREADS: 1
          MPLBACKEND: "Agg"

      - uses: actions/upload-artifact@v4
        with:
          name: notebooks-for-fermi-${{ github.sha }}
          path: docs/notebooks

  xspec_notebooks:
    name: "Build the XSPEC notebooks"
    runs-on: macos-12
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Cache conda
        uses: actions/cache@v4
        env:
          # Increase this value to reset cache if etc/example-environment.yml has not changed
          CACHE_NUMBER: 0
        with:
          path: ~/conda_pkgs_dir
          key: conda-xspec_notebooks-python-3.9-${{ hashFiles('ci/environment_xspec.yml') }}

      - name: Setup Miniconda
        uses: conda-incubator/setup-miniconda@v3
        with:
          auto-update-conda: true
          auto-activate-base: false
          miniforge-variant: Mambaforge
          activate-environment: test_env
          python-version: 3.9
          channels: threeml, conda-forge, xspecmodels, defaults
          environment-file: ci/environment_xspec.yml
          use-only-tar-bz2: true

      - name: Init Environment
        shell: bash -l {0}
        run: |
          # Make sure we fail in case of error
          set -e
          # miniconda_os=Linux
          # compilers="gcc_linux-64 gxx_linux-64 gfortran_linux-64"

          miniconda_os=MacOSX
          compilers="clang_osx-64 clangxx_osx-64 gfortran_osx-64"

          brew update
          brew install --cask basictex

          eval "$(/usr/libexec/path_helper)"
          #sudo apt-get install texlive

          mamba install ${compilers} jupytext jupyterthemes jupyter_latex_envs emcee pymultinest ultranest

      - name: Install the package
        shell: bash -l {0}
        run: |
          pip install zeus_mcmc dynesty "black<24"
          pip install --upgrade speclite
          #pip install git+https://github.com/desihub/speclite.git
          if [[ "${ISDEV}" == "true" ]]; then
            pip install --upgrade --pre astromodels
            #pip install git+https://github.com/threeML/astromodels.git@dev
          else
            pip install --upgrade astromodels
          fi
          pip install -e .
        env:
          ISDEV: ${{contains(github.ref, 'dev') || contains(github.base_ref, 'dev')}}
      - name: Execute the notebooks
        shell: bash -l {0}
        run: |
          # Make sure we fail in case of error
          set -e
          # copy the doc configuration over
          mkdir -p ~/.config/threeML
          cp threeML/data/doc_config.yml ~/.config/threeML/

          jupytext --to ipynb --pipe black --execute docs/md_docs/slow_execute/xspec_models.md
          jupytext --to ipynb --pipe black --execute docs/md_docs/slow_execute/joint_fitting_xrt_and_gbm_xspec_models.md
          jupytext --to ipynb --pipe black --execute docs/md_docs/slow_execute/Photometry_demo.md

          mv docs/md_docs/slow_execute/*.ipynb docs/notebooks/
          ls docs/notebooks

        env:
          OMP_NUM_THREADS: 1
          MKL_NUM_THREADS: 1
          NUMEXPR_NUM_THREADS: 1
          MPLBACKEND: "Agg"

      - uses: actions/upload-artifact@v4
        with:
          name: notebooks-for-xspec-${{ github.sha }}
          path: docs/notebooks

  multinest_notebooks:
    name: "Build the multinest notebooks"
    runs-on: macos-12
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Cache conda
        uses: actions/cache@v4
        env:
          # Increase this value to reset cache if etc/example-environment.yml has not changed
          CACHE_NUMBER: 0
        with:
          path: ~/conda_pkgs_dir
          key: conda-hal_notebooks-python-3.7-${{ hashFiles('ci/environment_hal.yml') }}

      - name: Setup Miniconda
        uses: conda-incubator/setup-miniconda@v3
        with:
          auto-update-conda: true
          auto-activate-base: false
          #mamba-version: "*"
          activate-environment: test_env
          python-version: ${{ matrix.python-version }}
          channels: conda-forge, threeml, defaults
          environment-file: ci/environment_hal.yml
          use-only-tar-bz2: true

      - name: Init Environment
        shell: bash -l {0}
        run: |
          # Make sure we fail in case of error
          set -e
          # miniconda_os=Linux
          # compilers="gcc_linux-64 gxx_linux-64 gfortran_linux-64"

          miniconda_os=MacOSX
          compilers="clang_osx-64 clangxx_osx-64 gfortran_osx-64"

          brew update
          brew install --cask basictex

          eval "$(/usr/libexec/path_helper)"
          #sudo apt-get install texlive

          conda install ${compilers} jupytext jupyterthemes jupyter_latex_envs emcee ultranest

      - name: Install the package
        shell: bash -l {0}
        run: |
          pip install zeus_mcmc dynesty "black<24"
          pip install --upgrade speclite
          #pip install git+https://github.com/desihub/speclite.git
          #pip install --no-binary :all: root_numpy

          if [[ "${ISDEV}" == "true" ]]; then
            pip install --upgrade --pre astromodels
            #pip install git+https://github.com/threeML/astromodels.git@dev
          else
            pip install --upgrade astromodels
          fi
          pip install -e .
        env:
          ISDEV: ${{contains(github.ref, 'dev') || contains(github.base_ref, 'dev')}}

      - name: Execute the notebooks
        shell: bash -l {0}
        run: |
          # Make sure we fail in case of error
          set -e
          # copy the doc configuration over
          mkdir -p ~/.config/threeML
          cp threeML/data/doc_config.yml ~/.config/threeML/

          jupytext --to ipynb --pipe black --execute docs/md_docs/slow_execute/Bayesian_tutorial.md

          jupytext --to ipynb --pipe black --execute docs/md_docs/slow_execute/sampler_docs.md

          jupytext --to ipynb --pipe black --execute docs/md_docs/slow_execute/Minimization_tutorial.md
          jupytext --to ipynb --pipe black --execute docs/md_docs/slow_execute/grb080916C.md

          jupytext --to ipynb --pipe black --execute docs/md_docs/slow_execute/joint_BAT_gbm_demo.md

          mv docs/md_docs/slow_execute/*.ipynb docs/notebooks/
          ls docs/notebooks

        env:
          OMP_NUM_THREADS: 1
          MKL_NUM_THREADS: 1
          NUMEXPR_NUM_THREADS: 1
          MPLBACKEND: "Agg"

      - uses: actions/upload-artifact@v4
        with:
          name: notebooks-for-multinest-${{ github.sha }}
          path: docs/notebooks

  upload_notebooks:
    needs: [fast_notebooks, fermi_notebooks, hal_notebooks, xspec_notebooks, multinest_notebooks]
    name: "Upload notebooks and trigger RTD"
    runs-on: macos-12

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

      - uses: actions/download-artifact@master
        with:
          name: notebooks-for-fermi-${{ github.sha }}
          path: docs/notebooks

      - uses: actions/download-artifact@master
        with:
          name: notebooks-for-fast-${{ github.sha }}
          path: docs/notebooks

      - uses: actions/download-artifact@master
        with:
          name: notebooks-for-hal-${{ github.sha }}
          path: docs/notebooks

      - uses: actions/download-artifact@master
        with:
          name: notebooks-for-xspec-${{ github.sha }}
          path: docs/notebooks

      - uses: actions/download-artifact@master
        with:
          name: notebooks-for-multinest-${{ github.sha }}
          path: docs/notebooks

      - name: Check that all notebooks are there
        shell: bash -l {0}
        run: |

          ls docs/notebooks

      - uses: actions/upload-artifact@v4
        with:
          name: notebooks-for-${{ github.sha }}
          path: docs/notebooks

      - name: Sleep for 10 min
        uses: juliangruber/sleep-action@v1
        with:
          time: 10m

      - name: Trigger RTDs build
        uses: dfm/rtds-action@main
        with:
          webhook_url: ${{ secrets.RTDS_WEBHOOK_URL }}
          webhook_token: ${{ secrets.RTDS_WEBHOOK_TOKEN }}
          commit_ref: ${{ github.ref }}

  api_doc:
    name: "Create the API stubs"
    runs-on: macos-12
    steps:
      - uses: actions/checkout@v4
        with:
          persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token
          fetch-depth: 0 # otherwise, you will failed to push refs to dest repo

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

      - name: Build the API doc
        run: |

          brew install c-blosc
          brew install hdf5

          pip3 install cython tempita
          pip3 install cython blosc2 h5py
          pip3 install numpy scipy numba astropy pandas
          pip3 install wheel pkgconfig numexpr

          #python setup.py develop
          pip3 install -e .

          brew install sphinx-doc pandoc

          pip3 install mock recommonmark
          pip3 install sphinx-rtd-dark-mode
          pip3 install -U sphinx

          sphinx-apidoc -f -o docs/api/ threeML

      - uses: actions/upload-artifact@v4
        with:
          name: api-stubs-for-${{ github.sha }}
          path: docs/api

  build_docs:
    name: "Build the Documentation"
    runs-on: macos-12
    needs: [upload_notebooks, api_doc]
    steps:

      - uses: actions/checkout@v4
        with:
          persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token
          fetch-depth: 0 # otherwise, you will failed to push refs to dest repo

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

      - name: Install package
        run: |

          brew install c-blosc
          brew install hdf5

          pip3 install wheel pkgconfig
          pip3 install tempita
          pip3 install cython blosc2 h5py
          pip3 install numpy scipy numba astropy

          brew install sphinx-doc pandoc

          pip3 install mock recommonmark
          pip3 install sphinx-rtd-dark-mode sphinx-math-dollar
          pip3 install -U sphinx
          pip3 install -r docs/requirements.txt

          if [[ "${ISDEV}" == "true" ]]; then
            pip install --upgrade --pre astromodels
            #pip install git+https://github.com/threeML/astromodels.git@dev
          else
            pip install --upgrade astromodels
          fi
          pip install -e .

          rm -rf docs/md_docs/*
        env:
          ISDEV: ${{contains(github.ref, 'dev') || contains(github.base_ref, 'dev')}}

      - uses: actions/download-artifact@master
        with:
          name: notebooks-for-${{ github.sha }}
          path: docs/notebooks

      - uses: actions/download-artifact@master
        with:
          name: api-stubs-for-${{ github.sha }}
          path: docs/notebooks/api

      - name: Build and Commit
        uses: sphinx-notes/pages@v2
        with:
          documentation_path: docs
          sphinx_version: 5.1.1
          requirements_path: docs/requirements.txt

      - name: Push changes
        if: github.event_name == 'push' #&& startsWith(github.event.ref, 'refs/tags')
        uses: ad-m/github-push-action@master
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          branch: gh-pages


Install and test using Conda

name: Install and test using Conda

on:
  #push:
  schedule:
    - cron: "0 20 * * 1"

jobs:
  test-install-threeml:
    strategy:
      fail-fast: false
      matrix:
        os: ["ubuntu-latest", "macos-latest"]
        python-version: [3.9]
        package: [" ", "--with-xspec", "--with-xspec --with-root", "--with-xspec --with-fermi"]
    runs-on: ${{ matrix.os }}
    steps:
    - name: Checkout
      uses: actions/checkout@v4
    - name: XCode
      uses: maxim-lobanov/setup-xcode@v1
      with:
        xcode-version: latest
      if: runner.os == 'macOS'
    - name: Setup Miniconda
      uses: conda-incubator/setup-miniconda@v3
      with:
        auto-update-conda: true
        auto-activate-base: true
        activate-environment: ""
        channels: conda-forge, xspecmodels, threeml, defaults
    - name: Install threeML
      run: |
        bash install_3ML.sh --batch --python ${{ matrix.python-version }} ${{ matrix.package }}
    - name: test threeML
      run: |
        source threeML_init.sh
        pytest -vv --pyargs threeML
        pytest -vv --pyargs astromodels
      env:
        OMP_NUM_THREADS: 1
        MKL_NUM_THREADS: 1
        NUMEXPR_NUM_THREADS: 1
        MPLBACKEND: "Agg"

  test-install-threeml-dev:
    strategy:
      fail-fast: false
      matrix:
        os: ["ubuntu-latest", "macos-latest"]
        python-version: [3.9]
        package: [" ", "--with-xspec", "--with-xspec --with-root", "--with-xspec --with-fermi"]
    runs-on: ${{ matrix.os }}
    steps:
    - name: Checkout
      uses: actions/checkout@v4
    - name: XCode
      uses: maxim-lobanov/setup-xcode@v1
      with:
        xcode-version: latest
      if: runner.os == 'macOS'
    - name: Setup Miniconda
      uses: conda-incubator/setup-miniconda@v3
      with:
        auto-update-conda: true
        auto-activate-base: true
        activate-environment: ""
        channels: conda-forge, xspecmodels, threeml, defaults
    - name: Install threeML
      run: |
        bash install_3ML.sh --batch --dev --python ${{ matrix.python-version }} ${{ matrix.package }}
    - name: test threeML
      run: |
        source threeML_init.sh
        pytest -vv --pyargs threeML
        pytest -vv --pyargs astromodels
      env:
        OMP_NUM_THREADS: 1
        MKL_NUM_THREADS: 1
        NUMEXPR_NUM_THREADS: 1
        MPLBACKEND: "Agg"


Close stale issues and PRs

name: Close stale issues and PRs
on:
  schedule:
  - cron: 30 1 * * *

jobs:
  stale:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/stale@v3
      with:
        repo-token: ${{ secrets.GITHUB_TOKEN }}
        stale-issue-message: 'This issue has become stale. Is there an update? We will close in 15 days'
        stale-pr-message: 'This PR has become stale. We will close in 60 days'
        stale-issue-label: 'no-issue-activity'
        stale-pr-label: 'no-pr-activity'
        days-before-pr-stale: 90
        days-before-issue-stale: 30
        days-before-issue-close: 15
        days-before-pr-close: 60