Руководство по использованию act с GitHub Actions

Руководство по использованию act с GitHub Actions

Проект act - это мощный инструмент, который можно использовать вместе с GitHub Actions для быстрого тестирования и доработки конвейера непрерывной интеграции и непрерывной доставки (CI/CD). С помощью act вы можете локально использовать контейнеры Docker для прямого запуска этапов в GitHub Actions. act помогает разработчикам запускать независимые этапы конвейера и в целом улучшает цикл обратной связи при построении конвейеров с помощью GitHub Actions.

В этой статье мы представим act на примере проекта, установим его, а затем рассмотрим различные способы, которыми act может улучшить ваш опыт создания и тестирования GitHub Actions. Чтобы проследить за ходом работы, посмотрите мой пример проекта на GitHub. Давайте начнем!

Что такое GitHub Actions?

Прежде чем приступить к работе с act, мы должны получить базовое представление о том, как работают GitHub Actions. Подобно CI/CD инструментам, таким как CircleCI, Jenkins и другим, GitHub Actions позволяют вам определить конвейер в YAML-файле. Затем GitHub будет запускать ваш конвейер при определенных событиях, которые могут включать открытие запроса на притяжение или слияние с основной веткой.

Синтаксис GitHub Actions выглядит следующим образом:

name: Node.js CI
'on':
  push:
    branches:
      - master
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Use Node.js 16.x
        uses: actions/setup-node@v3
        with:
          node-version: 16.x
          cache: npm
      - run: npm install
      - run: npm run build

В приведенном выше примере действие GitHub Action определено с заданием сборки, которое проверяет ваш код, выполняет установку npm и собирает проект. У вас могут быть дополнительные задания, которые зависят от этого, но шаги могут быть и собственными действиями. Например, если вы хотите кэшировать модули node, вы можете просто добавить следующий код:

     - run: npm install
      - run: npm run build
      - name: Cache node modules
        uses: actions/cache@v3
        env:
          cache-name: cache-node-modules
        with:
          path: ~/.npm
          key: >-
            ${{ runner.os }}-build-${{ env.cache-name }}-${{
            hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-build-${{ env.cache-name }}-

actions/cache@v3 - это собственное действие, которое выполняется как шаг в этом конвейере. Вы также можете создать эти действия. Например, включив их в своем репозитории GitHub, вы можете запускать CI/CD на pushes to master и другие события. В GitHub это выглядит следующим образом:

Синтаксис сборки GitHub Actions Build

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

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

Как использовать act?

act работает как CLI на вашей локальной машине, поддерживая Linux, Mac и Windows. Я работаю на Mac, поэтому я использовал brew для установки act следующей командой:

brew install act

Чтобы узнать больше об установке, ознакомьтесь с инструкциями в репозитории GitHub.

После установки act использовать его очень просто. Внутри папки .github в вашем репозитории вызовите CLI непосредственно с помощью act из терминала внутри проекта, в котором настроен YAML-файл действия GitHub. Если у вас еще не настроены действия GitHub, нажмите на опцию actions в верхней части вашего проекта GitHub, и GitHub проведет вас через создание начального YAML-файла:

Github Actions Настройка Yaml-файла
GitHub Actions Редактирование файла YAML

Существует множество различных вариантов, но наиболее полезными мне показались следующие:

# List all the actions in your YAML file
act -l

# List actions for a specific event (here the event is push)
act push -l

# Get Act to run the workflow as if a specific push to master event occured
act push

# Get Act to run a specific job
act -j test

# pass secrets into a job so that the GitHub action can consume them
act -s MY_TOKEN_SECRET=<token> -s MY_NETLIFY_SITE_ID=<site_id> 

# run a GitHub action that uses artifacts between jobs
act --artifact-server-path /tmp/artifacts push

При выполнении этих команд act создает контейнер Docker для запуска ваших действий на GitHub. Образы, перечисленные в проекте act на GitHub, включают следующие:

Github Actions Создание Docker-контейнера

Если в задании GitHub Action указан образ для использования, оно извлекает этот образ и запускает его в контейнере act для выполнения работы.

Смотрим на Act в действии

Как я уже говорил во вступлении, я использовал пример проекта с Act для проверки некоторых функций. Проект представляет собой очень простое, базовое приложение для составления списка дел на React. Я включил один тест, для которого я мог создать этап в конвейере, а также включил этап для развертывания в Netlify.

Код ниже представляет собой фактический YAML-файл, который я создал для GitHub Actions в этом проекте:

name: Node.js CI
'on':
  push:
    branches:
      - master
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/[email protected]
      - name: Use Node.js 16.x
        uses: actions/[email protected]
        with:
          node-version: 16.x
          cache: npm
      - run: npm install
      - run: npm run build
      - name: Cache node modules
        uses: actions/[email protected]
        env:
          cache-name: cache-node-modules
        with:
          path: ~/.npm
          key: >-
            ${{ runner.os }}-build-${{ env.cache-name }}-${{
            hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-build-${{ env.cache-name }}-
      - name: Archive production artifacts
        uses: actions/[email protected]
        with:
          name: built-project
          path: build
          retention-days: 1
  test:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/[email protected]
      - name: Use Node.js 16.x
        uses: actions/[email protected]
        with:
          node-version: 16.x
          cache: npm
      - name: Download build for testing
        uses: actions/[email protected]
        with:
          name: built-project
      - run: npm install
      - run: npm run pipeline-test
  deploy:
    needs: [build, test]
    runs-on: ubuntu-latest
    name: 'Deploy to Netlify'
    steps:
      - uses: actions/[email protected]
      - name: Download build for deployment
        uses: actions/[email protected]
        with:
          name: built-project
      - uses: jsmrcaga/[email protected]
        with:
          NETLIFY_AUTH_TOKEN: ${{ secrets.MY_TOKEN_SECRET }}
          NETLIFY_SITE_ID: ${{ secrets.MY_NETLIFY_SITE_ID }}
          NETLIFY_DEPLOY_TO_PROD: true
          build_command: "echo build command not required since we are using artifacts"

Как видите, у меня три разных работы:

  • build: Собирает проект, кэширует модули узла и кэширует собранные активы.
  • test: Запускает связанные с проектом тесты. В данном случае это только один файл App.test.tsx.
  • deploy: Берет активы, которые были собраны в первом задании, и затем развертывает их в Netlify с помощью Netlify Deploy GitHub Action.

Задание тестирования зависит от задания сборки, а задание развертывания зависит от заданий тестирования и сборки. Я также использовал кэширование и хранение артефактов между этапами. Эти темы выходят за рамки данной статьи, но для справки я рекомендую ознакомиться с документацией по Actions на GitHub.

Используя Act в этом конвейере, я смог сделать несколько вещей, включая независимый запуск заданий, а также прямой просмотр данных о заданиях. Мне это показалось очень полезным, поскольку я мог строить конвейер без необходимости напрямую взаимодействовать с консолью GitHub. Это сэкономило значительное время, которое в противном случае я бы потратил на развертывание и обновление YAML-файла, а затем на ожидание завершения работы консоли.

В примере проекта я перечислил связанные задания следующим образом:

➜  getting-started-with-act git:(master) act -l
WARN  ⚠ You are using Apple M1 chip and you have not specified container architecture, you might encounter issues while running act. If so, try running it with '--container-architecture linux/amd64'. ⚠  
Stage  Job ID  Job name           Workflow name  Workflow file  Events
0      build   build              Node.js CI     node.js.yml    push  
1      test    test               Node.js CI     node.js.yml    push  
2      deploy  Deploy to Netlify  Node.js CI     node.js.yml    push  

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

➜  getting-started-with-act git:(master) act push -l
WARN  ⚠ You are using Apple M1 chip and you have not specified container architecture, you might encounter issues while running act. If so, try running it with '--container-architecture linux/amd64'. ⚠  
Stage  Job ID  Job name           Workflow name  Workflow file  Events
0      build   build              Node.js CI     node.js.yml    push  
1      test    test               Node.js CI     node.js.yml    push  
2      deploy  Deploy to Netlify  Node.js CI     node.js.yml    push  

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

➜  getting-started-with-act git:(master) act -j build
WARN  ⚠ You are using Apple M1 chip and you have not specified container architecture, you might encounter issues while running act. If so, try running it with '--container-architecture linux/amd64'. ⚠  
[Node.js CI/build] 🚀  Start image=node:16-buster-slim
[Node.js CI/build]   🐳  docker pull image=node:16-buster-slim platform= username= forcePull=false
[Node.js CI/build]   🐳  docker create image=node:16-buster-slim platform= entrypoint=["tail" "-f" "/dev/null"] cmd=[]
[Node.js CI/build]   🐳  docker run image=node:16-buster-slim platform= entrypoint=["tail" "-f" "/dev/null"] cmd=[]
[Node.js CI/build]   ☁  git clone 'https://github.com/actions/setup-node' # ref=v3
[Node.js CI/build]   ☁  git clone 'https://github.com/actions/cache' # ref=v3
[Node.js CI/build]   ☁  git clone 'https://github.com/actions/upload-artifact' # ref=v3
[Node.js CI/build] ⭐ Run Main actions/[email protected]
[Node.js CI/build]   🐳  docker cp src=/Users/andrewevans/Documents/projects/getting-started-with-act/. dst=/Users/andrewevans/Documents/projects/getting-started-with-act
[Node.js CI/build]   ✅  Success - Main actions/[email protected]
[Node.js CI/build] ⭐ Run Main Use Node.js 16.x
[Node.js CI/build]   🐳  docker cp src=/Users/andrewevans/.cache/act/[email protected]/ dst=/var/run/act/actions/[email protected]/
[Node.js CI/build]   🐳  docker exec cmd=[node /var/run/act/actions/[email protected]/dist/setup/index.js] user= workdir=
[Node.js CI/build]   💬  ::debug::isExplicit: 
[Node.js CI/build]   💬  ::debug::explicit? false

Если я хочу запустить задания сборки и тестирования вместе, мне нужно указать местоположение для артефактов. Действие GitHub Action, передающее артефакты между заданиями, использует местоположение по умолчанию на серверах GitHub.

Поскольку я запускаю его локально в контейнере Docker, мне нужно указать местоположение, которое он будет использовать в контейнере. На изображениях ниже вы можете видеть, как задание запускается, а затем успешно создается и сохраняется артефакт:

[Node.js CI/build]   🐳  docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/3] user= workdir=
| 
| > [email protected] build
| > react-scripts build
| 
| Creating an optimized production build...
| Compiled successfully.
| 
| File sizes after gzip:
| 
|   47.11 kB  build/static/js/main.172f414d.js
|   1.79 kB   build/static/js/787.de4328d8.chunk.js
|   313 B     build/static/css/main.51a848c0.css
| 
| The project was built assuming it is hosted at /.
| You can control this with the homepage field in your package.json.
| 
| The build folder is ready to be deployed.
| You may serve it with a static server:
| 
|   npm install -g serve
|   serve -s build
| 
| Find out more about deployment here:
| 
|   https://cra.link/deployment
| 
[Node.js CI/build]   ✅  Success - Main npm run build
[Node.js CI/build] ⭐ Run Main Cache node modules

Часто у вас есть секреты, которые нужно передать определенным заданиям. При работе с act это можно сделать непосредственно в командной строке с помощью следующего кода:

act -s MY_SECRET=<first_secret> push 

Есть много других вещей, которые можно делать с помощью act в процессе разработки. Мне показалось очень полезным иметь возможность запускать задания независимо для отладки возникающих проблем.

Как я уже говорил ранее, я также включил этап развертывания для загрузки артефактов в Netlify. У меня были некоторые проблемы с передачей маркеров, и в конечном итоге я понял, что это была проблема со способом генерации маркера в Netlify. Тем не менее, вы можете видеть, как можно использовать этап развертывания. Вы можете протестировать это с другими провайдерами, такими как AWS, Azure и т.д.

Заключение

Эта статья - лишь вершина айсберга того, что вы можете сделать с помощью act. Запустив Docker вместе с act, я смог увидеть запущенные контейнеры и образы, которые были стянуты. Я также прошел через множество итераций, выполняя части заданий, а затем обращаясь к документации, чтобы очистить код. Это очень помогло в разработке конвейера, даже если он был очень простым.

Я настоятельно рекомендую ознакомиться с проектом act и прочитать о нем больше в README репозитория. Я обнаружил, что у act довольно сильное сообщество, поэтому все проблемы, которые я видел, обычно имели связанную с ними проблему на GitHub, к которой я мог обратиться за помощью.

Спасибо за чтение!