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
54 changes: 54 additions & 0 deletions .github/actions/setup-ios-xcode/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Setup iOS Xcode
description: >
Materialize the pinned Xcode at its /nix/store path via xmtp-cache-apple
(Apple's license forbids serving Xcode from a binary cache). Single source
of truth for the Xcode version and store path used by the iOS workflows —
keep in sync with xcodeVer in nix/ios-packages.nix.

runs:
using: composite
steps:
# The local bundle is only needed for the cold-cache bootstrap import;
# warm runs restore a NAR and never touch it. A runner with no local
# Xcode still works warm — and on a cold cache it fails in the
# bootstrap step with a clear missing-bundle cause (nothing can
# conjure Xcode there anyway).
- name: Resolve Xcode bundle path
id: xcode-path
shell: bash
run: |
p=""
for c in /Applications/Xcode_26.3*.app /Applications/Xcode-26.3*.app /Applications/Xcode.app; do
[ -d "$c" ] || continue
v=$(defaults read "$c/Contents/version" CFBundleShortVersionString 2>/dev/null || true)
case "$v" in 26.3|26.3.*) p="$c"; break ;; esac
done
if [ -z "$p" ]; then
echo "::warning::No local Xcode 26.3 bundle found; OK on a warm cache, the cold-cache bootstrap will fail."
p=/Applications/Xcode_26.3.app
fi
echo "path=$p" >> "$GITHUB_OUTPUT"
# requireFile fixed-output path: moves only if the pinned sha256 for
# xcode_26_3 changes, never with nixpkgs/flake.lock bumps.
echo "nix-path=/nix/store/x9hdz5mfp44i9b05sswp271jdv68r8vx-Xcode.app" >> "$GITHUB_OUTPUT"
# On a NAR-cache miss the action imports the runner bundle, which is a
# pruned image that never hashes to the pin — its export step then fails.
# Tolerate that: builds substitute from xmtp.cachix and swift steps use
# the runner bundle via the DEVELOPER_DIR fallback below.
- uses: xmtplabs/xmtp-cache-apple@v1.0.3
Comment thread
macroscopeapp[bot] marked this conversation as resolved.
continue-on-error: true
with:
xcode-path: ${{ steps.xcode-path.outputs.path }}
xcode-nix-path: ${{ steps.xcode-path.outputs.nix-path }}
# Point non-nix tool invocations (raw xcodebuild/swift steps) at the
# pinned store Xcode when it materialized, else at the version-verified
# runner bundle — runner images are pruned and never hash to the pin.
- name: Export DEVELOPER_DIR
shell: bash
run: |
dev="${{ steps.xcode-path.outputs.nix-path }}"
if ! nix path-info "$dev" >/dev/null 2>&1; then
echo "::warning::Pinned Xcode not in the store (expected on a cold NAR cache); swift steps use the runner bundle."
dev="${{ steps.xcode-path.outputs.path }}"
fi
echo "DEVELOPER_DIR=$dev/Contents/Developer" >> "$GITHUB_ENV"
1 change: 1 addition & 0 deletions .github/workflows/lint-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jobs:
with:
github-token: ${{ github.token }}
cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }}
- uses: ./.github/actions/setup-ios-xcode
- uses: taiki-e/install-action@just
Comment on lines +16 to 17

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium workflows/lint-ios.yml:16

The new setup-ios-xcode step pins the workflow to a specific Xcode NAR, but just ios lint only runs swiftlint and swiftformat which don't require Xcode. When the Xcode cache is cold, the runner fails at bootstrap despite the lint tools being available, turning a previously reliable job into an intermittently failing gate. Consider removing this step since it's unnecessary for the tools being invoked.

-      - uses: ./.github/actions/setup-ios-xcode
       - uses: taiki-e/install-action@just
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @.github/workflows/lint-ios.yml around lines 16-17:

The new `setup-ios-xcode` step pins the workflow to a specific Xcode NAR, but `just ios lint` only runs `swiftlint` and `swiftformat` which don't require Xcode. When the Xcode cache is cold, the runner fails at bootstrap despite the lint tools being available, turning a previously reliable job into an intermittently failing gate. Consider removing this step since it's unnecessary for the tools being invoked.

