diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 35a9205d..48d6e71d 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -121,6 +121,11 @@ jobs: - name: Checkout repository uses: actions/checkout@v5 + - name: Setup Xcode + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: 16.4 + - name: Create working directory run: mkdir -p ${{ env.WORKING_DIR }} diff --git a/.github/workflows/test-nitro-cli.yml b/.github/workflows/test-nitro-cli.yml index 511bc67d..fbc29e00 100644 --- a/.github/workflows/test-nitro-cli.yml +++ b/.github/workflows/test-nitro-cli.yml @@ -1,7 +1,8 @@ name: Test Nitro CLI - Generate & Build +# Minimal permissions for downloading artifacts from other runs permissions: - contents: write + contents: read actions: read on: @@ -18,15 +19,18 @@ concurrency: jobs: test-ios-build: name: Test iOS Build - ${{ matrix.pm }} - ${{ matrix.package-type }} (${{ matrix.mode }}) - if: github.event.workflow_run.conclusion == 'success' - runs-on: macOS-15 + # Run on successful upstream, or when manually dispatched + if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' + runs-on: macOS-latest strategy: + fail-fast: false matrix: pm: ['bun', 'yarn'] package-type: ['module', 'view'] mode: ['Debug', 'Release'] env: WORKING_DIR: ${{ github.workspace }}/react-native-test-${{ matrix.package-type }} + SCHEME: ${{ matrix.package-type == 'module' && 'TestModuleExample' || 'TestViewExample' }} steps: - name: Create working directory run: mkdir -p ${{ env.WORKING_DIR }} @@ -57,14 +61,8 @@ jobs: ruby-version: '3.2' bundler-cache: true - - name: Setup pnpm - if: matrix.pm == 'pnpm' - uses: pnpm/action-setup@v4 - with: - version: 10 - - name: Setup Node.js - if: matrix.pm == 'yarn' || matrix.pm == 'pnpm' + if: matrix.pm == 'yarn' uses: actions/setup-node@v4 with: node-version: 22.x @@ -95,6 +93,16 @@ jobs: ${{ matrix.pm }} run build node post-script.js + - name: Cache CocoaPods + uses: actions/cache@v4 + with: + path: | + ~/.cocoapods/repos + ${{ env.WORKING_DIR }}/example/ios/Pods + key: ${{ runner.os }}-pods-${{ hashFiles(format('{0}/example/ios/Podfile.lock', env.WORKING_DIR)) }} + restore-keys: | + ${{ runner.os }}-pods- + - name: Install CocoaPods dependencies working-directory: ${{ env.WORKING_DIR }}/example run: ${{ matrix.pm }} pod @@ -106,18 +114,11 @@ jobs: - name: Build iOS project working-directory: ${{ env.WORKING_DIR }}/example/ios run: | - # Get the correct scheme name based on package type - if [ "${{ matrix.package-type }}" == "module" ]; then - SCHEME="TestModuleExample" - else - SCHEME="TestViewExample" - fi - set -o pipefail && xcodebuild \ CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ \ -derivedDataPath build -UseModernBuildSystem=YES \ -workspace "${SCHEME}.xcworkspace" \ - -scheme "$SCHEME" \ + -scheme "${SCHEME}" \ -sdk iphonesimulator \ -configuration ${{ matrix.mode }} \ -destination 'platform=iOS Simulator,name=iPhone 16' \ @@ -126,9 +127,11 @@ jobs: test-android-build: name: Test Android Build - ${{ matrix.pm }} - ${{ matrix.package-type }} (${{ matrix.mode }}) - if: github.event.workflow_run.conclusion == 'success' + # Run on successful upstream, or when manually dispatched + if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' runs-on: ubuntu-latest strategy: + fail-fast: false matrix: pm: ['bun', 'yarn'] package-type: ['module', 'view'] @@ -154,14 +157,8 @@ jobs: echo "Package structure:" find . -type f -name "*.json" -o -name "*.js" -o -name "*.ts" | head -20 - - name: Setup pnpm - if: matrix.pm == 'pnpm' - uses: pnpm/action-setup@v4 - with: - version: 10 - - name: Setup Node.js - if: matrix.pm == 'yarn' || matrix.pm == 'pnpm' + if: matrix.pm == 'yarn' uses: actions/setup-node@v4 with: node-version: 22.x @@ -203,6 +200,16 @@ jobs: working-directory: ${{ env.WORKING_DIR }}/example/android run: chmod +x ./gradlew + - name: Cache Gradle + uses: actions/cache@v4 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles(format('{0}/example/android/**/*.gradle*', env.WORKING_DIR)) }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Clean and generate codegen artifacts working-directory: ${{ env.WORKING_DIR }}/example/android run: | diff --git a/assets/template/.github/workflows/android-build.yml b/assets/template/.github/workflows/android-build.yml index 503f6d0a..9d8ef32d 100644 --- a/assets/template/.github/workflows/android-build.yml +++ b/assets/template/.github/workflows/android-build.yml @@ -1,5 +1,8 @@ name: Build Android +permissions: + contents: read + on: push: branches: @@ -25,63 +28,52 @@ on: - '**/bun.lock' - '**/react-native.config.js' - '**/nitro.json' + workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: - build_new: - name: Build Android Example App (new architecture) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: oven-sh/setup-bun@v2 - - - name: Install npm dependencies (bun) - run: bun install - - - name: Setup JDK 17 - uses: actions/setup-java@v4 - with: - distribution: 'zulu' - java-version: 17 - java-package: jdk - cache: gradle - - - name: Run Gradle Build for example/android/ - working-directory: example/android - run: ./gradlew assembleDebug --no-daemon --build-cache - - - name: Stop Gradle Daemon - working-directory: example/android - run: ./gradlew --stop - - build_old: - name: Build Android Example App (old architecture) + build: + name: Build Android Example App (${{ matrix.arch }}) runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + arch: [new, old] steps: - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v2 - - name: Install npm dependencies (bun) + - name: Install dependencies (bun) run: bun install - name: Disable new architecture in gradle.properties + if: matrix.arch == 'old' run: sed -i "s/newArchEnabled=true/newArchEnabled=false/g" example/android/gradle.properties - name: Setup JDK 17 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'zulu' - java-version: 17 - java-package: jdk - cache: gradle + java-version: '17' + cache: 'gradle' + + - name: Cache Gradle + uses: actions/cache@v4 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('example/android/**/*.gradle*') }} + restore-keys: | + ${{ runner.os }}-gradle- - - name: Run Gradle Build for example/android/ + - name: Run Gradle build working-directory: example/android run: ./gradlew assembleDebug --no-daemon --build-cache - - name: Stop Gradle Daemon + - name: Stop Gradle daemon working-directory: example/android run: ./gradlew --stop diff --git a/assets/template/.github/workflows/ios-build.yml b/assets/template/.github/workflows/ios-build.yml index 220fcec3..d4ac2990 100644 --- a/assets/template/.github/workflows/ios-build.yml +++ b/assets/template/.github/workflows/ios-build.yml @@ -1,5 +1,8 @@ name: Build iOS +permissions: + contents: read + on: push: branches: @@ -33,6 +36,7 @@ on: - '**/*.podspec' - '**/react-native.config.js' - '**/nitro.json' + workflow_dispatch: env: USE_CCACHE: 1 @@ -42,9 +46,13 @@ concurrency: cancel-in-progress: true jobs: - build_new: - name: Build iOS Example App (new architecture) + build: + name: Build iOS Example App (${{ matrix.arch }}) runs-on: macOS-15 + strategy: + fail-fast: false + matrix: + arch: [new, old] steps: - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v2 @@ -53,93 +61,47 @@ jobs: with: xcode-version: 16.4 - - name: Install npm dependencies (bun) - run: bun install - - - name: Setup Ruby (bundle) - uses: ruby/setup-ruby@v1 - with: - ruby-version: 2.7.2 - bundler-cache: true - working-directory: example/ios - - - name: Install xcpretty - run: gem install xcpretty - - - name: Restore Pods cache - uses: actions/cache@v4 - with: - path: example/ios/Pods - key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock', '**/Gemfile.lock') }} - restore-keys: | - ${{ runner.os }}-pods- - - name: Install Pods - working-directory: example/ios - run: pod install - - name: Build App - working-directory: example/ios - run: "set -o pipefail && xcodebuild \ - CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ \ - -derivedDataPath build -UseModernBuildSystem=YES \ - -workspace $$exampleApp$$.xcworkspace \ - -scheme $$exampleApp$$ \ - -sdk iphonesimulator \ - -configuration Debug \ - -destination 'platform=iOS Simulator,name=iPhone 16' \ - build \ - CODE_SIGNING_ALLOWED=NO | xcpretty" - - build_old: - name: Build iOS Example App (old architecture) - runs-on: macOS-15 - steps: - - uses: actions/checkout@v4 - - uses: oven-sh/setup-bun@v2 - - - name: Setup Xcode - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: 16.4 - - - name: Install npm dependencies (bun) + - name: Install dependencies (bun) run: bun install - name: Disable new architecture in Podfile + if: matrix.arch == 'old' run: sed -i "" "s/ENV\['RCT_NEW_ARCH_ENABLED'\] = '1'/ENV['RCT_NEW_ARCH_ENABLED'] = '0'/g" example/ios/Podfile - - name: Restore buildcache - uses: mikehardy/buildcache-action@v2 - continue-on-error: true - - name: Setup Ruby (bundle) uses: ruby/setup-ruby@v1 with: - ruby-version: 2.7.2 + ruby-version: '3.2' bundler-cache: true working-directory: example/ios - name: Install xcpretty run: gem install xcpretty - - name: Restore Pods cache + - name: Cache CocoaPods uses: actions/cache@v4 with: - path: example/ios/Pods - key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock', '**/Gemfile.lock') }} + path: | + ~/.cocoapods/repos + example/ios/Pods + key: ${{ runner.os }}-pods-${{ hashFiles('example/ios/Podfile.lock') }} restore-keys: | ${{ runner.os }}-pods- + - name: Install Pods working-directory: example/ios run: pod install + - name: Build App working-directory: example/ios - run: "set -o pipefail && xcodebuild \ - CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ \ - -derivedDataPath build -UseModernBuildSystem=YES \ - -workspace $$exampleApp$$.xcworkspace \ - -scheme $$exampleApp$$ \ - -sdk iphonesimulator \ - -configuration Debug \ - -destination 'platform=iOS Simulator,name=iPhone 16' \ - build \ - CODE_SIGNING_ALLOWED=NO | xcpretty" + run: | + set -o pipefail && xcodebuild \ + CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ \ + -derivedDataPath build -UseModernBuildSystem=YES \ + -workspace $$exampleApp$$.xcworkspace \ + -scheme $$exampleApp$$ \ + -sdk iphonesimulator \ + -configuration Debug \ + -destination 'platform=iOS Simulator,name=iPhone 16' \ + build \ + CODE_SIGNING_ALLOWED=NO | xcpretty diff --git a/scripts/e2e-maestro.sh b/scripts/e2e-maestro.sh old mode 100644 new mode 100755 index 131be412..42750e6d --- a/scripts/e2e-maestro.sh +++ b/scripts/e2e-maestro.sh @@ -64,9 +64,17 @@ if [ "$PLATFORM" == "ios" ]; then # Check if xcpretty is available if command -v xcpretty >/dev/null 2>&1; then set -o pipefail && $buildCmd | xcpretty + if [ $? -ne 0 ]; then + echo "❌ iOS build failed!" + exit 1 + fi else echo "⚠️ xcpretty not found. Install with: gem install xcpretty" $buildCmd + if [ $? -ne 0 ]; then + echo "❌ iOS build failed!" + exit 1 + fi fi # Launch the simulator if not already booted @@ -92,6 +100,10 @@ else # Build with optimizations and pretty output echo "🔨 Building Android app..." ./gradlew assembleRelease --no-daemon --build-cache --parallel --console=rich + if [ $? -ne 0 ]; then + echo "❌ Android build failed!" + exit 1 + fi APK_PATH="app/build/outputs/apk/release/app-release.apk" # Install the APK