2026 эксклюзивный удалённый Mac iOS macOS CI xcodebuild timing XCLogParser SSH headless регрессия сборки
CI/CD и автоматизация 2026-05-07

2026: эксклюзивный удалённый Mac iOS/macOS CI — xcodebuild -showBuildTimingSummary и XCLogParser на headless-узле по SSH: регрессия времени сборки, таблица сравнения, пороговые скрипты и шаги пайплайна + FAQ

На выделенном удалённом Mac, к которому вы ходите только по SSH, всё равно нужен честный ответ на вопрос: «этот PR замедлил компиляцию?» У Apple есть два взаимодополняющих рычага: xcodebuild -showBuildTimingSummary для грубой сводки по сборке и XCLogParser для структурированных срезов из .xcactivitylog / xcresult. Ниже — готовая к копированию таблица сравнения, шаблон пороговой проверки и шаги пайплайна для headless-сессий — после того как вы выстроили дисциплину checkout из Git: blobless, мелкий клон, sparse-checkout и LFS на эксклюзивном удалённом Mac CI и политику DerivedData из Xcode 26: удалённый Mac CI, xcodebuild и Derived Data по SSH.

1. TL;DR — что подключить в первую очередь

  • Всегда добавляйте -showBuildTimingSummary к рабочему вызову xcodebuild, если важна wall-time; это недорогой текст в конце лога.
  • Парсите ту же сборку через XCLogParser, когда нужны таргеты, шаги компиляции Swift или фазы линковки для дашбордов — особенно после обновлений Xcode, когда формат сводки сдвигается.
  • Храните подписанный baseline JSON на ключ (класс ветки, build ID Xcode, схема, destination); на шумных headless-хостах сравнивайте p95, а не один прогон.
  • Гейтите merge небольшим скриптом: падаем только если регрессия превышает бюджет и «скучная» статистика (например, два подряд зелёных прогона до приглушения алертов).

2. Почему SSH headless делает тайминг шумнее (и как это приручить)

Выделенное железо быстрое, но узлы Mac CI делят тепловой бюджет, фрагментацию APFS и службы Simulator с вчерашними джобами. Без baseline прирост компиляции +12% выглядит как «просто вторник». Сначала наблюдаемость, потом пороги: зафиксируйте DEVELOPER_DIR, логируйте sysctl hw.model и xcodebuild -version, записывайте свободное место на диске раз на джобу.

3. Инструмент A — -showBuildTimingSummary

В конце успешной сборки Xcode печатает агрегированные «корзины» времени (компиляция, линковка, codegen и т.д. — подписи зависят от тулчейна). Это дёшевый дымовой сигнал: один grep-дружелюбный блок на вызов, без лишних зависимостей.

  • Плюсы: нулевая установка, достаточно стабильно для «взорвалась ли линковка?», работает в обычном SSH-логе.
  • Минусы: не JSON; сложнее списать вину на один SPM-таргет; парсер ломается, если Apple переименует строки.

Пример формы (флаги зависят от вашей схемы):

xcodebuild \
  -scheme YourApp \
  -destination 'platform=iOS Simulator,name=iPhone 16' \
  -derivedDataPath "$CI_DERIVED_DATA" \
  -resultBundlePath "$CI_RESULT_BUNDLE.xcresult" \
  build \
  -showBuildTimingSummary

4. Инструмент B — XCLogParser

XCLogParser читает activity-логи Xcode и отдаёт JSON, HTML и другие сводки. В CI JSON-строки в объектном хранилище обычно лучше гигантских HTML-деревьев.

  • Установка: закрепите бинарник релиза или соберите из исходников в образе runner; кэшируйте артефакт в пути, завязанном на версию тулчейна.
  • Типичная команда: xclogparser parse --file path/to/LogStoreManifest.plist --reporter json или укажите на бандл xcresult рядом со сборкой — выберите одну конвенцию и не смешивайте пути между джобами.
  • Плюсы: структурированные таргеты и шаги для Grafana / BigQuery; удобно diff-ить, если снимаете хэши медленных файлов.
  • Минусы: ещё одна цепочка поставки; крупные апдейты Xcode могут потребовать обновления парсера.

5. Таблица сравнения: для чего какой сигнал

Измерение -showBuildTimingSummary XCLogParser
Стоимость настройки на чистом runner Нет (только Xcode) Установка + закрепление версии
Гранулярность Корзины по всей сборке Таргеты / команды / заметки
Стабильность между dot-релизами Xcode Текст может «плыть» Парсер должен следовать за Apple
Лучший детектор регрессии для Обрывов по линковке / codegen Какой таргет съел бюджет
Артефакты для хранения stdout CI + опционально junit JSON + компактный xcresult

6. Шаблон порогового скрипта (bash-форма, CI-агностично)

Держите политику в данных, а не в глазах инженера. Храните baseline.json с ключом по отпечатку тулчейна. Скрипт должен: (1) извлечь суммарные секунды компиляции из JSON XCLogParser или распарсить блок summary; (2) загрузить baseline; (3) посчитать дельту %; (4) упасть только если дельта > порога и детекторы холодного старта (диск, троттлинг) зелёные.

# Псевдологика — подставьте имена полей под вашу версию reporter XCLogParser
TOTAL_NEW=$(jq '.compileCommandDuration // 0' metrics.json)
TOTAL_BASE=$(jq '.compileCommandDuration // 0' baseline.json)
DELTA=$(python3 - <<PY
new, base = float("$TOTAL_NEW"), float("$TOTAL_BASE")
print((new - base) / base * 100 if base else 0.0)
PY
)
test "$(printf '%.0f' "$DELTA")" -lt 15  # пример: упасть, если компиляция +15%

Публикуйте цифры в summary шага (GitHub Actions $GITHUB_STEP_SUMMARY, отчёты metrics в GitLab и т.д.), чтобы продукт видел ту же правду, что и платформа. См. также CocoaPods и SPM: кэш, изоляция и xcodebuild по SSH на выделенном Mac CI — там же про конкурентный доступ к кэшам, что напрямую бьёт по времени сборки.

7. Шаги пайплайна (happy path)

  1. Нормализуйте окружение: фиксированный DEVELOPER_DIR, неинтерактивная оболочка, задокументированные LANG / LC_ALL.
  2. Один писатель DerivedData на каталог джобы; не переиспользуйте грязные деревья между параллельными джобами.
  3. Соберите один раз, проанализируйте дважды: тот же xcresult кормит отчётам XCTest и извлечению тайминга XCLogParser.
  4. Артефакты: сырой текст summary, JSON парсера и урезанный хвост xcodebuild.log (~200 строк) только при падении — экономьте egress.
  5. Политика обновления baseline: ночной main после зелёных health-check пересобирает baseline; feature-ветки сравниваются с последним промотированным baseline.
  6. Маршрутизация алертов: владельцам сквада по CODEOWNERS, если JSON показал медленные таргеты.

8. FAQ

В1: После обновления Xcode текст summary сдвинулся — сломался grep.

Считайте разбор summary best-effort. Канонической метрикой сделайте XCLogParser (или xcresulttool, где уместно), а grep по summary оставьте для человекочитаемых CI-логов.

В2: Загрузка Simulator доминирует в wall time — мы меряем не то?

Разделите метрики: compile/link vs оркестрация тестов. Либо грейте симуляторы в шаге «тёплого пула», либо принимайте, что гейты регрессии пока только на фазе компиляции, пока boot не стабилизирован.

В3: Можно ли гонять XCLogParser по SSH без копирования всего DerivedData?

Укажите инструменту на бандл xcresult или конкретный manifest activity-лога внутри него — rsync только этих путей, а не многогигабайтные workspace.

В4: Команды «играют» метрикой, отключая предупреждения.

Сочетайте тайминг-гейты с бюджетом предупреждений и проверками размера бинарника — «финансовому» CI нужно больше одного рычага.

Почему Mac mini по-прежнему выигрывает для чувствительного к таймингу Apple CI

Регрессия времени сборки имеет смысл только при повторяемом сигнале. Узлы Mac mini на Apple Silicon дают предсказуемую полосу unified memory для Swift-компиляции, нативный macOS-стек для Simulator и подписи и настолько низкое энергопотребление в простое (~4 Вт у M4-класса), что держать «тёплый» baseline-runner онлайн не похоже на счёт за ЦОД. macOS объединяет Gatekeeper, SIP и FileVault так, что риск «случайного» вредоноса ниже, чем при постоянной пересборке обобщённых Windows-образов — это важно, когда долгоживущие runner хранят идентичности для подписи. Та же машина, на которой xcodebuild стабильно работает по SSH, — лучшее место для постобработки XCLogParser без кросс-ОС сюрпризов с путями.

Если нужно железо, из-за которого таблица выше становится скучной, а не шумной, Mac mini M4 — сильная опора на 2026 год: откройте главную ниже, сравните тарифы и приложите этот runbook к платформенному ADR.

Рекомендуемые тарифы

M4.S Хит продаж

10-Core 16GB 256GB
$105.9
/ в месяц от
Получить сейчас