- name: Lint iOS SDK
run: just ios lint
14 changes: 9 additions & 5 deletions .github/workflows/release-ios.yml

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium

- uses: ./.github/actions/setup-release-tools

The publish job runs pod trunk push XMTP.podspec, which invokes xcodebuild for validation, but this job never calls .github/actions/setup-ios-xcode. It uses the runner's default Xcode, so if that differs from the pinned toolchain the pod validation/build can fail on the exact Xcode-version mismatch this PR is trying to eliminate. Add the same setup-ios-xcode step to the publish job (before the CocoaPods push) so both jobs use the same Xcode.

Also found in 1 other location(s)

sdks/ios/dev/.ensure-xcode:23

XCODE_VERSION is taken from the ambient environment (XCODE_VERSION="${XCODE_VERSION:-26.3}"), but the actual iOS build graph is still pinned to xcodeVer = "26.3" in nix/ios-packages.nix. If a developer or CI job already exports XCODE_VERSION (a common variable name in Apple build tooling), this script will materialize and/or cache the wrong darwin.xcode_* store path and return success, after which the subsequent nix build still fails because the real pinned Xcode was never imported.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @.github/workflows/release-ios.yml around line 130:

The `publish` job runs `pod trunk push XMTP.podspec`, which invokes `xcodebuild` for validation, but this job never calls `.github/actions/setup-ios-xcode`. It uses the runner's default Xcode, so if that differs from the pinned toolchain the pod validation/build can fail on the exact Xcode-version mismatch this PR is trying to eliminate. Add the same `setup-ios-xcode` step to the `publish` job (before the CocoaPods push) so both jobs use the same Xcode.

Also found in 1 other location(s):
- sdks/ios/dev/.ensure-xcode:23 -- `XCODE_VERSION` is taken from the ambient environment (`XCODE_VERSION="${XCODE_VERSION:-26.3}"`), but the actual iOS build graph is still pinned to `xcodeVer = "26.3"` in `nix/ios-packages.nix`. If a developer or CI job already exports `XCODE_VERSION` (a common variable name in Apple build tooling), this script will materialize and/or cache the wrong `darwin.xcode_*` store path and return success, after which the subsequent `nix build` still fails because the real pinned Xcode was never imported.

Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ jobs:
with:
github-token: ${{ github.token }}
cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }}
- uses: ./.github/actions/setup-ios-xcode
Comment thread
macroscopeapp[bot] marked this conversation as resolved.
- name: Compute version
id: version
run: |
Expand Down Expand Up @@ -76,17 +77,20 @@ jobs:
echo "base-version=$BASE" >> "$GITHUB_OUTPUT"
echo "Computed version: $VERSION"
- name: Build xcframeworks
run: nix build .#ios-xcframeworks --out-link build/ios
run: nix build .#ios-release --out-link build/ios

- name: Package and checksum
id: checksum
run: |
cp -rL build/ios/LibXMTPSwiftFFI LibXMTPSwiftFFI
# cp -R + zip -y: the macOS dynamic framework's Versions/ symlinks
# are part of the signed bundle — dereferencing them post-signing
# invalidates the rcodesign signature.
mkdir LibXMTPSwiftFFI && cp -R build/ios/LibXMTPSwiftFFI/. LibXMTPSwiftFFI/
chmod -R u+w LibXMTPSwiftFFI
(cd LibXMTPSwiftFFI && zip -qr ../LibXMTPSwiftFFI.zip .)
cp -rL build/ios/LibXMTPSwiftFFIDynamic LibXMTPSwiftFFIDynamic
(cd LibXMTPSwiftFFI && zip -qry ../LibXMTPSwiftFFI.zip .)
mkdir LibXMTPSwiftFFIDynamic && cp -R build/ios/LibXMTPSwiftFFIDynamic/. LibXMTPSwiftFFIDynamic/
chmod -R u+w LibXMTPSwiftFFIDynamic
(cd LibXMTPSwiftFFIDynamic && zip -qr ../LibXMTPSwiftFFIDynamic.zip .)
(cd LibXMTPSwiftFFIDynamic && zip -qry ../LibXMTPSwiftFFIDynamic.zip .)
echo "checksum=$(shasum -a 256 LibXMTPSwiftFFI.zip | awk '{ print $1 }')" >> "$GITHUB_OUTPUT"
echo "dynamic-checksum=$(shasum -a 256 LibXMTPSwiftFFIDynamic.zip | awk '{ print $1 }')" >> "$GITHUB_OUTPUT"
- name: Create or update GitHub Release
Expand Down
4 changes: 1 addition & 3 deletions .github/workflows/test-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ jobs:
github-token: ${{ github.token }}
cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }}
with-warpbuild-cache: "false"
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: "26"
- uses: ./.github/actions/setup-ios-xcode
- uses: taiki-e/install-action@just
- name: Build and test
env:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,4 @@ docs/plans
# Claude Code
.claude/scheduled_tasks.lock
/target-linux-amd64
nixpkgs
36 changes: 12 additions & 24 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 7 additions & 31 deletions flake.nix

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High

packages = {

The new import ./nix/ios-packages.nix at line 58 replaces the manually-defined iOS packages, but the old flake outputs .#ios-xcframeworks, .#ios-xcframeworks-fast, .#ios-libs, and .#ios-libs-fast are removed without compatibility aliases. The iOS release workflow in .github/workflows/release-ios.yml still invokes nix build .#ios-xcframeworks, so it will fail with "does not provide attribute 'ios-xcframeworks'" after this change. Consider re-exporting these attributes from ./nix/ios-packages.nix or adding passthrough aliases in packages to maintain backward compatibility.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @flake.nix around line 83:

The new import `./nix/ios-packages.nix` at line 58 replaces the manually-defined iOS packages, but the old flake outputs `.#ios-xcframeworks`, `.#ios-xcframeworks-fast`, `.#ios-libs`, and `.#ios-libs-fast` are removed without compatibility aliases. The iOS release workflow in `.github/workflows/release-ios.yml` still invokes `nix build .#ios-xcframeworks`, so it will fail with "does not provide attribute 'ios-xcframeworks'" after this change. Consider re-exporting these attributes from `./nix/ios-packages.nix` or adding passthrough aliases in `packages` to maintain backward compatibility.

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
};

inputs = {
# Cross pkgsets apply the upstream iOS branch as a patch
# on top — see nixpkgs-patched in nix/lib/default.nix.
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
fenix = {
url = "github:nix-community/fenix";
Expand All @@ -17,7 +19,10 @@
flake-parts = {
url = "github:hercules-ci/flake-parts";
};
foundry.url = "github:shazow/foundry.nix/stable";
foundry = {
url = "github:shazow/foundry.nix/stable";
inputs.nixpkgs.follows = "nixpkgs";
};
crane = {
url = "github:ipetkov/crane";
};
Expand Down Expand Up @@ -46,6 +51,7 @@
./nix/node-packages.nix
./nix/android-packages.nix
./nix/apps.nix
./nix/ios-packages.nix
];
perSystem =
{
Expand Down Expand Up @@ -83,36 +89,6 @@
;
wasm-bindings = (pkgs.callPackage ./nix/package/wasm.nix { }).bin;
wasm-bindings-test = (pkgs.callPackage ./nix/package/wasm.nix { test = true; }).bin;
}
// lib.optionalAttrs pkgs.stdenv.isDarwin {
# stdenvNoCC is passed to callPackage (for the aggregate derivation).
# This avoids Nix's apple-sdk and cc-wrapper,
# which inject -mmacos-version-min flags that
# conflict with iOS cross-compilation. The builds are impure (__noChroot)
# and use the system Xcode SDK directly via ios-env.nix paths.
ios-libs =
(pkgs.callPackage ./nix/package/ios.nix {
stdenv = pkgs.stdenvNoCC;
}).aggregate;
# iOS bindings - simulator + host macOS only (fast dev/CI builds)
ios-libs-fast =
(
(pkgs.callPackage ./nix/package/ios.nix {
stdenv = pkgs.stdenvNoCC;
}).mkIos
[
"aarch64-apple-darwin"
"aarch64-apple-ios-sim"
]
).aggregate;
ios-xcframeworks =
(pkgs.callPackage ./nix/package/ios.nix {
stdenv = pkgs.stdenvNoCC;
}).release;
ios-xcframeworks-fast =
(pkgs.callPackage ./nix/package/ios.nix {
stdenv = pkgs.stdenvNoCC;
}).devFast;
};
};
};
Expand Down
Loading
Loading