diff --git a/.buildkite/react-native-pipeline.full.yml b/.buildkite/react-native-pipeline.full.yml index 69df54337..ce76b239b 100644 --- a/.buildkite/react-native-pipeline.full.yml +++ b/.buildkite/react-native-pipeline.full.yml @@ -66,6 +66,69 @@ steps: - exit_status: "*" limit: 1 + - label: ':android: Build RN {{matrix.reactnative}} native integration test fixture APK (Old Arch)' + key: "build-react-native-android-fixture-native-integration-old-arch-full" + timeout_in_minutes: 30 + agents: + queue: macos-14 + env: + JAVA_VERSION: "{{matrix.java}}" + NODE_VERSION: "18" + RN_VERSION: "{{matrix.reactnative}}" + NOTIFIER_VERSION: '8.0.0' + BUILD_ANDROID: "true" + NATIVE_INTEGRATION: "1" + artifact_paths: + - "test/react-native/features/fixtures/generated/native-integration/old-arch/**/reactnative.apk" + commands: + - bundle install + - ./bin/generate-react-native-fixture + matrix: + setup: + reactnative: + - "0.71" + - "0.72" + - "0.73" + - "0.74" + java: + - "17" + adjustments: + - with: + reactnative: "0.64" + java: "11" + retry: + automatic: + - exit_status: "*" + limit: 1 + + - label: ':android: Build RN {{matrix}} native integration test fixture APK (New Arch)' + key: "build-react-native-android-fixture-native-integration-new-arch-full" + timeout_in_minutes: 30 + agents: + queue: macos-14 + env: + JAVA_VERSION: "17" + NODE_VERSION: "18" + RN_VERSION: "{{matrix}}" + NOTIFIER_VERSION: '8.0.0' + RCT_NEW_ARCH_ENABLED: "true" + BUILD_ANDROID: "true" + NATIVE_INTEGRATION: "1" + artifact_paths: + - "test/react-native/features/fixtures/generated/native-integration/new-arch/**/reactnative.apk" + commands: + - bundle install + - ./bin/generate-react-native-fixture + matrix: + - "0.71" + - "0.72" + - "0.73" + - "0.74" + retry: + automatic: + - exit_status: "*" + limit: 1 + - label: ':mac: Build RN {{matrix}} test fixture ipa (Old Arch)' key: "build-react-native-ios-fixture-old-arch-full" timeout_in_minutes: 15 @@ -120,6 +183,62 @@ steps: - exit_status: "*" limit: 1 + - label: ':mac: Build RN {{matrix}} native integration test fixture ipa (Old Arch)' + key: "build-react-native-ios-fixture-native-integration-old-arch-full" + timeout_in_minutes: 30 + agents: + queue: "macos-14" + env: + NODE_VERSION: "18" + RN_VERSION: "{{matrix}}" + NOTIFIER_VERSION: '8.0.0' + BUILD_IOS: "true" + XCODE_VERSION: "15.3.0" + NATIVE_INTEGRATION: "1" + artifact_paths: + - "test/react-native/features/fixtures/generated/native-integration/old-arch/**/output/reactnative.ipa" + commands: + - bundle install + - ./bin/generate-react-native-fixture + matrix: + - "0.64" + - "0.71" + - "0.72" + - "0.73" + - "0.74" + retry: + automatic: + - exit_status: "*" + limit: 1 + + - label: ':mac: Build RN {{matrix}} native integration test fixture ipa (New Arch)' + key: "build-react-native-ios-fixture-native-integration-new-arch-full" + timeout_in_minutes: 30 + agents: + queue: "macos-14" + env: + NODE_VERSION: "18" + RN_VERSION: "{{matrix}}" + RCT_NEW_ARCH_ENABLED: "1" + NOTIFIER_VERSION: '8.0.0' + BUILD_IOS: "true" + XCODE_VERSION: "15.3.0" + NATIVE_INTEGRATION: "1" + artifact_paths: + - "test/react-native/features/fixtures/generated/native-integration/new-arch/**/output/reactnative.ipa" + commands: + - bundle install + - ./bin/generate-react-native-fixture + matrix: + - "0.71" + - "0.72" + - "0.73" + - "0.74" + retry: + automatic: + - exit_status: "*" + limit: 1 + # # End-to-end tests # @@ -200,6 +319,88 @@ steps: - "0.73" - "0.74" + - label: ":bitbar: :android: RN {{matrix}} native integration Android 12 (Old Arch) end-to-end tests" + depends_on: "build-react-native-android-fixture-native-integration-old-arch-full" + timeout_in_minutes: 20 + plugins: + artifacts#v1.9.0: + download: "test/react-native/features/fixtures/generated/native-integration/old-arch/{{matrix}}/reactnative.apk" + upload: ./test/react-native/maze_output/**/* + docker-compose#v4.7.0: + pull: react-native-maze-runner + run: react-native-maze-runner + service-ports: true + command: + - --app=/app/features/fixtures/generated/native-integration/old-arch/{{matrix}}/reactnative.apk + - --farm=bb + - --device=ANDROID_12 + - --a11y-locator + - --fail-fast + - --appium-version=1.22 + - --no-tunnel + - --aws-public-ip + - --tags=@native_integration + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^main|next$$" + api-token-env-name: "REACT_NATIVE_PERFORMANCE_BUILDKITE_ANALYTICS_TOKEN" + env: + NATIVE_INTEGRATION: "1" + retry: + manual: + permit_on_passed: true + concurrency: 25 + concurrency_group: "bitbar" + concurrency_method: eager + matrix: + - "0.64" + - "0.71" + - "0.72" + - "0.73" + - "0.74" + + - label: ":bitbar: :android: RN {{matrix}} native integration Android 12 (New Arch) end-to-end tests" + depends_on: "build-react-native-android-fixture-native-integration-new-arch-full" + timeout_in_minutes: 20 + plugins: + artifacts#v1.9.0: + download: "test/react-native/features/fixtures/generated/native-integration/new-arch/{{matrix}}/reactnative.apk" + upload: ./test/react-native/maze_output/**/* + docker-compose#v4.7.0: + pull: react-native-maze-runner + run: react-native-maze-runner + service-ports: true + command: + - --app=/app/features/fixtures/generated/native-integration/new-arch/{{matrix}}/reactnative.apk + - --farm=bb + - --device=ANDROID_12 + - --a11y-locator + - --fail-fast + - --appium-version=1.22 + - --no-tunnel + - --aws-public-ip + - --tags=@native_integration + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^main|next$$" + api-token-env-name: "REACT_NATIVE_PERFORMANCE_BUILDKITE_ANALYTICS_TOKEN" + env: + RCT_NEW_ARCH_ENABLED: "1" + NATIVE_INTEGRATION: "1" + retry: + manual: + permit_on_passed: true + concurrency: 25 + concurrency_group: "bitbar" + concurrency_method: eager + matrix: + - "0.71" + - "0.72" + - "0.73" + - "0.74" + - label: ":bitbar: :mac: RN {{matrix}} iOS 14 (Old Arch) end-to-end tests" depends_on: "build-react-native-ios-fixture-old-arch-full" timeout_in_minutes: 30 @@ -276,3 +477,85 @@ steps: - "0.72" - "0.73" - "0.74" + + - label: ":bitbar: :mac: RN {{matrix}} native integration iOS 14 (Old Arch) end-to-end tests" + depends_on: "build-react-native-ios-fixture-native-integration-old-arch-full" + timeout_in_minutes: 20 + plugins: + artifacts#v1.9.0: + download: "test/react-native/features/fixtures/generated/native-integration/old-arch/{{matrix}}/output/reactnative.ipa" + upload: ./test/react-native/maze_output/**/* + docker-compose#v4.12.0: + pull: react-native-maze-runner + run: react-native-maze-runner + service-ports: true + command: + - --app=/app/features/fixtures/generated/native-integration/old-arch/{{matrix}}/output/reactnative.ipa + - --farm=bb + - --device=IOS_14 + - --a11y-locator + - --fail-fast + - --appium-version=1.22 + - --no-tunnel + - --aws-public-ip + - --tags=@native_integration + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^main|next$$" + api-token-env-name: "REACT_NATIVE_PERFORMANCE_BUILDKITE_ANALYTICS_TOKEN" + env: + NATIVE_INTEGRATION: "1" + retry: + manual: + permit_on_passed: true + concurrency: 25 + concurrency_group: "bitbar" + concurrency_method: eager + matrix: + - "0.64" + - "0.71" + - "0.72" + - "0.73" + - "0.74" + + - label: ":bitbar: :mac: RN {{matrix}} native integration iOS 14 (New Arch) end-to-end tests" + depends_on: "build-react-native-ios-fixture-native-integration-new-arch-full" + timeout_in_minutes: 20 + plugins: + artifacts#v1.9.0: + download: "test/react-native/features/fixtures/generated/native-integration/new-arch/{{matrix}}/output/reactnative.ipa" + upload: ./test/react-native/maze_output/**/* + docker-compose#v4.12.0: + pull: react-native-maze-runner + run: react-native-maze-runner + service-ports: true + command: + - --app=/app/features/fixtures/generated/native-integration/new-arch/{{matrix}}/output/reactnative.ipa + - --farm=bb + - --device=IOS_14 + - --a11y-locator + - --fail-fast + - --appium-version=1.22 + - --no-tunnel + - --aws-public-ip + - --tags=@native_integration + test-collector#v1.10.2: + files: "reports/TEST-*.xml" + format: "junit" + branch: "^main|next$$" + api-token-env-name: "REACT_NATIVE_PERFORMANCE_BUILDKITE_ANALYTICS_TOKEN" + env: + RCT_NEW_ARCH_ENABLED: "1" + NATIVE_INTEGRATION: "1" + retry: + manual: + permit_on_passed: true + concurrency: 25 + concurrency_group: "bitbar" + concurrency_method: eager + matrix: + - "0.71" + - "0.72" + - "0.73" + - "0.74" diff --git a/bin/generate-react-native-fixture b/bin/generate-react-native-fixture index 51f0a8262..4090e4096 100755 --- a/bin/generate-react-native-fixture +++ b/bin/generate-react-native-fixture @@ -128,12 +128,6 @@ if (!process.env.SKIP_GENERATE_FIXTURE) { // generate Android Fixture if (process.env.BUILD_ANDROID === 'true' || process.env.BUILD_ANDROID === '1') { - // build and publish bugsnag-android-performance to local maven repo - // this is required even if we're not building the native integration fixture because - // @bugsnag/react-native-performance has a compileOnly dependency on bugsnag-android-performance - // TODO: remove this once changes have been released in bugsnag-android-performance - publishLocalAndroidPerformance() - execFileSync('./gradlew', ['assembleRelease'], { cwd: `${fixtureDir}/android`, stdio: 'inherit' }) fs.copyFileSync(`${fixtureDir}/android/app/build/outputs/apk/release/app-release.apk`, `${fixtureDir}/reactnative.apk`) } @@ -182,6 +176,14 @@ if (process.env.BUILD_IOS === 'true' || process.env.BUILD_IOS === '1') { /** Update fixture configuration to support React Native 0.64 */ function configureRN064Fixture(fixtureDir) { // Android + const gradlePath = resolve(fixtureDir, 'android/build.gradle') + let gradle = fs.readFileSync(gradlePath, 'utf8') + // add kotlinVersion = "1.4.10" to the buildscript ext block + const buildscriptExt = 'ext {' + const kotlinVersion = 'kotlinVersion = "1.4.10"' + gradle = gradle.replace(buildscriptExt, `${buildscriptExt}\n ${kotlinVersion}`) + fs.writeFileSync(gradlePath, gradle) + const moduleGradlePath = resolve(fixtureDir, 'android/app/build.gradle') let moduleGradle = fs.readFileSync(moduleGradlePath, 'utf8') @@ -213,18 +215,6 @@ function configureRN064Fixture(fixtureDir) { moduleGradle = moduleGradle.replace(currentReactConfig, updatedReactConfig).replace(flipperDependencies, '') fs.writeFileSync(moduleGradlePath, moduleGradle) - // iOS - const podfilePath = resolve(fixtureDir, 'ios/Podfile') - let podfile = fs.readFileSync(podfilePath, 'utf8') - - // disable flipper - podfile = podfile.replace("use_flipper!", "# use_flipper!") - - // bump the minimum iOS version to 11 - podfile = podfile.replace("platform :ios, '10.0'", "platform :ios, '11.0'") - - fs.writeFileSync(podfilePath, podfile) - // set --openssl-legacy-provider node option in pbxproj file const pbxprojPath = resolve(fixtureDir, 'ios/reactnative.xcodeproj/project.pbxproj') let pbxproj = fs.readFileSync(pbxprojPath, 'utf8') @@ -331,6 +321,11 @@ function replaceGeneratedFixtureFiles() { podfileContents = podfileContents.replace(/:flipper_configuration/, '# :flipper_configuration') } + // for RN versions < 0.73, bump the minimum iOS version to 13 (required for Cocoa Performance) + if (parseFloat(reactNativeVersion) < 0.73) { + podfileContents = podfileContents.replace(/platform\s*:ios,\s*(?:'[\d.]+'|min_ios_version_supported)/, "platform :ios, '13.0'") + } + fs.writeFileSync(`${fixtureDir}/ios/Podfile`, podfileContents) // pin xcodeproj version to < 1.26.0 @@ -343,34 +338,12 @@ function replaceGeneratedFixtureFiles() { } } -function publishLocalAndroidPerformance() { - // add bugsnag-android-performance as a git submodule - execSync(`git submodule add -b integration/react-native-integration https://github.com/bugsnag/bugsnag-android-performance`, { cwd: fixtureDir, stdio: 'inherit' }) - - // build and publish bugsnag-android-performance to maven local - execSync(`./gradlew -PVERSION_NAME=9.9.9 clean publishToMavenLocal`, { cwd: `${fixtureDir}/bugsnag-android-performance`, stdio: 'inherit' }) - - // add mavenLocal() to the repositories section in the android/build.gradle file - const buildGradlePath = resolve(fixtureDir, 'android/build.gradle') - let buildGradle = fs.readFileSync(buildGradlePath, 'utf8') - const repositoriesBlock = `allprojects { - repositories { - mavenLocal() - mavenCentral() - google() - } -}` - - buildGradle = `${repositoriesBlock}\n${buildGradle}` - fs.writeFileSync(buildGradlePath, buildGradle) -} - function installAndroidPerformance() { // declare dependency in the app/build.gradle file const appGradlePath = resolve(fixtureDir, 'android/app/build.gradle') let appGradle = fs.readFileSync(appGradlePath, 'utf8') - const performanceDependency = 'implementation("com.bugsnag:bugsnag-android-performance:9.9.9")' + const performanceDependency = 'implementation("com.bugsnag:bugsnag-android-performance:1.+")' const dependenciesSection = 'dependencies {' appGradle = appGradle.replace(dependenciesSection, `${dependenciesSection}\n ${performanceDependency}`) @@ -382,7 +355,7 @@ function installCocoaPerformance() { const podfilePath = resolve(fixtureDir, 'ios/Podfile') let podfile = fs.readFileSync(podfilePath, 'utf8') - const performancePod = `pod 'BugsnagPerformance', :git => 'https://github.com/bugsnag/bugsnag-cocoa-performance.git', :branch => 'integration/react-native-integration'` + const performancePod = `pod 'BugsnagPerformance'` const targetSection = 'target \'reactnative\' do' podfile = podfile.replace(targetSection, `${targetSection}\n ${performancePod}`) diff --git a/packages/platforms/react-native/android/build.gradle b/packages/platforms/react-native/android/build.gradle index 79b4b83bb..67c37b878 100644 --- a/packages/platforms/react-native/android/build.gradle +++ b/packages/platforms/react-native/android/build.gradle @@ -36,5 +36,5 @@ repositories { dependencies { implementation 'com.facebook.react:react-native' - compileOnly("com.bugsnag:bugsnag-android-performance:9.9.9") + compileOnly("com.bugsnag:bugsnag-android-performance:1.11.0") } \ No newline at end of file diff --git a/packages/platforms/react-native/android/src/main/java/com/bugsnag/android/performance/NativeBugsnagPerformanceImpl.java b/packages/platforms/react-native/android/src/main/java/com/bugsnag/android/performance/NativeBugsnagPerformanceImpl.java index 1368c5681..3ab0a3b01 100644 --- a/packages/platforms/react-native/android/src/main/java/com/bugsnag/android/performance/NativeBugsnagPerformanceImpl.java +++ b/packages/platforms/react-native/android/src/main/java/com/bugsnag/android/performance/NativeBugsnagPerformanceImpl.java @@ -26,6 +26,7 @@ import java.security.SecureRandom; import java.util.Iterator; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; @@ -158,17 +159,17 @@ WritableMap attachToNativeSDK() { result.putInt("attributeStringValueLimit", nativeConfig.getAttributeStringValueLimit()); result.putInt("attributeArrayLengthLimit", nativeConfig.getAttributeArrayLengthLimit()); - var appVersion = nativeConfig.getAppVersion(); + String appVersion = nativeConfig.getAppVersion(); if (appVersion != null) { result.putString("appVersion", nativeConfig.getAppVersion()); } - var samplingProbability = nativeConfig.getSamplingProbability(); + Double samplingProbability = nativeConfig.getSamplingProbability(); if (samplingProbability != null) { result.putDouble("samplingProbability", samplingProbability); } - var enabledReleaseStages = nativeConfig.getEnabledReleaseStages(); + Set enabledReleaseStages = nativeConfig.getEnabledReleaseStages(); if (enabledReleaseStages != null) { result.putArray("enabledReleaseStages", Arguments.fromArray(enabledReleaseStages.toArray(new String[0]))); } @@ -186,7 +187,15 @@ WritableMap startNativeSpan(String name, ReadableMap options) { SpanFactory spanFactory = BugsnagPerformance.INSTANCE.getInstrumentedAppState$internal().getSpanFactory(); SpanImpl nativeSpan = spanFactory.createCustomSpan(name, spanOptions); - nativeSpan.getAttributes().getEntries$internal().removeIf(entry -> !entry.getKey().equals("bugsnag.sampling.p")); + // all span attributes are set from JS, with the exception of the bugsnag.sampling.p attribute + // this needs to be preserved as it may not be re-populated when the span is processed + Iterator> entries = nativeSpan.getAttributes().getEntries$internal().iterator(); + while (entries.hasNext()) { + Map.Entry entry = entries.next(); + if (!entry.getKey().equals("bugsnag.sampling.p")) { + entries.remove(); + } + } String spanKey = EncodingUtils.toHexString(nativeSpan.getSpanId()) + EncodingUtils.toHexString(nativeSpan.getTraceId()); openSpans.put(spanKey, nativeSpan); diff --git a/test/react-native/features/fixtures/scenario-launcher/android/build.gradle b/test/react-native/features/fixtures/scenario-launcher/android/build.gradle index a9117a400..d7b4aa029 100644 --- a/test/react-native/features/fixtures/scenario-launcher/android/build.gradle +++ b/test/react-native/features/fixtures/scenario-launcher/android/build.gradle @@ -36,6 +36,6 @@ repositories { dependencies { compileOnly "com.bugsnag:bugsnag-android:6.+" - compileOnly("com.bugsnag:bugsnag-android-performance:9.9.9") + compileOnly("com.bugsnag:bugsnag-android-performance:1.11.0") implementation 'com.facebook.react:react-native' } \ No newline at end of file