Jenkins для Android на чистій системі і без UI

На Хабре вже є схожі статті на тему складання Android додатки з допомогою Jenkins. Ключовими особливостями/доповненнями поточної буде наступне:

  1. Ми встановимо Jenkins на віддалену Linux машину, де відсутня UI.
  2. Ми будемо збирати додаток з приватного репозиторію.
  3. Ми вирішимо проблему складання програми з гілки ім'я якої нам не відомо.
  4. Після складання .apk файлів ми відправимо їх у Fabric і оповістимо тестувальників.
  5. Після відправлення в Fabric ми опублікуємо програму на Google Play.
  6. Захистимо завдання щодо публікації додатки від запуску тестерами.

Установка jenkins
Отже, ви отримали доступ на сервер. UI там відсутня, але це зовсім не проблема.
Для початку давайте встановимо сам jenkins сервер.

$ wget -q -O - https://pkg.jenkins.io/debian/jenkins-ci.org.key | sudo apt-key add -
$ sudo sh -c 'echo deb http://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'
$ sudo apt-get update
$ sudo apt-get install jenkins

Більш докладно про те, що робить встановлення цього пакету можна почитати в офіційній документації.

Після встановлення в теці
/var/lib/jenkins
перебуватиме сам Jenkins, репозиторії проектів та інші необхідні для роботи Jenkins файли. Тепер ви вже можете зайти в Jenkins через браузер і почати налаштування свого CI сервера.

Однак перед цим необхідно встановити все необхідне для складання Android програми.

Установка Android SDK+JAVA
офіційному сайті внизу можна знайти посилання на дистрибутив, який нам потрібен. Звичайно його встановлюють разом з Android Studio, однак у нашому випадку, вона нам не потрібна, тому вибираємо потрібну посилання і завантажуємо інструменти командного рядка(Command Line Tools).

На момент написання статті актуальна версія для Linux була: android-sdk_r24.4.1. Для установки виконуємо команди:

$ wget http://dl.google.com/android/android-sdk_r24.4.1-linux.tgz
$ tar -xvf android-sdk_r24.4.1-linux.tgz

Далі вам необхідно завантажити використовувані у вашому проекті Platform Tools, Build tools і поточне API, для якого ви збираєте додаток. Для цього загляньте в build.gradle файл вашого проекту (на рівень модуля додатка). Наприклад, в моєму проекті цікавить нас частина виглядає наступним чином:

android {
....
compileSdkVersion 25
buildToolsVersion '25.0.0'
....
}

Це наочно показує, які версії нам необхідно завантажити. Для того, щоб ми могли завантажити необхідні нам компоненти, додамо в системні змінні наступні параметри:

$ export ANDROID_HOME=~/android-sdk-linux # Місце де ми зберегли SDK Tools
$ export PATH=$ANDROID_HOME/tools:$PATH
$ export PATH=$ANDROID_HOME/platform-tools:$PATH

Далі в більшості гайдів пропонується просто завантажити всі компоненти за допомогою команди:

$ android update sdk --no-ui --all

Але так як нам шкода даремно витрачати місце на жорсткому диску, ми будемо завантажувати тільки те, що нам потрібно. Виконаємо команду, щоб дізнатися, що саме нам потрібно скачувати:

$ android list sdk --all

Результати виглядають наступним чином:



Тепер ми можемо встановити тільки те, що нам потрібно з допомогою команди:

$ android update sdk --no-ui --all --filter 1,2,163,164,168,169,170,171

Тепер поставимо JAVA з допомогою команди:

$ sudo apt-get install openjdk-8-jdk

Відмінно! Ми поставили все необхідне для складання Jenkins і складання програми. Тепер переходимо до налаштування Jenkins.

Налаштування доступу до приватного репозиторія
Якщо ваш git публічний репозиторій або ви вирішили отримувати доступ до нього за допомогою логіна і пароля, можете пропустити цей блок і перейти до наступного.

Отже, ми вирішили, що ми будемо все робити правильно і доступ до сховища отримувати по SSH. Для цього нам треба згенерувати ключ ssh і покласти його в директорію /var/lib/jenkins/.ssh.

Коли ви встановили jenkins, автоматично згенерований користувач з іменем jenkins на unix-машині. Для того, щоб jenkins міг використовувати ключ, найпростіше буде його згенерувати з-під jenkins користувача.

$ sudo su jenkins -s /bin/bash
$ ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

Після цього буде згенеровано 2 файлу (зі стандартними іменами id_rsa, id_rsa.pub). Файл id_rsa необхідно покласти в папку /var/lib/jenkins/.ssh, після цього необхідно в налаштуваннях github репозиторію додати Deploy Key (вміст файлу id_rsa.pub).

Виглядає це наступним чином:



Далі треба додати URL репозиторію у список відомих. Для цього спробуємо звернутися до дерева і отримати список гілок репозиторію.

$ sudo apt-get install git # Встановлюємо git
$ sudo su jenkins -s /bin/bash
$ git ls-remote -h git@github.com:[your_repo_url]

І погоджуємося на додавання github у список відомих хостів. Якщо у вас немає доступу до файлу id_rsa, значить ви створили його не з-під jenkins користувача, і в цьому випадку вам треба дати доступ jenkins користувачеві на роботу з цим файлом:

$ sudo chmod 700 /var/lib/jenkins/.ssh/id_rsa 

Після виконання цих кроків ми зможемо отримати доступ до нашого приватного сховища для складання Android програми.

Створення завдання для складання програми
Тепер перейдемо до jenkins. За замовчуванням він буде доступний порт 8080. Перейдемо в будь-якому браузері на даний порт. Після першого запуску залогуватися можна буде за допомогою пароля, який знаходиться у файлі /var/lib/jenkins/secrets/initialAdminPassword. Після цього ви потрапляєте в Jenkins панель. Для початку нам потрібно налаштувати шлях до ANDROID_HOME директорії.

Manage Jenkins(Налаштувати Jenkins) → System Configuration(Конфігурація Системи):



Також налаштуємо шляху до JDK, версію Gradle і Git. Для цього вкажіть директорію, де зберігається JAVA, і додайте необхідну для складання версію gradle.

Manage Jenkins(Налаштувати Jenkins) → Global Configuration Tool:





Тепер ми можемо створити першу задачу для складання програми. Виберемо створення завдання з вільною конфігурацією. На вкладці «Управлінням вихідним кодом» вибираємо git. Далі вказуємо url git репозиторію для доступу по ssh. Для першої задачі будемо збирати з гілки майстра. Саме вона за замовчуванням і вказана.

Далі додамо крок складання з допомогою запуску gradle скрипта. Вибираємо gradle версію, додану раніше. На всіх важливих полях знаходяться підказки, навіщо вони потрібні. Наприклад, якщо у вас нестандартна структура проекту, то вам потрібно вказати місце, де знаходить кореневої build.gradle файл проекту і ім'я файлу, якщо воно відрізняється від build.gradle.



Далі заархивируем.апк файли, щоб можна було їх пізніше скачати тестувальникам або кому-небудь іншому. Для цього треба додати послесборочную завдання і вказати формат, файли ми хочемо зберігати. Перший раз при створенні завдання я припускав, що пошук потрібного файлу здійснюється за допомогою формату регулярного виразу, однак виявилося, що для пошуку файлів Jenkins використовує Ant path style. Стандартно пропонується зберігати всі файли з розширенням.апк, проте велика частина з них нам не потрібна, тому будемо зберігати тільки ті, які закінчуються на debug.апк, і release.апк.



Збірка підписаних apk з допомогою build.gradle скрипта
Для публікації програми в Google Play .apk файл повинен бути підписаний спеціальним ключем. Якщо ви підписували з допомогою Android Studio, вказуючи шлях до файлу, то треба навчитися робити це з build.gradle скрипта. Далі ми розглянемо найпростіший приклад і способи, як його можна покращити. Досить покласти ключ під контроль версій, і після цього посилатися на нього з build скрипта. Ось приклад, як це можна реалізувати.

android {
signingConfigs {
release {
keyAlias 'KEY_ALIAS'
keyPassword 'KEY_PASSWORD'
storeFile file('RELATIVE_PATH_TO_KEYSTORE')
storePassword 'STORE_PASSWORD'
}
}
...
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}

Недоліком рішення є те, що ваш приватний ключ зберігається під версионным контролем, як і пароль для складання релизной версії програми. Зверніть увагу на те, що навіть якщо ви в майбутньому приберете ключ і поправите build.gradle скрипт, то існує ймовірність, що хто-небудь, покопавшись в історії комітів, відновить цю інформацію, так що будьте уважні. Більш правильним рішенням було б тримати property файл, який не перебуває під версионным контролем і лежить, наприклад, ~/home директорії, в якому були б написані всі необхідні параметри.

Наприклад, у нашому проекті використовується наступний підхід. Файл з налаштуваннями та файл для підпису відсутні в контроль версій. У розробників вони підкладені руками. Таким чином, ми вирішуємо проблему того, що хтось, кому цього робити не слідують, може підписати ваш додаток. Тепер треба вирішити проблему, щоб підписувати додаток міг сам Jenkins. Для цього будемо при підписи додатки перевіряти наявність файлу в двох місцях. Перше — це коренева директорія проекту. Друге — певне місце на сервері, де очікується, що цей файл повинен зберігатися. Далі ви підкладаєте цей файл на jenkins сервер і отримуєте можливість збирати підписані версії програми. Ось приклад gradle скрипта, як це реалізується:

android {
...
signingConfigs {
if (rootProject.file("release.properties").exists() || new File("/home/ubuntu/release.properties").exists()) {
def properties = new Properties()
def fileToLoad = rootProject.file("release.properties").exists() ?
new FileInputStream(rootProject.file("release.properties")) : new FileInputStream("/home/username/release.properties")
properties.load(fileToLoad)
release {
keyAlias properties.keyAlias
keyPassword properties.keyAliasPassword
storePassword properties.keyStorePassword
storeFile rootProject.file('keystore.jks')
}
}
}
...
buildTypes {
release {
if (signingConfigs.hasProperty("release"))
signingConfig signingConfigs.release
}
}
}

Публікація тестових збірок в Fabric та оповіщення тестувальників
Fabric — чудова система для складання креш-репортов за вашим додатком. Якщо ви використовуєте стандартну гугл аналітику для складання крешей, то дуже рекомендую подивитися fabric або firebase. Для використання Fabric нам знадобиться встановити jenkins плагін.

Налаштувати jenkins(Manage Jenkins) → Керування плагінами (Manage Plugins) вкладка Доступні, вводимо Fabric. Нас цікавить Fabric Beta Publisher. Після його установки повернемося до опису завдання і додамо ще один.





Необхідно вказати Fabric_api_key, а також secret_key, і вказати відносний шлях .apk файлу програми, яку ми будемо заливати для тестувальників. Подивитися ці значення можна в особистому кабінеті fabric. Settings → Organizations → {Your_app_name} → API_KEY, Build Secret.

Далі ви можете надіслати нотифікації для ваших тестувальників. Можна вказувати як email, так і групу тестувальників. Яким чином управляти групами, вам буде видніше найкраще самим. Наприклад, ми воліємо використовувати 2 групи: dev, production. Всі тестові збірки додатків нотифицируют dev групу тестувальників, а збірки, які будуть заливатися в Google Play, нотифицируют production групу тестувальників.

Далі, якщо наші складання якимось чином відрізняються один від одного, то нам необхідно зазначити цю інформацію у Build Notes для тестувальників. Робимо це через Environment Variable і скрипт, який буде заповнювати дану інформацію.

На нашому проекті дотримуються такого підходу. Коли приходить час релізу, master гілки створюється гілка delivery_xx, де xx — номер спринту. На жаль, Jenkins за замовчуванням не вміє збирати складання з гілок, де ім'я гілки може змінюватися. Нам доведеться навчити його цьому самим.
Для цього нам знадобиться встановити ще один плагін — EnvInject. Після цього повертаємося в вид завдання і встановлюємо нову опцію — Prepare an environment for the run. Завдяки цьому плагіну ми можемо виконати який-небудь groovy скрипт, і після цього зберегти в змінних середовища всі необхідні результати.

В нашому випадку нам необхідно отримати список гілок у репозиторію і знайти гілку, ім'я якої починається на delivery. Також, нам треба встановити build notes для тестувальників, щоб вони знали, з якої гілки проводилася збірка додатки. Скрипт для цього буде виглядати наступним чином:

def gitURL = "git@github.com:[your_repo_url]"
def command = "git ls-remote -h $gitURL"

def proc = command.execute()
proc.waitFor()
if (proc.exitValue() != 0) {
println "Error ${proc.err.text}"
}

