skip to content
Архитектура в курилке

Отлаживаем Github Action-ы локально

/ чтиво на 4 минуты

Содержание

Проблематика

У нас есть какой-то проект, возможно даже с тестами, линтерами, возможно над ним работает 2, а то даже и 3(!) человека. И вся эта радость у нас лежит на Github.

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

Success

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

Конечно, самый просто вариант - это создать новую ветку, в которую мы будем пушить изменения, в надежде, что вот-вот, сейчас то оно заработает. Это все прекрасно, но можно же и не ждать, а просто запустить нужную утилитку.

Act

Act

Ссылка на гитхуб

Ссылка на сам сайт проекта

По сути своей - это лишь обертка над существующими образами github-action-ов.

Единственный пререквизит - запущенный docker (или podman).

По сути своей все просто - ставите Вашими любимым пакетным менеджером

Terminal window
brew install act
sudo pacman -S act

или просто качаем готовый бинарь

Terminal window
curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash

Первый запуск

При первом запуске act Вам будет предложено на базе какого образа будет производиться запуск всех workflow. Пока рекомендую выбирать Medium, в дальнейшем все можно будет поменять.

Первый запуск Act

Это может занять длительное время в зависимости от размера образа и Вашего интернета.

Как только образ будет скачан, act произведет прогон Action-а для события pull_request (в данном примере).

Работа

Рассмотрим на примере простого приложения nodeJs, в котором просто прогоняются линтеры на Pull Request-ах:

name: Linting
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
with:
node-version: "lts/*"
- name: Install dependencies
run: npm install
- name: Run Astro checks
run: npm run check
- name: Run ESLint
run: npm run lint

Флоу стандартный: создаем новую ветку, в .github/workflows/rust.yml пишем наши правки. Далее начинается самое интересное.

Act локально запускает те workflow, для которых при запуске ему были переданы аргументы. Так в нашем случае будем проверять создание Pull Request-а, а значит запустим

Terminal window
act pull_request

И получим

Act nodejs

Action прошел все хорошо, Вы великолепны! Так можно локально прогонять практически любые Action-ы перед их деплоем в сам Github.

Кастомные образа

Теперь рассмотрим немного неожиданный, но интересный пример. В репе с Rust кодом нам предлагют простенькие Action-ы:

Suggested workflows

Самый банальный workflow - проверяет, что приложение собирается и тесты проходят. Тригерится неа все пуши в main и на Pull Request-ы в него же.

name: Rust
on:
push:
branches:
- main
pull_request:
branches:
- main
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose

Попробуем запустить его как и раньше, но получим ошибку:

Terminal window
[Rust/build] ⭐ Run Main Build
[Rust/build] 🐳 docker exec cmd=[bash -e /var/run/act/workflow/1] user= workdir=
| /var/run/act/workflow/1: line 2: cargo: command not found
[Rust/build] ❌ Failure - Main Build
[Rust/build] exitcode '127': command not found, please refer to https://github.com/nektos/act/issues/107 for more information
[Rust/build] ⭐ Run Complete job
[Rust/build] ✅ Success - Complete job
[Rust/build] 🏁 Job failed
Error: Job 'build' failed

Это связано с тем, что в самих образах, на которых Github гоняет Action-ы куда больше установлено, и весят они соотвественно. Можно попробовать выбрать более жирный образ, но с ним тоже могут быть проблемы (как пишут в issue)

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

Сам необходимый образ был нарыт в DockrHub-е автора

Так команда становится уже

Terminal window
act -P ubuntu-latest=catthehacker/ubuntu:rust-latest pull_request

И в итоге видим заветное:

Terminal window
[Rust/build] ✅ Success - Main Run tests
[Rust/build] ⭐ Run Complete job
[Rust/build] Cleaning up container for job build
[Rust/build] ✅ Success - Complete job
[Rust/build] 🏁 Job succeeded

Аналогичным образом можно подговить образ локально и указать его.

За основу я решил взять базовый образ Ubuntu:

FROM catthehacker/ubuntu:act-latest
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"

Здесь мы просто ставим последнюю версию утилит для Rust-а и билдим образ:

Terminal window
docker build -t test .

Готово, можем убедиться, что в образе есть все необходимое:

Docker cargo

Теперь для того, чтобы act не скачивал образа, а брал только локальные, добавим параметр --action-offline-mode и наш локальный образ (в данном случае test):

Terminal window
act --action-offline-mode -P ubuntu-latest=test pull_request

После этого Action-ы тоже работают:

Terminal window
[Rust/build] ✅ Success - Main Run tests
[Rust/build] ⭐ Run Complete job
[Rust/build] Cleaning up container for job build
[Rust/build] ✅ Success - Complete job
[Rust/build] 🏁 Job succeeded

Таким образом можно накручивать любой необходимый функционал, которого нет в образах автора.

Заключение

Автор позиционирует свое творение как аналог Makefile-а, чтобы единым источником правды была папка .workflows с более воспроизводимым окружением. Тут уже больше на цвет и вкус.

Больше примеров использования и параметров можно найти в документации.

Еще можете заглянуть и попробовать расширение для Vs Code.

По мере возможности буду добавлять что-то новое.

Всего доброго!