name: Stable tests

# This file tests the claimed support range of NiBabel including
#
# * Operating systems: Linux, Windows (x64 & x86), OSX
# * Dependencies: minimum requirements, optional requirements
# * Installation methods: setup.py, sdist, wheel, archive

on:
  push:
    branches:
      - master
      - maint/*
    tags:
      - "*"
  pull_request:
    branches:
      - master
      - maint/*
  schedule:
    - cron: '0 0 * * 1'

defaults:
  run:
    shell: bash

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

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - uses: actions/setup-python@v4
        with:
          python-version: 3
      - run: pip install --upgrade build twine
      - name: Build sdist and wheel
        run: python -m build
      - run: twine check dist/*
      - name: Build git archive
        run: git archive -v -o dist/nibabel-archive.tgz HEAD
      - uses: actions/upload-artifact@v3
        with:
          name: dist
          path: dist/

  test-package:
    runs-on: ubuntu-latest
    needs: [build]
    strategy:
      matrix:
        package: ['wheel', 'sdist', 'archive']
    steps:
      - uses: actions/download-artifact@v3
        with:
          name: dist
          path: dist/
      - uses: actions/setup-python@v4
        with:
          python-version: 3
      - name: Display Python version
        run: python -c "import sys; print(sys.version)"
      - name: Update pip
        run: pip install --upgrade pip
      - name: Install wheel
        run: pip install dist/nibabel-*.whl
        if: matrix.package == 'wheel'
      - name: Install sdist
        run: pip install dist/nibabel-*.tar.gz
        if: matrix.package == 'sdist'
      - name: Install archive
        run: pip install dist/nibabel-archive.tgz
        if: matrix.package == 'archive'
      - run: python -c 'import nibabel; print(nibabel.__version__)'
      - name: Install test extras
        run: pip install nibabel[test]
      - name: Run tests
        run: pytest --doctest-modules --doctest-plus -v --pyargs nibabel

  stable:
    # Check each OS, all supported Python, minimum versions and latest releases
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: ['ubuntu-latest', 'windows-latest', 'macos-latest']
        python-version: [3.8, 3.9, "3.10", "3.11"]
        architecture: ['x64', 'x86']
        install: ['pip']
        check: ['test']
        pip-flags: ['']
        depends: ['REQUIREMENTS']
        optional-depends: ['DEFAULT_OPT_DEPENDS']
        include:
          # Basic dependencies only
          - os: ubuntu-latest
            python-version: 3.8
            install: pip
            check: test
            pip-flags: ''
            depends: REQUIREMENTS
            optional-depends: ''
          # Absolute minimum dependencies
          - os: ubuntu-latest
            python-version: 3.8
            install: pip
            check: test
            pip-flags: ''
            depends: MIN_REQUIREMENTS
            optional-depends: ''
          # Absolute minimum dependencies plus old MPL, Pydicom, Pillow
          - os: ubuntu-latest
            python-version: 3.8
            install: pip
            check: test
            pip-flags: ''
            depends: MIN_REQUIREMENTS
            optional-depends: MIN_OPT_DEPENDS
          # Clean install imports only with package-declared dependencies
          - os: ubuntu-latest
            python-version: 3.8
            install: pip
            check: skiptests
            pip-flags: ''
            depends: ''
        exclude:
          - os: ubuntu-latest
            architecture: x86
          - os: macos-latest
            architecture: x86
    env:
      DEPENDS: ${{ matrix.depends }}
      OPTIONAL_DEPENDS: ${{ matrix.optional-depends }}
      INSTALL_TYPE: ${{ matrix.install }}
      CHECK_TYPE: ${{ matrix.check }}
      EXTRA_PIP_FLAGS: ${{ matrix.pip-flags }}

    steps:
      - uses: actions/checkout@v3
        with:
          submodules: recursive
          fetch-depth: 0
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}
          architecture: ${{ matrix.architecture }}
      - name: Display Python version
        run: python -c "import sys; print(sys.version)"
      - name: Create virtual environment
        run: tools/ci/create_venv.sh
      - name: Build archive
        run: |
          source tools/ci/build_archive.sh
          echo "ARCHIVE=$ARCHIVE" >> $GITHUB_ENV
      - name: Install dependencies
        run: tools/ci/install_dependencies.sh
      - name: Install NiBabel
        run: tools/ci/install.sh
      - name: Run tests
        run: tools/ci/check.sh
        if: ${{ matrix.check != 'skiptests' }}
      - name: Submit coverage
        run: tools/ci/submit_coverage.sh
        if: ${{ always() }}
      - name: Upload pytest test results
        uses: actions/upload-artifact@v3
        with:
          name: pytest-results-${{ matrix.os }}-${{ matrix.python-version }}
          path: for_testing/test-results.xml
        if: ${{ always() && matrix.check == 'test' }}

  publish:
    runs-on: ubuntu-latest
    environment: "Package deployment"
    needs: [stable, test-package]
    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
    steps:
      - uses: actions/download-artifact@v3
        with:
          name: dist
          path: dist/
      - uses: pypa/gh-action-pypi-publish@release/v1
        with:
          user: __token__
          password: ${{ secrets.PYPI_API_TOKEN }}
