# Apple client CI — runs on the self-hosted macOS runner (home-mac-mini-1, host mode; # see scripts/ci/setup-macos-runner.sh). Builds the Rust core into # PunktfunkCore.xcframework, then builds + tests the Swift package. Network-dependent # tests (RemoteFirstLightTests) self-skip without PUNKTFUNK_REMOTE_HOST. # # A second job (`screenshots`) captures the App Store Connect screenshots of the REAL UI # (mac window + iOS/iPad/tvOS Simulators, see clients/apple/tools/screenshots.sh) and attaches # them to the run as a single zip artifact (`punktfunk-appstore-screenshots`). It is isolated # from the build/test job and best-effort, so a capture gap never reds the core signal. name: apple on: push: branches: [main] pull_request: workflow_dispatch: jobs: swift: runs-on: macos-arm64 timeout-minutes: 60 steps: - uses: actions/checkout@v4 - name: Rust toolchain (self-healing on a fresh runner) run: | if ! command -v rustup >/dev/null && [ ! -x "$HOME/.cargo/bin/rustup" ]; then curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ | sh -s -- -y --no-modify-path --profile minimal fi RUSTUP="$(command -v rustup || echo "$HOME/.cargo/bin/rustup")" dirname "$RUSTUP" >> "$GITHUB_PATH" "$RUSTUP" target add aarch64-apple-darwin x86_64-apple-darwin # `punktfunk-core` now decodes Opus in-core for the Apple client (surround), pulling # `audiopus_sys`, which builds a vendored static libopus via CMake when pkg-config can't find a # system Opus — so the xcframework is self-contained (no runtime libopus.dylib on end-user Macs). # CMake must be on PATH; install it self-healing on a fresh runner. - name: CMake (for the vendored libopus audiopus_sys builds) run: | # Runner steps run with `bash --noprofile --norc`, so Homebrew's bin dir isn't on PATH — # locate brew explicitly, install cmake if missing, and export its bin dir to GITHUB_PATH so # the xcframework build step (audiopus_sys → vendored libopus) finds `cmake`. for B in /opt/homebrew/bin/brew /usr/local/bin/brew; do [ -x "$B" ] && BREW="$B" && break; done if [ -z "$BREW" ]; then echo "::error::Homebrew not found on the runner"; exit 1; fi BREW_BIN="$(dirname "$BREW")"; export PATH="$BREW_BIN:$PATH" command -v cmake >/dev/null || "$BREW" install cmake echo "$BREW_BIN" >> "$GITHUB_PATH" # Homebrew's CMake 4 dropped compatibility with the vendored libopus's pre-3.5 # `cmake_minimum_required`; treat 3.5 as the policy minimum (the cmake crate's child cmake # inherits this from the env during the xcframework build). echo "CMAKE_POLICY_VERSION_MINIMUM=3.5" >> "$GITHUB_ENV" - name: Build PunktfunkCore.xcframework run: bash scripts/build-xcframework.sh - name: Build (PunktfunkKit + PunktfunkClient app shell) working-directory: clients/apple run: swift build - name: Test (unit + real-codec round trip; remote tests self-skip) working-directory: clients/apple run: swift test # App Store screenshots of the real UI, zipped and attached to the run as a build artifact. # Skipped on PRs (cost); runs on main pushes + manual dispatch. Needs the build/test job green # first, and is a separate job so a capture hiccup can never red the core signal. # # Scope = the two REQUIRED iOS sizes (iPhone 6.9" + iPad 13"), captured on the Simulator # (`simctl io screenshot`, no Screen Recording grant needed). macOS and tvOS are deliberately # NOT in CI: the self-hosted runner is headless (no window-server session), so the mac window # capture can't run there; tvOS needs the Tier-3 build-std slice. Generate those two locally on # a GUI Mac with `clients/apple/tools/screenshots.sh macos tvos`. screenshots: needs: swift if: gitea.event_name != 'pull_request' runs-on: macos-arm64 timeout-minutes: 75 steps: - uses: actions/checkout@v4 - name: Rust toolchain + iOS Simulator targets run: | if ! command -v rustup >/dev/null && [ ! -x "$HOME/.cargo/bin/rustup" ]; then curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ | sh -s -- -y --no-modify-path --profile minimal fi RUSTUP="$(command -v rustup || echo "$HOME/.cargo/bin/rustup")" dirname "$RUSTUP" >> "$GITHUB_PATH" "$RUSTUP" target add aarch64-apple-darwin x86_64-apple-darwin \ aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios # See the swift job: audiopus_sys (via the in-core Opus decode) builds vendored libopus with CMake. - name: CMake (for the vendored libopus audiopus_sys builds) run: | # Runner steps run with `bash --noprofile --norc`, so Homebrew's bin dir isn't on PATH — # locate brew explicitly, install cmake if missing, and export its bin dir to GITHUB_PATH so # the xcframework build step (audiopus_sys → vendored libopus) finds `cmake`. for B in /opt/homebrew/bin/brew /usr/local/bin/brew; do [ -x "$B" ] && BREW="$B" && break; done if [ -z "$BREW" ]; then echo "::error::Homebrew not found on the runner"; exit 1; fi BREW_BIN="$(dirname "$BREW")"; export PATH="$BREW_BIN:$PATH" command -v cmake >/dev/null || "$BREW" install cmake echo "$BREW_BIN" >> "$GITHUB_PATH" # Homebrew's CMake 4 dropped compatibility with the vendored libopus's pre-3.5 # `cmake_minimum_required`; treat 3.5 as the policy minimum (the cmake crate's child cmake # inherits this from the env during the xcframework build). echo "CMAKE_POLICY_VERSION_MINIMUM=3.5" >> "$GITHUB_ENV" - name: Build PunktfunkCore.xcframework (mac + iOS slices) run: BUILD_IOS=1 bash scripts/build-xcframework.sh - name: Capture screenshots (iPhone 6.9" + iPad 13"; auto-creates the Simulators) working-directory: clients/apple env: SETTLE: "8" # Simulators settle slower than a local run run: | # Independent invocations: one platform failing skips it, not the other. bash tools/screenshots.sh ios || echo "::warning::iOS (iPhone 6.9\") screenshots skipped" bash tools/screenshots.sh ipad || echo "::warning::iPad 13\" screenshots skipped" echo "Produced:"; ls -la screenshots || true - name: Upload screenshots (zip artifact) if: always() # v3, not v4: Gitea's artifact backend identifies as GHES, which @actions/artifact v2+ # (upload-artifact@v4) refuses. v3 uses the older API Gitea supports; download is still a zip. uses: actions/upload-artifact@v3 with: name: punktfunk-appstore-screenshots path: clients/apple/screenshots if-no-files-found: warn retention-days: 30