version: 2.1

executors:
  go-builder:
    docker:
      - image: ethereumoptimism/go-builder:latest

commands:
  go-lint-test:
    parameters:
      working_directory:
        description: Working directory
        type: string
    steps:
      - checkout
      - run:
          name: Lint
          command: golangci-lint run -E goimports -E sqlclosecheck -E bodyclose -E asciicheck ./...
          working_directory: <<parameters.working_directory>>
      - run:
          name: Test
          command: |
            mkdir -p /test-results
            gotestsum --junitfile /test-results/tests.xml
          working_directory: <<parameters.working_directory>>
      - store_test_results:
          path: /test-results

jobs:
  go-lint-test:
    parameters:
      working_directory:
        description: Working directory
        type: string
    docker:
      - image: ethereumoptimism/go-builder:latest
      - image: cimg/postgres:14.1
    steps:
      - go-lint-test:
          working_directory: <<parameters.working_directory>>

  go-lint-test-build:
    parameters:
      binary_name:
        description: Binary name to build
        type: string
      working_directory:
        description: Working directory
        type: string
    docker:
      - image: ethereumoptimism/go-builder:latest
      - image: cimg/postgres:14.1
    steps:
      - go-lint-test:
          working_directory: <<parameters.working_directory>>
      - run:
          name: Build
          command: make <<parameters.binary_name>>
          working_directory: <<parameters.working_directory>>

  yarn-monorepo:
    docker:
      - image: ethereumoptimism/js-builder:latest
    steps:
      - restore_cache:
          keys:
            - v2-cache-source-{{ .Branch }}-{{ .Revision }}
            - v2-cache-source-{{ .Branch }}
      - checkout
      - save_cache:
          key: v2-cache-source-{{ .Branch }}-{{ .Revision }}
          paths:
            - ".git"
      - restore_cache:
          keys:
            - v2-cache-yarn-install-{{ checksum "yarn.lock" }}
            - v2-cache-yarn-install
      - run:
          name: Install dependencies
          command: yarn --frozen-lockfile
      - save_cache:
          key: v2-cache-yarn-install-{{ checksum "yarn.lock" }}
          paths:
            - node_modules
            - packages/common-ts/node_modules
            - packages/contracts/node_modules
            - packages/core-utils/node_modules
            - packages/data-transport-layer/node_modules
            - packages/fault-detector/node_modules
            - packages/message-relayer/node_modules
            - packages/replica-healthcheck/node_modules
            - packages/sdk/node_modules
            - integration-tests/node_modules
      - run:
          name: Build monorepo
          command: yarn build
      - save_cache:
          key: v2-cache-yarn-build-{{ .Revision }}
          paths:
            - "."

  contracts-slither:
    docker:
      - image: ethereumoptimism/js-builder:latest
    steps:
      - restore_cache:
          keys:
            - v2-cache-yarn-build-{{ .Revision }}
      - checkout
      - run:
          name: Run Slither
          command: yarn test:slither
          working_directory: packages/contracts

  contracts-tests:
    docker:
      - image: ethereumoptimism/js-builder:latest
    resource_class: xlarge
    steps:
      - restore_cache:
          keys:
            - v2-cache-yarn-build-{{ .Revision }}
      - checkout
      - run:
          name: Lint
          command: yarn lint:check
          working_directory: packages/contracts
      - run:
          name: Check deployment docs
          command: yarn autogen:markdown && git diff --exit-code
          working_directory: packages/contracts
      - run:
          name: Slither
          command: yarn test:slither
          working_directory: packages/contracts
      - run:
          name: Test
          command: yarn test:coverage
          working_directory: packages/contracts

  dtl-tests:
    docker:
      - image: ethereumoptimism/js-builder:latest
    steps:
      - restore_cache:
          keys:
            - v2-cache-yarn-build-{{ .Revision }}
      - checkout
      - run:
          name: Test
          command: yarn test:coverage
          working_directory: packages/data-transport-layer

  geth-tests:
    docker:
      - image: ethereumoptimism/go-builder:latest
    steps:
      - checkout
      - run:
          name: Test
          command: make test
          working_directory: l2geth

  depcheck:
    docker:
      - image: ethereumoptimism/js-builder:latest
    steps:
      - restore_cache:
          keys:
            - v2-cache-yarn-build-{{ .Revision }}
      - checkout
      # Note: The below needs to be manually configured whenever we
      # add a new package to CI.
      - run:
          name: Check contracts
          command: npx depcheck
          working_directory: packages/contracts
      - run:
          name: Check core-utils
          command: npx depcheck
          working_directory: packages/core-utils
      - run:
          name: Check data-transport-layer
          command: npx depcheck
          working_directory: packages/data-transport-layer
      - run:
          name: Check sdk
          command: npx depcheck
          working_directory: packages/sdk
      - run:
          name: Check integration-tests
          command: npx depcheck
          working_directory: integration-tests

  bss-core-tests:
    docker:
      - image: ethereumoptimism/go-builder:latest
    steps:
      - checkout
      - run:
          name: Lint
          command: golangci-lint run -E goimports -E sqlclosecheck -E bodyclose -E asciicheck ./...
          working_directory: bss-core
      - run:
          name: Test
          command: |
            mkdir -p /test-results
            gotestsum --junitfile /test-results/tests.xml
          working_directory: bss-core
      - store_test_results:
          path: /test-results

  integration-tests:
    machine:
      image: ubuntu-2004:202111-02
      docker_layer_caching: true
    environment:
      DOCKER_BUILDKIT: 1
    parallelism: 3
    steps:
      - checkout
      - run:
          name: Bring up the stack
          command: |
            docker-compose build --progress=plain
            docker-compose up -d --scale replica_healthcheck=1
          working_directory: ops
      - run:
          name: Wait for sequencer
          command: bash scripts/wait-for-sequencer.sh
          working_directory: ops
      - run:
          name: Run integration tests
          command: |
            circleci tests glob "../integration-tests/test/*.spec.ts" | circleci tests split | tee splits.txt
            docker-compose run integration_tests $(cat splits.txt)
          working_directory: ops

  js-lint-test:
    parameters:
      package_name:
        description: Package name
        type: string
    docker:
      - image: ethereumoptimism/js-builder:latest
    steps:
      - restore_cache:
          keys:
            - v2-cache-yarn-build-{{ .Revision }}
      - checkout
      - run:
          name: Lint
          command: yarn lint:check
          working_directory: packages/<<parameters.package_name>>
      - run:
          name: Test
          command: yarn test:coverage
          working_directory: packages/<<parameters.package_name>>

  docker-publish:
    environment:
      DOCKER_BUILDKIT: 1
    parameters:
      docker_tags:
        description: Docker image tags as csv
        type: string
      docker_file:
        description: Path to Dockerfile
        type: string
      docker_context:
        description: Docker build context
        type: string
      target:
        description: Docker build target
        type: string
        default: ""
    docker:
      - image: circleci/buildpack-deps:stretch
    steps:
      - checkout
      - setup_remote_docker:
          version: 20.10.12
      - when:
          condition: <<parameters.target>>
          steps:
            - run:
                name: Build with context
                command: |
                    docker build \
                    $(echo -ne "<< parameters.docker_tags >>" | sed "s/,/\n/g" | sed -e 's/^/-t /' | tr '\n' ' ') \
                    -f <<parameters.docker_file>> \
                    --target <<parameters.target>> \
                    <<parameters.docker_context>>
      - unless:
          condition: <<parameters.target>>
          steps:
            - run:
                name: Build
                command: |
                    docker build \
                    $(echo -ne "<< parameters.docker_tags >>" | sed "s/,/\n/g" | sed -e 's/^/-t /' | tr '\n' ' ') \
                    -f <<parameters.docker_file>> \
                    <<parameters.docker_context>>
      - run:
          name: Publish
          command: |
            echo "$DOCKER_PASS" | docker login -u "$DOCKER_USERNAME" --password-stdin
            docker push <<parameters.docker_tags>>

