name: Run tests

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

# Every job here only reads the repo; nothing publishes or writes back.
permissions:
  contents: read

# Superseded runs are wasted work: without this, pushing twice to a PR leaves the
# first 20-job run going to completion. Keyed on the PR number where there is one
# and on the SHA otherwise, so pushes to main never cancel each other.
concurrency:
  group: >-
    ${{ github.workflow }}-${{ github.ref_type }}-
    ${{ github.event.pull_request.number || github.sha }}
  cancel-in-progress: true

defaults:
  run:
    shell: bash -eux {0}

jobs:
  tests:
    runs-on: ${{ matrix.os }}
    timeout-minutes: 20
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
    steps:
      - uses: actions/checkout@v7
        with:
          persist-credentials: false
      - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
        with:
          python_package_manager: "uv pip"
          node_version: "none"
      - name: Run the tests
        if: ${{ !startsWith(matrix.os, 'windows') }}
        run: |
          hatch run cov:test --cov-fail-under 75
      - name: Run the tests on windows
        if: ${{ startsWith(matrix.os, 'windows') }}
        run: |
          hatch run cov:nowarn
      # Checks that the nodejs version source is writable. Not OS- or
      # version-sensitive, so once is enough.
      - name: Check the version is writable
        if: ${{ matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12' }}
        run: hatch version 100.100.100
      - uses: jupyterlab/maintainer-tools/.github/actions/upload-coverage@v1

  coverage:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    needs:
      - tests
    steps:
      - uses: actions/checkout@v7
        with:
          persist-credentials: false
      - uses: jupyterlab/maintainer-tools/.github/actions/report-coverage@v1
        with:
          fail_under: 77

  test_lint:
    name: Test Lint
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v7
        with:
          persist-credentials: false
      - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
        with:
          python_package_manager: "uv pip"
          node_version: "none"
      - name: Run Linters
        run: |
          hatch run typing:test
          hatch run lint:build
          pipx run interrogate -v nbformat
          pipx run doc8 --max-line-length=200

  docs:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v7
        with:
          persist-credentials: false
      - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
        with:
          python_package_manager: "uv pip"
          node_version: "none"
      - name: Test docs
        run: hatch run docs:build

  test_minimum_versions:
    name: Test Minimum Versions
    timeout-minutes: 20
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
        with:
          persist-credentials: false
      - name: Base Setup
        uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
        with:
          dependency_type: minimum
          python_package_manager: "uv pip"
          node_version: "none"
      - name: Run the unit tests
        run: |
          hatch run test:nowarn

  test_prereleases:
    name: Test Prereleases
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - name: Checkout
        uses: actions/checkout@v7
        with:
          persist-credentials: false
      - name: Base Setup
        uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
        with:
          dependency_type: pre
          python_package_manager: "uv pip"
          node_version: "none"
      - name: Run the tests
        run: |
          hatch run test:nowarn

  make_sdist:
    name: Make SDist
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v7
        with:
          persist-credentials: false
      - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
        with:
          python_package_manager: "uv pip"
      - uses: jupyterlab/maintainer-tools/.github/actions/make-sdist@v1

  test_sdist:
    runs-on: ubuntu-latest
    needs: [make_sdist]
    name: Install from SDist and Test
    timeout-minutes: 20
    steps:
      - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
        with:
          python_package_manager: "uv pip"
      - uses: jupyterlab/maintainer-tools/.github/actions/test-sdist@v1

  check_release:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - name: Checkout
        uses: actions/checkout@v7
        with:
          persist-credentials: false
      - name: Base Setup
        uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
        with:
          python_package_manager: "uv pip"
      - name: Install Dependencies
        run: |
          uv pip install --system -e .
      - name: Check Release
        uses: jupyter-server/jupyter_releaser/.github/actions/check-release@v2
        with:
          token: ${{ secrets.GITHUB_TOKEN }}

  check_links:
    name: Check Links
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v7
        with:
          persist-credentials: false
      - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
        with:
          python_package_manager: "uv pip"
          node_version: "none"
      - uses: jupyterlab/maintainer-tools/.github/actions/check-links@v1
        with:
          ignore_glob: "tests/*.ipynb"
