krz/domain-dig

an ios app for DNS & SSL analysis

clone: git clone https://gitbay.org/krz/domain-dig.git

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