forked from permissionlesstech/bitchat
-
Notifications
You must be signed in to change notification settings - Fork 0
194 lines (178 loc) · 8.26 KB
/
Copy pathswift-tests.yml
File metadata and controls
194 lines (178 loc) · 8.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
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).
# The long steps carry tighter individual bounds (5-minute test watchdog,
# 6-minute benchmark step, 10-minute floor gate that may re-run the
# benchmarks up to twice on a noisy runner); this is the backstop.
timeout-minutes: 25
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. If a metric
# still lands below floor (a saturated runner can dip one), the script
# re-runs the benchmarks — appending to the same log and keeping each
# benchmark's best value per metric — so noise clears on retry while a
# real regression fails every attempt. Floors are never lowered by this.
- name: Performance floor gate
if: matrix.name == 'app'
timeout-minutes: 10
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 do not link the shipping app targets. This job covers the
# iOS-conditional paths and both universal Release link configurations.
ios-build:
name: Build Release apps (universal)
runs-on: macos-latest
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Build iOS (simulator, no signing)
# Build both simulator architectures so CI validates every vendored
# Arti simulator slice and the configuration that ships.
run: |
set -o pipefail
xcodebuild -project bitchat.xcodeproj \
-scheme "bitchat (iOS)" \
-configuration Release \
-sdk iphonesimulator \
-destination 'generic/platform=iOS Simulator' \
ARCHS='arm64 x86_64' \
ONLY_ACTIVE_ARCH=NO \
CODE_SIGNING_ALLOWED=NO \
build
- name: Build macOS (universal, no signing)
run: |
set -o pipefail
xcodebuild -project bitchat.xcodeproj \
-scheme "bitchat (macOS)" \
-configuration Release \
-destination 'generic/platform=macOS' \
ARCHS='arm64 x86_64' \
ONLY_ACTIVE_ARCH=NO \
CODE_SIGNING_ALLOWED=NO \
build
# Advisory only: SwiftLint reports style violations without ever failing the
# build. Runs in a pinned container (no Xcode plugin, no pbxproj changes) so
# it can never break the documented xcodebuild path or block a merge.
lint:
name: SwiftLint (advisory)
runs-on: ubuntu-latest
timeout-minutes: 15
# This job runs a third-party container image, so give it the least
# privilege we can: a read-only token, and no credentials left in the
# checkout for the container to find.
permissions:
contents: read
container:
# Tag for readability, digest for immutability (tags can be repointed).
# Bump both together, deliberately — never a floating tag.
image: ghcr.io/realm/swiftlint:0.65.0@sha256:a482729f4b58741875af1566f23397f3f6db300372756fc31606d0a4527fab9e
continue-on-error: true
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
- name: Run SwiftLint
run: swiftlint lint --reporter github-actions-logging