После нескольких недель непрерывных сборок на облачном Mac проблемы с окружением чаще всего возникают не из-за отсутствия инструментов, а потому, что разные люди устанавливали их в разное время. Одной задаче требуется jq, другой скрипт рассчитывает на наличие swiftlint, а после разовых сеансов диагностики остаются дополнительные формулы. Когда работу принимает новая машина, одного клонирования репозитория недостаточно, чтобы восстановить системные зависимости. Brewfile хорошо отвечает на вопрос «какие инструменты нужны», но не является файлом точной фиксации версий. Надёжнее управлять декларациями, сведениями о версиях и процедурой очистки отдельно.
Сначала проведите аудит машины, а не экспортируйте всё подряд
Сначала проверьте путь к Homebrew и текущую архитектуру, чтобы скрипты не продолжали использовать другой, устаревший путь.
command -v brew
brew --prefix
uname -m
brew doctor
Затем отдельно просмотрите формулы верхнего уровня, все установленные версии и фоновые службы:
brew leaves
brew list --formula --versions
brew services list
Вывод brew leaves лучше подходит в качестве отправной точки для декларации, чем полный список, поскольку в основном содержит явно установленные инструменты верхнего уровня. Полный список версий следует архивировать как подтверждение конфигурации сборки, а не переносить в Brewfile без изменений.
Не запускайте обновление или очистку, пока на машине выполняются сборочные задачи. Сначала остановите распределение заданий, а затем убедитесь, что компиляторы, базы данных и вспомогательные службы не используются никакими процессами.
Если машина эксплуатируется уже давно, сначала создайте файл-кандидат, а затем проверьте его построчно:
mkdir -p ci/homebrew
brew bundle dump --force --file=ci/homebrew/Brewfile.candidate
git diff -- ci/homebrew/Brewfile.candidate
В файл-кандидат могут попасть личные инструменты, временные средства диагностики или графические приложения, не относящиеся к проекту. В итоговый список следует включать только то, что действительно необходимо для сборки и устранения неполадок.
Используйте Brewfile как декларацию требований
Базовый список для непрерывной сборки iOS может оставаться совсем коротким:
brew "git"
brew "jq"
brew "swiftlint"
brew "xcbeautify"
Добавьте файл в репозиторий как ci/homebrew/Brewfile и при установке явно указывайте путь:
brew bundle check --file=ci/homebrew/Brewfile
brew bundle install --file=ci/homebrew/Brewfile --no-upgrade
Команду check удобно выполнять при запуске задачи. Она лишь проверяет соответствие окружения декларации; не следует автоматически запускать полное обновление при каждой сборке. Команда install --no-upgrade устанавливает отсутствующие инструменты, снижая вероятность того, что обычная сборка неожиданно изменит существующее окружение.
Разделяйте Brewfile по назначению
Если один облачный Mac VMKeep выполняет несколько типов работ, рекомендуется разделить список на базовый и проектный. Например, в базовый слой можно включить только Git, средства обработки JSON и инструменты для работы с журналами, а линтеры и вспомогательные средства публикации оставить на уровне проекта. Порядок установки должен быть постоянным: сначала базовый слой, затем проектный.
Не используйте один постоянно разрастающийся глобальный Brewfile для всех репозиториев. С ним при каждой очистке будет трудно оценить область влияния, а новые проекты могут ошибочно принять исторически оставшиеся инструменты за собственные обязательные зависимости.
Записывайте версии и контекст выполнения отдельно
Обычно Brewfile не фиксирует точные версии стандартных формул. Одинаковые списки на двух машинах ещё не доказывают, что они дадут одинаковый результат. После каждого изменения окружения сохраняйте снимок фактически установленных версий:
{
date -u
sw_vers
xcodebuild -version
brew --version
brew list --formula --versions
} > ci/homebrew/toolchain.snapshot.txt
Снимок версий можно сохранять как артефакт конвейера либо добавлять в эксплуатационную документацию после проверенного обновления окружения. При обнаружении различий сначала сравните версии Xcode, macOS, Homebrew и прямых зависимостей, затем проверьте файлы фиксации зависимостей проекта. Не начинайте с удаления всех кешей.
Чётко определяйте границы версий
Команда brew pin предотвращает только локальное обновление на текущей машине и не гарантирует, что на новой машине будет доступна та же историческая версия. Поэтому её можно использовать как краткосрочную защиту, но она не заменяет зафиксированный образ машины, проектный менеджер версий или проверенные бинарные артефакты.
Для инструментов, непосредственно влияющих на результат сборки, скрипт должен при запуске проверять допустимый диапазон версий и завершаться с явной ошибкой при несоответствии. Для инструментов, которые лишь улучшают оформление журналов, можно разрешить более широкий диапазон, чтобы некритичные различия не приводили к остановке сборки.
Выполняйте безопасную очистку после предварительного просмотра и в период простоя
Перед фактической очисткой просмотрите элементы, отсутствующие в Brewfile:
brew bundle cleanup --file=ci/homebrew/Brewfile
Эта команда используется только для проверки вывода. Убедившись, что перечисленные формулы не нужны другим проектам, LaunchAgent или фоновым службам, выполните:
brew bundle cleanup --file=ci/homebrew/Brewfile --force
brew autoremove
brew cleanup
На общей машине требуется особая осторожность: отсутствие формулы в Brewfile текущего репозитория не означает, что её не использует другая задача. Более надёжная граница — отдельный физический узел для каждого типа долгосрочной рабочей нагрузки либо как минимум отдельные учётные записи исполнителей, рабочие каталоги и списки зависимостей.
После очистки снова запустите brew bundle check, а затем выполните минимальную цепочку приёмочной проверки: выведите версии инструментов, разберите конфигурацию проекта и завершите одну сборку без загрузки артефактов. Изменение окружения можно считать завершённым только после успешного прохождения всех трёх этапов.
Превратите изменения окружения в проверяемые события
Стабильный процесс не должен позволять сборочным скриптам самовольно выполнять brew install. При добавлении нового инструмента коммит должен одновременно включать изменение Brewfile, описание назначения, снимок версий и способ отката. Обновления следует выполнять в отдельное окно обслуживания: сначала проверить репрезентативные проекты и только после этого возобновить распределение задач.
Повседневную проверку рекомендуется свести к четырём пунктам:
- Успешно ли выполняется
brew bundle check; - Соответствуют ли версии Xcode и ключевых формул ожидаемым;
- Есть ли в Brewfile непроверенные изменения;
- Работают ли постоянно какие-либо необъявленные фоновые службы.
Ценность Brewfile не в автоматической установке всех возможных инструментов, а в превращении системных зависимостей из «сложившегося состояния машины» в декларацию внутри репозитория, которую можно обсуждать, сравнивать и откатывать. В сочетании со снимками версий и осторожной очисткой это превращает проблемы окружения облачного Mac из предмета догадок в подтверждённые различия конфигурации.
Часто задаваемые вопросы
Фиксирует ли Brewfile точные версии пакетов Homebrew?
Нет. Brewfile описывает набор необходимых инструментов, но обычные formula обновляются вместе с репозиторием. Для точного воспроизведения нужны снимок версий, закреплённый образ машины или отдельный менеджер версий.
Безопасно ли сразу запускать brew bundle cleanup --force на общей машине?
Нет. Сначала запустите команду без --force и изучите список удаления. Убедитесь, что инструменты не нужны другим заданиям, а очистку выполняйте в период простоя.
Продолжите проверку этого рабочего процесса на облачном Mac
Выберите подходящий объём памяти, хранилище, узел и срок аренды из трёх конфигураций Apple Silicon.