krz/domain-dig
an ios app for DNS & SSL analysis
clone: git clone https://gitbay.org/krz/domain-dig.git
v4.9.0: .github/workflows/build.yml · raw
1name: Build
2
3# Compile gate and accessibility audit for the GitHub mirror. builds.sr.ht is the
4# primary remote for this project but has no macOS images, so xcodebuild cannot
5# run there; this job builds and tests on a GitHub-hosted macOS runner instead.
6#
7# This runs `xcodebuild test`, which also compiles the app, the widget, and the
8# share extension (the DomainDig scheme's build action pulls both in as
9# dependencies). The test target is DomainDigUITests — an accessibility audit
10# suite; see DomainDigUITests/AccessibilityAuditHarness.swift.
11#
12# WHAT THIS JOB IS FOR, given the audit also runs locally:
13# a clean checkout of the merge result. A local hook runs against the working
14# tree and therefore cannot catch a file that was never committed — the failure
15# mode that matters most here, since DomainDig.xcodeproj is hand-edited and uses
16# file-system-synchronized groups where a whole missing folder still builds fine
17# locally. This job is the only place that check exists; sr.ht cannot run it.
18#
19# DELIBERATELY ONE JOB, NEWEST RUNTIME ONLY. Audit coverage is not nested across
20# OS versions, so the oldest supported OS genuinely needs its own run — but the
21# macos-26 image ships only iOS 26.x runtimes, so CI *cannot* provide it. Asking
22# for two jobs here bought two near-identical 26.x runs at double the macOS
23# minutes. Floor coverage lives in Scripts/audit-a11y.sh, run from a machine that
24# actually has an 18.x runtime installed, and is wired to the pre-push hook in
25# .githooks/. See Docs/ACCESSIBILITY.md for the split.
26#
27# The audit REPORTS but does not FAIL by default. It surfaces violations that
28# exist today, so gating on it would block every unrelated PR until the
29# accessibility pass in issue #21 completes. Findings land in the job log and in
30# the uploaded .xcresult bundle, tagged [report] or [FAIL]. Enforcement is a
31# committed constant: widen `AccessibilityAuditHarness.enforcedAuditTypes` as
32# each phase clears a category. (Env vars were tried first — neither a plain
33# xcodebuild env var nor a TEST_RUNNER_-prefixed build setting reaches the UI
34# test process.)
35#
36# pull_request only, plus manual dispatch. GitHub builds the merge result (PR
37# merged into main), so a green PR validates exactly what will land on main.
38# Note: this repo currently also pushes directly to main for releases, and those
39# pushes are NOT gated here — add a `push: { branches: [main] }` trigger below if
40# you want direct-to-main commits covered too.
41#
42# paths-ignore skips prose-only changes. Both globs are single-star, so they
43# match the repo root and Docs/ but nothing deeper — a .md that ever lands inside
44# a source directory still builds.
45on:
46 pull_request:
47 paths-ignore: ['*.md', 'Docs/*.md']
48 workflow_dispatch:
49
50# The job only reads code; drop the default read-write GITHUB_TOKEN scope.
51permissions:
52 contents: read
53
54concurrency:
55 group: build-${{ github.ref }}
56 cancel-in-progress: true
57
58jobs:
59 test:
60 name: xcodebuild test
61 # macos-latest still points at macOS 15, which lacks the iOS 26+ SDK this app
62 # is built against.
63 runs-on: macos-26
64
65 steps:
66 - uses: actions/checkout@v7
67
68 - name: Show toolchain
69 run: |
70 xcodebuild -version
71 swift --version
72
73 - name: Select simulator
74 id: sim
75 run: |
76 set -euo pipefail
77
78 # Newest available iPhone runtime. No deployment-target filtering is
79 # needed for "newest" — it is always at or above the floor. The
80 # previous selector took the first iPhone from ANY runtime, which on a
81 # machine with an older runtime installed could pick a simulator below
82 # the deployment target, where the app cannot install.
83 selected=$(xcrun simctl list devices available --json \
84 | jq -c '
85 [ .devices | to_entries[]
86 | (.key | capture("SimRuntime\\.iOS-(?<maj>[0-9]+)-(?<min>[0-9]+)$")) as $v
87 | (($v.maj | tonumber) * 1000 + ($v.min | tonumber)) as $rank
88 | .value[]
89 | select(.name | startswith("iPhone"))
90 | { rank: $rank, udid: .udid, name: .name, os: "\($v.maj).\($v.min)" }
91 ]
92 | sort_by(.rank, .name)
93 | last
94 ')
95
96 if [ -z "$selected" ] || [ "$selected" = "null" ]; then
97 echo "::error::No iPhone simulator available on this image"
98 xcrun simctl list devices available >&2
99 exit 1
100 fi
101
102 label=$(echo "$selected" | jq -r '"\(.name) (iOS \(.os))"')
103 echo "Selected $label"
104 echo "udid=$(echo "$selected" | jq -r .udid)" >> "$GITHUB_OUTPUT"
105 echo "label=$label" >> "$GITHUB_OUTPUT"
106
107 - name: Test on ${{ steps.sim.outputs.label }}
108 run: |
109 set -o pipefail
110 xcodebuild test \
111 -project DomainDig.xcodeproj \
112 -scheme DomainDig \
113 -destination "id=${{ steps.sim.outputs.udid }}" \
114 -resultBundlePath TestResults.xcresult \
115 CODE_SIGNING_ALLOWED=NO
116
117 - name: Upload results
118 # Always upload: on success the bundle carries the accessibility burndown
119 # list, which is the reason this suite exists.
120 if: always()
121 uses: actions/upload-artifact@v4
122 with:
123 name: test-results
124 path: TestResults.xcresult
125 retention-days: 7