diff --git a/.github/workflows/android-basic.yml b/.github/workflows/android-basic.yml new file mode 100644 index 0000000000..e283655989 --- /dev/null +++ b/.github/workflows/android-basic.yml @@ -0,0 +1,34 @@ +name: Build Android (basic-example) + +on: + pull_request: + paths: + - .github/workflows/android-basic.yml + - .github/workflows/android-build.yml + - packages/react-native-gesture-handler/package.json + - packages/react-native-gesture-handler/android/** + - packages/react-native-gesture-handler/shared/** + - packages/react-native-gesture-handler/src/specs/** + - apps/basic-example/** + - '!apps/basic-example/ios/**' + - '!apps/basic-example/Gemfile*' + - rnrepo.config.json + - yarn.lock + push: + branches: + - main + workflow_dispatch: + +concurrency: + group: android-basic-${{ github.ref }} + cancel-in-progress: true + +jobs: + basic-example: + if: github.repository == 'software-mansion/react-native-gesture-handler' + + uses: ./.github/workflows/android-build.yml + with: + app: basic-example + artifact-name: android-apk-basic-example + abi: x86_64 diff --git a/.github/workflows/android-build.yml b/.github/workflows/android-build.yml index 590dd55ad9..78b3d91c5a 100644 --- a/.github/workflows/android-build.yml +++ b/.github/workflows/android-build.yml @@ -1,30 +1,26 @@ -name: Test Android build +name: Build Android app +# Reusable: builds one example app in Release and uploads the APK. on: - pull_request: - paths: - - .github/workflows/android-build.yml - - packages/react-native-gesture-handler/android/** - - apps/basic-example/android/** - - apps/basic-example/package.json - - rnrepo.config.json - - yarn.lock - push: - branches: - - main - workflow_dispatch: + workflow_call: + inputs: + app: + description: Directory under apps/ holding the example app to build. + required: true + type: string + artifact-name: + description: Name to upload the built APK under. + required: true + type: string + abi: + description: ABI to build. Must match the emulator the e2e job installs the APK on. + required: true + type: string jobs: build: - if: github.repository == 'software-mansion/react-native-gesture-handler' - runs-on: ubuntu-latest - strategy: - matrix: - working-directory: [apps/basic-example, apps/expo-example] - concurrency: - group: android-${{ matrix.working-directory }}-${{ github.ref }} - cancel-in-progress: true + timeout-minutes: 60 steps: - name: checkout @@ -43,9 +39,18 @@ jobs: cache: yarn - name: Install node dependencies - working-directory: ${{ matrix.working-directory }} + working-directory: apps/${{ inputs.app }} run: yarn install --immutable - - name: Build app - working-directory: ${{ matrix.working-directory }}/android - run: ./gradlew :app:assembleDebug --console=plain -PreactNativeArchitectures=arm64-v8a + - name: Build app in Release mode + working-directory: apps/${{ inputs.app }}/android + run: ./gradlew :app:assembleRelease --console=plain -PreactNativeArchitectures=${{ inputs.abi }} + + - name: Upload APK artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.artifact-name }} + path: apps/${{ inputs.app }}/android/app/build/outputs/apk/release/*.apk + if-no-files-found: error + compression-level: 0 + retention-days: 3 diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml new file mode 100644 index 0000000000..6ad16bb9b2 --- /dev/null +++ b/.github/workflows/android.yml @@ -0,0 +1,33 @@ +name: Build Android (expo-example) + +on: + pull_request: + paths: + - .github/workflows/android.yml + - .github/workflows/android-build.yml + - packages/react-native-gesture-handler/package.json + - packages/react-native-gesture-handler/android/** + - packages/react-native-gesture-handler/shared/** + - packages/react-native-gesture-handler/src/** + - apps/expo-example/** + - apps/common-app/** + - rnrepo.config.json + - yarn.lock + push: + branches: + - main + workflow_dispatch: + +concurrency: + group: android-${{ github.ref }} + cancel-in-progress: true + +jobs: + expo-example: + if: github.repository == 'software-mansion/react-native-gesture-handler' + + uses: ./.github/workflows/android-build.yml + with: + app: expo-example + artifact-name: android-apk-expo-example + abi: x86_64 diff --git a/.github/workflows/ios-basic.yml b/.github/workflows/ios-basic.yml new file mode 100644 index 0000000000..c05c6e6f43 --- /dev/null +++ b/.github/workflows/ios-basic.yml @@ -0,0 +1,35 @@ +name: Build iOS (basic-example) + +on: + pull_request: + paths: + - .github/workflows/ios-basic.yml + - .github/workflows/ios-build.yml + - packages/react-native-gesture-handler/package.json + - packages/react-native-gesture-handler/RNGestureHandler.podspec + - packages/react-native-gesture-handler/apple/** + - packages/react-native-gesture-handler/shared/** + - packages/react-native-gesture-handler/src/specs/** + - apps/basic-example/** + - '!apps/basic-example/android/**' + - rnrepo.config.json + - yarn.lock + push: + branches: + - main + workflow_dispatch: + +concurrency: + group: ios-basic-${{ github.ref }} + cancel-in-progress: true + +jobs: + basic-example: + if: github.repository == 'software-mansion/react-native-gesture-handler' + + uses: ./.github/workflows/ios-build.yml + with: + app: basic-example + scheme: BasicExample + artifact-name: ios-app-basic-example + xcode-version: '26.4.1' diff --git a/.github/workflows/ios-build.yml b/.github/workflows/ios-build.yml index 30076035ac..ad22f873fb 100644 --- a/.github/workflows/ios-build.yml +++ b/.github/workflows/ios-build.yml @@ -1,40 +1,49 @@ -name: Test iOS build +name: Build iOS app +# Reusable: builds one example app for the simulator in Release and uploads the +# .app bundle. on: - pull_request: - paths: - - .github/workflows/ios-build.yml - - packages/react-native-gesture-handler/RNGestureHandler.podspec - - packages/react-native-gesture-handler/apple/** - - apps/basic-example/ios/** - - apps/basic-example/package.json - - rnrepo.config.json - - yarn.lock - push: - branches: - - main - workflow_dispatch: + workflow_call: + inputs: + app: + description: Directory under apps/ holding the example app to build. + required: true + type: string + scheme: + description: Xcode scheme of the app (also the workspace name). + required: true + type: string + artifact-name: + description: Name to upload the packaged .app bundle under. + required: true + type: string + xcode-version: + description: Xcode version to build with. + required: true + type: string jobs: build: - if: github.repository == 'software-mansion/react-native-gesture-handler' - runs-on: macos-26 - strategy: - matrix: - working-directory: [apps/basic-example, apps/expo-example] - concurrency: - group: ios-${{ matrix.working-directory }}-${{ github.ref }} - cancel-in-progress: true + timeout-minutes: 60 steps: - name: checkout uses: actions/checkout@v4 - - name: Use latest stable Xcode - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: '26.4.1' + - name: Select Xcode + env: + XCODE_VERSION: ${{ inputs.xcode-version }} + run: | + XCODE_APP="/Applications/Xcode_${XCODE_VERSION}.app" + if [ ! -d "$XCODE_APP" ]; then + echo "Xcode ${XCODE_VERSION} is not installed on this runner. Available:" >&2 + ls -d /Applications/Xcode*.app >&2 + exit 1 + fi + echo "Using $XCODE_APP" + echo "DEVELOPER_DIR=$XCODE_APP/Contents/Developer" >> "$GITHUB_ENV" + DEVELOPER_DIR="$XCODE_APP/Contents/Developer" xcodebuild -version - name: Use Node.js 24 uses: actions/setup-node@v6 @@ -43,14 +52,48 @@ jobs: cache: yarn - name: Install node dependencies - working-directory: ${{ matrix.working-directory }} + working-directory: apps/${{ inputs.app }} run: yarn install --immutable + # expo-example runs `expo prebuild` on postinstall, which installs its pods. - name: Install pods - if: ${{ matrix.working-directory == 'apps/basic-example' }} - working-directory: ${{ matrix.working-directory }}/ios + if: ${{ inputs.app == 'basic-example' }} + working-directory: apps/${{ inputs.app }}/ios run: bundle install && NO_FLIPPER=1 bundle exec pod install - - name: Build app - working-directory: ${{ matrix.working-directory }} - run: npx react-native run-ios + - name: Build app in Release mode + working-directory: apps/${{ inputs.app }}/ios + run: | + xcodebuild \ + -workspace ${{ inputs.scheme }}.xcworkspace \ + -scheme ${{ inputs.scheme }} \ + -configuration Release \ + -sdk iphonesimulator \ + -destination 'generic/platform=iOS Simulator' \ + -derivedDataPath build \ + CODE_SIGNING_ALLOWED=NO \ + build + + # Artifact zips drop POSIX permissions and symlinks, which would leave the + # .app with a non-executable binary — tar the bundle to keep it installable. + - name: Package app bundle + working-directory: apps/${{ inputs.app }}/ios + run: | + APP_PATH=$(find build/Build/Products/Release-iphonesimulator -maxdepth 1 -name '*.app' -type d | head -1) + if [ -z "$APP_PATH" ]; then + echo "Could not find built .app" >&2 + exit 1 + fi + echo "Packaging $APP_PATH" + mkdir -p "$RUNNER_TEMP/artifact" + tar -czf "$RUNNER_TEMP/artifact/app.tar.gz" \ + -C "$(dirname "$APP_PATH")" "$(basename "$APP_PATH")" + + - name: Upload app artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.artifact-name }} + path: ${{ runner.temp }}/artifact/app.tar.gz + if-no-files-found: error + compression-level: 0 + retention-days: 3 diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml new file mode 100644 index 0000000000..a40c21d9ac --- /dev/null +++ b/.github/workflows/ios.yml @@ -0,0 +1,35 @@ +name: Build iOS (expo-example) + +on: + pull_request: + paths: + - .github/workflows/ios.yml + - .github/workflows/ios-build.yml + - packages/react-native-gesture-handler/package.json + - packages/react-native-gesture-handler/RNGestureHandler.podspec + - packages/react-native-gesture-handler/apple/** + - packages/react-native-gesture-handler/shared/** + - packages/react-native-gesture-handler/src/** + - apps/expo-example/** + - apps/common-app/** + - rnrepo.config.json + - yarn.lock + push: + branches: + - main + workflow_dispatch: + +concurrency: + group: ios-${{ github.ref }} + cancel-in-progress: true + +jobs: + expo-example: + if: github.repository == 'software-mansion/react-native-gesture-handler' + + uses: ./.github/workflows/ios-build.yml + with: + app: expo-example + scheme: ExpoExample + artifact-name: ios-app-expo-example + xcode-version: '26.4.1' diff --git a/.github/workflows/static-example-apps-checks.yml b/.github/workflows/static-example-apps-checks.yml index a454c914cc..92e4d572a4 100644 --- a/.github/workflows/static-example-apps-checks.yml +++ b/.github/workflows/static-example-apps-checks.yml @@ -3,7 +3,7 @@ name: Test TypeScript and Lint on: pull_request: paths: - - apps/basic-example/**' + - apps/basic-example/** - apps/common-app/** push: branches: