Руководства по разработке

Проверка общих схем Xcode для Cloud Mac CI

Проверка общих схем Xcode для Cloud Mac CI

После того как команда клонирует проект на облачный Mac, чаще всего недооценивают не ошибки компиляции, а ситуацию, когда конвейер вообще не находит ожидаемую схему либо одноимённая схема запускает в удалённой среде другие цели. Локальный Xcode читает пользовательские настройки из каталога разработчика, тогда как чистая рабочая область CI видит только файлы из репозитория. Чтобы точка входа сборки оставалась стабильной, Scheme необходимо версионировать и проверять так же, как скрипты и файлы блокировки зависимостей.

Рассматривайте Scheme как интерфейс CI

Scheme, доступная конвейеру, должна определять как минимум четыре аспекта: какие Target собирать, какую Build Configuration использовать, какие Test Bundle запускать и какую конфигурацию применять при Archive. То, что имя отображается в меню Xcode, ещё не означает, что эти сведения добавлены в репозиторий.

Сначала проверьте наличие общих файлов:

find . \( -path "*/xcshareddata/xcschemes/*.xcscheme" \
  -o -path "*/xcuserdata/*/xcschemes/*.xcscheme" \) -print

Scheme в каталоге xcuserdata относится к пользовательским настройкам и не может служить точкой входа CI. Включите Shared в окне Manage Schemes в Xcode, а затем убедитесь, что файл появился по одному из следующих путей:

App.xcodeproj/xcshareddata/xcschemes/App.xcscheme
App.xcworkspace/xcshareddata/xcschemes/App.xcscheme

После этого с помощью git status и git check-ignore -v убедитесь, что файл отслеживается и не исключён по ошибке слишком широким правилом для *.xcuser* или xcshareddata.

«Видно локально» означает лишь, что конфигурация существует в каталоге текущего пользователя. «Доступно в CI» должно подтверждаться результатом команды в каталоге с чистым клоном репозитория.

Зафиксируйте Workspace, Scheme и конфигурацию

Конвейер не должен полагаться на автоматический выбор проекта в Xcode. При наличии CocoaPods, агрегирующих проектов или локальных Package результаты открытия .xcodeproj и .xcworkspace могут различаться. Явно задайте три значения точки входа в переменных CI:

WORKSPACE="App.xcworkspace"
SCHEME="App"
CONFIGURATION="Release"

xcodebuild \
  -workspace "$WORKSPACE" \
  -scheme "$SCHEME" \
  -configuration "$CONFIGURATION" \
  -list

Вывод -list должен содержать ожидаемую Scheme. Затем выполните автоматическую проверку вывода в JSON, чтобы не полагаться только на ручное чтение журналов:

xcodebuild -workspace "$WORKSPACE" -list -json > xcode-list.json
python3 - <<'PY'
import json
data = json.load(open("xcode-list.json"))
schemes = data.get("workspace", {}).get("schemes", [])
if "App" not in schemes:
    raise SystemExit("Required Xcode scheme is missing")
PY

Если в репозитории одновременно поддерживаются точки входа для разработки, предварительной и рабочей среды, их назначение должно быть понятно из названий, например App-Dev, App-Staging и App-Release. Не выбирайте в скрипте первую Scheme по порядку в списке: после добавления зависимости порядок может измениться.

Проверяйте Build, Test и Archive по отдельности

Успешная публикация Scheme решает только проблему видимости, но ещё не подтверждает корректность действий. Рекомендуется разделить проверку на три уровня.

Проверьте итоговые настройки сборки

Сначала экспортируйте окончательные настройки и уделите особое внимание PRODUCT_BUNDLE_IDENTIFIER, CONFIGURATION, SDKROOT, SUPPORTED_PLATFORMS и каталогу артефактов:

xcodebuild \
  -workspace "$WORKSPACE" \
  -scheme "$SCHEME" \
  -configuration "$CONFIGURATION" \
  -showBuildSettings > build-settings.txt

grep -E "PRODUCT_BUNDLE_IDENTIFIER|CONFIGURATION =|SDKROOT|SUPPORTED_PLATFORMS" \
  build-settings.txt

Здесь отображается результат объединения Scheme, настроек проекта и параметров командной строки, поэтому он точнее отражает фактическое выполнение, чем непосредственная проверка project.pbxproj.

Проверьте точку входа тестов

На этапе тестирования сначала соберите тестируемые артефакты, а затем запускайте тесты. Это позволяет отличить неисправную точку входа компиляции от сбоя выполнения тестов:

xcodebuild \
  -workspace "$WORKSPACE" \
  -scheme "$SCHEME" \
  -destination "platform=iOS Simulator,name=iPhone 16" \
  build-for-testing

Имя симулятора должно быть взято из вывода xcrun simctl list devices available на текущей машине. Не фиксируйте устройство, доступное только на личном компьютере. Если команде требуется определённая среда выполнения, одновременно зафиксируйте версию Xcode и целевую версию ОС.

Отдельно проверьте архивирование

Archive может использовать конфигурацию, отличную от Run и Test. Сначала проверьте конфигурацию ArchiveAction в .xcscheme, а затем выполните реальное архивирование в контролируемой задаче:

xcodebuild \
  -workspace "$WORKSPACE" \
  -scheme "$SCHEME" \
  -configuration Release \
  -destination "generic/platform=iOS" \
  -archivePath "$PWD/artifacts/App.xcarchive" \
  archive

Успешный обычный build не заменяет проверку Archive. Проблемы с обработкой ресурсов, этапами скриптов и параметрами архивирования часто проявляются только здесь.

Очистите локальное состояние и выполните повторную проверку

Самая надёжная проверка — не удаление DerivedData, а повторное клонирование в новый каталог. Так одновременно обнаруживаются незафиксированная Scheme, локальные символические ссылки, неотслеживаемые настройки и неявные зависимости:

ROOT="$(mktemp -d)"
git clone --no-local . "$ROOT/repo"
cd "$ROOT/repo"
git submodule update --init --recursive
xcodebuild -workspace App.xcworkspace -scheme App -list

Если проект зависит от этапа генерации, поместите соответствующую команду перед сборкой и проверьте стабильность результата. Не добавляйте в руководство шаг «один раз открыть проект в Xcode»: его невозможно выполнить в полностью автоматическом задании, и он маскирует отсутствие файлов.

Проверка в чистой среде должна охватывать как минимум следующее:

Проверка Критерий успешности
Видимость Scheme xcodebuild -list -json возвращает указанное имя
Принадлежность файла Scheme находится в xcshareddata и отслеживается Git
Конфигурация сборки Результат обработки параметров командной строки соответствует ожиданиям конвейера
Точка входа тестов build-for-testing создаёт тестовые артефакты
Точка входа архивирования Универсальная цель iOS создаёт .xcarchive
Неинтерактивное выполнение Не требуется открывать Xcode или читать личный каталог пользователя

Блокируйте изменения точки входа до слияния

Scheme представляет собой XML-файл, а конфликты слияния в нём часто обрабатывают как обычные текстовые конфликты. В результате имя может сохраниться, а Testable или BuildActionEntry — исчезнуть. Добавьте в запрос на слияние лёгкую проверку: подтвердите наличие общего файла, запретите добавление xcuserdata и выполните xcodebuild -list -json.

Также проверяйте Pre-actions и Post-actions схемы. Если скрипт ссылается на абсолютный путь, интерактивную конфигурацию Shell или инструмент, установленный только на компьютере определённого разработчика, удалённое выполнение всё равно завершится сбоем. Скрипты должны находить файлы через переменные сборки, такие как SRCROOT, и явно завершаться с ошибкой при отсутствии зависимостей.

Итоговый критерий проверки прост: получив репозиторий в пустом каталоге и имея только указанную в документации версию Xcode и команды, система должна перечислить Scheme, обработать настройки, собрать тестовые артефакты и завершить архивирование. Только после этого облачный Mac в G-Mini будет выполнять точку входа, определённую репозиторием, а не воспроизводить случайное состояние компьютера одного из разработчиков.

Часто задаваемые вопросы

Почему локальный Xcode видит схему, а CI на облачном Mac не видит?

Обычно схема хранится в xcuserdata и не попадает в чистый клон. Перенесите её в xcshareddata/xcschemes, добавьте файл в Git и повторите проверку из нового каталога.

Достаточно ли сделать схему Xcode общей для успешного Archive?

Нет. Общая схема становится видимой, но её Release-конфигурация, цель Archive и подготовительные действия могут оставаться неверными. Нужна отдельная проверка и реальное архивирование.

Выделенный физический узел

Облачный Mac для следующей очереди сборки

Сравните две конфигурации M4 и пять узлов и выберите аренду на день, неделю, месяц или квартал в зависимости от рабочего цикла.

Выбрать облачный Mac