defaults: &defaults
  working_directory: /home/circleci/metabase/metabase/
  docker:
    - image: circleci/clojure:lein-2.8.1-node-browsers

restore-be-deps-cache: &restore-be-deps-cache
  keys:
    - be-deps-{{ checksum "project.clj" }}
    - be-deps-

restore-fe-deps-cache: &restore-fe-deps-cache
  keys:
    - fe-deps-{{ checksum "yarn.lock" }}
    - fe-deps-

version: 2.1
jobs:

########################################################################################################################
#                                                       CHECKOUT                                                       #
########################################################################################################################

  checkout:
    <<: *defaults
    steps:
      - restore_cache:
          keys:
            - source-{{ .Branch }}-{{ .Revision }}
            - source-{{ .Branch }}
            - source-
      - checkout
      - save_cache:
          key: source-{{ .Branch }}-{{ .Revision }}
          paths:
            - .git
      # The basic idea here is to generate a file with checksums for all the backend source files, and save it as
      # `./backend-checksums.txt`. Then we'll use the checksum of that files for uberjar caching; thus we can reuse
      # the same uberjar for integration tests across any build where the backend files are the same
      - run:
          name: Generate checksums of all backend source files to use as Uberjar cache key
          command: >
            for file in `find ./src -type f -name '*.clj' | sort`;
              do echo `md5sum $file` >> backend-checksums.txt;
            done
      - persist_to_workspace:
          root: /home/circleci/
          paths:
            - metabase/metabase

