Github actions: базовые понятия

Что это такое и как удаленно прогонять тесты на каждый пуш при помощи одного крошечного конфига

Katya Pavlenko
6 min readJul 13, 2020

Поговорим про:
* что такое github actions
* как запускать их в своем репозитории
* более сложные вопросы про настройку конфига
* Продолжение: как написать собственный action на javascript

Что такое github actions вообще?

Это указание гитхабу запускать какой-то код каждый раз когда случается некое событие. Push, создание PR, таймер, внешнее событие, а также всякие другие.
Где запускается этот код? На виртуальных машинах гитхаба(но при желании можно и на своих гонять). Удобно, можно ничего не настраивать.
Что он делает? Да что угодно, насколько хватит фантазии, главное — позволяет автоматизировать какие-то действия, нужные для вашего процесса разработки: гонять тесты, собирать и деплоить продукты, собирать статистику, оповещать людей.

Таким образом github предоставляет возможность не только прикрутить неплохой бесплатный CI/CD(как раньше умел только gitlab, о котором у меня тоже была статья), но и создать очень гибкую и легко конфигурируемую систему поддержки разработки.

Звучит классно

Тут все восхитительно просто.

Для начала нужно придумать, что же хочется сделать. Потом найти готовый экшен/несколько, которые позволят это сделать. Их проще всего искать в github marketplace — по сути это просто список репозиториев, которые подали заявку, чтобы быть там. На самом деле вы будете ссылаться на конкретный репозиторий конкретного пользователя.

Если подходящие готовые не находятся, всегда можно написать свой. Это очень просто. Я, например, написала экшен, чтобы интегрировать jira в пулл-реквесты:

Пока что давайте разберем самый простой пример — пусть на каждый пуш в любой ветке гоняются тесты(пример будет про js-разработку)

В первую очередь нужно создать в своем проекте папку .github, а в ней папку. workflows, а в ней файл name-matters-only-for-you.yaml

контент у него будет такой:

name: 'test my project'
on:
push:
pull-request:
jobs:
test-job:
runs-on: ubuntu-16.04
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
name: 'setup node'
with:
node-version: '13.x'

- name: 'install'
run: npm i

- name: 'test'
run: npm run test

Тогда в интерфейсе гитхаба прогоны будут выглядеть вот так:

история запуска
А внутри каждого запуска вот так

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

# имя, чтобы отображалось в интерфейсе
name: 'test my project'
# тут список событий, на который экшен должен запускаться
on:
push: # пусть гоняется на любой пуш
pull-request: # и на пулл-реквест
# список того, что нужно делать. каждый job будет выводиться отдельным элементом слева UI
jobs:
test-job: # uniqe id
runs-on: ubuntu-16.04 # на какой машине гонять
steps: # список шагов, разберем подробнее отдельно ниже
- uses: actions/checkout@v2
....

Steps

  1. Весь конфиг пишется в yaml, поэтому важно следовать синтаксису и следить за отступами, новая сущность в списке начинается с
  2. Шаги — это по сути упорядоченный список. Они будут выполняться один за одним строго последовательно

Посмотрим еще раз на конфиг, тут видно, что у нас 4 шага, только у них почему-то разный набор параметров, как это работает?

steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
name: 'setup node'
with:
node-version: '13.x'

- name: 'install'
run: npm i

- name: 'test'
run: npm run test
  • name нужен просто для отображения в интерфейсе, без него прекрасно можно обойтись
  • uses тут указываем имя какого-то уже написанного экшена, если хотим его использовать. Экшен может быть конкретным бранчем в конкретном репозитории(любом), может быть вообще кодом, лежащим в соседней папке, а может быть и вовсе docker-image(полный список)
    В примере используется actions/checkout@v2 и actions/setup-node@v1 . По названию легко можно найти их в marketplace, посмотреть исходный код конкретной версии(она идет после @ в названии) и понять, что они делают. checkout делает pull репозитория и ветки, в котором запущен. Таким образом мы получаем доступ к коду. Без этого экшена делать npm i было бы не на чем.
    setup-node устанавливает ноду, чтобы мы могли дальше использовать ее
  • with если шаг использует экшен, то иногда в него хочется передать параметры. Параметры регламентированы самим экшеном. В примере мы можем указать версию ноды, необходимую для нашего проекта
  • run запускает какую-то команду в shell. Использовать shell-команду вместе с экшеном не получится, они должны жить в разных шагах

После того, как этот файл добавлен и запушен в master, на каждый дальнейший пуш будет прогоняться наш скрипт с тестами.
Если это был просто пуш, результат можно будет увидеть в списке коммитов. Если пулл-реквест — в саммари внизу

обратите внимание — галочка только у тех коммитов, которые были последними после очередного пуша

Вот и все, разобрали маленький пример, ура, можно дерзать!
Чтобы было проще, собрала список вещей, которые узнала, когда дерзала сама

Более сложные вопросы:

Как передать какой-нибудь токен, нигде его не публикуя? Или что такое secrets в конфигах?

Всякие токены доступа, опубликованные в публичном доступе, это большой риск для вашей секьюрности. Как передавать их в зашифрованном виде? Гитхаб уже позаботился об этом, создав secrets. Их можно найти в любом репозитории: settings -> secrets. Там можно создать секрет с почти любым именем, например, MY_TOKEN, добавить к нему значение, и тогда в любом экшене можно будет написать secrets.MY_TOKEN , и это значение будет использоваться

Прикольные вещи:
1. Один раз создав и сохранив секрет, посмотреть его значение будет уже нельзя, только обновить
2. Если попытаться вывести значение секрета в логах или внутри кода экшена, выведется ***
3. Однако лучше не логгировать секреты вообще, так как любую защиту такого рода все же можно обойти

Как добавить secrets.GITHUB_TOKEN, который нужен в конфиге?

Все секреты с именами, начинающимися на GITHUB — служебные и подставляются гитхабом автоматически. Можно не переживать, просто напишите {{ secrets.GITHUB_TOKEN }} и все будет работать

Как сделать так, чтобы нельзя было замержить пулл-реквест если тесты упали?

Нужно пойти в настройки репозитория и у становить там правила для мержа в master, выбрав галочкой workflow, содержащий важные тесты

Как передать результат работы одного шага в другой шаг?

Это очень классная фича! При помощи кода ниже я проверяю, есть ли измененные файлы после билда в папке lib и, если есть, делаю коммит с обновленной сборкой. Переменные, добавленные в шаге, доступны в любом следующем шаге этого же job

- name: "check if build has changed"
run: echo ::set-env name=DIFF::$(git diff --stat -- 'lib')

- name: "Commit files"
if: ${{ env.DIFF }}
run: git commit -m "build action" -a

Как передать результат работы между джобами?

Тут немного веселее!

jobs:
first-job:
- name: "check if build has changed"
id: has-diff
run: echo ::set-output name=DIFF::$(git diff --stat -- 'lib')

outputs:
diff_output: ${{ steps.has-diff.outputs.DIFF }}

second-job:
needs: build-test
steps:
- name: "print diff"
run: echo "${{ needs.build-test.outputs.diff_output }}"

Важно помнить, что и output, и env-параметры это строки, которые могут содержать специальные символы. Поэтому при выводе в консоль необходимо это учитывать, иначе можно получить вот такую ошибку, если написать run: echo ${{ needs.build-test.outputs.diff_output }} без кавычек:

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

--

--

Katya Pavlenko

frontend developer, love instant noodles and super simple explanations of complex things Github: https://github.com/cakeinpanic