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

Когда я услышал новости, я подумал, как это работает с Travis CI, который мы также используем, а затем я подумал, что автоматизация линтинга с помощью Actions - это первый логический шаг (и сейчас мы используем это, хотя это все еще в разработке!)

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

Итак, давайте рассмотрим некоторые из моих знаний, и в этой статье мы создадим простое действие GitHub. Мы выполним действие, которое запускается при любой фиксации, и рассмотрим сообщение фиксации.

Как выполняются действия - создание основы для нашего проекта

Первый шаг - и самый простой - это настройка нашего репозитория.

Довольно аккуратно. По сути, каждое действие выполняется в контейнере Docker, которому предоставляется разнообразный контекст из Github (переменные среды, имеющийся репозиторий), который затем может хорошо выполняться ... все, что вы можете в контейнере Docker!

По большому счету, первое, что я узнал из этого процесса, - это то, насколько мне не хватает знаний в отношении написания сценариев bash, но я поделюсь некоторыми интересными приемами и передовыми практиками, которые я нашел в ближайшее время!

Действие разбито так:

+-- Dockerfile
+-- README.md
+-- your_entry_script.sh
+-- ... any additional folders for organization

Dockerfile может быть настолько простым или сложным, насколько вы хотите, но в конечном итоге это место для установки небольших метаданных Action (LABEL и т. Д.), Установки зависимостей и инициализации команды ввода для контейнера. . Вот что использует наш проект сообщений git commit, который вы можете скопировать в качестве отправной точки:

FROM alpine:latest
LABEL "com.github.actions.name"="git-commit-message-check"
LABEL "com.github.actions.description"="Check the quality of the git commit message"
LABEL "com.github.actions.icon"="check-square"
LABEL "com.github.actions.color"="yellow"
RUN apk add --no-cache \
    jq \
    curl \
    git
COPY "run-git-message-check.sh" /usr/bin/run-git-message-check
CMD ["sh", "/usr/bin/run-git-message-check"]

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

Этот образ мышления начинается с корня, с минимального контейнера Docker alpine. Этот контейнер содержит самое необходимое, поэтому необходимо установить любую зависимость, даже такую ​​распространенную, как curl.

Мы устанавливаем еще несколько зависимостей, которые потребуются нашему сценарию (скоро вы увидите!), А затем КОПИРУЕМ наш основной сценарий в контейнер. Обратите внимание, что вам нужно chmod + x свой скрипт локально, чтобы гарантировать, что при копировании он будет исполняемым!

Создание сценария оболочки (и что я узнал о bash)

Теперь вы можете писать на любом языке, который будет работать в контейнере Docker, но было весело попробовать поиграть мои (несуществующие) мускулы bash!

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

Интересный способ вникнуть в это - создать Action, который ничего не делает, а только выводит среду выполнения. Взглянем:

#!/bin/bash
set -e
set -o pipefail
main() {
   jq --raw-output . "$GITHUB_EVENT_PATH"
}
main

Добавьте это в свой проект как run-git-message-check.sh. На данный момент, имея только этот код оболочки и контейнер Docker, вы очень близки к добавлению действия. Если вы хотите сделать паузу и попробовать, я рекомендую прочитать документацию GitHub по Создание нового действия GitHub, поскольку в ней подробно описаны детали его развертывания, которых мы не будем рассматривать в этой статье. (В основном потому, что здесь мы сосредоточены на функциональности Action, а все остальное - соединяющие элементы!)

Мне нравится, насколько прост этот сценарий оболочки, и я узнал несколько полезных вещей:

  • set -e останавливает выполнение сценария оболочки всякий раз, когда возникает ошибка команды или конвейера. Это сохраняет наши действия достаточно разумными, и это что-то новое для меня в мире bash!
  • Так же я много узнал о pipefail! Об этом уже написано отличное письмо, поэтому я рекомендую прочитать его!
  • Я узнал о shellcheck, который засоряет ваш bash! В моем примере репо, связанном позже, я предоставляю средства использования этого против кода, который мы пишем.

Кроме того, я ввел этот шелл-код и контейнер Docker в рабочий процесс, и вы можете увидеть фрагмент вывода на вкладке «Действия» GitHub (для краткости вырезано):

### STARTED post git quality control 19:04:00Z

Pulling image: gcr.io/github-actions-images/action-runner:latest
latest: Pulling from github-actions-images/action-runner
cd784148e348: Already exists
1a34a342bc8b: Pulling fs layer
571706cf6933: Pulling fs layer
....
....
(5/10) Installing curl (7.61.1-r1)
(6/10) Installing expat (2.2.5-r0)
(7/10) Installing pcre2 (10.31-r0)
(8/10) Installing git (2.18.1-r0)
(9/10) Installing oniguruma (6.8.2-r0)
(10/10) Installing jq (1.6_rc1-r1)
Executing busybox-1.28.4-r2.trigger
Executing ca-certificates-20171114-r3.trigger
OK: 20 MiB in 23 packages
 ---> b3a1810ba635
Step 7/8 : COPY "run-git-mesage-check.sh" /usr/bin/run-git-message-check

Красивый! По сути, он создает и запускает контейнер Docker, и весь журнал содержится в этом выводе.

Среда выполнения

Как и выше, мы использовали jq для проверки GITHUB_EVENT_PATH,, который представляет собой полезный файл JSON с такими метаданными, как :

