#==============================================================================
#==============================================================================
#==============================================================================
# CircleCI Build Configuration
#==============================================================================
#==============================================================================
#==============================================================================

version: 2.1

orbs:
  node: circleci/node@4.1.0
  slack: circleci/slack@4.2.0

#==============================================================================
#==============================================================================
# Aliases
#==============================================================================
#==============================================================================

aliases:
  - &workspace
    ~/project
  - &build_output
    target/build
  - &test_results_folder
    /tmp/junit
  - &node8-version
    "8.17.0"
  - &node10-version
    "10.23.0"
  - &node12-version
    "12.20.0"

  #============================================================================
  # Aliases: Parameters
  #============================================================================

  - node-version-parameter: &node-version-parameter
      node-version:
        description: "NodeJS version to use"
        type: string
  - twilio-realm-parameter: &twilio-realm-parameter
      twilio-realm:
        description: "Twilio Realm to use"
        type: enum
        enum: ["us1", "ie1"]
  - upload-location-parameter: &upload-location-parameter
      upload-location:
        description: "Upload location"
        type: enum
        enum: ["stage", "prod"]
  - dry-run-parameter: &dry-run-parameter
      dry-run:
        description: "Dry run"
        type: boolean
        default: true
  - target-branch-parameter: &target-branch-parameter
      target-branch:
        description: "Target branch for merge into"
        type: string
        default: "main"
  - steps-to-run-parameter: &steps-to-run-parameter
        steps-to-run:
          description: "Steps that will be executed"
          type: steps
          default: []

  #============================================================================
  # Aliases: Tag & Branch Filters
  #============================================================================

  # Filter to allow pretty any branch or tag - required by CircleCI for jobs that rc/tag jobs depend on.
  - any-branch-or-tag-filter: &any-branch-or-tag-filter
      filters:
        tags:
          only:
            - /.*/
  # Filter for RC and release builds only.
  - rc-or-release-tag-filter: &rc-or-release-tag-filter
      filters:
        tags:
          only: /^release-\d+\.\d+\.\d+(-rc\d+)?/
        branches:
          ignore: /.*/
  # Filter for RC builds only.
  - rc-tag-filter: &rc-tag-filter
      filters:
        tags:
          only: /^release-\d+\.\d+\.\d+-rc\d+/
        branches:
          ignore: /.*/
  # Filter for release builds only.
  - release-tag-filter: &release-tag-filter
      filters:
        tags:
          only: /^release-\d+\.\d+\.\d+/
        branches:
          ignore: /.*/
  # Filter for release branches - to merge them back to develop automatically.
  - release-branch-filter: &release-branch-filter
      filters:
        tags:
          ignore: /.*/
        branches:
          only:
            - /^release\/.*/

#==============================================================================
#==============================================================================
# Executors
#==============================================================================
#==============================================================================

executors:
  linux-docker-executor:
    docker:
      - image: circleci/node:latest
        auth:
           username: $DOCKER_HUB_USERNAME
           password: $DOCKER_HUB_PASSWORD
    resource_class: small
    working_directory: *workspace

#==============================================================================
#==============================================================================
# Commands
#==============================================================================
#==============================================================================

commands:

  #============================================================================
  # Commands: Git Maintenance
  #============================================================================

  git_run_with_disabled_branch_protection:
    description: "Run steps with disabled  \"Include administration\" policy for << parameters.target-branch >> branch protection on GitHub"
    parameters:
      <<: *target-branch-parameter
      <<: *steps-to-run-parameter
    steps:
      - run:
          name: "Setup git config"
          command: |
            source ~/.bashrc
            git config --global user.name "$GITHUB_USERNAME"
            git config --global user.email "$GITHUB_USER_EMAIL"
      - run:
          name: "Temporarily disable \"Include administration\" policy for << parameters.target-branch >> branch protection on GitHub"
          command: |
            source ~/.bashrc
            curl -u $GITHUB_USERNAME:$GITHUB_TOKEN -X DELETE https://api.github.com/repos/twilio/rtd-sdk-monorepo/branches/<< parameters.target-branch >>/protection/enforce_admins
      - steps: << parameters.steps-to-run >>
      - run:
          name: "Enable \"Include administration\" policy for << parameters.target-branch >> branch protection on GitHub"
          when: always
          command: |
            source ~/.bashrc
            curl -u $GITHUB_USERNAME:$GITHUB_TOKEN -X POST https://api.github.com/repos/twilio/rtd-sdk-monorepo/branches/<< parameters.target-branch >>/protection/enforce_admins

  bump_snapshot_version:
    steps:
      - run:
          name: "Bump snapshot version"
          command: |
            source ~/.bashrc
            ./tools/bump-snapshot-version.sh

  git_merge_release_to_develop:
    steps:
      - run:
          name: "Merge $CIRCLE_BRANCH into develop"
          command: |
            source ~/.bashrc
            ./tools/git-auto-merge.sh $CIRCLE_BRANCH develop

  init-private-npm:
    description: "Generate NPM settings"
    steps:
      - run:
          name: "Use private NPM settings"
          command: |
            echo "//registry.npmjs.org/:_authToken=\${AUTHOR_NPM_API_KEY}" > .npmrc
          working_directory: *workspace

  init-public-npm:
    description: "Generate NPM settings"
    steps:
      - run:
          name: "Use public NPM settings"
          command: |
            echo "//registry.npmjs.org/:_authToken=\${PUBLIC_NPM_API_KEY}" > .npmrc
          working_directory: *workspace

  prepare-publish-version:
    description: "Prepare version info for publishing"
    steps:
      - run:
          name: "Prepare version for publishing"
          command: |
            npx -p circleci-build-publisher@1.0.3 prepare-publish-version
          working_directory: *workspace

  strip-private-prefix:
    description: "Strip private @twilio prefix before publishing"
    steps:
      - run:
          name: "Strip @twilio prefix"
          command: |
            npx -p circleci-build-publisher@1.0.3 strip-private-prefix "@twilio"
          working_directory: *workspace

  gulp-build:
    description: "Gulp build"
    steps:
      - run:
          name: "Gulp build"
          command: |
            npx -p gulp-cli@2.3.0 gulp
          working_directory: *workspace

  npm-publish:
    description: "Publish to NPM"
    steps:
      - run:
          name: "Publish to NPM"
          command: |
            npm publish --verbose --tag=$(npx -p circleci-build-publisher@1.0.3 get-channel-name)
          working_directory: *workspace

#==============================================================================
#==============================================================================
# Jobs
#==============================================================================
#==============================================================================

jobs:

  #============================================================================
  # Jobs: Support
  #============================================================================

  bump-snapshot-version:
    executor: linux-docker-executor
    description: "Bump snapshot version"
    steps:
      - checkout
      - git_run_with_disabled_branch_protection:
          target-branch: develop
          steps-to-run: [bump_snapshot_version]

  git-merge-release-to-develop:
    executor: linux-docker-executor
    description: "Merge release branch into develop"
    steps:
      - checkout
      - git_run_with_disabled_branch_protection:
          target-branch: develop
          steps-to-run: [git_merge_release_to_develop]

  #============================================================================
  # Jobs: Test
  #============================================================================

  unit-test:
    executor:
      name: node/default
      tag: << parameters.node-version >>
    description: "Unit Test"
    parameters:
      <<: *node-version-parameter
    steps:
      - checkout
      - init-private-npm
      - node/install-packages
      - run:
          command: |
            npm run unitTest
      - slack/notify:
          event: fail
          template: basic_fail_1

  integration-test:
    executor:
      name: node/default
      tag: << parameters.node-version >>
    description: "Integration Test"
    parameters:
      <<: *node-version-parameter
      <<: *twilio-realm-parameter
    steps:
      - checkout
      - init-private-npm
      - node/install-packages
      - run:
          command: |
            npm run integrationTest
          environment:
            TWILIO_REGION: << parameters.twilio-realm >>
      - slack/notify:
          event: fail
          template: basic_fail_1

  #============================================================================
  # Jobs: Build & Package
  #============================================================================

  build-and-private-deploy:
    executor:
      name: node/default
      tag: *node10-version
    description: "Build and Private Deploy"
    steps:
      - checkout
      - init-private-npm
      - node/install-packages
      - prepare-publish-version
      - gulp-build
      - npm-publish
      - slack/notify:
          event: fail
          template: basic_fail_1

  build-and-public-deploy:
    executor:
      name: node/default
      tag: *node10-version
    description: "Build and Public Deploy"
    steps:
      - checkout
      - init-public-npm
      - strip-private-prefix
      - node/install-packages:
          override-ci-command: npm i  # Overwrite package-lock.json
      - prepare-publish-version
      - gulp-build
      - npm-publish
      - slack/notify:
          event: fail
          template: basic_fail_1
      - slack/notify:
          event: pass
          template: success_tagged_deploy_1

#==============================================================================
#==============================================================================
# Workflows: Build, Unit Test, Integration Test & Private/Public Publish
#==============================================================================
#==============================================================================

workflows:
  version: 2

  workflow:
    jobs:

      #========================================================================
      # Workflows: Unit Test, Integration Test
      #========================================================================

      - unit-test:
          <<: *any-branch-or-tag-filter
          matrix:
            parameters:
              node-version:
                - *node8-version
                - *node10-version
                - *node12-version
          context:
            - rtd-sdk-js-npm
            - rtd-sdk-shared-tokengen
            - rtd-sdk-js-mcs-client
            - rtd-sdk-slack-secrets

      - integration-test:
          <<: *any-branch-or-tag-filter
          matrix:
            parameters:
              node-version:
                - *node10-version
              twilio-realm:
                - us1
                - ie1
          context:
            - rtd-sdk-js-npm
            - rtd-sdk-shared-tokengen
            - rtd-sdk-js-mcs-client
            - rtd-sdk-slack-secrets

      #========================================================================
      # Workflows: Build, Private/Public Publish
      #========================================================================

      - build-and-private-deploy:
          <<: *any-branch-or-tag-filter
          requires:
            - unit-test
            - integration-test
          context:
            - rtd-sdk-js-npm
            - rtd-sdk-slack-secrets

      - build-and-public-deploy:
          <<: *rc-or-release-tag-filter
          requires:
            - build-and-private-deploy
          context:
            - rtd-sdk-js-npm
            - rtd-sdk-slack-secrets

      - bump-snapshot-version:
          <<: *release-tag-filter
          context: rtd-github-api
          requires:
            - build-and-public-deploy

  #============================================================================
  # Workflows: Auto-merge release branch into develop
  #============================================================================

  merge-release-to-develop:
    jobs:
      - git-merge-release-to-develop:
          <<: *release-branch-filter
          context: rtd-github-api
