version: 2

defaults: &defaults
  working_directory: /go/src/github.com/tendermint/tendermint
  docker:
    - image: circleci/golang
  environment:
    GOBIN: /tmp/workspace/bin

docs_update_config: &docs_update_config
  working_directory: ~/repo
  docker:
    - image: tendermintdev/jq_curl
  environment:
    AWS_REGION: us-east-1

release_management_docker: &release_management_docker
  machine: true

jobs:
  setup_dependencies:
    <<: *defaults
    steps:
      - run: mkdir -p /tmp/workspace/bin
      - run: mkdir -p /tmp/workspace/profiles
      - checkout
      - restore_cache:
          keys:
            - v3-pkg-cache
      - run:
          name: tools
          command: |
            export PATH="$GOBIN:$PATH"
            make get_tools
      - run:
          name: dependencies
          command: |
            export PATH="$GOBIN:$PATH"
            make get_vendor_deps
      - run:
          name: binaries
          command: |
            export PATH="$GOBIN:$PATH"
            make install install_abci
      - persist_to_workspace:
          root: /tmp/workspace
          paths:
            - bin
            - profiles
      - save_cache:
          key: v3-pkg-cache
          paths:
            - /go/pkg
      - save_cache:
          key: v3-tree-{{ .Environment.CIRCLE_SHA1 }}
          paths:
            - /go/src/github.com/tendermint/tendermint

  build_slate:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /tmp/workspace
      - restore_cache:
          key: v3-pkg-cache
      - restore_cache:
          key: v3-tree-{{ .Environment.CIRCLE_SHA1 }}
      - run:
          name: slate docs
          command: |
            set -ex
            export PATH="$GOBIN:$PATH"
            make build-slate

  lint:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /tmp/workspace
      - restore_cache:
          key: v3-pkg-cache
      - restore_cache:
          key: v3-tree-{{ .Environment.CIRCLE_SHA1 }}
      - run:
          name: metalinter
          command: |
            set -ex
            export PATH="$GOBIN:$PATH"
            make lint
      - run:
          name: check_dep
          command: |
            set -ex
            export PATH="$GOBIN:$PATH"
            make check_dep

  test_abci_apps:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /tmp/workspace
      - restore_cache:
          key: v3-pkg-cache
      - restore_cache:
          key: v3-tree-{{ .Environment.CIRCLE_SHA1 }}
      - run:
          name: Run abci apps tests
          command: |
            export PATH="$GOBIN:$PATH"
            bash abci/tests/test_app/test.sh

