version: 2.1

orbs:
  codecov: codecov/codecov@3.2.2

executors:
  golang:
    parameters:
      go-version:
        type: string
    docker:
      - image: "golang:<< parameters.go-version >>-bullseye"
    working_directory: /go/src/go.lsp.dev/protocol

command_vars:
  - cache_key: &cache_key gomod-<< parameters.go-version >>-{{ checksum "go.mod" }}-{{ checksum "go.sum" }}-2ptat08qmr4k
  - cache_tools_key: &cache_tools_key tools-<< parameters.go-version >>-{{ checksum "tools/go.mod" }}-{{ checksum "tools/go.sum" }}-2ptat08qmr4k

commands:
  restore_dependencies:
    parameters:
      go-version:
        type: string
    steps:
      - restore_cache:
          name: "Restore module dependencies cache"
          keys:
            - *cache_key
      - restore_cache:
          name: "Restore dependencies tools"
          keys:
            - *cache_tools_key
      - run:
          name: "Download project modules"
          command: |
            go mod download

  save_dependencies:
    parameters:
      go-version:
        type: string
    steps:
      - save_cache:
          name: "Save module cache"
          key: *cache_key
          paths:
            - /go/pkg/mod/cache
      - save_cache:
          name: "Save dependencies tools"
          key: *cache_tools_key
          paths:
            - /go/bin/
      - run:
          name: "go mod vendor"
          command: |
            go mod vendor

  install_tools:
    steps:
      - run:
          name: "Build project tools"
          command: |
            if [ -z $(find /go/bin/ -mindepth 1 -type f | head -1) ]; then
              make -j${CPUS} tools GOBIN=/go/bin
            fi

  setup:
    steps:
      - checkout
      - run:
          name: Check versions
          command: |
            go version
            go env
      - attach_workspace:
          name: "Attach vendor directory and dependencies tools"
          at: "/go"
      - run:
          name: "go mod vendor"
          command: |
            go mod vendor
      - run:
          name: "Parse CPUs"
          command: |
            # https://circleci.com/changelog#container-cgroup-limits-now-visible-inside-the-docker-executor
            CPUS="$(echo $(($(cat /sys/fs/cgroup/cpu/cpu.shares) / 1024)))"
            echo "export GOFLAGS='-p=${CPUS} -cpu=${CPUS}'" >> $BASH_ENV
            echo "export CPUS=${CPUS}" >> $BASH_ENV

jobs:
  tools:
    parameters:
      go-version:
        type: string
    executor:
      name: golang
      go-version: "<< parameters.go-version >>"
    resource_class: xlarge
    steps:
      - checkout
      - restore_dependencies:
          go-version: "<< parameters.go-version >>"
      - install_tools
      - save_dependencies:
          go-version: "<< parameters.go-version >>"
      - persist_to_workspace:
          root: /go
          paths:
            - bin
            - pkg/mod/cache

  test:
    parameters:
      go-version:
        type: string
    executor:
      name: golang
      go-version: "<< parameters.go-version >>"
    resource_class: xlarge
    steps:
      - run:
          name: Test and take a coverage
          environment:
            GOTESTSUM_FORMAT: standard-verbose
            GOTESTSUM_JUNITFILE: /tmp/test-results/tests.xml
            GOTESTSUM_JSONFILE: /tmp/test-results/tests.json
          command: |
            mkdir -p /tmp/test-results
            make coverage
      - codecov/upload:
          when: on_success

  lint:
    parameters:
      go-version:
        type: string
    executor:
      name: golang
      go-version: "<< parameters.go-version >>"
    resource_class: large
    steps:
      - run:
          name: Run fmt and lint for sources
          command: |
            make lint JOBS=${CPUS}
            git add -N . && git diff --exit-code

workflows:
  version: 2
  go1.18:
    jobs:
      - tools:
          name: go1.18-tools
          go-version: "1.18"
      - test:
          name: go1.18-test
          go-version: "1.18"
          requires:
            - go1.18-tools
          pre-steps:
            - setup
          post-steps:
            - store_test_results:
                path: /tmp/test-results
            - store_artifacts:
                path: /tmp/test-results
      - lint:
          name: go1.18-lint
          go-version: "1.18"
          requires:
            - go1.18-tools
          pre-steps:
            - setup
