# Как быстро настроить GitHub Actions # Как переехали с тревиса (?) - сложности (релизы, ...) - больше уникальности Привет, меня зовут Игорь, я разработчик решений на Tarantool в Mail.ru Group. Я работаю над витринами маркетинга в реальном времени для Мегафона, а также мейнтейню [tarantool/metrics](https://github.com/tarantool/metrics). Недавно мы переехали с Travic CI на GitHub Actions. Хочу поделиться опытом его настройки в `tarantool/metrics`. Статья будет полезна тем, кто переезжает на Actions с другого CI и тем, кто настраивает его впервые. Далее я расскажу о типах событий в GitHub, о синтаксисе Actions и покажу, как запускать тесты и собирать приложение для доставки пользователям. ## GitHub Actions ### Workflow и job **Workflow** - это процедура, которая выполняется после возникновения определенного события на GH. Каждый workflow состоит из одной или нескольких job. **Job** - это набор действий, которые выполняются на одном раннере. **Раннер** - это сервер, на котором запускаются команды. Можно воспользоваться гитхабовскими раннерами или поднять свои. Для простых задач гитхабовских раннеров будет достаточно. **Шаги** job'ы могут быть консольными командами или action'ами. **Action** - набор команд, который вынесен в отдельный репозиторий и предназначенный для выполнения определенного действия. ### Кратко про типы событий Обо всех событиях можно прочитать [здесь](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#webhook-events). Для повседневных задач (запуска тестов, деплоя) используются обычно следующие события: - `push` - пуш в ветку или мердж в мастер - `branches` - вводит ограничения на ветки - `tags` - ограничения на теги - `release` - вызывается при релизе через GitHub - `pull_request` - создание пулл реквеста - `workflow_run` - событие о запуске workflow - `schedule` - вызывается по крону ### Основные синтаксические конструкции Workflow состоит из нескольких основных секций (?): - `name` - имя workflow, оно используется в других workflow и отображается на гитхабе - `on` - здесь определяются типы событий, которые запускают workflow - `jobs` - это список job, у каждой из которых есть список "шагов" (они прописываются в `steps`), которые выполняются в рамках этой job'ы - `runs-on` - определяет ОС, на которой будет выполняться шаги job'ы - `steps` - набор шагов, которые выполняются в рамках этой job'ы ```yaml= name: Workflow name on: event_name: event_params jobs: job_name: runs-on: ubuntu-latest #job_params steps: - name: Step 1 name uses: actions/checkout@v2 - name: Step 2 name run: some shell commands ... ``` ### Действия на шаге job'ы Шагом job'ы может быть запуск action'a или консольной команды. `run` - запускает консольную команду. Перед вызовом `run` необходимо убедиться, что установлены необходимые пакеты и настроено окружение. `uses` - запускает action. Action'ы можно написать самостоятельно или воспользоваться уже имеющимися. Первым шагом каждой job'ы обычно является `actions/checkout`. Этот action копирует код из репозитория на раннер. ### Настройка окружения ~~Настройка окружения для разных языков производится с помощью конструкции `uses`.~~ Для большинства популярных языков уже написаны готовые экшены которые настраивают окружение, и не нужно каждый раз прописывать шаги по настройке и установке пакетов. Необходимые параметры для настройки (они прописываются с помощью конструкции `with`) можно посмотреть в соответствующем GitHub-репозитории. Вот так, например, можно настроить окружение для Go: ```yaml= jobs: job_name: steps: - name: Setup go uses: actions/setup-go@v2 with: go-version: '1.15' ``` ### Как подключить GH Actions 1. Создаем в репозитории папку `.github/workflows/`. 2. В папке создаем файл с расширением `.yml`. 3. Описываем в этом файле workflow 4. После этого workflow запустится автоматически при возникновении нужного события ## Тесты ### Матричное тестирование Для тестов часто требуется использовать различные версии языков, приложений или ос. Actions позволяет составить матрицу для тестов. Вот так, например, мы настроили матричные тесты для разных версии Tarantool и Cartridge: Файл `.github/workflows/tests.yaml`: ```yaml= name: Tests on: push: branches: - '*' # вызывается при пуше коммитов в любую ветку test: strategy: matrix: tarantool: - "1.10.8" ... - "2.7.0" cartridge: [ "", "1.2.0", "2.1.2" ] runs-on: ubuntu-latest container: image: tarantool/tarantool:${{ matrix.tarantool }} env: CARTRIDGE_VERSION: ${{ matrix.cartridge }} steps: ... ``` `matrix` также позволяет добавлять и исключать определенные тесты из матрицы. Например, если бы мы хотели пропускать тест для связки Tarantool 1.10 и Cartridge 2.1.2, и дополнительно проверять работу метрик на версии Tarantool 2.7 и Cartridge 2.4.0, следовало дописать: ```yaml= matrix: tarantool: - "1.10.8" ... - "2.7.0" cartridge: [ "", "1.2.0", "2.1.2" ] include: - tarantool: "2.7.0" cartridge: "2.4.0" exclude: - tarantool: "1.10.8" cartridge: "2.1.2" ``` На каждую пару `matrix.tarantool` и `matrix.cartridge` создается одна job'a, а также добавляются те, которые указаны в `include` и исключаются указанные в `exclude`. В итоге получаем `7х3 + 1 - 1 = 21` job. Вместо `tarantool` и `cartridge` можно использовать вообще любые параметры и обращаться к ним в любом месте тестов с помощью конструкции `${{ matrix.tarantool }}` ### Тело теста (wtf?) Сюда можно перенести команды, которые выполнялись в другом CI, например, Тревисе. ```yaml= # копируем код на раннер - uses: actions/checkout@v2 # устанавливаем зависимости - name: deps run: apk add --update alpine-sdk make curl git cmake gcc # запускаем команды из мейкфайла - name: lint run: make lint - name: test run: make test_with_coverage_report ``` ### Зависимости между тестами По умолчанию тесты отменяются, если хотя бы один из них упал. Чтобы изменить это поведение, можно прописать в `strategy` параметр `fail-fast: false`. (это про матрицу, остальное все равно упадет) Для запуска определенного теста после предыдущего можно прописать `needs: job_name` в параметрах job'ы. Это будет полезно, например, для разграничения запуска "тяжелых" тестов. В гитхабе можно посмотреть на визуализированные зависимости шагов: ![](https://i.imgur.com/rIJmBB7.png) ## Деплой В `tarantool/metrics` два типа релизов: релиз latest-версии по пушу в мастер и релиз тегированной версии по пушу тегов. Мы не хотим, чтобы деплои запускались после упавших тестов, поэтому в релизные джобы добавляем проверку на то, что предыдущий workflow завершился успешно. ~~Следует также иметь в виду, что при релизах через UI гитхаба, создаются только неаннотированные теги, с которыми есть **проблемы** (вспомнить бы какие)~~ ```yaml= on: workflow_run: workflows: ["Tests"] branches: [master] types: - completed # Запускаем только после завершения тестов в мастере push: tags: - '*' # И по пушу тегов ... jobs: push-scm-rockspec: runs-on: [ ubuntu-latest ] # Запускаем только если предыдущий workflow был успешным if: github.ref == 'refs/heads/master' && github.event.workflow_run.conclusion == 'success' steps: # заливаем рокспеку на рок-сервер ... push-tagged-rockspec: runs-on: [ ubuntu-latest ] if: startsWith(github.ref, 'refs/tags') # Запускаем когда запушили теги steps: ... - name: Set env run: echo "GIT_TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV # получаем название тега ... # заливаем рокспеку на рок-сервер ``` Для деплоя пакетов также можно использовать матрицы, вот так, например, мы выбираем разные дистрибутивы ОС: ```yaml= jobs: deploy: strategy: matrix: os: - name: el dist: 7 ... - name: fedora dist: 29 repository: - "1_10" ... - "2_4" runs-on: ubuntu-latest env: PACKAGECLOUD_TOKEN: ${{ secrets.PACKAGECLOUD_TOKEN }} OS: ${{ matrix.os.name }} DIST: ${{ matrix.os.dist }} ``` ## Дополнительно Вот так можно добавить в README бейдж о прохождении тестов (в ссылке `Tests` - название нужного workflow): ![Build Status](https://github.com/tarantool/metrics/workflows/Tests/badge.svg?branch=master) ```markdown ![Build Status](https://github.com/tarantool/metrics/workflows/Tests/badge.svg?branch=master) ``` Еще мы настроили автоматическое [закрытие тикетов по крону](https://github.com/actions/stale). Посмотреть можно [здесь](https://github.com/tarantool/metrics/blob/master/.github/workflows/stale.yml). ## Итоги В статье были рассмотрены основные термины и типы событий в GitHub, синтаксис Actions и показано, как мы описывали workflow для тестов сборки приложение для доставки пользователям. ## Ссылки - Скачать Tarantool можно на официальном сайте - Получить помощь можно в Telegram-чате. - [Введение в GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/introduction-to-github-actions) - [Синтаксис workflow](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions) - [События в GitHub](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#webhook-events)