defaults: &defaults working_directory: ~/repo macos: &macos macos: xcode: "12.5.0" resource_class: large 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: | 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" }} # COMMANDS commands: manage-pods: description: "Restore/Get/Save cache of pods libs" steps: - restore_cache: name: Restore pods # TODO: CircleCI isn't caching Podfile.lock correctly, because checksum changes after install # key: pods-v1-{{ checksum "ios/Podfile.lock" }} key: pods-v1-{{ checksum "ios/Podfile" }} - run: name: Install pods libs command: | bundle exec pod install working_directory: ios - save_cache: name: Save pods specs and pods cache # key: pods-v1-{{ checksum "ios/Podfile.lock" }} key: pods-v1-{{ checksum "ios/Podfile" }} paths: - ~/.pods - ios/Pods android-build: description: "Build Android app" 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.enableAapt2=false" >> ./gradle.properties echo -e "android.useAndroidX=true" >> ./gradle.properties echo -e "android.enableJetifier=true" >> ./gradle.properties echo -e "FLIPPER_VERSION=0.51.0" >> ./gradle.properties echo -e "VERSIONCODE=$CIRCLE_BUILD_NUM" >> ./gradle.properties if [[ $CIRCLE_JOB == "android-build-official" ]]; then echo -e "APPLICATION_ID=chat.rocket.android" >> ./gradle.properties echo -e "BugsnagAPIKey=$BUGSNAG_KEY_OFFICIAL" >> ./gradle.properties echo $CHAT_ROCKET_ANDROID_STORE_FILE_BASE64_JKS | base64 --decode > ./app/$KEYSTORE_OFFICIAL echo -e "KEYSTORE=$KEYSTORE_OFFICIAL" >> ./gradle.properties echo -e "KEYSTORE_PASSWORD=$CHAT_ROCKET_ANDROID_STORE_PASSWORD" >> ./gradle.properties echo -e "KEY_ALIAS=$CHAT_ROCKET_ANDROID_KEY_ALIAS" >> ./gradle.properties echo -e "KEY_PASSWORD=$CHAT_ROCKET_ANDROID_KEY_PASSWORD" >> ./gradle.properties else echo -e "APPLICATION_ID=chat.rocket.reactnative" >> ./gradle.properties echo -e "BugsnagAPIKey=$BUGSNAG_KEY" >> ./gradle.properties 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 working_directory: android - run: name: Set Google Services command: | if [[ $KEYSTORE ]]; then echo $GOOGLE_SERVICES_ANDROID | base64 --decode > google-services.json fi working_directory: android/app - run: name: Build App no_output_timeout: 30m command: | if [[ $CIRCLE_JOB == "android-build-official" ]]; then ./gradlew bundleOfficialPlayRelease fi if [[ $CIRCLE_JOB == "android-build-experimental" ]]; then ./gradlew bundleExperimentalPlayRelease fi if [[ $CIRCLE_JOB == "android-build-e2e" ]]; then ./gradlew app:assembleE2ePlayRelease app:assembleE2ePlayReleaseAndroidTest -DtestBuildType=release fi if [[ ! $KEYSTORE ]]; then ./gradlew assembleExperimentalPlayDebug fi working_directory: android - run: name: Upload sourcemaps to Bugsnag command: | if [[ $CIRCLE_JOB == "android-build-official" ]]; 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/officialPlay/release/app.bundle.map \ --bundle android/app/build/generated/assets/react/officialPlay/release/app.bundle fi if [[ $CIRCLE_JOB == "android-build-experimental" ]]; then npx bugsnag-source-maps upload-react-native \ --api-key=$BUGSNAG_KEY \ --app-version-code=$CIRCLE_BUILD_NUM \ --platform android \ --source-map=android/app/build/generated/sourcemaps/react/experimentalPlay/release/app.bundle.map \ --bundle android/app/build/generated/assets/react/experimentalPlay/release/app.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-e2e-test: description: "End-to-End testing for Android using detox" parameters: folder: type: string default: "" steps: - checkout - node/install: install-yarn: true - restore_cache: *restore-npm-cache-linux - run: *install-npm-modules - run: name: Create avd command: | SYSTEM_IMAGES="system-images;android-28;default;x86" sdkmanager "$SYSTEM_IMAGES" echo "no" | avdmanager --verbose create avd -n "PIXEL_API_28_AOSP" -k "$SYSTEM_IMAGES" -d "pixel" - run: name: Launch emulator command: | emulator -avd "PIXEL_API_28_AOSP" -delay-adb -verbose -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim background: true - run: name: Run the test command: | yarn detox test <> -c and.emu.release --cleanup ios-build: description: "Build iOS app" 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 [[ $KEYSTORE ]]; 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 if [[ $CIRCLE_JOB == "ios-build-official" ]]; then /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 /usr/libexec/PlistBuddy -c "Set IS_OFFICIAL YES" ./RocketChatRN/Info.plist /usr/libexec/PlistBuddy -c "Set IS_OFFICIAL YES" ./ShareRocketChatRN/Info.plist /usr/libexec/PlistBuddy -c "Set IS_OFFICIAL YES" ./NotificationService/Info.plist else /usr/libexec/PlistBuddy -c "Set :bugsnag:apiKey $BUGSNAG_KEY" ./RocketChatRN/Info.plist /usr/libexec/PlistBuddy -c "Set :bugsnag:apiKey $BUGSNAG_KEY" ./ShareRocketChatRN/Info.plist /usr/libexec/PlistBuddy -c "Set IS_OFFICIAL NO" ./RocketChatRN/Info.plist /usr/libexec/PlistBuddy -c "Set IS_OFFICIAL NO" ./ShareRocketChatRN/Info.plist /usr/libexec/PlistBuddy -c "Set IS_OFFICIAL NO" ./NotificationService/Info.plist fi if [[ $APP_STORE_CONNECT_API_BASE64 ]]; then echo $APP_STORE_CONNECT_API_BASE64 | base64 --decode > ./fastlane/app_store_connect_api_key.p8 if [[ $CIRCLE_JOB == "ios-build-official" ]]; then bundle exec fastlane ios build_official else if [[ $KEYSTORE ]]; then bundle exec fastlane ios build_experimental else bundle exec fastlane ios build_fork fi fi 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 upload-to-google-play-beta: description: "Upload to Google Play beta" parameters: official: type: boolean 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 official:<< parameters.official >> working_directory: android # EXPERIMENTAL ONLY upload-to-internal-app-sharing: description: "Upload to Internal App Sharing" 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 # EXPERIMENTAL ONLY # No plans to do it for Official upload-to-google-play-production: description: "Upload to Google Play production" 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 production working_directory: android upload-to-testflight: description: "Upload to TestFlight" parameters: official: 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_BASE64 | base64 --decode > ./fastlane/app_store_connect_api_key.p8 bundle exec fastlane ios beta official:<< parameters.official >> working_directory: ios - save_cache: *save-gems-cache version: 2.1 orbs: node: circleci/node@4.6.0 # EXECUTORS executors: mac-env: <<: *macos environment: <<: *bash-env # JOBS jobs: lint-testunit: <<: *defaults docker: - image: circleci/node:15 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 # Android builds android-build-experimental: <<: *defaults docker: - image: circleci/android:api-29-node environment: <<: *android-env <<: *bash-env steps: - android-build android-build-official: <<: *defaults docker: - image: circleci/android:api-29-node environment: <<: *android-env <<: *bash-env steps: - android-build android-build-e2e: <<: *defaults docker: - image: circleci/android:api-29-node environment: <<: *android-env <<: *bash-env steps: - android-build android-e2e-test-assorted: <<: *defaults machine: image: android:202102-01 resource_class: large environment: <<: *android-env <<: *bash-env steps: - android-e2e-test: folder: "./e2e/tests/assorted/" android-e2e-test-onboarding: <<: *defaults machine: image: android:202102-01 resource_class: large environment: <<: *android-env <<: *bash-env steps: - android-e2e-test: folder: "./e2e/tests/onboarding/" android-e2e-test-room: <<: *defaults machine: image: android:202102-01 resource_class: large environment: <<: *android-env <<: *bash-env steps: - android-e2e-test: folder: "./e2e/tests/room/" android-e2e-test-team: <<: *defaults machine: image: android:202102-01 resource_class: large environment: <<: *android-env <<: *bash-env steps: - android-e2e-test: folder: "./e2e/tests/team/" android-internal-app-sharing-experimental: <<: *defaults docker: - image: circleci/android:api-28-node steps: - upload-to-internal-app-sharing android-google-play-beta-experimental: <<: *defaults docker: - image: circleci/android:api-29-node steps: - upload-to-google-play-beta: official: false android-google-play-production-experimental: <<: *defaults docker: - image: circleci/android:api-29-node steps: - upload-to-google-play-production android-google-play-beta-official: <<: *defaults docker: - image: circleci/android:api-29-node steps: - upload-to-google-play-beta: official: true # iOS builds ios-build-experimental: executor: mac-env steps: - ios-build ios-build-official: executor: mac-env steps: - ios-build ios-testflight-experimental: executor: mac-env steps: - upload-to-testflight: official: false ios-testflight-official: executor: mac-env steps: - upload-to-testflight: official: true workflows: build-and-test: jobs: - lint-testunit # iOS Experimental - ios-hold-build-experimental: type: approval requires: - lint-testunit - ios-build-experimental: requires: - ios-hold-build-experimental - ios-testflight-experimental: requires: - ios-build-experimental # iOS Official - ios-hold-build-official: type: approval requires: - lint-testunit - ios-build-official: requires: - ios-hold-build-official - ios-hold-testflight-official: type: approval requires: - ios-build-official - ios-testflight-official: requires: - ios-hold-testflight-official # Android Experimental - android-hold-build-experimental: type: approval requires: - lint-testunit - android-build-experimental: requires: - android-hold-build-experimental - android-internal-app-sharing-experimental: requires: - android-build-experimental - android-hold-google-play-beta-experimental: type: approval requires: - android-build-experimental - android-google-play-beta-experimental: requires: - android-hold-google-play-beta-experimental - android-hold-google-play-production-experimental: type: approval requires: - android-build-experimental - android-google-play-production-experimental: requires: - android-hold-google-play-production-experimental # Android Official - android-hold-build-official: type: approval requires: - lint-testunit - android-build-official: requires: - android-hold-build-official - android-hold-google-play-beta-official: type: approval requires: - android-build-official - android-google-play-beta-official: requires: - android-hold-google-play-beta-official # Aandroid E2E Testing - android-hold-e2e: type: approval requires: - lint-testunit - android-build-e2e: requires: - android-hold-e2e - android-e2e-test-assorted: requires: - android-build-e2e - android-e2e-test-onboarding: requires: - android-build-e2e - android-e2e-test-room: requires: - android-build-e2e - android-e2e-test-team: requires: - android-build-e2e