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