name: Go
on:
  push:
    tags:
      - v*
    branches:
      - master
    paths:
      - "go/**"
      - "!go/**.md"
      - "go.*"
      - "**.go"
      - ".github/workflows/go.yml"
  pull_request:
    paths:
      - "go/**"
      - "!go/**.md"
      - "go.*"
      - "**.go"
      - ".github/workflows/go.yml"

jobs:
  golangci-lint:
    name: Golangci-lint
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup asdf
        uses: asdf-vm/actions/setup@9cd779f40fe38688dd19505ccbc4eaaf018b44e7
        with:
          asdf_version: 0.16.7

      - name: Setup golang
        run: |
          asdf plugin add golang
          asdf install golang
          . ~/.asdf/plugins/golang/set-env.bash

      - name: Setup golangci-lint
        run: |
          asdf plugin add golangci-lint
          asdf install golangci-lint

      - name: Run golangci-lint
        working-directory: go
        run: make lint

  # this is not very common to have a job that checks the flappy tests.
  #
  # reason: some tests are flappy, they works, but not always;
  #         this job checks that they are working sometimes.
  #         if this job fails, then a test is "broken", not "flappy".
  #
  #         summary: this job checks that "flappy tests" do not become "broken tests".
  #
  # we hope we can remove this job because all the tests are stable 100% of the time
  flappy-tests:
    name: Flappy tests (Linux)
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Load variables from file
        uses: antifree/json-to-variables@v1.0.1
        with:
          filename: .github/workflows/utils/variables.json

      - name: Setup asdf
        uses: asdf-vm/actions/setup@9cd779f40fe38688dd19505ccbc4eaaf018b44e7
        with:
          asdf_version: 0.16.7

      - name: Setup go
        run: |
          asdf plugin add golang
          asdf install golang
          echo "go_version=$(asdf current golang | xargs | cut -d ' ' -f 6)" >> $GITHUB_ENV

      - name: Cache go modules
        uses: actions/cache@v4
        with:
          path: ~/go/pkg/mod
          key: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-${{ hashFiles('**/go.sum') }}
          restore-keys: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-

      - name: Avoid triggering make generate
        run: touch go/gen.sum

      - name: Fetch go modules
        run: go mod download

      - name: Compile the testing binaries
        run: |
          pushd ./go/pkg/bertymessenger && go test -tags "fts5 sqlite sqlite_unlock_notify" -c -o ./tests.bin . && popd

      - name: Check go.mod and go.sum
        run: |
          go mod tidy -v
          git --no-pager diff go.mod go.sum
          git --no-pager diff --quiet go.mod go.sum

      - name: Run fast flappy tests
        working-directory: go
        env:
          TEST_SPEED: fast
          TEST_STABILITY: flappy
        run: make go.flappy-tests

  go-tests-on-linux:
    name: Stable tests (Linux)
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Load variables from file
        uses: antifree/json-to-variables@v1.0.1
        with:
          filename: .github/workflows/utils/variables.json

      - name: Setup asdf
        uses: asdf-vm/actions/setup@9cd779f40fe38688dd19505ccbc4eaaf018b44e7
        with:
          asdf_version: 0.16.7

      - name: Setup go
        run: |
          asdf plugin add golang
          asdf install golang
          echo "go_version=$(asdf current golang | xargs | cut -d ' ' -f 6)" >> $GITHUB_ENV

      - name: Cache go modules
        uses: actions/cache@v4
        with:
          path: ~/go/pkg/mod
          key: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-${{ hashFiles('**/go.sum') }}
          restore-keys: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-

      - name: Compile the project on Unix-like operating systems
        working-directory: go
        run: |
          touch gen.sum # avoid triggering make generate
          make go.install

      - name: Check go.mod and go.sum
        run: |
          go mod tidy -v
          git --no-pager diff go.mod go.sum
          git --no-pager diff --quiet go.mod go.sum

      - name: Run fast tests multiple times
        working-directory: go
        env:
          TEST_SPEED: fast
          GO_TEST_OPTS: -test.timeout=600s -count 1 -tags "fts5 sqlite sqlite_unlock_notify"
        run: set -o pipefail; make go.unittest | tee test_log.txt

      - name: Run all tests
        working-directory: go
        env:
          TEST_SPEED: any
          GO_TEST_OPTS: -test.timeout=600s -count 1 -tags "fts5 sqlite sqlite_unlock_notify"
        run: make go.unittest

      - name: Run all tests with race flag and generate coverage
        working-directory: go
        env:
          TEST_SPEED: any
          GO_TEST_OPTS: -test.timeout=1200s -count=1 -race -cover -tags "fts5 sqlite sqlite_unlock_notify" -coverprofile=coverage.txt -covermode=atomic
        run: make go.unittest

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v2.1.0
        env:
          OS: ${{ runner.os }}
          GOLANG: ${{ env.go_version }}
        with:
          file: ./go/coverage.txt
          flags: go.unittests
          env_vars: OS,GOLANG
          name: codecov-umbrella
          fail_ci_if_error: false

  go-tests-on-windows:
    name: Stable tests (Windows)
    runs-on: windows-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Load variables from file
        uses: antifree/json-to-variables@v1.0.1
        with:
          filename: .github/workflows/utils/variables.json

      - name: Get go version
        shell: bash
        run: echo "go_version=$(cat .tool-versions | grep '^golang [0-9]\+\.[0-9]\+\.[0-9]\+.*$' | cut -d ' ' -f 6)" >> $GITHUB_ENV

      - name: Setup go
        uses: actions/setup-go@v3
        with:
          go-version: ${{ env.go_version }}

      - name: Cache go modules
        uses: actions/cache@v4
        with:
          path: ~/go/pkg/mod
          key: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-${{ hashFiles('**/go.sum') }}
          restore-keys: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-

      - name: Compile the project on Windows
        run: go.exe install -buildmode=exe ./go/cmd/...
      - name: Check go.mod and go.sum
        run: |
          go mod tidy -v
          git --no-pager diff go.mod go.sum
          git --no-pager diff --quiet go.mod go.sum

      - name: Run fast tests multiple times
        working-directory: go
        env:
          TEST_SPEED: fast
        run: go.exe test ./... -tags "fts5 sqlite sqlite_unlock_notify" -buildmode=exe -timeout=600s -count=5

      - name: Run all tests
        working-directory: go
        env:
          TEST_SPEED: any
        run: go.exe test ./... -tags "fts5 sqlite sqlite_unlock_notify" -buildmode=exe -timeout=600s -count=1

  go-tests-on-macos:
    name: Stable tests (macOS)
    runs-on: macos-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Load variables from file
        uses: antifree/json-to-variables@v1.0.1
        with:
          filename: .github/workflows/utils/variables.json

      - name: Setup asdf
        uses: asdf-vm/actions/setup@9cd779f40fe38688dd19505ccbc4eaaf018b44e7
        with:
          asdf_version: 0.16.7

      - name: Setup go
        run: |
          asdf plugin add golang
          asdf install golang
          echo "go_version=$(asdf current golang | xargs | cut -d ' ' -f 6)" >> $GITHUB_ENV

      - name: Cache go modules
        uses: actions/cache@v4
        with:
          path: ~/go/pkg/mod
          key: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-${{ hashFiles('**/go.sum') }}
          restore-keys: ${{ runner.os }}-go-${{ env.go_version }}-${{ env.json_cache-versions_go }}-

      - name: Compile the project on Unix-like operating systems
        working-directory: go
        run: |
          touch gen.sum # avoid triggering make generate
          make go.install

      - name: Check go.mod and go.sum
        run: |
          go mod tidy -v
          git --no-pager diff go.mod go.sum
          git --no-pager diff --quiet go.mod go.sum

      - name: Run fast tests multiple times
        working-directory: go
        env:
          TEST_SPEED: fast
          GO_TEST_OPTS: -test.timeout=600s -count 1 -tags "fts5 sqlite sqlite_unlock_notify"
        run: set -o pipefail; make go.unittest | tee test_log.txt

      - name: Run all tests
        working-directory: go
        env:
          TEST_SPEED: any
          GO_TEST_OPTS: -test.timeout=600s -count 1 -tags "fts5 sqlite sqlite_unlock_notify"
        run: make go.unittest

      - name: Run all tests with race flag and generate coverage
        working-directory: go
        env:
          TEST_SPEED: any
          GO_TEST_OPTS: -test.timeout=1200s -count=1 -race -cover -tags "fts5 sqlite sqlite_unlock_notify" -coverprofile=coverage.txt -covermode=atomic
        run: make go.unittest

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v2.1.0
        env:
          OS: ${{ runner.os }}
          GOLANG: ${{ env.go_version }}
        with:
          file: ./go/coverage.txt
          flags: go.unittests
          env_vars: OS,GOLANG
          name: codecov-umbrella
          fail_ci_if_error: false

  # TODO: consider adding various GOARCH check per OS.
  #       i.e., to validate that we build on 32/64bit.