{
  "after": "1870aa8285a40ac84debc34885314b0553c1de55",
  "base_ref": null,
  "before": "b0dba7f5a0b290bfabcf4498ff19980f3c0b7fd6",
  "commits": [
    {
      "added": [],
      "author": {
        "email": "[email protected]",
        "name": "Bartek Ciszkowski",
        "username": "bartek"
      },
      "committer": {
        "email": "[email protected]",
        "name": "Bartek Ciszkowski",
        "username": "bartek"
      },
      "distinct": true,
      "id": "1870aa8285a40ac84debc34885314b0553c1de55",
      "message": "Fix COPY command in Docker",
      "modified": [
        "Dockerfile"
      ],
      "removed": [],
      "timestamp": "2019-01-15T21:14:45-05:00",
      "tree_id": "a791cf15588173a748df25d3b92208f31d384025",
      "url": "https://github.com/bartek/action-git-message/commit/1870aa8285a40ac84debc34885314b0553c1de55"
    }
  ],
...
}

Эти данные были получены, когда наш скрипт запустил команду jq в репозитории, который я создавал для этого проекта. Вы можете увидеть последний коммит (в котором я допустил опечатку в команде COPY). Вышеупомянутое - это лишь крошечный фрагмент метаданных, доступных вам в событии GitHub JSON.

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

Хорошо, давайте доработаем ядро ​​этого скрипта. Мне понравилась эта статья о лучших методах работы с сообщениями git, и в ней подчеркиваются следующие правила:

  1. Отделяйте тему от текста пустой строкой
  2. Ограничьте строку темы до 50 символов
  3. Используйте заглавные буквы в теме письма
  4. Не заканчивайте строку темы точкой
  5. Используйте повелительное наклонение в теме письма
  6. Оберните тело на 72 символа
  7. Используйте текст, чтобы объяснить что и почему по сравнению с как

Мой bash-foo прошел здесь серьезное испытание, поэтому я сосредоточился на соблюдении правила 2, добавив при этом возможность публиковать комментарии на GitHub для всех соответствующих ша коммитов. Я попытаюсь скрыть свое отсутствие навыков bash, сказав, что я сохраняю пример простым, чтобы быть кратким, но я уверен, что кто-то придет сюда, прочитает это и предоставит однострочник, чтобы свести мой скрипт к нулю (на самом деле - Я был бы признателен). Без дальнейших церемоний:

#!/bin/bash
set -e
set -o pipefail
URI=https://api.github.com
API_VERSION=v3
API_HEADER="Accept: application/vnd.github.${API_VERSION}+json; application/vnd.github.antiope-preview+json"
AUTH_HEADER="Authorization: token ${GITHUB_TOKEN}"
post_quality_control_message() {
   for i in ${!COMMIT_IDS[@]};
   do
      id=${COMMIT_IDS[$i]}
      curl -sSL -H "${AUTH_HEADER}" -H "${API_HEADER}" -d @quality_message.json -H "Content-Type: application/json" -X POST "${URI}/repos/${GITHUB_REPOSITORY}/commits/${id}/comments"
   done
}
main() {
   commits=$(jq --raw-output .commits "$GITHUB_EVENT_PATH")
COMMIT_IDS=()
   for row in $(echo "${commits}" | jq -r '.[] | @base64'); do
     message="$(echo "$row" | base64 --decode | jq -r '.message')"
if [ ${#message} -ge 50 ]; then
        COMMIT_IDS+="$(echo "$row" | base64 --decode | jq -r '.id')"
        continue
     fi
done
post_quality_control_message;
}
main

Для справки, весь этот код вы можете найти в моем репозитории.

Здесь происходит несколько вещей, но вкратце:

  • В качестве первого шага я использую jq для получения коммитов из данных события Github. Это снова файл JSON, предоставленный средой выполнения GitHub Actions.
  • Наше действие запускается всякий раз, когда в репозитории происходит какое-либо событие push (это определяется, когда вы выполняете фактический рабочий процесс), поэтому у нас есть контекст коммита git, среди других деталей в нашей среде.
  • Затем я напрягаю свои несуществующие мускулы bash и перебираю каждую фиксацию, которую нашел в JSON, фиксируя длину сообщения, проверяя, превышает ли она 50 символов или больше - и если да, сохраняя этот идентификатор фиксации для последующего отчета. .
  • Затем, перебирая все собранные идентификаторы фиксации, я использую GitHub API для отправки сообщения в комментарии к фиксации. Вот как это выглядит:

И с этим у нас есть функциональное действие GitHub.

То, что мы создали сегодня, бесполезно изолированно, но это дало нам некоторое представление о том, что могут делать GitHub Actions! Мы убедились, что получаем прекрасную и компактную среду выполнения, можем запускать множество произвольных команд и взаимодействовать с GitHub API.

Все это собрано вместе, и вы получите довольно мощную экосистему!

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

Мне нужно еще многому научиться, и я надеюсь, что вы сочли это хорошим началом. Я настоятельно рекомендую вступительный доклад о действиях GitHub, когда они были представлены на AWS re: Create ранее в 2018 году.

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

Следите за нами в Medium и Twitter, чтобы увидеть больше отрывков из мира технологий согласно G!

Хотите помочь G Adventures изменить жизнь людей и путешествовать по миру? Ознакомьтесь со всеми нашими вакансиями и подайте заявку сегодня.