def branch = proc.in.text.readLines()
.collect { it.replaceAll(/[a-z0-9]*\trefs\/heads\//, ")}
.find { it.startsWith("delivery")}

if (branch == null) {
def build = Thread.currentThread().executable
build.doStop()
return 0
}

def map = [BRANCH: branch, FABRIC_RELEASE_NOTES: "$branch"]

Безсумнівно, тут ви можете дописати будь-яку необхідну у вашому конкретному випадку логіку.
Далі підправимо ім'я гілки з якої буде проводиться збірка.



І оновимо блок публікації додатка в fabric, як показано на скріні вище.
Тепер ми вміємо робити майже всі пункти, описаних на початку статті, і нам залишилося тільки навчитися публікувати підсумкову збірку додаток в google play.

Публікація в Google Play
Для нас вже підготували плагін для публікації додатків в Google Play з допомогою Jenkins. Ставимо його: Google Play Android Publisher Plugin. Далі нам необхідно створити спеціальний сервісний обліковий запис, який буде займатися публікацією додатків в Google Play. Для цього необхідно виконати наступні кроки:

  1. Заходимо в консоль розробника під власником облікового запису.
  2. Установки → Доступ до API.
  3. Натискаємо «Створити проект».
  4. Натискаємо «Створити акаунт додатків».
  5. Переходимо по посиланню.
  6. У випадаючому списку натискаємо «Edit» і міняємо ім'я акаунту на необхідний, наприклад «Jenkins».
  7. У випадаючому списку вибираємо «Сreate key» та вибираємо тип ключа «JSON».
  8. Натискаємо створити ключ.
  9. Автоматично буде завантажений файл, який пізніше буде використовуватись для аутентифікації консолі плагін для публікації програми.
Те ж саме в картинках:









Далі необхідно видати відповідні доступи в консолі розробника для створеного сервісного облікового запису і публікації додатків. Для цього виконуємо наступні кроки:

  1. Повертаємося в консоль розробника
  2. Для створеного аккаунта додатків натискаємо «Відкрити доступ»
  3. Для створеного аккаунта додатків натискаємо «Відкрити доступ»
  4. Необхідно переконатися, що є дозволи для Зміни інформації про програму та управлінні Production, Alpha і Beta версій програми
  5. Натискаємо додати
Те ж саме в картинках:





Тепер ми можемо вийти з консолі розробника і перейти до налаштування Jenkins для публікації додатки.

  1. Переходимо в Jenkins
  2. Вибираємо пункт меню «Credentials»
  3. Вибираємо загальні доступи і натискаємо «Add Credentials»
  4. Вибираємо тип доступу: Google Service Account from private key»
  5. Вводимо ім'я доступу(пізніше буде використовуватися в налаштуванні завдання), наприклад android-publish
  6. Вибираємо тип «JSON key»
  7. Завантажуємо файл, який ми раніше скачали «JSON key»
  8. Натискаємо OK, щоб створити доступ
Теж саме в картинках:





Далі переходимо в вид завдання і додаємо Крок після складання — Upload Android APK to Google Play.
Необхідно вказати credentials для цього кроку, які ми додали раніше. А також шлях до apk файлу та інформацію, який відсоток користувачів необхідно перевести на дану версію. Ймовірно, спочатку це буде 100%. Також необхідно вказати, яку версію .apk файлу ви заливаєте. Ви можете публікувати alpha, beta, production версії через jenkins. Після цього, можна спокійно запускати завдання, а самому йти пити чай, поки jenkins зробить за вас всю рутинну роботу по збірці, підписування програми та публікації.



Захист критичних завдань
Тепер ми вміємо створювати завдання, можемо давати доступи тестерам, і вони самі будуть збирати собі складання додатків, коли їм це буде потрібно. Природно, ми не хочемо, щоб наші QA випадково опублікували додаток. Пропоную поступити таким чином.
Нам буде необхідно винести публікацію програми в окрему задачу і забрати доступи у QA по запуску цього завдання.

  1. Переходимо в Налаштування Jenkins → Сonfigure Global Security
  2. Блок «Авторизація» → вибираємо пункт «Project-based Matrix Authorization Strategy»
  3. Одразу додаємо своє ім'я користувача і виставляємо для себе всі пункти як доступні. Якщо не зробити цей пункт, ви забороните доступ для самого себе з jenkins (якщо все-таки так трапилося, дивіться рішення тут).
  4. Далі додаєте ім'я користувача QA, і встановлюєте йому дозволу, які вважаєте потрібними. Для нас принципово не давати йому запускати завдання. Блок «Завдання», пункт «Build»
  5. Після цього переходимо до завдання, доступ для якої хочемо дати QA, і даємо йому відповідні доступи.


Тепер наші QA не зможуть випадково опублікувати додаток в Google Play.

Мабуть, на цьому все. Ми могли б і далі покращувати автоматичне складання і публікацію додатків, проте це виходить за рамки даного підручника.

p.s. Було б цікаво також порівняти Jenkins з іншими CI серверами і подивитися, як реалізовувати аналогічні пункти для складання додатків. Також цікаво спробувати оформити завдання не у вигляді вільної конфігурації, а з допомогою PipeLine, щоб ми могли всю конфігурацію описувати в документі, який ми помістимо під контроль версій і будемо динамічно змінювати у проекті.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.