pod install проходит на рабочем Mac, но падает на удалённом Runner: в логе появляется ошибка Ruby, недоступный Specs или отказ в доступе к частному Pod.
Быстрое решение: сначала зафиксируйте, какой Ruby, Bundler и CocoaPods запускает CI, затем проверяйте сбой по слою — источник Specs, аутентификацию, загрузку зависимости или интеграцию с Xcode. Сохраните Podfile.lock и воспроизведите исходную ошибку; не запускайте pod update и не очищайте кэш наугад.
Это руководство для инженеров, которые сопровождают CI на macOS и сравнивают удалённый Runner с локальной средой.
Оно также пригодится командам с частными Pod и разработчикам, которым важно проверить исправление на том же коммите и с прежними версиями зависимостей.
Локальный успех против ошибки CI: сначала установите границу сбоя
Если одна команда ведёт себя по-разному на рабочем Mac и в удалённой среде, не начинайте с изменения Podfile. Сначала определите этап, на котором прекращается выполнение. CocoaPods может завершиться до разбора зависимостей, во время поиска спецификаций, при скачивании исходников или уже после установки — на интеграции с проектом Xcode. Это разные неисправности, и у них разные доказательства.
Сопоставляйте запуск на одном коммите и с одним и тем же содержимым Podfile и Podfile.lock. В локальном терминале и в логе CI найдите первую ошибку, а не только последнюю строку с ненулевым кодом возврата. Сохраните полный вывод команды: заключительное сообщение часто лишь сообщает, что установка прервана, но не объясняет причину.
Зафиксируйте контекст запуска. Важно знать, какая учётная запись выполняет задачу, из какой рабочей директории запускается команда и какой именно исполняемый файл pod найден через PATH. Интерактивный SSH-сеанс может загружать профиль оболочки, а CI — запускать неинтерактивную оболочку с другим набором переменных. Поэтому проверка «в терминале команда есть» сама по себе не доказывает, что CI вызывает ту же команду.
Полезно добавить диагностические команды непосредственно в шаг перед установкой:
pwd
whoami
printf '%s\n' "$PATH"
which ruby
ruby --version
which bundle
bundle --version
which pod
pod --version
Сверяйте вывод с локальной машиной и сохраняйте его как артефакт или в доступном для команды логе. Если which pod указывает на неожиданную глобальную установку, дальнейшая диагностика сети пока преждевременна. Если все пути ожидаемые, переходите к конкретной ошибке разбора или загрузки.
В официальном руководстве CocoaPods по поиску неисправностей описаны типовые сообщения и способы проверки, но оно не подтверждает состояние сети конкретного Runner. Для сбоя подключения нужны актуальные логи и проверка из той же среды, где выполняется задача.
Разные Ruby и pod против зафиксированного окружения проекта
Сбой может возникать ещё до обращения к Specs. Например, CI находит системный Ruby, а локальная машина использует другой. Или в интерактивной оболочке доступен pod, установленный глобально, тогда как шаг сборки запускает другую версию. Проверяйте реальные пути и версии внутри задания, а не предполагайте, что настройки профиля пользователя применились автоматически.
Документация CocoaPods указывает установку через RubyGems и отмечает Ruby 2.6 как минимальную версию в своём руководстве по установке; сверяйте это требование с актуальной инструкцией CocoaPods по установке. Наличие подходящей версии Ruby ещё не гарантирует правильное окружение: важны источник установки, выбранная версия Bundler и то, какой pod получает команда оболочки.
Если проект использует Gemfile и Gemfile.lock, устанавливайте Ruby-зависимости проекта через Bundler. Затем запускайте CocoaPods в этом контексте:
bundle install
bundle exec pod install
bundle exec ограничивает запуск зависимостями, определёнными для текущего проекта, вместо случайного использования глобальной команды. Условия такого способа работы изложены в руководстве CocoaPods по Gemfile и Bundler.
Проверьте, что CI запускает команды из каталога, где лежат файлы проекта. Если Gemfile находится в корне приложения, но задача запускается из подкаталога, Bundler может не найти ожидаемую конфигурацию. Аналогично, если одна часть сценария меняет каталог, а следующая использует относительный путь, команда может незаметно работать не с тем проектом.
| Наблюдение в CI | Что проверить | Следующий шаг |
|---|---|---|
ruby или bundle не найден |
PATH, учётную запись, способ запуска оболочки |
Исправить окружение до вызова CocoaPods |
pod найден, но команда не соответствует проекту |
Путь к pod, наличие Gemfile и Gemfile.lock |
Установить зависимости проекта и вызвать bundle exec pod install |
| Ошибка появляется при чтении Podfile | Рабочую директорию, синтаксис и объявленные источники | Проверить файл проекта и порядок source |
| Запрос завершился сетевой или TLS-ошибкой | Доступ Runner к адресу, прокси и TLS-цепочку | Повторить проверку подключения из той же задачи |
| Частный Pod не найден или не скачивается | Spec Repo, исходный репозиторий, учётные данные | Проверить раздельно чтение спецификации и исходников |
Не исправляйте расхождение установкой ещё одной глобальной копии CocoaPods, пока не проверили, какая из них вызывается. Это может замаскировать ошибку на одном Runner и оставить нестабильное окружение на остальных.
Ошибка Specs/CDN против ошибки Podfile: проверьте источник и сеть отдельно
Сообщение о том, что спецификация не найдена, не всегда означает, что CocoaPods неправильно разобрал проект. Причина может быть в неверном имени или версии Pod, неверно заданном источнике, отсутствии доступа к репозиторию спецификаций или сетевой ошибке при обращении к удалённой стороне.
Читать лог стоит как последовательность событий. Если есть TLS-ошибка, отказ соединения или тайм-аут, сначала проверяйте сетевой путь Runner и применённые в CI сетевые правила. Если получен HTTP-ответ, определите, кто его вернул: целевой сервис, прокси или другой промежуточный узел. Если сообщение говорит, что подходящая версия не найдена, проверьте объявленные источники, имя зависимости и ограничение версии в Podfile.
Сверьте source в Podfile с фактической схемой проекта. В справочнике по синтаксису Podfile описывается настройка источников и объявление зависимостей. Наличие нужного source в файле ещё не доказывает, что Runner может получить к нему доступ: важны разрешение имени, соединение, TLS и доступность самого репозитория из рабочей среды.
Не подменяйте источник Specs только потому, что одна попытка завершилась ошибкой. Такая замена способна изменить набор доступных спецификаций и затруднить сравнение с локальным результатом. Сначала подтвердите, что сбой воспроизводится из CI, зафиксируйте сообщение и проверьте доступ тем способом, который использует сам шаг установки. Историческая проблема в обсуждении разработчиков — не доказательство того, что соответствующая служба недоступна сейчас.
Отдельно исключите различия конфигурации: локальная машина может иметь дополнительный источник или сохранённое состояние репозитория, которого нет у CI. Сравните объявленные в проекте источники и те, что фактически используются при запуске. Если неисправность исчезает после изменения источника, сохраните исходный лог и зафиксируйте, что именно изменилось; иначе невозможно отличить исправление сетевого доступа от смены набора спецификаций.
Доступ к частному Pod против ошибки разрешения версии
Частная зависимость требует двух независимых проверок. Сначала CI должен получить спецификацию, по которой CocoaPods узнаёт Pod и его версии. Затем он должен получить исходный код, указанный этой спецификацией. Успех первой операции не подтверждает доступ ко второй: у них могут быть разные репозитории, адреса и правила доступа.
Начните с конфигурации Spec Repo. Убедитесь, что источник добавлен и Podfile направляет зависимость туда, где команда ожидает её найти. Официальное руководство CocoaPods по частным Pod описывает работу с частными спецификациями и источниками. Сверьте его с текущим способом подключения в проекте, а не переносите команды из старой инструкции без проверки контекста.
Затем проверьте исходный репозиторий зависимости. Уточните, какая учётная запись выполняет задачу, каким механизмом передаются учётные данные и разрешено ли этой учётной записи читать нужный репозиторий. Если доступ локально основан на ключе разработчика или интерактивной авторизации, CI может не иметь эквивалентных полномочий. Проверьте подключение с тем же способом аутентификации, который задан в задаче.
В CI используйте контролируемые секреты и подставляйте их через переменные окружения или предусмотренный системой механизм хранения секретов. В примерах ниже должны фигурировать только условные имена:
export PRIVATE_REPO_TOKEN="${CI_PRIVATE_REPO_TOKEN}"
Не выводите значение переменной, не встраивайте токен в URL, который может попасть в лог, и не печатайте конфигурацию с раскрытыми ключами. Проверяйте наличие секрета без вывода его содержимого. Если аутентификация не проходит, сопоставьте идентификатор учётной записи и предоставленные ей права с фактически запущенным процессом.
Диагностика должна закончиться ясным ответом: не удалось получить спецификацию, не прошла авторизация к исходникам или CocoaPods не нашёл подходящую версию. Формулировка «частный Pod не работает» смешивает эти причины и не подсказывает, какое разрешение или адрес нужно исправить.
Podfile.lock против обновления всех зависимостей
Когда установка проходит на локальном компьютере, но версии зависимостей в CI отличаются, первым делом проверьте Podfile.lock. Убедитесь, что файл включён в систему контроля версий и что задача выполняется с тем файлом, который относится к проверяемому коммиту. При ошибке рабочей директории CI может читать другой Podfile или вообще работать с неполной копией проекта.
Разница между командами принципиальна. pod install устанавливает зависимости с учётом зафиксированного результата в Podfile.lock; pod update предназначена для обновления зависимостей. CocoaPods отдельно описывает эту разницу в руководстве pod install и pod update. Поэтому замена команды установки на обновление не является нейтральным способом «починить CI»: она меняет условия воспроизведения и может затронуть больше зависимостей, чем исходно упало.
Сначала проверьте команду в CI и путь к lock-файлу. Зафиксируйте git status и убедитесь, что установка не переписывает Podfile.lock из-за отличающегося рабочего каталога или состояния репозитория. Если задача намеренно обновляет зависимость, оформите это отдельно: измените нужную запись, рассмотрите diff lock-файла и проверьте сборку на подготовленном изменении. Не объединяйте обновление версий с диагностикой неизвестной ошибки.
Учитывайте и локальные источники расхождения. Разработчик мог получить изменённый lock-файл, не включённый в коммит, или локальная среда могла содержать спецификацию, которой нет в конфигурации Runner. Сравните версию файлов из одного коммита, а не просто повторите локальную команду. Для воспроизводимой проверки важны и одинаковый Podfile.lock, и одинаковая команда, и согласованная Ruby-среда.
Успешная установка против готовой сборки: проверяйте этапы отдельно
Завершившаяся без ошибки команда установки не означает, что приложение успешно соберётся. Установка CocoaPods может получить зависимости и сформировать проект Pods, а последующий шаг Xcode — завершиться ошибкой компиляции, подписи или настройки рабочего пространства. Не называйте такой результат сбоем установки, если лог подтверждает, что CocoaPods завершил свою работу.
Проверьте, какой файл открывает следующий шаг. Для проекта с CocoaPods обычно требуется работать с созданным workspace, а не считать исходный проект эквивалентной заменой. Сверьте настройки схемы, пути к файлам и аргументы команды сборки. Если ошибка появляется только на этапе Xcode, сохраните её отдельно от вывода pod install; так станет ясно, требуется ли исправить интеграцию зависимостей или собственно параметры сборки.
После исправления повторите исходный сценарий на том же коммите, с тем же Podfile.lock и тем же способом вызова Bundler. Запишите, что изменилось: путь к Ruby, права доступа, сеть, источник или рабочая директория. Затем подтвердите прохождение установки и отдельно — последующего шага сборки. Если результат снова отрицательный, вернитесь к первому конкретному сообщению ошибки. Пересоздание Runner не заменяет диагностику, если не установлено, что проблема связана с состоянием узла.
Перед завершением разбора отметьте выполненные проверки:
- [ ] Сохранены полный лог и первый конкретный текст ошибки.
- [ ] На рабочем Mac и в CI проверен один и тот же коммит.
- [ ] Внутри задачи записаны
PATH, Ruby, Bundler и путь кpod. - [ ] Проверены рабочая директория и фактические пути к
PodfileиPodfile.lock. - [ ] Ошибка отнесена к запуску команды, Specs, аутентификации, загрузке исходников или интеграции Xcode.
- [ ] Доступ к частным спецификациям и исходникам проверен раздельно.
- [ ]
pod updateне использовался как замена воспроизведению ошибки. - [ ] После исправления повторены установка и последующая сборка на исходном коммите.
Если проверки завершились без результата, приложите лог команды, версии и пути инструментов, состояние lock-файла и точный этап сбоя. Не добавляйте секреты и содержимое токенов. По такому набору фактов другой инженер сможет продолжить разбор, не гадая, какую среду запускал CI.
Частые вопросы
Почему локальная установка CocoaPods проходит, а удалённая завершается ошибкой?
Чаще всего отличается не проект, а контекст запуска: CI может использовать другой Ruby или pod, другую рабочую директорию либо учётную запись без доступа к частным репозиториям. Сравните один коммит и полные логи, затем проверьте пути инструментов прямо внутри задания. Сначала определите этап отказа, и только после этого меняйте конфигурацию.
Как выбрать правильный Ruby и команду pod в удалённом CI?
Снимите версии и пути Ruby, RubyGems, Bundler и CocoaPods непосредственно в шаге CI. Если зависимости Ruby проекта закреплены в Gemfile и Gemfile.lock, установите их через Bundler и запускайте установку командой bundle exec pod install. Это помогает не зависеть от случайно выбранной глобальной команды, но не исправляет неверную рабочую директорию или сетевой отказ.
Как понять, что Specs/CDN недоступен, а не ошибочно настроен источник?
Не делайте вывод только по сообщению «Pod не найден». TLS и ошибки соединения требуют проверки сетевого пути, HTTP-ответ — установления его источника, а отсутствие подходящей версии — проверки имени, версии и источников в Podfile. Сопоставьте конфигурацию проекта с фактической сетевой доступностью из Runner; единичная ошибка не подтверждает общий отказ CDN.
Какие права нужны CI для частного Pod?
Проверьте отдельно чтение репозитория спецификаций и репозитория исходного кода зависимости: доступ к одному не гарантирует доступа к другому. Установите, под какой учётной записью работает задача, как ей передаются учётные данные и разрешено ли чтение нужных репозиториев. Секреты храните как контролируемые CI-переменные, не раскрывайте их в логах и тестируйте доступ с полномочиями Runner.
Если проектная конфигурация подтверждена, а нестабильность связана с отсутствием постоянно доступной macOS-среды, сопоставьте стоимость и обслуживание текущего Runner с удалённым Mac. Собственный узел требует управления системой и доступами; локальная машина зависит от её доступности и может расходиться с CI по окружению. При оценке собственного оборудования можно отдельно рассмотреть вариант Mac mini M4 и учесть затраты на обслуживание. Удалённая аренда тоже не универсальна: для постоянно высокой нагрузки или необходимости физических интерфейсов собственный Mac может быть уместнее. Если же среда нужна на период сборок и проверки, изучите варианты удалённого Mac в MESHLAUNCH и оцените их под свой график CI и требования к инструментам.