Lint and Test

name: Lint and Test

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

permissions:
  contents: read

env:
  PYTEST_ADDOPTS: '--color=yes'

jobs:
  lint:
    name: Lint
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        python-version:
          - "3.8"
          - "3.9"
          - "3.10"
          - "3.11"
          - "3.12"

    steps:
    - uses: actions/checkout@v4
      with:
        show-progress: false

    - name: Install Poetry
      uses: snok/install-poetry@v1.3.4
      with:
        version: 1.6.1
        virtualenvs-create: true
        virtualenvs-in-project: true

    - name: Set up Python ${{ matrix.python-version }}
      id: python
      uses: actions/setup-python@v5
      with:
        python-version: ${{ matrix.python-version }}
        allow-prereleases: true
        cache: poetry

    - name: Install dependencies
      if: steps.python.outputs.cache-hit != 'true'
      run: poetry install --no-interaction --no-root --with dev

    - name: Install library
      run: poetry install --no-interaction

    - name: Check formatting with `black`
      run: poetry run black --check .

    - name: Lint with `flake8`
      run: poetry run flake8 . --count --statistics

    - name: Check for typos
      run: poetry run typos --color always

  docs-tests:
    name: Documentation Tests
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4
      with:
        show-progress: false

    - name: Install Poetry
      uses: snok/install-poetry@v1.3.4
      with:
        version: 1.6.1
        virtualenvs-create: true
        virtualenvs-in-project: true

    - name: Set up Python
      id: python
      uses: actions/setup-python@v5
      with:
        python-version: "3.x"
        cache: poetry

    - name: Install dependencies
      run: poetry install --no-interaction --no-root --with dev,docs

    - name: Install library
      run: poetry install --no-interaction

    - name: Install Vault (for doctests)
      run: |
        curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
        echo "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" \
          | sudo tee /etc/apt/sources.list.d/hashicorp.list

        sudo apt update \
          -o Dir::Etc::sourceparts="-" \
          -o APT::Get::List-Cleanup="0" \
          -o Dir::Etc::sourcelist="sources.list.d/hashicorp.list"

        sudo apt install \
          vault-enterprise=1.7.2+ent \
          ;

        # We disble cap_ipc_lock here as its generally incompatabile with GitHub
        # Actions' runtime environments.
        sudo setcap cap_ipc_lock= /usr/bin/vault

    - name: Sphinx - doctest Build
      working-directory: ./docs
      run: |
        poetry run make doctest

  unit-tests:
    name: Unit Tests
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        python-version:
          - "3.8"
          - "3.9"
          - "3.10"
          - "3.11"
          - "3.12"

    steps:
    - uses: actions/checkout@v4
      with:
        show-progress: false

    - name: Install Poetry
      uses: snok/install-poetry@v1.3.4
      with:
        version: 1.6.1
        virtualenvs-create: true
        virtualenvs-in-project: true

    - name: Set up Python ${{ matrix.python-version }}
      id: python
      uses: actions/setup-python@v5
      with:
        python-version: ${{ matrix.python-version }}
        allow-prereleases: true
        cache: poetry

    - name: Install dependencies
      if: steps.python.outputs.cache-hit != 'true'
      run: poetry install --no-interaction --no-root --with dev

    - name: Install library
      run: poetry install --no-interaction

    - name: pytest tests/unit_tests
      run: |
        poetry run pytest \
          -rsxfE \
          --cov=hvac \
          --cov-report=xml:reports/coverage_units_py${{ matrix.python-version }}.xml \
          tests/unit_tests

    - name: Upload unit tests coverage artifacts
      uses: actions/upload-artifact@v4
      with:
        name: coverage_reports_${{ matrix.python-version }}
        path: reports/*.xml
        if-no-files-found: error
        retention-days: 1

  integration-tests:
    name: Integration Tests
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        python-version:
          - "3.8"
        vault-version:
          - "vault-enterprise=1.6.*+ent"
          - "vault-enterprise=1.7.*+ent"
          - "vault=1.11.*"
          - "vault=1.12.*"
          - "vault=1.13.*"
          - "vault=1.14.*"
          - "vault=1.15.*"
          - "vault=1.16.*"

    steps:
    - uses: actions/checkout@v4
      with:
        show-progress: false

    - name: Install Poetry
      uses: snok/install-poetry@v1.3.4
      with:
        version: 1.6.1
        virtualenvs-create: true
        virtualenvs-in-project: true

    - name: Set up Python ${{ matrix.python-version }}
      id: python
      uses: actions/setup-python@v5
      with:
        python-version: ${{ matrix.python-version }}
        allow-prereleases: true
        cache: poetry

    - name: Install dependencies
      if: steps.python.outputs.cache-hit != 'true'
      run: poetry install --no-interaction --no-root --with dev

    - name: Install library
      run: poetry install --no-interaction

    - name: Install Vault and Consul (for integration tests)
      run: |
        curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
        echo "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" \
          | sudo tee /etc/apt/sources.list.d/hashicorp.list

        sudo apt update \
          -o Dir::Etc::sourceparts="-" \
          -o APT::Get::List-Cleanup="0" \
          -o Dir::Etc::sourcelist="sources.list.d/hashicorp.list"

        sudo apt install \
          consul \
          ${{ matrix.vault-version }} \
          ;

        # We disble cap_ipc_lock here as its generally incompatabile with GitHub
        # Actions' runtime environments.
        sudo setcap cap_ipc_lock= /usr/bin/vault

    - name: pytest tests/integration_tests
      env:
        COVFILE: coverage_integration_py${{ matrix.python-version }}_${{ matrix.vault-version }}.xml
      run: |
        poetry run pytest \
          -rsxfE \
          --cov=hvac \
          --cov-report=xml:reports/${COVFILE//[^A-Za-z0-9\-_\.]/_} \
          tests/integration_tests

    - name: Set safe coverage report name
      id: vv
      env:
        VV: ${{ matrix.vault-version }}
      run: |
        echo "VV=${VV//[*+]/}" >> "$GITHUB_OUTPUT"

    - name: Upload integration tests coverage artifacts
      uses: actions/upload-artifact@v4
      with:
        name: coverage_reports_${{ matrix.python-version }}_${{ steps.vv.outputs.VV }}
        path: reports/*.xml
        if-no-files-found: error
        retention-days: 1

  upload-to-codecov:
    name: Upload to Codecov
    runs-on: ubuntu-latest
    needs:
      - unit-tests
      - integration-tests
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          show-progress: false

      - name: Download artifacts
        uses: actions/download-artifact@v4

      - name: Upload to Codecov
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          fail_ci_if_error: true


Release Drafter

name: Release Drafter

on:
  push:
    branches:
      - main
  workflow_dispatch: {}

permissions:
  contents: read

jobs:
  update_release_draft:
    permissions:
      contents: write
      pull-requests: read
    runs-on: ubuntu-latest
    steps:
      - name: Run release-drafter action
        id: release-drafter
        uses: release-drafter/release-drafter@v6
        with:
          disable-autolabeler: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Adding markdown
        run: |
          cat <<MKDOWN >> $GITHUB_STEP_SUMMARY
          ### Release Drafter :rocket:

          * **Draft Release URL**:
          [${{ steps.release-drafter.outputs.name }} (${{ steps.release-drafter.outputs.id }})](${{ steps.release-drafter.outputs.html_url }})
          * **Tag Name**: ${{ steps.release-drafter.outputs.tag_name }}
          MKDOWN


Release

name: Release

on:
  release:
    types: [published]

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
    - uses: actions/checkout@v4
      with:
        show-progress: false

    - name: Install Poetry
      uses: snok/install-poetry@v1.3.4
      with:
        version: 1.6.1
        virtualenvs-create: true
        virtualenvs-in-project: true

    - name: Set up Python
      id: python
      uses: actions/setup-python@v5
      with:
        python-version: '3.x'
        cache: poetry

    - name: Install dependencies
      if: steps.python.outputs.cache-hit != 'true'
      run: poetry install --no-interaction --no-root

    - name: Install library
      run: poetry install --no-interaction

    - name: Build
      run: poetry build

    - name: Upload artifact
      uses: actions/upload-artifact@v4
      with:
        name: package
        path: dist/
        retention-days: 7
        if-no-files-found: error

  pypi:
    needs: [build]
    runs-on: ubuntu-latest
    permissions:
      id-token: write
    environment:
        name: pypi-publishing
        url: https://pypi.org/project/hvac/
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: package
          path: dist

      - name: Show tree
        run: tree

      - name: Publish
        uses: pypa/gh-action-pypi-publish@release/v1

  asset:
    needs: [build]
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: package
          path: dist

      - name: Show tree
        run: tree

      - name: Add release asset
        uses: softprops/action-gh-release@69320dbe05506a9a39fc8ae11030b214ec2d1f87
        with:
          tag_name: ${{ github.event.release.tag_name }}
          fail_on_unmatched_files: true
          files: |
            dist/*


CI

---
name: CI

on:
  push:
    branches: [trunk]
    tags: ["*"]
  pull_request:
    branches: [trunk]
  workflow_dispatch:

env:
  FORCE_COLOR: "1"
  PIP_DISABLE_VERSION_CHECK: "1"

permissions:
  contents: read

jobs:
  tests:
    name: nox on ${{ matrix.python-version }}
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]

    steps:
      - name: Harden Runner
        uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
        with:
          disable-sudo: true
          egress-policy: block
          allowed-endpoints: >
            docs.djangoproject.com:443
            docs.python.org:443
            files.pythonhosted.org:443
            github.com:443
            pypi.org:443
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
      - name: "Install dependencies"
        run: |
          python -VV
          python -Im site
          python -Im pip install --upgrade pip setuptools wheel
          python -Im pip install --upgrade nox
          python -Im nox --version
      - name: "Run CI suite with nox"
        run: "python -Im nox --non-interactive --error-on-external-run --python ${{ matrix.python-version }}"


Build

name: Build

on: [push, pull_request]

jobs:
  build_wheels:
    name: Build wheels on ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-13, macos-14]

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

      - name: Build sdist
        run: |
          pipx run build --sdist
          python3 -c "import pathlib,glob;pathlib.Path('GITHUB_ENV').write_text('SDIST_PATH' + glob.glob('dist/*.tar.gz')[0])"

      - name: Build wheels
        uses: pypa/cibuildwheel@v2.18.1
        env:
          CIBW_BUILD:
            "cp37-* cp38-* cp39-* cp310-* cp311-* cp312-* pp39-* pp310-*"
          CIBW_TEST_COMMAND: "python -m pymunk.tests"
          CIBW_BUILD_VERBOSITY: 3
        with:
          package-dir: "$SDIST_PATH"

      - name: Upload wheel artifacts
        uses: actions/upload-artifact@v4
        if: ${{ github.ref == 'refs/heads/master'}}
        with:
          name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
          path: ./wheelhouse/*.whl
          retention-days: 7

      - name: Upload sdist artifact
        uses: actions/upload-artifact@v4
        if:
          ${{ github.ref == 'refs/heads/master' && matrix.os ==
          'windows-latest'}}
        with:
          name: sdist-${{ matrix.os }}-${{ strategy.job-index }}
          path: ./dist/*.tar.gz
          retention-days: 7

  build_wasm:
    name: Build wheels for wasm / emscripten
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
      - uses: actions/setup-python@v5
        with:
          python-version: "3.11.2"
      - run: |
          pip install pyodide-build>=0.23.3
          echo EMSCRIPTEN_VERSION=$(pyodide config get emscripten_version) >> $GITHUB_ENV
      - uses: mymindstorm/setup-emsdk@v14
        with:
          version: ${{ env.EMSCRIPTEN_VERSION }}
      - run: pyodide build
        env:
          PYMUNK_BUILD_SLIM: 1
      - uses: actions/upload-artifact@v4
        if: ${{ github.ref == 'refs/heads/master' }}
        with:
          path: ./dist/*.whl
          retention-days: 7


test

name: test

on: [push, pull_request]

jobs:
    fips-test:
        runs-on: ubuntu-latest
        steps:
        - uses: actions/checkout@v1
        - name: test
          run: ./test-linux.sh


Codespell

---
name: Codespell

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

permissions:
  contents: read

jobs:
  codespell:
    name: Check for spelling errors
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Codespell
        uses: codespell-project/actions-codespell@v2


Test suite

name: Test suite

on:
  push:
    branches:
      - master
    tags:
      - "*"
  pull_request:
    branches:
      - master

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

jobs:
  test:

    runs-on: ubuntu-latest
    continue-on-error: true
    strategy:
      matrix:
        # We test NumPy dev on 3.11
        python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
        requires: ['requirements.txt']
        include:
          - python-version: '3.8'
            requires: 'min-requirements.txt'

    steps:
    - name: Checkout repo
      uses: actions/checkout@v3
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}
        allow-prereleases: true
    - name: Install
      run: |
        set -eo pipefail
        python -m pip install --upgrade pip
        python -m pip install -r ${{ matrix.requires }}
        python -m pip install -r requirements-dev.txt
        if [[ "${{ matrix.python-version }}" == "3.11" ]]; then
          python -m pip install --only-binary numpy --pre --extra-index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple "numpy>=2.1.0.dev0"
        fi
        python -m pip install .
    - name: Lint
      run: |
        pipx run flake8 --ignore N802,N806,W504 --select W503 nitime/ tools/
    - name: Test
      run: |
        mkdir ~/for_test && cd ~/for_test && pytest --pyargs nitime --cov-report term-missing --cov=nitime


Build

name: Build

on:
  push:
    branches:
      - master
    tags:
      - "*"
  pull_request:
    branches:
      - master

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

jobs:
  job_metadata:
    runs-on: ubuntu-latest
    outputs:
      commit_message: ${{ steps.get_commit_message.outputs.commit_message }}
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 2
      - name: Print head git commit message
        id: get_commit_message
        run: |
          if [[ -z "$COMMIT_MSG" ]]; then
            COMMIT_MSG=$(git show -s --format=%s $REF)
          fi
          echo commit_message=$COMMIT_MSG | tee -a $GITHUB_OUTPUT
        env:
          COMMIT_MSG: ${{ github.event.head_commit.message }}
          REF: ${{ github.event.pull_request.head.sha }}

  build-sdist:
    name: Build sdist
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - name: Build sdist
        run: pipx run build -s
      - uses: actions/upload-artifact@v3
        with:
          name: sdist
          path: ./dist/*.tar.gz

  build-wheel:
    name: Build wheel for ${{ matrix.python }}-${{ matrix.buildplat[1] }}
    needs: [job_metadata]
    runs-on: ${{ matrix.buildplat[0] }}
    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') || contains(needs.job_metadata.outputs.commit_message, '[build wheels]')
    strategy:
      fail-fast: false
      matrix:
        buildplat:
          - [ubuntu-latest, musllinux_x86_64]
          - [ubuntu-latest, manylinux_aarch64]
          - [macos-13, macosx_x86_64]  # native Intel hardware
          - [windows-latest, win_amd64]
        python: ["cp38", "cp39", "cp310", "cp311", "cp312"]
        # No NumPy wheels on 3.8 aarch64 or musl
        exclude:
          - buildplat: [ubuntu-latest, manylinux_aarch64]
            python: "cp38"
          - buildplat: [ubuntu-latest, musllinux_x86_64]
            python: "cp38"
        include:
          # Manylinux and arm64 builds (on native hardware) are cheap, do all in one
          - { buildplat: ["ubuntu-latest", "manylinux_x86_64"], python: "*" }
          - { buildplat: ["macos-14", "macosx_arm64"], python: "*" }

    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - uses: actions/setup-python@v3

      - name: Update pip/pipx
        run: pip install --upgrade pip pipx

      # For aarch64 support
      # https://cibuildwheel.pypa.io/en/stable/faq/#emulation
      - uses: docker/setup-qemu-action@v3
        with:
          platforms: all
        if: runner.os == 'Linux' && endsWith(matrix.buildplat[1], 'aarch64')

      - name: Build wheel(s)
        run: pipx run --spec "cibuildwheel>=2.15" cibuildwheel
        env:
          CIBW_BUILD: ${{ matrix.python }}-${{ matrix.buildplat[1] }}

      - uses: actions/upload-artifact@v3
        with:
          name: ${{ matrix.python == '*' && 'all' || matrix.python }}-${{ startsWith(matrix.buildplat[1], 'macosx') && 'macosx' || matrix.buildplat[1] }}
          path: ./wheelhouse/*.whl

  test-sdist:
    name: Test sdist
    needs: [build-sdist]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/download-artifact@v3
        with:
          name: sdist
          path: ./dist
      - uses: actions/setup-python@v4
        with:
          python-version: "3.11"
      - name: Display Python version
        run: python -c "import sys; print(sys.version)"
      - name: Install sdist
        run: pip install dist/*.tar.gz
      - run: python -c 'import nitime; print(nitime.__version__)'
      - name: Install pytest
        run: pip install pytest
      - name: Run tests
        run: pytest -v --pyargs nitime

  pre-publish:
    runs-on: ubuntu-latest
    needs: [test-sdist, build-wheel]
    steps:
      - uses: actions/download-artifact@v3
        with:
          path: dist/
      - name: Check artifacts
        run: ls -lR
      - name: Consolidate and re-check
        run: |
          mv dist/*/*.{tar.gz,whl} dist
          rmdir dist/*/
          ls -lR
      - run: pipx run twine check dist/*

  publish:
    runs-on: ubuntu-latest
    environment: "Package deployment"
    needs: [pre-publish]
    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
    steps:
      - uses: actions/download-artifact@v3
        with:
          path: dist/
      - name: Consolidate artifacts
        run: |
          mv dist/*/*.{tar.gz,whl} dist
          rmdir dist/*/
      - uses: pypa/gh-action-pypi-publish@release/v1
        with:
          user: __token__
          password: ${{ secrets.PYPI_API_TOKEN }}


CodeQL

name: 'CodeQL'

on:
  push:
    branches: [ 'main' ]
  pull_request:
    branches: [ 'main' ]
  schedule:
    - cron: '42 2 12/16 * *'

jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-latest
    timeout-minutes: 360
    permissions:
      actions: read
      contents: read
      security-events: write

    strategy:
      fail-fast: false
      matrix:
        language:
          - javascript-typescript
          - python

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

    - name: Initialize CodeQL
      uses: github/codeql-action/init@v3
      with:
        languages: ${{ matrix.language }}
        queries: +security-extended,security-and-quality

    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@v3
      with:
        category: "/language:${{matrix.language}}"


Tests

name: Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    permissions:
      contents: read

    container:
      image: ghcr.io/weasyl/ci-base-image@sha256:9a366824361bf3123b28364ab6a4bd039ac765fafd5a1baab07f5c7c4485c007
      options: --user 1001

    services:
      weasyl-database:
        image: postgres:9.6
        env:
          POSTGRES_HOST_AUTH_METHOD: trust
          POSTGRES_USER: weasyl
          POSTGRES_DB: weasyl_test
        # probably ready by the time the tests run anyway; no need to add latency
        #options: >-
        #  --health-cmd pg_isready
        #  --health-interval 10s
        #  --health-timeout 5s
        #  --health-retries 5

      weasyl-memcached:
        image: memcached:1.5-alpine

    steps:
      - uses: actions/checkout@v4

      - name: Cache npm dependencies
        uses: actions/cache@v4
        with:
          path: ~/.npm
          key: cache-${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
          restore-keys: |
            cache-${{ runner.os }}-npm-

      - name: Cache Poetry dependencies
        uses: actions/cache@v4
        with:
          path: ~/.cache/pypoetry
          key: cache-${{ runner.os }}-poetry-${{ hashFiles('poetry.lock') }}
          restore-keys: |
            cache-${{ runner.os }}-poetry-

      - name: Create virtualenv
        run: python3 -m venv --system-site-packages .venv

      - name: Install npm dependencies
        run: npm ci

      - name: Install Poetry dependencies
        run: poetry install

      - name: Configure Weasyl
        run: |
          cp ci/site.config.txt config/
          cp config/weasyl-staff.example.py config/weasyl-staff.py
          printf %.8s "$GITHUB_SHA" > version.txt

      - name: Build assets
        run: node build.js

      - name: Test libweasyl
        env:
          WEASYL_TEST_SQLALCHEMY_URL: postgresql+psycopg2cffi://weasyl@weasyl-database/weasyl_test
        run: .venv/bin/coverage run -m pytest libweasyl.test libweasyl.models.test

      - name: Test weasyl
        env:
          WEASYL_APP_ROOT: .
          WEASYL_STORAGE_ROOT: testing
        run: .venv/bin/coverage run -m pytest weasyl.test

      - name: Create coverage report
        run: |
          .venv/bin/coverage combine
          .venv/bin/coverage xml

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage.xml
          token: ${{ secrets.CODECOV_TOKEN }}


Python package

name: Python package
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']

    steps:
    - uses: actions/checkout@v2
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v1
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install .[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 with pytest
      run: |
        # TODO: Figure out if we can run headless tests
        pytest tests/test_docs.py


Docker Package

name: Docker Package
on:
  push:
    tags: "*"
    branches:
      - master
  pull_request:

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build-and-publish-base:
    runs-on: ubuntu-latest
    if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' || ( github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository )
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Log into the Container registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: token
          password: ${{ secrets.GITHUB_TOKEN }}

      # Build and publish image with all sources
      - name: Extract metadata for the Docker image
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
      - name: Build and push the Docker image
        uses: docker/build-push-action@v6
        with:
          context: .
          file: slim.Dockerfile
          target: all
          push: ${{ github.actor != 'dependabot[bot]' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

  build-and-publish-targets:
    runs-on: ubuntu-latest
    if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' || ( github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository )
    strategy:
      fail-fast: false
      matrix:
        target: ["geo", "jupyter", "jupyter-geo"]
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Log into the Container registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: token
          password: ${{ secrets.GITHUB_TOKEN }}

      # Build and publish image with only geospatial sources
      - name: Extract metadata for the geospatial Docker image
        id: meta_target
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          flavor: |
            latest=auto
            suffix=-${{ matrix.target }},onlatest=true
      - name: Build and push the geosptial Docker image
        uses: docker/build-push-action@v6
        with:
          context: .
          file: slim.Dockerfile
          target: ${{ matrix.target }}
          push: ${{ github.actor != 'dependabot[bot]' }}
          tags: ${{ steps.meta_target.outputs.tags }}
          labels: ${{ steps.meta_target.outputs.labels }}


continuous-deployment

name: continuous-deployment

# on push events tagged with a version number
on:
  push:
    tags:
      - 'v*'

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - uses: actions/setup-python@v4
      with:
        python-version: '3.10'

    - name: Get version from tag
      id: tag_name
      run: |
        echo ::set-output name=current_version::${GITHUB_REF#refs/tags/v}
      shell: bash

    - name: Get Changelog Entry
      id: changelog_reader
      uses: mindsers/changelog-reader-action@v2
      with:
        version: ${{ steps.tag_name.outputs.current_version }}
        path: ./CHANGELOG.md

    - name: Create Release
      uses: actions/create-release@latest
      env:
        GITHUB_TOKEN: ${{ secrets.AccessToken }}
      with:
        tag_name: ${{ github.ref }}
        release_name: Release ${{ github.ref }}
        body: |
          Automated preprocessing of Next-Generation Sequencing data, including full (sc)ATAC-seq, ChIP-seq, and (sc)RNA-seq workflows.

          ${{ steps.changelog_reader.outputs.log_entry }}
        draft: false
        prerelease: false


docs

name: docs

on:
  push:

jobs:
  docs:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          persist-credentials: false

      - uses: actions/setup-python@v3
        with:
          python-version: 3.8

      - name: Install dependencies 🔨 & Build 🔧
        run: |
          # setup mambaforge
          wget -q -O Mambaforge.sh  "https://github.com/conda-forge/miniforge/releases/download/4.11.0-1/Mambaforge-$(uname)-$(uname -m).sh"
          bash Mambaforge.sh -b -p "${HOME}/conda" > /dev/null
          source "${HOME}/conda/etc/profile.d/conda.sh"
          source "${HOME}/conda/etc/profile.d/mamba.sh"
          mamba activate

          # load channels
          $CONDA/bin/conda config --add channels bioconda
          $CONDA/bin/conda config --add channels conda-forge

          # install seq2science with added docs requirements
          declare -a requirements=(
            "graphviz>=7"
            "importlib_metadata=4.11.4"
            "m2r2>=0.3.3"
            "networkx>=3"
            "sphinx>=6"
            "sphinx_rtd_theme>=1.2"
            "sphinx-argparse>=0.4"
          )
          cp requirements.yaml doc_reqs.yaml
          for pkg in "${requirements[@]}"; do
            echo "  - conda-forge::${pkg}" >> doc_reqs.yaml
          done
          mamba env create --name seq2science --file doc_reqs.yaml
          rm doc_reqs.yaml
          mamba activate seq2science
          pip3 install .

          # make the docs
          python docs/scripts/schemas.py
          python docs/scripts/rule_description.py
          python docs/scripts/gen_dags.py
          cp CHANGELOG.md docs/content
          sphinx-build docs/ build -W
          touch build/.nojekyll

      # only deploy
      - name: Deploy 📬
        uses: JamesIves/github-pages-deploy-action@releases/v3
        if: github.ref == 'refs/heads/master'
        with:
          ACCESS_TOKEN: ${{ secrets.AccessToken }}
          BRANCH: gh-pages # The branch the action should deploy to.
          FOLDER: build # The folder the action should deploy.


Tests and release

# (C) Copyright 2021 ECMWF.
#
# This software is licensed under the terms of the Apache Licence Version 2.0
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
# In applying this licence, ECMWF does not waive the privileges and immunities
# granted to it by virtue of its status as an intergovernmental organisation
# nor does it submit to any jurisdiction.
#

name: Tests and release

on:
  workflow_dispatch: {}

  # schedule:
  #   # Every day at 3:07am
  #   # on the "default" branch set in github (currently is develop)
  #   - cron:  '07 3 * * *'

  release:
    types: [created]

  push:
    branches:
      - "*"

  repository_dispatch:
    types:
    - cdsapi-updated
    - magics-python-updated
    - ecmwf-api-client-updated

jobs:
  quality:
    name: Code QA
    runs-on: ubuntu-latest
    steps:
    - run: sudo apt-get install -y pandoc # Needed by sphinx for notebooks
    - uses: actions/checkout@v4
    - uses: actions/setup-python@v5
      with:
        python-version: 3.x
    - uses: pre-commit/action@v3.0.1

  download-test-data:
    name: Download test data
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-python@v4
      with:
        python-version: 3.x

    - name: Tokens
      shell: python
      env:
        ECMWFAPIRC: ${{ secrets.ECMWFAPIRC }}
        CDSAPIRC: ${{ secrets.CDSAPIRC }}

      run: |
        import os
        # for n in ('ECMWFAPIRC', 'CDSAPIRC'):
        n = 'ECMWFAPIRC'
        m = os.path.expanduser("~/." + n.lower())
        if os.environ[n]:
            with open(m, "w") as f:
                print(os.environ[n], file=f)
    - run: mkdir test-data
    - run: echo "dataA" > test-data/dataA.txt
    - run: echo "dataB" > test-data/dataB.txt
    - run: cat test-data/dataA.txt
    - name: Tar files
      run: tar -cvf test-data.tar test-data
    - name: Upload Artifact
      uses: actions/upload-artifact@v3
      with:
        name: test-data
        path: test-data.tar

  tests-with-external-download:
    if: github.event_name == 'release' && github.event.action == 'created'
    strategy:
      fail-fast: true
      matrix:
        platform: ["ubuntu-latest", "macos-latest", "windows-latest"]
        python-version: ["3.10"]
    name: Long tests with external downloads Python ${{ matrix.python-version }} ${{ matrix.platform }}
    runs-on: ${{ matrix.platform }}
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}

    - name: Tokens
      shell: python
      env:
        ECMWFAPIRC: ${{ secrets.ECMWFAPIRC }}
        CDSAPIRC: ${{ secrets.CDSAPIRC }}
      run: |
        import os
        # for n in ('ECMWFAPIRC', 'CDSAPIRC'):
        n = 'ECMWFAPIRC'
        m = os.path.expanduser("~/." + n.lower())
        if os.environ[n]:
            with open(m, "w") as f:
                print(os.environ[n], file=f)
    - name: Install climetlab
      run: pip install -e .  # run: pip install .[interactive,tensorflow,zarr]
    - run: climetlab versions
    - name: Install test tools
      run: |
        pip install pytest
        pip freeze
    - name: Long Tests
      run: pytest --durations=0 -E release -k 'not test_notebooks'

  tests-notebooks:
    if: github.event_name == 'release' && github.event.action == 'created'
    strategy:
      matrix:
        platform: ["ubuntu-latest"]
        python-version: ["3.9"]
    name: Tests notebooks Python ${{ matrix.python-version }} ${{ matrix.platform }}
    runs-on: ${{ matrix.platform }}
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}

    - name: Tokens
      shell: python
      env:
        ECMWFAPIRC: ${{ secrets.ECMWFAPIRC }}
        CDSAPIRC: ${{ secrets.CDSAPIRC }}
      run: |
        import os
        # for n in ('ECMWFAPIRC', 'CDSAPIRC'):
        n = 'ECMWFAPIRC'
        m = os.path.expanduser("~/." + n.lower())
        if os.environ[n]:
            with open(m, "w") as f:
                print(os.environ[n], file=f)
    - name: Install climetlab
      run: pip install -e .  # run: pip install .[interactive,tensorflow,zarr]
    - run: climetlab versions
    - name: Install test tools
      run: |
        pip install pytest
        pip freeze
    - name: Tests notebooks
      run: pytest tests/documentation/test_notebooks.py

  short-tests:

    needs: [download-test-data]
    strategy:
      matrix:
        platform: ["ubuntu-latest", "macos-latest", "windows-latest"]
        python-version: ["3.9", "3.10"]

    name: Short tests Python ${{ matrix.python-version }} ${{ matrix.platform }}
    runs-on: ${{ matrix.platform }}
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}

    - name: Download test-data
      uses: actions/download-artifact@v3
      with:
        name: test-data
    - run: tar xvf test-data.tar
    - run: cat test-data/dataA.txt

    - name: Tokens
      # (this should be removed when tests are refactored)
      shell: python
      env:
        ECMWFAPIRC: ${{ secrets.ECMWFAPIRC }}
        CDSAPIRC: ${{ secrets.CDSAPIRC }}
      run: |
        import os
        # for n in ('ECMWFAPIRC', 'CDSAPIRC'):
        n = 'ECMWFAPIRC'
        m = os.path.expanduser("~/." + n.lower())
        if os.environ[n]:
            with open(m, "w") as f:
                print(os.environ[n], file=f)

    - run: pip install --upgrade pip

    - name: Install climetlab
      run: pip install -e .

    - run: climetlab versions
    - name: Install test tools
      run: |
        pip install pytest
        pip freeze
    - name: Check imports
      run: |
        pytest tests/test_imports.py
      env:
        SKIP_TEST_IMPORTS: 0
    - name: Tests
      run: |
        # -E flag is defined in conftest.py
        # notebooks need more dependencies
        # pytest --durations=0 -E release -k 'not test_notebooks'
        pytest --durations=10 -vv -E short

  deploy:
    name: Upload to Pypi and release
    needs: [short-tests, quality, tests-with-external-download, tests-notebooks]
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - 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 build wheel twine
      - name: Build and publish
        env:
          TWINE_USERNAME: __token__
          TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
        run: |
          python -m build
          twine upload dist/*


Coverage

# (C) Copyright 2021 ECMWF.
#
# This software is licensed under the terms of the Apache Licence Version 2.0
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
# In applying this licence, ECMWF does not waive the privileges and immunities
# granted to it by virtue of its status as an intergovernmental organisation
# nor does it submit to any jurisdiction.
#
name: Coverage

on:
  # schedule:
  #   # Every day at 3:07am
  #   - cron:  '07 3 * * *'

  workflow_dispatch: {}

jobs:
  coverage:

    runs-on: "ubuntu-latest"
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-python@v4
      with:
        python-version: "3.10"

    - name: Tokens
      shell: python
      env:
        ECMWFAPIRC: ${{ secrets.ECMWFAPIRC }}
        CDSAPIRC: ${{ secrets.CDSAPIRC }}
      run: |
        import os
        for n in ('ECMWFAPIRC', 'CDSAPIRC'):
            m = os.path.expanduser("~/." + n.lower())
            if os.environ[n]:
                with open(m, "w") as f:
                    print(os.environ[n], file=f)

    - name: Install climetlab
      run: pip install -e .[interactive,zarr,tensorflow]

    - name: Install test tools
      run: pip install pytest pytest-cov nbformat nbconvert ipykernel

    - name: Check imports
      env:
        SKIP_TEST_IMPORTS: 0
      run: pytest tests/test_imports.py

    - name: Tests with code coverage
      run: pytest --cov=climetlab --cov-report=html --cov-report=xml -E release

    - name: Codecov Upload
      uses: codecov/codecov-action@v2


QA and short tests

# (C) Copyright 2021 ECMWF.
#
# This software is licensed under the terms of the Apache Licence Version 2.0
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
# In applying this licence, ECMWF does not waive the privileges and immunities
# granted to it by virtue of its status as an intergovernmental organisation
# nor does it submit to any jurisdiction.
#

name: QA and short tests

on:
  workflow_dispatch: {}

  # schedule:
  #   # Every day at 3:07am
  #   # on the "default" branch set in github (currently is develop)
  #   - cron:  '07 3 * * *'

  pull_request:

jobs:
  quality:
    name: Code QA
    runs-on: ubuntu-latest
    steps:
    - run: sudo apt-get install -y pandoc # Needed by sphinx for notebooks
    - uses: actions/checkout@v4
    - uses: actions/setup-python@v5
      with:
        python-version: 3.x
    - uses: pre-commit/action@v3.0.1

  short-tests:
    name: Short tests
    runs-on: "ubuntu-latest"
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-python@v4
      with:
        python-version: "3.10"
    - name: Install climetlab
      run: pip install -e .
    - run: pip install pytest
    - run: pytest -vv -E short


Run tests

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

name: Run tests

on:
  push:
    branches: [ devel ]
  pull_request:
    branches: [ devel ]

jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ ubuntu-latest ]
        python-version: [ 3.8, 3.9, '3.10', '3.11' ]
        isMerge:
          - ${{ github.event_name == 'push' && github.ref == 'refs/heads/devel' }}
        exclude:
          - { isMerge: false, python-version: 3.9 }
          - { isMerge: false, python-version: '3.10' }
        include:
          - os: macos-latest
            python-version: '3.10'

    name: ${{ matrix.os }} / Python ${{ matrix.python-version }}

    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 non-Python dependencies on Ubuntu
        if: matrix.os == 'ubuntu-latest'
        run: |
          sudo apt-get update
          sudo apt-get install gfortran
          sudo apt-get install openmpi-bin libopenmpi-dev
          sudo apt-get install libhdf5-openmpi-dev

      - name: Install non-Python dependencies on macOS
        if: matrix.os == 'macos-latest'
        run: |
          brew install open-mpi
          brew install hdf5-mpi
          brew install libomp
          GFORTRAN_HOME=$(which gfortran || true)
          echo "GFORTRAN_HOME : $GFORTRAN_HOME"
          if [[ ! -f "$GFORTRAN_HOME" ]]; then
            gfort=$(find ${PATH//:/\/ } -name 'gfortran-*' -exec basename {} \; | sort | tail -n 1 || true)
            echo "Found $gfort"
            gfort_path=$(which ${gfort})
            folder=$(dirname ${gfort_path})
            ln -s ${gfort_path} ${folder}/gfortran
          fi
          echo "MPI_OPTS=--oversubscribe" >> $GITHUB_ENV

      - name: Print information on MPI and HDF5 libraries
        run: |
          ompi_info
          h5pcc -showconfig -echo || true

      - name: Upgrade pip
        run: |
          python -m pip install --upgrade pip

#      - name: Get pip cache dir
#        id: pip-cache-dir
#        run: |
#          echo "::set-output name=dir::$(python -m pip cache dir)"
#
#      - name: pip cache
#        uses: actions/cache@v2
#        id: pip-cache
#        with:
#          path: ${{ steps.pip-cache-dir.outputs.dir }}
#          key: ${{ matrix.os }}-${{ matrix.python-version }}-pip-${{ hashFiles('**/requirements.txt') }}
#          restore-keys: |
#            ${{ matrix.os }}-${{ matrix.python-version }}-pip-

      - name: Determine directory of parallel HDF5 library
        run: |
          if [[ "${{ matrix.os }}" == "ubuntu-latest" ]]; then
            HDF5_DIR=$(dpkg -L libhdf5-openmpi-dev | grep libhdf5.so | xargs dirname)
          elif [[ "${{ matrix.os }}" == "macos-latest" ]]; then
            HDF5_DIR=$(brew list hdf5-mpi | grep "libhdf5.dylib" | xargs dirname | xargs dirname)
          fi
          echo $HDF5_DIR
          echo "HDF5_DIR=$HDF5_DIR" >> $GITHUB_ENV

      - name: Download a specific release of PETSc
        run: |
          git clone --depth 1 --branch v3.20.5 https://gitlab.com/petsc/petsc.git

      - name: Install PETSc with complex support, and test it
        working-directory: ./petsc
        run: |
          export PETSC_DIR=$(pwd)
          export PETSC_ARCH=petsc-cmplx
          ./configure --with-scalar-type=complex --with-fortran-bindings=0 --have-numpy=1
          make all check
          echo "PETSC_DIR=$PETSC_DIR" >> $GITHUB_ENV
          echo "PETSC_ARCH=$PETSC_ARCH" >> $GITHUB_ENV

      - name: Install petsc4py
        working-directory: ./petsc
        run: |
          python -m pip install wheel Cython numpy
          python -m pip install src/binding/petsc4py

      - name: Install Python dependencies
        run: |
          export CC="mpicc" HDF5_MPI="ON"
          python -m pip install -r requirements.txt
          python -m pip install -r requirements_extra.txt --no-build-isolation
          python -m pip list

      - name: Check h5py installation
        run: |
            python -c "from h5py import File; print(File)"

      - name: Install project
        run: |
          python -m pip install .
          python -m pip freeze

      - name: Initialize test directory
        run: |
          mkdir pytest
          cp mpi_tester.py pytest

      - name: Run single-process tests with Pytest
        working-directory: ./pytest
        run: |
          export PSYDAC_MESH_DIR=$GITHUB_WORKSPACE/mesh
          export OMP_NUM_THREADS=2
          python -m pytest -n auto --pyargs psydac -m "not parallel and not petsc"

      - name: Run MPI tests with Pytest
        working-directory: ./pytest
        run: |
          export PSYDAC_MESH_DIR=$GITHUB_WORKSPACE/mesh
          export OMP_NUM_THREADS=2
          python mpi_tester.py --mpirun="mpiexec -n 4 ${MPI_OPTS}" --pyargs psydac -m "parallel and not petsc"

      - name: Run single-process PETSc tests with Pytest
        working-directory: ./pytest
        run: |
          export PSYDAC_MESH_DIR=$GITHUB_WORKSPACE/mesh
          export OMP_NUM_THREADS=2
          python -m pytest -n auto --pyargs psydac -m "not parallel and petsc"

      - name: Run MPI PETSc tests with Pytest
        working-directory: ./pytest
        run: |
          export PSYDAC_MESH_DIR=$GITHUB_WORKSPACE/mesh
          export OMP_NUM_THREADS=2
          python mpi_tester.py --mpirun="mpiexec -n 4 ${MPI_OPTS}" --pyargs psydac -m "parallel and petsc"

      - name: Remove test directory
        if: ${{ always() }}
        run: |
          rm -rf pytest


documentation

name: documentation

on:
  push:
    branches: [ devel ]
  pull_request:
    branches: [ devel ]

permissions:
  contents: read
  pages: write
  id-token: write

jobs:
  build_docs:
    runs-on: ubuntu-latest
    env:
      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN}}
    steps:
    - name: Checkout
      uses: actions/checkout@v3
    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: 3.9
    - name: Install non-Python dependencies on Ubuntu
      run: |
        sudo apt update
        sudo apt install graphviz
    - name: Install Python dependencies
      run: |
        python -m pip install -r docs_requirements.txt
    - name: Make the sphinx doc
      run: |
        rm -rf docs/source/modules/STUBDIR
        make -C docs clean
        make -C docs html
        python docs/update_links.py
    - name: Setup Pages
      uses: actions/configure-pages@v3
    - name: Upload artifact
      uses: actions/upload-pages-artifact@v1
      with:
        path: 'docs/build/html'

  deploy_docs:
    if: github.event_name != 'pull_request'
    needs: build_docs
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
    - name: Deploy to GitHub Pages
      id: deployment
      uses: actions/deploy-pages@v2


Wheel Builder

# GitHub Workflow to build, test, and upload wheels

# TODO: Implement GitHub's caching to speed up builds
# TODO: Decide on specific versions of dependencies, and our pinning strategy
# TODO: Implement ARM-based macOS builds on a self-hosted runner
# TODO: Raspberry Pi builds
# TODO: Linting

name: Wheel Builder

on: [push, pull_request]

jobs:
  build_wheels:
    name: Build for ${{ matrix.cibw-build }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
        # - os: windows-latest
        #   python-version: 3.8
        #   cibw-build: cp38-win_amd64
        # - os: windows-latest
        #   python-version: 3.9
        #   cibw-build: cp39-win_amd64
        # - os: windows-latest
        #   python-version: '3.10'
        #   cibw-build: cp310-win_amd64
        # - os: windows-latest
        #   python-version: 3.11
        #   cibw-build: cp311-win_amd64
        - os: ubuntu-latest
          python-version: 3.8
          cibw-build: cp38-manylinux_x86_64
        - os: ubuntu-latest
          python-version: 3.9
          cibw-build: cp39-manylinux_x86_64
        - os: ubuntu-latest
          python-version: '3.10'
          cibw-build: cp310-manylinux_x86_64
        - os: ubuntu-latest
          python-version: 3.11
          cibw-build: cp311-manylinux_x86_64
        # - os: macos-latest
        #   python-version: 3.8
        #   cibw-build: cp38-macosx_x86_64
        # - os: macos-latest
        #   python-version: 3.9
        #   cibw-build: cp39-macosx_x86_64
        # - os: macos-latest
        #   python-version: '3.10'
        #   cibw-build: cp310-macosx_x86_64
        # - os: macos-latest
        #   python-version: 3.11
        #   cibw-build: cp311-macosx_x86_64
        # I have no idea how to use the ARM runners on GitHub. Supposedly they exist but I can't figure them out.
        # So for now we'll just manually build and upload Apple Silicon wheels? Last updated Oct 2 2023
        # - os: macos-13-arm64
        #   python-version: 3.8
        #   cibw-build: cp38-macosx_universal2
        # - os: macos-13-arm64
        #   python-version: 3.9
        #   cibw-build: cp39-macosx_universal2
        # - os: macos-13-arm64
        #   python-version: '3.10'
        #   cibw-build: cp310-macosx_universal2
        # - os: macos-13-arm64
        #   python-version: 3.11
        #   cibw-build: cp311-macosx_universal2

    steps:
      - name: Checkout MPF-MC
        uses: actions/checkout@v4
      - name: Setup python
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}
      - name: Run cibuildwheel
        uses: pypa/cibuildwheel@v2.16.1  # Oct 2, 2023
        env:
          CIBW_BEFORE_ALL_LINUX: > # This is done here and not as its own step as this runs inside the cibw containered environment
            yum install -y SDL2.x86_64 SDL2-devel.x86_64 SDL2_image.x86_64 SDL2_image-devel.x86_64
            SDL2_mixer.x86_64 SDL2_mixer-devel.x86_64 gstreamer1.x86_64 gstreamer1-devel.x86_64 &&
            python -m pip install --upgrade pip &&
            pip install --upgrade setuptools wheel build &&
            git clone --recursive --branch ${{ github.ref_name }} https://github.com/missionpinball/mpf.git _mpf ||
            git clone --recursive --branch `python get_version.py` https://github.com/missionpinball/mpf.git _mpf ||
            git clone --recursive --branch dev https://github.com/missionpinball/mpf.git _mpf &&
            pip install -e _mpf
          CIBW_BEFORE_ALL_MACOS: >
            brew install SDL2 SDL2_mixer SDL2_image SDL2_ttf gstreamer
          CIBW_BEFORE_ALL: >
            python -m pip install --upgrade pip &&
            pip install --upgrade setuptools wheel build &&
            git clone --recursive --branch ${{ github.ref_name }} https://github.com/missionpinball/mpf.git _mpf ||
            git clone --recursive --branch `python get_version.py` https://github.com/missionpinball/mpf.git _mpf ||
            git clone --recursive --branch dev https://github.com/missionpinball/mpf.git _mpf &&
            pip install -e _mpf
          CIBW_BUILD: ${{ matrix.cibw-build }}
          CIBW_BUILD_VERBOSITY: 3
      - name: Upload wheels
        uses: actions/upload-artifact@v3
        with:
          name: mpf-mc_wheels
          path: ./wheelhouse/*.whl

  make_sdist:
    name: Make SDist
    runs-on: ubuntu-latest
    steps:
    - name: Check out MPF-MC
      uses: actions/checkout@v3
      with:
        fetch-depth: 0
    - name: Build SDist
      run: >
        sudo apt-get update &&
        sudo apt-get -y remove libunwind-14 &&
        sudo apt-get -y install libunwind-dev libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev
        gstreamer1.0-plugins-base gstreamer1.0-plugins-base gstreamer1.0-plugins-bad
        gstreamer1.0-plugins-ugly libgstreamer1.0-dev &&
        pip install --upgrade setuptools wheel build &&
        python -m build --sdist
    - name: Upload SDist
      uses: actions/upload-artifact@v3
      with:
        name: mpf-mc_wheels
        path: dist/*.tar.gz

  test_wheels:
    name: Test Python ${{ matrix.python-version }} on ${{ matrix.os }}
    needs: [build_wheels]
    strategy:
      fail-fast: false
      matrix:
        python-version: [3.8, 3.9, '3.10', 3.11]
        #os: [ubuntu-latest, macos-latest, windows-latest]
        os: [ubuntu-latest]
        include:
          - os: ubuntu-latest
            python-version: 3.11
            run-tests: true
    runs-on: ${{ matrix.os }}
    env:
      DISPLAY: ':99.0'
    steps:
    - name: Install runtime libraries on macOS
      if: runner.os == 'macOS'
      run: brew install SDL2 SDL2_mixer gstreamer
    - name: Install runtime libraries on Linux
      if: runner.os == 'linux'
      run: |
        sudo apt-get update
        sudo apt-get -y install libsdl2-2.0 libsdl2-mixer-2.0 gstreamer-1.0 gstreamer1.0-plugins-base gstreamer1.0-plugins-base gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly xvfb
    - name: Set up python
      uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install runtime dependencies via pip
      run: |
        python -m pip install --upgrade pip
        pip install --upgrade setuptools wheel coveralls prospector==1.3.1
    - name: Download the newly-built wheel
      uses: actions/download-artifact@v3
      with:
        name: mpf-mc_wheels
        path: dist
    - name: Clone & install MPF  # try to find a matching version before we default to dev
      run: >
        git clone --recursive --branch ${{ github.ref_name }} https://github.com/missionpinball/mpf.git _mpf ||
        git clone --recursive --branch `python get_version.py` https://github.com/missionpinball/mpf.git _mpf ||
        git clone --recursive --branch dev https://github.com/missionpinball/mpf.git _mpf &&
        pip install -e _mpf
    - name: List wheels in dist
      run: ls -l dist
    - name: Install MPF-MC from new wheel
      shell: bash  # Need bash on windows to use the if statement

      # We need some logic here to force pip to use the new wheel we just built. Otherwise if we're on a pull request, it will try to install from pypi which won't test the new wheel.
      # We can't use --no-index because we need to install the rest of the dependencies from pypi
      run: |
        if [ "${{ runner.os }}" == "Linux" ]; then
          platform="manylinux_2_17_x86_64.manylinux2014_x86_64"
        elif [ "${{ runner.os }}" == "macOS" ]; then
          platform="macosx_10_9_x86_64"
        elif [ "${{ runner.os }}" == "Windows" ]; then
          platform="win_amd64"
        fi

        python_version_nodot=$(echo "${{ matrix.python-version }}" | tr -d '.')
        wheel_file=$(ls dist/mpf_mc-*cp${python_version_nodot}-*-${platform}.whl)
        pip install "$wheel_file"
    - name: Run tests  # Can't figure out how to run tests on mac or windows, but I guess that's ok? At least we test the wheel installs? TODO?
      if: ${{ matrix.run-tests }}
      run: |
        /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1280x720x24 -ac +extension GLX
        coverage3 run --concurrency=thread -m unittest discover -v mpfmc.tests
        coverage3 run -a --concurrency=thread -m unittest discover -v mpfmc.integration
    - name: Upload coverage data to coveralls.io
      run: coveralls --service=github
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        COVERALLS_FLAG_NAME: ${{ matrix.python-version }}-${{ matrix.os }}
        COVERALLS_PARALLEL: true

  publish_to_pypi:  # only if this release has a tag and is a push from us (e.g. not a pull request)
    name: Publish to PYPI
    needs: [test_wheels, make_sdist]
    runs-on: ubuntu-latest
    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
    environment:
      name: pypi
      url: https://pypi.org/p/mpf
    permissions:
      id-token: write
    steps:
    - name: Download wheels
      uses: actions/download-artifact@v3
      with:
        name: mpf-mc_wheels
        path: dist
    - name: Publish to PyPI
      uses: pypa/gh-action-pypi-publish@release/v1

  coveralls:
    name: Finalize Coveralls
    needs: test_wheels
    runs-on: ubuntu-latest
    container: python:3-slim
    steps:
    - name: Finished
      run: |
        pip3 install --upgrade coveralls
        coveralls --service=github --finish
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


CI

name: CI
concurrency:
  group: >-
    ${{ github.workflow }}-
    ${{ github.ref_type }}-
    ${{ github.event.pull_request.number || github.sha }}
  cancel-in-progress: true
on:
  workflow_dispatch:
    inputs:
      git-ref:
        description: Git Ref (Optional)
        required: false
  push:
    paths-ignore:
      - ".editorconfig"
      - ".gitattributes"
      - ".gitignore"
      - ".gitmodules"
      - "*.ini"
      - "*.md"
      - "**/*.txt"
      - "examples/**"
      - "news/**"
      - "peeps/**"
    branches:
      - main
  pull_request:
    paths-ignore:
      - ".editorconfig"
      - ".gitattributes"
      - ".gitignore"
      - ".gitmodules"
      - "*.ini"
      - "*.md"
      - "**/*.txt"
      - "examples/**"
      - "news/**"
      - "peeps/**"
permissions:
  contents: read # to fetch code (actions/checkout)
jobs:
  lint:
    name: Check code linting
    runs-on: ubuntu-latest
    env:
      PIPENV_DEFAULT_PYTHON_VERSION: ${{ matrix.python-version }}
      PYTHONWARNINGS: ignore:DEPRECATION
      PYTHONIOENCODING: "utf-8"
      GIT_ASK_YESNO: "false"
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: 3.x
      - run: |
          python -m pip install pre-commit
          pre-commit run --all-files --verbose --show-diff-on-failure
  vendor:
    name: Vendoring
    needs: lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: 3.x
      - run: |
          python -m pip install --upgrade wheel invoke parver beautifulsoup4 towncrier requests parse hatch-fancy-pypi-readme semver
          python -m invoke vendoring.update
  tests:
    name: ${{matrix.os}} / ${{ matrix.python-version }}
    needs: lint
    runs-on: ${{ matrix.os }}-latest
    strategy:
      fail-fast: false
      matrix:
        python-version: [3.8, 3.9, "3.10", 3.11, 3.12]
        os: [MacOS, Ubuntu, Windows]

    steps:
      - uses: actions/checkout@v4

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

      - name: Get python path
        id: python-path
        run: |
          echo "path=$(python -c 'import sys; print(sys.executable)')" >> $GITHUB_OUTPUT
      - name: Install latest pip, setuptools, wheel
        run: |
          python -m pip install --upgrade pip setuptools wheel
      - name: Install dependencies
        env:
          PIPENV_DEFAULT_PYTHON_VERSION: ${{ matrix.python-version }}
          PYTHONWARNINGS: ignore:DEPRECATION
          PYTHONIOENCODING: "utf-8"
          GIT_ASK_YESNO: "false"
        run: |
          git submodule sync
          git submodule update --init --recursive
          python -m pip install -e . --upgrade
          pipenv install --deploy --dev --python=${{ steps.python-path.outputs.path }}
      - name: Run pypiserver Windows
        run: |
         cmd /c start pipenv run pypi-server run -v --host=0.0.0.0 --port=8080 --hash-algo=sha256 --disable-fallback ./tests/pypi/ ./tests/fixtures
        if: ${{matrix.os  == 'Windows' }}
      - name: Run pypiserver Mac
        run: |
          pipenv run pypi-server run -v --host=0.0.0.0 --port=8080 --hash-algo=sha256 --disable-fallback ./tests/pypi/ ./tests/fixtures &
        if: ${{matrix.os  == 'MacOS' }}
      - name: Run pypiserver Ubuntu
        run: |
          pipenv run pypi-server run -v --host=0.0.0.0 --port=8080 --hash-algo=sha256 --disable-fallback ./tests/pypi/ ./tests/fixtures &
        if: ${{matrix.os  == 'Ubuntu' }}
      - name: Run tests
        env:
          PIPENV_DEFAULT_PYTHON_VERSION: ${{ matrix.python-version }}
          PYTHONWARNINGS: ignore:DEPRECATION
          PIPENV_NOSPIN: "1"
          CI: "1"
          GIT_ASK_YESNO: "false"
          PYPI_VENDOR_DIR: "./tests/pypi/"
          PYTHONIOENCODING: "utf-8"
          GIT_SSH_COMMAND: ssh -o StrictHostKeyChecking=accept-new -o CheckHostIP=no
        run: |
          pipenv run pytest -ra -n auto -v --fulltrace tests

  build:
    name: Build Package
    needs: lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: 3.x
      - run: pip install -U build twine
      - run: |
          python -m build
          twine check dist/*


Upload Python Package

name: Upload Python Package

on:
  push:
    # Sequence of patterns matched against refs/tags
    tags:
      - v[0-9]+.[0-9]+.*  # add .* to allow dev releases

permissions: {}
jobs:
  deploy:
    permissions:
      contents: write # to create a release (actions/create-release)

    name: pipenv PyPI Upload
    runs-on: ubuntu-latest
    env:
      CI: "1"

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

    - name: Create Release
      id: create_release
      uses: ncipollo/release-action@v1
      with:
        tag: ${{ github.ref }}
        name: Release ${{ github.ref_name }}
        draft: false
        prerelease: false
        token: ${{ secrets.GITHUB_TOKEN }}

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

    - name: Install dependencies
      run: |
        python -m pip install --upgrade --upgrade-strategy=eager pip setuptools build wheel twine
        python -m pip install -e . --upgrade
        python -m pipenv install --dev
      env:
        PIPENV_DEFAULT_PYTHON_VERSION: "3.10"

    - name: Build wheels
      run: |
        python -m pipenv run python -m build

    # to upload to test pypi, pass repository_url: https://test.pypi.org/legacy/ and use secrets.TEST_PYPI_TOKEN
    - name: Publish a Python distribution to PyPI
      uses: pypa/gh-action-pypi-publish@release/v1
      with:
        user: __token__
        password: ${{ secrets.PYPI_TOKEN }}
        # repository_url: https://test.pypi.org/legacy/
        packages-dir: dist/

    # git push https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git HEAD:master
    # we need to use a deploy key for this to get around branch protection as the default token fails
    - name: Pre-bump
      run: |
        git config --local user.name 'github-actions[bot]'
        git config --local user.email 'github-actions[bot]@users.noreply.github.com'
        python -m pipenv run inv release.bump-version --dev --commit

    - name: Push changes
      uses: ad-m/github-push-action@master
      with:
        github_token: ${{ secrets.REPO_TOKEN }}


ruff

# https://beta.ruff.rs
name: ruff
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  workflow_dispatch:
jobs:
  ruff:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - run: pip install --user ruff
    - run: ruff check --output-format=github .


Test with pytest

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

name: Test with pytest

on:
  pull_request:
  push:

jobs:
  build:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        python-version: ["3.7", "3.11", "3.12"]  # no particular need for 3.9 or 3.10
        os: [macos-latest, ubuntu-latest, windows-latest]
    steps:
    - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633  # v4.1.2
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d  # v4.6.0
      with:
        python-version: ${{ matrix.python-version }}
    - name: Upgrade pip
      run: >-
        python -m pip install
        --upgrade
        --disable-pip-version-check
        pip
    - name: Perform package installs
      run: >-
        pip install
        .
        pytest
        pytest-cov
    - name: Test with pytest
      run: pytest


Keep pre-commit hooks up to date

# Copyright (c) 2023 Sebastian Pipping <sebastian@pipping.org>
# Licensed under the Apache License Version 2.0

name: Keep pre-commit hooks up to date

on:
  schedule:
    - cron: '0 16 * * 5'  # Every Friday 4pm
  workflow_dispatch:

# NOTE: This will drop all permissions from GITHUB_TOKEN except metadata read,
#       and then (re)add the ones listed below:
permissions:
  contents: write
  pull-requests: write

jobs:
  pre_commit_autoupdate:
    name: Detect outdated pre-commit hooks
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633  # v4.1.2

      - name: Set up Python 3.11
        uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d  # v5.1.0
        with:
          python-version: 3.11

      - name: Install pre-commit
        run: |-
          pip install \
            --disable-pip-version-check \
            --no-warn-script-location \
            --user \
            pre-commit
          echo "PATH=${HOME}/.local/bin:${PATH}" >> "${GITHUB_ENV}"

      - name: Check for outdated hooks
        run: |-
          pre-commit autoupdate
          git diff -- .pre-commit-config.yaml

      - name: Create pull request from changes (if any)
        id: create-pull-request
        uses: peter-evans/create-pull-request@70a41aba780001da0a30141984ae2a0c95d8704e  # v6.0.2
        with:
          author: 'pre-commit <pre-commit@tools.invalid>'
          base: main
          body: |-
            For your consideration.

            :warning: Please **CLOSE AND RE-OPEN** this pull request so that [further workflow runs get triggered](https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#triggering-further-workflow-runs) for this pull request.
          branch: precommit-autoupdate
          commit-message: "pre-commit: Autoupdate"
          delete-branch: true
          draft: true
          labels: enhancement
          title: "pre-commit: Autoupdate"

      - name: Log pull request URL
        if: "${{ steps.create-pull-request.outputs.pull-request-url }}"
        run: |
          echo "Pull request URL is: ${{ steps.create-pull-request.outputs.pull-request-url }}"


Run pre-commit

# Copyright (c) 2023 Sebastian Pipping <sebastian@pipping.org>
# Licensed under the Apache License Version 2.0

name: Run pre-commit

# Drop permissions to minimum for security
permissions:
  contents: read

on:
  pull_request:
  push:
  schedule:
    - cron: '0 2 * * 5'  # Every Friday at 2am
  workflow_dispatch:

jobs:
  pre_commit_run:
    name: Run pre-commit
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633  # v4.1.2

      - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d  # v5.1.0
        with:
          python-version: 3.11

      - name: Install yapf (to be available to pre-commit)
        run: |-
          pip install \
            --disable-pip-version-check \
            --no-warn-script-location \
            --user \
            .
          echo "PATH=${HOME}/.local/bin:${PATH}" >> "${GITHUB_ENV}"

      - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd  # v3.0.1


Release

name: Release

on:
  push:
    tags:
    - '*'

jobs:
  build:
    if: github.repository == 'jazzband/django-taggit'
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0

      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: 3.8

      - name: Install dependencies
        run: |
          python -m pip install -U pip
          python -m pip install -U setuptools twine wheel

      - name: Build package
        run: |
          python setup.py --version
          python setup.py sdist --format=gztar bdist_wheel
          twine check dist/*

      - name: Upload packages to Jazzband
        if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
        uses: pypa/gh-action-pypi-publish@master
        with:
          user: jazzband
          password: ${{ secrets.JAZZBAND_RELEASE_KEY }}
          repository_url: https://jazzband.co/projects/django-taggit/upload


Test

name: Test

on: [push, pull_request]

jobs:
  build:
    name: Python ${{ matrix.python-version }}
    runs-on: ubuntu-latest

    # The maximum number of minutes to let a workflow run
    # before GitHub automatically cancels it. Default: 360
    timeout-minutes: 30

    strategy:
      # When set to true, GitHub cancels
      # all in-progress jobs if any matrix job fails.
      fail-fast: false

      max-parallel: 5

      matrix:
        python-version:
          - "3.8"
          - "3.9"
          - "3.10"
          - "3.11"

    steps:
      - uses: actions/checkout@v2

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

      - name: Get pip cache dir
        id: pip-cache
        run: echo "::set-output name=dir::$(pip cache dir)"

      - name: Cache
        uses: actions/cache@v2
        with:
          path: ${{ steps.pip-cache.outputs.dir }}
          key: ${{ matrix.python-version }}-v1-${{ hashFiles('**/setup.py') }}-${{ hashFiles('**/tox.ini') }}
          restore-keys: |
            ${{ matrix.python-version }}-v1-

      - name: Install Python dependencies
        run: |
          python -m pip install --upgrade pip
          python -m pip install --upgrade tox tox-gh-actions

      - name: Tox tests
        run: tox -v

      - name: Upload coverage
        uses: codecov/codecov-action@v1
        with:
          name: Python ${{ matrix.python-version }}


CI

name: CI

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

jobs:

  lint-build:
    name: Linting
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
    steps:
    - uses: actions/checkout@v2
    - name: Set up Python 3.9
      uses: actions/setup-python@v2
      with:
        python-version: 3.9
    - name: Install dev dependencies
      run: |
          python -m pip install --upgrade pip
          pip install -U invoke pycodestyle flake8
    - name: Lint
      run: |
          invoke test --style;

  docs-build:
    name: Docs
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
    steps:
    - uses: actions/checkout@v2
    - name: Set up Python 3.9
      uses: actions/setup-python@v2
      with:
        python-version: 3.9
    - name: Install dev dependencies
      run: |
          python -m pip install --upgrade pip
          pip install -U invoke sphinx tornado pscript>=0.5.6 webruntime dialite;
    - name: Build docs
      run: |
        python -c 'import flexx.ui';
        invoke docs --clean --build;

  test-builds:
    name: ${{ matrix.name }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: Test Linux py35
            os: ubuntu-latest
            pyversion: '3.5'
          - name: Test Linux py36
            os: ubuntu-latest
            pyversion: '3.6'
          - name: Test Linux py37
            os: ubuntu-latest
            pyversion: '3.7'
          - name: Test Linux py38
            os: ubuntu-latest
            pyversion: '3.8'
          - name: Test Linux py39
            os: ubuntu-latest
            pyversion: '3.9'
    steps:
    - uses: actions/checkout@v2
    - name: Set up Python ${{ matrix.pyversion }}
      uses: actions/setup-python@v2
      with:
        python-version: ${{ matrix.pyversion }}
    - name: Install dev dependencies
      run: |
          python -m pip install --upgrade pip
          pip install -U tornado pscript>=0.5.6 webruntime dialite;
          pip install -U invoke pytest pytest-cov;
    - name: Unit tests
      uses: GabrielBB/xvfb-action@v1
      with:
        run: invoke test --unit


name: CI

on:
  push:
    branches: [main]
  pull_request: {}

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

jobs:
  check-manifest:
    if: github.event_name != 'schedule'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pipx run check-manifest

  pre-commit:
    if: github.event_name != 'schedule'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.x"
      - uses: pre-commit/action@v3.0.1

  typing:
    if: github.event_name != 'schedule'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.x"
      - name: install
        run: |
          python -m pip install -U pip
          python -m pip install -e ".[test]"
      - name: type-check
        run: |
          mypy --install-types --non-interactive --config-file pyproject.toml subliminal tests

  docs:
    if: github.event_name != 'schedule'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.x"
      - run: |
          python -m venv venv
          source ./venv/bin/activate
          python -m pip install -e .[docs]
          sphinx-build -b html docs/ docs/_build
      - uses: actions/upload-artifact@v4
        with:
          name: docs
          path: docs/_build/

  test:
    name: Test
    if: github.event_name != 'schedule'
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
        exclude:
          # macos-latest only work with arm64
          - os: macos-latest
            python-version: ["3.8", "3.9"]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
          cache: 'pip'
      - name: install
        run: |
          python -m pip install --upgrade pip
          pip install -e .[test]
      - name: run pytest --cov
        env:
          COVERAGE_FILE: ".coverage.${{ matrix.os }}.${{ matrix.python-version }}"
          # Alternatively you can run coverage with the --parallel flag or add
          # `parallel = True` in the coverage config file.
          # If using pytest-cov, you can also add the `--cov-append` flag
          # directly or through PYTEST_ADD_OPTS.
        run: |
          pytest --cov --cov-report=xml
      - name: Store coverage file
        uses: actions/upload-artifact@v4
        with:
          name: coverage-${{ matrix.os }}-${{ matrix.python-version }}
          path: .coverage.${{ matrix.os }}.${{ matrix.python-version }}

  coverage:
    name: Coverage
    runs-on: ubuntu-latest
    needs: test
    permissions:
      pull-requests: write
      contents: write
    steps:
      - uses: actions/checkout@v4

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

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

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


Post coverage comment

name: Post coverage comment

on:
  workflow_run:
    workflows: ["CI"]
    types:
      - completed

jobs:
  test:
    name: Run tests & display coverage
    runs-on: ubuntu-latest
    if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
    permissions:
      # Gives the action the necessary permissions for publishing new
      # comments in pull requests.
      pull-requests: write
      # Gives the action the necessary permissions for editing existing
      # comments (to avoid publishing multiple comments in the same PR)
      contents: write
      # Gives the action the necessary permissions for looking up the
      # workflow that launched this workflow, and download the related
      # artifact that contains the comment to be published
      actions: read
    steps:
      # DO NOT run actions/checkout here, for security reasons
      # For details, refer to https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
      - name: Post comment
        uses: py-cov-action/python-coverage-comment-action@v3
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GITHUB_PR_RUN_ID: ${{ github.event.workflow_run.id }}
          # Update those if you changed the default values:
          # COMMENT_ARTIFACT_NAME: python-coverage-comment-action
          # COMMENT_FILENAME: python-coverage-comment-action.txt


Test-APIs

name: Test-APIs

on:
  schedule:
    - cron: "12 12 12 * *" # run once a month on the 12th at 12:12

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

jobs:
  test-api:
    name: Test APIs
    if: github.event_name == 'schedule'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.x"
      - name: install
        run: |
          python -m pip install -U pip
          python -m pip install -e ".[test]"
      - name: remove cassettes
        run: |
          rm -rf tests/cassettes
      - name: run test
        run: |
          pytest


CodeQL

# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"

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

jobs:
  analyze:
    name: Analyze
    runs-on: 'ubuntu-latest'
    permissions:
      actions: read
      contents: read
      security-events: write

    strategy:
      fail-fast: false
      matrix:
        language: [ 'python' ]
        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
        # Use only 'java' to analyze code written in Java, Kotlin or both
        # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
        # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support

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

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

        # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
        # queries: security-extended,security-and-quality

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

    # ℹ Command-line programs to run using the OS shell.
    # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun

    #   If the Autobuild fails above, remove it and uncomment the following three lines.
    #   modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.

    # - run: |
    #     echo "Run, Build Application using script"
    #     ./location_of_script_within_repo/buildscript.sh

    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@v2
      with:
        category: "/language:${{matrix.language}}"


Code quality

name: Code quality

on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    if: "!contains(github.event.head_commit.message, '[skip ci]')"
    strategy:
      matrix:
        python-version: ["3.11.x"]
        toxenv: [ruff, isort, black, pypi-description, docs, towncrier]
    steps:
    - uses: actions/checkout@v3
      with:
        repository: ${{ github.event.pull_request.head.repo.full_name }}
        ref: ${{ github.event.pull_request.head.ref }}
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}
    - name: Cache pip
      uses: actions/cache@v3
      with:
        path: ~/.cache/pip
        key: ${{ runner.os }}-pip-${{ matrix.toxenv }}
        restore-keys: |
          ${{ runner.os }}-pip-${{ matrix.toxenv }}
    - name: Cache tox
      uses: actions/cache@v3
      with:
        path: .tox
        key: ${{ runner.os }}-lint-${{ matrix.toxenv }}-${{ hashFiles('setup.cfg') }}
        restore-keys: |
          ${{ runner.os }}-lint-${{ matrix.toxenv }}-
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip setuptools tox>4
    - name: Test with tox
      if: ${{ matrix.toxenv != 'towncrier' || (!contains(github.event.head_commit.message, '[pre-commit.ci]') && !contains(github.event.pull_request.body, 'pre-commit.ci start')) }}
      run: |
        tox -e${{ matrix.toxenv }}


Event Logger

name: Event Logger
on: push

jobs:
  log-github-event-goodies:
    name: "LOG Everything on GitHub Event"
    runs-on: ubuntu-latest
    steps:
      - name: Logging
        run: |
          echo '${{toJSON(github.event)}}'


Upload Python Package

name: Upload Python Package

on:
  release:
    types: [published,prereleased]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.x'
    - name: Cache pip
      uses: actions/cache@v3
      with:
        path: ~/.cache/pip
        key: ${{ runner.os }}-pip-${{ matrix.toxenv }}
        restore-keys: |
          ${{ runner.os }}-pip-${{ matrix.toxenv }}
    - name: Cache tox
      uses: actions/cache@v3
      with:
        path: .tox
        key: ${{ runner.os }}-tox-release-${{ hashFiles('setup.cfg') }}
        restore-keys: |
          ${{ runner.os }}-tox-release-
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip setuptools tox>4
    - name: Build and publish
      env:
        TWINE_USERNAME: __token__
        TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
      run: |
        tox -erelease


Tox tests

name: Tox tests

on: [push, pull_request]

jobs:
  test:
    if: "!contains(github.event.head_commit.message, '[skip ci]')"
    runs-on: ubuntu-latest
    continue-on-error: ${{ matrix.continue-on-error }}
    strategy:
      matrix:
        python-version: ["3.11", "3.10", "3.9"]
        django: [42, 41, 32]
        cms: [311, 39]
        continue-on-error: [false]
        exclude:
          - django: 41
            cms: 39
          - django: 42
            cms: 39
    steps:
    - uses: actions/checkout@v3
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}
    - name: Cache pip
      uses: actions/cache@v3
      with:
        path: ~/.cache/pip
        key: ${{ runner.os }}-pip-${{ matrix.toxenv }}
        restore-keys: |
          ${{ runner.os }}-pip-${{ matrix.toxenv }}
    - name: Cache tox
      uses: actions/cache@v3
      with:
        path: .tox
        key: ${{ runner.os }}-tox-${{ format('{{py{0}-django{1}-cms{2}}}', matrix.python-version, matrix.django, matrix.cms) }}-${{ hashFiles('setup.cfg') }}
        restore-keys: |
          ${{ runner.os }}-tox-${{ format('{{py{0}-django{1}-cms{2}}}', matrix.python-version, matrix.django, matrix.cms) }}-
    - name: Install dependencies
      run: |
        sudo apt-get install gettext
        python -m pip install --upgrade pip setuptools tox>4
    - name: Test with tox
      env:
        TOX_ENV: ${{ format('py-django{1}-cms{2}', matrix.python-version, matrix.django, matrix.cms) }}
        COMMAND: coverage run
        COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        COVERALLS_SERVICE_NAME: github
      run: |
        tox -e$TOX_ENV
        .tox/$TOX_ENV/bin/coverage xml
    - name: Coveralls Parallel
      uses: coverallsapp/github-action@v2
      with:
        github-token: ${{ secrets.GITHUB_TOKEN }}
        parallel: true
    - uses: codecov/codecov-action@v3
      with:
        token: ${{ secrets.CODECOV_TOKEN }}
        flags: unittests
        files: ./coverage.xml
        fail_ci_if_error: false
    services:
      redis:
        image: redis
        ports:
          - 6379:6379
  finish:
    needs: test
    if: ${{ always() }}
    runs-on: ubuntu-latest
    steps:
    - name: Coveralls Finished
      uses: coverallsapp/github-action@v2
      with:
        parallel-finished: true


