feat: new arch support #116
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened] | |
| push: | |
| branches: [main, master] | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.head_ref }} | |
| cancel-in-progress: true | |
| env: | |
| # Cross-platform build configuration | |
| NODE_VERSION: '20' | |
| JAVA_VERSION: '17' | |
| RUBY_VERSION: '3.2' | |
| # Cache keys for cross-platform builds | |
| GRADLE_CACHE_KEY: gradle-cache-v2 | |
| COCOAPODS_CACHE_KEY: cocoapods-cache-v2 | |
| NODE_MODULES_CACHE_KEY: node-modules-cache-v2 | |
| jobs: | |
| # Cross-platform dependency and security checks | |
| security: | |
| runs-on: ubuntu-latest | |
| name: Security & Dependency Review | |
| steps: | |
| - name: Checkout the code | |
| uses: actions/checkout@v4 | |
| - name: Dependency Review | |
| uses: actions/dependency-review-action@v4 | |
| if: github.event_name == 'pull_request' | |
| continue-on-error: true | |
| with: | |
| fail-on-severity: high | |
| warn-on-severity: moderate | |
| - name: Setup node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| - name: Cache node_modules | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| node_modules | |
| ~/.npm | |
| key: ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}-${{ hashFiles('package.json', 'yarn.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}- | |
| - name: Install dependencies | |
| run: | | |
| echo "Installing dependencies for security checks..." | |
| if ! yarn install --frozen-lockfile; then | |
| echo "⚠️ Frozen lockfile failed, updating lockfile..." | |
| yarn install | |
| fi | |
| - name: Run yarn audit | |
| run: | | |
| echo "Running yarn audit..." | |
| yarn audit --level moderate || echo "⚠️ Yarn audit found vulnerabilities, but continuing..." | |
| continue-on-error: true | |
| # Cross-platform architecture compatibility testing | |
| architecture-compatibility: | |
| runs-on: ubuntu-latest | |
| name: Cross-Platform Architecture Compatibility | |
| strategy: | |
| matrix: | |
| node-version: [20, 22] | |
| architecture: [legacy, new] | |
| platform: [android, ios, both] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ matrix.node-version }} | |
| cache: 'yarn' | |
| - name: Cache node_modules | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| node_modules | |
| ~/.npm | |
| key: ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}-${{ matrix.node-version }}-${{ hashFiles('package.json', 'yarn.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}-${{ matrix.node-version }}- | |
| ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}- | |
| - name: Install dependencies | |
| run: | | |
| echo "Installing dependencies for architecture compatibility tests..." | |
| if ! yarn install --frozen-lockfile; then | |
| echo "⚠️ Frozen lockfile failed, updating lockfile..." | |
| yarn install | |
| fi | |
| - name: Run TypeScript compilation | |
| run: yarn typecheck | |
| - name: Run linting | |
| run: yarn lint | |
| - name: Run unit tests | |
| run: yarn test --run | |
| - name: Test cross-platform architecture detection | |
| run: | | |
| if [ "${{ matrix.architecture }}" = "new" ]; then | |
| echo "Testing new architecture detection for ${{ matrix.platform }}..." | |
| export RCT_NEW_ARCH_ENABLED=1 | |
| yarn test --run --testNamePattern="Architecture detection" | |
| else | |
| echo "Testing legacy architecture detection for ${{ matrix.platform }}..." | |
| export RCT_NEW_ARCH_ENABLED=0 | |
| yarn test --run --testNamePattern="Architecture detection" | |
| fi | |
| - name: Test cross-platform build configuration | |
| run: | | |
| echo "Testing build configuration for ${{ matrix.platform }} platform..." | |
| yarn test --run --testNamePattern="Property 6" | |
| - name: Validate cross-platform Codegen specs | |
| run: | | |
| if [ -f "specs/NativeImageMarker.ts" ]; then | |
| echo "✅ Codegen spec file exists" | |
| # Use CI-specific TypeScript configuration to avoid type conflicts | |
| npx tsc --noEmit --project tsconfig.ci.json | |
| else | |
| echo "❌ Codegen spec file missing" | |
| exit 1 | |
| fi | |
| - name: Check cross-platform package.json configuration | |
| run: | | |
| if grep -q "codegenConfig" package.json; then | |
| echo "✅ Package.json has codegenConfig" | |
| else | |
| echo "❌ Package.json missing codegenConfig" | |
| exit 1 | |
| fi | |
| - name: Build library | |
| run: yarn prepack | |
| - name: Test cross-platform library exports | |
| run: | | |
| node -e " | |
| // Mock React Native environment for Node.js testing | |
| global.TurboModuleRegistry = undefined; | |
| global.UIManager = undefined; | |
| // Mock react-native module | |
| require.cache[require.resolve('react-native')] = { | |
| exports: { | |
| TurboModuleRegistry: undefined, | |
| UIManager: undefined, | |
| NativeModules: {}, | |
| Platform: { OS: 'test', select: (obj) => obj.default }, | |
| Image: { resolveAssetSource: () => null } | |
| } | |
| }; | |
| const lib = require('./lib/commonjs/index.js'); | |
| console.log('✅ Library exports:', Object.keys(lib)); | |
| if (!lib.default) { | |
| console.error('❌ Default export missing'); | |
| process.exit(1); | |
| } | |
| console.log('✅ Cross-platform integration test passed'); | |
| " | |
| - name: Verify cross-platform architecture detection in built library | |
| run: | | |
| node -e " | |
| // Mock React Native environment for Node.js testing | |
| global.TurboModuleRegistry = undefined; | |
| global.UIManager = undefined; | |
| // Mock react-native module | |
| require.cache[require.resolve('react-native')] = { | |
| exports: { | |
| TurboModuleRegistry: undefined, | |
| UIManager: undefined, | |
| NativeModules: {}, | |
| Platform: { OS: 'test', select: (obj) => obj.default }, | |
| Image: { resolveAssetSource: () => null } | |
| } | |
| }; | |
| const { ArchitectureDetector } = require('./lib/commonjs/ArchitectureDetector.js'); | |
| console.log('✅ ArchitectureDetector available'); | |
| const isNewArch = ArchitectureDetector.isNewArchitecture(); | |
| console.log('Architecture detection result for ${{ matrix.platform }}:', isNewArch); | |
| console.log('✅ Cross-platform architecture detection test passed'); | |
| " | |
| # Cross-platform build configuration validation | |
| validate-build-configs: | |
| runs-on: macos-latest | |
| name: Cross-Platform Build Configuration Validation | |
| strategy: | |
| matrix: | |
| platform: [android, ios, both] | |
| rn-version: ['0.73', '0.81', '0.8x'] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Ruby | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: ${{ env.RUBY_VERSION }} | |
| bundler-cache: true | |
| - name: Setup JDK | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: 'zulu' | |
| java-version: ${{ env.JAVA_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| - name: Cache cross-platform dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.gradle/caches | |
| ~/.gradle/wrapper | |
| ~/Library/Caches/CocoaPods | |
| ~/.cocoapods | |
| node_modules | |
| key: ${{ runner.os }}-cross-platform-deps-${{ matrix.platform }}-${{ matrix.rn-version }}-${{ hashFiles('package.json', 'android/build.gradle', 'react-native-image-marker.podspec') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cross-platform-deps-${{ matrix.platform }}-${{ matrix.rn-version }}- | |
| ${{ runner.os }}-cross-platform-deps-${{ matrix.platform }}- | |
| ${{ runner.os }}-cross-platform-deps- | |
| - name: Install CocoaPods | |
| run: gem install cocoapods | |
| - name: Install dependencies | |
| run: | | |
| echo "Installing dependencies for build config validation..." | |
| if ! yarn install --frozen-lockfile; then | |
| echo "⚠️ Frozen lockfile failed, updating lockfile..." | |
| yarn install | |
| fi | |
| echo "Installing example-0.73 dependencies for Android build tests..." | |
| cd example-0.73 | |
| if ! yarn install --frozen-lockfile; then | |
| echo "⚠️ Frozen lockfile failed, updating lockfile..." | |
| yarn install | |
| fi | |
| cd .. | |
| - name: Validate iOS podspec syntax (basic check) | |
| if: matrix.platform == 'ios' || matrix.platform == 'both' | |
| run: | | |
| # Basic syntax validation without dependency resolution | |
| ruby -c react-native-image-marker.podspec | |
| echo "✅ Podspec syntax is valid" | |
| - name: Test podspec with different architecture flags | |
| if: matrix.platform == 'ios' || matrix.platform == 'both' | |
| run: | | |
| echo "Testing legacy architecture podspec for RN ${{ matrix.rn-version }}..." | |
| export RCT_NEW_ARCH_ENABLED=0 | |
| ruby -e " | |
| require 'json' | |
| # Load and evaluate the podspec in a safe context | |
| podspec_content = File.read('react-native-image-marker.podspec') | |
| # Check if the podspec contains expected architecture-specific configurations | |
| if podspec_content.include?('RCT_NEW_ARCH_ENABLED') || podspec_content.include?('new_arch_enabled') | |
| puts '✅ Legacy architecture podspec contains architecture detection logic for RN ${{ matrix.rn-version }}' | |
| else | |
| puts '⚠️ Podspec may not have architecture-specific logic, but this is acceptable' | |
| end | |
| " | |
| echo "Testing new architecture podspec for RN ${{ matrix.rn-version }}..." | |
| export RCT_NEW_ARCH_ENABLED=1 | |
| ruby -e " | |
| require 'json' | |
| # Load and evaluate the podspec in a safe context | |
| podspec_content = File.read('react-native-image-marker.podspec') | |
| # Check if the podspec contains expected architecture-specific configurations | |
| if podspec_content.include?('RCT_NEW_ARCH_ENABLED') || podspec_content.include?('new_arch_enabled') | |
| puts '✅ New architecture podspec contains architecture detection logic for RN ${{ matrix.rn-version }}' | |
| else | |
| puts '⚠️ Podspec may not have architecture-specific logic, but this is acceptable' | |
| end | |
| " | |
| echo "✅ Podspec architecture compatibility test completed" | |
| - name: Validate Android Gradle syntax | |
| if: matrix.platform == 'android' || matrix.platform == 'both' | |
| run: | | |
| cd android | |
| # Only validate syntax, don't try to build the library module directly | |
| echo "Validating Android Gradle configuration syntax..." | |
| if [ -f "build.gradle" ]; then | |
| echo "✅ Android build.gradle exists" | |
| # Check for basic Gradle syntax by parsing the file | |
| if grep -q "apply plugin" build.gradle; then | |
| echo "✅ Android build.gradle has plugin declarations" | |
| fi | |
| if grep -q "android {" build.gradle; then | |
| echo "✅ Android build.gradle has android configuration block" | |
| fi | |
| else | |
| echo "❌ Android build.gradle not found" | |
| exit 1 | |
| fi | |
| - name: Test legacy architecture Android build for RN version | |
| if: matrix.platform == 'android' || matrix.platform == 'both' | |
| run: | | |
| # Test with example project instead of library module | |
| cd example-0.73/android | |
| echo "Testing legacy architecture build configuration for RN ${{ matrix.rn-version }}..." | |
| echo "newArchEnabled=false" > gradle.properties | |
| echo "hermesEnabled=true" >> gradle.properties | |
| echo "# Testing RN ${{ matrix.rn-version }} compatibility" >> gradle.properties | |
| echo "android.useAndroidX=true" >> gradle.properties | |
| echo "android.enableJetifier=true" >> gradle.properties | |
| ./gradlew help --dry-run | |
| - name: Test new architecture Android build for RN version | |
| if: matrix.platform == 'android' || matrix.platform == 'both' | |
| run: | | |
| # Test with example project instead of library module | |
| cd example-0.73/android | |
| echo "Testing new architecture build configuration for RN ${{ matrix.rn-version }}..." | |
| echo "newArchEnabled=true" > gradle.properties | |
| echo "hermesEnabled=true" >> gradle.properties | |
| echo "# Testing RN ${{ matrix.rn-version }} compatibility" >> gradle.properties | |
| echo "android.useAndroidX=true" >> gradle.properties | |
| echo "android.enableJetifier=true" >> gradle.properties | |
| ./gradlew help --dry-run | |
| - name: Test cross-platform version detection | |
| run: | | |
| echo "Testing version detection for RN ${{ matrix.rn-version }} on ${{ matrix.platform }}..." | |
| yarn test --run --testNamePattern="Cross-platform version detection" | |
| # Cross-platform dependency installation with enhanced caching | |
| install-dep: | |
| runs-on: macos-latest | |
| env: | |
| NO_FLIPPER: '1' | |
| name: Cross-Platform Dependency Installation | |
| strategy: | |
| matrix: | |
| platform: [android, ios, both] | |
| steps: | |
| - name: Checkout the code | |
| uses: actions/checkout@v4 | |
| - name: Verify cross-platform changed files | |
| uses: tj-actions/changed-files@v46 | |
| id: verify-cross-platform-changed-files | |
| with: | |
| files: | | |
| !*.md | |
| !*.MD | |
| !*.yml | |
| - name: Cache cross-platform node_modules | |
| uses: actions/cache@v4 | |
| id: cache-cross-platform-node-modules | |
| if: steps.verify-cross-platform-changed-files.outputs.any_changed == 'true' | |
| with: | |
| path: | | |
| node_modules | |
| example/node_modules | |
| example-0.73/node_modules | |
| expo-example/node_modules | |
| ~/.npm | |
| key: ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}-${{ matrix.platform }}-${{ hashFiles('package.json', 'example/package.json', 'example-0.73/package.json', 'expo-example/package.json') }} | |
| restore-keys: | | |
| ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}-${{ matrix.platform }}- | |
| ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}- | |
| - name: Cache cross-platform Ruby gems | |
| uses: actions/cache@v4 | |
| if: steps.verify-cross-platform-changed-files.outputs.any_changed == 'true' && (matrix.platform == 'ios' || matrix.platform == 'both') | |
| with: | |
| path: | | |
| vendor/bundle | |
| ~/.gem | |
| key: ${{ runner.os }}-gems-${{ env.RUBY_VERSION }}-${{ hashFiles('Gemfile.lock', 'example/Gemfile.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-gems-${{ env.RUBY_VERSION }}- | |
| - name: Set up Ruby | |
| if: steps.verify-cross-platform-changed-files.outputs.any_changed == 'true' | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: ${{ env.RUBY_VERSION }} | |
| bundler-cache: true | |
| - name: Setup node | |
| if: steps.verify-cross-platform-changed-files.outputs.any_changed == 'true' | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| - name: Install yarn dependencies for main project | |
| if: steps.cache-cross-platform-node-modules.outputs.cache-hit != 'true' && steps.verify-cross-platform-changed-files.outputs.any_changed == 'true' | |
| run: | | |
| echo "Installing dependencies for main project..." | |
| if ! yarn install --frozen-lockfile; then | |
| echo "⚠️ Frozen lockfile failed, updating lockfile..." | |
| yarn install | |
| fi | |
| - name: Install yarn dependencies for example apps | |
| if: steps.cache-cross-platform-node-modules.outputs.cache-hit != 'true' && steps.verify-cross-platform-changed-files.outputs.any_changed == 'true' | |
| run: | | |
| echo "Installing dependencies for example apps..." | |
| echo "Installing example dependencies..." | |
| cd example | |
| if ! yarn install --frozen-lockfile; then | |
| echo "⚠️ Frozen lockfile failed, updating lockfile..." | |
| yarn install | |
| fi | |
| cd .. | |
| echo "Installing example-0.73 dependencies..." | |
| cd example-0.73 | |
| if ! yarn install --frozen-lockfile; then | |
| echo "⚠️ Frozen lockfile failed, updating lockfile..." | |
| yarn install | |
| fi | |
| cd .. | |
| echo "Installing expo-example dependencies..." | |
| cd expo-example | |
| if ! yarn install --frozen-lockfile; then | |
| echo "⚠️ Frozen lockfile failed, updating lockfile..." | |
| yarn install | |
| fi | |
| cd .. | |
| # Cross-platform Android build with enhanced matrix and caching | |
| android-build: | |
| runs-on: macos-latest | |
| name: Cross-Platform Android Build | |
| needs: install-dep | |
| strategy: | |
| matrix: | |
| architecture: [legacy, new] | |
| rn-version: ['0.73', '0.81'] | |
| example-app: [example, example-0.73] | |
| exclude: | |
| # Only test example with 0.73 and example-0.73 with 0.81 to avoid redundancy | |
| - rn-version: '0.81' | |
| example-app: example | |
| - rn-version: '0.73' | |
| example-app: example-0.73 | |
| steps: | |
| - name: Checkout the code | |
| uses: actions/checkout@v4 | |
| - name: Verify Android changed files | |
| uses: tj-actions/changed-files@v46 | |
| id: verify-android-changed-files | |
| with: | |
| files: | | |
| android/** | |
| src/** | |
| assets/** | |
| package.json | |
| ${{ matrix.example-app }}/** | |
| !${{ matrix.example-app }}/ios/** | |
| - name: Cache cross-platform node_modules | |
| uses: actions/cache@v4 | |
| if: steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| id: cache-cross-platform-node-modules | |
| with: | |
| path: | | |
| node_modules | |
| ${{ matrix.example-app }}/node_modules | |
| ~/.npm | |
| key: ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}-android-${{ matrix.rn-version }}-${{ hashFiles('package.json', format('{0}/package.json', matrix.example-app)) }} | |
| restore-keys: | | |
| ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}-android-${{ matrix.rn-version }}- | |
| ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}-android- | |
| ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}- | |
| - name: Cache enhanced Gradle dependencies | |
| uses: actions/cache@v4 | |
| id: cache-enhanced-gradle | |
| if: steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| with: | |
| path: | | |
| ~/.gradle/caches | |
| ~/.gradle/wrapper | |
| ~/.gradle/daemon | |
| ${{ matrix.example-app }}/android/.gradle | |
| ${{ matrix.example-app }}/android/build | |
| key: ${{ runner.os }}-${{ env.GRADLE_CACHE_KEY }}-${{ matrix.architecture }}-${{ matrix.rn-version }}-${{ matrix.example-app }}-${{ hashFiles(format('{0}/android/gradle/wrapper/gradle-wrapper.properties', matrix.example-app), 'android/src/**/*.kt', format('{0}/android/build.gradle', matrix.example-app)) }} | |
| restore-keys: | | |
| ${{ runner.os }}-${{ env.GRADLE_CACHE_KEY }}-${{ matrix.architecture }}-${{ matrix.rn-version }}-${{ matrix.example-app }}- | |
| ${{ runner.os }}-${{ env.GRADLE_CACHE_KEY }}-${{ matrix.architecture }}-${{ matrix.rn-version }}- | |
| ${{ runner.os }}-${{ env.GRADLE_CACHE_KEY }}-${{ matrix.architecture }}- | |
| ${{ runner.os }}-${{ env.GRADLE_CACHE_KEY }}- | |
| - name: Setup node | |
| uses: actions/setup-node@v4 | |
| if: steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| - name: Set up JDK | |
| uses: actions/setup-java@v4 | |
| if: steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| with: | |
| distribution: 'zulu' | |
| java-version: ${{ env.JAVA_VERSION }} | |
| - name: Configure cross-platform architecture | |
| if: steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| run: | | |
| cd ${{ matrix.example-app }}/android | |
| echo "Configuring ${{ matrix.architecture }} architecture for RN ${{ matrix.rn-version }}..." | |
| # Backup original gradle.properties | |
| cp gradle.properties gradle.properties.backup | |
| # Configure architecture-specific properties | |
| if [ "${{ matrix.architecture }}" = "new" ]; then | |
| echo "newArchEnabled=true" >> gradle.properties | |
| echo "hermesEnabled=true" >> gradle.properties | |
| echo "# RN ${{ matrix.rn-version }} New Architecture Build" >> gradle.properties | |
| else | |
| echo "newArchEnabled=false" >> gradle.properties | |
| echo "hermesEnabled=true" >> gradle.properties | |
| echo "# RN ${{ matrix.rn-version }} Legacy Architecture Build" >> gradle.properties | |
| fi | |
| # Set Kotlin version based on RN version | |
| if [ "${{ matrix.rn-version }}" = "0.73" ]; then | |
| echo "kotlin_version=1.8.0" >> gradle.properties | |
| elif [ "${{ matrix.rn-version }}" = "0.81" ]; then | |
| echo "kotlin_version=1.9.22" >> gradle.properties | |
| else | |
| echo "kotlin_version=1.9.22" >> gradle.properties | |
| fi | |
| # Ensure required properties are set | |
| echo "android.useAndroidX=true" >> gradle.properties | |
| echo "android.enableJetifier=true" >> gradle.properties | |
| echo "org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=512m" >> gradle.properties | |
| echo "org.gradle.daemon=true" >> gradle.properties | |
| echo "org.gradle.parallel=true" >> gradle.properties | |
| echo "org.gradle.configureondemand=true" >> gradle.properties | |
| echo "Final gradle.properties configuration:" | |
| cat gradle.properties | |
| - name: Run CI health check | |
| if: steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| env: | |
| MATRIX_PLATFORM: android | |
| MATRIX_ARCHITECTURE: ${{ matrix.architecture }} | |
| MATRIX_RN_VERSION: ${{ matrix.rn-version }} | |
| MATRIX_EXAMPLE_APP: ${{ matrix.example-app }} | |
| CACHE_HIT_GRADLE: ${{ steps.cache-enhanced-gradle.outputs.cache-hit }} | |
| CACHE_HIT_NODE_MODULES: ${{ steps.cache-cross-platform-node-modules.outputs.cache-hit }} | |
| run: | | |
| echo "🏥 Running pre-build health checks..." | |
| node scripts/ci-error-handler.js health-check | |
| - name: Install Gradle dependencies with enhanced caching and error handling | |
| if: steps.cache-enhanced-gradle.outputs.cache-hit != 'true' && steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| env: | |
| MATRIX_PLATFORM: android | |
| MATRIX_ARCHITECTURE: ${{ matrix.architecture }} | |
| MATRIX_RN_VERSION: ${{ matrix.rn-version }} | |
| MATRIX_EXAMPLE_APP: ${{ matrix.example-app }} | |
| CACHE_HIT_GRADLE: ${{ steps.cache-enhanced-gradle.outputs.cache-hit }} | |
| run: | | |
| echo "Installing Gradle dependencies for ${{ matrix.architecture }} architecture, RN ${{ matrix.rn-version }}..." | |
| cd ${{ matrix.example-app }} | |
| if ! yarn install --frozen-lockfile; then | |
| echo "⚠️ Frozen lockfile failed, updating lockfile..." | |
| yarn install | |
| fi | |
| cd android | |
| # Clean any existing build artifacts | |
| ./gradlew clean --stacktrace --no-build-cache | |
| # Download dependencies without building | |
| ./gradlew dependencies --stacktrace --no-build-cache | |
| - name: Run cross-platform unit tests with error handling | |
| if: steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| env: | |
| MATRIX_PLATFORM: android | |
| MATRIX_ARCHITECTURE: ${{ matrix.architecture }} | |
| MATRIX_RN_VERSION: ${{ matrix.rn-version }} | |
| MATRIX_EXAMPLE_APP: ${{ matrix.example-app }} | |
| run: | | |
| echo "Checking for Android unit tests for ${{ matrix.architecture }} architecture, RN ${{ matrix.rn-version }}..." | |
| cd ${{ matrix.example-app }}/android | |
| # Check if test source directory exists | |
| if [ -d "app/src/test" ] && [ "$(find app/src/test -name '*.java' -o -name '*.kt' | wc -l)" -gt 0 ]; then | |
| echo "Running unit tests..." | |
| ./gradlew test --stacktrace --no-build-cache --info | |
| else | |
| echo "⚠️ No unit tests found, skipping test execution" | |
| echo "This is acceptable for example applications" | |
| fi | |
| - name: Build cross-platform APK with error handling | |
| if: steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| env: | |
| MATRIX_PLATFORM: android | |
| MATRIX_ARCHITECTURE: ${{ matrix.architecture }} | |
| MATRIX_RN_VERSION: ${{ matrix.rn-version }} | |
| MATRIX_EXAMPLE_APP: ${{ matrix.example-app }} | |
| run: | | |
| echo "Installing main project dependencies for library build..." | |
| if ! yarn install --frozen-lockfile; then | |
| echo "⚠️ Frozen lockfile failed, updating lockfile..." | |
| yarn install | |
| fi | |
| echo "Building library for cross-platform compatibility..." | |
| yarn prepack | |
| echo "Preparing Android build for ${{ matrix.architecture }} architecture..." | |
| cd ${{ matrix.example-app }}/android | |
| # Verify gradle.properties configuration | |
| echo "📋 Current gradle.properties:" | |
| cat gradle.properties | |
| # Clean any stale build artifacts that might cause CMake issues | |
| echo "🧹 Cleaning stale build artifacts..." | |
| rm -rf app/.cxx | |
| rm -rf app/build/generated/autolinking | |
| rm -rf app/build/generated/source | |
| # Clean library module's codegen directory (absolute path from workspace root) | |
| LIBRARY_CODEGEN_DIR="$GITHUB_WORKSPACE/android/build/generated/source/codegen" | |
| if [ -d "$LIBRARY_CODEGEN_DIR" ]; then | |
| echo "🧹 Removing library codegen directory: $LIBRARY_CODEGEN_DIR" | |
| rm -rf "$LIBRARY_CODEGEN_DIR" | |
| fi | |
| # Clean library module's entire build directory to ensure no codegen artifacts | |
| LIBRARY_BUILD_DIR="$GITHUB_WORKSPACE/android/build" | |
| if [ -d "$LIBRARY_BUILD_DIR" ]; then | |
| echo "🧹 Cleaning library build directory: $LIBRARY_BUILD_DIR" | |
| rm -rf "$LIBRARY_BUILD_DIR" | |
| fi | |
| # For legacy architecture, ensure autolinking doesn't reference codegen | |
| if [ "${{ matrix.architecture }}" = "legacy" ]; then | |
| echo "🔧 Configuring for Legacy Architecture build..." | |
| # Verify newArchEnabled is false | |
| if grep -q "newArchEnabled=true" gradle.properties; then | |
| echo "⚠️ Warning: newArchEnabled=true found in gradle.properties for legacy build!" | |
| echo "This should have been set to false in the configuration step." | |
| fi | |
| # Force regenerate autolinking to exclude codegen references | |
| echo "🔄 Regenerating autolinking configuration for Legacy Architecture..." | |
| cd .. | |
| # Remove node_modules/.bin cache that might have stale autolinking | |
| rm -rf node_modules/.bin/react-native-* | |
| cd android | |
| fi | |
| echo "Building APK for ${{ matrix.architecture }} architecture, RN ${{ matrix.rn-version }}..." | |
| echo "Using --info flag for detailed build logs..." | |
| # Run Gradle directly without wrapper to see full output | |
| ./gradlew assembleRelease --stacktrace --no-build-cache --info 2>&1 | tee build.log | |
| # Check exit code | |
| if [ ${PIPESTATUS[0]} -ne 0 ]; then | |
| echo "❌ Build failed!" | |
| echo "📄 Showing last 200 lines of build log:" | |
| tail -200 build.log | |
| exit 1 | |
| fi | |
| mv app/build/outputs/apk/release/app-release.apk app-release-${{ matrix.architecture }}-${{ matrix.rn-version }}-${{ matrix.example-app }}-${{ github.sha }}.apk | |
| - name: Upload cross-platform APK | |
| if: steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: app-release-${{ matrix.architecture }}-${{ matrix.rn-version }}-${{ matrix.example-app }}-${{ github.sha }}.apk | |
| path: ${{ github.workspace }}/${{ matrix.example-app }}/android/app-release-${{ matrix.architecture }}-${{ matrix.rn-version }}-${{ matrix.example-app }}-${{ github.sha }}.apk | |
| retention-days: 7 | |
| - name: Validate cross-platform build artifacts | |
| if: steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| run: | | |
| cd ${{ matrix.example-app }}/android | |
| APK_FILE="app-release-${{ matrix.architecture }}-${{ matrix.rn-version }}-${{ matrix.example-app }}-${{ github.sha }}.apk" | |
| if [ -f "$APK_FILE" ]; then | |
| echo "✅ APK built successfully: $APK_FILE" | |
| ls -la "$APK_FILE" | |
| else | |
| echo "❌ APK build failed" | |
| exit 1 | |
| fi | |
| - name: Generate build report | |
| if: always() && steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| env: | |
| MATRIX_PLATFORM: android | |
| MATRIX_ARCHITECTURE: ${{ matrix.architecture }} | |
| MATRIX_RN_VERSION: ${{ matrix.rn-version }} | |
| MATRIX_EXAMPLE_APP: ${{ matrix.example-app }} | |
| run: | | |
| echo "📊 Generating build report..." | |
| node scripts/ci-error-handler.js report | |
| - name: Upload build reports | |
| if: always() && steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: android-build-reports-${{ matrix.architecture }}-${{ matrix.rn-version }}-${{ matrix.example-app }} | |
| path: | | |
| ci-*.md | |
| ci-build.log | |
| retention-days: 7 | |
| # Cross-platform Android API level testing | |
| android-api-level-test: | |
| runs-on: macos-14 | |
| needs: android-build | |
| name: Cross-Platform Android API Level Test | |
| strategy: | |
| matrix: | |
| api-level: [24, 31, 34] | |
| target: [default] | |
| architecture: [legacy, new] | |
| rn-version: ['0.73', '0.81'] | |
| example-app: [example, example-0.73] | |
| exclude: | |
| # Only test example with 0.73 and example-0.73 with 0.81 to avoid redundancy | |
| - rn-version: '0.81' | |
| example-app: example | |
| - rn-version: '0.73' | |
| example-app: example-0.73 | |
| steps: | |
| - name: Checkout the code | |
| uses: actions/checkout@v4 | |
| - name: Verify Android changed files | |
| uses: tj-actions/changed-files@v46 | |
| id: verify-android-changed-files | |
| with: | |
| files: | | |
| android/** | |
| src/** | |
| assets/** | |
| package.json | |
| ${{ matrix.example-app }}/** | |
| !${{ matrix.example-app }}/ios/** | |
| - name: Cache cross-platform node_modules | |
| uses: actions/cache@v4 | |
| if: steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| id: cache-cross-platform-node-modules | |
| with: | |
| path: | | |
| node_modules | |
| ${{ matrix.example-app }}/node_modules | |
| ~/.npm | |
| key: ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}-android-test-${{ matrix.rn-version }}-${{ hashFiles('package.json', format('{0}/package.json', matrix.example-app)) }} | |
| restore-keys: | | |
| ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}-android-test-${{ matrix.rn-version }}- | |
| ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}-android-test- | |
| ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}- | |
| - name: Cache enhanced Gradle dependencies for testing | |
| uses: actions/cache@v4 | |
| if: steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| id: cache-enhanced-gradle-test | |
| with: | |
| path: | | |
| ~/.gradle/caches | |
| ~/.gradle/wrapper | |
| ~/.gradle/daemon | |
| ${{ matrix.example-app }}/android/.gradle | |
| ${{ matrix.example-app }}/android/build | |
| key: ${{ runner.os }}-${{ env.GRADLE_CACHE_KEY }}-test-${{ matrix.architecture }}-${{ matrix.rn-version }}-${{ matrix.example-app }}-api${{ matrix.api-level }}-${{ hashFiles(format('{0}/android/gradle/wrapper/gradle-wrapper.properties', matrix.example-app), 'android/src/**/*.kt') }} | |
| restore-keys: | | |
| ${{ runner.os }}-${{ env.GRADLE_CACHE_KEY }}-test-${{ matrix.architecture }}-${{ matrix.rn-version }}-${{ matrix.example-app }}- | |
| ${{ runner.os }}-${{ env.GRADLE_CACHE_KEY }}-test-${{ matrix.architecture }}-${{ matrix.rn-version }}- | |
| ${{ runner.os }}-${{ env.GRADLE_CACHE_KEY }}-test-${{ matrix.architecture }}- | |
| ${{ runner.os }}-${{ env.GRADLE_CACHE_KEY }}-test- | |
| - name: Setup node | |
| uses: actions/setup-node@v4 | |
| if: steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| - name: Set up JDK | |
| uses: actions/setup-java@v4 | |
| if: steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| with: | |
| distribution: 'zulu' | |
| java-version: ${{ env.JAVA_VERSION }} | |
| - name: Configure cross-platform architecture for testing | |
| if: steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| run: | | |
| cd ${{ matrix.example-app }}/android | |
| echo "Configuring ${{ matrix.architecture }} architecture for API ${{ matrix.api-level }} testing, RN ${{ matrix.rn-version }}..." | |
| if [ "${{ matrix.architecture }}" = "new" ]; then | |
| echo "newArchEnabled=true" >> gradle.properties | |
| echo "hermesEnabled=true" >> gradle.properties | |
| else | |
| echo "newArchEnabled=false" >> gradle.properties | |
| echo "hermesEnabled=false" >> gradle.properties | |
| fi | |
| echo "android.useAndroidX=true" >> gradle.properties | |
| echo "android.enableJetifier=true" >> gradle.properties | |
| cat gradle.properties | |
| - name: Cross-platform instrumentation tests | |
| uses: reactivecircus/android-emulator-runner@v2 | |
| if: steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| with: | |
| api-level: ${{ matrix.api-level }} | |
| target: ${{ matrix.target }} | |
| arch: x86_64 | |
| profile: pixel_5 | |
| script: | | |
| echo "Running instrumentation tests for ${{ matrix.architecture }} architecture, API ${{ matrix.api-level }}, RN ${{ matrix.rn-version }}..." | |
| cd ${{ matrix.example-app }}/android && ./gradlew connectedCheck --stacktrace --no-build-cache --info | |
| - name: Upload cross-platform test reports | |
| uses: actions/upload-artifact@v4 | |
| if: steps.verify-android-changed-files.outputs.any_changed == 'true' | |
| with: | |
| name: Android-Test-Reports-${{ matrix.architecture }}-${{ matrix.rn-version }}-${{ matrix.example-app }}-API${{ matrix.api-level }} | |
| path: ${{ github.workspace }}/${{ matrix.example-app }}/android/app/build/reports | |
| retention-days: 7 | |
| # Cross-platform iOS build and test with enhanced matrix and caching | |
| ios-build-test: | |
| runs-on: macos-latest | |
| env: | |
| NO_FLIPPER: '1' | |
| needs: install-dep | |
| name: Cross-Platform iOS Build and Test | |
| strategy: | |
| matrix: | |
| cocoapods: ['1.14.3', '1.15.2'] | |
| architecture: [legacy, new] | |
| rn-version: ['0.73', '0.81'] | |
| example-app: [example, example-0.73] | |
| exclude: | |
| # Only test example with 0.73 and example-0.73 with 0.81 to avoid redundancy | |
| - rn-version: '0.81' | |
| example-app: example | |
| - rn-version: '0.73' | |
| example-app: example-0.73 | |
| steps: | |
| - name: Checkout the code | |
| uses: actions/checkout@v4 | |
| - name: Setup Xcode version | |
| uses: maxim-lobanov/setup-xcode@v1 | |
| with: | |
| xcode-version: latest-stable | |
| - name: Verify iOS changed files | |
| uses: tj-actions/changed-files@v46 | |
| id: verify-iOS-changed-files | |
| with: | |
| files: | | |
| ios/** | |
| src/** | |
| assets/** | |
| package.json | |
| ${{ matrix.example-app }}/** | |
| !${{ matrix.example-app }}/android/** | |
| - name: Cache cross-platform node_modules | |
| uses: actions/cache@v4 | |
| id: cache-cross-platform-node-modules | |
| if: steps.verify-iOS-changed-files.outputs.any_changed == 'true' | |
| with: | |
| path: | | |
| node_modules | |
| ${{ matrix.example-app }}/node_modules | |
| ~/.npm | |
| key: ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}-ios-${{ matrix.rn-version }}-${{ hashFiles('package.json', format('{0}/package.json', matrix.example-app)) }} | |
| restore-keys: | | |
| ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}-ios-${{ matrix.rn-version }}- | |
| ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}-ios- | |
| ${{ runner.os }}-${{ env.NODE_MODULES_CACHE_KEY }}- | |
| - name: Cache enhanced CocoaPods dependencies | |
| id: cache-enhanced-pods | |
| uses: actions/cache@v4 | |
| if: steps.verify-iOS-changed-files.outputs.any_changed == 'true' | |
| with: | |
| path: | | |
| ${{ matrix.example-app }}/ios/Pods | |
| ~/Library/Caches/CocoaPods | |
| ~/.cocoapods | |
| key: ${{ runner.os }}-${{ env.COCOAPODS_CACHE_KEY }}-${{ matrix.cocoapods }}-${{ matrix.architecture }}-${{ matrix.rn-version }}-${{ matrix.example-app }}-${{ hashFiles(format('{0}/ios/Podfile', matrix.example-app), 'package.json', 'react-native-image-marker.podspec') }} | |
| restore-keys: | | |
| ${{ runner.os }}-${{ env.COCOAPODS_CACHE_KEY }}-${{ matrix.cocoapods }}-${{ matrix.architecture }}-${{ matrix.rn-version }}-${{ matrix.example-app }}- | |
| ${{ runner.os }}-${{ env.COCOAPODS_CACHE_KEY }}-${{ matrix.cocoapods }}-${{ matrix.architecture }}-${{ matrix.rn-version }}- | |
| - name: Cache Ruby gems | |
| uses: actions/cache@v4 | |
| if: steps.verify-iOS-changed-files.outputs.any_changed == 'true' | |
| with: | |
| path: | | |
| vendor/bundle | |
| ~/.gem | |
| key: ${{ runner.os }}-gems-${{ env.RUBY_VERSION }}-${{ hashFiles('Gemfile.lock', format('{0}/Gemfile.lock', matrix.example-app)) }} | |
| restore-keys: | | |
| ${{ runner.os }}-gems-${{ env.RUBY_VERSION }}- | |
| - name: Set up Ruby | |
| uses: ruby/setup-ruby@v1 | |
| if: steps.verify-iOS-changed-files.outputs.any_changed == 'true' | |
| with: | |
| ruby-version: ${{ env.RUBY_VERSION }} | |
| bundler-cache: true | |
| - name: Install CocoaPods | |
| if: steps.verify-iOS-changed-files.outputs.any_changed == 'true' | |
| run: gem install cocoapods -v ${{ matrix.cocoapods }} | |
| - name: Setup node | |
| if: steps.verify-iOS-changed-files.outputs.any_changed == 'true' | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| - name: Configure cross-platform architecture | |
| if: steps.verify-iOS-changed-files.outputs.any_changed == 'true' | |
| run: | | |
| cd ${{ matrix.example-app }}/ios | |
| echo "Configuring ${{ matrix.architecture }} architecture for RN ${{ matrix.rn-version }}..." | |
| if [ "${{ matrix.architecture }}" = "new" ]; then | |
| export RCT_NEW_ARCH_ENABLED=1 | |
| echo "RCT_NEW_ARCH_ENABLED=1" >> .xcode.env.local | |
| echo "# RN ${{ matrix.rn-version }} New Architecture Build" >> .xcode.env.local | |
| else | |
| export RCT_NEW_ARCH_ENABLED=0 | |
| echo "RCT_NEW_ARCH_ENABLED=0" >> .xcode.env.local | |
| echo "# RN ${{ matrix.rn-version }} Legacy Architecture Build" >> .xcode.env.local | |
| fi | |
| echo "USE_HERMES=1" >> .xcode.env.local | |
| cat .xcode.env.local | |
| - name: Run CI health check | |
| if: steps.verify-iOS-changed-files.outputs.any_changed == 'true' | |
| env: | |
| MATRIX_PLATFORM: ios | |
| MATRIX_ARCHITECTURE: ${{ matrix.architecture }} | |
| MATRIX_RN_VERSION: ${{ matrix.rn-version }} | |
| MATRIX_EXAMPLE_APP: ${{ matrix.example-app }} | |
| CACHE_HIT_COCOAPODS: ${{ steps.cache-enhanced-pods.outputs.cache-hit }} | |
| CACHE_HIT_NODE_MODULES: ${{ steps.cache-cross-platform-node-modules.outputs.cache-hit }} | |
| run: | | |
| echo "🏥 Running pre-build health checks..." | |
| node scripts/ci-error-handler.js health-check | |
| - name: Install example app dependencies | |
| if: steps.verify-iOS-changed-files.outputs.any_changed == 'true' | |
| run: | | |
| echo "📦 Installing dependencies for ${{ matrix.example-app }}..." | |
| cd ${{ matrix.example-app }} | |
| if ! yarn install --frozen-lockfile; then | |
| echo "⚠️ Frozen lockfile failed, updating lockfile..." | |
| yarn install | |
| fi | |
| - name: Setup iOS environment | |
| if: steps.verify-iOS-changed-files.outputs.any_changed == 'true' | |
| env: | |
| RCT_NEW_ARCH_ENABLED: ${{ matrix.architecture == 'new' && '1' || '0' }} | |
| run: | | |
| echo "🍎 Setting up iOS environment for ${{ matrix.architecture }} architecture..." | |
| cd ${{ matrix.example-app }}/ios | |
| # Configure Node.js path for Xcode | |
| NODE_PATH=$(command -v node) | |
| echo "Node.js found at: $NODE_PATH" | |
| # Create or update .xcode.env.local | |
| cat > .xcode.env.local << EOF | |
| # Auto-generated by iOS CI setup | |
| export NODE_BINARY=\$(command -v node) | |
| export RCT_NEW_ARCH_ENABLED=${{ matrix.architecture == 'new' && '1' || '0' }} | |
| export USE_HERMES=1 | |
| EOF | |
| echo "✅ Created .xcode.env.local:" | |
| cat .xcode.env.local | |
| # Verify CocoaPods installation | |
| POD_VERSION=$(pod --version) | |
| echo "✅ CocoaPods version: $POD_VERSION" | |
| - name: Install CocoaPods dependencies | |
| if: steps.cache-enhanced-pods.outputs.cache-hit != 'true' && steps.verify-iOS-changed-files.outputs.any_changed == 'true' | |
| env: | |
| RCT_NEW_ARCH_ENABLED: ${{ matrix.architecture == 'new' && '1' || '0' }} | |
| run: | | |
| echo "📦 Installing CocoaPods dependencies for ${{ matrix.architecture }} architecture..." | |
| cd ${{ matrix.example-app }}/ios | |
| # Clean previous builds and cached podspecs to avoid version conflicts | |
| rm -rf build DerivedData | |
| rm -rf Pods/Local\ Podspecs | |
| # Clean CocoaPods cache if there are version conflicts | |
| if [ -f "Podfile.lock" ]; then | |
| echo "🧹 Cleaning CocoaPods cache to avoid version conflicts..." | |
| pod cache clean --all || true | |
| # Remove Podfile.lock to force fresh resolution | |
| rm -f Podfile.lock | |
| fi | |
| # Install pods with architecture configuration | |
| if [ "${{ matrix.architecture }}" = "new" ]; then | |
| echo "🏗️ Installing with New Architecture enabled" | |
| RCT_NEW_ARCH_ENABLED=1 pod install --repo-update --verbose | |
| else | |
| echo "🏗️ Installing with Legacy Architecture" | |
| RCT_NEW_ARCH_ENABLED=0 pod install --repo-update --verbose | |
| fi | |
| echo "✅ CocoaPods installation completed" | |
| - name: Verify CocoaPods installation and recover from cache failure | |
| if: steps.verify-iOS-changed-files.outputs.any_changed == 'true' | |
| env: | |
| RCT_NEW_ARCH_ENABLED: ${{ matrix.architecture == 'new' && '1' || '0' }} | |
| run: | | |
| cd ${{ matrix.example-app }}/ios | |
| echo "🔍 Checking CocoaPods installation integrity..." | |
| # Check if CocoaPods installation is valid | |
| PODS_VALID=true | |
| # 1. Check if Pods directory exists and is not empty | |
| if [ ! -d "Pods" ] || [ ! "$(ls -A Pods 2>/dev/null)" ]; then | |
| echo "⚠️ Pods directory missing or empty" | |
| PODS_VALID=false | |
| fi | |
| # 2. Check if Podfile.lock exists | |
| if [ ! -f "Podfile.lock" ]; then | |
| echo "⚠️ Podfile.lock missing" | |
| PODS_VALID=false | |
| fi | |
| # 3. Check if critical Pod directories exist | |
| if [ "$PODS_VALID" = "true" ]; then | |
| CRITICAL_PODS=("React-Core" "React-RCTImage" "React-RCTText") | |
| for pod in "${CRITICAL_PODS[@]}"; do | |
| if [ ! -d "Pods/$pod" ]; then | |
| echo "⚠️ Critical pod missing: $pod" | |
| PODS_VALID=false | |
| break | |
| fi | |
| done | |
| fi | |
| # 4. Check cache hit status | |
| CACHE_HIT="${{ steps.cache-enhanced-pods.outputs.cache-hit }}" | |
| if [ "$CACHE_HIT" = "true" ] && [ "$PODS_VALID" = "false" ]; then | |
| echo "⚠️ Cache hit reported but Pods installation is invalid" | |
| echo "📊 This indicates cache corruption or partial restore" | |
| echo "🔍 Cache key used: ${{ runner.os }}-${{ env.COCOAPODS_CACHE_KEY }}-${{ matrix.cocoapods }}-${{ matrix.architecture }}-${{ matrix.rn-version }}-${{ matrix.example-app }}" | |
| fi | |
| if [ "$PODS_VALID" = "true" ]; then | |
| echo "✅ CocoaPods installation verified" | |
| echo "📊 Installed pods:" | |
| ls -la Pods/ | head -10 | |
| else | |
| echo "⚠️ CocoaPods installation incomplete (cache restore may have failed)" | |
| echo "🔄 Attempting to recover by reinstalling pods..." | |
| # Clean up incomplete installation | |
| rm -rf Pods Podfile.lock | |
| rm -rf build DerivedData | |
| # Reinstall pods | |
| if [ "${{ matrix.architecture }}" = "new" ]; then | |
| echo "🏗️ Installing with New Architecture enabled" | |
| RCT_NEW_ARCH_ENABLED=1 pod install --repo-update --verbose | |
| else | |
| echo "🏗️ Installing with Legacy Architecture" | |
| RCT_NEW_ARCH_ENABLED=0 pod install --repo-update --verbose | |
| fi | |
| # Verify installation after recovery | |
| if [ -d "Pods" ] && [ -f "Podfile.lock" ]; then | |
| echo "✅ CocoaPods installation recovered successfully" | |
| else | |
| echo "❌ CocoaPods installation failed after recovery attempt" | |
| exit 1 | |
| fi | |
| fi | |
| - name: Install xcpretty | |
| if: steps.verify-iOS-changed-files.outputs.any_changed == 'true' | |
| run: gem install xcpretty | |
| - name: Cross-platform iOS build and test with error handling | |
| if: steps.verify-iOS-changed-files.outputs.any_changed == 'true' | |
| env: | |
| MATRIX_PLATFORM: ios | |
| MATRIX_ARCHITECTURE: ${{ matrix.architecture }} | |
| MATRIX_RN_VERSION: ${{ matrix.rn-version }} | |
| MATRIX_EXAMPLE_APP: ${{ matrix.example-app }} | |
| RCT_NEW_ARCH_ENABLED: ${{ matrix.architecture == 'new' && '1' || '0' }} | |
| run: | | |
| echo "🍎 Building and testing iOS app for ${{ matrix.architecture }} architecture, RN ${{ matrix.rn-version }}..." | |
| node scripts/ci-error-handler.js monitor "./scripts/ios-ci-build.sh ${{ matrix.example-app }} ${{ matrix.architecture }} 3" | |
| - name: Upload iOS build artifacts | |
| if: steps.verify-iOS-changed-files.outputs.any_changed == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: iOS-Build-${{ matrix.architecture }}-${{ matrix.rn-version }}-${{ matrix.example-app }}-CocoaPods${{ matrix.cocoapods }} | |
| path: | | |
| ${{ github.workspace }}/${{ matrix.example-app }}/ios/build/DerivedData/Build/Products/Release-iphonesimulator/ | |
| ${{ github.workspace }}/${{ matrix.example-app }}/ios/build/DerivedData/Logs/ | |
| retention-days: 7 | |
| - name: Validate cross-platform iOS build artifacts | |
| if: steps.verify-iOS-changed-files.outputs.any_changed == 'true' | |
| run: | | |
| cd ${{ matrix.example-app }}/ios | |
| BUILD_DIR="build/DerivedData/Build/Products/Release-iphonesimulator" | |
| if [ -d "$BUILD_DIR" ] && [ "$(ls -A $BUILD_DIR)" ]; then | |
| echo "✅ iOS build artifacts created successfully for ${{ matrix.architecture }} architecture, RN ${{ matrix.rn-version }}" | |
| ls -la "$BUILD_DIR" | |
| else | |
| echo "❌ iOS build artifacts missing" | |
| exit 1 | |
| fi | |
| - name: Generate build report | |
| if: always() && steps.verify-iOS-changed-files.outputs.any_changed == 'true' | |
| env: | |
| MATRIX_PLATFORM: ios | |
| MATRIX_ARCHITECTURE: ${{ matrix.architecture }} | |
| MATRIX_RN_VERSION: ${{ matrix.rn-version }} | |
| MATRIX_EXAMPLE_APP: ${{ matrix.example-app }} | |
| run: | | |
| echo "📊 Generating build report..." | |
| node scripts/ci-error-handler.js report | |
| - name: Upload build reports | |
| if: always() && steps.verify-iOS-changed-files.outputs.any_changed == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ios-build-reports-${{ matrix.architecture }}-${{ matrix.rn-version }}-${{ matrix.example-app }}-CocoaPods${{ matrix.cocoapods }} | |
| path: | | |
| ci-*.md | |
| ci-build.log | |
| retention-days: 7 | |
| # Cross-platform CI completion with enhanced reporting | |
| ci-complete: | |
| name: Cross-Platform CI Complete | |
| needs: [security, architecture-compatibility, validate-build-configs, android-build, android-api-level-test, ios-build-test] | |
| if: ${{ always() }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code for reporting | |
| uses: actions/checkout@v4 | |
| - name: Collect cross-platform build results | |
| run: | | |
| echo "## Cross-Platform CI Build Results" >> $GITHUB_STEP_SUMMARY | |
| echo "| Job | Status | Platform | Architecture | RN Version |" >> $GITHUB_STEP_SUMMARY | |
| echo "|-----|--------|----------|--------------|------------|" >> $GITHUB_STEP_SUMMARY | |
| # Security checks | |
| if [ "${{ needs.security.result }}" = "success" ]; then | |
| echo "| Security & Dependency Review | ✅ Success | Cross-Platform | N/A | N/A |" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "| Security & Dependency Review | ❌ ${{ needs.security.result }} | Cross-Platform | N/A | N/A |" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| # Architecture compatibility | |
| if [ "${{ needs.architecture-compatibility.result }}" = "success" ]; then | |
| echo "| Architecture Compatibility | ✅ Success | Cross-Platform | Legacy + New | Multiple |" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "| Architecture Compatibility | ❌ ${{ needs.architecture-compatibility.result }} | Cross-Platform | Legacy + New | Multiple |" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| # Build config validation | |
| if [ "${{ needs.validate-build-configs.result }}" = "success" ]; then | |
| echo "| Build Configuration Validation | ✅ Success | Android + iOS | Legacy + New | 0.73 + 0.81 + 0.8x |" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "| Build Configuration Validation | ❌ ${{ needs.validate-build-configs.result }} | Android + iOS | Legacy + New | 0.73 + 0.81 + 0.8x |" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| # Android builds | |
| if [ "${{ needs.android-build.result }}" = "success" ]; then | |
| echo "| Android Build | ✅ Success | Android | Legacy + New | 0.73 + 0.81 |" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "| Android Build | ❌ ${{ needs.android-build.result }} | Android | Legacy + New | 0.73 + 0.81 |" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| # Android API tests | |
| if [ "${{ needs.android-api-level-test.result }}" = "success" ]; then | |
| echo "| Android API Level Test | ✅ Success | Android | Legacy + New | API 24/31/34 |" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "| Android API Level Test | ❌ ${{ needs.android-api-level-test.result }} | Android | Legacy + New | API 24/31/34 |" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| # iOS builds | |
| if [ "${{ needs.ios-build-test.result }}" = "success" ]; then | |
| echo "| iOS Build and Test | ✅ Success | iOS | Legacy + New | 0.73 + 0.81 |" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "| iOS Build and Test | ❌ ${{ needs.ios-build-test.result }} | iOS | Legacy + New | 0.73 + 0.81 |" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| - name: Check all cross-platform job status | |
| if: >- | |
| ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }} | |
| run: | | |
| echo "❌ Cross-platform CI failed!" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Failed Jobs:" >> $GITHUB_STEP_SUMMARY | |
| if [ "${{ needs.security.result }}" != "success" ]; then | |
| echo "- Security & Dependency Review: ${{ needs.security.result }}" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [ "${{ needs.architecture-compatibility.result }}" != "success" ]; then | |
| echo "- Architecture Compatibility: ${{ needs.architecture-compatibility.result }}" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [ "${{ needs.validate-build-configs.result }}" != "success" ]; then | |
| echo "- Build Configuration Validation: ${{ needs.validate-build-configs.result }}" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [ "${{ needs.android-build.result }}" != "success" ]; then | |
| echo "- Android Build: ${{ needs.android-build.result }}" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [ "${{ needs.android-api-level-test.result }}" != "success" ]; then | |
| echo "- Android API Level Test: ${{ needs.android-api-level-test.result }}" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [ "${{ needs.ios-build-test.result }}" != "success" ]; then | |
| echo "- iOS Build and Test: ${{ needs.ios-build-test.result }}" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| exit 1 | |
| - name: Report cross-platform success | |
| if: ${{ !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') }} | |
| run: | | |
| echo "🎉 All cross-platform CI tests passed!" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### ✅ Successful Cross-Platform Validations:" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Security checks** passed across all platforms" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Architecture compatibility** validated for Legacy and New Architecture" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Build configurations** validated for Android and iOS" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Android builds and tests** passed for multiple RN versions and API levels" >> $GITHUB_STEP_SUMMARY | |
| echo "- **iOS builds and tests** passed for multiple RN versions and CocoaPods versions" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Cross-platform caching** optimized build times" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Parallel builds** executed successfully without conflicts" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 📊 Build Matrix Coverage:" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Platforms**: Android, iOS" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Architectures**: Legacy, New Architecture (TurboModules + Fabric)" >> $GITHUB_STEP_SUMMARY | |
| echo "- **React Native Versions**: 0.73, 0.81, 0.8x" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Example Apps**: example (Legacy), example-0.73 (New Architecture)" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Android API Levels**: 24, 31, 34" >> $GITHUB_STEP_SUMMARY | |
| echo "- **CocoaPods Versions**: 1.14.3, 1.15.2" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Xcode Versions**: 15.0, 15.2" >> $GITHUB_STEP_SUMMARY |