Skip to content

ci: rework CI into a checks/iOS/macOS pipeline for all platforms - #4

Merged
weskcode merged 1 commit into
developfrom
feature/ci-all-platforms
Sep 2, 2026
Merged

weskcode merged 1 commit into
developfrom
feature/ci-all-platforms

Conversation

@weskcode

@weskcode weskcode commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Reworks CI from two near-duplicate jobs into a checks → iOS / macOS pipeline.

What was wrong

Problem Consequence
Setup duplicated 4× across jobs Every toolchain change had to be made in four places
Ran only on main develop merges were never verified
No result bundles kept UI screenshots (.keepAlways) died with the runner; failures had to be reproduced blind
Nothing checked the Mac binary was universal macOS still ships to Intel
-only-testing named UI classes explicitly The UI target globs its whole directory — a new test class would silently never run
No concurrency Superseded pushes kept burning scarce macOS runners

Structure

  • Composite action .github/actions/setup — Xcode select, SDK assert, XcodeGen, generate. One definition instead of four.
  • checks job runs first. It asserts the deployment floor, App Group wiring, and privacy-manifest reasons. None of those are caught by any build, because every xcodebuild here passes CODE_SIGNING_ALLOWED=NO — so entitlements are never applied. A bad config now fails in seconds rather than after 12 minutes of simulator work.
  • iOS and macOS gate on it and run in parallel.

Coverage added

  • Universal macOS Release build + lipo assertion on both slices. Nothing previously proved the shipped Mac app contained x86_64. Only the x86_64 test run needs Rosetta — which the arm64 runner doesn't document — so that half stays in Scripts/verify-macos.sh for local use.
  • iOS unit tests run once, not per matrix leg; they're pure logic and device-independent.
  • Result bundles uploaded on failure, 14-day retention.

iPad

Deliberately not a matrix leg yet. The UI suite on develop has no iPad handling — no idiom checks, no sidebar/split-view paths — so the leg would fail on the first UI test. The iPad-capable suite arrives with the App Store screenshots branch (854b3da). Once that merges, adding ipad to the matrix list is the only change needed; the rationale is recorded inline.

Verification

Runner facts confirmed against the actions/runner-images manifest rather than assumed: macos-26 is arm64 with Xcode 26.6 default and iOS 26.2/26.4/26.5 runtimes, each carrying both iPhone and iPad devices — so the resolver's 26.5 floor and its SDK-major ceiling both land on 26.5.

Locally verified: YAML parses, composite action satisfies every rule (using: composite, shell: on each step), checks steps pass, the lipo assertion logic works against known-good output, and both resolver families return devices.

An adversarial review raised 6 high/blocker issues; verification confirmed 2 and refuted 4. Both real ones are fixed here — the composite action was untracked (would have failed every job with "Can't find 'action.yml'"), and the iPad leg above.

🤖 Generated with Claude Code

The workflow duplicated its setup four times, ran only on main, kept no
diagnostics, and never verified the shipped Mac binary was universal.

Structure:
- New composite action .github/actions/setup replaces the Xcode-select,
  SDK-assert, XcodeGen and generate steps duplicated across both jobs.
- A cheap `checks` job runs first. It asserts the deployment floor, App Group
  wiring and privacy-manifest reasons -- none of which any build catches, since
  every xcodebuild here passes CODE_SIGNING_ALLOWED=NO -- so a bad config fails
  in seconds instead of after twelve minutes of simulator work.
- iOS and macOS both gate on it and run in parallel.

Coverage:
- Universal macOS Release build with an explicit lipo assertion on both the
  arm64 and x86_64 slices. Nothing previously proved the shipped Mac app
  carried both, and macOS still ships to Intel. Only the x86_64 *test* run
  needs Rosetta, which the arm64 runner does not document, so that half stays
  in Scripts/verify-macos.sh for local use.
- iOS unit tests run once rather than on every matrix leg; they are pure logic
  and device-independent.
- The UI step drops -only-testing. The UI target globs its whole source
  directory, so naming classes there silently skipped any newly added class.

Operations:
- concurrency cancels superseded runs, so a new push stops burning the macOS
  runners the previous one held.
- permissions: contents: read.
- Push now also builds `develop`, which was previously merged unverified.
- Result bundles are written and uploaded on failure. UI tests attach
  screenshots with .keepAlways; those previously died with the runner and every
  failure had to be reproduced blind.

iPad is intentionally not a matrix leg yet: the UI suite here has no iPad
handling, so the leg would fail. The rationale and the one-word change to
enable it are recorded inline.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@weskcode
weskcode merged commit 49940ac into develop Sep 2, 2026
3 checks passed
@weskcode
weskcode deleted the feature/ci-all-platforms branch September 2, 2026 17:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant