Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions .github/CICD.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
41 changes: 30 additions & 11 deletions .github/workflows/formulus-android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions formulus/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <jsi/jsi.h>` 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. |
Expand Down
3 changes: 2 additions & 1 deletion formulus/android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ android.useAndroidX=true
# You can also override it from the CLI using
# ./gradlew <task> -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.
Expand Down
1 change: 1 addition & 0 deletions formulus/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
11 changes: 11 additions & 0 deletions formulus/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading