Настраиваем Gitlab CI для сборки Android-проекта

от автора

Привет! Меня зовут Даша, я Android-разработчик в команде онлайн-кинотеатра PREMIER и я хочу с вами поделиться историей как мы начали приводить в порядок Gitlab CI скрипты 🙂

В нашем проекте стало много вариантов сборок и чтобы не тратить кучу времени на ожидание и поиск необходимого билда нам нужно было хотя бы получить отбивку об окончании работы джобы. А затем — решить неудобства с копипастой, чтобы поддержка скриптов не вызывала выгорание:) Погнали!

Собираем

Начнем с простейшего скрипта в .gitlab-ci.yml:

image: jangrewe/gitlab-ci-android stages:   - build  _Google_ProdBundle:   stage: build # стейдж сборки приложения   when: manual # запуск только вручную   script:     - ./gradlew -Pci --console=plain :app:bundleProdGoogleRelease -Pbuildnum="$CI_JOB_ID"   artifacts:     name: "$CI_JOB_STAGE-$CI_COMMIT_REF_NAME"     paths:       - sources/app/build/outputs/bundle/prodGoogleRelease/ # путь к артефактам     expire_in: 1 week # время жизни артефакта, у нас он должен храниться только 1 неделю

Мы используем image jangrewe/gitlab-ci-android, так как в нем уже есть Android SDK и другие библиотеки для сборки приложений для Android. Все статические переменные, касающиеся безопасности, лежат в Gitlab Variables (Settings -> CI/CD -> Variables). 

Здесь у нас запускается сборка Google-варианта bundleProdGoogleRelease с параметром Pbuildnum, который мы используем в качестве кода сборки (versionCode), и также записываем его в название сборки, чтобы соотнести ее с джобой. Pbuildnum — это project property, который можно достать в самом gradle.build таким образом:

versionCode = project.property('buildnum').toString().toBigDecimal()

Как использовать project properties — вы можете прочитать здесь.

CI_JOB_ID — идентификатор джобы, используется для указания версии сборки.

CI_JOB_STAGE — стейдж джобы, CI_COMMIT_REF_NAME — имя ветки.

Также здесь имеется параметр expire_in, который указывает на время хранения готового артефакта на сервере, здесь у нас это 1 неделя. Запуск производится вручную во избежание высокой нагрузки на сервер.

В данной джобе использую предопределенные переменные Gitlab CI, такие как CI_JOB_STAGE,  CI_COMMIT_REF_NAME, CI_JOB_ID, но также существует множество других, о которых описано в документации Gitlab CI.

Выглядит просто: джоба отработала — артефакт готов. На этом этапе пайплайн в работе оказывал негативный эффект на нашу психику, а глаза краснели во время поиска необходимой сборки…

Оповещаем

…а можно было бы просто получить ссылку в мессенджере сразу и скачать артефакт оттуда 🙂 

Мессенджер можно использовать любой, а я покажу на примере Slack. 

Для реализации отправки сообщений в Slack необходимо сгенерировать webhook, данный процесс детально описан в документации

_Google_ProdBundle:   stage: build   …   #   …   after_script:     -      - >-       curl -X POST --data-urlencode 'payload={"channel": "'$SLACK_CI_CHANNEL'", "username": "AndroidCI", "text": ":white_check_mark: *Premier-Android*: Готов новый артефакт *'${CI_JOB_NAME}'* <'${ARTIFACT_URL}'|'${CI_JOB_ID}'>" }' $SLACK_WEBHOOK

Блок after_script вызывается после выполнения основного блока script. 

Здесь мы отправляем POST-запрос с параметром —data-urlencode, где указали шаблон сообщения и полученный ранее SLACK_WEBHOOK.

ARTIFACT_URL у нас формируется следующим образом:

${JOBS_PATH}${CI_JOB_ID}${ARTIFACTS_ARCHIVE_PATH}${ARTIFACT_PATH}

JOBS_PATH — это путь к списку джоб в Gitlab.

CI_JOB_ID — идентификатор выбранной джобы.

Для того, чтобы сформировать ссылку на браузер в ARTIFACTS_ARCHIVE_PATH, мы указываем /artifacts/browse/, а для ссылки на скачивание — /artifacts/file/.

И указываем в ARTIFACT_PATH путь bundle или apk-файлам. 

И вот в Slack нам прилетает такое сообщение:

И по клику на номер джобы откроется окно с артефактом, который можно будет скачать:

Вуаля, запустил сборку, получил уведомление со ссылкой, скачал и пошел искать баги 🙂  

Вот мы и настроили сборку и отправку сообщений: коллеги выбирают тип сборки, нажимают на кнопочку и ждут оповещения.

Вроде бы выглядит нормально, да и для небольших проектов и этого достаточно 🙂 Но не торопитесь радоваться! Нас остановила полиция копипасты и выписывает нам штраф. А за что? 

Внимательные читатели поняли, что для каждого вида сборки нам надо копировать весь вышеперечисленный код и исправлять пару строчек 🙂  