# if this test fails, fix it and update the docs at:
# https://github.com/tendermint/tendermint/blob/develop/docs/abci-cli.md
  test_abci_cli:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /tmp/workspace
      - restore_cache:
          key: v3-pkg-cache
      - restore_cache:
          key: v3-tree-{{ .Environment.CIRCLE_SHA1 }}
      - run:
          name: Run abci-cli tests
          command: |
            export PATH="$GOBIN:$PATH"
            bash abci/tests/test_cli/test.sh

  test_apps:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /tmp/workspace
      - restore_cache:
          key: v3-pkg-cache
      - restore_cache:
          key: v3-tree-{{ .Environment.CIRCLE_SHA1 }}
      - run: sudo apt-get update && sudo apt-get install -y --no-install-recommends bsdmainutils
      - run:
          name: Run tests
          command: bash test/app/test.sh

  test_cover:
    <<: *defaults
    parallelism: 4
    steps:
      - attach_workspace:
          at: /tmp/workspace
      - restore_cache:
          key: v3-pkg-cache
      - restore_cache:
          key: v3-tree-{{ .Environment.CIRCLE_SHA1 }}
      - run: mkdir -p /tmp/logs
      - run:
          name: Run tests
          command: |
            for pkg in $(go list github.com/tendermint/tendermint/... | circleci tests split --split-by=timings); do
              id=$(basename "$pkg")

              go test -v -timeout 5m -race -coverprofile=/tmp/workspace/profiles/$id.out -covermode=atomic "$pkg" | tee "/tmp/logs/$id-$RANDOM.log"
            done
      - persist_to_workspace:
          root: /tmp/workspace
          paths:
            - "profiles/*"
      - store_artifacts:
          path: /tmp/logs

  test_persistence:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /tmp/workspace
      - restore_cache:
          key: v3-pkg-cache
      - restore_cache:
          key: v3-tree-{{ .Environment.CIRCLE_SHA1 }}
      - run:
          name: Run tests
          command: bash test/persist/test_failure_indices.sh

  localnet:
      working_directory: /home/circleci/.go_workspace/src/github.com/tendermint/tendermint
      machine:
        image: circleci/classic:latest
      environment:
        GOBIN: /home/circleci/.go_workspace/bin
        GOPATH: /home/circleci/.go_workspace/
        GOOS: linux
        GOARCH: amd64
      parallelism: 1
      steps:
        - checkout
        - run:
            name: run localnet and exit on failure
            command: |
              set -x
              docker run --rm -v "$PWD":/go/src/github.com/tendermint/tendermint -w /go/src/github.com/tendermint/tendermint golang make build-linux
              make localnet-start &
              ./scripts/localnet-blocks-test.sh 40 5 10 localhost

  test_p2p:
    environment:
      GOBIN: /home/circleci/.go_workspace/bin
      GOPATH: /home/circleci/.go_workspace
    machine:
      image: circleci/classic:latest
    steps:
      - checkout
      - run: mkdir -p $GOPATH/src/github.com/tendermint
      - run: ln -sf /home/circleci/project $GOPATH/src/github.com/tendermint/tendermint
      - run: bash test/p2p/circleci.sh
      - store_artifacts:
          path: /home/circleci/project/test/p2p/logs

  upload_coverage:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /tmp/workspace
      - restore_cache:
          key: v3-pkg-cache
      - restore_cache:
          key: v3-tree-{{ .Environment.CIRCLE_SHA1 }}
      - run:
          name: gather
          command: |
            set -ex

            echo "mode: atomic" > coverage.txt
            for prof in $(ls /tmp/workspace/profiles/); do
              tail -n +2 /tmp/workspace/profiles/"$prof" >> coverage.txt
            done
      - run:
          name: upload
          command: bash .circleci/codecov.sh -f coverage.txt

  deploy_docs:
    <<: *docs_update_config
    steps:
      - checkout
      - run:
          name: Trigger website build
          command: |
            curl --silent \
                 --show-error \
                 -X POST \
                 --header "Content-Type: application/json" \
                 -d "{\"branch\": \"$CIRCLE_BRANCH\"}" \
                 "https://circleci.com/api/v1.1/project/github/$CIRCLE_PROJECT_USERNAME/$WEBSITE_REPO_NAME/build?circle-token=$TENDERBOT_API_TOKEN" > response.json

            RESULT=`jq -r '.status' response.json`
            MESSAGE=`jq -r '.message' response.json`

            if [[ ${RESULT} == "null" ]] || [[ ${RESULT} -ne "200" ]]; then
                echo "CircleCI API call failed: $MESSAGE"
                exit 1
            else
                echo "Website build started"
            fi

  prepare_build:
    <<: *defaults
    steps:
      - checkout
      - run:
          name: Get next release number
          command: |
            export LAST_TAG="`git describe --tags --abbrev=0 --match "${CIRCLE_BRANCH}.*"`"
            echo "Last tag: ${LAST_TAG}"
            if [ -z "${LAST_TAG}" ]; then
              export LAST_TAG="${CIRCLE_BRANCH}"
              echo "Last tag not found. Possibly fresh branch or feature branch. Setting ${LAST_TAG} as tag."
            fi
            export NEXT_TAG="`python -u scripts/release_management/bump-semver.py --version "${LAST_TAG}"`"
            echo "Next tag: ${NEXT_TAG}"
            echo "export CIRCLE_TAG=\"${NEXT_TAG}\"" > release-version.source
      - run:
          name: Build dependencies
          command: |
            make get_tools get_vendor_deps
      - persist_to_workspace:
          root: .
          paths:
            - "release-version.source"
      - save_cache:
          key: v1-release-deps-{{ .Branch }}-{{ .Revision }}
          paths:
            - "vendor"

  build_artifacts:
    <<: *defaults
    parallelism: 4
    steps:
      - checkout
      - restore_cache:
          keys:
            - v1-release-deps-{{ .Branch }}-{{ .Revision }}
      - attach_workspace:
          at: /tmp/workspace
      - run:
          name: Build artifact
          command: |
            # Setting CIRCLE_TAG because we do not tag the release ourselves.
            source /tmp/workspace/release-version.source
            if test ${CIRCLE_NODE_INDEX:-0} == 0 ;then export GOOS=linux GOARCH=amd64   && export OUTPUT=build/tendermint_${GOOS}_${GOARCH} && make build && python -u scripts/release_management/zip-file.py ;fi
            if test ${CIRCLE_NODE_INDEX:-0} == 1 ;then export GOOS=darwin GOARCH=amd64  && export OUTPUT=build/tendermint_${GOOS}_${GOARCH} && make build && python -u scripts/release_management/zip-file.py ;fi
            if test ${CIRCLE_NODE_INDEX:-0} == 2 ;then export GOOS=windows GOARCH=amd64 && export OUTPUT=build/tendermint_${GOOS}_${GOARCH} && make build && python -u scripts/release_management/zip-file.py ;fi
            if test ${CIRCLE_NODE_INDEX:-0} == 3 ;then export GOOS=linux GOARCH=arm     && export OUTPUT=build/tendermint_${GOOS}_${GOARCH} && make build && python -u scripts/release_management/zip-file.py ;fi
      - persist_to_workspace:
          root: build
          paths:
            - "*.zip"
            - "tendermint_linux_amd64"

  release_artifacts:
    <<: *defaults
    steps:
      - checkout
      - attach_workspace:
          at: /tmp/workspace
      - run:
          name: Deploy to GitHub
          command: |
            # Setting CIRCLE_TAG because we do not tag the release ourselves.
            source /tmp/workspace/release-version.source
            echo "---"
            ls -la /tmp/workspace/*.zip
            echo "---"
            python -u scripts/release_management/sha-files.py
            echo "---"
            cat /tmp/workspace/SHA256SUMS
            echo "---"
            export RELEASE_ID="`python -u scripts/release_management/github-draft.py`"
            echo "Release ID: ${RELEASE_ID}"
            #Todo: Parallelize uploads
            export GOOS=linux GOARCH=amd64   && python -u scripts/release_management/github-upload.py --id "${RELEASE_ID}"
            export GOOS=darwin GOARCH=amd64  && python -u scripts/release_management/github-upload.py --id "${RELEASE_ID}"
            export GOOS=windows GOARCH=amd64 && python -u scripts/release_management/github-upload.py --id "${RELEASE_ID}"
            export GOOS=linux GOARCH=arm     && python -u scripts/release_management/github-upload.py --id "${RELEASE_ID}"
            python -u scripts/release_management/github-upload.py --file "/tmp/workspace/SHA256SUMS" --id "${RELEASE_ID}"
            python -u scripts/release_management/github-publish.py --id "${RELEASE_ID}"

  release_docker:
    <<: *release_management_docker
    steps:
      - checkout
      - attach_workspace:
          at: /tmp/workspace
      - run:
          name: Deploy to Docker Hub
          command: |
            # Setting CIRCLE_TAG because we do not tag the release ourselves.
            source /tmp/workspace/release-version.source
            cp /tmp/workspace/tendermint_linux_amd64 DOCKER/tendermint
            docker build --label="tendermint" --tag="tendermint/tendermint:${CIRCLE_TAG}" --tag="tendermint/tendermint:latest" "DOCKER"
            docker login -u "${DOCKERHUB_USER}" --password-stdin <<< "${DOCKERHUB_PASS}"
            docker push "tendermint/tendermint"
            docker logout

workflows:
  version: 2
  test-suite:
    jobs:
      - deploy_docs:
          filters:
            branches:
              only:
                - master
                - develop
      - setup_dependencies
      - lint:
          requires:
            - setup_dependencies
      - test_abci_apps:
          requires:
            - setup_dependencies
      - test_abci_cli:
          requires:
            - setup_dependencies
      - test_apps:
          requires:
            - setup_dependencies
      - test_cover:
          requires:
            - setup_dependencies
      - test_persistence:
          requires:
            - setup_dependencies
      - localnet:
          requires:
            - setup_dependencies
      - test_p2p
      - upload_coverage:
          requires:
            - test_cover
  release:
    jobs:
      - prepare_build
      - build_artifacts:
          requires:
            - prepare_build
      - release_artifacts:
          requires:
            - prepare_build
            - build_artifacts
          filters:
            branches:
              only:
                - /v[0-9]+\.[0-9]+/
      - release_docker:
          requires:
            - prepare_build
            - build_artifacts
          filters:
            branches:
              only:
                - /v[0-9]+\.[0-9]+/
