Skip to content

chore(expo): bump clerk-ios to 1.6.0 #1115

chore(expo): bump clerk-ios to 1.6.0

chore(expo): bump clerk-ios to 1.6.0 #1115

name: Expo
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
branches:
- main
paths:
- '.github/workflows/expo-native-build.yml'
- 'integration/e2e.expo-native.config.ts'
- 'integration/templates/expo-native/**'
- 'integration/tests/expo-native/**'
- 'packages/expo/**'
- 'packages/expo-biometrics/**'
- 'packages/expo-google-signin/**'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: expo-native-${{ github.head_ref || github.ref }}
cancel-in-progress: true
env:
FIXTURE_DIR: integration/templates/expo-native
E2E_DIR: integration/tests/expo-native
FIXTURE_PUBLISHABLE_KEY: pk_test_ZHVtbXkuY2xlcmsuYWNjb3VudHMuZGV2JA
SDK_PACK_DIR: /tmp/clerk-expo-pack
E2E_INSTANCE_NAME: clerkstage-with-native-components
BAPI_URL: https://api.clerkstage.dev
IOS_SIMULATORS: '2'
E2E_TELEMETRY_DISABLED: '1'
jobs:
native-build:
if: ${{ github.head_ref != 'changeset-release/main' && (github.event_name == 'workflow_dispatch' || github.event.pull_request.draft == false) }}
name: Native ${{ matrix.run-e2e == true && 'E2E' || 'Build' }} (${{ matrix.platform }}, sdk ${{ matrix.expo-sdk }})
runs-on: ${{ matrix.runner }}
timeout-minutes: ${{ matrix.run-e2e == true && 60 || 45 }}
env:
CLERK_TEST_USERNAME_PREFIX: e2e_${{ github.run_id }}_${{ matrix.platform }}_
strategy:
fail-fast: false
matrix:
include:
- expo-sdk: 54
platform: android
runner: blacksmith-8vcpu-ubuntu-2204
- expo-sdk: 54
platform: ios
runner: blacksmith-6vcpu-macos-26
- expo-sdk: 55
platform: android
runner: blacksmith-8vcpu-ubuntu-2204
- expo-sdk: 55
platform: ios
runner: blacksmith-6vcpu-macos-26
- expo-sdk: 57
platform: android
runner: blacksmith-8vcpu-ubuntu-2204
run-e2e: true
- expo-sdk: 57
platform: ios
runner: blacksmith-6vcpu-macos-26
run-e2e: true
steps:
- name: Checkout repo
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
persist-credentials: false
- name: Compute native build cache key
id: native-build-key
env:
PLATFORM: ${{ matrix.platform }}
run: |
build_hash="$(
git ls-files -s -- \
.npmrc \
package.json \
pnpm-lock.yaml \
pnpm-workspace.yaml \
tsconfig.json \
turbo.json \
packages/clerk-js \
packages/expo \
packages/expo-biometrics \
packages/expo-google-signin \
packages/react \
packages/shared \
"$FIXTURE_DIR" |
git hash-object --stdin
)"
if [ "$PLATFORM" = "android" ]; then
artifact="$FIXTURE_DIR/android/app/build/outputs/apk/release/app-release.apk"
else
artifact="$FIXTURE_DIR/ios/build/Build/Products/Release-iphonesimulator/ClerkExpoNativeBuildFixture.app"
fi
echo "hash=$build_hash" >> "$GITHUB_OUTPUT"
echo "artifact=$artifact" >> "$GITHUB_OUTPUT"
- name: Restore native build
id: native-build-cache
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ${{ steps.native-build-key.outputs.artifact }}
# Bump the version when native build commands change.
key: expo-native-build-v1-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }}
- if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true
uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4
- if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 24.15.0
cache: pnpm
- name: Install monorepo dependencies
if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true
run: pnpm install --frozen-lockfile
- name: Build and pack Clerk packages
if: steps.native-build-cache.outputs.cache-hit != 'true'
run: |
pnpm --filter @clerk/expo... --filter @clerk/expo-biometrics build
mkdir -p "$SDK_PACK_DIR"
pnpm --filter @clerk/expo pack --pack-destination "$SDK_PACK_DIR"
pnpm --filter @clerk/expo-google-signin pack --pack-destination "$SDK_PACK_DIR"
pnpm --filter @clerk/expo-biometrics pack --pack-destination "$SDK_PACK_DIR"
- name: Install fixture dependencies
if: steps.native-build-cache.outputs.cache-hit != 'true'
working-directory: ${{ env.FIXTURE_DIR }}
env:
EXPO_SDK: ${{ matrix.expo-sdk }}
RUN_E2E: ${{ matrix.run-e2e == true && 'true' || 'false' }}
run: |
cp "package.sdk-$EXPO_SDK.json" package.json
pnpm install --no-frozen-lockfile
# [0-9] keeps this glob off the clerk-expo-google-signin tarball.
SDK_TARBALL="$(ls "$SDK_PACK_DIR"/clerk-expo-[0-9]*.tgz)"
GOOGLE_SIGNIN_TARBALL="$(ls "$SDK_PACK_DIR"/clerk-expo-google-signin-*.tgz)"
BIOMETRICS_TARBALL="$(ls "$SDK_PACK_DIR"/clerk-expo-biometrics-*.tgz)"
pnpm add "$SDK_TARBALL" "$GOOGLE_SIGNIN_TARBALL" "$BIOMETRICS_TARBALL" -w
# expo-dev-client makes even release builds boot into the dev
# launcher (unreachable Metro in CI), which stalls every e2e
# flow on a blank screen. Skip it on e2e jobs only.
DEV_CLIENT="expo-dev-client"
if [ "$RUN_E2E" = "true" ]; then DEV_CLIENT=""; fi
pnpm expo install expo-auth-session expo-constants expo-crypto $DEV_CLIENT expo-secure-store expo-web-browser
if [ "$RUN_E2E" = "true" ]; then
REACT_VERSION=$(node -p 'require("react/package.json").version')
REACT_DOM_VERSION=$(node -p 'require("react-dom/package.json").version')
if [ "$REACT_VERSION" != "$REACT_DOM_VERSION" ]; then
echo "::error::React version mismatch: react@$REACT_VERSION, react-dom@$REACT_DOM_VERSION"
exit 1
fi
fi
- name: Check e2e secret availability
id: gate
if: matrix.run-e2e == true
env:
KEYS: ${{ secrets.INTEGRATION_STAGING_INSTANCE_KEYS }}
run: |
if [ -n "$KEYS" ]; then
echo "ok=true" >> "$GITHUB_OUTPUT"
else
echo "ok=false" >> "$GITHUB_OUTPUT"
echo "::notice::INTEGRATION_STAGING_INSTANCE_KEYS unavailable (fork PR?); running build-only."
fi
- name: Resolve Clerk instance keys
id: keys
if: steps.gate.outputs.ok == 'true'
continue-on-error: true
env:
INTEGRATION_STAGING_INSTANCE_KEYS: ${{ secrets.INTEGRATION_STAGING_INSTANCE_KEYS }}
run: node scripts/resolve-instance-keys.mjs INTEGRATION_STAGING_INSTANCE_KEYS "$E2E_INSTANCE_NAME"
- name: Write fixture .env
if: steps.native-build-cache.outputs.cache-hit != 'true'
working-directory: ${{ env.FIXTURE_DIR }}
env:
E2E_PK: ${{ steps.keys.outputs.pk }}
run: |
echo "EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=${E2E_PK:-$FIXTURE_PUBLISHABLE_KEY}" > .env
- name: Set up JDK 17
if: matrix.platform == 'android'
uses: actions/setup-java@cf277c60eb25467037889841efdb72551f06f6c3 # v4
with:
distribution: temurin
java-version: 17
- name: Set up Gradle cache
if: matrix.platform == 'android' && steps.native-build-cache.outputs.cache-hit != 'true'
uses: gradle/actions/setup-gradle@4733eaac7c1b0da527e4206b7671e0061de1ce37 # v6.3.0
with:
# This workflow never runs on main, so the default (write from main
# only) would never seed the cache.
cache-read-only: false
add-job-summary: on-failure
- name: Prebuild Android fixture
if: matrix.platform == 'android' && steps.native-build-cache.outputs.cache-hit != 'true'
working-directory: ${{ env.FIXTURE_DIR }}
run: pnpm expo prebuild --clean --platform android
- name: Build Android fixture
if: matrix.platform == 'android' && steps.native-build-cache.outputs.cache-hit != 'true'
working-directory: ${{ env.FIXTURE_DIR }}
run: pnpm build:android
# The module's Robolectric tests need an Expo host project for expo-modules-core, so they run in the fixture.
# The packed module leaves out its tests, so they are copied in from the repo.
- name: Test expo-biometrics Android module
if: matrix.platform == 'android' && steps.native-build-cache.outputs.cache-hit != 'true'
working-directory: ${{ env.FIXTURE_DIR }}/android
run: |
cp -R "$GITHUB_WORKSPACE/packages/expo-biometrics/android/src/test" "$(readlink -f ../node_modules/@clerk/expo-biometrics)/android/src/"
./gradlew :clerk-expo-biometrics:testDebugUnitTest
- name: Prebuild iOS fixture
if: matrix.platform == 'ios' && steps.native-build-cache.outputs.cache-hit != 'true'
working-directory: ${{ env.FIXTURE_DIR }}
run: pnpm expo prebuild --clean --platform ios
- name: Build iOS fixture
if: matrix.platform == 'ios' && steps.native-build-cache.outputs.cache-hit != 'true'
working-directory: ${{ env.FIXTURE_DIR }}
run: pnpm build:ios
- name: Save native build
if: steps.native-build-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ${{ steps.native-build-key.outputs.artifact }}
key: ${{ steps.native-build-cache.outputs.cache-primary-key }}
- name: Boot iOS simulators
if: matrix.platform == 'ios' && matrix.run-e2e == true && steps.keys.outputs.pk != ''
run: ${{ env.E2E_DIR }}/boot-ios-simulators.sh boot "$IOS_SIMULATORS"
- name: Cache iOS automation runner
if: matrix.platform == 'ios' && steps.keys.outputs.pk != ''
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.agent-device
key: agent-device-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: agent-device-${{ runner.os }}-
- name: Run iOS e2e
id: run_e2e_ios
if: matrix.platform == 'ios' && steps.keys.outputs.sk != ''
env:
CLERK_SECRET_KEY: ${{ steps.keys.outputs.sk }}
CLERK_API_URL: ${{ env.BAPI_URL }}
run: |
"$E2E_DIR/boot-ios-simulators.sh" wait
mkdir -p "$RUNNER_TEMP/e2e-device-logs"
log_pids=()
trap 'kill "${log_pids[@]}" 2>/dev/null || true; wait "${log_pids[@]}" 2>/dev/null || true' EXIT
for udid in ${CLERK_TEST_DEVICES//,/ }; do
xcrun simctl install "$udid" "$FIXTURE_DIR/ios/build/Build/Products/Release-iphonesimulator/ClerkExpoNativeBuildFixture.app"
xcrun simctl spawn "$udid" log stream --style compact \
--predicate 'processImagePath CONTAINS "ClerkExpoNativeBuildFixture"' \
> "$RUNNER_TEMP/e2e-device-logs/$udid-console.log" 2>&1 &
log_pids+=($!)
done
pnpm test:integration:expo-native:ios --reporter list,junit,markdown
- name: Enable KVM
if: matrix.platform == 'android' && steps.keys.outputs.sk != ''
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: AVD cache
id: avd-cache
if: matrix.platform == 'android' && steps.keys.outputs.sk != ''
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-34-google_apis-x86_64-v1
- name: Create AVD snapshot
if: matrix.platform == 'android' && steps.keys.outputs.sk != '' && steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d # v2
with:
api-level: 34
target: google_apis
arch: x86_64
force-avd-creation: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim
disable-animations: false
script: echo "Generated AVD snapshot for caching."
- name: Run Android e2e
id: run_e2e_android
if: matrix.platform == 'android' && steps.keys.outputs.sk != ''
uses: reactivecircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d # v2
env:
CLERK_SECRET_KEY: ${{ steps.keys.outputs.sk }}
CLERK_API_URL: ${{ env.BAPI_URL }}
with:
api-level: 34
target: google_apis
arch: x86_64
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim
disable-animations: true
# The action runs each script line in a separate sh -c; the folded
# scalar (>-) plus && keeps everything in one shell invocation.
script: >-
mkdir -p "$RUNNER_TEMP/e2e-device-logs" &&
adb install -r "$FIXTURE_DIR/android/app/build/outputs/apk/release/app-release.apk" &&
(adb logcat -v threadtime > "$RUNNER_TEMP/e2e-device-logs/logcat.log" 2>&1 &) &&
pnpm test:integration:expo-native:android --reporter list,junit,markdown
- name: Delete leftover test users
if: always() && steps.keys.outputs.sk != ''
env:
CLERK_SECRET_KEY: ${{ steps.keys.outputs.sk }}
run: |
curl -fsS -G "$BAPI_URL/v1/users" --data-urlencode "limit=100" --data-urlencode "query=$CLERK_TEST_USERNAME_PREFIX" -H "Authorization: Bearer $CLERK_SECRET_KEY" |
jq -r --arg p "$CLERK_TEST_USERNAME_PREFIX" '.[] | select((.username // "") | startswith($p)) | .id' |
while read -r user_id; do
curl -fsS --retry 3 --retry-delay 1 -o /dev/null -X DELETE "$BAPI_URL/v1/users/$user_id" -H "Authorization: Bearer $CLERK_SECRET_KEY" ||
echo "::warning::Could not delete leftover test user $user_id"
done
- name: Upload e2e artifacts
if: always() && steps.keys.outputs.sk != ''
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: e2e-${{ matrix.platform }}
include-hidden-files: true
path: |
integration/.e2e
${{ runner.temp }}/e2e-device-logs
if-no-files-found: warn
retention-days: 7
- name: Report e2e outcome
if: always() && steps.keys.outputs.sk != ''
env:
IOS_OUTCOME: ${{ steps.run_e2e_ios.outcome }}
ANDROID_OUTCOME: ${{ steps.run_e2e_android.outcome }}
run: |
outcome="$IOS_OUTCOME"
[ "$outcome" = "skipped" ] && outcome="$ANDROID_OUTCOME"
echo "## Native e2e (${{ matrix.platform }}): $outcome" >> "$GITHUB_STEP_SUMMARY"
if [ -f integration/.e2e/summary.md ]; then
cat integration/.e2e/summary.md >> "$GITHUB_STEP_SUMMARY"
fi
if [ "$outcome" = "failure" ]; then
echo "::error::Native e2e failed. See the e2e-${{ matrix.platform }} artifact."
fi
flaky=$(jq -r '[.run.results[] | select(.status == "flaky") | .file] | join(", ")' integration/.e2e/report.json 2>/dev/null || true)
if [ -n "$flaky" ]; then
echo "::error::Flaky flow(s), failed then passed on the retry: $flaky"
exit 1
fi