А именно: 

./gradlew -Pci --console=plain :app:bundleProdGoogleRelease -Pbuildnum="$CI_JOB_ID"  paths:       - sources/app/build/outputs/bundle/prodGoogleRelease/

Непорядок, нам нужно это исправить, иначе наш .gitlab-ci.yml разрастется до огромных размеров, и как потом такое поддерживать… Приступим!

Модернизируем

Первым делом выделим группы пайплайнов, чтобы в каждом лежали только скрипты, выполняющие одно и то же для каждой сборки. 

Для этого необходимо использовать модификатор include в .gitlab-ci.yml. 

После изменений файл .gitlab-ci.yml начал выглядеть так:

image: jangrewe/gitlab-ci-android  include:   - local: .gitlab-ci-merge.yml   - local: .gitlab-ci-build.yml   - local: .gitlab-ci-build-tv.yml   - local: .gitlab-ci-deploy.yml   - local: .gitlab-ci-huawei.yml   - local: .gitlab-ci-browserstack.yml   - local: .gitlab-ci-distribution.yml   - local: .gitlab-ci-code-analyze.yml  … # VARIABLES …  stages:   - analyze   - build   - deploy   - test

Далее мы выделим общие действия, которые используются во всех скриптах, и добавим их в наш gitlab-ci.yml. Для этого мы используем reference-теги для объявления общих скриптов.

Сохраняем переменные в variable.env для их дальнейшего переиспользования в следующей джобе, подробнее про переменные и их использование можно почитать здесь.

.base_task:   allow_failure: false   before_script:     - echo "LAST_JOB_URL=${CI_JOB_URL}" >> variable.env     - echo "LAST_JOB_ID=${CI_JOB_ID}" >> variable.env     - echo "LAST_JOB_NAME=${CI_JOB_NAME}" >> variable.env     - cat variable.env   artifacts:     reports:       dotenv: variable.env

Выделяем общий скрипт сборки:

.base_bundle_task:   variables:     ARTIFACT_NAME: "$CI_JOB_STAGE-$CI_COMMIT_REF_NAME"   script:     - ./gradlew -Pbuildnum="${CI_JOB_ID}" --console=plain :${APPLICATION}:bundle${VARIANT}     - echo "${JOBS_PATH}${CI_JOB_ID}${ARTIFACTS_ARCHIVE_PATH}${ARTIFACT_PATH}" > .var_artifact_url     - echo "SUCCESS" > .var_state     - echo "APPLICATION=${APPLICATION}" >> variable.env     - echo "LAST_JOB_ID=${CI_JOB_ID}" >> variable.env     - echo "VARIANT=${VARIANT}" >> variable.env     - echo "ARTIFACT_PATH=${ARTIFACT_PATH}" >> variable.env   artifacts:     name: "${ARTIFACT_NAME}"     paths:       - $ARTIFACT_PATH     expire_in: 1 week

Более подробно про передачу переменных между джобами описано здесь.

И добавляем код отправки сообщений со ссылками на сборки.

.with_notification:   allow_failure: false   before_script:     - echo ${SLACK_CI_CHANNEL} > .var_channel     - echo ${CI_JOB_URL} > .var_artifact_url     - echo "NONE" > .var_state   after_script:     - CHANNEL=$(cat .var_channel)     - ARTIFACT_URL=$(cat .var_artifact_url)     - STATE=$(cat .var_state)     - env     - >       if [ "${STATE}" == "SUCCESS" ]; then curl -X POST --data-urlencode 'payload={"channel": "'${CHANNEL}'", "username": "AndroidCI", "text": ":white_check_mark: *Premier-Android*: Готов новый артефакт *'${CI_JOB_NAME}'* <'${ARTIFACT_URL}'|'${CI_JOB_ID}'>" }' $SLACK_WEBHOOK; fi

Далее с помощью extends наследуем джобу от вышеописанных скриптов.    

В итоге после выноса общего кода в отдельный файл .gitlab-ci-build.yml пайплайн для релизной Google-сборки выглядит вот так: 

_Google_ProdBundle:   extends:     - .base_task     - .base_bundle_task     - .with_notification   stage: build   when: manual   variables:     ARTIFACT_PATH: "sources/app/build/outputs/bundle/prodGoogleRelease"     APPLICATION: "app"     VARIANT: "ProdGoogleRelease"

Таким образом, скрипт стал немного гибче, для других сборок нам достаточно только поменять вариант и путь к сборке. Этот пайплайн можно будет оптимизировать и дальше, но это уже другая история… 🙂 

Хоть и ненамного, но мы упростили жизнь нам и нашим тестировщикам. Для сборки артефакта и отправки его в тест нам нужно только нажать одну кнопочку, вот и все! 

З. Ы.: на этом мы не прощаемся, в следующих статьях автоматизируем еще что-нибудь 🙂


ссылка на оригинал статьи https://habr.com/ru/company/gazprommedia/blog/706222/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *