# Как быстро настроить 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'ы. Это будет полезно, например, для разграничения запуска "тяжелых" тестов.
В гитхабе можно посмотреть на визуализированные зависимости шагов:

## Деплой
В `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):

```markdown

```
Еще мы настроили автоматическое [закрытие тикетов по крону](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)