From e1a7965107a3c04afad8d87ddf8aea1c08591477 Mon Sep 17 00:00:00 2001 From: Alexander Pantiukhov Date: Thu, 19 Mar 2026 12:01:36 +0100 Subject: [PATCH 1/6] CI: detect-changes workflow to only check the affected components on the CI side --- .github/file-filters.yml | 51 +++++++- .github/workflows/detect-changes.yml | 115 +++++++++++++++++ .github/workflows/e2e-v2.yml | 120 ++++++++++++++---- .github/workflows/native-tests.yml | 12 +- .github/workflows/sample-application-expo.yml | 46 +++++-- .github/workflows/sample-application.yml | 95 ++++++++++---- 6 files changed, 373 insertions(+), 66 deletions(-) create mode 100644 .github/workflows/detect-changes.yml diff --git a/.github/file-filters.yml b/.github/file-filters.yml index ce33af45d8..fa5c8b5b2d 100644 --- a/.github/file-filters.yml +++ b/.github/file-filters.yml @@ -16,4 +16,53 @@ high_risk_code: &high_risk_code - 'scripts/sentry-xcode.sh' - 'scripts/sentry-xcode-debug-files.sh' - 'sentry.gradle' - + +# --- Platform-specific filters for CI optimization --- +# Used by detect-changes.yml to skip platform-irrelevant CI jobs. + +# Changes that affect iOS native code +ios_native: + - 'packages/core/ios/**' + - 'packages/core/RNSentryCocoaTester/**' + - 'packages/core/RNSentry.podspec' + - 'samples/react-native/ios/**' + - 'samples/react-native/scripts/*ios*' + - 'samples/react-native/scripts/pod-install.sh' + - 'samples/react-native/Gemfile' + - 'samples/react-native-macos/**' + - 'samples/expo/ios/**' + +# Changes that affect Android native code +android_native: + - 'packages/core/android/**' + - 'packages/core/RNSentryAndroidTester/**' + - 'packages/core/sentry.gradle' + - 'samples/react-native/android/**' + - 'samples/react-native/scripts/*android*' + - 'samples/expo/android/**' + +# Changes to JS/TS source code (affects ALL platforms) +js_source: + - 'packages/core/src/**' + - 'packages/core/plugin/**' + - 'packages/core/scripts/**' + - 'packages/core/package.json' + - 'packages/core/tsconfig.json' + +# Changes to JS/TS test files only +js_test: + - 'packages/core/test/**' + +# Changes to E2E test infrastructure +e2e_tests: + - 'dev-packages/e2e-tests/**' + +# Changes to performance test infrastructure +perf_tests: + - 'performance-tests/**' + +# CI workflow or infrastructure changes (should trigger everything) +ci: + - '.github/workflows/**' + - '.github/actions/**' + - '.github/file-filters.yml' diff --git a/.github/workflows/detect-changes.yml b/.github/workflows/detect-changes.yml new file mode 100644 index 0000000000..69983fc064 --- /dev/null +++ b/.github/workflows/detect-changes.yml @@ -0,0 +1,115 @@ +name: Detect Changes +on: + workflow_call: + outputs: + # Raw filter outputs + ios_native: + description: 'Whether iOS native files changed' + value: ${{ jobs.changes.outputs.ios_native }} + android_native: + description: 'Whether Android native files changed' + value: ${{ jobs.changes.outputs.android_native }} + js_source: + description: 'Whether JS/TS source files changed' + value: ${{ jobs.changes.outputs.js_source }} + js_test: + description: 'Whether JS/TS test files changed' + value: ${{ jobs.changes.outputs.js_test }} + e2e_tests: + description: 'Whether E2E test files changed' + value: ${{ jobs.changes.outputs.e2e_tests }} + perf_tests: + description: 'Whether performance test files changed' + value: ${{ jobs.changes.outputs.perf_tests }} + ci: + description: 'Whether CI workflow files changed' + value: ${{ jobs.changes.outputs.ci }} + # Convenience: should iOS-related jobs run? + needs_ios: + description: 'Whether iOS jobs should run' + value: ${{ jobs.changes.outputs.needs_ios }} + # Convenience: should Android-related jobs run? + needs_android: + description: 'Whether Android jobs should run' + value: ${{ jobs.changes.outputs.needs_android }} + +jobs: + changes: + name: Detect file changes + runs-on: ubuntu-latest + outputs: + ios_native: ${{ steps.filter.outputs.ios_native }} + android_native: ${{ steps.filter.outputs.android_native }} + js_source: ${{ steps.filter.outputs.js_source }} + js_test: ${{ steps.filter.outputs.js_test }} + e2e_tests: ${{ steps.filter.outputs.e2e_tests }} + perf_tests: ${{ steps.filter.outputs.perf_tests }} + ci: ${{ steps.filter.outputs.ci }} + needs_ios: ${{ steps.evaluate.outputs.needs_ios }} + needs_android: ${{ steps.evaluate.outputs.needs_android }} + steps: + - uses: actions/checkout@v4 + + - name: Detect changed paths + uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 + id: filter + with: + filters: .github/file-filters.yml + + - name: Evaluate platform needs + id: evaluate + env: + IOS_NATIVE: ${{ steps.filter.outputs.ios_native }} + ANDROID_NATIVE: ${{ steps.filter.outputs.android_native }} + JS_SOURCE: ${{ steps.filter.outputs.js_source }} + CI_CHANGED: ${{ steps.filter.outputs.ci }} + E2E_TESTS: ${{ steps.filter.outputs.e2e_tests }} + PERF_TESTS: ${{ steps.filter.outputs.perf_tests }} + IS_MAIN_OR_RELEASE: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) }} + run: | + echo "--- Change Detection Summary ---" + echo "ios_native=$IOS_NATIVE" + echo "android_native=$ANDROID_NATIVE" + echo "js_source=$JS_SOURCE" + echo "ci=$CI_CHANGED" + echo "e2e_tests=$E2E_TESTS" + echo "perf_tests=$PERF_TESTS" + echo "is_main_or_release=$IS_MAIN_OR_RELEASE" + + # iOS is needed if: + # - iOS native code changed + # - JS source changed (may affect native bridges) + # - CI config changed (need to validate workflows) + # - E2E or perf tests changed (they test both platforms) + # - Push to main or release branch (always run everything) + if [[ "$IOS_NATIVE" == "true" \ + || "$JS_SOURCE" == "true" \ + || "$CI_CHANGED" == "true" \ + || "$E2E_TESTS" == "true" \ + || "$PERF_TESTS" == "true" \ + || "$IS_MAIN_OR_RELEASE" == "true" ]]; then + echo "needs_ios=true" >> "$GITHUB_OUTPUT" + echo "=> needs_ios=true" + else + echo "needs_ios=false" >> "$GITHUB_OUTPUT" + echo "=> needs_ios=false" + fi + + # Android is needed if: + # - Android native code changed + # - JS source changed (may affect native bridges) + # - CI config changed (need to validate workflows) + # - E2E or perf tests changed (they test both platforms) + # - Push to main or release branch (always run everything) + if [[ "$ANDROID_NATIVE" == "true" \ + || "$JS_SOURCE" == "true" \ + || "$CI_CHANGED" == "true" \ + || "$E2E_TESTS" == "true" \ + || "$PERF_TESTS" == "true" \ + || "$IS_MAIN_OR_RELEASE" == "true" ]]; then + echo "needs_android=true" >> "$GITHUB_OUTPUT" + echo "=> needs_android=true" + else + echo "needs_android=false" >> "$GITHUB_OUTPUT" + echo "=> needs_android=false" + fi diff --git a/.github/workflows/e2e-v2.yml b/.github/workflows/e2e-v2.yml index af566ae755..25d1533a7a 100644 --- a/.github/workflows/e2e-v2.yml +++ b/.github/workflows/e2e-v2.yml @@ -29,12 +29,15 @@ jobs: diff_check: needs: [ready-to-merge-gate] uses: ./.github/workflows/skip-ci.yml + detect-changes: + needs: [ready-to-merge-gate] + uses: ./.github/workflows/detect-changes.yml auth_token_check: uses: ./.github/workflows/skip-ci-noauth.yml secrets: inherit metrics: runs-on: ${{ matrix.runs-on }} - needs: [diff_check, auth_token_check] + needs: [diff_check, detect-changes, auth_token_check] if: ${{ needs.diff_check.outputs.skip_ci != 'true' && needs.auth_token_check.outputs.skip_ci != 'true' && !startsWith(github.ref, 'refs/heads/release/') }} env: SENTRY_DISABLE_AUTO_UPLOAD: 'true' @@ -56,13 +59,29 @@ jobs: name: Android appPlain: performance-tests/TestAppPlain/android/app/build/outputs/apk/release/app-release.apk steps: + - name: Check if platform is needed + id: platform-check + run: | + if [[ "${{ matrix.platform }}" == "ios" && "${{ needs.detect-changes.outputs.needs_ios }}" != "true" ]]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "Skipping iOS — no relevant changes detected." + elif [[ "${{ matrix.platform }}" == "android" && "${{ needs.detect-changes.outputs.needs_android }}" != "true" ]]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "Skipping Android — no relevant changes detected." + else + echo "skip=false" >> "$GITHUB_OUTPUT" + fi + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + if: ${{ steps.platform-check.outputs.skip != 'true' }} - uses: ./.github/actions/disk-cleanup - if: ${{ matrix.platform == 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' }} - run: corepack enable + if: ${{ steps.platform-check.outputs.skip != 'true' }} - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6 + if: ${{ steps.platform-check.outputs.skip != 'true' }} with: package-manager-cache: false node-version: 20 @@ -70,32 +89,38 @@ jobs: cache-dependency-path: yarn.lock - name: Install Ninja - if: ${{ matrix.platform == 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' }} run: sudo apt-get update && sudo apt-get install -y ninja-build - uses: actions/setup-java@v5 + if: ${{ steps.platform-check.outputs.skip != 'true' }} with: java-version: '17' distribution: 'adopt' - name: Gradle cache + if: ${{ steps.platform-check.outputs.skip != 'true' }} uses: gradle/gradle-build-action@v3 - uses: ruby/setup-ruby@v1 - if: ${{ matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} with: ruby-version: '3.3.0' - name: Install Global Dependencies + if: ${{ steps.platform-check.outputs.skip != 'true' }} run: npm i -g react-native-cli @sentry/cli - name: Install Dependencies + if: ${{ steps.platform-check.outputs.skip != 'true' }} run: yarn install - name: Build SDK + if: ${{ steps.platform-check.outputs.skip != 'true' }} run: yarn build - uses: actions/cache@v5 + if: ${{ steps.platform-check.outputs.skip != 'true' }} id: app-plain-cache with: path: ${{ matrix.appPlain }} @@ -107,7 +132,7 @@ jobs: key: ${{ github.workflow }}-${{ github.job }}-appplain-${{ matrix.platform }}-${{ matrix.rn-architecture }}-${{ hashFiles('performance-tests/TestAppSentry/package.json') }} - name: Build app plain - if: steps.app-plain-cache.outputs['cache-hit'] != 'true' + if: ${{ steps.platform-check.outputs.skip != 'true' && steps.app-plain-cache.outputs['cache-hit'] != 'true' }} working-directory: ./performance-tests/TestAppPlain run: | cd ${{ matrix.platform }} @@ -137,6 +162,7 @@ jobs: MATCH_USERNAME: ${{ secrets.MATCH_USERNAME }} - name: Build app with Sentry + if: ${{ steps.platform-check.outputs.skip != 'true' }} working-directory: ./performance-tests/TestAppSentry run: | cd ${{ matrix.platform }} @@ -167,6 +193,7 @@ jobs: MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} MATCH_USERNAME: ${{ secrets.MATCH_USERNAME }} - name: Collect apps metrics + if: ${{ steps.platform-check.outputs.skip != 'true' }} uses: getsentry/action-app-sdk-overhead-metrics@5f2d99b8e5a7b833386524924d24320501099a44 with: name: ${{ matrix.name }} (${{ matrix.rn-architecture }}) @@ -177,7 +204,7 @@ jobs: react-native-build: name: Build RN ${{ matrix.rn-version }} ${{ matrix.rn-architecture }} ${{ matrix.engine }} ${{ matrix.platform }} ${{ matrix.build-type }} ${{ matrix.ios-use-frameworks }} runs-on: ${{ matrix.runs-on }} - needs: [diff_check, auth_token_check] + needs: [diff_check, detect-changes, auth_token_check] if: ${{ needs.diff_check.outputs.skip_ci != 'true' && needs.auth_token_check.outputs.skip_ci != 'true' && !startsWith(github.ref, 'refs/heads/release/') }} env: RN_VERSION: ${{ matrix.rn-version }} @@ -235,28 +262,47 @@ jobs: ios-use-frameworks: 'dynamic' steps: + - name: Check if platform is needed + id: platform-check + run: | + if [[ "${{ matrix.platform }}" == "ios" && "${{ needs.detect-changes.outputs.needs_ios }}" != "true" ]]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "Skipping iOS — no relevant changes detected." + elif [[ "${{ matrix.platform }}" == "android" && "${{ needs.detect-changes.outputs.needs_android }}" != "true" ]]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "Skipping Android — no relevant changes detected." + else + echo "skip=false" >> "$GITHUB_OUTPUT" + fi + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + if: ${{ steps.platform-check.outputs.skip != 'true' }} - uses: ./.github/actions/disk-cleanup - if: ${{ matrix.platform == 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' }} - name: Sentry Release + if: ${{ steps.platform-check.outputs.skip != 'true' }} run: | SENTRY_RELEASE_CANDIDATE=$(echo 'e2e/${{ github.ref }}' | perl -pe 's/\//-/g') echo "SENTRY_RELEASE=$SENTRY_RELEASE_CANDIDATE" >> $GITHUB_ENV - name: Sentry Dist + if: ${{ steps.platform-check.outputs.skip != 'true' }} run: | SENTRY_DIST_CANDIDATE=${{ matrix.rn-version }}-${{ matrix.rn-architecture }}-${{ matrix.engine }}-${{ matrix.platform }}-${{ matrix.build-type }}-${{ matrix.ios-use-frameworks }}-${GITHUB_SHA:0:8} echo "SENTRY_DIST=$SENTRY_DIST_CANDIDATE" >> $GITHUB_ENV - name: Sentry Envs + if: ${{ steps.platform-check.outputs.skip != 'true' }} run: | echo "SENTRY_RELEASE=$SENTRY_RELEASE" echo "SENTRY_DIST=$SENTRY_DIST" - run: corepack enable + if: ${{ steps.platform-check.outputs.skip != 'true' }} - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6 + if: ${{ steps.platform-check.outputs.skip != 'true' }} with: package-manager-cache: false node-version: 20 @@ -264,41 +310,47 @@ jobs: cache-dependency-path: yarn.lock - name: Install Ninja - if: ${{ matrix.platform == 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' }} run: sudo apt-get update && sudo apt-get install -y ninja-build - uses: actions/setup-java@v5 + if: ${{ steps.platform-check.outputs.skip != 'true' }} with: java-version: '17' distribution: 'adopt' - name: Gradle cache + if: ${{ steps.platform-check.outputs.skip != 'true' }} uses: gradle/gradle-build-action@v3 - name: Setup Global Tools + if: ${{ steps.platform-check.outputs.skip != 'true' }} run: | npm i -g yalc semver - name: Setup Global Xcode Tools - if: ${{ matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} run: which xcbeautify || brew install xcbeautify - name: Install JS Dependencies + if: ${{ steps.platform-check.outputs.skip != 'true' }} run: yarn install - uses: ruby/setup-ruby@v1 - if: ${{ matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} with: ruby-version: '3.3.0' - name: Setup Plain RN ${{ matrix.rn-version }} App + if: ${{ steps.platform-check.outputs.skip != 'true' }} run: ./dev-packages/e2e-tests/cli.mjs ${{ matrix.platform }} --create - name: Build Plain RN ${{ matrix.rn-version }} App + if: ${{ steps.platform-check.outputs.skip != 'true' }} run: ./dev-packages/e2e-tests/cli.mjs ${{ matrix.platform }} --build - name: Upload App - if: matrix.build-type == 'production' + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.build-type == 'production' }} uses: actions/upload-artifact@v7 with: name: ${{ matrix.rn-version }}-${{ matrix.rn-architecture }}-${{ matrix.engine }}-${{ matrix.platform }}-${{ matrix.build-type }}-${{ matrix.ios-use-frameworks }}-app-package @@ -306,7 +358,7 @@ jobs: retention-days: 1 - name: Upload logs - if: ${{ always() }} + if: ${{ always() && steps.platform-check.outputs.skip != 'true' }} uses: actions/upload-artifact@v7 with: name: rn-build-logs-${{ matrix.rn-version }}-${{ matrix.rn-architecture }}-${{ matrix.engine }}-${{ matrix.platform }}-${{ matrix.build-type }}-${{ matrix.ios-use-frameworks }} @@ -316,7 +368,7 @@ jobs: name: Test RN ${{ matrix.rn-version }} ${{ matrix.rn-architecture }} ${{ matrix.engine }} ${{ matrix.platform }} ${{ matrix.build-type }} ${{ matrix.ios-use-frameworks }} - needs: [react-native-build, diff_check] + needs: [react-native-build, diff_check, detect-changes] if: ${{ needs.diff_check.outputs.skip_ci != 'true' }} runs-on: ${{ matrix.runs-on }} @@ -337,35 +389,52 @@ jobs: runs-on: ["ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04", "runner_group_id:10"] steps: + - name: Check if platform is needed + id: platform-check + run: | + if [[ "${{ matrix.platform }}" == "ios" && "${{ needs.detect-changes.outputs.needs_ios }}" != "true" ]]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "Skipping iOS — no relevant changes detected." + elif [[ "${{ matrix.platform }}" == "android" && "${{ needs.detect-changes.outputs.needs_android }}" != "true" ]]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "Skipping Android — no relevant changes detected." + else + echo "skip=false" >> "$GITHUB_OUTPUT" + fi + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + if: ${{ steps.platform-check.outputs.skip != 'true' }} - name: Install Maestro + if: ${{ steps.platform-check.outputs.skip != 'true' }} uses: dniHze/maestro-test-action@bda8a93211c86d0a05b7a4597c5ad134566fbde4 # pin@v1.0.0 with: version: ${{env.MAESTRO_VERSION}} - name: Install iDB Companion - if: ${{ matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} run: brew tap facebook/fb && brew install facebook/fb/idb-companion - uses: ./.github/actions/disk-cleanup - if: ${{ matrix.platform == 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' }} - name: Setup Global Xcode Tools - if: ${{ matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} run: which xcbeautify || brew install xcbeautify - name: Download App Package - if: matrix.build-type == 'production' + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.build-type == 'production' }} uses: actions/download-artifact@v8 with: name: ${{ matrix.rn-version }}-${{ matrix.rn-architecture }}-${{ matrix.engine }}-${{ matrix.platform }}-${{ matrix.build-type }}-${{ matrix.ios-use-frameworks }}-app-package path: dev-packages/e2e-tests - name: Enable Corepack + if: ${{ steps.platform-check.outputs.skip != 'true' }} run: corepack enable - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6 + if: ${{ steps.platform-check.outputs.skip != 'true' }} with: package-manager-cache: false node-version: 20 @@ -373,19 +442,21 @@ jobs: cache-dependency-path: yarn.lock - name: Install Ninja - if: ${{ matrix.platform == 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' }} run: sudo apt-get update && sudo apt-get install -y ninja-build - uses: actions/setup-java@v5 + if: ${{ steps.platform-check.outputs.skip != 'true' }} with: java-version: '17' distribution: 'adopt' - name: Gradle cache + if: ${{ steps.platform-check.outputs.skip != 'true' }} uses: gradle/gradle-build-action@v3 - name: Setup KVM - if: ${{ matrix.platform == 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' }} shell: bash run: | # check if virtualization is supported... @@ -397,10 +468,11 @@ jobs: sudo udevadm trigger --name-match=kvm - name: Install JS Dependencies + if: ${{ steps.platform-check.outputs.skip != 'true' }} run: yarn install - name: Run tests on Android - if: ${{ matrix.platform == 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' }} uses: reactivecircus/android-emulator-runner@e89f39f1abbbd05b1113a29cf4db69e7540cae5a # pin@v2.37.0 with: api-level: 30 @@ -420,24 +492,24 @@ jobs: script: ./dev-packages/e2e-tests/cli.mjs ${{ matrix.platform }} --test - name: List available iOS simulators - if: ${{ matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} run: xcrun simctl list devices available - uses: futureware-tech/simulator-action@e89aa8f93d3aec35083ff49d2854d07f7186f7f5 # pin@v5 - if: ${{ matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} with: model: ${{ env.IOS_DEVICE }} os_version: ${{ env.IOS_VERSION }} - name: Run tests on iOS - if: ${{ matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} env: # Increase timeout for Maestro iOS driver startup (default is 60s, some CI runners need more time) MAESTRO_DRIVER_STARTUP_TIMEOUT: 120000 run: ./dev-packages/e2e-tests/cli.mjs ${{ matrix.platform }} --test - name: Upload logs - if: ${{ always() }} + if: ${{ always() && steps.platform-check.outputs.skip != 'true' }} uses: actions/upload-artifact@v7 with: name: ${{ matrix.rn-version }}-${{ matrix.rn-architecture }}-${{ matrix.engine }}-${{ matrix.platform }}-${{ matrix.build-type }}-${{ matrix.ios-use-frameworks }}-logs diff --git a/.github/workflows/native-tests.yml b/.github/workflows/native-tests.yml index 42baeb965b..1c8fc951ce 100644 --- a/.github/workflows/native-tests.yml +++ b/.github/workflows/native-tests.yml @@ -24,11 +24,15 @@ jobs: needs: [ready-to-merge-gate] uses: ./.github/workflows/skip-ci.yml + detect-changes: + needs: [ready-to-merge-gate] + uses: ./.github/workflows/detect-changes.yml + test-ios: name: ios runs-on: ["ghcr.io/cirruslabs/macos-tahoe-xcode:26.2.0", "runner_group_id:10"] - needs: [diff_check] - if: ${{ needs.diff_check.outputs.skip_ci != 'true' }} + needs: [diff_check, detect-changes] + if: ${{ needs.diff_check.outputs.skip_ci != 'true' && needs.detect-changes.outputs.needs_ios == 'true' }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 @@ -98,8 +102,8 @@ jobs: test-android: name: android runs-on: ["ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04", "runner_group_id:10"] - needs: [diff_check] - if: ${{ needs.diff_check.outputs.skip_ci != 'true' }} + needs: [diff_check, detect-changes] + if: ${{ needs.diff_check.outputs.skip_ci != 'true' && needs.detect-changes.outputs.needs_android == 'true' }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 diff --git a/.github/workflows/sample-application-expo.yml b/.github/workflows/sample-application-expo.yml index 612a45324f..32f3ea45e0 100644 --- a/.github/workflows/sample-application-expo.yml +++ b/.github/workflows/sample-application-expo.yml @@ -27,10 +27,14 @@ jobs: needs: [ready-to-merge-gate] uses: ./.github/workflows/skip-ci.yml + detect-changes: + needs: [ready-to-merge-gate] + uses: ./.github/workflows/detect-changes.yml + build: name: Build ${{ matrix.platform }} ${{ matrix.build-type }} ${{ matrix.ios-use-frameworks}} runs-on: ${{ matrix.runs-on }} - needs: [diff_check] + needs: [diff_check, detect-changes] if: ${{ needs.diff_check.outputs.skip_ci != 'true' }} env: SENTRY_DISABLE_AUTO_UPLOAD: 'true' @@ -52,17 +56,32 @@ jobs: - platform: 'android' ios-use-frameworks: 'dynamic-frameworks' steps: + - name: Check if platform is needed + id: platform-check + run: | + if [[ "${{ matrix.platform }}" == "ios" && "${{ needs.detect-changes.outputs.needs_ios }}" != "true" ]]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "Skipping iOS — no relevant changes detected." + elif [[ "${{ matrix.platform }}" == "android" && "${{ needs.detect-changes.outputs.needs_android }}" != "true" ]]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "Skipping Android — no relevant changes detected." + else + echo "skip=false" >> "$GITHUB_OUTPUT" + fi + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + if: ${{ steps.platform-check.outputs.skip != 'true' }} - name: Enable Corepack (NPM) - if: ${{ matrix.platform != 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform != 'ios' }} run: npm i -g corepack - name: Enable Corepack - if: ${{ matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} run: corepack enable - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6 + if: ${{ steps.platform-check.outputs.skip != 'true' }} with: package-manager-cache: false node-version: 20 @@ -70,7 +89,7 @@ jobs: cache-dependency-path: yarn.lock - uses: ruby/setup-ruby@v1 - if: ${{ matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} with: working-directory: ${{ matrix.platform == 'ios' && ' samples/expo' }} ruby-version: '3.3.0' # based on what is used in the sample @@ -78,30 +97,34 @@ jobs: cache-version: 1 # cache the installed gems - uses: actions/setup-java@v5 + if: ${{ steps.platform-check.outputs.skip != 'true' }} with: java-version: '17' distribution: 'adopt' - name: Gradle cache + if: ${{ steps.platform-check.outputs.skip != 'true' }} uses: gradle/gradle-build-action@ac2d340dc04d9e1113182899e983b5400c17cda1 # v3.5.0 - name: Setup Global Xcode Tools - if: ${{ matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} run: which xcbeautify || brew install xcbeautify - name: Install SDK Dependencies + if: ${{ steps.platform-check.outputs.skip != 'true' }} run: yarn install - name: Build SDK + if: ${{ steps.platform-check.outputs.skip != 'true' }} run: yarn build - name: Prebuild apps - if: ${{ matrix.platform == 'android' || matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && (matrix.platform == 'android' || matrix.platform == 'ios') }} working-directory: samples/expo run: npx expo prebuild - name: Install App Pods - if: ${{ matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} working-directory: samples/expo/ios run: | [[ "${{ matrix.build-type }}" == "production" ]] && ENABLE_PROD=1 || ENABLE_PROD=0 @@ -113,7 +136,7 @@ jobs: cat Podfile.lock | grep $RN_SENTRY_POD_NAME - name: Build Android App - if: ${{ matrix.platform == 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' }} working-directory: samples/expo/android env: # Increase memory for Expo SDK 55 lint tasks @@ -124,7 +147,7 @@ jobs: ./gradlew ":app:assemble$CONFIG" -PreactNativeArchitectures=x86 - name: Build iOS App - if: ${{ matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} working-directory: samples/expo/ios env: # Fix for Xcode 26+ with MetalToolchain: use default Xcode toolchain to avoid @@ -150,18 +173,19 @@ jobs: | xcbeautify --quieter --is-ci --disable-colored-output - name: Build Web App - if: ${{ matrix.platform == 'web' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'web' }} working-directory: samples/expo run: | npx expo export -p web - name: Export Expo + if: ${{ steps.platform-check.outputs.skip != 'true' }} working-directory: samples/expo run: | npx expo export - name: Upload logs - if: ${{ always() }} + if: ${{ always() && steps.platform-check.outputs.skip != 'true' }} uses: actions/upload-artifact@v7 with: name: build-sample-expo-${{ matrix.platform }}-${{ matrix.build-type }}-${{ matrix.ios-use-frameworks}}-logs diff --git a/.github/workflows/sample-application.yml b/.github/workflows/sample-application.yml index b27f5c9387..97e29c3b3b 100644 --- a/.github/workflows/sample-application.yml +++ b/.github/workflows/sample-application.yml @@ -35,10 +35,14 @@ jobs: needs: [ready-to-merge-gate] uses: ./.github/workflows/skip-ci.yml + detect-changes: + needs: [ready-to-merge-gate] + uses: ./.github/workflows/detect-changes.yml + build: name: Build ${{ matrix.rn-architecture }} ${{ matrix.platform }} ${{ matrix.build-type }} ${{ matrix.ios-use-frameworks}} runs-on: ${{ matrix.runs-on }} - needs: [diff_check] + needs: [diff_check, detect-changes] if: ${{ needs.diff_check.outputs.skip_ci != 'true' }} env: SENTRY_DISABLE_AUTO_UPLOAD: 'true' @@ -67,17 +71,35 @@ jobs: - ios-use-frameworks: 'dynamic-frameworks' platform: 'macos' steps: + - name: Check if platform is needed + id: platform-check + run: | + if [[ "${{ matrix.platform }}" == "ios" && "${{ needs.detect-changes.outputs.needs_ios }}" != "true" ]]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "Skipping iOS — no relevant changes detected." + elif [[ "${{ matrix.platform }}" == "macos" && "${{ needs.detect-changes.outputs.needs_ios }}" != "true" ]]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "Skipping macOS — no relevant changes detected." + elif [[ "${{ matrix.platform }}" == "android" && "${{ needs.detect-changes.outputs.needs_android }}" != "true" ]]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "Skipping Android — no relevant changes detected." + else + echo "skip=false" >> "$GITHUB_OUTPUT" + fi + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + if: ${{ steps.platform-check.outputs.skip != 'true' }} - name: Enable Corepack (NPM) - if: ${{ matrix.platform == 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' }} run: npm i -g corepack - name: Enable Corepack - if: ${{ matrix.platform != 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform != 'android' }} run: corepack enable - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6 + if: ${{ steps.platform-check.outputs.skip != 'true' }} with: package-manager-cache: false node-version: 18 @@ -85,7 +107,7 @@ jobs: cache-dependency-path: yarn.lock - uses: ruby/setup-ruby@v1 - if: ${{ matrix.platform == 'ios' || matrix.platform == 'macos' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && (matrix.platform == 'ios' || matrix.platform == 'macos') }} with: working-directory: ${{ matrix.platform == 'ios' && env.REACT_NATIVE_SAMPLE_PATH || 'samples/react-native-macos' }} ruby-version: '3.3.0' # based on what is used in the sample @@ -93,25 +115,29 @@ jobs: cache-version: 1 # cache the installed gems - uses: actions/setup-java@v5 + if: ${{ steps.platform-check.outputs.skip != 'true' }} with: java-version: '17' distribution: 'adopt' - name: Gradle cache + if: ${{ steps.platform-check.outputs.skip != 'true' }} uses: gradle/gradle-build-action@v3 - name: Setup Global Xcode Tools - if: ${{ matrix.platform == 'ios' || matrix.platform == 'macos' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && (matrix.platform == 'ios' || matrix.platform == 'macos') }} run: which xcbeautify || brew install xcbeautify - name: Install SDK Dependencies + if: ${{ steps.platform-check.outputs.skip != 'true' }} run: yarn install - name: Build SDK + if: ${{ steps.platform-check.outputs.skip != 'true' }} run: yarn build - name: Install App Pods - if: ${{ matrix.platform == 'ios' || matrix.platform == 'macos' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && (matrix.platform == 'ios' || matrix.platform == 'macos') }} working-directory: samples run: | [[ "${{ matrix.platform }}" == "ios" ]] && cd react-native @@ -124,7 +150,7 @@ jobs: ./scripts/pod-install.sh - name: Build Android App - if: ${{ matrix.platform == 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' }} working-directory: ${{ env.REACT_NATIVE_SAMPLE_PATH }} run: | export RN_ARCHITECTURE="${{ matrix.rn-architecture }}" @@ -134,7 +160,7 @@ jobs: ./scripts/build-android.sh -PreactNativeArchitectures=x86 - name: Build iOS App - if: ${{ matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} working-directory: ${{ env.REACT_NATIVE_SAMPLE_PATH }} env: # Fix for Xcode 26+ with MetalToolchain: use default Xcode toolchain to avoid @@ -148,7 +174,7 @@ jobs: ./scripts/build-ios.sh - name: Build macOS App - if: ${{ matrix.platform == 'macos' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'macos' }} working-directory: samples/react-native-macos/macos run: | [[ "${{ matrix.build-type }}" == "production" ]] && export CONFIG='Release' || export CONFIG='Debug' @@ -167,7 +193,7 @@ jobs: | xcbeautify --quieter --is-ci --disable-colored-output - name: Archive iOS App - if: ${{ matrix.platform == 'ios' && matrix.rn-architecture == 'new' && matrix.build-type == 'production' && matrix.ios-use-frameworks == 'no-frameworks' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' && matrix.rn-architecture == 'new' && matrix.build-type == 'production' && matrix.ios-use-frameworks == 'no-frameworks' }} working-directory: ${{ env.REACT_NATIVE_SAMPLE_PATH }} run: | zip -r \ @@ -175,7 +201,7 @@ jobs: sentryreactnativesample.app - name: Archive Android App - if: ${{ matrix.platform == 'android' && matrix.rn-architecture == 'new' && matrix.build-type == 'production' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' && matrix.rn-architecture == 'new' && matrix.build-type == 'production' }} run: | zip -j \ ${{ env.ANDROID_APP_ARCHIVE_PATH }} \ @@ -183,7 +209,7 @@ jobs: ${{ env.REACT_NATIVE_SAMPLE_PATH }}/app-androidTest.apk - name: Upload iOS APP - if: ${{ matrix.platform == 'ios' && matrix.rn-architecture == 'new' && matrix.build-type == 'production' && matrix.ios-use-frameworks == 'no-frameworks' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' && matrix.rn-architecture == 'new' && matrix.build-type == 'production' && matrix.ios-use-frameworks == 'no-frameworks' }} uses: actions/upload-artifact@v7 with: name: sample-rn-${{ matrix.rn-architecture }}-${{ matrix.build-type }}-${{ matrix.ios-use-frameworks}}-${{ matrix.platform }} @@ -191,7 +217,7 @@ jobs: retention-days: 1 - name: Upload Android APK - if: ${{ matrix.platform == 'android' && matrix.rn-architecture == 'new' && matrix.build-type == 'production' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' && matrix.rn-architecture == 'new' && matrix.build-type == 'production' }} uses: actions/upload-artifact@v7 with: name: sample-rn-${{ matrix.rn-architecture }}-${{ matrix.build-type }}-${{ matrix.platform }} @@ -199,7 +225,7 @@ jobs: retention-days: 1 - name: Upload logs - if: ${{ always() }} + if: ${{ always() && steps.platform-check.outputs.skip != 'true' }} uses: actions/upload-artifact@v7 with: name: build-sample-${{ matrix.rn-architecture }}-${{ matrix.platform }}-${{ matrix.build-type }}-${{ matrix.ios-use-frameworks}}-logs @@ -208,7 +234,7 @@ jobs: test: name: Test ${{ matrix.platform }} ${{ matrix.build-type }} REV2 runs-on: ${{ matrix.runs-on }} - needs: [diff_check, build] + needs: [diff_check, detect-changes, build] if: ${{ needs.diff_check.outputs.skip_ci != 'true' }} strategy: # we want that the matrix keeps running, default is to cancel them if it fails. @@ -227,48 +253,64 @@ jobs: build-type: 'production' steps: + - name: Check if platform is needed + id: platform-check + run: | + if [[ "${{ matrix.platform }}" == "ios" && "${{ needs.detect-changes.outputs.needs_ios }}" != "true" ]]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "Skipping iOS — no relevant changes detected." + elif [[ "${{ matrix.platform }}" == "android" && "${{ needs.detect-changes.outputs.needs_android }}" != "true" ]]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "Skipping Android — no relevant changes detected." + else + echo "skip=false" >> "$GITHUB_OUTPUT" + fi + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + if: ${{ steps.platform-check.outputs.skip != 'true' }} - name: Install Maestro + if: ${{ steps.platform-check.outputs.skip != 'true' }} uses: dniHze/maestro-test-action@bda8a93211c86d0a05b7a4597c5ad134566fbde4 # pin@v1.0.0 with: version: ${{env.MAESTRO_VERSION}} - name: Download iOS App Archive - if: ${{ matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} uses: actions/download-artifact@v8 with: name: sample-rn-${{ matrix.rn-architecture }}-${{ matrix.build-type }}-${{ matrix.ios-use-frameworks}}-${{ matrix.platform }} path: ${{ env.REACT_NATIVE_SAMPLE_PATH }} - name: Download Android APK - if: ${{ matrix.platform == 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' }} uses: actions/download-artifact@v8 with: name: sample-rn-${{ matrix.rn-architecture }}-${{ matrix.build-type }}-${{ matrix.platform }} path: ${{ env.REACT_NATIVE_SAMPLE_PATH }} - name: Unzip iOS App Archive - if: ${{ matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} working-directory: ${{ env.REACT_NATIVE_SAMPLE_PATH }} run: unzip ${{ env.IOS_APP_ARCHIVE_PATH }} - name: Unzip Android APK - if: ${{ matrix.platform == 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' }} working-directory: ${{ env.REACT_NATIVE_SAMPLE_PATH }} run: | unzip ${{ env.ANDROID_APP_ARCHIVE_PATH }} rm app-androidTest.apk - name: Enable Corepack (NPM) - if: ${{ matrix.platform == 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' }} run: npm i -g corepack - name: Enable Corepack - if: ${{ matrix.platform != 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform != 'android' }} run: corepack enable - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6 + if: ${{ steps.platform-check.outputs.skip != 'true' }} with: package-manager-cache: false node-version: 18 @@ -276,13 +318,14 @@ jobs: cache-dependency-path: yarn.lock - name: Install JS Dependencies + if: ${{ steps.platform-check.outputs.skip != 'true' }} run: yarn install - uses: ./.github/actions/disk-cleanup - if: ${{ matrix.platform == 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' }} - name: Setup KVM - if: ${{ matrix.platform == 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' }} shell: bash run: | # check if virtualization is supported... @@ -295,18 +338,18 @@ jobs: - name: Boot ${{ env.IOS_DEVICE }} with iOS ${{ env.IOS_VERSION }} uses: futureware-tech/simulator-action@e89aa8f93d3aec35083ff49d2854d07f7186f7f5 # pin@v5 - if: ${{ matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} with: model: ${{ env.IOS_DEVICE }} os_version: ${{ env.IOS_VERSION }} - name: Run iOS Tests - if: ${{ matrix.platform == 'ios' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} working-directory: ${{ env.REACT_NATIVE_SAMPLE_PATH }} run: yarn test-ios - name: Run Android Tests on API ${{ env.ANDROID_API_LEVEL }} - if: ${{ matrix.platform == 'android' }} + if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'android' }} uses: reactivecircus/android-emulator-runner@e89f39f1abbbd05b1113a29cf4db69e7540cae5a # pin@v2.37.0 with: api-level: ${{ env.ANDROID_API_LEVEL }} From ddfeed8c2b470c14ef207cc2a96999c079e44056 Mon Sep 17 00:00:00 2001 From: Alexander Pantiukhov Date: Thu, 19 Mar 2026 16:13:05 +0100 Subject: [PATCH 2/6] Updated performance test approach --- .github/workflows/detect-changes.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/detect-changes.yml b/.github/workflows/detect-changes.yml index 69983fc064..417a2e7052 100644 --- a/.github/workflows/detect-changes.yml +++ b/.github/workflows/detect-changes.yml @@ -64,7 +64,6 @@ jobs: JS_SOURCE: ${{ steps.filter.outputs.js_source }} CI_CHANGED: ${{ steps.filter.outputs.ci }} E2E_TESTS: ${{ steps.filter.outputs.e2e_tests }} - PERF_TESTS: ${{ steps.filter.outputs.perf_tests }} IS_MAIN_OR_RELEASE: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) }} run: | echo "--- Change Detection Summary ---" @@ -73,20 +72,20 @@ jobs: echo "js_source=$JS_SOURCE" echo "ci=$CI_CHANGED" echo "e2e_tests=$E2E_TESTS" - echo "perf_tests=$PERF_TESTS" echo "is_main_or_release=$IS_MAIN_OR_RELEASE" # iOS is needed if: # - iOS native code changed # - JS source changed (may affect native bridges) # - CI config changed (need to validate workflows) - # - E2E or perf tests changed (they test both platforms) + # - E2E tests changed (they test both platforms end-to-end) # - Push to main or release branch (always run everything) + # Note: perf_tests changes only affect the `metrics` job in e2e-v2.yml, + # not the native test suites or sample app builds. if [[ "$IOS_NATIVE" == "true" \ || "$JS_SOURCE" == "true" \ || "$CI_CHANGED" == "true" \ || "$E2E_TESTS" == "true" \ - || "$PERF_TESTS" == "true" \ || "$IS_MAIN_OR_RELEASE" == "true" ]]; then echo "needs_ios=true" >> "$GITHUB_OUTPUT" echo "=> needs_ios=true" @@ -99,13 +98,14 @@ jobs: # - Android native code changed # - JS source changed (may affect native bridges) # - CI config changed (need to validate workflows) - # - E2E or perf tests changed (they test both platforms) + # - E2E tests changed (they test both platforms end-to-end) # - Push to main or release branch (always run everything) + # Note: perf_tests changes only affect the `metrics` job in e2e-v2.yml, + # not the native test suites or sample app builds. if [[ "$ANDROID_NATIVE" == "true" \ || "$JS_SOURCE" == "true" \ || "$CI_CHANGED" == "true" \ || "$E2E_TESTS" == "true" \ - || "$PERF_TESTS" == "true" \ || "$IS_MAIN_OR_RELEASE" == "true" ]]; then echo "needs_android=true" >> "$GITHUB_OUTPUT" echo "=> needs_android=true" From aa5d8a710bb2d1d25695048eae11fda73f60d7de Mon Sep 17 00:00:00 2001 From: Alexander Pantiukhov Date: Thu, 19 Mar 2026 16:15:04 +0100 Subject: [PATCH 3/6] Smallish workflow update --- .github/workflows/detect-changes.yml | 14 +++++++++++++- .github/workflows/e2e-v2.yml | 3 +++ .github/workflows/native-tests.yml | 3 +++ .github/workflows/sample-application-expo.yml | 3 +++ .github/workflows/sample-application.yml | 3 +++ 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/detect-changes.yml b/.github/workflows/detect-changes.yml index 417a2e7052..813fd9f19e 100644 --- a/.github/workflows/detect-changes.yml +++ b/.github/workflows/detect-changes.yml @@ -1,6 +1,18 @@ name: Detect Changes on: workflow_call: + inputs: + # Pass the caller's event name and ref so we can detect push-to-main/release. + # Inside a reusable workflow github.event_name is always 'workflow_call', + # so the caller must forward the real values explicitly. + caller_event_name: + description: 'The triggering event name from the caller (github.event_name)' + required: true + type: string + caller_ref: + description: 'The triggering ref from the caller (github.ref)' + required: true + type: string outputs: # Raw filter outputs ios_native: @@ -64,7 +76,7 @@ jobs: JS_SOURCE: ${{ steps.filter.outputs.js_source }} CI_CHANGED: ${{ steps.filter.outputs.ci }} E2E_TESTS: ${{ steps.filter.outputs.e2e_tests }} - IS_MAIN_OR_RELEASE: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) }} + IS_MAIN_OR_RELEASE: ${{ inputs.caller_event_name == 'push' && (inputs.caller_ref == 'refs/heads/main' || startsWith(inputs.caller_ref, 'refs/heads/release/')) }} run: | echo "--- Change Detection Summary ---" echo "ios_native=$IOS_NATIVE" diff --git a/.github/workflows/e2e-v2.yml b/.github/workflows/e2e-v2.yml index 686ab5a0c2..1f5846d363 100644 --- a/.github/workflows/e2e-v2.yml +++ b/.github/workflows/e2e-v2.yml @@ -32,6 +32,9 @@ jobs: detect-changes: needs: [ready-to-merge-gate] uses: ./.github/workflows/detect-changes.yml + with: + caller_event_name: ${{ github.event_name }} + caller_ref: ${{ github.ref }} auth_token_check: uses: ./.github/workflows/skip-ci-noauth.yml secrets: inherit diff --git a/.github/workflows/native-tests.yml b/.github/workflows/native-tests.yml index 1c8fc951ce..c8e0fa50bb 100644 --- a/.github/workflows/native-tests.yml +++ b/.github/workflows/native-tests.yml @@ -27,6 +27,9 @@ jobs: detect-changes: needs: [ready-to-merge-gate] uses: ./.github/workflows/detect-changes.yml + with: + caller_event_name: ${{ github.event_name }} + caller_ref: ${{ github.ref }} test-ios: name: ios diff --git a/.github/workflows/sample-application-expo.yml b/.github/workflows/sample-application-expo.yml index 32f3ea45e0..2c6d402f79 100644 --- a/.github/workflows/sample-application-expo.yml +++ b/.github/workflows/sample-application-expo.yml @@ -30,6 +30,9 @@ jobs: detect-changes: needs: [ready-to-merge-gate] uses: ./.github/workflows/detect-changes.yml + with: + caller_event_name: ${{ github.event_name }} + caller_ref: ${{ github.ref }} build: name: Build ${{ matrix.platform }} ${{ matrix.build-type }} ${{ matrix.ios-use-frameworks}} diff --git a/.github/workflows/sample-application.yml b/.github/workflows/sample-application.yml index 97e29c3b3b..e4976fa949 100644 --- a/.github/workflows/sample-application.yml +++ b/.github/workflows/sample-application.yml @@ -38,6 +38,9 @@ jobs: detect-changes: needs: [ready-to-merge-gate] uses: ./.github/workflows/detect-changes.yml + with: + caller_event_name: ${{ github.event_name }} + caller_ref: ${{ github.ref }} build: name: Build ${{ matrix.rn-architecture }} ${{ matrix.platform }} ${{ matrix.build-type }} ${{ matrix.ios-use-frameworks}} From 9972c54be220038b53ecaa460fcaff96259c2951 Mon Sep 17 00:00:00 2001 From: Alexander Pantiukhov Date: Thu, 19 Mar 2026 16:38:47 +0100 Subject: [PATCH 4/6] Detect changes to sample apps --- .github/file-filters.yml | 28 +++--- .github/workflows/detect-changes.yml | 93 ++++++++++++++----- .github/workflows/sample-application-expo.yml | 2 +- .github/workflows/sample-application.yml | 4 +- 4 files changed, 88 insertions(+), 39 deletions(-) diff --git a/.github/file-filters.yml b/.github/file-filters.yml index fa5c8b5b2d..3d0cf6eb3a 100644 --- a/.github/file-filters.yml +++ b/.github/file-filters.yml @@ -20,26 +20,19 @@ high_risk_code: &high_risk_code # --- Platform-specific filters for CI optimization --- # Used by detect-changes.yml to skip platform-irrelevant CI jobs. -# Changes that affect iOS native code +# Changes to the SDK's iOS native code only (packages/core). +# Does NOT include sample apps — sample changes have their own filters below. ios_native: - 'packages/core/ios/**' - 'packages/core/RNSentryCocoaTester/**' - 'packages/core/RNSentry.podspec' - - 'samples/react-native/ios/**' - - 'samples/react-native/scripts/*ios*' - - 'samples/react-native/scripts/pod-install.sh' - - 'samples/react-native/Gemfile' - - 'samples/react-native-macos/**' - - 'samples/expo/ios/**' -# Changes that affect Android native code +# Changes to the SDK's Android native code only (packages/core). +# Does NOT include sample apps — sample changes have their own filters below. android_native: - 'packages/core/android/**' - 'packages/core/RNSentryAndroidTester/**' - 'packages/core/sentry.gradle' - - 'samples/react-native/android/**' - - 'samples/react-native/scripts/*android*' - - 'samples/expo/android/**' # Changes to JS/TS source code (affects ALL platforms) js_source: @@ -53,6 +46,19 @@ js_source: js_test: - 'packages/core/test/**' +# Changes to the React Native sample app. +# Triggers: sample-application.yml, buildandtest.yml (job_bundle). +# Does NOT trigger: native-tests.yml, e2e-v2.yml, sample-application-expo.yml. +sample_react_native: + - 'samples/react-native/**' + - 'samples/react-native-macos/**' + +# Changes to the Expo sample app. +# Triggers: sample-application-expo.yml only. +# Does NOT trigger: native-tests.yml, e2e-v2.yml, sample-application.yml. +sample_expo: + - 'samples/expo/**' + # Changes to E2E test infrastructure e2e_tests: - 'dev-packages/e2e-tests/**' diff --git a/.github/workflows/detect-changes.yml b/.github/workflows/detect-changes.yml index 813fd9f19e..648d748fed 100644 --- a/.github/workflows/detect-changes.yml +++ b/.github/workflows/detect-changes.yml @@ -14,12 +14,12 @@ on: required: true type: string outputs: - # Raw filter outputs + # Raw filter outputs — exposed for fine-grained use by callers ios_native: - description: 'Whether iOS native files changed' + description: 'Whether SDK iOS native files changed' value: ${{ jobs.changes.outputs.ios_native }} android_native: - description: 'Whether Android native files changed' + description: 'Whether SDK Android native files changed' value: ${{ jobs.changes.outputs.android_native }} js_source: description: 'Whether JS/TS source files changed' @@ -27,23 +27,34 @@ on: js_test: description: 'Whether JS/TS test files changed' value: ${{ jobs.changes.outputs.js_test }} + sample_react_native: + description: 'Whether the React Native sample app changed' + value: ${{ jobs.changes.outputs.sample_react_native }} + sample_expo: + description: 'Whether the Expo sample app changed' + value: ${{ jobs.changes.outputs.sample_expo }} e2e_tests: - description: 'Whether E2E test files changed' + description: 'Whether E2E test infrastructure changed' value: ${{ jobs.changes.outputs.e2e_tests }} perf_tests: - description: 'Whether performance test files changed' + description: 'Whether performance test infrastructure changed' value: ${{ jobs.changes.outputs.perf_tests }} ci: - description: 'Whether CI workflow files changed' + description: 'Whether CI workflow/action files changed' value: ${{ jobs.changes.outputs.ci }} - # Convenience: should iOS-related jobs run? + # Convenience outputs consumed by individual workflows needs_ios: - description: 'Whether iOS jobs should run' + description: 'Whether iOS jobs should run (native tests, E2E, sample builds)' value: ${{ jobs.changes.outputs.needs_ios }} - # Convenience: should Android-related jobs run? needs_android: - description: 'Whether Android jobs should run' + description: 'Whether Android jobs should run (native tests, E2E, sample builds)' value: ${{ jobs.changes.outputs.needs_android }} + needs_sample_react_native: + description: 'Whether the React Native sample app workflow should run' + value: ${{ jobs.changes.outputs.needs_sample_react_native }} + needs_sample_expo: + description: 'Whether the Expo sample app workflow should run' + value: ${{ jobs.changes.outputs.needs_sample_expo }} jobs: changes: @@ -54,11 +65,15 @@ jobs: android_native: ${{ steps.filter.outputs.android_native }} js_source: ${{ steps.filter.outputs.js_source }} js_test: ${{ steps.filter.outputs.js_test }} + sample_react_native: ${{ steps.filter.outputs.sample_react_native }} + sample_expo: ${{ steps.filter.outputs.sample_expo }} e2e_tests: ${{ steps.filter.outputs.e2e_tests }} perf_tests: ${{ steps.filter.outputs.perf_tests }} ci: ${{ steps.filter.outputs.ci }} needs_ios: ${{ steps.evaluate.outputs.needs_ios }} needs_android: ${{ steps.evaluate.outputs.needs_android }} + needs_sample_react_native: ${{ steps.evaluate.outputs.needs_sample_react_native }} + needs_sample_expo: ${{ steps.evaluate.outputs.needs_sample_expo }} steps: - uses: actions/checkout@v4 @@ -68,12 +83,14 @@ jobs: with: filters: .github/file-filters.yml - - name: Evaluate platform needs + - name: Evaluate what needs to run id: evaluate env: IOS_NATIVE: ${{ steps.filter.outputs.ios_native }} ANDROID_NATIVE: ${{ steps.filter.outputs.android_native }} JS_SOURCE: ${{ steps.filter.outputs.js_source }} + SAMPLE_RN: ${{ steps.filter.outputs.sample_react_native }} + SAMPLE_EXPO: ${{ steps.filter.outputs.sample_expo }} CI_CHANGED: ${{ steps.filter.outputs.ci }} E2E_TESTS: ${{ steps.filter.outputs.e2e_tests }} IS_MAIN_OR_RELEASE: ${{ inputs.caller_event_name == 'push' && (inputs.caller_ref == 'refs/heads/main' || startsWith(inputs.caller_ref, 'refs/heads/release/')) }} @@ -82,18 +99,22 @@ jobs: echo "ios_native=$IOS_NATIVE" echo "android_native=$ANDROID_NATIVE" echo "js_source=$JS_SOURCE" + echo "sample_react_native=$SAMPLE_RN" + echo "sample_expo=$SAMPLE_EXPO" echo "ci=$CI_CHANGED" echo "e2e_tests=$E2E_TESTS" echo "is_main_or_release=$IS_MAIN_OR_RELEASE" - # iOS is needed if: - # - iOS native code changed + # iOS/Android native test suites and E2E builds run when: + # - The SDK's own native code changed (packages/core/ios or android) # - JS source changed (may affect native bridges) - # - CI config changed (need to validate workflows) - # - E2E tests changed (they test both platforms end-to-end) + # - CI config changed (need to validate workflows themselves) + # - E2E test infra changed (they test both platforms end-to-end) # - Push to main or release branch (always run everything) - # Note: perf_tests changes only affect the `metrics` job in e2e-v2.yml, - # not the native test suites or sample app builds. + # Sample app changes do NOT trigger the full native test suite — + # they only trigger their own sample-application workflows. + # Performance test changes do NOT trigger native tests either — + # they only trigger the metrics job in e2e-v2.yml. if [[ "$IOS_NATIVE" == "true" \ || "$JS_SOURCE" == "true" \ || "$CI_CHANGED" == "true" \ @@ -106,14 +127,6 @@ jobs: echo "=> needs_ios=false" fi - # Android is needed if: - # - Android native code changed - # - JS source changed (may affect native bridges) - # - CI config changed (need to validate workflows) - # - E2E tests changed (they test both platforms end-to-end) - # - Push to main or release branch (always run everything) - # Note: perf_tests changes only affect the `metrics` job in e2e-v2.yml, - # not the native test suites or sample app builds. if [[ "$ANDROID_NATIVE" == "true" \ || "$JS_SOURCE" == "true" \ || "$CI_CHANGED" == "true" \ @@ -125,3 +138,33 @@ jobs: echo "needs_android=false" >> "$GITHUB_OUTPUT" echo "=> needs_android=false" fi + + # React Native sample workflow runs when the RN sample itself changed, + # or when anything that the sample depends on changed (SDK source, CI). + if [[ "$SAMPLE_RN" == "true" \ + || "$JS_SOURCE" == "true" \ + || "$IOS_NATIVE" == "true" \ + || "$ANDROID_NATIVE" == "true" \ + || "$CI_CHANGED" == "true" \ + || "$IS_MAIN_OR_RELEASE" == "true" ]]; then + echo "needs_sample_react_native=true" >> "$GITHUB_OUTPUT" + echo "=> needs_sample_react_native=true" + else + echo "needs_sample_react_native=false" >> "$GITHUB_OUTPUT" + echo "=> needs_sample_react_native=false" + fi + + # Expo sample workflow runs when the Expo sample itself changed, + # or when anything that the sample depends on changed (SDK source, CI). + if [[ "$SAMPLE_EXPO" == "true" \ + || "$JS_SOURCE" == "true" \ + || "$IOS_NATIVE" == "true" \ + || "$ANDROID_NATIVE" == "true" \ + || "$CI_CHANGED" == "true" \ + || "$IS_MAIN_OR_RELEASE" == "true" ]]; then + echo "needs_sample_expo=true" >> "$GITHUB_OUTPUT" + echo "=> needs_sample_expo=true" + else + echo "needs_sample_expo=false" >> "$GITHUB_OUTPUT" + echo "=> needs_sample_expo=false" + fi diff --git a/.github/workflows/sample-application-expo.yml b/.github/workflows/sample-application-expo.yml index 2c6d402f79..907eb05db6 100644 --- a/.github/workflows/sample-application-expo.yml +++ b/.github/workflows/sample-application-expo.yml @@ -38,7 +38,7 @@ jobs: name: Build ${{ matrix.platform }} ${{ matrix.build-type }} ${{ matrix.ios-use-frameworks}} runs-on: ${{ matrix.runs-on }} needs: [diff_check, detect-changes] - if: ${{ needs.diff_check.outputs.skip_ci != 'true' }} + if: ${{ needs.diff_check.outputs.skip_ci != 'true' && needs.detect-changes.outputs.needs_sample_expo == 'true' }} env: SENTRY_DISABLE_AUTO_UPLOAD: 'true' strategy: diff --git a/.github/workflows/sample-application.yml b/.github/workflows/sample-application.yml index e4976fa949..f799b05fd6 100644 --- a/.github/workflows/sample-application.yml +++ b/.github/workflows/sample-application.yml @@ -46,7 +46,7 @@ jobs: name: Build ${{ matrix.rn-architecture }} ${{ matrix.platform }} ${{ matrix.build-type }} ${{ matrix.ios-use-frameworks}} runs-on: ${{ matrix.runs-on }} needs: [diff_check, detect-changes] - if: ${{ needs.diff_check.outputs.skip_ci != 'true' }} + if: ${{ needs.diff_check.outputs.skip_ci != 'true' && needs.detect-changes.outputs.needs_sample_react_native == 'true' }} env: SENTRY_DISABLE_AUTO_UPLOAD: 'true' strategy: @@ -238,7 +238,7 @@ jobs: name: Test ${{ matrix.platform }} ${{ matrix.build-type }} REV2 runs-on: ${{ matrix.runs-on }} needs: [diff_check, detect-changes, build] - if: ${{ needs.diff_check.outputs.skip_ci != 'true' }} + if: ${{ needs.diff_check.outputs.skip_ci != 'true' && needs.detect-changes.outputs.needs_sample_react_native == 'true' }} strategy: # we want that the matrix keeps running, default is to cancel them if it fails. fail-fast: false From 10e98a61943ec741ecfd2d9a3edf9be862cc4dd3 Mon Sep 17 00:00:00 2001 From: Alexander Pantiukhov Date: Fri, 20 Mar 2026 09:55:16 +0100 Subject: [PATCH 5/6] fix(ci): Include sample app and perf test changes in step-level platform gates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The step-level platform-check in sample-application, sample-application-expo, and e2e-v2 workflows gated on needs_ios/needs_android, which only track SDK source and native code changes. When only sample app or performance test files changed, the job-level condition correctly triggered (via needs_sample_react_native, needs_sample_expo), but every platform step was skipped — runners allocated, zero meaningful work done, false green reported. Fix by checking sample_react_native/sample_expo/perf_tests as the first condition in each platform-check step. If the relevant files changed, all platforms proceed without skipping. Affected workflows: - sample-application.yml: build and test jobs (sample_react_native) - sample-application-expo.yml: build job (sample_expo) - e2e-v2.yml: metrics job (perf_tests) --- .github/workflows/e2e-v2.yml | 10 +++++++++- .github/workflows/sample-application-expo.yml | 7 ++++++- .github/workflows/sample-application.yml | 17 +++++++++++++++-- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/.github/workflows/e2e-v2.yml b/.github/workflows/e2e-v2.yml index 1f5846d363..54b06f0500 100644 --- a/.github/workflows/e2e-v2.yml +++ b/.github/workflows/e2e-v2.yml @@ -65,7 +65,15 @@ jobs: - name: Check if platform is needed id: platform-check run: | - if [[ "${{ matrix.platform }}" == "ios" && "${{ needs.detect-changes.outputs.needs_ios }}" != "true" ]]; then + # Performance test changes should always run metrics (that's the + # whole point). The needs_ios/needs_android flags only track SDK + # source & native code — not performance-tests/** files. + PERF_CHANGED="${{ needs.detect-changes.outputs.perf_tests }}" + + if [[ "$PERF_CHANGED" == "true" ]]; then + echo "skip=false" >> "$GITHUB_OUTPUT" + echo "Performance tests changed — running metrics for ${{ matrix.platform }}." + elif [[ "${{ matrix.platform }}" == "ios" && "${{ needs.detect-changes.outputs.needs_ios }}" != "true" ]]; then echo "skip=true" >> "$GITHUB_OUTPUT" echo "Skipping iOS — no relevant changes detected." elif [[ "${{ matrix.platform }}" == "android" && "${{ needs.detect-changes.outputs.needs_android }}" != "true" ]]; then diff --git a/.github/workflows/sample-application-expo.yml b/.github/workflows/sample-application-expo.yml index 907eb05db6..590344de12 100644 --- a/.github/workflows/sample-application-expo.yml +++ b/.github/workflows/sample-application-expo.yml @@ -62,7 +62,12 @@ jobs: - name: Check if platform is needed id: platform-check run: | - if [[ "${{ matrix.platform }}" == "ios" && "${{ needs.detect-changes.outputs.needs_ios }}" != "true" ]]; then + SAMPLE_CHANGED="${{ needs.detect-changes.outputs.sample_expo }}" + + if [[ "$SAMPLE_CHANGED" == "true" ]]; then + echo "skip=false" >> "$GITHUB_OUTPUT" + echo "Sample app changed — building ${{ matrix.platform }}." + elif [[ "${{ matrix.platform }}" == "ios" && "${{ needs.detect-changes.outputs.needs_ios }}" != "true" ]]; then echo "skip=true" >> "$GITHUB_OUTPUT" echo "Skipping iOS — no relevant changes detected." elif [[ "${{ matrix.platform }}" == "android" && "${{ needs.detect-changes.outputs.needs_android }}" != "true" ]]; then diff --git a/.github/workflows/sample-application.yml b/.github/workflows/sample-application.yml index f799b05fd6..fe90ca546e 100644 --- a/.github/workflows/sample-application.yml +++ b/.github/workflows/sample-application.yml @@ -77,7 +77,15 @@ jobs: - name: Check if platform is needed id: platform-check run: | - if [[ "${{ matrix.platform }}" == "ios" && "${{ needs.detect-changes.outputs.needs_ios }}" != "true" ]]; then + # Sample app changes should always build all platforms (that's the + # whole point of this workflow). The needs_ios/needs_android flags + # only track SDK source & native code — not sample app files. + SAMPLE_CHANGED="${{ needs.detect-changes.outputs.sample_react_native }}" + + if [[ "$SAMPLE_CHANGED" == "true" ]]; then + echo "skip=false" >> "$GITHUB_OUTPUT" + echo "Sample app changed — building ${{ matrix.platform }}." + elif [[ "${{ matrix.platform }}" == "ios" && "${{ needs.detect-changes.outputs.needs_ios }}" != "true" ]]; then echo "skip=true" >> "$GITHUB_OUTPUT" echo "Skipping iOS — no relevant changes detected." elif [[ "${{ matrix.platform }}" == "macos" && "${{ needs.detect-changes.outputs.needs_ios }}" != "true" ]]; then @@ -259,7 +267,12 @@ jobs: - name: Check if platform is needed id: platform-check run: | - if [[ "${{ matrix.platform }}" == "ios" && "${{ needs.detect-changes.outputs.needs_ios }}" != "true" ]]; then + SAMPLE_CHANGED="${{ needs.detect-changes.outputs.sample_react_native }}" + + if [[ "$SAMPLE_CHANGED" == "true" ]]; then + echo "skip=false" >> "$GITHUB_OUTPUT" + echo "Sample app changed — testing ${{ matrix.platform }}." + elif [[ "${{ matrix.platform }}" == "ios" && "${{ needs.detect-changes.outputs.needs_ios }}" != "true" ]]; then echo "skip=true" >> "$GITHUB_OUTPUT" echo "Skipping iOS — no relevant changes detected." elif [[ "${{ matrix.platform }}" == "android" && "${{ needs.detect-changes.outputs.needs_android }}" != "true" ]]; then From 5513a3fe5d4cfd7385623de2894f01453c7b943f Mon Sep 17 00:00:00 2001 From: Alexander Pantiukhov Date: Fri, 20 Mar 2026 10:25:10 +0100 Subject: [PATCH 6/6] fix(ci): Remove leading space in ruby/setup-ruby working-directory for Expo sample The working-directory value had a leading space (' samples/expo') due to an unnecessary ternary expression. Since the step is already guarded by an if condition checking matrix.platform == 'ios', the ternary was redundant. Simplified to the plain path 'samples/expo'. --- .github/workflows/sample-application-expo.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sample-application-expo.yml b/.github/workflows/sample-application-expo.yml index 590344de12..061deb792b 100644 --- a/.github/workflows/sample-application-expo.yml +++ b/.github/workflows/sample-application-expo.yml @@ -99,7 +99,7 @@ jobs: - uses: ruby/setup-ruby@v1 if: ${{ steps.platform-check.outputs.skip != 'true' && matrix.platform == 'ios' }} with: - working-directory: ${{ matrix.platform == 'ios' && ' samples/expo' }} + working-directory: samples/expo ruby-version: '3.3.0' # based on what is used in the sample bundler-cache: true # runs 'bundle install' and caches installed gems automatically cache-version: 1 # cache the installed gems