Часть 1, Часть 2
В одной из последних статей я делала обзор GitHub Actions и показывала, как использовать существующий экшен для развертывания сайта Gatsby на GitHub Pages. В этой же статье я хочу углубиться в изучение экшенов GitHub, чтобы подробнее раскрыть их основную идею, показать и пояснить архитектуру, а также рассмотреть этапы их построения.
Но прежде чем переходить к особенностям этого инструмента GitHub, давайте уточним, какую он вообще несет пользу. Для этого мы рассмотрим события GitHub и то, как этот ресурс поддерживал их обработку ранее.
События GitHub
GitHub предоставляет хостинг проектов ПО и контроль версий через Git. Обеспечивая возможность сотрудничества между командами (зачастую распределенными), ревью кода и управление проектами, этот ресурс сформировал ядро жизненного цикла разработки ПО.
События GitHub играют важную роль в успешном функционировании GitHub, одновременно предоставляя точки возможного расширения путем интеграции с другими инструментами, применяемыми при разработке ПО. Вы можете использовать GitHub для совместной работы над исходным кодом, JIRA для управления проектами и Confluence для обработки документации. События GitHub помогают расширять спектр типичных выполняемых на GitHub действий и привязываться к другим инструментам, которые вы уже используете.
“Каждое событие соответствует конкретному набору действий, которые могут осуществляться в вашей организации и/или репозитории. Например, если вы подпишитесь на событие issues
, то будете получать подробную информацию при каждом открытии issue
, его закрытии, отметке и т.д.” — документация GitHub
Например, при отправке пул-реквеста на GitHub вам может понадобиться обновить статус соответствующего тикета в Jira.
На какие события GitHub можно реагировать?
В GitHub по части событий есть обширная документация. Вы можете подключаться к огромному спектру рабочих процессов и расширять их согласно нуждам команды или бизнеса.
Например:
- Когда происходит что-то, связанное с
issue
, можно использовать событияissues
для вызова изменений в другой системе. - Когда происходит что-то, связанное с пул-реквестом, можно аналогичным образом использовать события пул-реквестов.
Возможности в этом плане безграничны — можно автоматически находить и исправлять в коде проблемы стиля при каждом слиянии, отправлять сообщение Telegram при каждом неудачном развертывании или автоматически отмечать каждый новый пул-реквест в репозитории.
Как это было до появления GitHub Actions
Как же осуществляется прослушивание событий GitHub и реагирование на них? До появления GitHub Actions для получения событий GitHub рекомендовалось использовать веб-хуки.
Слушателем событий в данном случае является веб-сервис, выражающий конечную точку HTTP. Нужно лишь настроить в репозитории веб-хук, используя эту конечную точку в качестве цели доставки событий.
После этого при возникновении активности в репозитории GitHub будет выполнен POST события на эту конечную точку. При этом веб-хук может расширять активность, выполняя в ответ на событие пользовательский код.
Самый большой недостаток веб-хуков в необходимости существовать в качестве внешнего сервиса. Это подразумевает написание нового сервиса, его развертывание и дальнейшее обслуживание.
Знакомство с GitHub Actions
GitHub Actions вместо независимо развернутого веб-хука предоставляют способ реагирования на события GitHub в рамках самой этой платформы.
“GitHub Actions — это ваш рабочий процесс, создаваемый вами, выполняемый нами.” — блог GitHub
GitHub Actions обеспечивает ряд преимуществ:
- Предоставляет возможность реагировать на события внутри GitHub, избавляя тем самым от необходимости привлечения внешнего инструмента и пересылки данных через другой сервис.
- Предоставляет более дешевый тариф, чем отдельный сервис для CI/CD. В данном случае для публичных репозиториев тариф бесплатный, а для частных предполагается оплата по факту использования.
- Позволяет повторно задействовать общие рабочие процессы. Этот момент особенно важен, поскольку избавляет разработчиков от необходимости повторного решения одних и тех же задач. Вместо этого публичные рабочие процессы формируют экосистему экшенов, которые разработчики могут разветвлять, редактировать, перебирать и улучшать во многом аналогично коду.
Структура — рабочие процессы, задачи, этапы, экшены и исполнители
Событие GitHub запускает рабочий процесс:
- В рабочем процессе (workflow) присутствует одна или более задач (по умолчанию выполняемых параллельно).
- Задача (job) состоит из одного или более этапов (step), выполняемых одним исполнителем (runner). Данные внутри одной задачи могут передаваться из предшествующих этапов в последующие.
- Этап состоит из экшена и ввода этого экшена, а также допускает присвоение имени.
- Экшен — это наименьший самостоятельный компонент рабочего процесса.
- Исполнитель — это сервер, где установлено соответствующее приложение, которое прослушивает задачи, по очереди выполняет их, сообщает о прогрессе и логирует результаты.
Типы экшенов GitHub
Будучи наименьшим самостоятельным компонентом рабочего процесса, экшен включает в себя код, необходимый для выполнения одного логического задания — проверить репозиторий, настроить Node или развернуть статический сайт.
Как мы видели выше, эти логические задания могут комбинироваться для выполнения более общей задачи.
Написать экшен можно одним из двух способов:
JavaScript
В этом случае вы пишите код для экшена на JavaScript. Данный код выполняется с помощью версии Node, указанной вами в файле метаданных action.yml
(подробнее об этом позже).
У этого подхода есть ряд недостатков:
- Экшен зависит от доступной на исполнителе версии Node. Например, Ubuntu-18 Runner на GitHub работает на Node 12. Если вы используете собственный исполнитель, работающий на Node 10, то экшены JS, написанные для Node 12, могут работать некорректно.
- Зависимости должны упаковываться вместе с экшеном (включением каталога
node_modules
в репозиторий экшена или его упаковыванием в отдельный файл при помощи vercel/ncc).
Контейнеры Docker
Контейнеры Docker объединяют среду и код экшена GitHub вместе, что делает их более надежным способом упаковки.
Это значит, что получателю экшена не нужно беспокоиться об инструментах или зависимостях, используемых в данном экшене. Например, если он был определен в Node 12, но запускается в нестандартном исполнителе на Node 10, то это не вызовет проблем, поскольку экшен Docker выполняется в собственном контейнере, имеющем подходящую для данного экшена версию Node.
Создание экшена на Javascript
В одной из давних статей я описывала настройку веб-хука GitHub для отправки комментариев к пул реквестам, открываемым новыми участниками в репозитории. Сейчас я хочу воссоздать это поведение при помощи экшена.
Инициализация репозитория
- Создайте пустой каталог.
- Выполните в нем
npm init -y
.
Описание экшена
Создайте в том же каталоге файл action.yml
. Этот файл содержит метаданные, описывающие назначение экшена, его ввод и вывод.
name: 'Welcome bot on new pull requests'
description: 'Greet new contributors on a repository'
inputs:
access-token:
description: 'A GitHub personal access token used to make comments on your behalf'
required: true
message:
description: 'A personal message to send to a new contributor on your repository'
required: true
default: 'Welcome, {}! Thank you for your contribution'
runs:
using: 'node12'
main: 'src/index.js'
Для получения полномочий делать комментарии от имени пользователя экшену необходим access-token
. Приветственное сообщение для новых участников message
тоже можно настроить.
Мы указываем, что этот экшен выполняется на node12
и устанавливаем в качестве точки входа src/index.js
(где располагается код для экшена).
Добавление зависимостей toolkit
GitHub предоставляет для экшенов toolkit (инструментарий), содержащий основные утилиты, которые могут потребоваться любому экшену. Мы будем использовать эти утилиты для чтения полезной нагрузки событий, создания клиента API GitHub и других тонкостей, которые не хотим реализовывать вручную.
npm install @actions/core
npm install @actions/github
Написание кода экшена
const core = require('@actions/core');
const github = require('@actions/github');
async function run() {
try {
const accessToken = core.getInput('access-token');
const message = core.getInput('message');
const payload = github.context.payload;
const githubClient = github.getOctokit(accessToken);
core.info("Request received");
if (payload.action === "opened") {
core.info("New Pull Request..");
const pullRequest = payload.pull_request;
const userName = pullRequest.user.login;
const owner = pullRequest.base.repo.owner.login;
const repoName = pullRequest.base.repo.name;
const issueNumber = pullRequest.number;
const comment = message.replace(/{}/g, userName);
const shouldComment = await isFirstPull(
githubClient, owner, repoName,
userName, issueNumber
);
// Отправляем комментарий к пул реквесту нового участника
if (shouldComment) {
core.info("Commenting");
githubClient.issues.createComment({ owner, repo: repoName, issue_number: issueNumber, body: comment });
}
}
} catch (err) {
core.setFailed(err.message);
}
}
В этом коде мы:
- Импортируем модули
core
иgithub
из инструментария. - Обращаемся к вводам экшена, используя функцию
core.getInput
. - Обращаемся к полезной нагрузке события, используя модуль
github
:github.context.payload
. - Создаем клиент GitHub, используя модуль
github
:github.getOctokit(accessToken)
с получением токена доступа из ввода. - Просматриваем
payload
на наличие нового пул реквеста (т.е.action
становитсяopened
), а также проверяем, сделан ли пул реквест новым участником. - Если да, то используем
githubClient
, созданный ранее, для отправки комментария к пул реквесту:githubClient.issues.createComment
.
Вот и все!
Коммит кода
- Добавьте каталог
src
, файлыpackage.json
иpackage-lock.json
, а также каталогnode_modules
. - Сделайте коммит изменений.
- Отметьте изменения тегом:
git tag -am "Release version 1.0" v1.0
. - Отправьте их в репозиторий:
git push --follow-tags
.
Весь итоговый код для этого экшена можете найти в моем репозитории.
Экшен в рабочем процессе репозитория
Перейдите в репозиторий, где хотели бы использовать этот экшен для комментирования пул реквестов новых участников. Создайте в нем каталог .github/workflows
. Добавьте в этот каталог файл .yml
для описания рабочего процесса:
name: Comment on pull request
on:
pull_request:
branches:
main
jobs:
comment:
runs-on: ubuntu-latest
steps:
- uses: deborah-digges/[email protected]
with:
access-token: ${{ secrets.ACCESS_TOKEN }}
Именно здесь вы указываете события, в ответ на которые хотите запускать рабочий процесс. В данном случае нам нужно, чтобы он запускался в pull_request
в ветке main
.
В текущем рабочем процессе есть одна задача comment
, которая содержит один этап, состоящий из только что созданного нами экшена, использующего формат deborah-digges/[email protected]
, который указывает:
- Имя пользователя или организации на GitHub, где искать экшен.
- Название репозитория, где расположен этот экшен и его зависимости.
- Версию экшена, которая может быть либо в форме тега, либо в виде хэша коммита.
Добавление токена доступа
Мы указываем вводный access-token
нашего экшена со значением ${{ secrets.ACCESS_TOKEN }}
. Чтобы установить это значение, добавьте личный токен доступа в раздел Secrets
вашего репозитория.
В этом репозитории лежит весь исходный код, реализующий данный экшен.
Тестирование экшена
Пора его опробовать! Протестируйте свой новый рабочий процесс, создав пул реквест в собственный репозиторий. Если это будет первый пул реквест, то вы должны получить приветственное сообщение от дружелюбного экшена.
Читайте также:
- GitHub Codespaces: быстрая разработка на ходу с Flutter
- Kubernetes: безопасное управление секретами с GitOps
- Синхронизация Git-репозиториев в режиме реального времени
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи Deborah Digges: A Deep Dive Into GitHub Actions