DevOps и аудит 27 апреля 2026

2026-04-27 Несколько сборок Xcode.app, xcode-select и DEVELOPER_DIR на задачу в CI-матрице на арендованном облачном Mac (HK / JP / KR / SG / US)

MacXCode Engineering Team 27 апреля 2026 ~20 мин чтения

Релиз- и платформенные команды, арендующие один Mac mini M4 с Apple Silicon в Сингапуре для App Store и держащие быструю полосу для экспериментов, часто ставят более одного Xcode.app. Сценарий отказа предсказуем: зелёная задача в 10:00 на Xcode 16.3, потому что кто-то выполнил xcode-select -s в support-shell; архив в 10:15 тихо берёт 16.2; позже App Store Connect отклоняет бинарник из-за будущего минимума SDK. Этот runbook 2026-04-27 — операционный слой над общим советом «закрепите тулчейн»: когда xcode-select, когда только DEVELOPER_DIR, как называть бандлы в /Applications, как привязать метки self-hosted runner к явным путям. В паре с OpenClaw LLM 429/503 и бюджетами повторов. Контекст: Swift 6 строгая конкурентность CI, покрытие и ворота xcresult, изоляция DerivedData.

Почему второй Xcode на арендованном хосте в 2026 — норма

Ритм релизов Apple не совпадает со спринтами. Продукт на iOS 18 может оставаться на стабильной 16.2, пока другая команда проверяет 16.3 для предстоящих требований минимального SDK. Физические узлы дороги; общий облачный Mac в Токио или Сеуле несёт оба неделями. Абстракция: одна аренда железа, много логических тулчейнов с явным выбором на каждую CI-задачу. Без этого «мультиматрица» в YAML — театр.

  • Окна комплаенса — требования Apple по минимальному SDK и сборке Xcode двигаются по календарю; второй Xcode нужен, чтобы доказать релиз-кандидат параллельно с прод-пином.
  • Тест против релиза — интеграционные ветки собираются с более новым SDK для предупреждений об устаревании; линия App Store держит документированные пути кодподписи и export с export и App Store Connect API.
  • Экономика фермы — удваивать аренду на каждый минор Xcode редко окупается; дисциплинированный DEVELOPER_DIR укладывает NVMe и unified memory в коридор 24–32 ГБ при аккуратном расписании.

Эксплуатация должна без тикета ответить, какой бандл использовала какая задача; иначе после алерта по диску вырежут runtime и потеряют воспроизводимость.

xcode-select или DEVELOPER_DIR

Оба указывают на Xcode.app/Contents/Developer, но радиус действия разный: xcode-select — удобство для человека; DEVELOPER_DIRконтракт процесса в автоматизации.

Управление Охват Типично Риск
xcode-select -s … Вся пользовательская сессия, часть GUI при следующем запуске Ad-hoc SSH, VNC, ручной архив Две параллельные CI на одном пользователе — побеждает последний switch; гонки за symlinks Developer.
Export DEVELOPER_DIR Только дочерние процессы этой оболочки GitHub Actions, Buildkite, cron Забыли export в launchd, унаследовали старый PATH.
Абсолютные пути к xcodebuild Отдельные вызовы Диагностика недоверенного env Хрупко к апгрейдам; после проверки предпочитайте DEVELOPER_DIR.
Политика: CI на общих хостах никогда не вызывает inline sudo xcode-select. Глобальный дефолт — только в окне обслуживания с тикетом и логом xcodebuild -version.

Файловая система: активный тулчейн виден в ls /Applications

Имена на долгие апгрейды

Сразу после распаковки .xip переименуйте в Xcode-16-2-0.app и т.д. Пробелы в имени бандла законны, но неудобны в shell; дефисная semver совпадает с тем, как вы будете вводить DEVELOPER_DIR с телефона по SSH. Сохраняйте суффикс .app; не симлинкуйте только Developer без пары PlistDTXcode влияет на dSYM и атрибуцию крэшей.

du -sh /Applications/Xcode-*.app — сигнал ёмкости: обычно 12–20 ГБ до симуляторов, крупные iOS-major платформы ещё 8–20 ГБ. На пулах 1 ТБочистка CI: удалять устаревшие runtime только после 10 рабочих дней нулевой нагрузки на строку матрицы.

Метки CI: один runner, два DEVELOPER_DIR

Будь то метки GitHub Actions, очереди Buildkite или внутренний аналог nomad, инвариант один: метка вроде xcode-16-2 должна отображаться в один набор env, экспортированный до xcodebuild. Таблица в README мешает менеджеру релизов «попробовать 16-3 в проде» на неверном узле.

Метка DEVELOPER_DIR Потребители
xcode-stable /Applications/Xcode-16-2-0.app/Contents/Developer App Store, TestFlight, hotfix, LTS
xcode-next /Applications/Xcode-16-3-0.app/Contents/Developer Dep-Warn, пилот Swift 6, нотаризация

Наследование окружения у self-hosted runner на macOS отличается для runsvc.sh и интерактивного ssh. Кладите DEVELOPER_DIR в точную обёртку runner, не в личный ~/.zshrc — иначе keychain и подпись всплывают только в одной полосе.

Восемь шагов

  1. Распаковать .xip с уникальным именем; shasum -a 256 в тикете.
  2. sudo xcodebuild -license accept, если политика позволяет.
  3. Минимальные платформы через xcodebuild -download… под матрицу.
  4. Скрипт вроде /usr/local/bin/mxcode-16-2: только export и xcodebuild -version в stdout; коммит в infra-репозиторий.
  5. Сопоставить метки оркестратора; перезапустить золотой симуляторный тест.
  6. Сверить подпись: оптимизация подписи, тот же SHA-1 дистрибуции.
  7. ci-toolchain.txt рядом с IPA; как coverage + junit.
  8. Снимать тулчейн только при нуле открытых тикетов на метку; давление диска — отдельный runbook через статью про диск.

export DEVELOPER_DIR="/Applications/Xcode-16-2-0.app/Contents/Developer" /usr/bin/xcodebuild -version

Ловушки и защита в App Store

Логируйте на каждую сборку: полный xcodebuild -version с Build version, echo $DEVELOPER_DIR после фильтра env, хеш exportOptions. Для notarytool тот же DEVELOPER_DIR, что и у компиляции.

Дрейф симулятора: строки -destination в headless-тестах пересматривать после каждого добавления/удаления runtime.

FAQ

Вопрос Ответ 2026
Общий DerivedData? Нет в проде: см. статью про DerivedData.
Только CI — можно глобальный xcode-select? Редко «только CI»: люди заходят по SSH для репро. В CI — DEVELOPER_DIR; комфортный переключатель в справке.

Почему Mac mini M4 в HK / JP / KR / SG / US

Две полные линии Xcode нагружают память и I/O; компилятор, индексация и кэши Metal делят unified memory. Виртуализированные фермы скрывают NUMA. Арендованный Mac mini M4 в регионе делает расчёт DEVELOPER_DIR честным. При перегрузке очереди лучше второй узел в регионе через цены MacXCode, чем гнать параллелизм на одном узле 24 ГБ. С OpenClaw на той же машине свяжите 429/503 и повторы.

Документируйте внутреннему чату, какие метки CI считаются «LTS» и какие «next», и кто уполномочен менять соответствие путей DEVELOPER_DIR—без владельца таблица в README превращается в устаревшую легенду за один квартал. Регулярно прогоняйте контрольную сборку на каждой метке после обновления платформы симулятора: молчаливый дрейф -destination стоил многим командам больше времени, чем сам апгрейд Xcode.

Второй тулчейн — туда, где тестировщики

1–2 ТБ · Apple Silicon M4 · SSH и опционально VNC