version: 2.1

executors:
  default:
    parameters:
      postgres:
        type: boolean
        default: false
      selenium:
        type: boolean
        default: false
    docker:
    - image: plumeorg/plume-buildenv:v0.3.0
    - image: <<#parameters.postgres>>circleci/postgres:9.6-alpine<</parameters.postgres>><<^parameters.postgres>>alpine:latest<</parameters.postgres>>
      environment:
        POSTGRES_USER: postgres
        POSTGRES_DB: plume
    - image: <<#parameters.selenium>>elgalu/selenium:latest<</parameters.selenium>><<^parameters.selenium>>alpine:latest<</parameters.selenium>>
    working_directory: ~/projects/Plume
    environment:
      RUST_TEST_THREADS: 1
      FEATURES: <<#parameters.postgres>>postgres<</ parameters.postgres>><<^parameters.postgres>>sqlite<</parameters.postgres>>
      DATABASE_URL: <<#parameters.postgres>>postgres://postgres@localhost/plume<</parameters.postgres>><<^parameters.postgres>>plume.sqlite<</parameters.postgres>>


commands:
  restore_env:
    description: checkout and pull cache
    parameters:
      cache:
        type: enum
        default: none
        enum: ["none", "clippy", "postgres", "sqlite", "release-postgres", "release-sqlite"]
    steps:
    - checkout
    - run: git config --global --remove-section url."ssh://git@github.com"
    - restore_cache:
        keys:
        - v0-<< parameters.cache >>-{{ checksum "Cargo.lock" }}-{{ .Branch }}
        - v0-<< parameters.cache >>-{{ checksum "Cargo.lock" }}-master

  cache:
    description: push cache
    parameters:
      cache:
        type: enum
        enum: ["clippy", "postgres", "sqlite", "release-postgres", "release-sqlite"]
    steps:
    - save_cache:
        key: v0-<< parameters.cache >>-{{ checksum "Cargo.lock" }}-{{ .Branch }}
        paths:
        - ~/.cargo/
        - ./target

  clippy:
    description: run cargo clippy
    parameters:
      package:
        type: string
        default: plume
      no_feature:
        type: boolean
        default: false
    steps:
    - run: cargo clippy <<^parameters.no_feature>>--no-default-features --features="${FEATURES}"<</parameters.no_feature>> --release -p <<parameters.package>> -- -D warnings

  run_with_coverage:
    description: run command with environment for coverage
    parameters:
      cmd:
        type: string
    steps:
    - run: |
       export RUSTFLAGS="-Zprofile -Zfewer-names -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Zno-landing-pads -Clink-arg=-Xlinker -Clink-arg=--no-keep-memory -Clink-arg=-Xlinker -Clink-arg=--reduce-memory-overheads"
       export CARGO_INCREMENTAL=0
       << parameters.cmd >>

  upload_coverage:
    description: merge coverage files and upload to codecov.io
    parameters:
      type:
        type: string
    steps:
    - run: zip -0 ccov.zip `find . -name 'plume*.gc*' -o -name 'plm*.gc*'`
    - run: grcov ccov.zip -s . -t lcov --llvm --branch --ignore-not-existing --ignore '/*' -o lcov.info
    - run: bash <(curl -s https://codecov.io/bash) -f lcov.info -F <<parameters.type>>
    - run: find . -name 'plume*.gc*' -delete -o -name 'plm*.gc*' -delete
    - run: rm ccov.zip lcov.info

  build:
    description: build a package
    parameters:
      package:
        type: string
        default: plume
      release:
        type: boolean
        default: false
    steps:
    - run: |
            cmd="cargo build <<#parameters.release>>--release<</parameters.release>> --no-default-features --features="${FEATURES}" -p <<parameters.package>> -j"
            for i in 36 4 2 1 1; do
                $cmd $i && exit 0
            done
            exit 1

jobs:
  cargo fmt:
    executor:
      name: default
    steps:
    - restore_env
    - run: cargo fmt --all -- --check

  clippy:
    parameters:
      postgres:
        type: boolean
    executor:
      name: default
      postgres: << parameters.postgres >>
    steps:
    - restore_env:
        cache: clippy
    - clippy
    - clippy:
        package: plume-cli
    - clippy:
        package: plume-front
        no_feature: true
    - cache:
        cache: clippy

  unit:
    parameters:
      postgres:
        type: boolean
    executor:
      name: default
      postgres: << parameters.postgres >>
    steps:
    - restore_env:
        cache: <<#parameters.postgres>>postgres<</ parameters.postgres>><<^parameters.postgres>>sqlite<</parameters.postgres>>
    - run_with_coverage:
        cmd: |
          cmd="cargo test --all --exclude plume-front --exclude plume-macro --no-run --no-default-features --features=${FEATURES} -j"
          for i in 36 4 2 1 1; do
              $cmd $i && break
          done
          cargo test --all --exclude plume-front --exclude plume-macro --no-default-features --features="${FEATURES}" -j1 -- --test-threads=1
    - upload_coverage:
        type: unit
    - cache:
        cache: <<#parameters.postgres>>postgres<</ parameters.postgres>><<^parameters.postgres>>sqlite<</parameters.postgres>>

  integration:
    parameters:
      postgres:
        type: boolean
    executor:
      name: default
      postgres: << parameters.postgres >>
      selenium: true
    steps:
    - restore_env:
        cache: <<#parameters.postgres>>postgres<</ parameters.postgres>><<^parameters.postgres>>sqlite<</parameters.postgres>>
    - run: cargo web deploy -p plume-front
    - run_with_coverage:
        cmd: |
            cmd="cargo install --debug --no-default-features --features="${FEATURES}",test --force --path . -j"
            for i in 36 4 2 1 1; do
                $cmd $i && exit 0
            done
            exit 1
    - run_with_coverage:
        cmd: |
            cmd="cargo install --debug --no-default-features --features="${FEATURES}" --force --path plume-cli -j"
            for i in 36 4 2 1 1; do
                $cmd $i && exit 0
            done
            exit 1
    - run:
        name: run test
        command: ./script/run_browser_test.sh
        environment:
          BROWSER: firefox
    - upload_coverage:
        type: integration
    - cache:
        cache: <<#parameters.postgres>>postgres<</ parameters.postgres>><<^parameters.postgres>>sqlite<</parameters.postgres>>

  release:
    parameters:
      postgres:
        type: boolean
    executor:
      name: default
      postgres: << parameters.postgres >>
    steps:
    - restore_env:
        cache: release-<<#parameters.postgres>>postgres<</ parameters.postgres>><<^parameters.postgres>>sqlite<</parameters.postgres>>
    - run: cargo web deploy -p plume-front --release
    - build:
        package: plume
        release: true
    - build:
        package: plume-cli
        release: true
    - cache:
        cache: release-<<#parameters.postgres>>postgres<</ parameters.postgres>><<^parameters.postgres>>sqlite<</parameters.postgres>>
    - run: ./script/generate_artifact.sh
    - unless:
        condition: << parameters.postgres >>
        steps:
        - run: ./script/upload_test_environment.sh
    - store_artifacts:
        path: plume.tar.gz
        destination: plume.tar.gz
    - store_artifacts:
        path: wasm.tar.gz
        destination: wasm.tar.gz

  push translations:
    executor:
      name: default
    steps:
    - restore_env:
        cache: none
    - run: cargo build
    - run: crowdin upload -b master

workflows:
  version: 2
  build and test:
    jobs:
    - cargo fmt
    - clippy:
        postgres: false
    - clippy:
        postgres: true
    - unit:
        postgres: false
    - unit:
        postgres: true
    - integration:
        postgres: false
    - integration:
        postgres: true
    - release:
        postgres: false
    - release:
        postgres: true
    - push translations:
        filters:
          branches:
            only:
              - /^master/
