version: 2.1

executors:
  node-executor:
    working_directory: ~/repo
    machine:
      # What software on the machine https://discuss.circleci.com/t/linux-machine-executor-update-2022-july-q3-update/44873
      image: ubuntu-2204:2022.07.1
      # About DLC https://circleci.com/docs/docker-layer-caching
      # We only build image when doing nightly builds, enabling DLC takes significant effect on billing but not on building speeds.
      docker_layer_caching: false
    resource_class: large

parameters:
  workflow_name:
    type: string
    default: 'none'

# Set some environment variables like the base SHA of PRs ...etc.
set_env: &set_env
  name: Setup Environment Variables
  command: |
    if [ ! -z "$CIRCLE_PULL_REQUEST" ]; then
      # Use the base commit of PR as the affected base.

      echo 'Fetching Base Commit from GitHub'
      # Get the PR number from env for different kinds of PR
      echo 'export CIRCLE_PR_NUMBER="${CIRCLE_PR_NUMBER:-${CIRCLE_PULL_REQUEST##*/}}"' >> $BASH_ENV
      source $BASH_ENV
      
      # Obtain the SHA via Github API
      echo "export CIRCLE_PR_BASE_SHA=`curl -s https://api.github.com/repos/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/pulls/${CIRCLE_PR_NUMBER} | jq -r '.base.sha'`" >> $BASH_ENV
      # Set the affected args for nx affect xxx commands
      echo 'export AFFECTED_ARGS="--head=HEAD --base=${CIRCLE_PR_BASE_SHA}"' >> $BASH_ENV

    elif [ "$CIRCLE_BRANCH" == "develop" ]; then
      # Use the last build commit if there is nightly-build tag

      last_commit="$(git rev-list -n 1 tags/nightly-build || echo '')"

      # Check whether the commit is on the target branch
      if [ "$last_commit" != "" ] && [ "$(git merge-base $last_commit $CIRCLE_BRANCH)" == "$last_commit" ]; then
        # use last build sha as the base.
        echo "Using $last_commit as the base (last build)"
        echo "export AFFECTED_ARGS=\"--head=HEAD --base=$last_commit\"" >> $BASH_ENV
      else
        # use main branch as the base.
        echo "Using main branch as the base"
        echo 'export AFFECTED_ARGS="--head=HEAD --base=origin/main"' >> $BASH_ENV 
      fi
      
    else

      echo "Testing/Linting on all packages"
      echo 'export AFFECTED_ARGS="--all"' >> $BASH_ENV 

    fi

    # Set the memory size for node processes
    echo 'export NODE_OPTIONS="--max_old_space_size=6144"' >> $BASH_ENV
    source $BASH_ENV
    echo $AFFECTED_ARGS

# Retrieve node_modules and the module cache from Circle CI storage.
yarn_cache: &yarn_cache
  keys:
    - node-deps-node16-{{ checksum "yarn.lock" }}
    # fallback to using the latest cache if no exact match is found
    - node-deps-node16-

# Install node modules via yarn with the frozen lock file
yarn_install: &yarn_install
  name: Install Dependencies
  command: yarn install --frozen-lockfile --non-interactive

# Install code cov uploader and check the signature
# https://docs.codecov.com/docs/codecov-uploader
codecov_install: &codecov_install
  name: Install codecov
  command: |
    if [ ! -f ./codecov ]; then
    curl -Os https://uploader.codecov.io/v0.1.0_4653/linux/codecov
    curl https://keybase.io/codecovsecurity/pgp_keys.asc | gpg --no-default-keyring --keyring trustedkeys.gpg --import # One-time step
    curl -Os https://uploader.codecov.io/latest/linux/codecov
    curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM
    curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM.sig
    gpgv codecov.SHA256SUM.sig codecov.SHA256SUM
    shasum -a 256 -c codecov.SHA256SUM
    chmod +x codecov
    fi

set_private_npm_token: &set_private_npm_token
  name: Set the NPM Registry with PRIVATE_PACKAGE_NPM_TOKEN to install private packages
  # Set the NPM Registry with NPM TOKEN to install our private packages
  command: |
    npm set //registry.npmjs.org/:_authToken=${PRIVATE_PACKAGE_NPM_TOKEN}

