Skip to content

chore(deps): update dependency metro to ^0.84.0 #150

chore(deps): update dependency metro to ^0.84.0

chore(deps): update dependency metro to ^0.84.0 #150

Workflow file for this run

name: 📱 E2E iOS (Maestro)
on:
pull_request_review:
types: [submitted]
pull_request:
branches:
- main
types: [opened, reopened, synchronize, ready_for_review]
concurrency:
# Key off the PR number (works across pull_request and pull_request_review
# events). Falls back to ref for direct pushes / re-runs.
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.event.review.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
# Run the (expensive) macOS build when:
# - the PR is opened/updated by the repo owner (GSTJ), OR
# - a reviewer has approved the PR (including subsequent pushes to an
# already-approved PR).
approval-gate:
name: 🔐 Approval gate
runs-on: ubuntu-latest
outputs:
approved: ${{ steps.check.outputs.approved }}
steps:
- name: Check for approval (or trusted author)
id: check
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_AUTHOR: ${{ github.event.pull_request.user.login || github.event.review.pull_request.user.login }}
run: |
PR_NUM="${{ github.event.pull_request.number || github.event.review.pull_request.number }}"
if [ -z "$PR_NUM" ]; then
echo "No PR number; skipping."
echo "approved=false" >> "$GITHUB_OUTPUT"
exit 0
fi
# Trusted authors run E2E without needing an approval.
case "$PR_AUTHOR" in
GSTJ)
echo "PR author $PR_AUTHOR is trusted; running E2E."
echo "approved=true" >> "$GITHUB_OUTPUT"
exit 0
;;
esac
# If this run was triggered by a review submission, check it's an approval.
if [ "${{ github.event_name }}" = "pull_request_review" ] && [ "${{ github.event.review.state }}" != "approved" ]; then
echo "Review state is ${{ github.event.review.state }}, not approved."
echo "approved=false" >> "$GITHUB_OUTPUT"
exit 0
fi
# Otherwise look up the latest review per reviewer on this PR.
STATE=$(gh api "repos/${{ github.repository }}/pulls/$PR_NUM/reviews" \
--jq '[.[] | select(.state=="APPROVED" or .state=="CHANGES_REQUESTED")] | sort_by(.submitted_at) | last | .state' \
|| echo "")
if [ "$STATE" = "APPROVED" ]; then
echo "PR is approved."
echo "approved=true" >> "$GITHUB_OUTPUT"
else
echo "PR has no APPROVED review yet (latest review: ${STATE:-none}). Skipping E2E."
echo "approved=false" >> "$GITHUB_OUTPUT"
fi
maestro-ios:
name: 🧪 Maestro smoke tests (iOS sim)
needs: approval-gate
if: needs.approval-gate.outputs.approved == 'true'
runs-on: macos-15
timeout-minutes: 60
env:
EXAMPLE_DIR: examples/kitchen-sink
APP_ID: com.gstj.reactnativemagicmodalexample
steps:
- name: 🏗 Setup Repo
uses: actions/checkout@v4
- name: 🏗 Select Xcode 26 (Swift 6.1+ for expo-modules-core)
run: |
# expo-modules-core 55.x uses @MainActor extension syntax (Swift 6.1+).
# macos-15 default is Xcode 16.4 (Swift 6.0) which can't parse it.
XCODE_PATH=$(ls -d /Applications/Xcode_26*.app 2>/dev/null | head -1)
if [ -z "$XCODE_PATH" ]; then
echo "No Xcode 26 found; falling back to default. Pods may not compile."
xcodebuild -version
else
sudo xcode-select -s "$XCODE_PATH/Contents/Developer"
xcodebuild -version
fi
- name: 🏗 Setup PNPM
uses: pnpm/action-setup@v4
- name: 🏗 Setup Node
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: pnpm
- name: 🏗 Setup Ruby (for CocoaPods)
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.4.9"
bundler-cache: false
- name: 🏗 Install CocoaPods
run: gem install cocoapods --no-document
- name: 🏗 Get PNPM store directory
id: pnpm-cache
run: |
echo "pnpm_cache_dir=$(pnpm store path)" >> "$GITHUB_OUTPUT"
- name: 🏗 Setup PNPM cache
uses: actions/cache@v4
with:
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: 📦 Install Dependencies
run: pnpm install --frozen-lockfile
- name: 🏗 Install ccache (Pods enable it via expo-build-properties)
run: |
brew install ccache
ccache --version
ccache --max-size=2G
echo "CCACHE_DIR=$HOME/.ccache" >> "$GITHUB_ENV"
echo "CCACHE_SLOPPINESS=clang_index_store,file_macro,include_file_mtime,include_file_ctime,time_macros" >> "$GITHUB_ENV"
echo "CCACHE_FILECLONE=true" >> "$GITHUB_ENV"
echo "CCACHE_DEPEND=true" >> "$GITHUB_ENV"
echo "CCACHE_INODECACHE=true" >> "$GITHUB_ENV"
# Split restore + save so the warmed caches get uploaded even when the
# later maestro step fails. actions/cache@v4 only saves on whole-job
# success; restore/save lets us save unconditionally.
- name: 🗄 Restore ccache compiler cache
id: ccache-restore
uses: actions/cache/restore@v4
with:
path: ~/.ccache
key: ${{ runner.os }}-ccache-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-ccache-
- name: 🗄 Restore CocoaPods (specs + downloaded sources)
id: pods-cache-restore
uses: actions/cache/restore@v4
with:
path: |
~/.cocoapods
~/Library/Caches/CocoaPods
key: ${{ runner.os }}-pods-cache-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pods-cache-
- name: 🗄 Restore iOS Pods/build/DerivedData
id: ios-cache-restore
uses: actions/cache/restore@v4
with:
path: |
${{ env.EXAMPLE_DIR }}/ios/Pods
${{ env.EXAMPLE_DIR }}/ios/build
~/Library/Developer/Xcode/DerivedData
# Pods.lock changes when any native dep version moves; keying on
# the workspace lockfile is a safe proxy until ios/Podfile.lock
# is tracked in git.
key: ${{ runner.os }}-ios-pods-derived-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-ios-pods-derived-
- name: 🏗 Install Maestro CLI
run: |
curl -fsSL "https://get.maestro.mobile.dev" | bash
echo "$HOME/.maestro/bin" >> "$GITHUB_PATH"
- name: 🔎 Verify Maestro
run: maestro --version
- name: 📱 Boot iOS Simulator
id: boot-sim
run: |
# Use the latest iPhone simulator already available on the runner image.
DEVICE_UDID=$(xcrun simctl list devices available -j \
| python3 -c "import json,sys; d=json.load(sys.stdin)['devices']; \
rt=sorted([k for k in d if 'iOS' in k]); \
uuids=[x['udid'] for x in d[rt[-1]] if 'iPhone' in x['name']]; \
print(uuids[-1])")
echo "Using simulator UDID: $DEVICE_UDID"
xcrun simctl boot "$DEVICE_UDID" || true
xcrun simctl bootstatus "$DEVICE_UDID" -b
echo "device_udid=$DEVICE_UDID" >> "$GITHUB_OUTPUT"
- name: 🛠 Expo prebuild (iOS)
working-directory: ${{ env.EXAMPLE_DIR }}
# No --clean so cached ios/Pods + DerivedData stay usable across runs.
run: pnpm expo prebuild --platform ios
- name: 🧰 Enable ccache in Podfile.properties.json
working-directory: ${{ env.EXAMPLE_DIR }}
# RN 0.83 Podfile reads `apple.ccacheEnabled` and wires ccache via
# react_native_post_install when true.
run: |
python3 -c "
import json, pathlib
p = pathlib.Path('ios/Podfile.properties.json')
d = json.loads(p.read_text())
d['apple.ccacheEnabled'] = 'true'
p.write_text(json.dumps(d, indent=2))
print(p.read_text())
"
# The Podfile invokes pod install during prebuild — re-run it so
# the ccache flag actually takes effect.
cd ios && pod install
- name: 🏗 Build & install iOS app on simulator
working-directory: ${{ env.EXAMPLE_DIR }}
run: pnpm expo run:ios --configuration Release --no-bundler --device "${{ steps.boot-sim.outputs.device_udid }}"
- name: 📊 ccache stats
if: always()
run: ccache --show-stats || true
- name: 🧪 Run Maestro smoke flows
working-directory: ${{ env.EXAMPLE_DIR }}
run: |
maestro test \
.maestro/smoke-launch.yaml \
.maestro/smoke-modal-open-close.yaml
- name: 📤 Upload Maestro debug output
if: always()
uses: actions/upload-artifact@v4
with:
name: maestro-debug-output
path: |
~/.maestro/tests/**
${{ env.EXAMPLE_DIR }}/.maestro/**/*.png
if-no-files-found: ignore
retention-days: 7
# Save caches even when a later step (maestro) fails. Each save is
# gated on the cache not already being a key hit so we don't waste
# GHA cache quota re-uploading identical contents.
- name: 💾 Save ccache compiler cache
if: always() && steps.ccache-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: ~/.ccache
key: ${{ steps.ccache-restore.outputs.cache-primary-key }}
- name: 💾 Save CocoaPods cache
if: always() && steps.pods-cache-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: |
~/.cocoapods
~/Library/Caches/CocoaPods
key: ${{ steps.pods-cache-restore.outputs.cache-primary-key }}
- name: 💾 Save iOS Pods/build/DerivedData cache
if: always() && steps.ios-cache-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: |
${{ env.EXAMPLE_DIR }}/ios/Pods
${{ env.EXAMPLE_DIR }}/ios/build
~/Library/Developer/Xcode/DerivedData
key: ${{ steps.ios-cache-restore.outputs.cache-primary-key }}