fix(ci): fix lint, build types path, and iOS grep #4
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: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| concurrency: | |
| group: ci-${{ github.ref }} | |
| cancel-in-progress: true | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # Job 1: Typecheck & Lint | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| jobs: | |
| typecheck-lint: | |
| name: Typecheck & Lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node 20 | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| - name: Install dependencies | |
| # --ignore-scripts prevents `prepare` (bob build) from running during install. | |
| # The build is validated separately in the Build job. | |
| run: npm install --ignore-scripts --legacy-peer-deps | |
| - name: Typecheck | |
| run: npm run typecheck | |
| - name: Lint | |
| run: npm run lint | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # Job 2: Build — verifies bob compiles src/ to all three output targets | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| build: | |
| name: Build Package | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node 20 | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| - name: Install dependencies | |
| run: npm install --ignore-scripts --legacy-peer-deps | |
| - name: Build | |
| run: npm run build | |
| - name: Verify outputs | |
| run: | | |
| echo "=== CommonJS ===" | |
| ls lib/commonjs/ | |
| echo "=== ESM ===" | |
| ls lib/module/ | |
| echo "=== Types ===" | |
| ls lib/typescript/src/ | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # Job 3: Android — structure & manifest validation | |
| # Full Kotlin compile requires a host app; we validate files & manifest instead. | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| android-validate: | |
| name: Android Validate | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Validate required Kotlin files exist | |
| run: | | |
| required=( | |
| "android/build.gradle" | |
| "android/src/main/AndroidManifest.xml" | |
| "android/src/main/java/com/rick427/backgroundtimer/BackgroundTimerModule.kt" | |
| "android/src/main/java/com/rick427/backgroundtimer/BackgroundTimerPackage.kt" | |
| "android/src/main/java/com/rick427/backgroundtimer/BackgroundTimerService.kt" | |
| "android/src/main/java/com/rick427/backgroundtimer/AlarmReceiver.kt" | |
| "android/src/main/java/com/rick427/backgroundtimer/BootReceiver.kt" | |
| "android/src/main/java/com/rick427/backgroundtimer/TimerStore.kt" | |
| "android/src/main/java/com/rick427/backgroundtimer/TimerData.kt" | |
| ) | |
| failed=0 | |
| for f in "${required[@]}"; do | |
| if [ -f "$f" ]; then | |
| echo " ✅ $f" | |
| else | |
| echo " ❌ MISSING: $f" | |
| failed=1 | |
| fi | |
| done | |
| exit $failed | |
| - name: Validate AndroidManifest permissions & components | |
| run: | | |
| manifest="android/src/main/AndroidManifest.xml" | |
| check() { | |
| local label="$1"; local pattern="$2" | |
| if grep -q "$pattern" "$manifest"; then | |
| echo "✅ $label" | |
| else | |
| echo "❌ MISSING: $label" | |
| exit 1 | |
| fi | |
| } | |
| check "FOREGROUND_SERVICE permission" "FOREGROUND_SERVICE" | |
| check "WAKE_LOCK permission" "WAKE_LOCK" | |
| check "SCHEDULE_EXACT_ALARM permission" "SCHEDULE_EXACT_ALARM" | |
| check "RECEIVE_BOOT_COMPLETED permission" "RECEIVE_BOOT_COMPLETED" | |
| check "BackgroundTimerService declared" "BackgroundTimerService" | |
| check "AlarmReceiver declared" "AlarmReceiver" | |
| check "BootReceiver declared" "BootReceiver" | |
| - name: Validate AGP 8 namespace in build.gradle | |
| run: | | |
| if grep -q 'namespace "com.rick427.backgroundtimer"' android/build.gradle; then | |
| echo "✅ namespace declared (AGP 8+ requirement)" | |
| else | |
| echo "❌ namespace missing from build.gradle" | |
| exit 1 | |
| fi | |
| - name: Validate minSdk is 26 (Android 8+) | |
| run: | | |
| if grep -q 'minSdk 26' android/build.gradle; then | |
| echo "✅ minSdk 26 declared" | |
| else | |
| echo "❌ minSdk 26 not found — required for Foreground Services" | |
| exit 1 | |
| fi | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # Job 4: iOS — Swift source & podspec validation | |
| # Full pod compile requires Xcode + RN; we validate structure & key APIs. | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| ios-validate: | |
| name: iOS Validate | |
| runs-on: macos-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Validate required Swift and ObjC files exist | |
| run: | | |
| required=( | |
| "ios/RNBackgroundTimer.swift" | |
| "ios/RNBackgroundTimer.m" | |
| "ios/RNBackgroundTimer-Bridging-Header.h" | |
| "ios/BGTaskManager.swift" | |
| "ios/TimerData.swift" | |
| "ios/TimerStore.swift" | |
| "ios/background-timer.podspec" | |
| ) | |
| failed=0 | |
| for f in "${required[@]}"; do | |
| if [ -f "$f" ]; then | |
| echo " ✅ $f" | |
| else | |
| echo " ❌ MISSING: $f" | |
| failed=1 | |
| fi | |
| done | |
| exit $failed | |
| - name: Validate podspec required fields | |
| run: | | |
| podspec="ios/background-timer.podspec" | |
| check_field() { | |
| local label="$1"; local pattern="$2" | |
| if grep -q "$pattern" "$podspec"; then | |
| echo "✅ $label" | |
| else | |
| echo "❌ MISSING: $label" | |
| exit 1 | |
| fi | |
| } | |
| check_field "name" "s.name" | |
| check_field "version" "s.version" | |
| check_field "iOS 13 min" "ios.*13" | |
| check_field "Swift version" "SWIFT_VERSION" | |
| check_field "React-Core dep" "React-Core" | |
| - name: Validate BGTaskScheduler is used | |
| run: | | |
| if grep -q "BGTaskScheduler" ios/BGTaskManager.swift; then | |
| echo "✅ BGTaskScheduler used in BGTaskManager.swift" | |
| else | |
| echo "❌ BGTaskScheduler not found in BGTaskManager.swift" | |
| exit 1 | |
| fi | |
| - name: Validate UIBackgroundTask is used | |
| run: | | |
| # beginBackgroundTask is called inside BGTaskManager (the dedicated task manager), | |
| # not in RNBackgroundTimer directly which delegates to BGTaskManager. | |
| if grep -q "beginBackgroundTask" ios/BGTaskManager.swift; then | |
| echo "✅ UIBackgroundTask (beginBackgroundTask) used in BGTaskManager.swift" | |
| else | |
| echo "❌ beginBackgroundTask not found in BGTaskManager.swift" | |
| exit 1 | |
| fi | |
| - name: Validate Turbo Module ObjC bridge declarations | |
| run: | | |
| bridge="ios/RNBackgroundTimer.m" | |
| if grep -q "RCT_EXTERN_MODULE" "$bridge"; then | |
| echo "✅ RCT_EXTERN_MODULE declared" | |
| else | |
| echo "❌ RCT_EXTERN_MODULE not found in $bridge" | |
| exit 1 | |
| fi |