Автоматизация рутинных задач с помощью GitHub Actions

Read on English

Вы будете тратить меньше времени на тестирование приложения, сборку, проверку качества кода, актуальность задач, если автоматизируете рутинные процессы. GitHub Actions — это сервис, который позволит описать сценарии любой сложности и условия для его запуска.

Сервис бесплатен для проектов с открытым исходным кодом. Для приватных проектов количество бесплатных минут работы сценариев ограничено. Ознакомиться с ценами и лимитами можно на странице сервиса

Что такое GitHub Actions

Actions — это готовые наборы команд, которыми описывается порядок действий при срабатывании определенного триггера: коммита в ветку, созданной задачи, публикации нового релиза и так далее. Также сценарии можно запускать по времени, как это делается с помощью утилиты cron.

Actions могут взаимодействовать с кодом приложения и историей его изменений, с рабочим окружением репозитория(задачи, проекты, документация, релизы), со сторонними сервисами для развертывания приложения или отправки каких-то запросов с уведомлениями. Это мощный инструмент, который будет вместе с вами работать над проектом.

Как описать сценарий

Файлы сценариев — workflow — хранятся в директории .github/workflow в репозитории вашего проекта. Это конфигурационные файлы формата YAML.

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

name: ... on: ... jobs: ...

Каждая задача может иметь имя, указание операционной системы, зависимость от других задач и список шагов.

Каждый шаг может быть как набором bash-команд, так и готовым action.

Для примера рассмотрим сценарий, который собирает фронтенд для сайта codex.so в режиме production и добавляет сборку в пулл-реквест. 

# Имя сценария name: Build frontend # Условия для выполнения: любые действия с пулл-реквестом on: [pull_request] # Список задач jobs: build: # Название задачи name: Build frontend # Выполнить на вирутальной машине с Ubuntu runs-on: ubuntu-latest # Список шагов steps: # Использовать код проекта из определенного коммита # По умолчанию используется ветка, изменения которой вызвали выполнение сценария - uses: actions/checkout@v2 # Настройка Node.js 15 для работы на виртуальной машине - name: Use Node.js 15 uses: actions/setup-node@v1 with: node-version: 15 # Установка node-пакетов проекта и сборка фронтенда # Выполнятся описанные bash-команды - name: Go to app dir, Install Node.js packages, Build static files run: cd www && yarn && yarn build # Попытка закоммитить обновления сборки фронтенда в ветку от имени бота github-actions (указываем его имя и почту с идентификатором официального бота от гитхаба) - uses: EndBug/add-and-commit@v7 with: author_name: github-actions author_email: 41898282+github-actions[bot]@users.noreply.github.com message: 'Build frontend'

Ознакомьтесь с документацией от GitHub по работе со сценариями для того, чтобы узнать подробнее о возможностях workflow файлов.

Локальное тестирование правильности работы сценариев не предусмотрено.

Где искать экшены

Попробуйте найти нужное действие в каталогах, перед тем, как создавать и публиковать свое собственное.

В GitHub Marketplace есть отдельный раздел, посвященный Actions. Некоторые из них созданы известными компаниями, но бóльшая часть создается и публикуется самостоятельными разработчиками. 

github.com

Также стоит уделить внимание и неофициальному каталогу интересных действий — Awesome Actions.

github.com

Здесь можно найти много интересных решений и вдохновиться — возможно, у вас есть похожая задача, а вы и не думали, что её можно тоже автоматизировать.

Как написать свой Action

Допустим, вы не нашли готовое решение для нужного шага, а описать весь набор команд в виде bash-скрипта неудобно или не представляется возможным. В таком случае Вы можете воспользоваться инструкцией от GitHub. Код action может быть написан на JavaScript, собран в виде готового Docker-образа с любым содержимым. Также набор шагов может быть описан в файле в виде списка консольных команд

Однако надо помнить, что actions на основе докер-контейнеров могут быть запущены только на виртуальной машине с Linux.

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

В качестве примера разберем codex-team/action-nodejs-package-info — действие, которое получает информацию о названии приложения и его версии из package.json файла.

Настройки хранятся в файле action.yml в корне проекта.

# Мета-информация об action используется для формирования карточки в маркетплейсе # Имя действия name: 'Get package info' # Описание description: 'Action for getting information from package.json file' # Иконка и ее цвет фона branding: icon: 'box' color: 'red' # Параметры, которое могут или должны быть переданы на вход inputs: path: description: 'Path to package.json file' required: false default: ./ # Параметры, которые будут доступны по результатам выполнения шага outputs: name: description: 'Package name' version: description: 'Package version' npmjs-link: description: 'Link to npmjs.com package page' # Условия запуска кода runs: # Описание среды и ее версии using: 'node12' # Пусть к собранному скрипту main: 'dist/index.js'

Далее, для работы кода вам потребуется установить пару практически обязательных node-зависимостей:

Добавим скрипт build для сборки исходного кода index.js со всеми зависимостями (например, @actions/core) в единый файл dist/index.js.

{ "name": "action-nodejs-package-info", "scripts": { "build": "ncc build index.js --minify" }, "devDependencies": { "@actions/core": "^1.2.6", "@vercel/ncc": "^0.25.1" } }

И сам исходный файл с простой логикой. Получаем путь к package.json файлу, считываем его и экспортируем некоторые параметры.

import fs from 'fs'; import { join } from 'path'; const core = require('@actions/core'); /** * Read package.json file * @param {string} path * @returns {object} */ const readPackageJson = function (path) { const packageJson = fs.readFileSync(join(path, 'package.json')).toString(); return JSON.parse(packageJson); }; try { /** * Path to directory with package.json file * @type {string} */ const path = core.getInput('path'); /** * Get data from package.json file * @type {object} */ const packageInfo = readPackageJson(path); core.setOutput("name", packageInfo.name); core.setOutput("version", packageInfo.version); core.setOutput("npmjs-link", `https://www.npmjs.com/package/${packageInfo.name}`); } catch (error) { core.setFailed(error.message); }

Команда core.getInput() получает значения импортированных переменных, а core.setOutput() экспортирует значения обратно в сценарий. Подробная информация о ключевых методах для работы с действиями доступна в описании пакета @actions/core

Также, не забудьте добавить README.md файл с описанием работы действия и всех параметров. А перед коммитом изменений выполните команду yarn build для актуализации файла со сборкой или настройте сценарий, который будет делать это за вас. 

Для того, чтобы использовать ваш Action в сценариях, необходимо создать версию с тегом. Для этого перейдите в раздел "Релизы" в репозитории проекта и создайте новый релиз. На этой же странице вам будет предложено опубликовать действие в маркетплейс, после чего оно появится в поиске.

Проверьте действие, использовав его в каком-нибудь сценарии. На момент написания заметки это единственный вариант тестирования корректности работы кода.

Полезные ссылки

Официальная документация по Actions от GitHub

Список доступных иконок и цветов для иконки действия

Примеры самодельных действий

Примеры сценариев, которые используются в проектах CodeX