name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  release:
    types: [published]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Set up pnpm
        uses: pnpm/action-setup@v4
        with:
          version: 10

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'pnpm'
          cache-dependency-path: web/pnpm-lock.yaml

      - name: Build web assets
        working-directory: web
        run: |
          pnpm install --frozen-lockfile
          pnpm build

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version-file: 'go.mod'
          cache: true

      - name: Lint code
        run: |
          set -euo pipefail
          go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.4
          LINT_BIN="$(go env GOPATH)/bin/golangci-lint"

          run_lint() {
            "$LINT_BIN" run "$@" || {
              code=$?
              # exit code 5 = "no go files to analyze" (e.g. only non-Go files changed) — not a lint failure
              [ "$code" -eq 5 ] && return 0
              return "$code"
            }
          }

          if [ "${{ github.event_name }}" = "pull_request" ]; then
            git fetch --no-tags origin "${{ github.base_ref }}"
            run_lint --new-from-rev "origin/${{ github.base_ref }}" ./...
          elif [ "${{ github.event_name }}" = "push" ] && [ "${{ github.event.before }}" != "0000000000000000000000000000000000000000" ]; then
            run_lint --new-from-rev "${{ github.event.before }}" ./...
          elif git rev-parse --verify HEAD^ >/dev/null 2>&1; then
            run_lint --new-from-rev "$(git rev-parse HEAD^)" ./...
          else
            run_lint ./...
          fi

      - name: Lint GitHub workflows
        run: |
          go install github.com/rhysd/actionlint/cmd/actionlint@v1.7.8
          "$(go env GOPATH)/bin/actionlint" -color

  unit-test:
    runs-on: ubuntu-latest
    needs: lint

    steps:
      - uses: actions/checkout@v4

      - name: Set up pnpm
        uses: pnpm/action-setup@v4
        with:
          version: 10

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'pnpm'
          cache-dependency-path: web/pnpm-lock.yaml

      - name: Build web assets
        working-directory: web
        run: |
          pnpm install --frozen-lockfile
          pnpm build

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version-file: 'go.mod'
          cache: true

      - name: Download dependencies
        run: go mod download
        env:
          GOPROXY: https://proxy.golang.org,direct
          GOSUMDB: sum.golang.org
          GONOSUMDB: ""

      - name: Verify module checksums
        run: go mod verify
        env:
          GOPROXY: https://proxy.golang.org,direct
          GOSUMDB: sum.golang.org
          GONOSUMDB: ""

      - name: Build
        run: go build ./...

      - name: Run tests
        run: go test ./... -v -race

      - name: Run tests with coverage
        run: go test ./... -coverprofile=coverage.out -covermode=atomic

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v4
        if: github.event_name == 'push'
        with:
          files: ./coverage.out
          fail_ci_if_error: false

  smoke-test:
    runs-on: ubuntu-latest
    needs: unit-test

    steps:
      - uses: actions/checkout@v4

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version-file: 'go.mod'
          cache: true

      - name: Run smoke tests
        run: go test -v -tags=smoke,no_web ./tests/e2e/...

  regression-test:
    runs-on: ubuntu-latest
    needs: smoke-test

    steps:
      - uses: actions/checkout@v4

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version-file: 'go.mod'
          cache: true

      - name: Run regression tests
        run: go test -v -tags=regression,no_web ./tests/e2e/...

  performance-test:
    runs-on: ubuntu-latest
    needs: regression-test

    steps:
      - uses: actions/checkout@v4

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version-file: 'go.mod'
          cache: true

      - name: Run performance benchmarks
        run: go test -bench=. -benchmem -tags=performance,no_web ./tests/performance/...
