name: iOS Build & Deploy on: push: tags: - "ios-v*" workflow_dispatch: inputs: upload_to_testflight: description: "Upload to TestFlight after build" required: false default: "true" type: choice options: - "true" - "false" concurrency: group: ios-build-${{ github.ref }} cancel-in-progress: true jobs: test: name: Test runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: "20" cache: "npm" - name: Install backend dependencies & test run: cd backend && npm ci && npm test -- --ci - name: Install frontend dependencies & test run: cd frontend && npm ci && npm test -- --run --reporter=basic build-ios: name: Build iOS App needs: test runs-on: macos-14 env: SCHEME: App PROJECT: ios/App/App.xcodeproj WORKSPACE: ios/App/App.xcworkspace ARCHIVE_PATH: build/App.xcarchive IPA_PATH: build/App.ipa EXPORT_OPTIONS: scripts/export-options.plist steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: "20" cache: "npm" - name: Install root dependencies run: npm ci - name: Install frontend dependencies run: cd frontend && npm ci - name: Build web bundle run: npm run build:web - name: Ensure iOS platform & sync Capacitor run: | if [ ! -d "ios/App/App.xcodeproj" ]; then echo "Adding iOS platform..." npx cap add ios fi npx cap sync ios - name: Install CocoaPods run: cd ios/App && pod install --repo-update - name: Install Apple certificates & provisioning profile uses: apple-actions/import-codesign-certs@v2 with: p12-file-base64: ${{ secrets.IOS_P12_BASE64 }} p12-password: ${{ secrets.IOS_P12_PASSWORD }} - name: Install provisioning profile run: | mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles echo "${{ secrets.IOS_PROVISION_PROFILE_BASE64 }}" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/${{ secrets.IOS_PROVISION_PROFILE_UUID }}.mobileprovision - name: Set version from tag if: startsWith(github.ref, 'refs/tags/ios-v') run: | TAG_VERSION="${GITHUB_REF#refs/tags/ios-v}" MAJOR=$(echo "$TAG_VERSION" | cut -d. -f1) MINOR=$(echo "$TAG_VERSION" | cut -d. -f2) PATCH=$(echo "$TAG_VERSION" | cut -d. -f3) BUILD=${{ github.run_number }} echo "Setting MARKETING_VERSION=$MAJOR.$MINOR.$PATCH" echo "Setting CURRENT_PROJECT_VERSION=$BUILD" sed -i '' "s/MARKETING_VERSION = .*;/MARKETING_VERSION = $MAJOR.$MINOR.$PATCH;/" ios/App/App.xcodeproj/project.pbxproj sed -i '' "s/CURRENT_PROJECT_VERSION = .*;/CURRENT_PROJECT_VERSION = $BUILD;/" ios/App/App.xcodeproj/project.pbxproj - name: Build Xcode archive run: | xcodebuild archive \ -workspace "$WORKSPACE" \ -scheme "$SCHEME" \ -configuration Release \ -destination "generic/platform=iOS" \ -archivePath "$ARCHIVE_PATH" \ -allowProvisioningUpdates \ CODE_SIGN_STYLE=Manual \ DEVELOPMENT_TEAM="${{ secrets.IOS_TEAM_ID }}" \ PROVISIONING_PROFILE_SPECIFIER="${{ secrets.IOS_PROVISION_PROFILE_NAME }}" \ | xcpretty --color || true - name: Export IPA run: | plutil -replace teamID -string "${{ secrets.IOS_TEAM_ID }}" "$EXPORT_OPTIONS" 2>/dev/null || true plutil -replace provisioningProfiles.net.hacecalor.farmafinder -string "${{ secrets.IOS_PROVISION_PROFILE_NAME }}" "$EXPORT_OPTIONS" 2>/dev/null || true xcodebuild -exportArchive \ -archivePath "$ARCHIVE_PATH" \ -exportOptionsPlist "$EXPORT_OPTIONS" \ -exportPath build \ -allowProvisioningUpdates \ | xcpretty --color || true - name: Upload artifact (IPA) uses: actions/upload-artifact@v4 with: name: FarmaFinder-iOS path: build/*.ipa retention-days: 30 - name: Upload to TestFlight if: > (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/ios-v')) || (github.event_name == 'workflow_dispatch' && inputs.upload_to_testflight == 'true') run: | xcrun altool \ --upload-app \ --type ios \ --file "$IPA_PATH" \ --apiKey "${{ secrets.APP_STORE_API_KEY_ID }}" \ --apiIssuer "${{ secrets.APP_STORE_API_ISSUER_ID }}" env: API_PRIVATE_KEY: ${{ secrets.APP_STORE_API_PRIVATE_KEY }} - name: Summary run: | if [ -f "$IPA_PATH" ]; then IPA_SIZE=$(du -h "$IPA_PATH" | cut -f1) echo "### iOS Build Summary" >> $GITHUB_STEP_SUMMARY echo "| Item | Value |" >> $GITHUB_STEP_SUMMARY echo "|------|-------|" >> $GITHUB_STEP_SUMMARY echo "| IPA Size | $IPA_SIZE |" >> $GITHUB_STEP_SUMMARY echo "| Tag | ${GITHUB_REF#refs/tags/} |" >> $GITHUB_STEP_SUMMARY echo "| Build # | ${{ github.run_number }} |" >> $GITHUB_STEP_SUMMARY else echo "::error::IPA not found at $IPA_PATH" exit 1 fi