2026-04-27 Несколько сборок Xcode.app, xcode-select и DEVELOPER_DIR на задачу в CI-матрице на арендованном облачном Mac (HK / JP / KR / SG / US)
Релиз- и платформенные команды, арендующие один 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. |
sudo xcode-select. Глобальный дефолт — только в окне обслуживания с тикетом и логом xcodebuild -version.Файловая система: активный тулчейн виден в ls /Applications
Имена на долгие апгрейды
Сразу после распаковки .xip переименуйте в Xcode-16-2-0.app и т.д. Пробелы в имени бандла законны, но неудобны в shell; дефисная semver совпадает с тем, как вы будете вводить DEVELOPER_DIR с телефона по SSH. Сохраняйте суффикс .app; не симлинкуйте только Developer без пары Plist — DTXcode влияет на 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 и подпись всплывают только в одной полосе.
Восемь шагов
- Распаковать
.xipс уникальным именем;shasum -a 256в тикете. sudo xcodebuild -license accept, если политика позволяет.- Минимальные платформы через
xcodebuild -download…под матрицу. - Скрипт вроде
/usr/local/bin/mxcode-16-2: только export иxcodebuild -versionв stdout; коммит в infra-репозиторий. - Сопоставить метки оркестратора; перезапустить золотой симуляторный тест.
- Сверить подпись: оптимизация подписи, тот же SHA-1 дистрибуции.
ci-toolchain.txtрядом с IPA; как coverage + junit.- Снимать тулчейн только при нуле открытых тикетов на метку; давление диска — отдельный 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