Publish Docker image

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

name: Publish Docker image

on:
  push:
    branches:
      - main
    tags:
      - "*.*.*"
  pull_request:

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}
  TEST_IMAGE: plextraktsync:ci-test

jobs:
  build-and-push-image:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

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

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Set version variable
        id: vars
        run: |
          if [[ "${GITHUB_REF#refs/heads/}" = "${GITHUB_REF}" ]]; then
            APP_VERSION=${GITHUB_REF#refs/tags/}
          else
            git fetch --tags --unshallow
            APP_VERSION=$(git describe --tags)_${GITHUB_REF#refs/heads/}
          fi
          echo "version=$APP_VERSION" >> $GITHUB_OUTPUT

      - name: Log in to the Container registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/0.') }}

      - name: Build and export to Docker
        uses: docker/build-push-action@v6
        env:
          APP_VERSION: ${{ steps.vars.outputs.version }}
        with:
          context: .
          load: true
          tags: ${{ env.TEST_IMAGE }}
          build-args: |
            APP_VERSION=${{ env.APP_VERSION }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Self-test Docker image
        run: |
          docker run -e TRACE=1 --rm ${{ env.TEST_IMAGE }} test

      - name: Build and push Docker image
        uses: docker/build-push-action@v6
        env:
          APP_VERSION: ${{ steps.vars.outputs.version }}
        with:
          context: .
          platforms: linux/amd64,linux/arm64,linux/arm/v7
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          build-args: |
            APP_VERSION=${{ env.APP_VERSION }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
# vim:ts=2:sw=2:et


Ruff Lint

name: Ruff Lint

on:
  - pull_request

jobs:
  ruff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: chartboost/ruff-action@v1

# vim:ts=2:sw=2:et


PyPI

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

name: PyPI

on:
  workflow_dispatch: ~
  release:
    types: [published]
  push:
    tags:
      - "*.*.*"

env:
  DEFAULT_PYTHON: 3.8

jobs:
  pypi:
    name: Publish to PyPI
    runs-on: ubuntu-latest
    environment:
      name: release
      url: https://pypi.org/p/plextraktsync
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set version variable
        id: vars
        run: |
          if [[ "${GITHUB_REF#refs/heads/}" = "${GITHUB_REF}" ]]; then
            APP_VERSION=${GITHUB_REF#refs/tags/}
          else
            git fetch --tags --unshallow
            version=$(git describe --tags --abbrev=0)
            subver=${{ github.run_number }}
            APP_VERSION=$version.post$subver
          fi
          echo "version=$APP_VERSION" >> $GITHUB_OUTPUT

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

      - name: Install dependencies and build
        env:
          APP_VERSION: ${{ steps.vars.outputs.version }}
        run: |
          set -x
          echo "__version__ = '$APP_VERSION'" > plextraktsync/__init__.py
          cat plextraktsync/__init__.py
          python -c "from plextraktsync import __version__; print(__version__)"
          python -m pip install --upgrade build
          #
          # Patch requirements.txt fpor setuptools-declarative-requirements:
          # https://github.com/s0undt3ch/setuptools-declarative-requirements/issues/6
          sed -i -e '/^-i/d' requirements.txt
          python -m build

      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          user: __token__
          password: ${{ secrets.PYPI_TOKEN }}
# vim:ts=2:sw=2:et


Test

name: Test

on:
  - pull_request

env:
  DEFAULT_PYTHON: 3.8

jobs:
  test:
    runs-on: ubuntu-latest
    name: Test
    steps:
      - name: Check out source repository
        uses: actions/checkout@v4
      - name: Set up Python environment
        uses: actions/setup-python@v5
        with:
          python-version: ${{ env.DEFAULT_PYTHON }}
          cache: pip
      - name: Install dependencies (pip)
        run: python -m pip install -r requirements.txt -r requirements.pipenv.txt
      - name: Install dependencies (pipenv)
        run: pipenv install --deploy
      - name: Install test dependencies
        run: pip install -r tests/requirements.txt

      - name: "Test: info"
        run: ./plextraktsync.sh info
      - name: "Test: pytest"
        run: pytest
# vim:ts=2:sw=2:et


name: publish_conda

on:
  push:
    # Sequence of patterns matched against refs/tags
    tags:
      - '*' # Push events to matching v*, i.e. v1.0, v20.15.10

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: publish-to-conda
        uses: sepandhaghighi/conda-package-publish-action@v1.2
        with:
          subDir: 'otherfile'
          AnacondaToken: ${{ secrets.ANACONDA_TOKEN }}


Upload Python Package

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

name: Upload Python Package

on:
  push:
    # Sequence of patterns matched against refs/tags
    tags:
      - '*' # Push events to matching v*, i.e. v1.0, v20.15.10

jobs:
  deploy:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: Set up Python
      uses: actions/setup-python@v1
      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: ${{ secrets.PYPI_USERNAME }}
        TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
      run: |
        python setup.py sdist bdist_wheel
        twine upload dist/*.tar.gz
        twine upload dist/*.whl


CI

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

name: CI

on: [push, pull_request]

env:
  TEST_PYTHON_VERSION: 3.9
  TEST_OS: 'ubuntu-20.04'

jobs:
  build:

    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-20.04, windows-latest, macOS-latest]
        python-version: [3.5, 3.6, 3.7, 3.8, 3.9, 3.10.0, 3.11.0, 3.12.0]
    steps:
    - uses: actions/checkout@v2
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v2
      with:
        python-version: ${{ matrix.python-version }}
    - name: Installation
      run: |
        python -m pip install --upgrade pip
        pip install .
    - name: First test
      run: |
        opem test
        opem --version
    - name: Test requirements Installation
      run: |
        python otherfile/requirements-splitter.py
        pip install --upgrade --upgrade-strategy=only-if-needed -r test-requirements.txt
    - name: Test with pytest
      run: |
        python -m pytest test --cov=opem --cov-report=term
    - name: Version check
      run: |
        python otherfile/version_check.py
      if: matrix.python-version == env.TEST_PYTHON_VERSION
    - name: Notebook run
      run: |
        pip install notebook>=5.2.2
        python otherfile/notebook_run.py
      if: matrix.python-version == env.TEST_PYTHON_VERSION && matrix.os == env.TEST_OS
    - name: Notebook to HTML
      run: |
        python otherfile/notebook_to_html.py
      if: matrix.python-version == env.TEST_PYTHON_VERSION && matrix.os == env.TEST_OS
    - name: Other tests
      run: |
          python -m vulture opem/ otherfile/ setup.py --min-confidence 65 --exclude=__init__.py --sort-by-size
          python -m bandit -r opem
          python -m pydocstyle -v
      if: matrix.python-version == env.TEST_PYTHON_VERSION && matrix.os == env.TEST_OS
    - name: Upload coverage to Codecov
      uses: codecov/codecov-action@v3
      with:
          fail_ci_if_error: true
      if: matrix.python-version == env.TEST_PYTHON_VERSION && matrix.os == env.TEST_OS
    - name: cProfile
      run: |
          python -m cProfile -s cumtime opem/Profile.py


name: CI

on:
  schedule:
    # run every day at 4am UTC
    - cron: '0 4 * * *'
  push:
  pull_request:
  workflow_dispatch:

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

jobs:

  tests:
    uses: OpenAstronomy/github-actions-workflows/.github/workflows/tox.yml@v1
    with:
      envs: |
        - macos: py310-test-oldestdeps
        - macos: py311-test
        - macos: py312-test
        - linux: py310-test-oldestdeps
        - linux: py311-test
        - linux: py312-test
        - linux: py312-test-devdeps
        - windows: py310-test-oldestdeps
        - windows: py311-test
        - windows: py312-test
      libraries: |
        apt:
          - libopenblas-dev
      coverage: 'codecov'

  publish:
    needs: tests
    uses: OpenAstronomy/github-actions-workflows/.github/workflows/publish.yml@v1
    with:
      test_extras: test
      test_command: pytest -p no:warnings --pyargs reproject
      targets: |
        - cp*-manylinux_x86_64
        - cp*-manylinux_aarch64
        - cp*-macosx_x86_64
        - cp*-macosx_arm64
        - cp*-win_amd64

      # Developer wheels
      upload_to_anaconda: ${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') }}
      anaconda_user: astropy
      anaconda_package: reproject
      anaconda_keep_n_latest: 10

    secrets:
      pypi_token: ${{ secrets.pypi_token }}
      anaconda_token: ${{ secrets.anaconda_token }}


Update Changelog

# This workflow takes the GitHub release notes an updates the changelog on the
# main branch with the body of the release notes, thereby keeping a log in
# the git repo of the changes.

name: "Update Changelog"

on:
  release:
    types: [released]

jobs:
  update:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          ref: main

      - name: Update Changelog
        uses: stefanzweifel/changelog-updater-action@v1
        with:
          release-notes: ${{ github.event.release.body }}
          latest-version: ${{ github.event.release.name }}
          path-to-changelog: CHANGES.md

      - name: Commit updated CHANGELOG
        uses: stefanzweifel/git-auto-commit-action@v5
        with:
          branch: main
          commit_message: Update CHANGELOG
          file_pattern: CHANGES.md