workflows:
  main:
    jobs:
      - yarn-monorepo
      - go-lint-test-build:
          name: batch-submitter-tests
          binary_name: batch-submitter
          working_directory: batch-submitter
      - go-lint-test-build:
          name: proxyd-tests
          binary_name: proxyd
          working_directory: proxyd
      - go-lint-test-build:
          name: teleportr-tests
          binary_name: teleportr
          working_directory: teleportr
      - go-lint-test-build:
          name: gas-oracle-tests
          binary_name: gas-oracle
          working_directory: gas-oracle
      - go-lint-test-build:
          name: indexer-tests
          binary_name: indexer
          working_directory: indexer
      - go-lint-test:
          name: bss-core-tests
          working_directory: bss-core
      - contracts-tests:
          requires:
            - yarn-monorepo
      - js-lint-test:
          name: dtl-tests
          package_name: data-transport-layer
          requires:
            - yarn-monorepo
      - js-lint-test:
          name: core-utils-tests
          package_name: core-utils
          requires:
            - yarn-monorepo
      - js-lint-test:
          name: sdk-tests
          package_name: sdk
          requires:
            - yarn-monorepo
      - js-lint-test:
          name: fault-detector-tests
          package_name: fault-detector
          requires:
            - yarn-monorepo
      - js-lint-test:
          name: message-relayer-tests
          package_name: message-relayer
          requires:
            - yarn-monorepo
      - js-lint-test:
          name: replica-healthcheck-tests
          package_name: replica-healthcheck
          requires:
            - yarn-monorepo
      - depcheck:
          requires:
            - yarn-monorepo
      - geth-tests
      - integration-tests

  nightly:
    triggers:
      - schedule:
          cron: "0 10 * * *"
          filters:
            branches:
              only:
                - develop
    jobs:
      - yarn-monorepo
      - docker-publish:
          name: l2geth-release
          docker_file: l2geth/Dockerfile
          docker_tags: ethereumoptimism/l2geth:nightly
          docker_context: .
          context:
            - optimism
      - docker-publish:
          name: gas-oracle-release
          docker_file: gas-oracle/Dockerfile
          docker_tags: ethereumoptimism/gas-oracle:nightly
          docker_context: .
          context:
            - optimism
      - docker-publish:
          name: hardhat-node-release
          docker_file: ops/docker/hardhat/Dockerfile
          docker_tags: ethereumoptimism/hardhat-node:nightly
          docker_context: ops/docker/hardhat
          context:
            - optimism
      - docker-publish:
          name: go-builder-release
          docker_file: ops/docker/go-builder/Dockerfile
          docker_tags: ethereumoptimism/go-builder:nightly
          docker_context: .
          context:
            - optimism
      - docker-publish:
          name: js-builder-release
          docker_file: ops/docker/js-builder/Dockerfile
          docker_tags: ethereumoptimism/js-builder:nightly
          docker_context: .
          context:
            - optimism
      - docker-publish:
          name: proxyd-release
          docker_file: proxyd/Dockerfile
          docker_tags: ethereumoptimism/proxyd:nightly
          docker_context: .
          context:
            - optimism
      - docker-publish:
          name: l2geth-exporter-release
          docker_file: l2geth-exporter/Dockerfile
          docker_tags: ethereumoptimism/l2geth-exporter:nightly
          docker_context: .
          context:
            - optimism
      - docker-publish:
          name: op-exporter-release
          docker_file: op-exporter/Dockerfile
          docker_tags: ethereumoptimism/op-exporter:nightly
          docker_context: .
          context:
            - optimism
      - docker-publish:
          name: fault-detector-release
          docker_file: ops/docker/Dockerfile.packages
          docker_tags: ethereumoptimism/fault-detector:nightly
          docker_context: .
          target: fault-detector
          context:
            - optimism
      - docker-publish:
          name: message-relayer-release
          docker_file: ops/docker/Dockerfile.packages
          docker_tags: ethereumoptimism/message-relayer:nightly
          docker_context: .
          target: message-relayer
          context:
            - optimism
      - docker-publish:
          name: data-transport-layer-release
          docker_file: ops/docker/Dockerfile.packages
          docker_tags: ethereumoptimism/data-transport-layer:nightly
          docker_context: .
          target: data-transport-layer
          context:
            - optimism
      - docker-publish:
          name: integration-tests-release
          docker_file: ops/docker/Dockerfile.packages
          docker_tags: ethereumoptimism/integration-tests:nightly
          docker_context: .
          target: integration-tests
          context:
            - optimism
      - docker-publish:
          name: replica-healthcheck-release
          docker_file: ops/docker/Dockerfile.packages
          docker_tags: ethereumoptimism/replica-healthcheck:nightly
          docker_context: .
          target: replica-healthcheck
          context:
            - optimism
      - docker-publish:
          name: batch-submitter-service-release
          docker_file: ops/docker/Dockerfile
          docker_tags: ethereumoptimism/batch-submitter-service:nightly
          docker_context: .
          context:
            - optimism
      - docker-publish:
          name: indexer-release
          docker_file: indexer/Dockerfile
          docker_tags: ethereumoptimism/indexer:nightly
          docker_context: .
          context:
            - optimism
      - docker-publish:
          name: teleportr-release
          docker_file: teleportr/Dockerfile
          docker_tags: ethereumoptimism/teleportr:nightly
          docker_context: .
          context:
            - optimism
