На дворе 2023 год, и вот вы и ваша команда наконец решили отказаться от CI-пайплайна, которым вы пользовались, в пользу автономного Jenkins CI. Замечательно! В этой статье мы не будем разглагольствовать о плюсах и минусах использования одних CI-систем в сравнении с другими, а сразу сосредоточимся на том, как настроить полностью функциональную среду Jenkins CI для iOS. Хоть вы, вероятно, и сможете самостоятельно настроить и запустить среду Jenkins всего за пару часов, и, возможно, у вас, скорее всего, получится запускать в ней сборку для iOS, в этом деле существует множество мелких подводных камней, которые со временем усугубляются и делают быструю незатейливую реализацию довольно нестабильной. Лично мне пришлось потратить несколько недель на эксперименты в попытках настроить все правильно, чтобы больше не сталкиваться с целым рядом загадочных ошибок и “время от времени” возникающих проблем. Что удивительно, я не нашел никакого исчерпывающего руководства по “лучшим практикам Jenkins”, поэтому решил написать собственное, в котором я поделюсь с вами знаниями, усвоенными на собственном горьком опыте. Описывать шаги, необходимые для получения машины с macOS, я не буду. В этой статье предполагается, что у вас уже есть какая-нибудь машина под macOS (да, без macOS никак), и вы уже установили Jenkins на своем сервере. Если Jenkins еще не установлен, то вам поможет это официальное руководство (этот шаг достаточно прост): https://www.jenkins.io/doc/book/installing/macos Кроме того, в этой статье мы будем использовать Homebrew, rbenv, xcodes, и Bundler. Я не буду вдаваться в подробности, почему я выбрал именно эти программные решения (возможно, в следующем посте 😉), но не стесняйтесь спрашивать меня, если вам очень интересно! Прежде всего, нам нужно установить Homebrew. Вам нужно следовать инструкциям, указанным здесь — тут все довольно просто. Следующие настройки должны облегчить вам запуск и работу, а также обеспечить необходимые меры безопасности для fastlane. Добавьте это в свой файл ~/.zshrc: Следует отметить, что в зависимости от используемого вами поставщика облачных услуг (например, AWS, Azure и т.д.) файл ~/.zshrc может уже содержать что-нибудь. В таком случае, чтобы избежать проблем, просто добавьте приведенный выше фрагмент в конец файла. После обновления вашего ~/.zshrc файл, подгрузите его, чтобы применить изменения (или просто завершите текущий SSH-сеанс и запустите новый): Затем, чтобы упростить себе настройку зависимостей, вы можете скопировать в свой терминал следующий фрагмент Я написал целую статью, посвященную этому шагу. На этом этапе мы прервемся, пока вы не разберетесь с учетными данными git на вашей машине с Jenkins, следуя инструкциям из статьи, приведенной ниже: Аутентификация с помощью GitHub в Jenkins CI через GitHub App Из-з того, как Jenkins выбирает, какие ветки билдить, при использовании различных стратегий для “обнаружения” ветвей (т.е. “Исключить ветки, которые также помечены как PR” или “Только ветки, которые также помечены как PR”) возникает своего рода состояние гонки. Это приводит к таким проблемам, как застревание PR (пулл-реквестов) в состоянии постоянного ожидания (“pending”), что блокирует их мерж. По этой причине нам понадобятся 2 конвейера: Один будет билдить все ветки, которые не должны быть отмечены как PR, например. main, master, development, staging, production (в зависимости от того, как вы их называете). Второй будет билдить все остальные ветки, которые могут стать PR. Мне потребовалось очень много времени, чтобы понять это, поскольку примерно в 5-10% случаев PR застревали и не могли быть замержены, потому что попадали в какое-то странное пограничное состояние. Это было единственное полностью рабочее решение, которое я нашел для этой проблемы. Чтобы создать новую джобу перейдите на https://<your_jenkins_domain.com>/view/all/newJob. Из доступных вариантов выберите Multibranch Pipeline: Мне нравится добавлять тип проекта (в данном случае Multibranch Pipeline) к имени конвейера, чтобы я сразу мог понять, какова его структура, на основе одного его имени. Таким образом, в данном случае я бы назвал его как-то вроде protected-branch-multibranch-pipeline 😊. В рамках подготовки этой джобы вам необходимо уделить внимание следующим ключевым параметрам: Учетные данные GitHub: выберите учетные данные приложения GitHub (GitHub App Credentials), которые вы добавили в разделе “Учетные данные git” выше. Добавить новое правило “Discover branches” и выбрать “All branches”. Добавьте в этом разделе фильтр “Filter by name (with regular expression)”, с текстом “master” или “(master|staging|production)” Периодический запуск: ☑️ Интервал: 1 минута. Честно говоря, это пережиток того времени, когда Jenkins не всегда обнаруживал сборки, которые было необходимо запустить. Но это было в самом начале моего приключения, еще до того, как я начал использовать GitHub App, поэтому я не до конца уверен, что от этой настройки можно отказаться. Может и можно. Все остальные настройки, не упомянутые выше, вам следует установить как того требует ваш проект или вкус. Посетите https://<your_jenkins_domain.com>/view/all/newJob еще раз, чтобы создать новую джобу, и снова выберите Multibranch Pipeline из доступных вариантов. Опять же, я рекомендую называть его как-то похоже на pull-requests-multibranch-pipeline, чтобы вы могли легко идентифицировать его в будущем. Выполните те же шаги, что и выше, за исключением того, что правило поведения, которое вы собираетесь добавить, будет “Discover pull requests from origin”, выбрав стратегию “The current pull request revision“: Вы же не думали, что я пропущу самую важную часть? В приведенных выше шагах при настройке новых джобов вам нужно было указать путь к вашему Jenkinsfile. Способ настройки Jenkins, описанный в этой статье, должен соответствовать определенному способу настройки Jenkinsfile и CI-скриптов, о чем я расскажу вам ниже. Вот шаблон, который вы можете использовать для основного Jenkinsfile, который можно использовать для запуска обоих protected-branch-multibranch-pipeline и pull-requests-multibranch-pipeline. Функция “withCredentials” работает следующим образом: В качестве входных данных здесь выступает Credentials ID, который вы зарегистрировали ранее в своих учетных данных Jenkins. Это дает плагину Jenkins возможность генерировать эфемерные токены (имя пользователя и пароль), которые затем можно использовать для отправки HTTPS-запросов на GitHub. Для вас критически важно понимать, что это HTTPS-аутентификация, а не SSH, поэтому, если у вас есть команды git, использующие SSH в конвейере, вы должны определять, что вы работаете в CI-среде, и переключить их на использование HTTPS. Типичным примером этого в iOS-среде является URL Git, используемый match fastlane. В первый раз, когда мы генерируем такие эфемерные учетные данные, мы предоставляем их в git config credential.helper, чтобы любая операция git (использующая HTTPS) с этого момента (даже на других этапах) смогла выполняться без повторного запроса имени пользователя и пароля. В приведенном выше примере вы можете наблюдать это на втором этапе, где мы вызываем danger (который публикует комментарии на GitHub, поэтому ему нужны учетные данные) — нам не нужно было генерировать для него новые учетные данные. Но в третьем этапе, где нам нужен прямой доступ к переменным окружения учетных данных (а переменные окружения не сохраняются между этапами), мы повторно генерируем учетные данные и таким образом снова устанавливаем значения для переменных окружения. Если вам интересно, вот как вы можете настроить экшн match в вашем Fastfile: Примечание 1: вы должны иметь плагин GitHub Branch Source версии 2.7.1 или выше, чтобы использовать эти API. Эта функция представлена и введена в 2020 году. Примечание 2: как указано в объявлении, полученный вами токен API будет действителен только в течение одного часа. Поэтому не делайте ошибку сохранения его в самом начале конвейера, предполагая, что он будет действителен на всем его протяжении. Прежде чем мы закончим с настройкой Jenkins, нам осталось сделать всего две вещи. Это может произойти, когда ваш конвейер пытается получить доступ к git внутри конвейера (например, при запуске установки пода или получении SPM, и т.д.). Это может быть вызвано тем, что ваша машина запрашивает аутентификацию по паролю из Keychain, но это не отображается в логах Jenkins. К сожалению, единственное решение, которое помогло мне полностью избавиться от этой проблемы, — это войти в систему с доступом к пользовательскому интерфейсу (например, VNC, а не SSH) и кликнуть “Always Allow" во всплывающем окне, запрашивающем разрешение на доступ к “login.keychain”. Вам нужно будет ввести root-пароль компьютера с macOS при появлении этого запроса. Но вам достаточно сделать это всего только один раз, и вы больше никогда не вернетесь к этой проблеме. Существует проблема, которая приводит к сбою сборки с ошибкой: Это происходило примерно в 5-10% сборок, полностью ломая их. Оказывается, учетные данные git Xcode могут конфликтовать с теми, которые мы устанавливаем, и тогда все рушится. Чтобы это исправить, просто следуйте моему ответу на этот вопрос на Stack Overflow: Jenkins Github Authentication иногда сбоит? Вам нужно будет повторять эти шаги каждый раз, когда устанавливается новая версия Xcode. В этом (объективно) длинном руководстве вам был предложен очень самоуверенный способ настройки вашей машины с Jenkins, адаптированный для iOS-среды. Если вы работаете с другими средами, большинство советов, показанных в этой статье, все-равно пригодятся вам, чтобы избежать тех или иных проблемы, например, с Android, React, Flutter, Node и т.д.  Изменятся, вероятно, только ваши зависимости и некоторые детали в примерах, которые я приводил при настройке Jenkinsfile. Когда я только настроил свою первую машину с Jenkins, я получил первую сборку за считанные часы, но это среда была еще далека от той, которая соответствовала бы потребностям команды. Например, GitHub Checks определенно необходим (но его не так просто настроить), и среда должна быть на 100% стабильной, лишенной случайных проблем во время сборки, иначе ваша команда не будет доверять этой системе CI. Другими словами, я сделал 80% работы очень быстро, но оставшиеся 20%, чтобы получить отполированный CI-конвейер, заняли у меня буквально недели. Я надеюсь, что следуя этому руководству, вам не придется беспокоиться об окружающей среде, и вы сможете сосредоточиться на том, что действительно важно: на построении идеального пайплайна для вашего проекта и вашей команды 🤗 В моей следующей статье я расскажу, что вы можете сделать, чтобы сохранить тяжелую работу, которую вы проделали, чтобы настроить свою машину с Jenkins. Проще говоря: как сохранить резервную копию вашего CI! Следите за обновлениями. Перевод материала подготовлен в рамках набора на специализацию iOS Developer. Узнать подробнее.  Редактор