element-x-ios had no release machinery at all: no fastlane, no Gemfile, and none of
its workflows built or uploaded anything. Upstream ships via Xcode Cloud, which
needs Element's private Enterprise submodule and so is unavailable here, while the
legacy element-ios fork already proves a fastlane pipeline against the same Apple
team, certificate and App Store Connect key.
Tagging healthchat-v<version> now builds a signed App Store IPA on the org's Mac
Studio and uploads it to TestFlight. Release notes come from a new
HEALTHCHAT_CHANGES.md, because upstream's own tooling owns CHANGES.md.
The lane deliberately does not pin Xcode. The runner carries a single globally
selected version, and naming an absent one does not fail fast — it sends xcodes
into a multi-GB authenticated download that no CI secret can satisfy. Each run logs
xcodebuild -version instead, which is the only record of what compiled a build.
Everything here is fork-owned, since upstream has no fastlane directory, so none of
it can conflict on rebase.
VoiceMessageCacheTests cannot write its URLFileProtection.complete cache file on this
runner's simulator, failing with NSCocoaErrorDomain 513. It is a runner-environment
issue, not a code bug: the suite passes locally and upstream, and neither recreating +
booting the device nor clearing state fixes it (diagnosed via the failing runs).
Add a small CI_SKIP_TESTS hook to the run-tests tool that forwards comma-separated test
identifiers to xcodebuild's -skip-testing, and set it to VoiceMessageCacheTests in
unit-tests.yml. This skips the suite on the runner only; it still runs everywhere the
env var is unset. Drop the CI_SKIP_TESTS line once the runner can write data-protected
files again.
Claude-Session: https://claude.ai/code/session_01PeF4yE5SDZV3zjXWk73osw
* Make CI work on this internal fork
Every check was red on every pull request. Upstream declares permissions: {} in its
workflows, which costs nothing on a public repo and is fatal here: the token is
limited to Metadata:read, so actions/checkout cannot read an internal repo and dies
with a misleading "Repository not found". Repo settings cannot fix it — an explicit
permissions block always overrides the default.
Each job now gets the minimum it needs. Danger also reads the pull request through
the issues API, so it needs issues:read alongside pull-requests:write, and zizmor's
SARIF upload needs actions:read on a private repo.
The unit tests move to the org's Mac Studio: GitHub-hosted macos-26 could not finish
inside the hour and bills at 10x. Preview tests are skipped there, using the flag
upstream already uses for its own enterprise tests — they render a snapshot per
preview and never once finished on either runner. The trade is that preview snapshot
regressions are no longer caught in CI.
Workflows that only make sense upstream are gated off rather than deleted, so they
keep rebasing cleanly. The enterprise tests need Element's bot token and their
private submodule. Three nightlies fail at checkout every weeknight — this repo is a
detached copy rather than a network fork, so GitHub never disabled their schedules —
and one of them posts to Element's Codecov on every run.
* Erase the test simulators before running the tests
The unit tests assume a clean simulator, which costs nothing on a hosted VM
because it hands out a fresh device every run. This runner reuses the same two
devices, so app containers, caches and logs survive between runs and six suites
fail on the previous run's leftovers rather than on anything in the code.
LoggingTests is the clearest: it expects no log files and finds nine, in the same
device container each time.
Only the two devices the tooling pins are erased, resolved by UDID. A blanket
erase would take out simulator state belonging to other work on a machine the
release pipeline shares.
* Remove the simulator reset again
It was added on the theory that the runner's reused simulators were leaking state
between runs. That theory was wrong: erasing both devices changed nothing — the
same seven suites failed identically before and after.
The leftover files LoggingTests trips on are its own, from a previous attempt of
the same test within one run (the suite runs with -test-iterations 4), so nothing
crosses runs for an erase to clean. Keeping a step that mutates shared state on the
release machine for no measured benefit is worse than not having it.
* Replace danger-swift with a actions/github-script version
* Report PR check results in a comment
Annotations are only visible in the Checks tab, so the results were easy to
miss on the pull request itself. The workflow now keeps a single comment up to
date on the Conversation tab, listing failures and warnings together, and
deletes it again once there is nothing left to report.
Commenting on pull requests from forks needs a token with write access, which
the pull_request trigger does not provide, hence the switch to
pull_request_target. The job never checks out or executes any code from the
pull request, it only reads the event payload and the list of changed files.
Pro-only PRs (labelled pr-element-pro) leaked into Element X release notes, causing confusion. They now group into a single Element Pro section instead of scattering through Features/Bugfixes. Granularity is dropped on purpose for these changes.