Использование Github Actions и Bash для создания динамического профиля Github
4 июня 2022 г.Около года назад Github запустил функцию, которая позволяет добавлять README в профиль пользователя. Чтобы добавить README в свой профиль, вам необходимо:
- создайте общедоступный репозиторий с именем, совпадающим с вашим именем пользователя Github.
- поместите
README.md
в корень репозитория
Вы можете узнать больше об этом в документации Github.
Что такое динамический профиль Github?
Динамический профиль Github обновляется автоматически по какому-либо внешнему событию или по расписанию. Это возможно с использованием Github Actions. Github Actions — еще одна недавно выпущенная функция Github. Github Actions — это, по сути, система CI/CD, которая позволяет создавать и запускать настраиваемые рабочие процессы.
Впервые я узнал о профиле README в этой статье на Hackernoon. Парень использовал PHP для получения и обновления списка последних сообщений в своем блоге. Хотя я эксперт по PHP, я хотел сделать его более сложным. Я понял, что синтаксический анализ XML и замена текста в файле достижимы только с помощью собственных инструментов Bash.
Парсинг RSS-канала
RSS-канал — это обычный XML-файл с простой схемой. Вот пример из моего только что запущенного блога:
```разметка
<канал>
<ссылка>https://atabakoff.com/posts/
<изображение>
<ссылка>https://atabakoff.com/aleksandr_tabakov.jpeg
<элемент>
https://atabakoff.com/how-to-run-vaultwarden-in-podman-as-a-systemd-service/
Каждое сообщение представлено элементом item, где нам нужны title, link и pubDate.
Парсинг RSS-канала с помощью grep
Наивный подход состоит в том, чтобы использовать grep
, а затем построить уценку в цикле bash. Давайте сначала попробуем grep
:
``` ударить
wget --quiet -O rss.xml https://atabakoff.com/posts/index.xml
кот rss.xml | grep -Po '<(название|ссылка|дата публикации)>[^<]+'
<ссылка>https://atabakoff.com/posts/
<ссылка>https://atabakoff.com/aleksandr_tabakov.jpeg
<ссылка>https://atabakoff.com/how-to-run-vaultwarden-in-podman-as-a-systemd-service/
Неплохо, но нам нужно избавиться от первых трех строк и открывающего тега:
``` ударить
кот rss.xml | grep -Po '<(title|link|pubDate)>[^<]+' | хвост -n +4 \
| grep -oE '>([^>]+)' | grep -oE '([^>]+)'
Как запустить Vaultwarden в Docker/Podman в качестве службы systemd
https://atabakoff.com/how-to-run-vaultwarden-in-podman-as-a-systemd-service/
Пт, 27 мая 2022 21:33:51 +0200
Просто для проверки grep
https://atabakoff.com/testing-grep/
Пт, 31 мая 2022 18:33:51 +0200
Я добавил один дополнительный элемент, чтобы проверить, работает ли мое выражение с несколькими сообщениями. В этот момент я начинаю думать, что grep
может быть не лучшим вариантом. Я быстро написал конвертер для преобразования RSS в уценку, прежде чем исследовать другие варианты:
``` ударить
!/бин/баш
items=$( cat rss.xml | grep -Po '<(title|link|pubDate)>[^<]+' | tail -n +4 \
| grep -oE '>([^>]+)' | grep -oE '([^>]+)' )
ЕСЛИ=$'
'
количество = 0
для товара в $items
делать
case $(expr $count % 3) в
'0')
название = $ элемент
ссылка = ''
дата публикации = ''
'1')
ссылка=$элемент
'2')
pubDate=$(дата -d "$item" +'%d/%m/%Y' )
кошка<<EOF
- $pubDate $название
EOF
эсак
количество = $ (($ количество + 1))
Выполнено
Запустите его для проверки:
``` ударить
./test.sh
- 05.03.2022 Только для проверки grep
Проверка производительности
Моя RSS-лента крошечная. Чтобы измерить производительность, нам нужно запустить парсер много раз. Я создал файл test.sh
:
``` ударить
!/бин/баш
х=100
в то время как [ "$x" -gt "0" ] ; делать
$(/bin/bash $1) 2>/dev/null
х=$((х-1))
Выполнено
Он принимает файл сценария в качестве параметра и запускает его 100 раз в цикле. Давайте запустим его с time
, чтобы увидеть, сколько времени требуется для анализа фида:
время ./test.sh grep-rss.sh
./test.sh grep.sh 1,87 с пользователь 0,72 с система 137% ЦП 1,883 всего
Не очень впечатляюще, но ожидаемо из-за использования регулярных выражений.
Парсинг RSS-канала в Bash
Я начал гуглить, есть ли способ разобрать XML в Bash, и нашел это [отличное решение] (https://www.linuxjournal.com/content/parsing-rss-news-feed-bash-script). Здесь описана та же проблема парсинга RSS-канала. Я изменил код для своих нужд и сохранил его в файле parse-rss.sh
:
``` ударить
!/бин/баш
xmlgetnext () {
местный IFS='>'
read -d '<' ЗНАЧЕНИЕ ТЕГА
кот $1 | пока xmlgetnext ; делать
случай $TAG в
'вещь')
название = ''
ссылка = ''
дата публикации = ''
'заглавие')
название=$ЗНАЧЕНИЕ
'ссылка на сайт')
ссылка=$ЗНАЧЕНИЕ
'дата публикации')
pubDate=$(дата -d "$VALUE" +'%d/%m/%Y' )
'/вещь')
кошка<<EOF
- $pubDate $название
EOF
эсак
Выполнено
Я провел тот же тест, чтобы сравнить производительность:
``` ударить
время ./test.sh parse-rss.sh
./test.sh parse.sh 0,81 с пользователь 0,33 с система 109% ЦП 1,042 всего
Почти в два раза быстрее: «1042» против «1883». Это последний подход, который я выбрал для обработки RSS-канала.
Обновление README.md
Обновление списка постов — это просто замена. Поскольку уценка позволяет использовать HTML-код, мы можем использовать HTML-комментарии, чтобы пометить заполнитель для сообщений:
```разметка
Стандартным инструментом для замены текста в Bash является sed
, но у него есть одно ограничение. Это строковый редактор, обрабатывающий только одну строку за один шаг. В нашем случае и заполнитель, и список постов представляют собой многострочный текст. Вот как я это решил:
``` ударить
!/бин/баш
ЧИСЛО=$(($2*3))
POSTS=$(cat $1 | head $NUM | tr '
' '\t')
кот README.md | тр '
' '\t' \
| sed -E "s#(<!--блог:начало-->).*(<!--блог:конец-->)#\1\t${Публикации}\2#g" \
| tr '\t' '
' > README.tmp
mv README.tmp README.md
rm -f rss.xml posts.md
Некоторые вещи, которые стоит пояснить:
NUM=$(($2*3))
— количество строк для указанного количества постов; в моем случае я хочу показать пять постов по три строки каждый (название, ссылка, дата)
tr '<br>' '\t'
должен преобразовать текст в одну строку для обработки с помощьюsed
tr '\t' '<br>'
возвращает символы новой строки
Конвейер действий Github
Теперь у нас есть наши сценарии, и нам нужно поместить их в конвейер. Действия Github просматривают специальный каталог .gihub/workflows
и обрабатывают там каждый файл .yaml
. Я создал там файл posts.yml
со следующим содержимым:
``ямл
name: Обновление сообщений в блоге
на:
толкать:
workflow_dispatch:
расписание:
- cron: '0 0 * '
вакансии:
обновить-readme-с-последними-сообщениями:
запуски: ubuntu-последняя
шаги:
- имя: Клонировать репозиторий
использует: action/checkout@v2
с:
глубина выборки: 1
- имя: Получить RSS-канал
выполнить: wget --quiet -O rss.xml https://atabakoff.com/posts/index.xml
- название: Разобрать RSS-канал
запустить: |
компакт-диск ${GITHUB_WORKSPACE}
./src/parse-rss.sh rss.xml > posts.md
- название: Обновление README.md
запустить: |
компакт-диск ${GITHUB_WORKSPACE}
./src/update-readme.sh posts.md 5
- имя: Нажмите изменения
запустить: |
git config --global user.name "${GITHUB_ACTOR}"
git config --global user.email "${GITHUB_ACTOR}@users.noreply.github.com"
git commit -am "Обновленные сообщения в блоге" | выход 0
git push
Вот что нужно пояснить:
push
- запускать по нажатию
cron: '0 0 * * *'
- это расписание, в моем случае каждый день в полночь
uses: action/checkout@v2
клонирует репозиторий
Затем я разделил получение, синтаксический анализ и обновление на отдельные этапы. Это позволяет мне быстро локализовать проблему, если что-то пойдет не так. Стоит отметить:
cd ${GITHUB_WORKSPACE}
должен перейти в текущий рабочий каталог, который является недавно клонированным репозиторием.
${GITHUB_ACTOR}
– ваше имя пользователя
${GITHUB_ACTOR}@users.noreply.github.com
— это специальный адрес электронной почты Github, который можно использовать для отправки изменений в репозиторий.
Вывод
Вы можете найти полное решение в репозиторий моего профиля. Было очень весело решать эту проблему с помощью чистого Bash.
При этом на Github существует множество действий сообщества. Они позволяют создать динамический профиль без написания кода. Все, что вам нужно сделать, это написать немного YAML. Но в этом мало сложностей. Это не путь воина.
Также опубликовано [здесь] (https://atabakoff.com/creating-a-dynamic-github-profile-with-github-actions-and-bash/).
Оригинал