Skip to content

ci(ios): run the iOS build and tests on every pull request - #754

Merged
TarikGul merged 10 commits into
mainfrom
tg/ios-ci-live
Sep 14, 2026
Merged

TarikGul merged 10 commits into
mainfrom
tg/ios-ci-live

Conversation

@TarikGul

@TarikGul TarikGul commented Sep 14, 2026

Copy link
Copy Markdown
Member

Turns on the iOS build and tests for every pull request, and makes them pass.

Folded together rather than stacked, so this is one CI run and one merge instead
of three, and main never carries a red iOS check.

Four files

.github/workflows/ios-pr.yml goes back to triggering on pull_request,
and gains a preview job. workflow_dispatch stays so a build can be reproduced
without pushing a commit. Every other iOS workflow stays on dispatch: they need
credentials that are not here yet and branch filters naming a branching model
this repository does not use.

.github/actions/bootstrap-ios-core generates what the app needs before its
package graph can resolve: the Rust codegen output, the host bindings and
xcframework, and the provider bindings. The app resolves the core from this tree
rather than a published version, and those outputs are gitignored, so without
this the build fails at package resolution. It mirrors the sequence
release-ios.yml already uses.

KnownChains.swift and TrUAPIHostRuntimeProvider.swift pass the
network suffix the host's chains belong to. HostRuntimeConfig requires it and
the app never passed it, so the app did not compile against the core at HEAD.
Background on #755.

What runs per pull request

job runner what it does
build macos-26 DevCI compile, with the warning ratchet that annotates new warnings inline and fails on them
test macos-26-xlarge the unit test suite
preview macos-26-xlarge an installable simulator .app, stamped with its commit

The preview needs no provisioning profile or signing identity, since the lane
signs ad-hoc, so it adds no credential requirement. The commit goes into the
bundle's Info.plist, not only the artifact name, and the job fails if the
stamp did not take.

Verified

build and test both passed on this code before it was folded together. That
run was the first time the app has been compiled and tested against a core built
from this tree.

Three things were wrong before it went green, recorded because they are the
interesting part: the core bindings were never generated, the xcframework was
built simulator-only while gym archives for a device, and the app did not pass
networkSuffix. The last had been on main since #627 on 2026-09-07, invisible
because iOS built against a pinned published core in another repository.

One value still needs confirming

KnownNetworkSuffix.current returns paseo for the Release configuration and
that is unverified, tracked by #760. No CI configuration builds that branch:
build_app_ci uses DevCI, which sets UNSTABLE and resolves to testnet,
the value these runs exercised.

Closes #680. Closes #755.

GitHub reads workflows only from the repository root, so everything under
hosts/ios/.github/workflows/ is inert. These seven are the ones that never
trigger themselves: two are workflow_call, five are workflow_dispatch. Moving
them changes no scheduled or pull request behaviour, so the mechanical work
lands before the secrets and runners that the pull request checks need.

Paths now resolve from the repository root. Composite action references become
./hosts/ios/.github/actions/..., which is also how the workflow_call references
between these files start resolving at all, since a local uses: path is always
read from the root regardless of where the calling file sits.

Steps that drive the app rather than the repository run from hosts/ios: the
fastlane invocations, the xcconfig edit, and the TestFlight build number lookup.
Steps that take a path argument keep a root-relative one instead, so
read-build-version reads a prefixed pbxproj default and a prefixed script path.

The shared composite actions pick up the same treatment: bundler resolves
hosts/ios/Gemfile, the SPM cache points at hosts/ios/source_packages, the
generated secrets and GoogleService-Info.plist land under hosts/ios, and the
built ipa is uploaded from there.

None of this is exercised yet. No current job resolves these workflows, and the
build itself needs the credentials tracked in #672, so this is verified by
actionlint and by every local reference resolving, not by a run.
The last eight, which is every iOS workflow that triggers itself. Four run on
pull_request and four on a schedule, so unlike the first batch they cannot be
moved and left alone: at the repository root they would run, and the build
credentials tracked in #672 are not all in place.

Each live trigger is therefore commented out rather than deleted, with the note
that restoring it is what puts the workflow live. The original filters are
preserved exactly, including the pull_request types and branch lists and the
cron expressions, so going live is a readable diff rather than a rewrite. pr.yml
and release_branch_lifecycle.yml carried only pull_request, so they gain a
workflow_dispatch trigger to stay valid.

Paths get the same treatment as the first batch. Steps that drive the app run
from hosts/ios, artifact and upload paths are prefixed, and the simulator
release writes a root-relative archive path because the release step resolves it
from the workspace.

These files are linted for the first time by moving to the root, so the
pre-existing findings are fixed here: six unquoted GITHUB_ENV and GITHUB_OUTPUT
redirects, and a glob that could be read as options.

Two things deliberately left for the follow-up that restores the triggers. The
branch filters name develop and main from the source repository's branching
model, which does not apply here. And no run has exercised any of this.
Every credential pr.yml reads is now set on this repository, so the trigger it
was held back from can be restored. Nothing else changes: the distribution and
schedule workflows stay on workflow_dispatch, since they need credentials that
are not here yet and branch filters that name a branching model this repository
does not use.

pr.yml never carried a branch filter, so restoring it is the trigger alone.
workflow_dispatch stays so a build can be reproduced without pushing a commit.

This also exercises the path rewrites for the first time. A workflow gaining a
pull_request trigger runs on the pull request that adds it, so the build and
test jobs here are the first real test of the move to the repository root.
@github-actions github-actions Bot added the github_actions Pull requests that update GitHub Actions code label Sep 14, 2026
The first run failed both jobs at package resolution:

  invalid custom path 'ios/truapi-provider/Sources/truapi_providerFFI/include'
  for target 'truapi_providerFFI'

Not a path rewrite. Every re-homed step succeeded. The app resolves the core
from this tree rather than a published version, and the core's bindings,
xcframework and FFI headers are gitignored build outputs, so the package graph
cannot resolve until they are generated. In the source repository the core
arrived prebuilt, so nothing had to generate it.

A composite action does that once and both jobs call it: the Rust codegen
output, the host bindings and xcframework, and the provider bindings. It mirrors
what release-ios.yml already does, which is the known-good sequence.

Simulator slice only, since a pull request never builds for a device, which
halves the xcframework build.
@github-actions

github-actions Bot commented Sep 14, 2026

Copy link
Copy Markdown

CI Status: 17 required jobs green, 13 passed and 4 skipped by path filter.

All job results
job result
android-bindings skipped
changes success
changeset-guard skipped
codegen success
e2e skipped
explorer success
ios-bindings success
ios-swift skipped
licenses success
playground success
release-guard success
rust success
ts-client success
ts-debugger success
ts-host success
wasm-provider success
workflow-lint success

Commit cc14c2cc · run log

The bootstrap built the simulator slice only, on the assumption a pull request
never builds for a device. The build job does:

  While building for iOS, no library for this platform was found in
  ios/truapi-host/Binaries/truapi_server.xcframework

build_app_ci archives through gym, which always targets a device, so it needs
the device slice. Only the test job is simulator-only, and both jobs share this
action, so both slices it is.
@TarikGul TarikGul mentioned this pull request Sep 14, 2026
3 tasks
TrUAPIHost's HostRuntimeConfig requires networkSuffix, added with the reserved
person and identity key derivation. The app never passed it, so it does not
compile against the core in this tree.

The value has to name the same network the chains do, since the reserved
identities are derived under it and a wrong value derives a different person
from the same seed rather than failing. So it lives beside the chain selection,
under the same compile-time conditions, where the two cannot drift apart.

UNSTABLE selects the previewnet chains, which the host CLI pairs with the
testnet suffix. NIGHTLY selects the nightly Paseo chains, which it pairs with
paseo. Release is unconfirmed and marked as such: its chains carry the same
assets as the nightly ones, pas in the native slot and pusd beside it, which
points at Paseo rather than Polkadot. No CI configuration builds that branch.
@TarikGul

Copy link
Copy Markdown
Member Author

The failing build and test here are expected and are not a regression.

This pull request turns on the pull_request trigger, so iOS CI runs on it. The
app does not compile against the core in this tree yet, for the reason in #755:
HostRuntimeConfig requires networkSuffix and the app never passed it.

The fix is #756, stacked on this branch. It is not in this branch, so this one
builds the code without it and fails at that call. Once #756 merges into here,
this goes green.

Merge order is #741, then this, then #756. Everything the re-homing itself owns
already passes: checkout, Xcode setup, Google services, secrets, and the in-tree
core bootstrap all succeed before the app compile is reached.

Base automatically changed from tg/rehome-ios-remaining-workflows to main September 14, 2026 14:06
The note pointed at the pull request that added it, which says nothing once the
change is merged. It names the issue that carries the open question instead.
# Conflicts:
#	.github/workflows/ios-pr.yml
A reviewer can run the change rather than read it. The simulator slice is
ad-hoc signed, so it needs no provisioning profile and no signing identity, and
therefore nothing the build job does not already have.

The commit goes into the bundle's Info.plist, not only the artifact name, so a
build that has been downloaded and unzipped still says where it came from. The
stamp is read back and the job fails if it did not take, because a build that
cannot name its commit should not be published.

Simulator slice only, unlike the build job, which archives for a device and
needs both. DevCI configuration, so the preview exercises the same chains and
settings the checks do.
@github-actions github-actions Bot added the host-work Needs implementation in one or more host repos label Sep 14, 2026
@TarikGul
TarikGul marked this pull request as ready for review September 14, 2026 14:51
@TarikGul
TarikGul requested a review from a team September 14, 2026 14:51
@TarikGul
TarikGul added this pull request to the merge queue Sep 14, 2026
Merged via the queue into main with commit f1115ed Sep 14, 2026
53 of 57 checks passed
@TarikGul
TarikGul deleted the tg/ios-ci-live branch September 14, 2026 15:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

github_actions Pull requests that update GitHub Actions code host-work Needs implementation in one or more host repos

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TrUAPIHost's Swift API requires networkSuffix and the iOS app does not pass it Re-home the iOS host workflows

3 participants