В ходе моей текущей работы мне приходилось автоматизировать рабочие места для создания приложений Android. Этот пост посвящен описанию болевых точек, с которыми я столкнулся, чтобы вы, читатели, не тратили свое время впустую, если вы собираетесь это сделать.
Среда выглядит следующим образом:
- Кукольный для автоматизации инфраструктуры
- Дженкинс для CI- сервера
- Проект Android
- Файл сборки Gradle для его сборки
- Робоэлектрик как основной каркас тестирования
Кукольный и Дженкинс
Моя отправная точка была действительно здоровой. Коллеги уже автоматизировали установку сервера Jenkins, необходимые пакеты, включая Java, а также предоставили повторно используемые классы Puppet для создания заданий. Задания Jenkins полагаются на один config.xml
файл, который представляет собой сборку из разных разделов. Каждый раздел обрабатывается специальным шаблоном. В этот момент я подумал, что создание простой работы в Gradle будет сродни прогулке в парке, что займет максимум несколько дней, и что вскоре мне будет поручено другое задание.
Первый шаг был достаточно легким: просто обновите существующий манифест Puppet, чтобы добавить плагин Gradle в Jenkins.
Обертка Gradle
Постоянные читатели этого блога знают мое мнение о Gradle. Тем не менее, я признаю, что гарантированная сборка, которая работает независимо от версии установленного инструмента, — это то, чего не хватает Maven — и оно должно быть. Для этого Gradle предоставляет так называемый механизм-оболочку через JAR, сценарий оболочки и файл свойств, последний из которых содержит URL-адрес для распространения Gradle ZIP. Все три должны быть сохранены в SCM .
Это было началом моих неприятностей. Необходимость загрузки в корпоративной среде означает прохождение и аутентификацию на прокси. Самый простой вариант — установить все в конфигурации задания … включая учетные данные прокси. Однако идти по этому пути не очень разумно с точки зрения безопасности, поскольку любой, имеющий доступ к интерфейсу Jenkins или файловой системе, сможет прочитать эти учетные данные. Есть необходимость в другом варианте.
У клиента уже есть работающий репозиторий Nexus с настроенным прокси. Было очень просто загрузить нужный дистрибутив Gradle и обновить свойства gradle.properties, чтобы они указывали на него.
Android SDK
Android SDK — это просто ZIP. Я использовал ту же тактику: скачай и загрузи в Nexus. На этом этапе существующий сценарий Puppet позаботился о его загрузке, распаковке и установке необходимых разрешений.
Этот шаг — начало реальных проблем, как бы то ни было. Разработчики Android знают, что Android SDK — всего лишь менеджер: нужно вручную проверить нужные платформы и инструменты, чтобы загрузить их в локальную файловую систему. Простой шаг для разработчика Android на его компьютере — это кошмар для автоматизации, хотя есть командная строка, эквивалентная установке / обновлению пакетов через SDK (с --no-ui
параметром). Для полного описания, пожалуйста, проверьте эту ссылку .
Инженеры Google не предоставляют 2 важных параметра:
- Учетные данные прокси — логин / пароль
- Принятие лицензионных соглашений
В Интернете много неработающих ответов, наиболее привлекательным из которых является файл конфигурации. Я не нашел ни одного из них, чтобы работать. Однако я нашел креативное решение с помощью expect
команды. Expect — изящная команда, которая читает стандартный вывод и соответственно вводит стандартный ввод. Хорошая вещь о ожидаемом, что это принимает регулярное выражение. Таким образом, когда он запрашивает прокси-сервер, вы вводите логин, когда он запрашивает пароль, вы делаете то же самое, а когда он запрашивает принятие лицензии, вы набираете «y». Это довольно просто — хотя мне потребовалось много проб и ошибок, чтобы достичь желаемых результатов.
Первоначально я планировал установить все необходимые пакеты Android с Puppet в рамках подготовки сервера. Для стандартных операций, таких как создание файла или установка системного пакета, Puppet может определить, требуется ли подготовка, например, если файл существует, его не нужно создавать, а также, если пакет установлен. В конце Puppet сообщает о каждой операции, которую он выполнил в журнале. Сначала я попытался внедрить этот тип кэширования, рассказав Puppet о том, какие пакеты были созданы во время инициализации, поскольку Android SDK создает одну папку на пакет. Первая проблема заключается в том, что Puppet принимает только одну папку для проверки. Кроме того, для некоторых пакетов информация о версии отсутствует (например, это относится к сервисам Google Play).
Таким образом, у коллеги возникла идея перейти от этого обновления от обеспечения Puppet к предварительному этапу в каждой работе. Это исправляет неидемпотентную проблему. Кроме того, это делает запуск обновления настраиваемым для каждого задания.
Robolectric
На данный момент я думал, что это будет сделано. К сожалению, это было не так, из-за библиотеки — Robolectric.
В то время я не знал о Robolectric , я просто знал, что это тестовая библиотека для Android, которая позволяет запускать тесты без подключенного физического устройства. Пытаясь запустить сборку на Jenkins, я наткнулся на «интересную» проблему: хотя Roboletric предоставляет POM с полным набором зависимостей, MavenDependencyResolver
класс жестко кодирует репозиторий, откуда его можно загрузить.
Единственный предоставленный обходной путь — расширить вышеуказанный класс, чтобы взломать вашу собственную реализацию. Мой использовал хранилище Nexus для предприятий, указанное выше
Загрузить и выпустить задачи
Конец реализации был относительно легким. Не хватало только загрузки артефактов в репозиторий Nexus и тега релиза в SCM.
Чтобы достичь первого, я просто добавил пользовательскую задачу Gradle, чтобы получить настройки Nexus из settings.xml
(предоставленных Puppet). Тогда мне удалось, чтобы upload
задача зависела от этого. Наконец, для каждого варианта выполнения assemble
задачи я добавил выходной файл в набор артефактов для загрузки. Таким образом, следующая команда будет загружать только варианты XXX и YYY независимо от того, какие варианты настроены в файле сборки:
./gradlew assembleXXX assembleYYY upload
Для выпуска, это даже проще: требуется только , что было установить этот Gradle плагин, который добавляет release
задачу, сродни развертывание в Maven.
Вывод
Как бэкэнд-разработчик, я привык к настройке Continuous Integration и был почти уверен, что смогу справиться с процессом Android CI за несколько дней. Я был довольно удивлен отсутствием зрелости экосистемы Android относительно CI. Каждый шаг болезненный, плохо документированный (если вообще) и решения кажутся больше взломами, чем что-либо еще. Если вы хотите пойти по этому пути, вас предупредили … и я желаю вам удачи.