При создании программного обеспечения возникает потребность в автоматизации рутинных действий: статический анализ, тестирование, сборка проекта, деплой, создание и публикация релиза, которые также входят в концепцию непрерывной интеграции и доставки (CI/CD). Этот пост посвящён обзору GitHub Actions на примерах настройки статического анализа (далее “прогон линтера”) и развёртывания на GitHub Pages проекта на typescript, который собирается с помощью webpack и управляется yarn.
Ключевая идея CI/CD систем (TeamCity, Gitlab CI, GitHub Actions, Jenkins, Travis) в построении набора удобных абстракций над исполнением набора команд на некой машине (раннере), при выполнении какого-то действия с репозиторием, а также управление тем, на каких раннерах будет происходить исполнение. В случае GitHub Actions исполнение может происходить либо на виртуальных машинах в инфраструктуре GitHub, для публичных репозиториев отсутствуют ограничения по использованию. Для приватных репозиториев бесплатно доступно 2000 минут в месяц, за превышение лимитов необходимо доплачивать или переходить на другой тарифный план, но имеется возможность подключать собственные раннеры. Всё остальное предоставляется бесплатно.
Конфигурирование GitHub Actions происходит с помощью yaml файлов в папке репозитория .github/workflows. Набором основных абстракций для Github Actions является Workflow, Job, Step, Action.
Step (шаг) ─ минимальная единица исполнения. Это либо исполнение одной команды в shell, либо вызов action. Actions ─ это абстракция, которая играет роль, аналогичную функциям в языках программирования. Они могут импортироваться из других репозиториев гитхаба, индексируются в GitHub Actions Marketplace, и позволяют эффективно переиспользовать часто повторяющиеся для разных репозиториев действия, например, существует action checkout@v2, копирующий репозиторий, action crazy-max/ghaction-github-pages, содержащий логику публикации статических файлов на Github Pages. Как и у функций, для кастомизации actions у них есть аналог аргументов. Actions могут быть написаны на javascript, являться docker контейнерами или последовательностью шагов.
Набор шагов (steps), который выполняется на одном раннере, называется job ─ поэтому на уровне job происходит выбор типа раннера (поддерживаемой им платформы). Обычно job делает одно осмысленное действие, например, тестирует проект. Набор job группируется в workflow ─ это процедура, которая запускается при срабатывании события, попадающего под фильтр. Событий в GitHub Action много: пуш в репозиторий (вообще или в определённую ветку), создание/модификация/влитие pull request, создание релиза и другие.
Теперь рассмотрим перечисленное на примере. Мы хотим в CI прогонять линтер на пуллреквестах, а при пуше в ветку master производить публикацию на Github Pages.
Поскольку у нас два разных триггера, нам необходимо два workflow. Начнём с линтера: создадим файл .github/workflows/ci.yaml (позднее здесь будут jobs и на тестирование, всё вместе это является непрерывной интеграцией):
# имя workflow, отображается в гитхабе
name: ci
# триггер, может быть строкой, массивом или сложным фильтром
on: pull_request # нам нужно, чтоб оно работало на пуллревестах
# словарь джоб
jobs:
lint: # джоба с названием lint
runs-on: ubuntu-latest # требуем раннер с убунтой
steps: # набор шагов
# uses - используем готовый action
- uses: actions/checkout@v2 # спуливает последний коммит
- uses: actions/setup-node@v2 # устанавливает node.js
with: # с помощью with можно передавать параметры экшенам
node-version: 14.x # нам надо настроить конкретную версию node.js
# run - вызов простой shell команды
- run: 'yarn install' # скачиваем зависимости, линтер среди них
- run: 'yarn lint' # прогоняем линтер
Перейдя по Details, можно увидеть, почему проверка ci/lint провалилась.
По ссылке https://github.com/RobolabGs2/phaser-playground/actions/runs/1313421545 также можно увидеть пример успешного прохождения линтера.
Теперь создадим .github/workflows/cd.yaml:
name: cd
# тут у нас более сложный фильтр
on:
push: # триггеримся на пуш
branches: # в ветки из списка
- master # в нашем случае - мастер
jobs:
deploy-pages-demo:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 14.x
- run: 'yarn install'
- run: 'yarn build'
# если вдруг билд не смог выполниться успешно, то мы
# не хотим продолжать выполнение джобы
- if: success() # поэтому тут добавим условие
uses: crazy-max/ghaction-github-pages@v2.5.0
with:
target_branch: gh-pages
build_dir: dist
# помимо аргументов экшена, можно устанавливать
# переменные окружения
env:
# поскольку этот экшен должен пушить в ветку репозитория
# ему необходим токен с соответсвующими правами
# секретные вещи передаются через секреты, которые шифруются
# в настройках репозитория и доступны только администраторам
# репозитория
# по умолчанию уже существует токен с доступом к текущему репозиторию
# обратимся тут к нему
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
После публикации кода в ветке master и активации github pages в настройках репозитория, по адресу https://robolabgs2.github.io/phaser-playground/ стало доступно текущее состояние демки.
Таким образом, мы получили с помощью 33 строк кода (комментарии не в счёт) работающую CI/CD систему, проверку качества кода и деплой демки проекта на Github Pages.
Ссылки на документацию и использованные actions:
2. Checkout action
3. Setup-node action
4. Github Pages action
5. Репозиторий, использованный в качестве примера.