Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions e2e/BITRISE.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,17 @@ The non-secret E2E defaults are defined in `e2e/bitrise.yml` under `app.envs`. D
| `E2E_BROWSERSTACK_TIMEOUT_SECONDS` | `1800` | BrowserStack build timeout. |
| `E2E_BROWSERSTACK_POLL_SECONDS` | `30` | BrowserStack status polling interval. |
| `E2E_IOS_EXPORT_METHOD` | `development` | Export method for the React Native iOS IPA. |
| `E2E_ANDROID_COMMAND_TIMEOUT_SECONDS` | `1800` | Per-command timeout for React Native Android artifact commands. |
| `E2E_PACKAGE_COMMAND_TIMEOUT_SECONDS` | `300` | Per-command timeout for package-suite matrix and suite commands. |
| `E2E_RUBY_INSTALL_TIMEOUT_SECONDS` | `1800` | Timeout for installing the exact repository Ruby version from `.ruby-version`. |

Secrets still need to be configured in Bitrise.io.

| Secret | Purpose |
|---|---|
| `STOREFRONT_DOMAIN` | Required by `scripts/setup_storefront_env` for sample app builds. |
| `STOREFRONT_ACCESS_TOKEN` | Required by `scripts/setup_storefront_env` for sample app builds. |

## Future secrets

Do not add BrowserStack credentials until the BrowserStack integration phase.
Expand All @@ -85,6 +91,10 @@ React Native iOS IPA generation is added in a later phase and will require Bitri

## Caching

React Native Android E2E builds use the released native Maven artifact versions declared by the React Native sample and module configuration. Do not set local native SDK override flags for these builds.

React Native Android E2E builds run on `linux-docker-android-22.04` with `g2.linux.large`. Their cache keys are prefixed with `rn-android-linux-` so Linux caches cannot restore macOS-built dependencies.

The pipeline uses Bitrise cache steps for key-based pnpm/CocoaPods/Gradle cache paths.

Do not add `activate-build-cache-for-xcode` or `activate-build-cache-for-gradle`; the Bitrise Build Cache add-on is disabled for Shopify Bitrise apps.
Expand Down
34 changes: 28 additions & 6 deletions e2e/bitrise.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ app:
- E2E_BROWSERSTACK_TIMEOUT_SECONDS: "1800"
- E2E_BROWSERSTACK_POLL_SECONDS: "30"
- E2E_IOS_EXPORT_METHOD: development
- E2E_ANDROID_COMMAND_TIMEOUT_SECONDS: "1800"
- E2E_PACKAGE_COMMAND_TIMEOUT_SECONDS: "300"
- E2E_RUBY_INSTALL_TIMEOUT_SECONDS: "1800"

Expand Down Expand Up @@ -100,28 +101,49 @@ workflows:
platforms/react-native/sample/ios/Pods

