name: ci
on:
  push:
    branches:
      - main
  pull_request:
env:
  # Default version of Go to use by CI workflows. This should be the latest
  # release of Go; developers likely use the latest release in development and
  # we want to catch any bugs (e.g. lint errors, race detection) with this
  # release before they are merged. The Go compatibility guarantees ensure
  # backwards compatibility with the previous two minor releases and we
  # explicitly test our code for these versions so keeping this at prior
  # versions does not add value.
  DEFAULT_GO_VERSION: "~1.26.0"
# Declare default permissions as read only.
permissions: read-all
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          fetch-depth: 0 ## Needed for "Set internal/tools/go.mod timestamp" step.
      - name: Install Go
        uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
        with:
          go-version: ${{ env.DEFAULT_GO_VERSION }}
          check-latest: true
          cache-dependency-path: "**/go.sum"
      - name: Tools cache
        uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
        env:
          cache-name: go-tools-cache
        with:
          path: .tools
          key: ${{ runner.os }}-${{ env.DEFAULT_GO_VERSION }}-${{ env.cache-name }}-${{ hashFiles('./internal/tools/**') }}
      # The step below is needed to not rebuild all the build tools.
      - name: Set internal/tools timestamps
        run: |
          git ls-files \
            internal/tools/go.mod \
            internal/tools/semconvkit \
            internal/tools/verifyreadmes \
          | while IFS= read -r filename; do
              unixtime=$(git log -1 --format="%at" -- "${filename}")
              touchtime=$(date -d @"${unixtime}" +'%Y%m%d%H%M.%S')
              touch -t "${touchtime}" "${filename}"
              ls -la --time-style=full-iso "${filename}"
            done
      - name: Generate
        run: make generate
      - name: Run linters
        run: make toolchain-check license-check lint vanity-import-check verify-readmes verify-mods
      - name: Build
        run: make build
      - name: Check clean repository
        run: make check-clean-work-tree

  govulncheck:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          fetch-depth: 0 ## Needed for "Set internal/tools/go.mod timestamp" step.
      - name: Install Go
        uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
        with:
          go-version: ${{ env.DEFAULT_GO_VERSION }}
          check-latest: true
          cache-dependency-path: "**/go.sum"
      - name: Tools cache
        uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
        env:
          cache-name: go-tools-cache
        with:
          path: .tools
          key: ${{ runner.os }}-${{ env.DEFAULT_GO_VERSION }}-${{ env.cache-name }}-${{ hashFiles('./internal/tools/**') }}
      # The step below is needed to not rebuild all the build tools.
      - name: Set internal/tools timestamps
        run: |
          git ls-files \
            internal/tools/go.mod \
            internal/tools/semconvkit \
            internal/tools/verifyreadmes \
          | while IFS= read -r filename; do
              unixtime=$(git log -1 --format="%at" -- "${filename}")
              touchtime=$(date -d @"${unixtime}" +'%Y%m%d%H%M.%S')
              touch -t "${touchtime}" "${filename}"
              ls -la --time-style=full-iso "${filename}"
            done
      - name: Run govulncheck
        run: make govulncheck

  test-bench:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - name: Setup Environment
        run: |
          echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV
          echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
      - name: Install Go
        uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
        with:
          go-version: ${{ env.DEFAULT_GO_VERSION }}
          cache-dependency-path: "**/go.sum"
      - name: Run benchmarks to check functionality
        run: make test-bench

  test-race:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - name: Install Go
        uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
        with:
          go-version: ${{ env.DEFAULT_GO_VERSION }}
          check-latest: true
          cache-dependency-path: "**/go.sum"
      - name: Run tests with race detector
        run: make test-race

  test-concurrent-safe:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - name: Install Go
        uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
        with:
          go-version: ${{ env.DEFAULT_GO_VERSION }}
          check-latest: true
          cache-dependency-path: "**/go.sum"
      - name: Run ConcurrentSafe tests multiple times with race detector
        run: make test-concurrent-safe

  test-coverage:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - name: Install Go
        uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
        with:
          go-version: ${{ env.DEFAULT_GO_VERSION }}
          check-latest: true
          cache-dependency-path: "**/go.sum"
      - name: Run coverage tests
        run: make test-coverage
      - name: Store coverage test output
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: coverage-artifacts-${{ env.DEFAULT_GO_VERSION }}
          path: coverage.txt

  codecov:
    runs-on: ubuntu-latest
    needs: [test-coverage]
    steps:
      - name: Checkout Repo
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        with:
          pattern: coverage-artifacts-${{ env.DEFAULT_GO_VERSION }}
      - name: Upload coverage report
        uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
        with:
          fail_ci_if_error: true
          files: ./coverage.txt
          verbose: true

  compatibility-test:
    strategy:
      matrix:
        go-version: ["1.26.0", "1.25.0"]
        platform:
          - os: ubuntu-latest
            arch: "386"
          - os: ubuntu-latest
            arch: amd64
          - os: ubuntu-22.04-arm
            arch: arm64
          - os: macos-latest
            arch: amd64
          - os: macos-latest
            arch: arm64
          - os: windows-latest
            arch: "386"
          - os: windows-latest
            arch: amd64
    runs-on: ${{ matrix.platform.os }}
    steps:
      - name: Checkout code
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - name: Install Go
        uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
        with:
          go-version: ${{ matrix.go-version }}
          check-latest: true
          cache-dependency-path: "**/go.sum"
      - name: Run tests
        env:
          GOARCH: ${{ matrix.platform.arch }}
        run: make test-short

  test-compatibility:
    runs-on: ubuntu-latest
    needs: [compatibility-test]
    if: always()
    steps:
      - name: Test if compatibility-test passed
        run: |
          echo ${{ needs.compatibility-test.result }}
          test ${{ needs.compatibility-test.result }} == "success"