jobs:
  install:
    executor: node-executor
    steps:
      - checkout
      - restore_cache:
          <<: *yarn_cache
      - run:
          <<: *yarn_install
      - save_cache:
          key: node-deps-node16-{{ checksum "yarn.lock" }}
          paths:
            - ~/.cache
            - node_modules
      - restore_cache:
          keys:
            - codecov-0.1.0_4653
      - run:
          <<: *codecov_install
      - save_cache:
          key: codecov-0.1.0_4653
          paths:
            - ./codecov

  lint:
    executor: node-executor
    steps:
      - checkout
      - run:
          <<: *set_env
      - restore_cache:
          <<: *yarn_cache
      - run: yarn nx workspace-lint
      - run: yarn nx affected --target=lint --maxWarnings=0 ${AFFECTED_ARGS}

  test:
    executor: node-executor
    steps:
      - checkout
      - run:
          <<: *set_env
      - restore_cache:
          <<: *yarn_cache
      - restore_cache:
          keys:
            - codecov-0.1.0_4653
      - run: rm -rf ./coverage
      - run:
          <<: *set_private_npm_token
      - run:
          # Because CircleCI could not set the JSON content like Github, so we encode the credentials JSON content to the base64 in env.
          # Then decode the env to the JSON content and write to "GOOGLE_APPLICATION_CREDENTIALS" env indicated location "gcp-ci-sa.json" to make the GCP storage service test cases work in "extension-store-canner" package.
          name: decode GOOGLE_CREDENTIALS_BASE64_DATA and save to gcp-ci-sa.json for GOOGLE_APPLICATION_CREDENTIALS
          command: |
            echo "$GOOGLE_CREDENTIALS_BASE64_DATA" | base64 --decode > gcp-ci-sa.json
        # Clear coverage folder
      - run: yarn nx affected --target=test --ci --coverage --coverageReporters=lcov ${AFFECTED_ARGS}
      - run:
          name: upload reports with flags
          command: |
            if [ -d "coverage/packages" ] 
            then
              for path in $(find coverage/packages -maxdepth 1 -type d | grep coverage/packages/); do
                package=${path##coverage/packages/}
                echo "Uploading coverage report for package: $package"
                ./codecov -t ${CODECOV_TOKEN} -f coverage/packages/$package/lcov.info -F $package
              done
            else
              echo "No coverage report found."
            fi

  nightly-build:
    executor: node-executor
    steps:
      # Using the deployment key with write access
      - add_ssh_keys:
          fingerprints:
            - 'd8:c0:e1:c8:8b:8d:dd:f8:50:cd:d9:34:1c:21:3d:85'
      - checkout
      - run:
          <<: *set_env
      - restore_cache:
          <<: *yarn_cache
      - run:
          <<: *set_private_npm_token
      - run:
          name: NPM publish
          # running with yarn nx causes npm config issues
          command: ./node_modules/.bin/nx affected --target=publish ${AFFECTED_ARGS} --tag dev
          environment:
            READY_FOR_PUBLISH: 'true'
      - run:
          name: Docker login
          command: echo "${GITHUB_PAT}" | docker login ghcr.io -u ${GITHUB_USER} --password-stdin
      - run:
          name: Docker publish
          command: yarn nx affected --target=publish:docker ${AFFECTED_ARGS} --tag dev
          environment:
            READY_FOR_PUBLISH: 'true'
      # After a success build, move the tag nightly-build to HEAD
      - run:
          name: Move nightly-build tag
          command: |
            # delete remote tag
            git push origin :refs/tags/nightly-build
            # tag current HEAD
            git tag -f nightly-build
            # push tag
            git push origin $CIRCLE_BRANCH --tags

workflows:
  version: 2
  pr-check:
    when:
      not:
        equal: [scheduled_pipeline, << pipeline.trigger_source >>]
    jobs:
      - install
      - lint:
          requires:
            - install
      - test:
          requires:
            - install
  nightly-build:
    when:
      or:
        - and:
            - equal: [scheduled_pipeline, << pipeline.trigger_source >>]
            - equal: ['nightly build', << pipeline.schedule.name >>]
        - and:
            - equal: [api, << pipeline.trigger_source >>]
            - equal: ['nightly build', << pipeline.parameters.workflow_name >>]
    jobs:
      - install
      - lint:
          requires:
            - install
      - test:
          requires:
            - install
      - nightly-build:
          requires:
            - install
            - lint
            - test
