mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-24 23:25:19 +00:00
The unpinned setup-swift action installs Swift 6.1, which refuses the
SDK on runner images that have rolled to Xcode 26.5 ("this SDK is not
supported by the compiler"). Jobs passed or failed depending on which
image they landed on. The Xcode-bundled toolchain always matches the
image's SDK, and matches local development. Cache keys now include the
toolchain version so artifacts from one compiler are never restored
into builds with another.
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
148 lines
6.2 KiB
YAML
148 lines
6.2 KiB
YAML
name: Build & Test
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
pull_request:
|
|
|
|
jobs:
|
|
test:
|
|
name: Run Swift Tests (${{ matrix.name }})
|
|
runs-on: macos-latest
|
|
# A hung test must fail fast, not hold a runner for GitHub's 360-minute
|
|
# default (observed: intermittent app-suite hangs starving the queue).
|
|
timeout-minutes: 15
|
|
|
|
strategy:
|
|
fail-fast: false # Don't cancel other matrix jobs when one fails
|
|
matrix:
|
|
include:
|
|
- name: app
|
|
path: .
|
|
- name: BitLogger
|
|
path: localPackages/BitLogger
|
|
- name: BitFoundation
|
|
path: localPackages/BitFoundation
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v5
|
|
|
|
# Use the Xcode-bundled Swift toolchain: it always matches the SDK on
|
|
# the runner image. A standalone swift.org toolchain (setup-swift) broke
|
|
# whenever the image's Xcode moved ahead of it ("this SDK is not
|
|
# supported by the compiler").
|
|
- name: Note toolchain version (cache key)
|
|
id: swift-version
|
|
run: echo "version=$(swift --version 2>/dev/null | head -1 | shasum | cut -c1-12)" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Cache build artifacts
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: ${{ matrix.path }}/.build
|
|
key: ${{ runner.os }}-${{ steps.swift-version.outputs.version }}-${{ matrix.name }}-${{ hashFiles(format('{0}/**/*.swift', matrix.path), format('{0}/**/Package.resolved', matrix.path)) }}
|
|
restore-keys: |
|
|
${{ runner.os }}-${{ steps.swift-version.outputs.version }}-${{ matrix.name }}-${{ hashFiles(format('{0}/**/Package.resolved', matrix.path)) }}
|
|
${{ runner.os }}-${{ steps.swift-version.outputs.version }}-${{ matrix.name }}-
|
|
|
|
- name: Build tests
|
|
# Built separately so the hang watchdog below times only test
|
|
# execution: a cold-cache coverage build on a slow runner can
|
|
# legitimately take several minutes, and is already bounded by the
|
|
# 15-minute job timeout.
|
|
run: swift build --build-tests --enable-code-coverage --package-path ${{ matrix.path }}
|
|
|
|
- name: Run Tests
|
|
# Perf benchmarks are excluded here and run in their own serial step
|
|
# below: measuring while parallel test processes contend for cores
|
|
# produces noisy numbers, and the XCTest measure machinery has hung
|
|
# intermittently under parallel workers on loaded runners. Excluded
|
|
# via --skip (not just the env guard): every app run since the
|
|
# baselines landed timed out at the 15-minute job limit with the
|
|
# baseline tests dispatched into the parallel phase.
|
|
#
|
|
# The watchdog samples any still-running test processes after 5
|
|
# minutes (the suite passes in seconds when healthy; the build is
|
|
# done by this step) and kills the run, so a hang fails fast with
|
|
# stacks in the log instead of a silent timeout.
|
|
env:
|
|
BITCHAT_SKIP_PERF_BASELINES: "1"
|
|
run: |
|
|
swift test --skip-build --parallel --quiet --enable-code-coverage \
|
|
--skip PerformanceBaselineTests \
|
|
--package-path ${{ matrix.path }} &
|
|
test_pid=$!
|
|
(
|
|
sleep 300
|
|
if kill -0 "$test_pid" 2>/dev/null; then
|
|
echo "::group::Tests still running after 5 minutes — sampling before kill"
|
|
for pid in $(pgrep -if 'swiftpm-testing|xctest|PackageTests' || true); do
|
|
echo "--- sample of pid $pid ---"
|
|
sample "$pid" 5 2>/dev/null || true
|
|
done
|
|
echo "::endgroup::"
|
|
pkill -KILL -P "$test_pid" 2>/dev/null || true
|
|
kill -KILL "$test_pid" 2>/dev/null || true
|
|
fi
|
|
) &
|
|
watchdog_pid=$!
|
|
wait "$test_pid" && status=0 || status=$?
|
|
kill "$watchdog_pid" 2>/dev/null || true
|
|
exit "$status"
|
|
|
|
# Benchmarks run serially on an otherwise idle runner for stable
|
|
# numbers; BITCHAT_PERF_LOG captures the PERF[...] lines for the gate.
|
|
- name: Run performance benchmarks (serial)
|
|
if: matrix.name == 'app'
|
|
timeout-minutes: 6
|
|
env:
|
|
BITCHAT_PERF_LOG: ${{ github.workspace }}/perf-output.log
|
|
run: swift test --quiet --filter PerformanceBaselineTests
|
|
|
|
# Order-of-magnitude performance regression gate. Floors are deliberately
|
|
# generous (see bitchatTests/Performance/perf-floors.json) so this
|
|
# catches algorithmic regressions, never runner variance.
|
|
- name: Performance floor gate
|
|
if: matrix.name == 'app'
|
|
run: ./scripts/check-perf-floors.sh perf-output.log
|
|
|
|
# Informational only: surfaces per-file and total line coverage in the
|
|
# job log so coverage trends are visible on every PR. No thresholds —
|
|
# this must never be the reason a build goes red.
|
|
- name: Coverage summary
|
|
run: |
|
|
BIN_PATH=$(swift build --show-bin-path --package-path ${{ matrix.path }})
|
|
PROF="$BIN_PATH/codecov/default.profdata"
|
|
XCTEST=$(find "$BIN_PATH" -maxdepth 1 -name '*.xctest' | head -1)
|
|
BINARY="$XCTEST/Contents/MacOS/$(basename "$XCTEST" .xctest)"
|
|
if [ -f "$PROF" ] && [ -f "$BINARY" ]; then
|
|
xcrun llvm-cov report "$BINARY" -instr-profile "$PROF" \
|
|
-ignore-filename-regex='(Tests|\.build|checkouts|Mocks|_PreviewHelpers)' || true
|
|
else
|
|
echo "No coverage data found; skipping summary."
|
|
fi
|
|
|
|
# SPM tests above only compile the macOS slice; this job covers the
|
|
# iOS-conditional code paths (UIKit, CoreBluetooth restoration, etc.).
|
|
ios-build:
|
|
name: Build iOS app (simulator)
|
|
runs-on: macos-latest
|
|
timeout-minutes: 15
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v5
|
|
|
|
- name: Build iOS (simulator, no signing)
|
|
# arm64 only: the vendored arti.xcframework has no x86_64 simulator slice.
|
|
run: |
|
|
set -o pipefail
|
|
xcodebuild -project bitchat.xcodeproj \
|
|
-scheme "bitchat (iOS)" \
|
|
-sdk iphonesimulator \
|
|
-destination 'generic/platform=iOS Simulator' \
|
|
ARCHS=arm64 \
|
|
CODE_SIGNING_ALLOWED=NO \
|
|
build
|