name: CI - Multi-Platform Native on: pull_request: push: branches: [ master, develop ] workflow_dispatch: inputs: configuration: description: 'Build configuration' required: false default: 'Debug' type: choice options: - Debug - Release platforms: description: 'Comma-separated platforms to build (ios, android, linux)' required: false default: 'ios' type: string run_tests: description: 'Run unit tests' required: false default: true type: boolean defaults: run: shell: bash jobs: # iOS Build Job build-ios: name: Build iOS (RSSuper) runs-on: macOS steps: - name: Checkout code uses: actions/checkout@v4 - name: Show available Xcode versions run: | echo "=== Available Xcode installations ===" ls -la /Applications/ | grep -i xcode || echo "No Xcode found in /Applications" echo "" echo "=== Current xcode-select path ===" xcode-select -p || echo "xcode-select failed" echo "" echo "=== xcodebuild version ===" xcodebuild -version || echo "xcodebuild failed" - name: Select Xcode version run: | echo "=== Current xcode-select path ===" xcode-select -p || echo "xcode-select failed" echo "=== Current Xcode version ===" xcodebuild -version || echo "xcodebuild failed" # Try common Xcode paths in order of preference (newest first) for path in \ "/Applications/Xcode_16.3.app/Contents/Developer" \ "/Applications/Xcode_16.2.app/Contents/Developer" \ "/Applications/Xcode_16.1.app/Contents/Developer" \ "/Applications/Xcode_16.0.app/Contents/Developer" \ "/Applications/Xcode_15.4.app/Contents/Developer" \ "/Applications/Xcode_15.3.app/Contents/Developer" \ "/Applications/Xcode_15.2.app/Contents/Developer" \ "/Applications/Xcode_15.1.app/Contents/Developer" \ "/Applications/Xcode_15.0.app/Contents/Developer" \ "/Applications/Xcode.app/Contents/Developer" do if [ -d "$path" ]; then CURRENT_PATH=$(xcode-select -p 2>/dev/null || echo "") if [ "$CURRENT_PATH" != "$path" ]; then echo "Switching Xcode to: $path" xcode-select -s "$path" || true else echo "Xcode already selected at: $path" fi break fi done echo "=== Selected Xcode path ===" xcode-select -p echo "=== Xcode version ===" xcodebuild -version - name: Build iOS Debug id: build_ios_debug run: | cd native-route/ios/RSSuper TIMESTAMP=$(date -u "+%Y-%m-%d %H:%M:%S UTC") COMMIT="${{ github.sha }}" SHORT_COMMIT="${COMMIT:0:7}" REF="${{ github.ref_name }}" BUILD_LOG=$(mktemp) echo "Capturing build output to: $BUILD_LOG" set +e xcodebuild -project RSSuper.xcodeproj \ -scheme RSSuper \ -configuration Debug \ -destination "generic/platform=iOS" \ build > "$BUILD_LOG" 2>&1 BUILD_EXIT=$? set -e cat "$BUILD_LOG" echo "Build completed with exit code: $BUILD_EXIT" if [ "$BUILD_EXIT" = "0" ]; then STATUS="PASSED" else STATUS="FAILED" fi # Extract errors ERRORS="" WARNINGS="" FALLBACK="" if [ -f "$BUILD_LOG" ] && [ -s "$BUILD_LOG" ]; then ERRORS=$(grep -E "\.swift:[0-9]+:[0-9]+: error:" "$BUILD_LOG" \ | sed 's|.*/\([^/]*\.swift\)|\1|' \ | sort -u || true) GENERAL_ERRORS=$(grep -E "error:|Error:" "$BUILD_LOG" \ | grep -v "\.swift:[0-9]+:[0-9]+:" \ | head -10 || true) WARNINGS=$(grep -E "\.swift:[0-9]+:[0-9]+: warning:" "$BUILD_LOG" \ | sed 's|.*/\([^/]*\.swift\)|\1|' \ | sort -u || true) if [ -z "$ERRORS" ] && [ -z "$GENERAL_ERRORS" ]; then FALLBACK=$(grep -E "error:|failed|FAILED|BUILD FAILED|note:" "$BUILD_LOG" \ | grep -v "^export " \ | grep -v "^ " \ | tail -30 || true) fi fi # Generate iOS build report { echo "# iOS Build Report" echo "" echo "| | |" echo "|---|---|" echo "| **Status** | $STATUS |" echo "| **Commit** | \`$SHORT_COMMIT\` |" echo "| **Branch** | \`$REF\` |" echo "| **Time** | $TIMESTAMP |" echo "" if [ "$STATUS" = "FAILED" ]; then echo "## Errors" echo "" if [ -n "$ERRORS" ]; then echo '```' echo "$ERRORS" echo '```' echo "" fi else echo "## Result" echo "" echo "iOS build completed successfully." echo "" fi if [ -n "$WARNINGS" ]; then echo "## Warnings" echo "" echo '```' echo "$WARNINGS" echo '```' echo "" fi } > ios-build-report.md echo "=== Generated ios-build-report.md ===" cat ios-build-report.md rm -f "$BUILD_LOG" exit $BUILD_EXIT - name: Upload iOS Debug artifact if: steps.build_ios_debug.outcome == 'success' uses: actions/upload-artifact@v4 with: name: RSSuper-iOS-Debug path: | ~/Library/Developer/Xcode/DerivedData/RSSuper-*/Build/Products/Debug-iphoneos/RSSuper.app if-no-files-found: warn retention-days: 7 - name: Run iOS Unit Tests if: ${{ github.event_name != 'workflow_dispatch' || inputs.run_tests == true }} run: | cd native-route/ios/RSSuper xcodebuild test -project RSSuper.xcodeproj \ -scheme RSSuper \ -configuration Debug \ -destination "generic/platform=iOS" \ ONLY_ACTIVE_ARCH=NO - name: Build iOS Release run: | cd native-route/ios/RSSuper xcodebuild -project RSSuper.xcodeproj \ -scheme RSSuper \ -configuration Release \ -destination "generic/platform=iOS" \ build - name: Upload iOS Release artifact uses: actions/upload-artifact@v4 with: name: RSSuper-iOS-Release path: | ~/Library/Developer/Xcode/DerivedData/RSSuper-*/Build/Products/Release-iphoneos/RSSuper.app if-no-files-found: warn retention-days: 30 # macOS Build Job (using same iOS project) build-macos: name: Build macOS runs-on: macOS steps: - name: Checkout code uses: actions/checkout@v4 - name: Select Xcode run: | xcode-select -s /Applications/Xcode.app/Contents/Developer xcodebuild -version - name: Build macOS run: | cd native-route/ios/RSSuper # Note: This requires the Xcode project to have a macOS target # For now, we'll build for iOS simulator which can run on macOS xcodebuild -project RSSuper.xcodeproj \ -scheme RSSuper \ -configuration Debug \ -destination "platform=macOS" \ build || echo "macOS target not configured yet" # Android Build Job build-android: name: Build Android runs-on: ubuntu-24.04 steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up JDK 17 uses: actions/setup-java@v4 with: java-version: '17' distribution: 'temurin' - name: Setup Android SDK uses: android-actions/setup-android@v3 - name: Build Android Debug run: | cd native-route/android # Create basic Android project structure if it doesn't exist if [ ! -f "build.gradle.kts" ]; then echo "Android project not yet initialized" echo "Placeholder for Android build" else ./gradlew assembleDebug fi - name: Upload Android artifact if: always() uses: actions/upload-artifact@v4 with: name: RSSuper-Android-Debug path: native-route/android/app/build/outputs/apk/debug/*.apk if-no-files-found: ignore retention-days: 7 # Linux Build Job build-linux: name: Build Linux runs-on: ubuntu steps: - name: Checkout code uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y \ build-essential \ cmake \ ninja-build \ pkg-config \ libgtk-3-dev \ libsqlite3-dev - name: Build Linux run: | cd native-route/linux # Placeholder for Linux build # This will be set up with proper build system later echo "Linux build placeholder" echo "Project structure will be created with:" echo "- CMake or Meson build system" echo "- GTK4 or GTK+3 for UI" echo "- Swift Linux runtime or alternative" # Summary Job build-summary: name: Build Summary runs-on: ubuntu needs: [build-ios, build-macos, build-android, build-linux] if: always() steps: - name: Generate Summary run: | echo "# RSSuper Multi-Platform Build Summary" > summary.md echo "" >> summary.md echo "## Build Results" >> summary.md echo "" >> summary.md echo "| Platform | Status |" >> summary.md echo "|----------|--------|" >> summary.md echo "| iOS | ${{ needs.build-ios.result }} |" >> summary.md echo "| macOS | ${{ needs.build-macos.result }} |" >> summary.md echo "| Android | ${{ needs.build-android.result }} |" >> summary.md echo "| Linux | ${{ needs.build-linux.result }} |" >> summary.md echo "" >> summary.md echo "## Details" >> summary.md echo "" >> summary.md echo "- **Commit:** ${{ github.sha }}" >> summary.md echo "- **Branch:** ${{ github.ref_name }}" >> summary.md echo "- **Date:** $(date -u "+%Y-%m-%d %H:%M:%S UTC")" >> summary.md echo "" >> summary.md cat summary.md - name: Upload Summary uses: actions/upload-artifact@v4 with: name: build-summary path: summary.md retention-days: 1