########################################################################################################################
#                                                       BACKEND                                                        #
########################################################################################################################

  be-deps:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run: lein deps
      - save_cache:
          key: be-deps-{{ checksum "project.clj" }}
          paths:
            - /home/circleci/.m2

  be-tests:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run:
          name: Run backend unit tests
          command: lein with-profile +ci test
          no_output_timeout: 5m

  be-linter-eastwood:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run:
          name: Run Eastwood linter
          command: lein with-profile +ci eastwood
          no_output_timeout: 5m

  be-linter-docstring-checker:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run:
          name: Run dockstring-checker
          command: lein with-profile +ci docstring-checker
          no_output_timeout: 5m

  be-linter-bikeshed:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run:
          name: Run dockstring-checker
          command: lein with-profile +ci bikeshed
          no_output_timeout: 5m

  be-linter-reflection-warnings:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run:
          name: Run dockstring-checker
          command: ./bin/reflection-linter
          no_output_timeout: 5m

  be-tests-mysql:
    working_directory: /home/circleci/metabase/metabase/
    docker:
      - image: circleci/clojure:lein-2.8.1-node-browsers
      - image: circleci/mysql:5.7.23
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run:
          name: Run backend unit tests (MySQL)
          environment:
            ENGINES: h2,mysql
            MB_ENCRYPTION_SECRET_KEY: Orw0AAyzkO/kPTLJRxiyKoBHXa/d6ZcO+p+gpZO/wSQ=
            MB_DB_TYPE: mysql
            MB_DB_HOST: localhost
            MB_DB_PORT: 3306
            MB_DB_DBNAME: circle_test
            MB_DB_USER: root
            MB_MYSQL_TEST_USER: root
          command: >
            /home/circleci/metabase/metabase/.circleci/skip-driver-tests.sh mysql ||
            lein with-profile +ci test
          no_output_timeout: 5m

  be-tests-postgres:
    working_directory: /home/circleci/metabase/metabase/
    docker:
      - image: circleci/clojure:lein-2.8.1-node-browsers
      - image: circleci/postgres:9.6-alpine
        environment:
          POSTGRES_USER: circle_test
          POSTGRES_DB: circle_test
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run:
          name: Run backend unit tests (Postgres)
          environment:
            ENGINES: h2,postgres
            MB_DB_TYPE: postgres
            MB_DB_PORT: 5432
            MB_DB_HOST: localhost
            MB_DB_DBNAME: circle_test
            MB_DB_USER: circle_test
            MB_POSTGRESQL_TEST_USER: circle_test
          command: >
            /home/circleci/metabase/metabase/.circleci/skip-driver-tests.sh postgres ||
            lein with-profile +ci test
          no_output_timeout: 5m

  be-tests-sparksql:
    working_directory: /home/circleci/metabase/metabase/
    docker:
      - image: circleci/clojure:lein-2.8.1-node-browsers
      - image: metabase/spark:2.1.1
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run:
          name: Make plugins dir
          command: mkdir /home/circleci/metabase/metabase/plugins
      - run:
          name: Download SparkSQL deps JAR
          command: wget --output-document=plugins/spark-deps.jar https://s3.amazonaws.com/sparksql-deps/metabase-sparksql-deps-1.2.1.spark2-standalone.jar
      - run:
          name: Wait for SparkSQL to be ready
          command: >
            /home/circleci/metabase/metabase/.circleci/skip-driver-tests.sh sparksql ||
            while ! nc -z localhost 10000; do sleep 0.1; done
          no_output_timeout: 5m
      - run:
          name: Run backend unit tests (SparkSQL)
          environment:
            ENGINES: h2,sparksql
          command: >
            /home/circleci/metabase/metabase/.circleci/skip-driver-tests.sh sparksql ||
            lein with-profile +ci test
          no_output_timeout: 5m

  be-tests-mongo:
    working_directory: /home/circleci/metabase/metabase/
    docker:
      - image: circleci/clojure:lein-2.8.1-node-browsers
      - image: circleci/mongo:3.2
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run:
          name: Run backend unit tests (MongoDB 3.2)
          environment:
            ENGINES: h2,mongo
          command: >
            /home/circleci/metabase/metabase/.circleci/skip-driver-tests.sh mongo ||
            lein with-profile +ci test
          no_output_timeout: 5m

  be-tests-vertica:
    working_directory: /home/circleci/metabase/metabase/
    docker:
      - image: circleci/clojure:lein-2.8.1-node-browsers
      - image: sumitchawla/vertica
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run:
          name: Make plugins dir
          command: mkdir /home/circleci/metabase/metabase/plugins
      - run:
          name: Download Vertica JAR
          command: >
            /home/circleci/metabase/metabase/.circleci/skip-driver-tests.sh vertica ||
            wget --output-document=plugins/vertica-jdbc-7.1.2-0.jar $VERTICA_JDBC_JAR
          no_output_timeout: 5m
      - run:
          name: Run backend unit tests (Vertica)
          environment:
            ENGINES: h2,vertica
          command: >
            /home/circleci/metabase/metabase/.circleci/skip-driver-tests.sh vertica ||
            lein with-profile +ci test
          no_output_timeout: 5m

  be-tests-snowflake:
    working_directory: /home/circleci/metabase/metabase/
    docker:
      - image: circleci/clojure:lein-2.8.1-node-browsers
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run:
          name: Run backend unit tests (Snowflake)
          environment:
            ENGINES: h2,snowflake
          command: >
            /home/circleci/metabase/metabase/.circleci/skip-driver-tests.sh snowflake ||
            lein with-profile +ci test
          no_output_timeout: 10m

  be-tests-sqlserver:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run:
          name: Run backend unit tests (SQL Server)
          environment:
            ENGINES: h2,sqlserver
          command: >
            /home/circleci/metabase/metabase/.circleci/skip-driver-tests.sh sqlserver ||
            lein with-profile +ci test
          no_output_timeout: 5m

  be-tests-bigquery:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run:
          name: Run backend unit tests (BigQuery)
          environment:
            ENGINES: h2,bigquery
          command: >
            /home/circleci/metabase/metabase/.circleci/skip-driver-tests.sh bigquery ||
            lein with-profile +ci test
          no_output_timeout: 5m

  be-tests-sqlite:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run:
          name: Run backend unit tests (SQLite)
          environment:
            ENGINES: h2,sqlite
          command: >
            /home/circleci/metabase/metabase/.circleci/skip-driver-tests.sh sqlite ||
            lein with-profile +ci test

  be-tests-druid:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run:
          name: Run backend unit tests (Druid)
          environment:
            ENGINES: h2,druid
          command: >
            /home/circleci/metabase/metabase/.circleci/skip-driver-tests.sh druid ||
            lein with-profile +ci test
          no_output_timeout: 5m

  be-tests-redshift:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run:
          name: Run backend unit tests (Redshift)
          environment:
            ENGINES: h2,redshift
          command: >
            /home/circleci/metabase/metabase/.circleci/skip-driver-tests.sh redshift ||
            lein with-profile +ci test
          no_output_timeout: 5m


  be-tests-presto:
    working_directory: /home/circleci/metabase/metabase/
    docker:
      - image: circleci/clojure:lein-2.8.1-node-browsers
      - image: metabase/presto-mb-ci
        environment:
          JAVA_TOOL_OPTIONS: "-Xmx2g"
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run:
          name: Wait for Presto to be ready
          command: >
            /home/circleci/metabase/metabase/.circleci/skip-driver-tests.sh sparksql ||
            while ! nc -z localhost 8080; do sleep 0.1; done
          no_output_timeout: 5m
      - run:
          name: Run backend unit tests (Presto)
          environment:
            ENGINES: h2,presto
            MB_PRESTO_TEST_HOST: localhost
            MB_PRESTO_TEST_PORT: 8080
          command: >
            /home/circleci/metabase/metabase/.circleci/skip-driver-tests.sh presto ||
            lein with-profile +ci test
          no_output_timeout: 5m


  be-tests-oracle:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - run:
          name: Make plugins dir
          command: mkdir /home/circleci/metabase/metabase/plugins
      - run:
          name: Download Oracle JAR
          command: >
            /home/circleci/metabase/metabase/.circleci/skip-driver-tests.sh oracle ||
            wget --output-document=/home/circleci/metabase/metabase/plugins/ojdbc7.jar $ORACLE_JDBC_JAR
      - run:
          name: Run backend unit tests (Oracle)
          environment:
            ENGINES: h2,oracle
          command: >
            /home/circleci/metabase/metabase/.circleci/skip-driver-tests.sh oracle ||
            lein with-profile +ci test
          no_output_timeout: 5m


########################################################################################################################
#                                                       FRONTEND                                                       #
########################################################################################################################

  fe-deps:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-fe-deps-cache
      - run:
          name: Run yarn if yarn.lock checksum has changed
          command: >
            if [ ! -f yarn.lock.checksum ] || [ "$(md5sum yarn.lock)" != "$(cat yarn.lock.checksum)" ];
              then SAUCE_CONNECT_DOWNLOAD_ON_INSTALL=true yarn;
            fi
          no_output_timeout: 5m
      - run:
          name: Save yarn checksum
          command: md5sum yarn.lock > yarn.lock.checksum
      - save_cache:
          key: fe-deps-{{ checksum "yarn.lock" }}
          paths:
            - /home/circleci/.yarn
            - /home/circleci/.yarn-cache
            - /home/circleci/metabase/metabase/node_modules
            - /home/circleci/yarn.lock.checksum

  fe-linter-eslint:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-fe-deps-cache
      - run:
          name: Run ESLint linter
          command: yarn lint-eslint
          no_output_timeout: 5m

  fe-linter-prettier:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-fe-deps-cache
      - run:
          name: Run Prettier formatting linter
          command: yarn lint-prettier
          no_output_timeout: 5m

  fe-linter-flow:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-fe-deps-cache
      - run:
          name: Run Flow type checker
          command: yarn flow
          no_output_timeout: 5m

  fe-tests-karma:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-fe-deps-cache
      - run:
          name: Run frontend tests (karma)
          command: yarn run test-karma
          no_output_timeout: 5m

  fe-tests-unit:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-fe-deps-cache
      - run:
          name: Run frontend unit tests
          command: yarn run test-unit
          no_output_timeout: 5m

  build-uberjar:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-be-deps-cache
      - restore_cache:
          keys:
            - uberjar-{{ checksum "./backend-checksums.txt" }}
      - run:
          name: Build uberjar if needed
          command: >
            if [ ! -f './target/uberjar/metabase.jar' ];
              then ./bin/build version uberjar;
            fi
          no_output_timeout: 5m
      - save_cache:
          key: uberjar-{{ checksum "./backend-checksums.txt" }}
          paths:
            - /home/circleci/metabase/metabase/target/uberjar/metabase.jar

  fe-tests-integrated:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - restore_cache:
          <<: *restore-fe-deps-cache
      - restore_cache:
          keys:
            - uberjar-{{ checksum "./backend-checksums.txt" }}
      - run:
          name: Generate version file
          command: ./bin/build version
      - run:
          name: Run frontend integrated tests
          command: yarn run test-integrated-no-build
          no_output_timeout: 5m


########################################################################################################################
#                                                   DEPLOYMENT, ETC.                                                   #
########################################################################################################################

  deploy-master:
    <<: *defaults
    steps:
      - attach_workspace:
          at: /home/circleci/
      - run: ./bin/deploy-webhook $DEPLOY_WEBHOOK


########################################################################################################################
#                                                      WORKFLOWS                                                       #
########################################################################################################################

workflows:
  version: 2
  build:
    jobs:
      - checkout
      - be-deps:
          requires:
            - checkout
      - be-tests:
          requires:
            - be-deps
      - be-linter-eastwood:
          requires:
            - be-deps
      - be-linter-docstring-checker:
          requires:
            - be-deps
      - be-linter-bikeshed:
          requires:
            - be-deps
      - be-linter-reflection-warnings:
          requires:
            - be-deps
      - be-tests-mysql:
          requires:
            - be-tests
      - be-tests-postgres:
          requires:
            - be-tests
      - be-tests-sparksql:
          requires:
            - be-tests
      - be-tests-mongo:
          requires:
            - be-tests
      - be-tests-sqlserver:
          requires:
            - be-tests
      - be-tests-bigquery:
          requires:
            - be-tests
      - be-tests-sqlite:
          requires:
            - be-tests
      - be-tests-presto:
          requires:
            - be-tests
      - be-tests-oracle:
          requires:
            - be-tests
      - be-tests-druid:
          requires:
            - be-tests
      - be-tests-redshift:
          requires:
            - be-tests
      - be-tests-vertica:
          requires:
            - be-tests
      - be-tests-snowflake:
          requires:
            - be-tests
      - fe-deps:
          requires:
            - checkout
      - fe-linter-eslint:
          requires:
            - fe-deps
      - fe-linter-prettier:
          requires:
            - fe-deps
      - fe-linter-flow:
          requires:
            - fe-deps
      - fe-tests-karma:
          requires:
            - fe-deps
      - fe-tests-unit:
          requires:
            - fe-deps
      - build-uberjar:
          requires:
            - be-deps
      - fe-tests-integrated:
          requires:
            - build-uberjar
            - fe-deps
      - deploy-master:
          requires:
            - be-linter-eastwood
            - be-linter-docstring-checker
            - be-linter-bikeshed
            - be-linter-reflection-warnings
            - be-tests
            - be-tests-mysql
            - be-tests-postgres
            - be-tests-sparksql
            - be-tests-mongo
            - be-tests-sqlserver
            - be-tests-bigquery
            - be-tests-sqlite
            - be-tests-presto
            - be-tests-oracle
            - be-tests-druid
            - be-tests-redshift
            - be-tests-vertica
            - be-tests-snowflake
            - fe-linter-eslint
            - fe-linter-prettier
            - fe-linter-flow
            - fe-tests-karma
            - fe-tests-unit
            - fe-tests-integrated
          filters:
            branches:
              only: master