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
33 changes: 14 additions & 19 deletions .claude/skills/build-compilation-dependencies/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ react-native-audio-api/
│ │ └── include_ffmpeg/ # Headers for FFmpeg
│ ├── common/cpp/test/
│ │ ├── CMakeLists.txt # Standalone test build (no Android/iOS)
│ │ ├── RunTests.sh # Test runner script
│ │ ├── run-tests.sh / filters.sh # smoke|extended|full (+ categories, CI path filters)
│ │ └── src/ # Google Test files
│ ├── RNAudioAPI.podspec # CocoaPods spec for iOS
│ └── scripts/
Expand Down Expand Up @@ -233,10 +233,11 @@ CI intentionally skips native Android/iOS builds (expensive). Use the tiered loc

```bash
yarn validate:fast # CI parity (format, lint, typecheck, enum sync, build, C++ + JS tests)
yarn validate:graph # graph tests + ASan (optional; graph path changes)
yarn validate:cpp # C++ smoke
yarn validate:cpp-extended # C++ extended (all categories)
yarn validate:android # yarn workspace … build:android
yarn validate:ios # yarn workspace … build:ios (macOS only)
yarn validate:full # --fast + --android + --ios
yarn validate:full # --fast + C++ extended + --android + --ios
```

Script: [`scripts/validate.sh`](../../../scripts/validate.sh) at monorepo root.
Expand All @@ -246,10 +247,10 @@ Script: [`scripts/validate.sh`](../../../scripts/validate.sh) at monorepo root.
| Layer | CI (`ci.yml` + `tests.yml`) | Local tiers |
|---|---|---|
| TS build (`bob build`) | Yes | `--fast` |
| C++ test subset (`RunTests.sh`) | Yes | `--fast` |
| C++ coverage (`RunCoverage.sh`, Clang) | Yes (`cpp-coverage` artifact) | `yarn test:cpp:coverage` |
| C++ smoke (`run-tests.sh`) | Yes | `--fast` |
| C++ coverage (`run-coverage.sh`, smoke, Clang) | Yes (`cpp-coverage` artifact) | `yarn test:cpp:coverage` |
| Jest | Yes | `--fast` |
| Graph tests | No, path-filtered in `graph-tests.yml` | `--graph` |
| Extended C++ by category (e.g. graph) | Path change or manual dispatch in `tests.yml` | `--cpp-extended` |
| HostObjects (26 JSI `.cpp` files) | **No** | `--android` + `--ios` |
| Android JNI C++ + Kotlin | **No** | `--android` |
| iOS ObjC++ | **No** | `--ios` |
Expand All @@ -272,7 +273,7 @@ Android (NDK) and iOS (Clang) cannot share object files — reuse is at the preb

- `--ios` on Linux → skip with message (exit 0)
- `--android` without `ANDROID_HOME` → fail on explicit `--android`; skip with warning inside `--full`
- Graph tests are separate from `--full` (slow; CI path-filters them)
- `--full` includes C++ extended (all categories) after `--fast`’s smoke, so local full covers C++ full + native builds

### Which tier to run

Expand All @@ -287,18 +288,12 @@ See the decision table in [post-work-checks](../post-work-checks/SKILL.md).

### How to run
```bash
yarn test # from monorepo root — runs RunTests.sh
yarn test # Jest + C++ smoke
yarn workspace react-native-audio-api test:cpp:smoke|extended|full
yarn workspace react-native-audio-api test:cpp:extended -- graph
```

`RunTests.sh` does:
```bash
cd packages/react-native-audio-api/common/cpp/test
cmake -S . -B build -Wno-dev
cd build && make -j10
./tests --gtest_print_time=1
```

The `build/` directory is deleted after each run.
`run-tests.sh [smoke|extended|full] [category…] [--ubasan|--tsan|--no-ubasan]` uses filters from `filters.sh`. Docs: `common/cpp/test/TESTING.md`. Shell scripts in this repo use kebab-case plus `.sh` (`run-tests.sh`, not `RunTests.sh`).

### Coverage (Clang / llvm-cov)

Expand All @@ -307,9 +302,9 @@ yarn workspace react-native-audio-api test:cpp:coverage
# open packages/react-native-audio-api/common/cpp/test/coverage-html/index.html
```

`RunCoverage.sh` configures a separate `build-coverage/` tree with `-DENABLE_COVERAGE=ON` (Clang-only LLVM source-based coverage: `-fprofile-instr-generate -fcoverage-mapping`), defaults `CC`/`CXX` to `clang`/`clang++` when unset, runs the same gtest filter as `RunTests.sh`, then prints `llvm-cov report` and writes HTML via `llvm-cov show -format=html`. When `GITHUB_STEP_SUMMARY` is set, the report is also appended there. Sanitizer targets are skipped when coverage is enabled. Requires Apple Clang / `xcrun llvm-profdata` and `xcrun llvm-cov` on macOS (or the same tools on PATH for Linux).
`run-coverage.sh` configures a separate `build-coverage/` tree with `-DENABLE_COVERAGE=ON` (Clang-only LLVM source-based coverage: `-fprofile-instr-generate -fcoverage-mapping`), defaults `CC`/`CXX` to `clang`/`clang++` when unset, runs the **smoke** filter from `filters.sh`, then prints `llvm-cov report` and writes HTML via `llvm-cov show -format=html`. When `GITHUB_STEP_SUMMARY` is set, the report is also appended there. Sanitizer targets are skipped when coverage is enabled. Requires Apple Clang / `xcrun llvm-profdata` and `xcrun llvm-cov` on macOS (or the same tools on PATH for Linux).

CI runs a parallel `cpp-coverage` job via `.github/workflows/cpp-coverage-job.yml` (called from `tests.yml` on pull requests; Clang + LLVM apt packages, separate from the GCC `cpp-tests` job). It uploads the HTML tree as the `cpp-coverage-html` artifact (14-day retention); download the zip from the Actions run and open `index.html`. Manual `workflow_dispatch` on `tests.yml` accepts booleans `run_cpp_tests` / `run_cpp_coverage` / `run_js_tests` (default true); PRs always run all three.
CI runs a parallel `cpp-coverage` job via `.github/workflows/cpp-coverage-job.yml` (called from `tests.yml` on pull requests; Clang + LLVM apt packages, separate from the GCC `cpp-smoke-tests` job). It uploads the HTML tree as the `cpp-coverage-html` artifact (14-day retention); download the zip from the Actions run and open `index.html`. Manual `workflow_dispatch` on `tests.yml` accepts booleans `run_cpp_smoke_tests` / `run_cpp_coverage` / `run_js_tests` (default true); non-draft PRs always run all three, including when a draft is marked ready for review (`ready_for_review` is listed explicitly because it is not a default `pull_request` type). Extended categories share `cpp-job.yml` and pass `categories`; path-filter YAML is generated by `filters.sh path-filters`.

> **Generated build trees must be named `build*`.** The C++ linters walk the filesystem with `find` and never consult git, so a `.gitignore` entry does not keep generated sources out of them. Exclusion happens by directory name in two places that must stay in sync: `**/build*/**` in `.clang-format-ignore` (used by `format:check:common`) and `-type d -name 'build*' -prune` in `scripts/cpplint.sh`. A CMake binary directory outside that prefix makes the pre-commit hook fail on generated files such as `CMakeFiles/*/CompilerIdCXX/CMakeCXXCompilerId.cpp`. CI never hits this because it checks out a clean tree.

Expand Down
6 changes: 4 additions & 2 deletions .claude/skills/build-compilation-dependencies/maintenance.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ Review this skill when `pre-push-update` reports changes in:
| `RNAudioAPI.podspec` | Subspecs table, `miniaudio_impl` workaround, `-force_load` list, xcframeworks list, `rnaa_utils.rb` dynamic paths |
| `apps/fabric-example/ios/Podfile` | New Architecture enablement, minimum iOS version helper |
| `common/cpp/test/CMakeLists.txt` | Excluded sources list, compile definitions, GoogleTest fetch URL, include paths, `ENABLE_COVERAGE` |
| `common/cpp/test/RunCoverage.sh` | Coverage build dir, Clang CC/CXX defaults, llvm-profdata/llvm-cov report+HTML, `GITHUB_STEP_SUMMARY`, ignore regexes |
| `common/cpp/test/run-coverage.sh` | Coverage build dir, Clang CC/CXX defaults, llvm-profdata/llvm-cov report+HTML, `GITHUB_STEP_SUMMARY`, ignore regexes, smoke filter via `filters.sh` |
| `common/cpp/test/filters.sh` / `run-tests.sh` | Mode/category gtest filters (smoke/extended/full), sanitizer flags, CI path-filter YAML (`path-filters`) |
| `.github/workflows/cpp-coverage-job.yml` | Reusable coverage job (Clang/LLVM install, artifact `cpp-coverage-html`) |
| `.github/workflows/js-job.yml` | Reusable JS integration tests job (draft-PR skip) |
| `.github/workflows/tests.yml` | Calls cpp/js/coverage jobs; `workflow_dispatch` booleans select jobs |
| `.github/workflows/ci.yml`, `tests.yml`, `wpt-tests.yml` | PR entry workflows that skip drafts; `ready_for_review` is listed (not a default type). Reusable jobs inherit it. |
| `.github/workflows/cpp-job.yml` | Shared C++ smoke + extended runner; path filters come from `filters.sh path-filters` |
| `.clang-format-ignore` / `scripts/cpplint.sh` | Autogenerated files exclusions |
| `common/cpp/test/src/MockAudioEventHandlerRegistry.h` | Mock interface — update fixture boilerplate in `build-details.md` if signature changes |
| `scripts/download-prebuilt-binaries.sh` | New download artifacts, new TAG version |
32 changes: 18 additions & 14 deletions .claude/skills/post-work-checks/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ Run these checks after any code change and before opening a PR.

## Quick Reference — Local Validation Tiers

CI always runs the **fast** tier (format, lint, typecheck, enum sync, TS build, C++ + JS tests). Graph tests run in a separate path-filtered workflow (`graph-tests.yml`). CI does **not** build Android Gradle, iOS pods, or example apps. Use `validate.sh` locally to close that gap:
CI always runs the **fast** tier (format, lint, typecheck, enum sync, TS build, C++ smoke + JS tests). Extended C++ categories (e.g. graph) run from `tests.yml` when matching paths change, or via `workflow_dispatch` booleans. CI does **not** build Android Gradle, iOS pods, or example apps. Use `validate.sh` locally to close that gap:

```bash
yarn validate:fast # CI parity — always run before opening a PR
yarn validate:graph # graph tests (when graph/audio-thread code changes)
yarn validate:android # Android native build (requires ANDROID_HOME)
yarn validate:ios # iOS native build (macOS only)
yarn validate:full # --fast + --android + --ios (skips unavailable platforms)
yarn validate:fast # CI parity — always run before opening a PR
yarn validate:cpp # C++ smoke
yarn validate:cpp-extended # C++ extended (all categories)
yarn validate:android # Android native build (requires ANDROID_HOME)
yarn validate:ios # iOS native build (macOS only)
yarn validate:full # --fast + C++ extended + --android + --ios
```

Equivalent: `./scripts/validate.sh --fast` (etc.)
Expand All @@ -42,7 +43,7 @@ Equivalent: `./scripts/validate.sh --fast` (etc.)
| `ios/audioapi/` | `--fast` + `--ios` |
| `CMakeLists.txt`, `build.gradle`, `podspec` | `--full` |

Graph changes under `common/cpp/audioapi/core/utils/graph/` → also run `yarn validate:graph`.
Graph changes under `common/cpp/audioapi/core/utils/graph/` → also run `yarn validate:cpp-extended` or `yarn workspace react-native-audio-api test:cpp:extended -- graph`.

---

Expand Down Expand Up @@ -73,7 +74,7 @@ Hooks run when lefthook is installed (`lefthook install`).

**If a hook fails, the commit is aborted.** Fix the issue and re-commit — do NOT use `--no-verify`.

There is no pre-push hook — `yarn validate:fast` (and native/graph tiers) are run manually before opening a PR. Native builds (`validate:android`, `validate:ios`, `validate:full`) and graph tests (`validate:graph`) are never run by lefthook.
There is no pre-push hook — `yarn validate:fast` (and native/C++ extended tiers) are run manually before opening a PR. Native builds (`validate:android`, `validate:ios`, `validate:full`) and extended C++ (`validate:cpp-extended`) are never run by lefthook.

---

Expand All @@ -92,24 +93,27 @@ yarn validate:fast
```bash
yarn validate:android # yarn workspace … build:android (~3–4 min)
yarn validate:ios # yarn workspace … build:ios (macOS only)
yarn validate:full # --fast + --android + --ios
yarn validate:full # --fast + C++ extended + --android + --ios
```

The Gradle project resolves through the `node_modules/react-native-audio-api` workspace symlink, so local edits in `packages/react-native-audio-api/` are picked up.

### Graph tests (when graph / audio-thread code changes)
### Extended graph (when graph / audio-thread code changes)

```bash
yarn validate:graph
yarn validate:cpp-extended # all extended categories
# or: yarn workspace react-native-audio-api test:cpp:extended -- graph
```

### C++ tests only

```bash
yarn workspace react-native-audio-api run test:cpp
yarn validate:cpp # smoke via validate.sh
yarn workspace react-native-audio-api run test:cpp # smoke
yarn workspace react-native-audio-api run test:cpp:full # smoke + all extended
```

**When**: after any change to `common/cpp/audioapi/core/`, `dsp/`, or `utils/` C++ files. Prefer this for a fast C++-only loop without running Jest; run `yarn validate:fast` before opening a PR.
**When**: after any change to `common/cpp/audioapi/core/`, `dsp/`, or `utils/` C++ files. Prefer smoke for a fast C++-only loop; see `common/cpp/test/TESTING.md`. Run `yarn validate:fast` before opening a PR.

### Library unit tests (JS + C++)

Expand Down Expand Up @@ -162,7 +166,7 @@ Later steps may surface issues caused by earlier ones — run in this order:
2. `yarn lint` — catch remaining code issues
3. `yarn typecheck` — catch TypeScript errors
4. `yarn validate:fast` — full CI-parity gate (or `yarn test` / `test:cpp` for a quick local loop; always run `--fast` before opening a PR)
5. `yarn validate:graph` — when graph / audio-thread code changed
5. `yarn validate:cpp-extended` — when graph / audio-thread code changed
6. `yarn validate:android` / `yarn validate:ios` / `yarn validate:full` — when native code or build files changed (see decision table above)

---
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/post-work-checks/maintenance.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ Review this skill when `pre-push-update` reports changes in:
| Root `package.json` scripts | New or renamed lint/format/test/`validate:*` commands |
| `packages/react-native-audio-api/package.json` scripts | Package-level command changes (including per-language lint/format) |
| `lefthook.yml` | Pre-commit / commit-msg hook changes |
| `scripts/validate.sh` | Tier behavior (`--fast` / `--graph` / `--android` / `--ios` / `--full`), skip rules |
| `scripts/validate.sh` | Tier behavior (`--fast` / `--cpp-extended` / `--android` / `--ios` / `--full`), skip rules |
| `scripts/check-audio-enum-sync*` or `packages/react-native-audio-api/scripts/check-audio-events-sync.sh` | Enum sync check details |
| `.github/workflows/ci.yml`, `tests.yml`, `graph-tests.yml` | What CI covers vs local validation tiers |
| `.github/workflows/ci.yml`, `tests.yml`, `cpp-job.yml` | What CI covers vs local validation tiers |
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Comment thread
SomePersonFromMars marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ on:
pull_request:
branches:
- main
types: [opened, synchronize, reopened, ready_for_review]
merge_group:
types:
- checks_requested
Expand Down
58 changes: 57 additions & 1 deletion .github/workflows/cpp-job.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,84 @@ on:
working-directory:
required: false
type: string
default: '.'
default: packages/react-native-audio-api
force:
description: Skip path filter and always run (manual workflow_dispatch)
required: false
type: boolean
default: false
categories:
description: >
Space-separated extended categories. When set, path filters come from
filters.sh. Empty means always run (smoke).
required: false
type: string
default: ''

jobs:
run:
name: ${{ inputs.name }}
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
defaults:
run:
working-directory: ${{ inputs.working-directory }}
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Compose path filters
if: ${{ inputs.force == false && inputs.categories != '' }}
env:
CATEGORIES: ${{ inputs.categories }}
working-directory: ${{ github.workspace }}
run: >
bash packages/react-native-audio-api/common/cpp/test/filters.sh
path-filters ${CATEGORIES}
> "$RUNNER_TEMP/cpp-path-filters.yml"

- name: Path filter
if: ${{ inputs.force == false && inputs.categories != '' }}
uses: dorny/paths-filter@v3
id: filter
with:
filters: ${{ runner.temp }}/cpp-path-filters.yml

- name: Decide whether to run
id: decide
env:
FORCE: ${{ inputs.force }}
CATEGORIES: ${{ inputs.categories }}
FILTER_RUN: ${{ steps.filter.outputs.run }}
JOB_NAME: ${{ inputs.name }}
working-directory: ${{ github.workspace }}
run: |
if [[ "$FORCE" == "true" ]]; then
echo "run=true" >> "$GITHUB_OUTPUT"
elif [[ -z "$CATEGORIES" ]]; then
echo "run=true" >> "$GITHUB_OUTPUT"
elif [[ "$FILTER_RUN" == "true" ]]; then
echo "run=true" >> "$GITHUB_OUTPUT"
else
echo "run=false" >> "$GITHUB_OUTPUT"
echo "No matching path changes; skipping $JOB_NAME."
fi

- name: Checkout with Node
if: steps.decide.outputs.run == 'true'
uses: ./.github/actions/checkout-with-node

- name: Setup Yarn
if: steps.decide.outputs.run == 'true'
uses: ./.github/actions/setup-yarn

- name: Setup CMake
if: steps.decide.outputs.run == 'true'
uses: ./.github/actions/setup-cmake

- name: ${{ inputs.name }}
if: steps.decide.outputs.run == 'true'
run: ${{ inputs.run }}
15 changes: 0 additions & 15 deletions .github/workflows/graph-tests.yml

This file was deleted.

29 changes: 21 additions & 8 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ name: Tests

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
workflow_dispatch:
inputs:
run_cpp_tests:
description: Run C++ tests (GCC)
run_cpp_smoke_tests:
description: Run C++ smoke tests (GCC)
type: boolean
default: true
run_cpp_extended_graph:
description: Run C++ extended category graph
type: boolean
default: false
run_cpp_coverage:
description: Run C++ coverage (Clang / llvm-cov)
description: Run C++ coverage (Clang / llvm-cov, smoke)
type: boolean
default: true
run_js_tests:
Expand All @@ -18,13 +23,21 @@ on:
default: true

jobs:
cpp-tests:
if: github.event_name == 'pull_request' || inputs.run_cpp_tests
cpp-smoke-tests:
if: github.event_name == 'pull_request' || inputs.run_cpp_smoke_tests
uses: ./.github/workflows/cpp-job.yml
with:
name: C++ smoke
run: yarn test:cpp:smoke

cpp-extended-graph:
if: github.event_name == 'pull_request' || inputs.run_cpp_extended_graph
uses: ./.github/workflows/cpp-job.yml
with:
name: C++ tests
working-directory: packages/react-native-audio-api
run: yarn test:cpp
name: C++ extended (graph)
run: yarn test:cpp:extended -- graph
categories: graph
force: ${{ github.event_name == 'workflow_dispatch' }}

cpp-coverage:
if: github.event_name == 'pull_request' || inputs.run_cpp_coverage
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/wpt-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ name: WPT Tests

on:
pull_request:
# ready_for_review is not a default type, but drafts are skipped below, so without it a
# pull request opened as a draft would never get a report until its next push.
types: [opened, synchronize, reopened, ready_for_review]
workflow_dispatch:

Expand Down
Loading
Loading