defaults: &defaults working_directory: ~/repo android-img: &android-img docker: - image: cimg/android:2023.04.1-node orbs: android: circleci/android@2.1.2 macos: &macos macos: xcode: "14.2.0" resource_class: macos.m1.large.gen1 bash-env: &bash-env BASH_ENV: "~/.nvm/nvm.sh" android-env: &android-env JAVA_OPTS: '-Xms512m -Xmx2g' GRADLE_OPTS: '-Xmx3g -Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-Xmx2g -XX:+HeapDumpOnOutOfMemoryError"' TERM: dumb 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 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: | bundle install working_directory: ios update-fastlane-android: &update-fastlane-android name: Update Fastlane command: | bundle config set --local deployment 'true' 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" }} # COMMANDS commands: manage-pods: description: "Restore/Get/Save cache of pods libs" steps: - restore_cache: name: Restore pods key: pods-v1-{{ checksum "ios/Podfile.lock" }} - run: name: Install pods libs command: | bundle exec pod install --deployment working_directory: ios - save_cache: name: Save pods specs and pods cache key: pods-v1-{{ checksum "ios/Podfile.lock" }} paths: - ~/.pods - ios/Pods upload-to-testflight: description: "Upload to TestFlight" parameters: distribute_external: type: boolean steps: - checkout - attach_workspace: at: ios - restore_cache: *restore-gems-cache - restore_cache: *restore-npm-cache-mac - run: *update-fastlane-ios - manage-pods - run: name: Fastlane Tesflight Upload command: | echo $APP_STORE_CONNECT_API_KEY_BASE64 | base64 --decode > ./fastlane/app_store_connect_api_key.p8 bundle exec fastlane ios beta distribute_external:<< parameters.distribute_external >> working_directory: ios - save_cache: *save-gems-cache create-e2e-account-file: description: "Create e2e account file" steps: - run: command: | echo $E2E_ACCOUNT | base64 --decode > ./e2e_account.ts working_directory: e2e version: 2.1 # EXECUTORS executors: mac-env: <<: *macos environment: <<: *bash-env # JOBS jobs: lint-testunit: <<: *defaults docker: - image: cimg/node:16.14 resource_class: large 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 -w 8 - run: name: Codecov command: | yarn codecov - save_cache: *save-npm-cache-linux # Android builds android-build: <<: *defaults <<: *android-img environment: <<: *android-env <<: *bash-env resource_class: xlarge steps: - checkout - restore_cache: *restore-npm-cache-linux - run: *install-npm-modules - restore_cache: *restore-gradle-cache - run: name: Configure Gradle command: | echo -e "" > ./gradle.properties echo -e "android.useAndroidX=true" >> ./gradle.properties echo -e "android.enableJetifier=true" >> ./gradle.properties echo -e "newArchEnabled=false" >> ./gradle.properties echo -e "hermesEnabled=true" >> ./gradle.properties echo -e "FLIPPER_VERSION=0.125.0" >> ./gradle.properties echo -e "VERSIONCODE=$CIRCLE_BUILD_NUM" >> ./gradle.properties echo -e "APPLICATION_ID=chat.rocket.android" >> ./gradle.properties echo -e "BugsnagAPIKey=$BUGSNAG_KEY_OFFICIAL" >> ./gradle.properties echo $KEYSTORE_OFFICIAL_BASE64 | base64 --decode > ./app/$KEYSTORE_OFFICIAL echo -e "KEYSTORE=$KEYSTORE_OFFICIAL" >> ./gradle.properties echo -e "KEYSTORE_PASSWORD=$KEYSTORE_OFFICIAL_PASSWORD" >> ./gradle.properties echo -e "KEY_ALIAS=$KEYSTORE_OFFICIAL_ALIAS" >> ./gradle.properties echo -e "KEY_PASSWORD=$KEYSTORE_OFFICIAL_PASSWORD" >> ./gradle.properties working_directory: android - run: name: Set Google Services command: | if [[ $GOOGLE_SERVICES_ANDROID ]]; then echo $GOOGLE_SERVICES_ANDROID | base64 --decode > google-services.json fi working_directory: android/app - run: name: Build App no_output_timeout: 40m command: | sudo apt install -y libicu-dev if [[ $CIRCLE_JOB == "android-build" ]]; then ./gradlew bundlePlayRelease fi if [[ ! $GOOGLE_SERVICES_ANDROID ]]; then ./gradlew assemblePlayDebug fi working_directory: android - run: name: Upload sourcemaps to Bugsnag command: | if [[ $CIRCLE_JOB == "android-build" ]]; then npx bugsnag-source-maps upload-react-native \ --api-key=$BUGSNAG_KEY_OFFICIAL \ --app-version-code=$CIRCLE_BUILD_NUM \ --platform android \ --source-map=android/app/build/generated/sourcemaps/react/playRelease/index.android.bundle.map \ --bundle android/app/build/ASSETS/createBundlePlayReleaseJsAndAssets/index.android.bundle 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/app/build/outputs android-internal-app-sharing: <<: *defaults <<: *android-img 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 internal_app_sharing working_directory: android android-beta: <<: *defaults <<: *android-img 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 beta working_directory: android e2e-build-android: <<: *defaults executor: name: android/android-machine resource-class: xlarge tag: 2023.04.1 environment: <<: *android-env steps: - checkout - restore_cache: *restore-npm-cache-linux - run: *install-npm-modules - save_cache: *save-npm-cache-linux - 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 "newArchEnabled=false" >> ./gradle.properties echo -e "hermesEnabled=true" >> ./gradle.properties echo -e "FLIPPER_VERSION=0.125.0" >> ./gradle.properties echo -e "VERSIONCODE=$CIRCLE_BUILD_NUM" >> ./gradle.properties echo -e "APPLICATION_ID=chat.rocket.android" >> ./gradle.properties echo -e "BugsnagAPIKey=$BUGSNAG_KEY" >> ./gradle.properties echo $KEYSTORE_EXPERIMENTAL_BASE64 | base64 --decode > ./app/$KEYSTORE_EXPERIMENTAL echo -e "KEYSTORE=$KEYSTORE_EXPERIMENTAL" >> ./gradle.properties echo -e "KEYSTORE_PASSWORD=$KEYSTORE_EXPERIMENTAL_PASSWORD" >> ./gradle.properties echo -e "KEY_ALIAS=$KEYSTORE_EXPERIMENTAL_ALIAS" >> ./gradle.properties echo -e "KEY_PASSWORD=$KEYSTORE_EXPERIMENTAL_PASSWORD" >> ./gradle.properties working_directory: android - run: name: Build Android no_output_timeout: 20m command: | export RUNNING_E2E_TESTS=true yarn e2e:android-build - save_cache: *save-gradle-cache - store_artifacts: path: android/app/build/outputs/apk/play/release/app-play-release.apk - store_artifacts: path: android/app/build/outputs/apk/androidTest/play/release/app-play-release-androidTest.apk - persist_to_workspace: root: /home/circleci/repo paths: - android/app/build/outputs/apk/ e2e-test-android: <<: *defaults executor: name: android/android-machine resource-class: xlarge tag: 2023.04.1 parallelism: 4 steps: - checkout - attach_workspace: at: /home/circleci/repo - restore_cache: *restore-npm-cache-linux - run: *install-npm-modules - save_cache: *save-npm-cache-linux - run: mkdir ~/junit - create-e2e-account-file - android/create-avd: avd-name: Pixel_API_31_AOSP install: true system-image: system-images;android-31;default;x86_64 - run: name: Setup emulator command: | echo "hw.lcd.density = 440" >> ~/.android/avd/Pixel_API_31_AOSP.avd/config.ini echo "hw.lcd.height = 2280" >> ~/.android/avd/Pixel_API_31_AOSP.avd/config.ini echo "hw.lcd.width = 1080" >> ~/.android/avd/Pixel_API_31_AOSP.avd/config.ini - android/start-emulator: avd-name: Pixel_API_31_AOSP verbose: true post-emulator-launch-assemble-command: '' - run: name: Run Detox Tests command: | TEST=$(circleci tests glob "e2e/tests/**/*.ts" | circleci tests split --split-by=timings) yarn e2e:android-test $TEST - store_artifacts: path: artifacts - run: command: cp junit.xml ~/junit/ when: always - store_test_results: path: ~/junit - store_artifacts: path: ~/junit ios-build: executor: mac-env steps: - checkout - restore_cache: *restore-gems-cache - restore_cache: *restore-npm-cache-mac - run: *install-npm-modules - run: *update-fastlane-ios - manage-pods - run: name: Set Google Services command: | if [[ $APP_STORE_CONNECT_API_KEY_BASE64 ]]; then echo $GOOGLE_SERVICES_IOS | base64 --decode > GoogleService-Info.plist fi working_directory: ios - run: name: Fastlane Build no_output_timeout: 40m command: | agvtool new-version -all $CIRCLE_BUILD_NUM /usr/libexec/PlistBuddy -c "Set :bugsnag:apiKey $BUGSNAG_KEY_OFFICIAL" ./RocketChatRN/Info.plist /usr/libexec/PlistBuddy -c "Set :bugsnag:apiKey $BUGSNAG_KEY_OFFICIAL" ./ShareRocketChatRN/Info.plist if [[ $APP_STORE_CONNECT_API_KEY_BASE64 ]]; then echo $APP_STORE_CONNECT_API_KEY_BASE64 | base64 --decode > ./fastlane/app_store_connect_api_key.p8 bundle exec fastlane ios build_official fi working_directory: ios - save_cache: *save-npm-cache-mac - save_cache: *save-gems-cache - store_artifacts: path: ios/Rocket.Chat.ipa - store_artifacts: path: ios/Rocket.Chat.app.dSYM.zip - persist_to_workspace: root: . paths: - ios/*.ipa - ios/*.zip ios-testflight: executor: mac-env steps: - upload-to-testflight: distribute_external: false ios-beta: executor: mac-env steps: - upload-to-testflight: distribute_external: true e2e-build-ios: executor: mac-env steps: - checkout - restore_cache: *restore-gems-cache - restore_cache: *restore-npm-cache-mac - run: *install-npm-modules - run: *update-fastlane-ios - save_cache: *save-npm-cache-mac - save_cache: *save-gems-cache - manage-pods - run: name: Configure Detox command: | brew tap wix/brew brew install applesimutils - run: name: Build no_output_timeout: 20m command: | /usr/libexec/PlistBuddy -c "Set :bugsnag:apiKey $BUGSNAG_KEY" ./ios/RocketChatRN/Info.plist /usr/libexec/PlistBuddy -c "Set :bugsnag:apiKey $BUGSNAG_KEY" ./ios/ShareRocketChatRN/Info.plist yarn detox clean-framework-cache && yarn detox build-framework-cache export RUNNING_E2E_TESTS=true yarn e2e:ios-build - persist_to_workspace: root: /Users/distiller/project paths: - ios/build/Build/Products/Release-iphonesimulator/Rocket.Chat.app e2e-test-ios: executor: mac-env parallelism: 5 steps: - checkout - attach_workspace: at: /Users/distiller/project - restore_cache: *restore-npm-cache-mac - run: *install-npm-modules - save_cache: *save-npm-cache-mac - run: mkdir ~/junit - run: name: Configure Detox command: | brew tap wix/brew brew install applesimutils yarn detox clean-framework-cache && yarn detox build-framework-cache - create-e2e-account-file - run: name: Run tests command: | TEST=$(circleci tests glob "e2e/tests/**/*.ts" | circleci tests split --split-by=timings) yarn e2e:ios-test $TEST - store_artifacts: path: artifacts - run: command: cp junit.xml ~/junit/ when: always - store_test_results: path: ~/junit - store_artifacts: path: ~/junit workflows: build-and-test: jobs: - lint-testunit - build-hold: type: approval requires: - lint-testunit filters: branches: ignore: - develop # E2E tests - e2e-hold: type: approval - e2e-build-ios: requires: - e2e-hold - e2e-test-ios: requires: - e2e-build-ios - e2e-build-android: requires: - e2e-hold - e2e-test-android: requires: - e2e-build-android # iOS - ios-build: requires: - build-hold - ios-testflight: requires: - ios-build # Android - android-build: requires: - build-hold - android-internal-app-sharing: requires: - android-build - android-hold-beta: type: approval requires: - android-build - android-beta: requires: - android-hold-beta # Workflows to run when a PR is merged to develop - android-build: name: android-build-develop filters: &filters-develop-only branches: only: - develop requires: - lint-testunit - android-beta: name: android-beta-develop requires: - android-build-develop - ios-build: name: ios-build-develop filters: <<: *filters-develop-only requires: - lint-testunit - ios-beta: requires: - ios-build-develop - e2e-build-ios: name: e2e-build-ios-develop filters: <<: *filters-develop-only - e2e-test-ios: requires: - e2e-build-ios - e2e-build-android: name: e2e-build-android-develop filters: <<: *filters-develop-only - e2e-test-android: requires: - e2e-build-android