Skip to content
Draft
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
51 changes: 0 additions & 51 deletions .github/workflows/ci-android.yml

This file was deleted.

102 changes: 78 additions & 24 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -192,44 +192,56 @@ jobs:
- name: Generate TrUAPIProvider bindings
run: make provider-swift

ios-changes:
name: iOS change filter
changes:
name: Change filter
runs-on: ubuntu-latest
outputs:
ios: ${{ steps.filter.outputs.ios }}
sdk_swift: ${{ steps.filter.outputs.sdk_swift }}
sdk_kotlin: ${{ steps.filter.outputs.sdk_kotlin }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 2
persist-credentials: false

# Actions has no per-job paths filter, so compute it once here and gate
# ios-swift on the output. On pull_request the checkout is the merge
# commit, so HEAD^1 is the base. Other events always run the gate.
# Actions has no per-job paths filter, so compute every gate once here and
# have each gated job read an output. On pull_request the checkout is the
# merge commit, so HEAD^1 is the base. Other events always run every gate.
#
# The bindings are generated, not committed, so a UniFFI surface change
# leaves no ios/ diff to key on. The list therefore names every crate the
# bindings are generated from, plus js/container, which is compiled into
# the TrUAPIHost target as a resource.
- name: Detect iOS-relevant changes
# Neither binding set is committed, so a UniFFI surface change leaves no
# ios/ or android/ diff to key on. Each list therefore names every crate
# its bindings are generated from. js/container is in the Swift list
# because it is compiled into the TrUAPIHost target as a resource. Both
# lists name this workflow, so editing a filter exercises what it gates.
- name: Detect which areas changed
id: filter
run: |
set -euo pipefail

if [ "${{ github.event_name }}" != "pull_request" ]; then
echo "ios=true" >> "$GITHUB_OUTPUT"
{
echo "sdk_swift=true"
echo "sdk_kotlin=true"
} >> "$GITHUB_OUTPUT"
exit 0
fi
if git diff --name-only HEAD^1 HEAD \
| grep -qE '^(ios/|Package\.swift$|Makefile$|js/container/|rust/crates/truapi/|rust/crates/truapi-platform/|rust/crates/truapi-server/|rust/crates/truapi-provider/)'; then
echo "ios=true" >> "$GITHUB_OUTPUT"
else
echo "ios=false" >> "$GITHUB_OUTPUT"
fi

changed="$(git diff --name-only HEAD^1 HEAD)"
gate() {
if grep -qE "$2" <<<"$changed"; then
echo "$1=true" >> "$GITHUB_OUTPUT"
else
echo "$1=false" >> "$GITHUB_OUTPUT"
fi
}

gate sdk_swift '^(ios/|Package\.swift$|Makefile$|js/container/|rust/crates/truapi/|rust/crates/truapi-platform/|rust/crates/truapi-server/|rust/crates/truapi-provider/|\.github/workflows/ci\.yml$)'
gate sdk_kotlin '^(android/|Makefile$|rust/crates/truapi/|rust/crates/truapi-platform/|rust/crates/truapi-server/|rust/crates/uniffi-bindgen-cli/|\.github/workflows/ci\.yml$)'

ios-swift:
name: iOS package (swift compile)
needs: [ios-changes, codegen]
if: needs.ios-changes.outputs.ios == 'true'
needs: [changes, codegen]
if: needs.changes.outputs.sdk_swift == 'true'
runs-on: macos-15
timeout-minutes: 30
env:
Expand Down Expand Up @@ -324,6 +336,46 @@ jobs:
CODE_SIGNING_ALLOWED=NO
swift build --target TrUAPIProvider

# Compile gate for the Android host module: regenerates the UniFFI Kotlin
# bindings and compiles the shell against them. No cross-compile, no
# publishing.
android-bindings:
name: Android host (kotlin compile)
needs: changes
if: needs.changes.outputs.sdk_kotlin == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# codegen.sh formats its generated Rust with `cargo +nightly fmt`.
- uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # nightly
with:
toolchain: nightly
components: rustfmt
- uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # stable
- uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2.8.1
- uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0
with:
distribution: temurin
java-version: "17"
- uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0
with:
gradle-version: "8.9"
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "22"
# truapi-server declares its generated modules unconditionally and they are
# gitignored, so the crate does not compile until codegen has run.
- name: Generate the Rust codegen output
run: |
npm ci --ignore-scripts
TRUAPI_SKIP_PACKAGE_BUILD=1 ./scripts/codegen.sh
- name: Generate UniFFI Kotlin bindings
run: make uniffi-kotlin
- name: Compile the shell against the bindings
run: gradle :truapi-host:assembleRelease

ts-client:
name: "@parity/truapi"
runs-on: ubuntu-latest
Expand Down Expand Up @@ -591,8 +643,9 @@ jobs:
licenses,
codegen,
ios-bindings,
ios-changes,
changes,
ios-swift,
android-bindings,
ts-client,
ts-host,
ts-debugger,
Expand All @@ -609,10 +662,11 @@ jobs:
"${{ needs.licenses.result }}"
"${{ needs.codegen.result }}"
"${{ needs.ios-bindings.result }}"
# ios-changes is listed because a failure there skips ios-swift,
# and skipped counts as a pass below.
"${{ needs.ios-changes.result }}"
# changes is listed because a failure there skips every gated
# job, and skipped counts as a pass below.
"${{ needs.changes.result }}"
"${{ needs.ios-swift.result }}"
"${{ needs.android-bindings.result }}"
"${{ needs.ts-client.result }}"
"${{ needs.ts-host.result }}"
"${{ needs.ts-debugger.result }}"
Expand Down
19 changes: 11 additions & 8 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,17 @@ scripts/truapi-host-installer.sh
still has a binding representation, and the `ios-swift` job generates the
package's Swift sources and container resource and then compiles the package
and its test target, which is what catches a hand-written conformer that
missed a new protocol requirement. `ios-swift` is path-filtered, and the
filter has to name every crate the bindings are generated from, since a
protocol change no longer leaves an `ios/` diff to key on. On the Kotlin side
the `ci-android` job compiles
`TrUAPIHost.kt` against freshly generated bindings on pull requests touching
`android/` or the native crates, which catches the same class of drift;
`make android-check` does it locally. The embedding apps are compiled by
neither.
missed a new protocol requirement. On the Kotlin side the `android-bindings`
job compiles `TrUAPIHost.kt` against freshly generated bindings, which catches
the same class of drift; `make android-check` does it locally. The embedding
apps are compiled by neither.
- Both compile gates are path-filtered from one place. The `changes` job in
`ci.yml` computes `sdk_swift` and `sdk_kotlin`, and each gated job reads the
output. Because neither binding set is committed, a filter has to name every
crate its bindings are generated from, since a protocol change leaves no
`ios/` or `android/` diff to key on. Every job in `ci.yml` is aggregated by
`ci-status`, which is the check worth requiring: a job skipped by its filter
counts as a pass, so a gate cannot stall a PR it does not apply to.
Hosts implement `HostBridge`, whose protocol extension defaults the optional
callbacks; `TrUAPIHostRuntime` and each product execution retain one.
To publish, include `@parity/ios-host <version>` in the `release:` PR title.
Expand Down