defaults: &defaults
  working_directory: ~/repo

macos: &macos
  macos:
    xcode: "11.2.1"

bash-env: &bash-env
  BASH_ENV: "~/.nvm/nvm.sh"

install-npm-modules: &install-npm-modules
  name: Install NPM modules
  command: yarn

restore-npm-cache-linux: &restore-npm-cache-linux
  name: Restore NPM cache
  key: node-modules-{{ checksum "yarn.lock" }}

save-npm-cache-linux: &save-npm-cache-linux
  key: node-modules-{{ checksum "yarn.lock" }}
  name: Save NPM cache
  paths:
    - ./node_modules

restore-npm-cache-mac: &restore-npm-cache-mac
  name: Restore NPM cache
  key: node-v1-mac-{{ checksum "yarn.lock" }}

save-npm-cache-mac: &save-npm-cache-mac
  key: node-v1-mac-{{ checksum "yarn.lock" }}
  name: Save NPM cache
  paths:
    - ./node_modules

install-node: &install-node
  name: Install Node 10
  command: |
    curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.6/install.sh | bash
    source ~/.nvm/nvm.sh
    # https://github.com/creationix/nvm/issues/1394
    set +e
    nvm install 10
    echo 'export PATH="/home/circleci/.nvm/versions/node/v10.20.1/bin:$PATH"' >> ~/.bash_profile
    source ~/.bash_profile

restore-gems-cache: &restore-gems-cache
  name: Restore gems cache
  key: bundle-v1-{{ checksum "ios/Gemfile.lock" }}

save-gems-cache: &save-gems-cache
  name: Save gems cache
  key: bundle-v1-{{ checksum "ios/Gemfile.lock" }}
  paths:
    - vendor/bundle

update-fastlane-ios: &update-fastlane-ios
  name: Update Fastlane
  command: |
    echo "ruby-2.6.4" > ~/.ruby-version
    bundle install
  working_directory: ios

update-fastlane-android: &update-fastlane-android
  name: Update Fastlane
  command: |
    echo "ruby-2.6.4" > ~/.ruby-version
    bundle install
  working_directory: android

save-gradle-cache: &save-gradle-cache
  name: Save gradle cache
  key: android-{{ checksum "android/build.gradle" }}-{{ checksum  "android/app/build.gradle" }}
  paths:
    - ~/.gradle

restore_cache: &restore-gradle-cache
  name: Restore gradle cache
  key: android-{{ checksum "android/build.gradle" }}-{{ checksum  "android/app/build.gradle" }}

restore-brew-cache: &restore-brew-cache
  name: Restore Brew cache
  key: brew-{{ checksum "yarn.lock" }}-{{ checksum ".circleci/config.yml" }}

save-brew-cache: &save-brew-cache
  name: Save brew cache
  key: brew-{{ checksum "yarn.lock" }}-{{ checksum ".circleci/config.yml" }}
  paths:
    - /usr/local/Homebrew

install-apple-sim-utils: &install-apple-sim-utils
  name: Install appleSimUtils
  command: |
    brew update
    brew tap wix/brew
    brew install wix/brew/applesimutils

rebuild-detox: &rebuild-detox
  name: Rebuild Detox framework cache
  command: |
    npx detox clean-framework-cache
    npx detox build-framework-cache

version: 2.1

# EXECUTORS
executors:
  mac-env:
    <<: *macos
    environment:
      <<: *bash-env

# COMMANDS
commands:
  detox-test:
    parameters:
      folder:
        type: string
    steps:
      - checkout

      - attach_workspace:
          at: .

      - restore_cache: *restore-npm-cache-mac

      - restore_cache: *restore-brew-cache

      - run: *install-node

      - run: *install-apple-sim-utils

      - run: *install-npm-modules
      
      - run: *rebuild-detox

      - run:
          name: Test
          command: |
            npx detox test << parameters.folder >> --configuration ios.sim.release --cleanup

# JOBS
jobs:
  lint-testunit:
    <<: *defaults
    docker:
      - image: circleci/node:10

    environment:
      CODECOV_TOKEN: caa771ab-3d45-4756-8e2a-e1f25996fef6

    steps:
      - checkout

      - restore_cache: *restore-npm-cache-linux

      - run: *install-npm-modules

      - run:
          name: Lint
          command: |
            yarn lint

      - run:
          name: Test
          command: |
            yarn test

      - run:
          name: Codecov
          command: |
            yarn codecov

      - save_cache: *save-npm-cache-linux

  # E2E
  e2e-build:
    executor: mac-env

    steps:
      - checkout

      - restore_cache: *restore-npm-cache-mac

      - restore_cache: *restore-brew-cache

      - run: *install-node

      - run: *install-apple-sim-utils

      - run: *install-npm-modules

      - run: *rebuild-detox

      - run:
          name: Build
          command: |
            npx detox build --configuration ios.sim.release

      - persist_to_workspace:
          root: .
          paths:
            - ios/build/Build/Products/Release-iphonesimulator/RocketChatRN.app

      - save_cache: *save-npm-cache-mac

      - save_cache: *save-brew-cache

  e2e-test-onboarding:
    executor: mac-env
    steps:
      - detox-test:
          folder: "./e2e/tests/onboarding"

  e2e-test-room:
    executor: mac-env
    steps:
      - detox-test:
          folder: "./e2e/tests/room"

  e2e-test-assorted:
    executor: mac-env
    steps:
      - detox-test:
          folder: "./e2e/tests/assorted"

  # Android builds
  android-build:
    <<: *defaults
    docker:
      - image: circleci/android:api-28-node

    environment:
      JAVA_OPTS: '-Xms512m -Xmx2g'
      GRADLE_OPTS: '-Xmx3g -Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-Xmx2g -XX:+HeapDumpOnOutOfMemoryError"'
      TERM: dumb
      <<: *bash-env

    steps:
      - checkout

      - run: *install-node

      - restore_cache: *restore-npm-cache-linux

      - run: *install-npm-modules

      - run: *update-fastlane-android

      - restore_cache: *restore-gradle-cache

      - run:
          name: Configure Gradle
          command: |
            echo -e "" > ./gradle.properties
            # echo -e "android.enableAapt2=false" >> ./gradle.properties
            echo -e "android.useAndroidX=true" >> ./gradle.properties
            echo -e "android.enableJetifier=true" >> ./gradle.properties
            echo -e "FLIPPER_VERSION=0.33.1" >> ./gradle.properties

            if [[ $KEYSTORE ]]; then
              echo $KEYSTORE_BASE64 | base64 --decode > ./app/$KEYSTORE
              echo -e "KEYSTORE=$KEYSTORE" >> ./gradle.properties
              echo -e "KEYSTORE_PASSWORD=$KEYSTORE_PASSWORD" >> ./gradle.properties
              echo -e "KEY_ALIAS=$KEY_ALIAS" >> ./gradle.properties
              echo -e "KEY_PASSWORD=$KEYSTORE_PASSWORD" >> ./gradle.properties
            fi

            echo -e "VERSIONCODE=$CIRCLE_BUILD_NUM" >> ./gradle.properties
            echo -e "BugsnagAPIKey=$BUGSNAG_KEY" >> ./gradle.properties
          working_directory: android

      - run:
          name: Set Google Services
          command: |
            cp google-services.prod.json google-services.json
          working_directory: android/app

      - run:
          name: Config variables
          command: |
            echo -e "export default { BUGSNAG_API_KEY: '$BUGSNAG_KEY' };" > ./config.js

      - run:
          name: Build Android App
          command: |
            if [[ $KEYSTORE ]]; then
              bundle exec fastlane android release
            else
              bundle exec fastlane android build
            fi
          working_directory: android

      - run:
          name: Upload sourcemaps to Bugsnag
          command: |
            if [[ $BUGSNAG_KEY ]]; then
              yarn generate-source-maps-android upload \
                --api-key=$BUGSNAG_KEY \
                --app-version=$CIRCLE_BUILD_NUM \
                --minifiedFile=android/app/build/generated/assets/react/release/app.bundle \
                --source-map=android/app/build/generated/sourcemaps/react/release/app.bundle.map \
                --minified-url=app.bundle \
                --upload-sources
            fi

      - store_artifacts:
          path: android/app/build/outputs

      - save_cache: *save-npm-cache-linux

      - save_cache: *save-gradle-cache

      - persist_to_workspace:
          root: .
          paths:
            - android/fastlane/report.xml
            - android/app/build/outputs

  android-google-play-alpha:
    <<: *defaults
    docker:
      - image: circleci/android:api-28-node

    steps:
      - checkout

      - attach_workspace:
          at: android

      - run:
          name: Store the google service account key
          command: echo "$FASTLANE_GOOGLE_SERVICE_ACCOUNT" | base64 --decode > service_account.json
          working_directory: android

      - run: *update-fastlane-android

      - run:
          name: Fastlane Play Store Upload
          command: bundle exec fastlane android alpha
          working_directory: android

  # iOS builds
  ios-build:
    executor: mac-env

    steps:
      - checkout

      - restore_cache: *restore-gems-cache

      - restore_cache: *restore-npm-cache-mac

      - run: *install-node

      - run: *install-npm-modules

      - run: *update-fastlane-ios

      - run:
          name: Set Google Services
          command: |
            cp GoogleService-Info.prod.plist GoogleService-Info.plist
          working_directory: ios

      - run:
          name: Upload sourcemaps to Bugsnag
          command: |
            if [[ $BUGSNAG_KEY ]]; then
              yarn generate-source-maps-ios
              curl https://upload.bugsnag.com/react-native-source-map \
                -F apiKey=$BUGSNAG_KEY \
                -F appBundleVersion=$CIRCLE_BUILD_NUM \
                -F dev=false \
                -F platform=ios \
                -F sourceMap=@ios-release.bundle.map \
                -F bundle=@ios-release.bundle
            fi

      - run:
          name: Fastlane Build
          no_output_timeout: 1200
          command: |
            agvtool new-version -all $CIRCLE_BUILD_NUM
            /usr/libexec/PlistBuddy -c "Set BugsnagAPIKey $BUGSNAG_KEY" ./RocketChatRN/Info.plist

            if [[ $MATCH_KEYCHAIN_NAME ]]; then
              bundle exec fastlane ios release
            else
              export MATCH_KEYCHAIN_NAME="temp"
              export MATCH_KEYCHAIN_PASSWORD="temp"
              bundle exec fastlane ios build
            fi
          working_directory: ios

      - save_cache: *save-npm-cache-mac

      - save_cache: *save-gems-cache

      - store_artifacts:
          path: ios/RocketChatRN.ipa

      - persist_to_workspace:
          root: .
          paths:
            - ios/*.ipa
            - ios/fastlane/report.xml

  ios-testflight:
    executor: mac-env

    steps:
      - checkout

      - attach_workspace:
          at: ios

      - restore_cache: *restore-gems-cache

      - run: *update-fastlane-ios

      - run:
          name: Fastlane Tesflight Upload
          command: |
            bundle exec fastlane ios beta
          working_directory: ios

      - save_cache: *save-gems-cache

workflows:
  build-and-test:
    jobs:
      - lint-testunit

      - e2e-hold:
          type: approval
          requires:
            - lint-testunit
      - e2e-build:
          requires:
            - e2e-hold
      - e2e-test-onboarding:
          requires:
            - e2e-build
      - e2e-test-room:
          requires:
            - e2e-build
      - e2e-test-assorted:
          requires:
            - e2e-build

      - ios-build:
          requires:
            - lint-testunit
      - ios-hold-testflight:
          type: approval
          requires:
            - ios-build
      - ios-testflight:
          requires:
            - ios-hold-testflight

      - android-build:
          requires:
            - lint-testunit
      - android-hold-google-play-alpha:
          type: approval
          requires:
            - android-build
      - android-google-play-alpha:
          requires:
            - android-hold-google-play-alpha