react-native/.circleci/config.yml
Nicola Corti 4994b8b5de Setup a top level buildAll Gradle task (#33838)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/33838

The idea behind this diff is to set a top level `buildAll` task that will be responsible
of invoking all the tasks we want to verify both in the internal and in the external CI.

This should ideally remove the breakages of the External CI happening from internal changes.

Changelog:
[Internal] [Changed] - Setup a top level buildAll Gradle task

Reviewed By: cipolleschi

Differential Revision: D36376384

fbshipit-source-id: d810b59577340628bb49562bfedf28440bd0f792
2022-05-16 09:27:54 -07:00

1402 lines
46 KiB
YAML

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
# -------------------------
# 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" }}}
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/.hermesversion" }}
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: cimg/node:16.14
resource_class: "xlarge"
nodeprevlts:
<<: *defaults
docker:
- image: cimg/node:14.19
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 "13.3.0"
resource_class: macos.x86.medium.gen2
# -------------------------
# COMMANDS
# -------------------------
commands:
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: ./scripts/circleci/gradle_download_deps.sh
- 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_VERSION_FILE="sdks/.hermesversion"
if [ ! -f "$HERMES_VERSION_FILE" ]; then
git ls-remote https://github.com/facebook/hermes main | cut -f 1 > $HERMES_VERSION_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
- run:
name: Analyze Pull Request (pull-bot)
command: |
cd bots
DANGER_GITHUB_API_TOKEN="$PUBLIC_PULLBOT_GITHUB_TOKEN_A""$PUBLIC_PULLBOT_GITHUB_TOKEN_B" yarn danger ci --use-github-checks
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: Build iOS
# -------------------------
build_ios:
executor: reactnativeios
parameters:
use_frameworks:
type: boolean
default: false
steps:
- checkout
- setup_ruby
- run_yarn
- run: |
cd packages/rn-tester
bundle check || bundle install
- run:
name: Configure Environment Variables
command: |
echo 'export PATH=/usr/local/opt/node@16/bin:$PATH' >> $BASH_ENV
source $BASH_ENV
- 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
- brew_install:
package: cmake
- 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
# -------------------------
# 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
- 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"
steps:
- checkout
- run_yarn
- attach_workspace:
at: .
- 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"
- 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
- 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
- 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
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_hermesc_macos:
executor: reactnativeios
environment:
- HERMES_WS_DIR: *hermes_workspace_root
steps:
- checkout
- *attach_hermes_workspace
- restore_cache:
key: *hermes_cache_key
- run:
name: Set up workspace
command: |
mkdir -p /tmp/hermes/osx-bin
cp ~/react-native/sdks/hermes-engine/utils/* "$HERMES_WS_DIR/hermes/utils/."
- run:
name: Install dependencies
command: |
brew install cmake
- run:
name: Build HermesC for macOS
command: |
if [ -f /tmp/hermes/osx-bin/hermesc ]; then
echo 'Skipping; Clean "/tmp/hermes/osx-bin" to rebuild.'
else
cd "$HERMES_WS_DIR/hermes"
./utils/build-mac-framework.sh
cp build_macosx/bin/hermesc /tmp/hermes/osx-bin/.
fi
- save_cache:
key: *hermes_cache_key
paths:
- /tmp/hermes/osx-bin/
- /tmp/hermes/hermes/destroot/
- /tmp/hermes/hermes/build_host_hermesc/
- /tmp/hermes/hermes/build_macosx/
- store_artifacts:
path: /tmp/hermes/osx-bin/
- persist_to_workspace:
root: /tmp/hermes/
paths:
- 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
- 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}\" }}"
# 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_hermesc_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_hermesc_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
- build_ios
- test_ios:
run_unit_tests: true
requires:
- build_ios
# DISABLED: USE_FRAMEWORKS=1 not supported by Flipper
# - build_ios:
# name: build_ios_frameworks
# use_frameworks: true
# - 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_hermesc_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_hermesc_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 from forks
- analyze_pr:
filters:
branches:
only: /^pull\/.*$/
# 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_hermesc_macos:
requires:
- prepare_hermes_workspace
- build_hermesc_windows:
requires:
- prepare_hermes_workspace
- build_npm_package:
publish_npm_args: --nightly
requires:
- build_hermesc_linux
- build_hermesc_macos
- build_hermesc_windows