e2e-build-react-native-android:
meta:
bitrise.io:
stack: linux-docker-android-22.04
machine_type_id: g2.linux.large
steps:
- git-clone@8: {}
- restore-cache@3:
inputs:
- key: |-
rn-android-{{ checksum "platforms/react-native/pnpm-lock.yaml" }}-{{ checksum "platforms/react-native/sample/android/**/*.gradle*" }}
rn-android-linux-{{ checksum "platforms/react-native/pnpm-lock.yaml" }}-{{ checksum "platforms/react-native/sample/android/**/*.gradle*" }}
- script@1:
title: Create React Native Android artifact placeholder
title: Build React Native Android APK artifact
inputs:
- content: |-
set -euo pipefail
mkdir -p "$BITRISE_DEPLOY_DIR/e2e"
echo "Phase 2 placeholder for React Native Android APK" > "$BITRISE_DEPLOY_DIR/e2e/react-native-android.apk"
envman add --key E2E_REACT_NATIVE_ANDROID_APP_PATH --value "$BITRISE_DEPLOY_DIR/e2e/react-native-android.apk"
source e2e/scripts/bitrise_ci_helpers
e2e_log "Enabling Corepack"
corepack enable
e2e_log "Checking storefront configuration secrets"
: "${STOREFRONT_DOMAIN:?STOREFRONT_DOMAIN is required. Check https://app.bitrise.io/app/f51f9054-053e-40f1-81e9-ae727567ae76/workflow_editor#!/secrets and enable Expose for pull requests.}"
: "${STOREFRONT_ACCESS_TOKEN:?STOREFRONT_ACCESS_TOKEN is required. Check https://app.bitrise.io/app/f51f9054-053e-40f1-81e9-ae727567ae76/workflow_editor#!/secrets and enable Expose for pull requests.}"
e2e_log "Configuring storefront environment"
./scripts/setup_storefront_env --skip-optional-prompts
e2e_log "Installing React Native dependencies"
cd platforms/react-native
e2e_run_with_timeout "${E2E_ANDROID_COMMAND_TIMEOUT_SECONDS:-1800}" pnpm install --frozen-lockfile
e2e_log "Building React Native module"
e2e_run_with_timeout "${E2E_ANDROID_COMMAND_TIMEOUT_SECONDS:-1800}" pnpm module build
e2e_log "Building Android E2E APK"
cd sample/android
e2e_run_with_timeout "${E2E_ANDROID_COMMAND_TIMEOUT_SECONDS:-1800}" ./gradlew assembleE2e --no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a
android_apk="$PWD/app/build/outputs/apk/e2e/app-e2e.apk"
test -f "$android_apk"
e2e_log "Publishing Android APK path"
envman add --key E2E_REACT_NATIVE_ANDROID_APP_PATH --value "$android_apk"
- deploy-to-bitrise-io@2:
inputs:
- pipeline_intermediate_files: |-
$E2E_REACT_NATIVE_ANDROID_APP_PATH:E2E_REACT_NATIVE_ANDROID_APP_PATH
- save-cache@1:
inputs:
- key: |-
rn-android-{{ checksum "platforms/react-native/pnpm-lock.yaml" }}-{{ checksum "platforms/react-native/sample/android/**/*.gradle*" }}
rn-android-linux-{{ checksum "platforms/react-native/pnpm-lock.yaml" }}-{{ checksum "platforms/react-native/sample/android/**/*.gradle*" }}
- paths: |-
platforms/react-native/node_modules
~/.gradle/caches
Expand Down
75 changes: 75 additions & 0 deletions e2e/test/bitrise_pipeline_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,72 @@ def test_dev_up_installs_bitrise_cli
assert_includes packages, "bitrise"
end

def test_react_native_android_workflow_uses_linux_resources
workflow = load_bitrise_config.fetch("workflows").fetch("e2e-build-react-native-android")
meta = workflow.fetch("meta").fetch("bitrise.io")
cache_keys = workflow.fetch("steps").flat_map { |step| step.values.first.fetch("inputs", []) }.filter_map { |input| input["key"] }

assert_equal "linux-docker-android-22.04", meta.fetch("stack")
assert_equal "g2.linux.large", meta.fetch("machine_type_id")
assert cache_keys.all? { |key| key.start_with?("rn-android-linux-") }
end

def test_react_native_android_sample_defines_metro_free_e2e_build_type
gradle = File.read("platforms/react-native/sample/android/app/build.gradle")

assert_includes gradle, "e2e {"
assert_includes gradle, "initWith release"
assert_includes gradle, "matchingFallbacks = ['release']"
assert_includes gradle, "signingConfig signingConfigs.debug"
assert_includes gradle, "minifyEnabled false"
end

def test_react_native_android_app_cmake_depends_on_library_codegen
gradle = File.read("platforms/react-native/sample/android/app/build.gradle")

assert_includes gradle, "gradle.projectsEvaluated"
assert_includes gradle, "rootProject.subprojects"
assert_includes gradle, 'tasks.findByName("generateCodegenArtifactsFromSchema")'
assert_includes gradle, 'tasks.matching { task -> task.name.startsWith("configureCMake") }'
assert_includes gradle, "task.dependsOn(codegenTasks)"
end

def test_react_native_android_workflow_builds_real_apk_artifact
script = workflow_script("e2e-build-react-native-android")

assert_equal "1800", app_env_values.fetch("E2E_ANDROID_COMMAND_TIMEOUT_SECONDS")
assert_includes script, 'e2e_log "Checking storefront configuration secrets"'
assert_includes script, 'STOREFRONT_DOMAIN is required'
assert_includes script, 'STOREFRONT_ACCESS_TOKEN is required'
assert_includes script, 'workflow_editor#!/secrets'
assert_includes script, 'Expose for pull requests'
assert_includes script, 'e2e_log "Configuring storefront environment"'
assert_includes script, 'e2e_log "Installing React Native dependencies"'
assert_includes script, 'e2e_log "Building React Native module"'
assert_includes script, 'e2e_log "Building Android E2E APK"'
assert_includes script, 'e2e_log "Publishing Android APK path"'
assert_includes script, "corepack enable"
assert_includes script, "cd platforms/react-native"
assert_command_order script, "cd platforms/react-native", "pnpm install --frozen-lockfile"
assert_includes script, "pnpm install --frozen-lockfile"
assert_includes script, "./scripts/setup_storefront_env --skip-optional-prompts"
assert_includes script, 'e2e_run_with_timeout "${E2E_ANDROID_COMMAND_TIMEOUT_SECONDS:-1800}" pnpm install --frozen-lockfile'
assert_includes script, 'e2e_run_with_timeout "${E2E_ANDROID_COMMAND_TIMEOUT_SECONDS:-1800}" pnpm module build'
assert_includes script, 'e2e_run_with_timeout "${E2E_ANDROID_COMMAND_TIMEOUT_SECONDS:-1800}" ./gradlew assembleE2e --no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a'
assert_includes script, "app/build/outputs/apk/e2e/app-e2e.apk"
refute_includes script, "assembleDebug"
refute_includes script, "app-debug.apk"
refute_includes script, "Phase 2 placeholder for React Native Android APK"
end

def test_react_native_android_workflow_does_not_use_local_native_sdk_overrides
script = workflow_script("e2e-build-react-native-android")

refute_includes script, "USE_LOCAL_SDK"
refute_includes script, "publish_android_snapshot"
refute_includes script, "--local"
end

def test_bitrise_setup_docs_exist
assert File.exist?("e2e/BITRISE.md")
end
Expand Down Expand Up @@ -205,4 +271,13 @@ def assert_workflow_has_step(config, workflow, step_name)
def cache_input(step, input_name)
step.fetch("inputs", []).find { |input| input.key?(input_name) }&.fetch(input_name).to_s
end

def assert_command_order(script, first_command, second_command)
first_index = script.index(first_command)
second_index = script.index(second_command)

assert first_index, "expected script to include #{first_command}"
assert second_index, "expected script to include #{second_command}"
assert_operator first_index, :<, second_index, "expected #{first_command} to run before #{second_command}"
end
end
18 changes: 18 additions & 0 deletions platforms/react-native/sample/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ android {
minifyEnabled true
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
e2e {
initWith release
matchingFallbacks = ['release']
signingConfig signingConfigs.debug
minifyEnabled false
}
}

testOptions {
Expand All @@ -153,6 +159,18 @@ android {
}
}

gradle.projectsEvaluated {
if (project.findProperty("newArchEnabled").toString() == "true") {
def codegenTasks = rootProject.subprojects.collect { subproject ->
subproject.tasks.findByName("generateCodegenArtifactsFromSchema")
}.findAll { task -> task != null }

tasks.matching { task -> task.name.startsWith("configureCMake") }.configureEach { task ->
task.dependsOn(codegenTasks)
}
}
}

def checkoutKitPackageJsonFile = rootProject.file("../../modules/@shopify/checkout-kit-react-native/package.json")
def checkoutKitPackageJson = new groovy.json.JsonSlurper().parse(checkoutKitPackageJsonFile)
def shopifySdkVersion = checkoutKitPackageJson.checkoutKit?.nativeSdkVersions?.android as String
Expand Down
Loading