From d2258383d6c5c9a70fdf24ad3388420e40a78832 Mon Sep 17 00:00:00 2001 From: Emil Rossing Date: Mon, 24 Aug 2026 17:40:10 +0200 Subject: [PATCH] fix(formulus): hoist buffer for release Metro and speed up Android CI Add buffer as a direct dependency so createBundleReleaseJsAndAssets can resolve it under pnpm. For CI: one Gradle invocation for APK+AAB, cache vendored Notifee, and keep full ABIs for GitHub Releases only (arm64 smoke on PR/push). Co-authored-by: Cursor --- .github/CICD.md | 10 ++++--- .github/workflows/formulus-android.yml | 41 +++++++++++++++++++------- formulus/AGENTS.md | 1 + formulus/android/gradle.properties | 3 +- formulus/package.json | 1 + formulus/pnpm-lock.yaml | 11 +++++++ 6 files changed, 51 insertions(+), 16 deletions(-) diff --git a/.github/CICD.md b/.github/CICD.md index 3c01a6a20..b3704e2ab 100644 --- a/.github/CICD.md +++ b/.github/CICD.md @@ -149,11 +149,13 @@ Formplayer assets are **not committed to git** and are ignored via `.gitignore`. #### Build Types -- **Pull Requests**: Debug APK (unsigned), **arm64-v8a only** (`-PreactNativeArchitectures=arm64-v8a`) to keep PR CI fast -- **Push to main/dev**: Release APK + AAB (signed), **all four ABIs** from `formulus/android/gradle.properties` -- **Release**: Same as main/dev; APK/AAB published to the GitHub Release +- **Pull Requests**: Debug APK (unsigned), **arm64-v8a only** (smoke) +- **Push to main/dev**: Release APK + AAB (signed), **arm64-v8a only** — CI artifacts, not F-Droid shippable +- **GitHub Release**: Release APK + AAB (signed), **all four ABIs** from `formulus/android/gradle.properties` (F-Droid / Play); assets attached to the release -Gradle uses `gradle/actions/setup-gradle` for dependency/build-cache restore. CI also enables parallel workers (local `gradle.properties` keeps them low for laptops). +APK and AAB are built in **one** Gradle invocation (`assembleRelease bundleRelease`) so Metro/native work is shared. Gradle uses `gradle/actions/setup-gradle` (daemon left on). Vendored Notifee (`formulus/third_party/notifee`) is cached across runs (key = hash of `vendor-notifee-core.mjs`). CI enables parallel workers (local `gradle.properties` keeps them low for laptops). + +NDK `ccache` is **not** wired yet: it needs CI-only CMake launcher hooks into React Native’s native build and can flake; revisit if release builds are still too slow after the above. #### Secrets Required diff --git a/.github/workflows/formulus-android.yml b/.github/workflows/formulus-android.yml index 73623f52c..3f204099f 100644 --- a/.github/workflows/formulus-android.yml +++ b/.github/workflows/formulus-android.yml @@ -29,6 +29,9 @@ concurrency: env: NODE_VERSION: '24' + # Full ABI set matches formulus/android/gradle.properties (F-Droid / Play shippable). + FORMULUS_ABIS_FULL: armeabi-v7a,arm64-v8a,x86,x86_64 + FORMULUS_ABIS_SMOKE: arm64-v8a jobs: build-formplayer-assets: @@ -117,6 +120,13 @@ jobs: working-directory: formulus run: pnpm install --frozen-lockfile + # vendor-notifee-core.mjs is a no-op when third_party/notifee is already at the pinned commit. + - name: Cache vendored Notifee + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: formulus/third_party/notifee + key: notifee-${{ hashFiles('formulus/scripts/vendor-notifee-core.mjs') }} + - name: Vendor Notifee Android core (source build; dir is gitignored) working-directory: formulus run: pnpm run vendor:notifee @@ -142,6 +152,7 @@ jobs: uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 with: # Persist the Gradle build cache across CI runs (wrapper + deps + task outputs). + # Leave the daemon on so assembleRelease + bundleRelease share one JVM. cache-read-only: false - name: Make Gradle wrapper executable @@ -172,35 +183,43 @@ jobs: echo "FORMULUS_RELEASE_KEY_ALIAS=${FORMULUS_RELEASE_KEY_ALIAS}" >> formulus/android/local.properties echo "FORMULUS_RELEASE_KEY_PASSWORD=${FORMULUS_RELEASE_KEY_PASSWORD}" >> formulus/android/local.properties - # PRs: compile arm64-v8a only (physical devices + most CI validation). - # Push/release: all four ABIs from gradle.properties (shippable APK/AAB). + # ABI policy: + # - PR + push to main/dev: arm64-v8a only (smoke / CI artifacts — not F-Droid shippable) + # - release: all four ABIs (F-Droid / Play) # Local gradle.properties keeps parallel/workers low for laptops; CI overrides those. + # setup-gradle prefers leaving the daemon on (no --no-daemon). - name: Build debug APK (PR, arm64-v8a only) if: github.event_name == 'pull_request' working-directory: formulus/android env: - ORG_GRADLE_PROJECT_reactNativeArchitectures: arm64-v8a + ORG_GRADLE_PROJECT_reactNativeArchitectures: ${{ env.FORMULUS_ABIS_SMOKE }} run: > - ./gradlew assembleDebug --no-daemon --stacktrace + ./gradlew assembleDebug --stacktrace -Dorg.gradle.parallel=true -Dorg.gradle.workers.max=4 - -PreactNativeArchitectures=arm64-v8a + -PreactNativeArchitectures=${{ env.FORMULUS_ABIS_SMOKE }} - - name: Build release APK (main/dev/release, all ABIs) - if: github.event_name != 'pull_request' + - name: Build release APK + AAB (push main/dev, arm64-v8a only) + if: github.event_name == 'push' working-directory: formulus/android + env: + ORG_GRADLE_PROJECT_reactNativeArchitectures: ${{ env.FORMULUS_ABIS_SMOKE }} run: > - ./gradlew assembleRelease --no-daemon --stacktrace + ./gradlew assembleRelease bundleRelease --stacktrace -Dorg.gradle.parallel=true -Dorg.gradle.workers.max=4 + -PreactNativeArchitectures=${{ env.FORMULUS_ABIS_SMOKE }} - - name: Build release AAB for Play Store (main/dev/release, all ABIs) - if: github.event_name != 'pull_request' + - name: Build release APK + AAB (GitHub Release, all ABIs) + if: github.event_name == 'release' working-directory: formulus/android + env: + ORG_GRADLE_PROJECT_reactNativeArchitectures: ${{ env.FORMULUS_ABIS_FULL }} run: > - ./gradlew bundleRelease --no-daemon --stacktrace + ./gradlew assembleRelease bundleRelease --stacktrace -Dorg.gradle.parallel=true -Dorg.gradle.workers.max=4 + -PreactNativeArchitectures=${{ env.FORMULUS_ABIS_FULL }} - name: Upload APK artifact uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 diff --git a/formulus/AGENTS.md b/formulus/AGENTS.md index 8fab4892d..ab76a0397 100644 --- a/formulus/AGENTS.md +++ b/formulus/AGENTS.md @@ -65,6 +65,7 @@ pnpm does not hoist transitive packages to the package root. Anything **imported | Package | Pinned to | Why | When to relax | | ------- | --------- | --- | ------------- | | `axios` | `^1.16.1` (direct dep) | OpenAPI-generated Synkronus client imports it; under pnpm it was only transitive via `@openapitools/openapi-generator-cli`, so release Metro bundling (`createBundleReleaseJsAndAssets`) failed while PR `assembleDebug` could pass. | Keep as direct dep while using the `typescript-axios` generator. | +| `buffer` | `^6.0.3` (direct dep) | `FRMLSHelpers.ts` imports `Buffer` from `buffer`; under pnpm it was not hoisted, so release Metro bundling failed the same way as `axios`. | Keep while app code imports the polyfill. | | `react-native-screens` | `4.25.2` (no `^`) | `4.26+` needs RN **0.84+** and uses `React.ComponentRef` in Fabric commands; codegen **0.83** only accepts `React.ElementRef`, so Android fails at `:react-native-screens:generateCodegenSchemaFromJavaScript`. | After upgrading RN to **≥ 0.84** (ideally **0.87**): restore a caret range (e.g. `^4.27.0`) and confirm Android codegen + screens still build. | | `@nozbe/sqlite` / `@nozbe/simdjson` | `3.46.0` / `3.9.4` (direct deps) | WatermelonDB JSI `CMakeLists.txt` resolves `node_modules/@nozbe/{sqlite,simdjson}` from a relative path; pnpm does not hoist those transitive packages there, so CMake gets `No SOURCES given to target: watermelondb-jsi`. | Keep as direct deps aligned with `@nozbe/watermelondb`'s versions. | | `@nozbe/watermelondb` | patched (`patches/@nozbe__watermelondb@0.28.0.patch`) | Same CMake file uses `../../../../../../../react-native`. Under pnpm the package is symlinked into `.pnpm/…`; on Linux `..` follows the real path into the package store (sqlite/simdjson present, **react-native not**), so `#include ` fails. Patch walks up until `jsi.h` is found. | Drop the patch when upstream CMake is pnpm-safe, or after switching away from WatermelonDB JSI. | diff --git a/formulus/android/gradle.properties b/formulus/android/gradle.properties index 914ab8030..c101597d1 100644 --- a/formulus/android/gradle.properties +++ b/formulus/android/gradle.properties @@ -25,7 +25,8 @@ android.useAndroidX=true # You can also override it from the CLI using # ./gradlew -PreactNativeArchitectures=x86_64 # Include armeabi-v7a so the APK runs on both 32-bit and 64-bit ARM devices. -# CI PRs override this to arm64-v8a only (see .github/workflows/formulus-android.yml). +# CI: PRs and push to main/dev override to arm64-v8a only; GitHub Release builds use all four +# (F-Droid / Play). See .github/workflows/formulus-android.yml. reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 # Use this property to enable support to the new architecture. diff --git a/formulus/package.json b/formulus/package.json index 3582b1a60..2a26622eb 100644 --- a/formulus/package.json +++ b/formulus/package.json @@ -43,6 +43,7 @@ "@react-navigation/native": "^7.3.17", "@react-navigation/stack": "^7.10.23", "axios": "^1.16.1", + "buffer": "^6.0.3", "i18next": "^26.4.0", "lucide-react-native": "^0.577.0", "react": "19.2.4", diff --git a/formulus/pnpm-lock.yaml b/formulus/pnpm-lock.yaml index 25874890a..fd781a4d6 100644 --- a/formulus/pnpm-lock.yaml +++ b/formulus/pnpm-lock.yaml @@ -82,6 +82,9 @@ importers: axios: specifier: ^1.16.1 version: 1.19.0(debug@4.4.3(supports-color@10.2.2))(supports-color@10.2.2) + buffer: + specifier: ^6.0.3 + version: 6.0.3 i18next: specifier: ^26.4.0 version: 26.4.0(typescript@5.9.3) @@ -2350,6 +2353,9 @@ packages: buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -7849,6 +7855,11 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + bytes@3.1.2: {} call-bind-apply-helpers@1.0.2: