name: CI

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

concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

env:
  VENV: .venv

permissions:
  contents: read
  checks: write

jobs:
  analysis:
    name: Code Analysis
    runs-on: ubuntu-latest
    if: (!contains(github.event.head_commit.message, '[skip ci]'))
    steps:
      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
      - name: Setup Environment
        uses: ./.github/actions/setup-env
      - name: Install project dependencies
        run: . script/bootstrap
      - name: Lint
        run: |
          poetry run invoke lint

  tests:
    name: Tests
    runs-on: ${{ matrix.os }}
    if: (!contains(github.event.head_commit.message, '[skip ci]'))
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest]
        python-version: ['3.10', '3.11', '3.12', '3.13', '3.14-dev']
      fail-fast: ${{ !contains(github.event.pull_request.labels.*.name, 'ci/run-all-tests') }}
    steps:
      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
      - name: Setup Environment
        uses: ./.github/actions/setup-env
        with:
          python-version: ${{ matrix.python-version }}
      - name: Install project dependencies
        run: . script/bootstrap
        shell: bash
      - name: Run Tests (with coverage)
        id: tests-with-coverage
        if: matrix.python-version == '3.14-dev' && matrix.os == 'ubuntu-latest'
        shell: bash
        run: poetry run invoke test --coverage
      - name: Run Tests
        if: steps.tests-with-coverage.outcome == 'skipped'
        shell: bash
        run: poetry run invoke test
      - name: Upload Coverage
        if: steps.tests-with-coverage.conclusion == 'success'
        uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
        with:
          token: ${{ secrets.CODECOV_TOKEN }}

# # TODO: How to do this with poetry?
  # version_checks:
  #   name: Dependency Version Constraint Checks
  #   runs-on: ubuntu-latest
  #   if: "!contains(github.event.head_commit.message, '[skip ci]')"
  #   env:
  #     SKIP_DEPS: 1
  #   steps:
  #    - uses: actions/checkout@v3.1.0
  #    - name: Setup Environment
  #      uses: ./.github/actions/setup-env
  #      with:
  #         python-version: 3.7 # it's min, so we'll use an older version of python
  #     - name: Install project dependencies
  #       run: |
  #         . script/bootstrap
  #         poetry install --with=test
  #     - name: Test
  #       env:
  #         CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
  #       run: |
  #         . $VENV/bin/activate
  #         poetry run invoke test --coverage

  benchmark:
    name: Benchmark
    runs-on: ubuntu-latest
    if: github.event_name == 'pull_request' && !contains(github.event.head_commit.message, '[skip ci]')
    needs: [tests]
    permissions:
      contents: write
      pull-requests: write
    steps:
      - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
      - name: Setup Environment
        uses: ./.github/actions/setup-env
      - name: Install project dependencies
        run: . script/bootstrap
      - name: Benchmark
        run: poetry run invoke benchmark
      - name: Publish Benchmark Results
        uses: benchmark-action/github-action-benchmark@4bdcce38c94cec68da58d012ac24b7b1155efe8b # v1.20.7
        with:
          tool: 'pytest'
          output-file-path: benchmarks.json
          github-token: ${{ github.token }}
          auto-push: false
          alert-threshold: '200%'
          comment-on-alert: true
          fail-on-alert: false
          comment-always: true

  required_checks:
    name: Required Checks
    needs:
      - analysis
      - tests
      - benchmark
    runs-on: ubuntu-latest
    if: always()
    steps:
      - name: Fail on error
        if: contains(needs.*.result, 'failure') || cancelled()
        run: exit 1
