version: 2.1

orbs:
  codecov: codecov/codecov@1.1.1

commands:
  create-typeorm-config:
    parameters:
      databases:
        type: string
        default: ""
    steps:
      - when:
          condition:
            equal: [<< parameters.databases >>, ""]
          steps:
            - run:
                name: "Enabling Databases in ORM config"
                command: cp ormconfig.circleci-common.json ./ormconfig.json
      - unless:
          condition:
            equal: [<< parameters.databases >>, ""]
          steps:
            - run:
                name: "Enabling Databases in ORM config"
                command: >
                  cat ormconfig.circleci-common.json \
                    | jq 'map(.skip = if (.name | IN($ARGS.positional[])) then false else true end)' --args << parameters.databases >> \
                    > ormconfig.json
      - run:
          name: Check ORMConfig
          command: cat ormconfig.json

  install-packages:
    parameters:
      cache-key:
        type: string
        default: ""
    steps:
      - restore_cache:
          name: Restore node_modules cache
          key: node_modules-<< parameters.cache-key >>-{{ checksum "package-lock.json" }}
      #      removed this item because lock-verify is deprecated
      #      - run:
      #          name: Verify `package.json` and `package-lock.json` are in sync
      #          command: npx lock-verify
      - run:
          # This uses `npm install` instead of `npm ci`
          # because of https://github.com/npm/cli/issues/558
          name: Install Node Packages
          command: |
            if [ ! -d node_modules ]; then
              npm install
            fi
      - save_cache:
          name: Save node_modules cache
          key: node_modules-{{ checksum "package-lock.json" }}
          paths:
            - node_modules

jobs:
  lint:
    working_directory: ~/typeorm
    docker:
      - image: cimg/node:16.20.0
    steps:
      - checkout
      - install-packages:
          cache-key: node16
      - run: npm run lint

  build:
    working_directory: ~/typeorm
    docker:
      - image: cimg/node:16.20.0
    steps:
      - checkout
      - install-packages:
          cache-key: node16
      - run: npm run compile
      - persist_to_workspace:
          root: ~/typeorm
          paths:
            - build/

  test:
    parameters:
      databases:
        type: string
        default: ""
      node-version:
        type: string
        default: "16"
    working_directory: ~/typeorm
    docker:
      - image: cimg/node:<< parameters.node-version >>
    steps:
      - checkout
      - setup_remote_docker
      - attach_workspace:
          at: ~/typeorm
      - create-typeorm-config:
          databases: << parameters.databases >>
      - run:
          name: Start all Relevant Services
          command: |
            SERVICES=$(
              npx js-yaml ./docker-compose.yml \
                | jq -r '.services | keys | map(select(. | IN($ARGS.positional[]))) | join(" ")' --args << parameters.databases >>
            )

            docker-compose --project-name typeorm --no-ansi up --detach $SERVICES
      - install-packages:
          cache-key: node<< parameters.node-version >>
      - run:
          name: Set up TypeORM Test Runner
          command: |
            docker run \
              --volume /typeorm \
              --name typeorm-code \
              --workdir /typeorm \
              cimg/node:<< parameters.node-version >> \
              /bin/bash -c "sudo chmod 777 /typeorm && sudo chown circleci /typeorm"
            docker cp ./ typeorm-code:/typeorm
      - run:
          name: Wait for Services to be Available
          command: |
            DEFAULT_WAIT_TIME=60
            ORACLE_WAIT_TIME=120

            COMMANDS=$(
                cat ormconfig.json \
                  | jq -r '
                    map(select(.skip == false)
                      | select(.host)
                      | select(.port)
                      | "nc -z " + .host + " " + (.port|tostring) + " && echo " + .host + " " + (.port|tostring) + " is up"
                    )
                    | join(" && ")
                  '
            )
            echo "Running '$COMMANDS'"

            WAIT_TIME=$([ ! -z "$(jq -r '.[] | select(.skip == false and .name == "oracle")' ormconfig.json)" ] && echo "$ORACLE_WAIT_TIME" || echo "$DEFAULT_WAIT_TIME")

            if [ ! -z "$COMMANDS" ]; then
              docker run \
                --network typeorm_default \
                --tty \
                ubuntu:trusty \
                timeout $WAIT_TIME sh -c "until ($COMMANDS); do echo \"Waiting for Services to be Available ...\"; sleep 5; done"
            fi
      # Download and cache dependencies
      - run:
          name: "Run Tests with Coverage"

          command: |
            docker run \
              --env npm_config_yes='true' \
              --volumes-from typeorm-code \
              --network typeorm_default \
              --tty \
              --workdir /typeorm \
              --name typeorm-testrunner \
              cimg/node:<< parameters.node-version >> \
              npx nyc npm run test-fast

            docker cp typeorm-testrunner:/typeorm/coverage/ ./
      - run:
          name: Stop all Relevant Services
          command: docker-compose down
      - store_artifacts:
          path: coverage
      - codecov/upload

workflows:
  version: 2
  test:
    jobs:
      - lint
      - build
      - test:
          name: test (postgres) - Node v16
          requires:
            - lint
            - build
          databases: "postgres"
          node-version: "16.20.0"
      - test:
          name: test (cockroachdb) - Node v16
          requires:
            - lint
            - build
          databases: "cockroachdb"
          node-version: "16.20.0"
      - test:
          name: test (mysql mariadb) - Node v16
          requires:
            - lint
            - build
          databases: "mysql mariadb"
          node-version: "16.20.0"
      - test:
          name: test (mssql) - Node v16
          requires:
            - lint
            - build
          databases: "mssql"
          node-version: "16.20.0"
      - test:
          name: test (oracle) - Node v16
          requires:
            - lint
            - build
          databases: "oracle"
          node-version: "16.20.0"
      - test:
          name: test (sqlite better-sqlite3 sqljs) - Node v16
          requires:
            - lint
            - build
          databases: "sqlite better-sqlite3 sqljs"
          node-version: "16.20.0"
      - test:
          name: test (mongodb) - Node v16
          requires:
            - lint
            - build
          databases: "mongodb"
          node-version: "16.20.0"
