name: Unit tests & Release

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

concurrency:
  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
  cancel-in-progress: true

permissions:
  contents: read # to fetch code (actions/checkout)

jobs:
  prepare-yarn-cache-ubuntu:
    uses: ./.github/workflows/prepare-cache.yml
    with:
      os: ubuntu-latest
  prepare-yarn-cache-macos:
    uses: ./.github/workflows/prepare-cache.yml
    with:
      os: macos-latest
  prepare-yarn-cache-windows:
    uses: ./.github/workflows/prepare-cache.yml
    with:
      os: windows-latest

  prettier:
    needs: prepare-yarn-cache-ubuntu
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          persist-credentials: false
      - uses: actions/setup-node@v4
        with:
          node-version: lts/*
          cache: yarn
      - name: install
        run: yarn
      - name: run prettier
        run: yarn prettier:check

  typecheck:
    needs: prepare-yarn-cache-ubuntu
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          persist-credentials: false
      - uses: actions/setup-node@v4
        with:
          node-version: lts/*
          cache: yarn
      - name: install
        run: yarn
      - name: run typecheck
        run: yarn typecheck

  test-node:
    name:
      # prettier-ignore
      Test on Node.js v${{ matrix.node-version }}, eslint v${{ matrix.eslint-version }}, and ts-eslint v${{ matrix.ts-eslint-plugin-version }}
    needs: prepare-yarn-cache-ubuntu
    strategy:
      fail-fast: false
      matrix:
        node-version: [16.x, 18.x, 19.x, 20.x, 21.x]
        eslint-version: [7, 8, 9]
        ts-eslint-plugin-version: [6, 7, 8]
        exclude:
          # ts-eslint/plugin@7 doesn't support node@16
          - node-version: 16.x
            ts-eslint-plugin-version: 7
          # ts-eslint/plugin@8 doesn't support node@16
          - node-version: 16.x
            ts-eslint-plugin-version: 8
          # eslint@9 doesn't support node@16
          - node-version: 16.x
            eslint-version: 9
          # ts-eslint/plugin@7 doesn't support eslint@7
          - eslint-version: 7
            ts-eslint-plugin-version: 7
          # ts-eslint/plugin@8 doesn't support eslint@7
          - eslint-version: 7
            ts-eslint-plugin-version: 8
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
        with:
          persist-credentials: false
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: yarn
      - name:
          # prettier-ignore
          install with eslint v${{ matrix.eslint-version }}
        run: |
          yarn
          yarn add @typescript-eslint/utils@${{ matrix.ts-eslint-plugin-version }}
          # prettier-ignore
          yarn add --dev eslint@${{ matrix.eslint-version }} @typescript-eslint/eslint-plugin@${{ matrix.ts-eslint-plugin-version }} @typescript-eslint/parser@${{ matrix.ts-eslint-plugin-version }}
      - name: run tests
        # only collect coverage on eslint versions that support dynamic import
        run: yarn test --coverage ${{ matrix.eslint-version == 8 }}
        env:
          CI: true
      - uses: codecov/codecov-action@v3
        if: ${{ matrix.eslint-version == 8 }}
  test-ubuntu:
    uses: ./.github/workflows/test.yml
    needs: prepare-yarn-cache-ubuntu
    with:
      os: ubuntu-latest
  test-macos:
    uses: ./.github/workflows/test.yml
    needs: prepare-yarn-cache-macos
    with:
      os: macos-latest
  test-windows:
    uses: ./.github/workflows/test.yml
    needs: prepare-yarn-cache-windows
    with:
      os: windows-latest

  docs:
    if: ${{ github.event_name == 'pull_request' }}
    needs: prepare-yarn-cache-ubuntu
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: lts/*
          cache: yarn
      - name: install
        run: yarn
      - name: regenerate docs
        run: yarn tools:regenerate-docs
      - name: report regenerated docs
        run: |
          git diff --name-only \
            | xargs -I '{}' bash -c \
              'echo "::error file={}::This needs to be regenerated by running \`tools:regenerate-docs\`" && false'

  release:
    permissions:
      contents: write # for semantic-release
      issues: write # to create comment
      pull-requests: write # to create comment

    if:
      # prettier-ignore
      ${{ github.event_name == 'push' && (github.event.ref == 'refs/heads/main' || github.event.ref == 'refs/heads/next') }}
    name: Release new version
    needs:
      [prettier, typecheck, test-node, test-ubuntu, test-macos, test-windows]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          persist-credentials: false
      - uses: actions/setup-node@v4
        with:
          node-version: lts/*
          cache: yarn
      - name: install
        run: yarn
      - run: yarn semantic-release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}