From a610498bc3649cf488aa6f57bc06b2c274742829 Mon Sep 17 00:00:00 2001 From: Kyle McDonald Date: Wed, 8 Jul 2026 10:23:00 -0500 Subject: [PATCH 1/2] ci: split Expo build into scoped bundle check and reserved native build Replace the single per-PR native EAS build with two workflows: - expo-bundle.yml: fast local `expo export` Metro bundle check, path-scoped to the types/client/react-core/react-native/expo dependency chain. No EXPO_TOKEN or EAS credits. - expo-native.yml: full native EAS build reserved for push to main, workflow_dispatch, and PRs labeled `expo:native-build`. Closes KNO-14076. --- .github/workflows/expo-bundle.yml | 45 +++++++++++++++++++++++++ .github/workflows/expo-native.yml | 55 +++++++++++++++++++++++++++++++ .github/workflows/expo.yml | 31 ----------------- 3 files changed, 100 insertions(+), 31 deletions(-) create mode 100644 .github/workflows/expo-bundle.yml create mode 100644 .github/workflows/expo-native.yml delete mode 100644 .github/workflows/expo.yml diff --git a/.github/workflows/expo-bundle.yml b/.github/workflows/expo-bundle.yml new file mode 100644 index 000000000..1420618ea --- /dev/null +++ b/.github/workflows/expo-bundle.yml @@ -0,0 +1,45 @@ +name: Expo Bundle Check +on: + pull_request: + paths: + - "packages/types/**" + - "packages/client/**" + - "packages/react-core/**" + - "packages/react-native/**" + - "packages/expo/**" + - "examples/expo-example/**" + - ".github/workflows/expo-bundle.yml" + - "yarn.lock" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + bundle: + name: Metro bundle + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: "22.x" + cache: yarn + registry-url: "https://registry.npmjs.org" + scope: "@knocklabs" + - name: Install dependencies + run: yarn install --immutable + - name: Build packages + run: yarn build:packages + # Exercises the @knocklabs/* module graph under React Native's Metro + # resolver (conditional "react-native" exports resolve to source). This + # is what catches an upstream client/react-core change that breaks how + # the react-native / expo packages bundle. Fully local: no EXPO_TOKEN, + # no EAS credits. EXPO_PUBLIC_* vars are optional for bundling. + - name: Metro bundle expo example + working-directory: examples/expo-example + run: yarn expo export --platform android --output-dir "$RUNNER_TEMP/expo-export" diff --git a/.github/workflows/expo-native.yml b/.github/workflows/expo-native.yml new file mode 100644 index 000000000..f698e2b0d --- /dev/null +++ b/.github/workflows/expo-native.yml @@ -0,0 +1,55 @@ +name: Expo Native Build +on: + # Post-merge native signal — catches native-only regressions (Expo SDK / + # native module bumps) that the per-PR Metro bundle check can't see. + push: + branches: + - main + paths: + - "packages/types/**" + - "packages/client/**" + - "packages/react-core/**" + - "packages/react-native/**" + - "packages/expo/**" + - "examples/expo-example/**" + - ".github/workflows/expo-native.yml" + - "yarn.lock" + # Opt-in on a risky PR: add the `expo:native-build` label to run the full build. + pull_request: + types: [labeled] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: EAS build (Android) + # On pull_request this only runs for the opt-in label; push/dispatch always run. + if: >- + github.event_name != 'pull_request' || + github.event.label.name == 'expo:native-build' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: "22.x" + cache: yarn + registry-url: "https://registry.npmjs.org" + scope: "@knocklabs" + - name: Install dependencies + run: yarn install --immutable + - name: Build packages + run: yarn build:packages + - name: Setup Expo and EAS + uses: expo/expo-github-action@c7b66a9c327a43a8fa7c0158e7f30d6040d2481e # 8.2.1 + with: + eas-version: latest + token: ${{ secrets.EXPO_TOKEN }} + - name: Build on EAS + run: cd examples/expo-example && eas build --platform android --profile preview --non-interactive diff --git a/.github/workflows/expo.yml b/.github/workflows/expo.yml deleted file mode 100644 index 253d6a04a..000000000 --- a/.github/workflows/expo.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Expo Build -on: - pull_request: - workflow_dispatch: - -permissions: - contents: read - -jobs: - build: - name: Install and build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version: "22.x" - cache: yarn - registry-url: "https://registry.npmjs.org" - scope: "@knocklabs" - - name: Install Dependencies - run: yarn install - - name: Build packages - run: yarn build:packages - - name: Setup Expo and EAS - uses: expo/expo-github-action@c7b66a9c327a43a8fa7c0158e7f30d6040d2481e # 8.2.1 - with: - eas-version: latest - token: ${{ secrets.EXPO_TOKEN }} - - name: Build on EAS - run: cd examples/expo-example && eas build --platform android --non-interactive From 966721d043cbf9d62d5147d9bfb1b027da35f224 Mon Sep 17 00:00:00 2001 From: Kyle McDonald Date: Wed, 8 Jul 2026 10:38:55 -0500 Subject: [PATCH 2/2] fix(ci): scope Expo native build concurrency to avoid canceling opt-in builds An unrelated `labeled` event on the same PR spun up a run in the same concurrency group and, via cancel-in-progress, killed an in-flight opt-in EAS build before its job's if-guard skipped it. Add the label/event as a group discriminator so only matching runs coalesce. Addresses comment by @cursor: unrelated labels cancel native build. --- .github/workflows/expo-native.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/expo-native.yml b/.github/workflows/expo-native.yml index f698e2b0d..66161a0c5 100644 --- a/.github/workflows/expo-native.yml +++ b/.github/workflows/expo-native.yml @@ -23,7 +23,10 @@ permissions: contents: read concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + # Include the label (or event) in the group so an unrelated `labeled` event on + # the same PR lands in a different group and can't cancel an in-flight opt-in + # EAS build. Pushes to main still coalesce (they share the `push` discriminator). + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event.label.name || github.event_name }} cancel-in-progress: true jobs: