-
Notifications
You must be signed in to change notification settings - Fork 2
[reference][native WIP] ci(native): macOS native build smoke lane (ERY-99) #598
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| name: Native Build Smoke | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| pull_request: | ||
| paths: | ||
| - .github/workflows/native-build-smoke.yml | ||
| - android/** | ||
| - capacitor.config.ts | ||
| - package.json | ||
| - package-lock.json | ||
| - public/** | ||
| - scripts/ios-init.sh | ||
| - src/native/** | ||
| - src/pages/mobile/** | ||
| - src/styles/mobile.css | ||
| - src/styles/mobile-ios.css | ||
|
|
||
| jobs: | ||
| native-build-smoke: | ||
| name: iOS bootstrap + Android smoke | ||
| runs-on: macos-15 | ||
| timeout-minutes: 60 | ||
| permissions: | ||
| contents: read | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v6 | ||
|
|
||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v6 | ||
| with: | ||
| node-version: "20" | ||
| cache: npm | ||
|
|
||
| - name: Setup Java 17 | ||
| uses: actions/setup-java@v5 | ||
| with: | ||
| distribution: temurin | ||
| java-version: "17" | ||
|
|
||
| - name: Capture native toolchain versions | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| mkdir -p artifacts | ||
| { | ||
| echo "Node $(node -v)" | ||
| echo "npm $(npm -v)" | ||
| xcodebuild -version | ||
| echo "CocoaPods $(pod --version)" | ||
| java -version | ||
| echo "ANDROID_HOME=${ANDROID_HOME:-unset}" | ||
| ls "$ANDROID_HOME/platforms" | grep "android-35" | ||
| ls "$ANDROID_HOME/build-tools" | grep "35.0" | ||
| } 2>&1 | tee artifacts/toolchain.log | ||
|
|
||
| - name: Bootstrap iOS workspace | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| mkdir -p artifacts | ||
| npm run ios:init 2>&1 | tee artifacts/ios-init.log | ||
|
|
||
| - name: Build iOS simulator target | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| mkdir -p artifacts | ||
| xcodebuild \ | ||
| -workspace ios/App/App.xcworkspace \ | ||
| -scheme App \ | ||
| -configuration Debug \ | ||
| -sdk iphonesimulator \ | ||
| -destination "generic/platform=iOS Simulator" \ | ||
| -derivedDataPath ios/App/build \ | ||
| CODE_SIGNING_ALLOWED=NO \ | ||
| build 2>&1 | tee artifacts/ios-build.log | xcbeautify | ||
|
|
||
| - name: Assemble Android debug APK | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| mkdir -p artifacts | ||
| npm run android:assemble:debug 2>&1 | tee artifacts/android-debug.log | ||
|
|
||
| - name: Assemble Android release APK | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| mkdir -p artifacts | ||
| npm run android:assemble:release 2>&1 | tee artifacts/android-release.log | ||
|
|
||
| - name: Upload native smoke artifacts | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: native-build-smoke-${{ github.run_id }} | ||
| if-no-files-found: warn | ||
| path: | | ||
| artifacts/*.log | ||
| android/app/build/outputs/** | ||
| ios/App/build/** | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,81 +1,48 @@ | ||
| # ERY-71 — Native Packaging & Self-Host Distribution Validation Note | ||
| # ERY-71 Native Packaging Validation | ||
|
|
||
| Date: 2026-05-24 | ||
| Owner: Engineer | ||
| Issue: [ERY-71](/ERY/issues/ERY-71) | ||
| Parent: [ERY-55](/ERY/issues/ERY-55) | ||
| Branch: `engineer/ery-71-native-packaging` (worktree off `17575bb`) | ||
| ## Lane decision | ||
|
|
||
| This note replaces reliance on the old umbrella PR description as the validation | ||
| record for the native branch. It lists exactly what changed, what was verified | ||
| here, and what is explicitly blocked on build tooling. | ||
| - Selected validation lane: GitHub Actions macOS 15 (`.github/workflows/native-build-smoke.yml`) | ||
| - Why: the current validation host only has Command Line Tools; it does not have `Xcode.app`, CocoaPods, Java, `sdkmanager`, or `adb`, so it cannot satisfy the iOS/Android acceptance checks locally. | ||
| - Scope of the lane: pin Node 20 + Java 17 on GitHub's macOS 15 runner, run `npm run ios:init`, build the generated iOS workspace for the simulator, then run `npm run android:assemble:debug` and `npm run android:assemble:release`, and upload logs/artifacts for review. | ||
|
|
||
| ## Changes in this branch | ||
| ## Local host evidence captured on 2026-05-24 | ||
|
|
||
| | Deliverable | Change | File(s) | | ||
| |---|---|---| | ||
| | ML Kit offline barcode | Wired the previously-dead `mlkitBarcodeDependencies` placeholder into a real `com.google.mlkit.vision.DEPENDENCIES` meta-data so Google Play fetches the model at install time, not first scan. Documented the GMS caveat + bundled-model path for air-gapped fleets (claim narrowed honestly). | `android/app/src/main/AndroidManifest.xml`, `android/app/build.gradle`, `docs/ANDROID.md` | | ||
| | LAN self-host distribution | Removed the fabricated sample-IP RFC1918 enumeration (false coverage, no CIDR match). Release builds are HTTPS-only; dev/live-reload cleartext is confined to `debug-overrides`; plain-HTTP LAN hosts are supported per-host via a documented custom-build template or TLS fronting (least privilege). | `android/app/src/main/res/xml/network_security_config.xml`, `docs/ANDROID.md`, `docs/IOS.md` | | ||
| | Version alignment | `android/app/build.gradle` versionName `0.5.1 → 0.5.2`, README badge + status line `0.5.1 → 0.5.2`. Now consistent with `package.json` (0.5.2) and `CHANGELOG` (0.5.2). | `android/app/build.gradle`, `README.md` | | ||
| | Check | Result | Evidence | | ||
| | --- | --- | --- | | ||
| | `xcodebuild -version` | FAIL | active developer dir is `/Library/Developer/CommandLineTools`; `Xcode.app` is not installed | | ||
| | `pod --version` | FAIL | `pod: command not found` | | ||
| | `java -version` | FAIL | no Java runtime present | | ||
| | `sdkmanager --version` | FAIL | `sdkmanager: command not found` | | ||
| | `adb version` | FAIL | `adb: command not found` | | ||
| | `npm run build` | PASS | build succeeds after explicitly restoring the missing darwin-arm64 Rollup + SWC native bindings that `npm ci` skipped on this Apple Silicon host | | ||
| | `npm run ios:init` on this host | FAIL | after the Rollup/SWC repair, the script reaches `npx cap add ios` and then stops at the real blocker: `CocoaPods is not installed` | | ||
| | `ios/` workspace produced locally | FAIL | `npx cap add ios` aborted before creating `ios/` because CocoaPods is absent on this host | | ||
|
|
||
| Note on target version: surfaces are aligned to the current canonical `0.5.2`. | ||
| The coordinated bump to `0.6.0` (package.json + gradle versionName + versionCode | ||
| increment + README + a new CHANGELOG section) is a release-tagging step under | ||
| [ERY-55](/ERY/issues/ERY-55) and should land atomically at the release cut, not | ||
| piecemeal here. Flagged for CTO decision. | ||
| ## Native validation status | ||
|
|
||
| ## What was verified here (pass) | ||
| First macOS lane run: GitHub Actions run [`26370608416`](https://github.com/SheetMetalConnect/eryxon-flow/actions/runs/26370608416) on `macos-15` (PR [#598](https://github.com/SheetMetalConnect/eryxon-flow/pull/598), `pull_request` trigger), 2026-05-24. Conclusion: **failure** at iOS bootstrap; downstream steps skipped. Logs/artifacts: `native-build-smoke-26370608416`. | ||
|
|
||
| - **XML well-formedness** — `network_security_config.xml` and | ||
| `AndroidManifest.xml` parse cleanly (`python3 xml.dom.minidom`). PASS. | ||
| - **Placeholder wiring** — `mlkitBarcodeDependencies` is now both defined | ||
| (build.gradle) and consumed (`${mlkitBarcodeDependencies}` in the manifest | ||
| meta-data). Confirmed by grep. PASS. | ||
| - **Version consistency** — package.json / build.gradle / README / CHANGELOG all | ||
| report `0.5.2`. PASS. | ||
| - **Least-privilege review** — release artifacts now have zero blanket cleartext | ||
| exception; cleartext is debug-only or one explicit operator-chosen host. PASS. | ||
| | Check | Status | Evidence | | ||
| | --- | --- | --- | | ||
| | macOS toolchain present (Xcode, CocoaPods, Java 17, Android SDK API 35) | PASS | "Capture native toolchain versions" step succeeded — confirms the lane is correctly provisioned | | ||
| | `npm run ios:init` (web build + `npx cap add ios`) | PARTIAL | web `vite build` PASS, `npx cap add ios` PASS (Xcode project + assets generated), then `pod install` FAILED | | ||
| | iOS `pod install` (CocoaPods dependency resolution) | FAIL | `GoogleMLKit/BarcodeScanning (= 7.0.0)` — pulled transitively by `@capacitor-mlkit/barcode-scanning` 7.5.0 — "required a higher minimum deployment target" than the Capacitor-generated Podfile's iOS target. Root cause below. | | ||
| | iOS simulator build of `ios/App/App.xcworkspace` | SKIPPED | iOS step failed before a workspace existed | | ||
| | `npm run android:assemble:debug` | SKIPPED | job halts on first failed step; Android never ran this run | | ||
| | `npm run android:assemble:release` | SKIPPED | job halts on first failed step; Android never ran this run | | ||
|
|
||
| ## What is BLOCKED on build tooling (fail / not-run) | ||
| ## Root cause + proposed fix (iOS) | ||
|
|
||
| This host has **Command Line Tools only (no Xcode.app), no CocoaPods, no JDK, no | ||
| Android SDK**. Probe output: | ||
| - `@capacitor-mlkit/barcode-scanning@7.5.0` depends on `GoogleMLKit/BarcodeScanning = 7.0.0`, which requires a higher minimum iOS deployment target than the default Capacitor Podfile emits. | ||
| - Fix: pin the generated iOS deployment target high enough for GoogleMLKit 7.0.0 (iOS 15.5+). Because `ios/` is not committed and `npx cap add ios` runs `pod install` during `add`, the target must be injected before pod resolution — e.g. set a Capacitor iOS `platform`/deployment-target config or generate the Podfile with `platform :ios, '15.5'` (+ a `post_install` target override) prior to `cap add ios`. This is a native-packaging change owned by ERY-71 follow-up, not the smoke-lane itself. | ||
|
|
||
| ``` | ||
| $ xcode-select -p -> /Library/Developer/CommandLineTools | ||
| $ xcodebuild -version -> error: requires Xcode (only CLT present) | ||
| $ pod --version -> pod: command not found | ||
| $ java -version -> Unable to locate a Java Runtime | ||
| $ echo $ANDROID_HOME -> (empty) | ||
| ``` | ||
| ## Workflow follow-up | ||
|
|
||
| Consequently the following could not be executed and remain unproven: | ||
| - The iOS failure masked Android validation (steps skipped). Split iOS and Android into independent jobs (or `if: always()` gating) so a failure in one still produces evidence for the other on the same run. | ||
|
|
||
| 1. **iOS workspace bootstrap** — `npm run ios:init` (`npx cap add ios` + `pod | ||
| install`) needs Xcode 15+ and CocoaPods. The `ios/` workspace therefore still | ||
| does not exist as a checked-in/validated artifact. NOT RUN — blocked on | ||
| toolchain. | ||
| 2. **Android build smoke** — `npm run android:assemble:debug` / `:release` | ||
| (gradle) needs JDK 17 + Android SDK (API 35). The ML Kit meta-data and the new | ||
| network-security config are correct by inspection and parse cleanly, but have | ||
| not been proven to compile/package/merge in a real build. NOT RUN — blocked on | ||
| toolchain. | ||
| ## Remaining Apple-specific gaps | ||
|
|
||
| ## Remaining Apple-specific blockers for TestFlight/App Store | ||
| ## Remaining Apple-specific gaps | ||
|
|
||
| Already enumerated in `docs/IOS.md` ("Remaining iOS-only gaps") and unchanged by | ||
| this branch — they require a Mac with Xcode + an Apple Developer account: | ||
|
|
||
| 1. APNs auth key + `PushNotifications.register()` wiring. | ||
| 2. Universal Links / Associated Domains (`applinks:app.eryxon.eu` entitlement + | ||
| `/.well-known/apple-app-site-association`). | ||
| 3. Splash screen assets + 1024×1024 app icon set. | ||
| 4. `Info.plist` localizations (`CFBundleLocalizations = [en, nl, de]`). | ||
|
|
||
| ## Recommended next steps | ||
|
|
||
| - CTO: approve commit+push of `engineer/ery-71-native-packaging`. | ||
| - Provision a native-build lane (local Mac with Xcode 15+/CocoaPods and JDK 17 + | ||
| Android SDK, or a CI macOS runner) so iOS bootstrap and the Android build smoke | ||
| can produce pass/fail evidence. Tracked as the ERY-71 build-validation follow-up. | ||
| - At the v0.6 release cut, perform the coordinated `0.6.0` version bump atomically. | ||
| - The pre-TestFlight items remain explicitly tracked in [docs/IOS.md](/Users/vanenkhuizen/Documents/GitHub/products/eryxon-flow/docs/IOS.md): APNs wiring, Associated Domains / Universal Links, splash/icon assets, and App Store metadata polish. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Replace this absolute macOS filesystem path with a repo-relative link (for example Useful? React with 👍 / 👎. |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep Android validation independent from the iOS bootstrap in this workflow: as written, a non-zero exit from
npm run ios:initstops the entirenative-build-smokejob before either Android assemble step runs, so Android regressions are never exercised whenever iOS is broken. In practice this defeats the lane’s stated goal of collecting smoke evidence for both platforms in a single run.Useful? React with 👍 / 👎.