pod install проходит на рабочем Mac, но падает на удалённом Runner: в логе появляется ошибка Ruby, недоступный Specs или отказ в доступе к частному Pod.

Быстрое решение: сначала зафиксируйте, какой Ruby, Bundler и CocoaPods запускает CI, затем проверяйте сбой по слою — источник Specs, аутентификацию, загрузку зависимости или интеграцию с Xcode. Сохраните Podfile.lock и воспроизведите исходную ошибку; не запускайте pod update и не очищайте кэш наугад.

Это руководство для инженеров, которые сопровождают CI на macOS и сравнивают удалённый Runner с локальной средой.
Оно также пригодится командам с частными Pod и разработчикам, которым важно проверить исправление на том же коммите и с прежними версиями зависимостей.

01

Локальный успех против ошибки 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. Для сбоя подключения нужны актуальные логи и проверка из той же среды, где выполняется задача.

02

Разные 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 и оставить нестабильное окружение на остальных.

03

Ошибка Specs/CDN против ошибки Podfile: проверьте источник и сеть отдельно

Сообщение о том, что спецификация не найдена, не всегда означает, что CocoaPods неправильно разобрал проект. Причина может быть в неверном имени или версии Pod, неверно заданном источнике, отсутствии доступа к репозиторию спецификаций или сетевой ошибке при обращении к удалённой стороне.

Читать лог стоит как последовательность событий. Если есть TLS-ошибка, отказ соединения или тайм-аут, сначала проверяйте сетевой путь Runner и применённые в CI сетевые правила. Если получен HTTP-ответ, определите, кто его вернул: целевой сервис, прокси или другой промежуточный узел. Если сообщение говорит, что подходящая версия не найдена, проверьте объявленные источники, имя зависимости и ограничение версии в Podfile.

Сверьте source в Podfile с фактической схемой проекта. В справочнике по синтаксису Podfile описывается настройка источников и объявление зависимостей. Наличие нужного source в файле ещё не доказывает, что Runner может получить к нему доступ: важны разрешение имени, соединение, TLS и доступность самого репозитория из рабочей среды.

Не подменяйте источник Specs только потому, что одна попытка завершилась ошибкой. Такая замена способна изменить набор доступных спецификаций и затруднить сравнение с локальным результатом. Сначала подтвердите, что сбой воспроизводится из CI, зафиксируйте сообщение и проверьте доступ тем способом, который использует сам шаг установки. Историческая проблема в обсуждении разработчиков — не доказательство того, что соответствующая служба недоступна сейчас.

Отдельно исключите различия конфигурации: локальная машина может иметь дополнительный источник или сохранённое состояние репозитория, которого нет у CI. Сравните объявленные в проекте источники и те, что фактически используются при запуске. Если неисправность исчезает после изменения источника, сохраните исходный лог и зафиксируйте, что именно изменилось; иначе невозможно отличить исправление сетевого доступа от смены набора спецификаций.

04

Доступ к частному Pod против ошибки разрешения версии

Частная зависимость требует двух независимых проверок. Сначала CI должен получить спецификацию, по которой CocoaPods узнаёт Pod и его версии. Затем он должен получить исходный код, указанный этой спецификацией. Успех первой операции не подтверждает доступ ко второй: у них могут быть разные репозитории, адреса и правила доступа.

Начните с конфигурации Spec Repo. Убедитесь, что источник добавлен и Podfile направляет зависимость туда, где команда ожидает её найти. Официальное руководство CocoaPods по частным Pod описывает работу с частными спецификациями и источниками. Сверьте его с текущим способом подключения в проекте, а не переносите команды из старой инструкции без проверки контекста.

Затем проверьте исходный репозиторий зависимости. Уточните, какая учётная запись выполняет задачу, каким механизмом передаются учётные данные и разрешено ли этой учётной записи читать нужный репозиторий. Если доступ локально основан на ключе разработчика или интерактивной авторизации, CI может не иметь эквивалентных полномочий. Проверьте подключение с тем же способом аутентификации, который задан в задаче.

В CI используйте контролируемые секреты и подставляйте их через переменные окружения или предусмотренный системой механизм хранения секретов. В примерах ниже должны фигурировать только условные имена:

export PRIVATE_REPO_TOKEN="${CI_PRIVATE_REPO_TOKEN}"

Не выводите значение переменной, не встраивайте токен в URL, который может попасть в лог, и не печатайте конфигурацию с раскрытыми ключами. Проверяйте наличие секрета без вывода его содержимого. Если аутентификация не проходит, сопоставьте идентификатор учётной записи и предоставленные ей права с фактически запущенным процессом.

Диагностика должна закончиться ясным ответом: не удалось получить спецификацию, не прошла авторизация к исходникам или CocoaPods не нашёл подходящую версию. Формулировка «частный Pod не работает» смешивает эти причины и не подсказывает, какое разрешение или адрес нужно исправить.

05

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-среда.

06

Успешная установка против готовой сборки: проверяйте этапы отдельно

Завершившаяся без ошибки команда установки не означает, что приложение успешно соберётся. Установка 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.

07

Частые вопросы

Почему локальная установка 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 и требования к инструментам.