version: 2.1
commands:
  setup_environment:
    description: "Setup testing environment"
    parameters:
      cache_key:
        type: string
        default: snarkos-stable-cache
    steps:
      - run: set -e
      - setup_remote_docker
      - run:
          name: Prepare environment and install dependencies
          command: |
            export SCCACHE_CACHE_SIZE=200M
            export WORK_DIR="$CIRCLE_WORKING_DIRECTORY/.cache/sccache"
            export SCCACHE_DIR="$CIRCLE_WORKING_DIRECTORY/.cache/sccache"
            mkdir -p "$CIRCLE_WORKING_DIRECTORY/.bin"
            wget https://github.com/mozilla/sccache/releases/download/0.2.13/sccache-0.2.13-x86_64-unknown-linux-musl.tar.gz
            tar -C "$CIRCLE_WORKING_DIRECTORY/.bin" -xvf sccache-0.2.13-x86_64-unknown-linux-musl.tar.gz
            mv $CIRCLE_WORKING_DIRECTORY/.bin/sccache-0.2.13-x86_64-unknown-linux-musl/sccache $CIRCLE_WORKING_DIRECTORY/.bin/sccache
            export PATH="$PATH:$CIRCLE_WORKING_DIRECTORY/.bin"
            export RUSTC_WRAPPER="sccache"
            rm -rf "$CIRCLE_WORKING_DIRECTORY/.cargo/registry"
            sudo apt-get update && sudo apt-get install -y clang llvm-dev llvm pkg-config xz-utils make libssl-dev libssl-dev
      - restore_cache:
          keys:
            - << parameters.cache_key >>
  clear_environment:
    description: "Clear environment"
    parameters:
      cache_key:
        type: string
        default: snarkos-stable-cache
    steps:
      - run: (sccache -s||true)
      - run: set +e
      - save_cache:
          key: << parameters.cache_key >>
          paths:
            - .cache/sccache
            - .cargo
  install_rust_nightly:
    description: "Install Rust nightly toolchain"
    steps:
      - run:
          command: |
            rustup toolchain install nightly-x86_64-unknown-linux-gnu

jobs:
  tests:
    docker:
      - image: cimg/rust:1.57.0
    resource_class: xlarge
    parallelism: 10
    steps:
      - checkout
      - setup_environment:
          cache_key: snarkos-stable-cache
      - run:
          name: Build and run tests
          no_output_timeout: 35m
          command: |
            cargo test -- --list --format terse | sed 's/: test//' > test_names.txt
            TEST_NAMES=$(circleci tests split test_names.txt)
            for i in $(echo $TEST_NAMES | sed "s/ / /g")
            do
                RUST_MIN_STACK=8388608 cargo test --workspace $i
            done
      - clear_environment:
          cache_key: snarkos-stable-cache

  storage:
    docker:
      - image: cimg/rust:1.57.0
    resource_class: xlarge
    parallelism: 5
    steps:
      - checkout
      - setup_environment:
          cache_key: snarkos-storage-cache
      - run:
          name: Build and run tests
          no_output_timeout: 35m
          command: |
            cd storage
            cargo test -- --list --format terse | sed 's/: test//' > test_names.txt
            TEST_NAMES=$(circleci tests split test_names.txt)
            for i in $(echo $TEST_NAMES | sed "s/ / /g")
            do
                RUST_MIN_STACK=8388608 cargo test --workspace $i
            done
      - clear_environment:
          cache_key: snarkos-storage-cache

  testing:
    docker:
      - image: cimg/rust:1.57.0
    resource_class: xlarge
    parallelism: 5
    steps:
      - checkout
      - setup_environment:
          cache_key: snarkos-testing-cache
      - run:
          name: Build and run tests
          no_output_timeout: 35m
          command: |
            cd testing
            cargo test -- --list --format terse | sed 's/: test//' > test_names.txt
            TEST_NAMES=$(circleci tests split test_names.txt)
            for i in $(echo $TEST_NAMES | sed "s/ / /g")
            do
                RUST_MIN_STACK=8388608 cargo test --workspace $i
            done
      - clear_environment:
          cache_key: snarkos-testing-cache

  # codecov:
  #   machine:
  #     image: ubuntu-1604:202004-01
  #     docker_layer_caching: true
  #   resource_class: xlarge
  #   steps:
  #     - attach_workspace:
  #         at: /home/circleci/project/
  #     - run:
  #         name: Run kcov
  #         command: >
  #           cd ~/project/project/ &&
  #           docker run --security-opt seccomp=unconfined -v ~/project/project/:/home/circleci/project/
  #           howardwu/snarkos-codecov:2021-03-25 bash /home/circleci/project/ci/kcov.sh
  #     - run: cd ./project/ && bash <(curl -s https://codecov.io/bash)

  fmt:
    docker:
      - image: cimg/rust:1.57.0
    resource_class: xlarge
    steps:
      - checkout
      - install_rust_nightly
      - setup_environment:
          cache_key: snarkos-fmt-cache
      - run:
          name: Check style
          no_output_timeout: 35m
          command: cargo +nightly fmt --all -- --check
      - clear_environment:
          cache_key: snarkos-fmt-cache

  clippy:
    docker:
      - image: cimg/rust:1.57.0
    resource_class: xlarge
    steps:
      - checkout
      - install_rust_nightly
      - setup_environment:
          cache_key: snarkos-clippy-cache
      - run:
          name: Check style
          no_output_timeout: 35m
          command: cargo +nightly clippy --workspace --all-targets
      - clear_environment:
          cache_key: snarkos-clippy-cache


  build-and-publish-docker-arm:
    machine:
      image: ubuntu-2004:202101-01
      docker_layer_caching: true
    resource_class: arm.large
    steps:
      - checkout
      - run: mkdir -p my_workspace
      - run:
          name: "Build snarkos Docker Image ARM V8"
          no_output_timeout: 2h
          command: |
            VERSION=$(git rev-parse --short HEAD)
            docker build -f Dockerfile -t $DOCKER_REPO:$CIRCLE_BRANCH-$VERSION-arm64 .
      - run:
          name: "Push snarkos Docker Image ARM V8"
          command: |
            VERSION=$(git rev-parse --short HEAD)
            echo $DOCKERHUB_TOKEN | docker login -u $DOCKERHUB_USERNAME --password-stdin
            # CREATE THE SHELL FILE WITH IMAGE NAME AND TAG
            docker push $DOCKER_REPO:$CIRCLE_BRANCH-$VERSION-arm64
            echo "Pushed $DOCKER_REPO:$CIRCLE_BRANCH-$VERSION-arm64"
      - run:
          name: "Save arm64 image tag"
          command: |
            VERSION=$(git rev-parse --short HEAD)
            echo "$CIRCLE_BRANCH-$VERSION-arm64" > my_workspace/docker_tag_arm
      - persist_to_workspace:
          root: my_workspace
          paths:
            - docker_tag_arm

  build-and-publish-docker-amd:
    machine:
      image: ubuntu-2004:202101-01
      docker_layer_caching: true
    resource_class: xlarge
    steps:
      - checkout
      - run: mkdir -p my_workspace
      - run:
          name: "Build snarkos Docker Image AMD"
          no_output_timeout: 2h
          command: |
            VERSION=$(git rev-parse --short HEAD)
            docker build -f Dockerfile -t $DOCKER_REPO:$CIRCLE_BRANCH-$VERSION-amd64 .
      - run:
          name: "Push snarkos Docker Image AMD"
          command: |
            VERSION=$(git rev-parse --short HEAD)
            echo $DOCKERHUB_TOKEN | docker login -u $DOCKERHUB_USERNAME --password-stdin
            docker push $DOCKER_REPO:$CIRCLE_BRANCH-$VERSION-amd64
            echo "Pushed $DOCKER_REPO:$CIRCLE_BRANCH-$VERSION-amd64"
      - run:
          name: "Save amd64 image tag"
          command: |
            VERSION=$(git rev-parse --short HEAD)
            echo "$CIRCLE_BRANCH-$VERSION-amd64" > my_workspace/docker_tag_amd
      - persist_to_workspace:
          root: my_workspace
          paths:
            - docker_tag_amd

  publish_snarkos_manifest:
    machine:
      image: ubuntu-2004:202101-01
      docker_layer_caching: true
    resource_class: medium
    steps:
      - checkout
      - attach_workspace:
          at: my_workspace
      - run:
          name: "Pull ARM docker image"
          command: |
            ARM_TAG=$(cat my_workspace/docker_tag_arm)
            echo $ARM_TAG
            echo $DOCKERHUB_TOKEN | docker login -u $DOCKERHUB_USERNAME --password-stdin
            docker pull $DOCKER_REPO:$ARM_TAG
      - run:
          name: "Pull AMD docker image"
          command: |
            AMD_TAG=$(cat my_workspace/docker_tag_amd)
            echo $AMD_TAG
            docker pull $DOCKER_REPO:$AMD_TAG
      - run:
          name: "Create and push docker multi arch manifest"
          command: |
            ARM_TAG=$(cat my_workspace/docker_tag_arm)
            AMD_TAG=$(cat my_workspace/docker_tag_amd)
            echo $DOCKERHUB_TOKEN | docker login -u $DOCKERHUB_USERNAME --password-stdin
            echo $DOCKER_REPO
            echo $CIRCLE_BRANCH
            echo $ARM_TAG
            echo $AMD_TAG
            docker manifest create $DOCKER_REPO:${CIRCLE_BRANCH}-latest --amend $DOCKER_REPO:${ARM_TAG} --amend $DOCKER_REPO:${AMD_TAG}
            docker manifest inspect $DOCKER_REPO:${CIRCLE_BRANCH}-latest
            docker manifest push $DOCKER_REPO:${CIRCLE_BRANCH}-latest
            echo "Pushed $DOCKER_REPO:${CIRCLE_BRANCH}-latest"

workflows:
  main-workflow:
    jobs:
      - tests
      - storage
      - testing
      # - codecov:
      #     requires:
      #       - rust-stable
      - fmt
      - clippy
  build-snarkos-docker-images:
    when:
      or:
        - equal: [ testnet2, << pipeline.git.branch >> ]
        - equal: [ docker-builds, << pipeline.git.branch >> ]
    jobs:
      - build-and-publish-docker-arm
      - build-and-publish-docker-amd
      - publish_snarkos_manifest:
          requires:
            - build-and-publish-docker-arm
            - build-and-publish-docker-amd
