version: 2.1 # ------------------------- # ORBS # ------------------------- orbs: win: circleci/windows@2.4.0 # ------------------------- # REFERENCES # ------------------------- references: defaults: &defaults working_directory: ~/react-native environment: - GIT_COMMIT_DESC: git log --format=oneline -n 1 $CIRCLE_SHA1 # The public github tokens are publicly visible by design - PUBLIC_PULLBOT_GITHUB_TOKEN_A: &github_pullbot_token_a "a6edf8e8d40ce4e8b11a" - PUBLIC_PULLBOT_GITHUB_TOKEN_B: &github_pullbot_token_b "150e1341f4dd9c944d2a" - PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A: &github_analysisbot_token_a "312d354b5c36f082cfe9" - PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B: &github_analysisbot_token_b "07973d757026bdd9f196" # Homebrew currently breaks while updating: # https://discuss.circleci.com/t/brew-install-fails-while-updating/32992 - HOMEBREW_NO_AUTO_UPDATE: 1 hermes_workspace_root: &hermes_workspace_root /tmp/hermes attach_hermes_workspace: &attach_hermes_workspace attach_workspace: at: *hermes_workspace_root # ------------------------- # Dependency Anchors # ------------------------- dependency_versions: # The Xcode version used on CircleCI OSS tests must be kept in sync with # the Xcode version used on Sandcastle OSS tests. See _XCODE_VERSION in # tools/utd/migrated_nbtd_jobs/react_native_oss.td xcode_version: &xcode_version "13.3.1" nodelts_image: &nodelts_image "cimg/node:16.14" nodeprevlts_image: &nodeprevlts_image "cimg/node:14.19" # ------------------------- # Cache Key Anchors # ------------------------- # Anchors for the cache keys cache_keys: buck_cache_key: &buck_cache_key v3-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }}} checkout_cache_key: &checkout_cache_key v1-checkout gems_cache_key: &gems_cache_key v1-gems-{{ checksum "Gemfile.lock" }} gradle_cache_key: &gradle_cache_key v1-gradle-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "ReactAndroid/gradle.properties" }} hermes_cache_key: &hermes_cache_key v1-hermes-{{ .Environment.CIRCLE_JOB }}-{{ checksum "/tmp/hermes/hermesversion" }} hermes_sdk_cache_key: &hermes_sdk_cache_key v1-hermes-{{ .Environment.CIRCLE_JOB }}-{{ checksum "sdks/.hermes-cache-key-file" }} hermes_windows_cache_key: &hermes_windows_cache_key v1-hermes-{{ .Environment.CIRCLE_JOB }}-{{ checksum "tmp/hermes/hermesversion" }} pods_cache_key: &pods_cache_key v6-pods-{{ .Environment.CIRCLE_JOB }}-{{ checksum "packages/rn-tester/Podfile.lock.bak" }}-{{ checksum "packages/rn-tester/Podfile" }} windows_yarn_cache_key: &windows_yarn_cache_key v1-win-yarn-cache-{{ arch }}-{{ checksum "yarn.lock" }} yarn_cache_key: &yarn_cache_key v5-yarn-cache-{{ .Environment.CIRCLE_JOB }} # ------------------------- # Filters # ------------------------- # CircleCI filters are OR-ed, with all branches triggering by default and tags excluded by default # CircleCI env-vars are only set with the branch OR tag that triggered the job, not both. # In this case, CIRCLE_BRANCH is unset, but CIRCLE_TAG is set. only_release_tags: &only_release_tags # Both of the following conditions must be included! # Ignore any commit on any branch by default. branches: ignore: /.*/ # Only act on version tags. tags: only: /v[0-9]+(\.[0-9]+)*(\-rc(\.[0-9]+)?)?/ # ------------------------- # EXECUTORS # ------------------------- executors: nodelts: <<: *defaults docker: # Note: Version set separately for Windows builds, see below. - image: *nodelts_image resource_class: "xlarge" nodeprevlts: <<: *defaults docker: - image: *nodeprevlts_image resource_class: "xlarge" reactnativeandroid: <<: *defaults docker: - image: reactnativecommunity/react-native-android:5.4 resource_class: "xlarge" environment: - TERM: "dumb" - ADB_INSTALL_TIMEOUT: 10 - GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-XX:+HeapDumpOnOutOfMemoryError"' - BUILD_THREADS: 2 # Repeated here, as the environment key in this executor will overwrite the one in defaults - PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A: *github_analysisbot_token_a - PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B: *github_analysisbot_token_b - PUBLIC_PULLBOT_GITHUB_TOKEN_A: *github_pullbot_token_a - PUBLIC_PULLBOT_GITHUB_TOKEN_B: *github_pullbot_token_b reactnativeios: <<: *defaults macos: xcode: *xcode_version resource_class: macos.x86.medium.gen2 # ------------------------- # COMMANDS # ------------------------- commands: # Checkout with cache, on machines that are using Docker the cache is ignored checkout_code_with_cache: parameters: checkout_base_cache_key: default: *checkout_cache_key type: string steps: - restore_cache: keys: - << parameters.checkout_base_cache_key >>-{{ .Branch }}-{{ .Revision }} - << parameters.checkout_base_cache_key >>-{{ .Branch }}- - << parameters.checkout_base_cache_key >> - checkout - save_cache: key: << parameters.checkout_base_cache_key >>-{{ .Branch }}-{{ .Revision }} paths: - ".git" setup_artifacts: steps: - run: name: Initial Setup command: mkdir -p ./reports/{buck,build,junit,outputs} setup_ruby: steps: - restore_cache: key: *gems_cache_key - run: name: Bundle Install command: | source /usr/local/share/chruby/auto.sh bundle check || bundle install --path vendor/bundle --clean - save_cache: key: *gems_cache_key paths: - vendor/bundle run_yarn: parameters: yarn_base_cache_key: default: *yarn_cache_key type: string steps: - restore_cache: keys: - << parameters.yarn_base_cache_key >>-{{ arch }}-{{ checksum "yarn.lock" }} - << parameters.yarn_base_cache_key >>-{{ arch }} - << parameters.yarn_base_cache_key >> - run: name: "Yarn: Install Dependencies" command: | # Skip yarn install on metro bump commits as the package is not yet # available on npm if [[ $(echo "$GIT_COMMIT_DESC" | grep -c "Bump metro@") -eq 0 ]]; then yarn install --non-interactive --cache-folder ~/.cache/yarn fi - save_cache: paths: - ~/.cache/yarn key: << parameters.yarn_base_cache_key >>-{{ arch }}-{{ checksum "yarn.lock" }} install_buck_tooling: steps: - restore_cache: keys: - *buck_cache_key - run: name: Install BUCK command: | buck --version # Install related tooling if [[ ! -e ~/okbuck ]]; then git clone https://github.com/uber/okbuck.git ~/okbuck --depth=1 fi - save_cache: paths: - ~/buck - ~/okbuck key: *buck_cache_key install_github_bot_deps: steps: - run: name: "Yarn: Install dependencies (GitHub bots)" command: cd bots && yarn install --non-interactive --cache-folder ~/.cache/yarn brew_install: parameters: package: description: Homebrew package to install type: string steps: - run: name: "Brew: Install << parameters.package >>" command: brew install << parameters.package >> >/dev/null with_rntester_pods_cache_span: parameters: steps: type: steps steps: - run: name: Setup CocoaPods cache # Copy packages/rn-tester/Podfile.lock since it can be changed by pod install command: cp packages/rn-tester/Podfile.lock packages/rn-tester/Podfile.lock.bak - restore_cache: keys: # The committed lockfile is generated using USE_FRAMEWORKS=0 and USE_HERMES=1 so it could load an outdated cache if a change # only affects the frameworks or hermes config. To help prevent this also cache based on the content of Podfile. - *pods_cache_key - steps: << parameters.steps >> - save_cache: paths: - packages/rn-tester/Pods key: *pods_cache_key download_gradle_dependencies: steps: - restore_cache: keys: - *gradle_cache_key - run: name: Download Dependencies Using Gradle command: ./gradlew downloadAll - save_cache: paths: - ~/.gradle - ReactAndroid/build/downloads - ReactAndroid/build/third-party-ndk key: *gradle_cache_key download_buck_dependencies: steps: - run: name: Download Dependencies Using Buck command: ./scripts/circleci/buck_fetch.sh run_e2e: parameters: platform: description: Target platform type: enum enum: ["android", "ios", "js"] default: "js" retries: description: How many times the job should try to run these tests type: integer default: 3 steps: - run: name: "Run Tests: << parameters.platform >> End-to-End Tests" command: node ./scripts/run-ci-e2e-tests.js --<< parameters.platform >> --retries << parameters.retries >> report_bundle_size: parameters: platform: description: Target platform type: enum enum: ["android", "ios"] steps: - install_github_bot_deps - run: name: Report size of RNTester.app (analysis-bot) command: GITHUB_TOKEN="$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A""$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B" scripts/circleci/report-bundle-size.sh << parameters.platform >> || true with_hermes_sdk_cache_span: parameters: steps: type: steps steps: - run: name: Setup Hermes cache command: | HERMES_CACHE_KEY_FILE="sdks/.hermes-cache-key-file" if [ ! -f "$HERMES_CACHE_KEY_FILE" ]; then git ls-remote https://github.com/facebook/hermes main | cut -f 1 > $HERMES_CACHE_KEY_FILE fi - restore_cache: keys: - *hermes_sdk_cache_key - steps: << parameters.steps >> - save_cache: key: *hermes_sdk_cache_key paths: - sdks/hermesc - sdks/hermes # ------------------------- # JOBS # ------------------------- jobs: # ------------------------- # JOBS: Analyze PR # ------------------------- # Analyze pull request and raise any lint/flow issues. # Issues will be posted to the PR itself via GitHub bots. # This workflow should only fail if the bots fail to run. analyze_pr: executor: reactnativeandroid steps: - checkout - run_yarn - install_github_bot_deps # Note: The yarn gpg key needs to be refreshed to work around https://github.com/yarnpkg/yarn/issues/7866 - run: name: Install additional GitHub bot dependencies # TEMP: Added workaround from https://github.com/nodesource/distributions/issues/1266#issuecomment-932583579 command: | curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - apt update && apt install -y shellcheck jq apt-get -y install openssl ca-certificates update-ca-certificates curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - apt update && apt install -y shellcheck jq - run: name: Run linters against modified files (analysis-bot) command: GITHUB_TOKEN="$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A""$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B" yarn lint-ci when: always # ------------------------- # JOBS: Analyze Code # ------------------------- analyze_code: executor: reactnativeandroid steps: - checkout - setup_artifacts - run_yarn - run: name: Lint code command: scripts/circleci/exec_swallow_error.sh yarn lint --format junit -o ./reports/junit/eslint/results.xml when: always - run: name: Lint Java command: scripts/circleci/exec_swallow_error.sh yarn lint-java --check when: always - run: name: Check for errors in code using Flow (iOS) command: yarn flow-check-ios when: always - run: name: Check for errors in code using Flow (Android) command: yarn flow-check-android when: always - run: name: Sanity checks command: | ./scripts/circleci/check_license.sh ./scripts/circleci/validate_yarn_lockfile.sh when: always - run: name: Check formatting command: yarn run format-check when: always - store_test_results: path: ./reports/junit # ------------------------- # JOBS: Test JavaScript # ------------------------- test_js: parameters: executor: type: executor default: nodelts run_disabled_tests: type: boolean default: false executor: << parameters.executor >> steps: - checkout - setup_artifacts - run_yarn - run: name: Install rsync command: sudo apt update && sudo apt install rsync # ------------------------- # Run JavaScript tests - run: name: "Run Tests: JavaScript Tests" command: node ./scripts/run-ci-javascript-tests.js --maxWorkers 2 - run_e2e: platform: js # Optionally, run disabled tests - when: condition: << parameters.run_disabled_tests >> steps: - run: echo "Failing tests may be moved here temporarily." # ------------------------- - store_test_results: path: ./reports/junit # ------------------------- # JOBS: iOS Unit Tests # ------------------------- test_ios: executor: reactnativeios parameters: use_frameworks: type: boolean default: false run_unit_tests: description: Specifies whether unit tests should run. type: boolean default: false run_disabled_tests: description: Specifies whether disabled tests should run. Set this to true to debug failing tests. type: boolean default: false environment: - REPORTS_DIR: "./reports/junit" steps: - checkout_code_with_cache - setup_artifacts - setup_ruby - run: name: Run Ruby Tests command: | cd scripts sh run_ruby_tests.sh - run_yarn - run: | cd packages/rn-tester bundle check || bundle install - run: name: Boot iPhone Simulator command: source scripts/.tests.env && xcrun simctl boot "$IOS_DEVICE" || true - run: name: Configure Environment Variables command: | echo 'export PATH=/usr/local/opt/node@16/bin:$PATH' >> $BASH_ENV source $BASH_ENV - run: name: "Brew: Tap wix/brew" command: brew tap wix/brew >/dev/null - brew_install: package: applesimutils watchman cmake - run: name: Configure Watchman command: echo "{}" > .watchmanconfig - when: condition: << parameters.use_frameworks >> steps: - run: name: Set USE_FRAMEWORKS=1 command: echo "export USE_FRAMEWORKS=1" >> $BASH_ENV - run: name: Set USE_HERMES=1 command: echo "export USE_HERMES=1" >> $BASH_ENV - run: name: Set BUILD_HERMES_SOURCE=1 command: echo "export BUILD_HERMES_SOURCE=1" >> $BASH_ENV - run: name: Setup the CocoaPods environment command: bundle exec pod setup - with_hermes_sdk_cache_span: steps: - with_rntester_pods_cache_span: steps: - run: name: Generate RNTesterPods Workspace command: cd packages/rn-tester && bundle exec pod install --verbose # ------------------------- # Runs iOS unit tests - when: condition: << parameters.run_unit_tests >> steps: - run: name: "Run Tests: iOS Unit and Integration Tests" command: yarn test-ios # Optionally, run disabled tests - when: condition: << parameters.run_disabled_tests >> steps: - run: echo "Failing tests may be moved here temporarily." - run: name: "Run Tests: CocoaPods" command: ./scripts/process-podspecs.sh - run: name: Free up port 8081 for iOS End-to-End Tests command: | # free up port 8081 for the packager before running tests set +eo pipefail lsof -i tcp:8081 | awk 'NR!=1 {print $2}' | xargs kill set -eo pipefail - run_e2e: platform: ios # ------------------------- # Collect Results - report_bundle_size: platform: ios - store_test_results: path: ./reports/junit # ------------------------- # JOBS: Test Android # ------------------------- test_android: executor: reactnativeandroid parameters: run_disabled_tests: type: boolean default: false environment: KOTLIN_HOME=third-party/kotlin steps: - checkout - setup_artifacts - run_yarn # Validate Android SDK installation and packages - run: name: Validate Android SDK Install command: ./scripts/validate-android-sdk.sh # Starting emulator in advance as it takes some time to boot. - run: name: Create Android Virtual Device command: source scripts/android-setup.sh && createAVD - run: name: Launch Android Virtual Device in Background command: source scripts/android-setup.sh && launchAVD background: true # Install Buck - install_buck_tooling # Validate Android test environment (including Buck) - run: name: Validate Android Test Environment command: ./scripts/validate-android-test-env.sh - download_buck_dependencies - download_gradle_dependencies # Build and compile - run: name: Build & Test React Native using Buck command: | buck build ReactAndroid/src/main/java/com/facebook/react buck build ReactAndroid/src/main/java/com/facebook/react/shell - run: name: Build & Test React Native using Gradle command: ./gradlew buildAll - run: name: Compile Native Libs for Unit and Integration Tests command: ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=$BUILD_THREADS no_output_timeout: 30m - run: name: Build RN Tester for Release using Gradle command: ./gradlew packages:rn-tester:android:app:assembleRelease # Build JavaScript Bundle for instrumentation tests - run: name: Build JavaScript Bundle command: node cli.js bundle --max-workers 2 --platform android --dev true --entry-file ReactAndroid/src/androidTest/js/TestBundle.js --bundle-output ReactAndroid/src/androidTest/assets/AndroidTestBundle.js # Wait for AVD to finish booting before running tests - run: name: Wait for Android Virtual Device command: source scripts/android-setup.sh && waitForAVD # ------------------------- # Run Android tests - run: name: Run Tests - Android Unit Tests with Buck command: buck test ReactAndroid/src/test/... --config build.threads=$BUILD_THREADS --xml ./reports/buck/all-results-raw.xml - run: name: Build Tests - Android Instrumentation Tests with Buck # Here, just build the instrumentation tests. There is a known issue with installing the APK to android-21+ emulator. command: | if [[ ! -e ReactAndroid/src/androidTest/assets/AndroidTestBundle.js ]]; then echo "JavaScript bundle missing, cannot run instrumentation tests. Verify Build JavaScript Bundle step completed successfully."; exit 1; fi source scripts/android-setup.sh && NO_BUCKD=1 retry3 timeout 300 buck build ReactAndroid/src/androidTest/buck-runner:instrumentation-tests --config build.threads=$BUILD_THREADS # Optionally, run disabled tests - when: condition: << parameters.run_disabled_tests >> steps: - run: echo "Failing tests may be moved here temporarily." - run_e2e: platform: android # ------------------------- # Collect Results - report_bundle_size: platform: android - run: name: Collect Test Results command: | find . -type f -regex ".*/build/test-results/debug/.*xml" -exec cp {} ./reports/build/ \; find . -type f -regex ".*/outputs/androidTest-results/connected/.*xml" -exec cp {} ./reports/outputs/ \; find . -type f -regex ".*/buck-out/gen/ReactAndroid/src/test/.*/.*xml" -exec cp {} ./reports/buck/ \; if [ -f ~/react-native/reports/buck/all-results-raw.xml ]; then cd ~/okbuck ./tooling/junit/buck_to_junit.sh ~/react-native/reports/buck/all-results-raw.xml ~/react-native/reports/junit/results.xml fi when: always - store_test_results: path: ./reports/junit # ------------------------- # JOBS: Test Android Template # ------------------------- test_android_template: executor: reactnativeandroid steps: - checkout - run_yarn - attach_workspace: at: . - run: name: Create Android template project command: | REPO_ROOT=$(pwd) PACKAGE=$(cat build/react-native-package-version) PATH_TO_PACKAGE="$REPO_ROOT/build/$PACKAGE" cd template npm add $PATH_TO_PACKAGE npm install - run: name: Build the template application command: cd template/android/ && ./gradlew assembleDebug # ------------------------- # JOBS: Test iOS Template # ------------------------- test_ios_template: executor: reactnativeios environment: - PROJECT_NAME: "iOSTemplateProject" - HERMES_WS_DIR: *hermes_workspace_root steps: - checkout_code_with_cache - run_yarn - attach_workspace: at: . - *attach_hermes_workspace - run: name: Set USE_HERMES=1 command: echo "export USE_HERMES=1" >> $BASH_ENV - run: name: Set HERMES_ENGINE_TARBALL_PATH command: | echo "export HERMES_ENGINE_TARBALL_PATH=$(ls -AU $HERMES_WS_DIR/hermes-runtime-darwin/hermes-runtime-darwin-*.tar.gz | head -1)" >> $BASH_ENV - run: name: Create iOS template project command: | REPO_ROOT=$(pwd) PACKAGE=$(cat build/react-native-package-version) PATH_TO_PACKAGE="$REPO_ROOT/build/$PACKAGE" node ./scripts/set-rn-template-version.js "file:$PATH_TO_PACKAGE" mkdir -p ~/tmp cd ~/tmp node "$REPO_ROOT/cli.js" init "$PROJECT_NAME" --template "$REPO_ROOT" --verbose - run: name: Build template project command: | xcodebuild build \ -workspace ~/tmp/$PROJECT_NAME/ios/$PROJECT_NAME.xcworkspace \ -scheme $PROJECT_NAME \ -sdk iphonesimulator # ------------------------- # JOBS: Test iOS RNTester # ------------------------- test_ios_rntester: executor: reactnativeios steps: - checkout_code_with_cache - run_yarn # The macOS machine can run out of storage if Hermes is enabled and built from source. # Since this job does not use the iOS Simulator, deleting it provides a quick way to # free up space. - run: name: Delete iOS Simulators background: true command: sudo rm -rf /Library/Developer/CoreSimulator/Profiles/Runtimes/ - run: name: Set USE_HERMES=1 command: echo "export USE_HERMES=1" >> $BASH_ENV - run: name: Set BUILD_HERMES_SOURCE=1 command: echo "export BUILD_HERMES_SOURCE=1" >> $BASH_ENV - brew_install: package: cmake - with_hermes_sdk_cache_span: steps: - run: name: Install CocoaPods dependencies command: | rm -rf packages/rn-tester/Pods cd packages/rn-tester && bundle exec pod install - run: name: Build RNTester command: | xcodebuild build \ -workspace packages/rn-tester/RNTesterPods.xcworkspace \ -scheme RNTester \ -sdk iphonesimulator # ------------------------- # JOBS: Windows # ------------------------- test_windows: executor: name: win/default parameters: run_disabled_tests: type: boolean default: false environment: - ANDROID_HOME: "C:\\Android\\android-sdk" - ANDROID_NDK: "C:\\Android\\android-sdk\\ndk\\20.1.5948944" - ANDROID_BUILD_VERSION: 31 - ANDROID_TOOLS_VERSION: 31.0.0 - GRADLE_OPTS: -Dorg.gradle.daemon=false steps: - checkout_code_with_cache - run: name: Install Node # Note: Version set separately for non-Windows builds, see above. command: | nvm install 16 nvm use 16 # Setup Dependencies - run: name: Install Yarn command: choco install yarn - run: name: Display Environment info command: npx envinfo@latest - restore_cache: keys: - *windows_yarn_cache_key - run: name: "Yarn: Install Dependencies" command: yarn install --frozen-lockfile --non-interactive - save_cache: key: *windows_yarn_cache_key paths: - C:\Users\circleci\AppData\Local\Yarn # Try to install the SDK up to 3 times, since network flakiness can cause install failures # Using a timeout of 9 mins, as circle ci will timeout if there is no output for 10 mins - run: name: Install Android SDK Tools command: choco install android-sdk --timeout 540; if (!$?) { choco install android-sdk --timeout 540 --force --forcedependencies}; if (!$?) { choco install android-sdk --force --forcedependencies} - run: name: Setup Android SDKs command: | sdkmanager --licenses sdkmanager "system-images;android-21;google_apis;armeabi-v7a" sdkmanager "platforms;android-%ANDROID_BUILD_VERSION%" sdkmanager "build-tools;%ANDROID_TOOLS_VERSION%" sdkmanager "add-ons;addon-google_apis-google-23" sdkmanager "extras;android;m2repository" # ------------------------- # Run Tests - run: name: "Flow: Check Android" command: yarn flow-check-android - run: name: "Flow: Check iOS" command: yarn flow-check-ios - run: name: "Run Tests: JavaScript Tests" command: yarn test # Optionally, run disabled tests - when: condition: << parameters.run_disabled_tests >> steps: - run: echo "Failing tests may be moved here temporarily." - run: name: Android Build command: ./gradlew.bat packages:rn-tester:android:app:assembleRelease # ------------------------- # JOBS: Coverage # ------------------------- # Collect JavaScript test coverage js_coverage: executor: nodelts environment: - CI_BRANCH: $CIRCLE_BRANCH - CI_PULL_REQUEST: $CIRCLE_PULL_REQUEST - CI_BUILD_NUMBER: $CIRCLE_BUILD_NUM - CI_BUILD_URL: $CIRCLE_BUILD_URL steps: - checkout - setup_artifacts - run_yarn - run: name: Collect test coverage information command: | scripts/circleci/exec_swallow_error.sh yarn test --coverage --maxWorkers=2 if [[ -e ./coverage/lcov.info ]]; then cat ./coverage/lcov.info | scripts/circleci/exec_swallow_error.sh ./node_modules/.bin/coveralls fi - store_artifacts: path: ~/react-native/coverage/ # ------------------------- # JOBS: Build hermesc # ------------------------- prepare_hermes_workspace: docker: - image: debian:bullseye environment: - HERMES_WS_DIR: *hermes_workspace_root - HERMES_VERSION_FILE: "sdks/.hermesversion" steps: - run: name: Install dependencies command: | apt update apt install -y wget git curl curl -sL https://deb.nodesource.com/setup_16.x | bash - apt install -y nodejs npm install --global yarn - checkout - run_yarn - run: name: Set up Hermes workspace and caching command: | mkdir -p "/tmp/hermes" "/tmp/hermes/download" "/tmp/hermes/hermes" if [ -f "$HERMES_VERSION_FILE" ]; then cat $HERMES_VERSION_FILE > /tmp/hermes/hermesversion else HERMES_TAG_SHA=$(git ls-remote https://github.com/facebook/hermes main | cut -f 1 | tr -d '[:space:]') echo $HERMES_TAG_SHA > /tmp/hermes/hermesversion fi - restore_cache: key: *hermes_cache_key - run: name: Download Hermes tarball command: | node scripts/hermes/prepare-hermes-for-build $CIRCLE_PULL_REQUEST cp sdks/download/* $HERMES_WS_DIR/download/. cp -r sdks/hermes/* $HERMES_WS_DIR/hermes/. - save_cache: key: *hermes_cache_key paths: - /tmp/hermes/download/ - /tmp/hermes/hermes/ - persist_to_workspace: root: *hermes_workspace_root paths: - download - hermes - hermesversion build_hermesc_linux: docker: - image: debian:bullseye resource_class: "xlarge" working_directory: /root steps: - run: name: Install dependencies command: | apt update apt install -y git openssh-client cmake build-essential \ libreadline-dev libicu-dev zip python3 - *attach_hermes_workspace - restore_cache: key: *hermes_cache_key - run: name: Set up workspace command: | mkdir -p /tmp/hermes/linux64-bin - run: name: Build HermesC for Linux command: | if [ -f /tmp/hermes/linux64-bin/hermesc ]; then echo 'Skipping; Clean "/tmp/hermes/linux64-bin" to rebuild.' else cd /tmp/hermes cmake -S hermes -B build -DHERMES_STATIC_LINK=ON -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=True -DCMAKE_CXX_FLAGS=-s -DCMAKE_C_FLAGS=-s \ -DCMAKE_EXE_LINKER_FLAGS="-Wl,--whole-archive -lpthread -Wl,--no-whole-archive" cmake --build build --target check-hermes -j 4 cp /tmp/hermes/build/bin/hermesc /tmp/hermes/linux64-bin/. fi - save_cache: key: *hermes_cache_key paths: - /tmp/hermes/linux64-bin/ - /tmp/hermes/hermes/destroot/ - store_artifacts: path: /tmp/hermes/linux64-bin/ - persist_to_workspace: root: /tmp/hermes/ paths: - linux64-bin build_hermes_macos: executor: reactnativeios environment: - HERMES_WS_DIR: *hermes_workspace_root steps: - checkout_code_with_cache - *attach_hermes_workspace - restore_cache: key: *hermes_cache_key - run: name: Set up workspace command: | mkdir -p /tmp/hermes/osx-bin mkdir -p ~/react-native/sdks/hermes cp -r $HERMES_WS_DIR/hermes/* ~/react-native/sdks/hermes/. - run: name: Install dependencies command: | brew install cmake - run: name: Build the Hermes iOS frameworks command: | cd ~/react-native/sdks/hermes ./utils/build-ios-framework.sh - run: name: Build the Hermes Mac frameworks command: | cd ~/react-native/sdks/hermes ./utils/build-mac-framework.sh cp build_macosx/bin/hermesc /tmp/hermes/osx-bin/. - run: name: Package the Hermes Apple frameworks command: | cd ~/react-native/sdks/hermes . ./utils/build-apple-framework.sh mkdir -p /tmp/cocoapods-package-root/destroot mkdir -p /tmp/hermes/output cp -R ./destroot /tmp/cocoapods-package-root cp LICENSE /tmp/cocoapods-package-root tar -C /tmp/cocoapods-package-root/ -czvf /tmp/hermes/output/hermes-runtime-darwin-v$(get_release_version).tar.gz . mkdir -p /tmp/hermes/hermes-runtime-darwin cp /tmp/hermes/output/hermes-runtime-darwin-v$(get_release_version).tar.gz /tmp/hermes/hermes-runtime-darwin/. - save_cache: key: *hermes_cache_key paths: - ~/react-native/hermes/build_host_hermesc - ~/react-native/hermes/build_iphoneos - ~/react-native/hermes/build_catalyst - ~/react-native/hermes/build_iphonesimulator - ~/react-native/hermes/build_macosx - ~/react-native/hermes/destroot - store_artifacts: path: /tmp/hermes/hermes-runtime-darwin/ - store_artifacts: path: /tmp/hermes/osx-bin/ - persist_to_workspace: root: /tmp/hermes/ paths: - hermes-runtime-darwin - osx-bin build_hermesc_windows: executor: name: win/default shell: powershell.exe environment: - HERMES_WS_DIR: 'C:\tmp\hermes' - ICU_URL: "https://github.com/unicode-org/icu/releases/download/release-64-2/icu4c-64_2-Win64-MSVC2017.zip" - MSBUILD_DIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin' - CMAKE_DIR: 'C:\Program Files\CMake\bin' steps: - *attach_hermes_workspace - restore_cache: key: *hermes_windows_cache_key - run: name: Set up workspace command: | New-Item -ItemType Directory $Env:HERMES_WS_DIR New-Item -ItemType Directory $Env:HERMES_WS_DIR\icu New-Item -ItemType Directory $Env:HERMES_WS_DIR\deps New-Item -ItemType Directory $Env:HERMES_WS_DIR\win64-bin New-Item -ItemType SymbolicLink -Target tmp\hermes\hermes -Path $Env:HERMES_WS_DIR -Name hermes - run: name: Build HermesC for Windows command: | if (-not(Test-Path -Path $Env:HERMES_WS_DIR\win64-bin\hermesc.exe)) { choco install --no-progress cmake --version 3.14.7 if (-not $?) { throw "Failed to install CMake" } choco install --no-progress python3 if (-not $?) { throw "Failed to install Python" } cd $Env:HERMES_WS_DIR\icu # If Invoke-WebRequest shows a progress bar, it will fail with # Win32 internal error "Access is denied" 0x5 occurred [...] $progressPreference = 'silentlyContinue' Invoke-WebRequest -Uri "$Env:ICU_URL" -OutFile "icu.zip" Expand-Archive -Path "icu.zip" -DestinationPath "." cd $Env:HERMES_WS_DIR Copy-Item -Path "icu\bin64\icu*.dll" -Destination "deps" # Include MSVC++ 2015 redistributables Copy-Item -Path "c:\windows\system32\msvcp140.dll" -Destination "deps" Copy-Item -Path "c:\windows\system32\vcruntime140.dll" -Destination "deps" Copy-Item -Path "c:\windows\system32\vcruntime140_1.dll" -Destination "deps" $Env:PATH += ";$Env:CMAKE_DIR;$Env:MSBUILD_DIR" $Env:ICU_ROOT = "$Env:HERMES_WS_DIR\icu" cmake -S hermes -B build_release -G 'Visual Studio 16 2019' -Ax64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=True -DHERMES_ENABLE_WIN10_ICU_FALLBACK=OFF if (-not $?) { throw "Failed to configure Hermes" } cd build_release cmake --build . --target hermesc --config Release if (-not $?) { throw "Failed to build Hermes" } cd $Env:HERMES_WS_DIR Copy-Item -Path "build_release\bin\Release\hermesc.exe" -Destination "win64-bin" # Include Windows runtime dependencies Copy-Item -Path "deps\*" -Destination "win64-bin" } else { Write-Host "Skipping; Clean c:\tmp\hermes\win64-bin to rebuild." } - save_cache: key: *hermes_windows_cache_key paths: - C:\tmp\hermes\win64-bin\ - C:\tmp\hermes\hermes\icu\ - C:\tmp\hermes\hermes\deps\ - C:\tmp\hermes\hermes\build_release\ - store_artifacts: path: C:\tmp\hermes\win64-bin\ - persist_to_workspace: root: C:\tmp\hermes\ paths: - win64-bin # ------------------------- # JOBS: Releases # ------------------------- prepare_package_for_release: parameters: version: type: string latest: type: boolean default: false executor: reactnativeios steps: - checkout_code_with_cache - run_yarn - add_ssh_keys: fingerprints: - "1c:98:e0:3a:52:79:95:29:12:cd:b4:87:5b:41:e2:bb" - run: name: "Set new react-native version and commit changes" command: | node ./scripts/prepare-package-for-release.js -v << parameters.version >> -l << parameters.latest >> build_npm_package: parameters: publish_npm_args: type: string default: --dry-run executor: reactnativeandroid environment: - HERMES_WS_DIR: *hermes_workspace_root steps: - run: name: Add github.com to SSH known hosts command: | mkdir -p ~/.ssh echo '|1|If6MU203eXTaaWL678YEfWkVMrw=|kqLeIAyTy8pzpj8x8Ae4Fr8Mtlc= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==' >> ~/.ssh/known_hosts - checkout - *attach_hermes_workspace - run: name: Copy HermesC binaries command: | mkdir -p ./sdks/hermesc ./sdks/hermesc/osx-bin ./sdks/hermesc/win64-bin ./sdks/hermesc/linux64-bin cp -r $HERMES_WS_DIR/osx-bin/* ./sdks/hermesc/osx-bin/. cp -r $HERMES_WS_DIR/win64-bin/* ./sdks/hermesc/win64-bin/. cp -r $HERMES_WS_DIR/linux64-bin/* ./sdks/hermesc/linux64-bin/. - run_yarn - install_buck_tooling - download_buck_dependencies - download_gradle_dependencies # START: Stables and nightlies # This conditional step sets up the necessary credentials for publishing react-native to npm, # and for interacting with GitHub as the react-native-bot account. Important: these steps # should not be allowed to run on commits from pull requests. - when: condition: or: - equal: [ --release, << parameters.publish_npm_args >> ] - equal: [ --nightly, << parameters.publish_npm_args >> ] steps: - run: echo "//registry.npmjs.org/:_authToken=${CIRCLE_NPM_TOKEN}" > ~/.npmrc - run: | git config --global user.email "react-native-bot@users.noreply.github.com" git config --global user.name "npm Deployment Script" echo "machine github.com login react-native-bot password $GITHUB_TOKEN" > ~/.netrc # END: Stables and nightlies - run: node ./scripts/publish-npm.js << parameters.publish_npm_args >> - run: name: Zip Hermes Native Symbols command: zip -r /tmp/hermes-native-symbols.zip ~/react-native/ReactAndroid/hermes-engine/build/intermediates/cmake/ - store_artifacts: path: /tmp/hermes-native-symbols.zip # START: Commitlies # Provide a react-native package for this commit as a Circle CI release artifact. - when: condition: equal: [ --dry-run, << parameters.publish_npm_args >> ] steps: - run: name: Build release package as a job artifact command: | mkdir -p build FILENAME=$(npm pack) mv $FILENAME build/ echo $FILENAME > build/react-native-package-version - store_artifacts: path: ~/react-native/build/ destination: build - persist_to_workspace: root: . paths: - build/* # END: Commitlies # START: Commits from pull requests # When building commits from pull requests, leave a comment on the PR with a link to build artifacts - when: condition: matches: { pattern: '^pull\/.*$', value: << pipeline.git.branch >> } steps: - install_github_bot_deps - run: name: Post link to PR build artifacts (pull-bot) command: GITHUB_TOKEN="$PUBLIC_PULLBOT_GITHUB_TOKEN_A""$PUBLIC_PULLBOT_GITHUB_TOKEN_B" scripts/circleci/post-artifacts-link.sh || true # END: Commits from pull requests # START: Stable releases - when: condition: equal: [ --release, << parameters.publish_npm_args >> ] steps: - run: name: Update rn-diff-purge to generate upgrade-support diff command: | curl -X POST https://api.github.com/repos/react-native-community/rn-diff-purge/dispatches \ -H "Accept: application/vnd.github.v3+json" \ -u "$PAT_USERNAME:$PAT_TOKEN" \ -d "{\"event_type\": \"publish\", \"client_payload\": { \"version\": \"${CIRCLE_TAG:1}\" }}" - run: name: Install dependencies command: apt update && apt install -y jq jo - run: name: Create draft GitHub Release and upload Hermes binaries command: | ARTIFACTS=("$HERMES_WS_DIR/hermes-runtime-darwin/hermes-runtime-darwin-$CIRCLE_TAG.tar.gz") ./scripts/circleci/create_github_release.sh $CIRCLE_TAG $CIRCLE_PROJECT_USERNAME $CIRCLE_PROJECT_REPONAME $GITHUB_TOKEN "${ARTIFACTS[@]}" # END: Stable releases # ------------------------- # JOBS: Nightly # ------------------------- nightly_job: machine: image: ubuntu-2004:202010-01 steps: - run: name: Nightly command: | echo "Nightly build run" # ------------------------- # PIPELINE PARAMETERS # ------------------------- parameters: run_package_release_workflow_only: default: false type: boolean release_latest: default: false type: boolean release_version: default: "9999" type: string # ------------------------- # WORK FLOWS # # When creating a new workflow, make sure to include condition `unless: << pipeline.parameters.run_package_release_workflow_only >>` # It's setup this way so we can trigger a release via a POST # See limitations: https://support.circleci.com/hc/en-us/articles/360050351292-How-to-trigger-a-workflow-via-CircleCI-API-v2 # ------------------------- workflows: version: 2 tests: unless: << pipeline.parameters.run_package_release_workflow_only >> jobs: - prepare_hermes_workspace - build_hermesc_linux: requires: - prepare_hermes_workspace - build_hermes_macos: requires: - prepare_hermes_workspace - build_hermesc_windows: requires: - prepare_hermes_workspace - build_npm_package: # Build a release package on every untagged commit, but do not publish to npm. publish_npm_args: --dry-run requires: - build_hermesc_linux - build_hermes_macos - build_hermesc_windows - test_js: run_disabled_tests: false - test_android: run_disabled_tests: false - test_android_template: requires: - build_npm_package - test_ios_template: requires: - build_npm_package - test_ios_rntester - test_ios: run_unit_tests: true # DISABLED: USE_FRAMEWORKS=1 not supported by Flipper # - test_ios: # name: test_ios_frameworks # use_frameworks: true # run_unit_tests: true # requires: # - build_ios_frameworks - test_js: name: test_js_prev_lts executor: nodeprevlts - test_windows: run_disabled_tests: false # This workflow should only be triggered by release script package_release: when: << pipeline.parameters.run_package_release_workflow_only >> jobs: # This job will trigger publish_release workflow - prepare_package_for_release: name: prepare_package_for_release version: << pipeline.parameters.release_version >> latest : << pipeline.parameters.release_latest >> publish_release: unless: << pipeline.parameters.run_package_release_workflow_only >> jobs: - prepare_hermes_workspace: filters: *only_release_tags - build_hermesc_linux: filters: *only_release_tags requires: - prepare_hermes_workspace - build_hermes_macos: filters: *only_release_tags requires: - prepare_hermes_workspace - build_hermesc_windows: filters: *only_release_tags requires: - prepare_hermes_workspace # This job will trigger when a version tag is pushed (by package_release) - build_npm_package: name: build_and_publish_npm_package context: react-native-bot publish_npm_args: --release filters: *only_release_tags requires: - build_hermesc_linux - build_hermes_macos - build_hermesc_windows analysis: unless: << pipeline.parameters.run_package_release_workflow_only >> jobs: # Run lints on every commit - analyze_code # Run code checks on PRs - analyze_pr # Gather coverage - js_coverage nightly: unless: << pipeline.parameters.run_package_release_workflow_only >> triggers: - schedule: cron: "0 20 * * *" filters: branches: only: - main jobs: - nightly_job - prepare_hermes_workspace - build_hermesc_linux: requires: - prepare_hermes_workspace - build_hermes_macos: requires: - prepare_hermes_workspace - build_hermesc_windows: requires: - prepare_hermes_workspace - build_npm_package: publish_npm_args: --nightly requires: - build_hermesc_linux - build_hermes_macos - build_hermesc_windows