Рецепты github shell action

от автора

Для приготовления github shell action нам понадобится github

В гитхабе действия можно написать тремя способами:

  1. на JavaScript

  2. в docker контейнере

  3. в интерпретаторе shell

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

К сожалению, полномочий встроенного ключа github_token не всегда хватает для выполнения необходимых действий, поэтому в первую очередь надо создать персональный ключ доступа с ограниченным скоупом public_repo и добавить его в секреты (скажем, под именем PUBLIC_REPO_ACCESS_TOKEN) в каждом своём репозитории.

Гитхаб действия будем запускать в ubuntu виртуалке или контейнере, что не столь важно, а важно то, что там уже установлены все необходимые программы. Т.к. при запуске действия гитхаб не клонирует репозиторий с текущим действием, то первым действием логично было бы сделать как раз это клонирование. Конечно, в гитхаб действиях уже есть стандартный инструмент для этого, но он написан на JavaScripte и выполняется в node.js, но мы-то делаем shell-действия! Итак,

1. Действие клонирования репозитория

Или git clone shell action

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

action.yml

name: git clone shell action # название действия description: git clone shell action # описание действия author: RekGRpth # автор действия runs: # запуски   using: composite # используя композитные действия   steps: # шаги     - run: "${GITHUB_ACTION_PATH}/action.sh" # запустить скрипт       shell: sh # в интерпретаторе sh

action.sh

#!/bin/sh  # показываем, что будем запускать # а также, выходим при ошибках # а также, считаем ошибкой отсутствие заданных переменных окружения # (что эмулирует обязательность параметров действия) set -eux # клонируем с прогрессом только одну ветку git clone --progress --single-branch \ # которую можно задать (необязательным) параметром-переменной     # (по-умолчанию - текущая ветка при выполнении действия) --branch "${INPUTS_BRANCH:-${GITHUB_REF##*/}}" \     # указываем пользователя репозитория     # а в качестве пароля - гитхаб токен     # и в конце собственно сам репозиторий     "https://${GITHUB_REPOSITORY_OWNER}:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" . 

Используем действие так:

.github/workflows/action.yml

... on: # когда запускать действие ... jobs: # работы   job: # работа     env: # через переменные окружения     # передаём секрет в качестве токена       GITHUB_TOKEN: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }}     runs-on: ubuntu-latest # запускаем в ubuntu     steps: # шаги     # клонируем текущий репозиторий       - uses: rekgrpth/git-clone-shell-action@v1 ...

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

2. Действие публикации релиза

Или github publish action shell action

action.yml точно такой-же, только название и описание — другие, а вот action.sh

#!/bin/sh  set -eux # с помощью программки гитхаб API (которая уже установлена в виртуалке/контейнере ubuntu) # сначала удаляем старый тег релиза репозитория с заданным тегом # (по-умолчанию - это текущая ветка) hub api --method DELETE "repos/${GITHUB_REPOSITORY}/git/refs/tags/${INPUTS_TAG:-${GITHUB_REF##*/}}" | jq . # затем вычисляем идентификатор старого релиза RELEASE_ID="$(hub api --method GET "repos/${GITHUB_REPOSITORY}/releases/tags/${INPUTS_TAG:-${GITHUB_REF##*/}}" | jq .id)" # и удаляем старый релиз hub api --method DELETE "repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}" | jq . # и, наконец, публикуем новый релиз hub api --method POST "repos/${GITHUB_REPOSITORY}/releases" --field "tag_name=${INPUTS_TAG:-${GITHUB_REF##*/}}" --field "target_commitish=${INPUTS_TAG:-${GITHUB_REF##*/}}" | jq . 

Используем действие так:

.github/workflows/action.yml

... on: ... jobs:   job:     runs-on: ubuntu-latest     steps:       - env:       # передаём токен           GITHUB_TOKEN: ${{ github.token }}         # публикуем релиз         uses: rekgrpth/github-publish-action-shell-action@v1

3. Действие ежегодного обновления лицензии

Или update license year shell action

action.sh

#!/bin/sh  set -eux # заменяем последний год (или добавляем его если нет) sed -Ei "s|^([Cc]opyright.+) ([0-9]{4})([-]?)([0-9]{4}?) (.+)$|\1 \2-$(date "+%Y") \5|g" \ "${INPUTS_LICENSE:-LICENSE}" # в лицензионном файле # задаём почту git config --local user.email "${INPUTS_EMAIL:-actions@github.com}" # и имя git config --local user.name "${INPUTS_NAME:-update license year}" # комиттим git commit --message "update license year" --all # и пушим git push --progress

Используем действие так:

.github/workflows/action.yml

... on:   schedule: # запускаем по крону     - cron: '0 0 1 1 *' # каждый год jobs:   job:     env:       GITHUB_TOKEN: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }}     runs-on: ubuntu-latest     steps:     # сначала клонируем репозиторий       - uses: rekgrpth/git-clone-shell-action@v1       # а потом обновляем в нём лицензию       - uses: rekgrpth/update-license-year-shell-action@v1

4. Действие обновления клонированного репозитория

Или git fetch upstream merge push shell action

action.sh

#!/bin/sh  set -eux # добавляем родительский репозиторий # (по-умолчанию с дефолтной веткой) git remote add --fetch --track "${INPUTS_BRANCH:-${GITHUB_REF##*/}}" \ # (по-умолчанию - с гитхаба, но можно задать и с гитлаба или ещё откуда) upstream "${INPUTS_URL:-${GITHUB_SERVER_URL}}/${INPUTS_REPOSITORY}.git" # задаём почту     git config --local user.email "${INPUTS_EMAIL:-actions@github.com}" # и имя git config --local user.name "${INPUTS_NAME:-git merge upstream}" # мержим git merge --allow-unrelated-histories "upstream/${INPUTS_BRANCH:-${GITHUB_REF##*/}}" # и пушим git push --progress

Используем действие так:

.github/workflows/action.yml

... on:   schedule:     - cron: '0 0 * * *' # каждый день jobs:   job:     env:       GITHUB_TOKEN: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }}     runs-on: ubuntu-latest     steps:     # клонируем репозиторий       - uses: rekgrpth/git-clone-shell-action@v1       - env:       # задаём родительский репозиторий           INPUTS_REPOSITORY: gawkextlib/code           # и откуда его брать           INPUTS_URL: git://git.code.sf.net/p         # обновляем наш репозиторий         uses: rekgrpth/git-fetch-upstream-merge-push-shell-action@v1

Тут надо сказать, что если в репозитории ничего не обновляется 60 дней, то гитхаб отключает такие действия по крону. Можно, наверное, написать действие по включению действий, а может, и нет…

5. Действие запуска другого действия в другом репозитории

Или github repository dispatch shell action

action.sh

#!/bin/sh  set -eux # с помощью гитхаб API запускаем другое действие в другом репозитории # (по-умолчанию, тип события - это текущая ветка) echo "{\"event_type\":\"${INPUTS_EVENT_TYPE:-${GITHUB_REF##*/}}\",\"client_payload\":${INPUTS_CLIENT_PAYLOAD}}" \ | hub api "repos/${INPUTS_REPOSITORY:-${GITHUB_REPOSITORY}}/dispatches" --input -

Используем действие так:

.github/workflows/action.yml

... on: ... jobs:   jon:     runs-on: ubuntu-latest     steps:       - env:           GITHUB_TOKEN: ${{ secrets.PUBLIC_REPO_ACCESS_TOKEN }}           # задаём сообщение           INPUTS_CLIENT_PAYLOAD: '{"repository":${{ toJson(github.event.repository.name) }}}'           # тип события           INPUTS_EVENT_TYPE: latest           # и репозиторий           INPUTS_REPOSITORY: ${{ github.repository_owner }}/${{ matrix.repo }}         # запускаем другое действие в другом репозитории         uses: rekgrpth/github-repository-dispatch-shell-action@v1     strategy: # с помощью стратегии       matrix: # одновременно запускаем         repo: # на несколкьих репозиториях:           - repo1           - repo2           - repo3

6. Действие сборки и публикации докер-образа

Или docker login build push shell action

action.sh

#!/bin/sh  set -eux export DOCKER_BUILDKIT=1 # используем новый сборщик # генерируем название образа REGISTRY_USERNAME_IMAGE_TAG="$(echo "${INPUTS_REGISTRY:-ghcr.io}/${INPUTS_USERNAME:-${GITHUB_REPOSITORY_OWNER}}/${INPUTS_IMAGE:-${GITHUB_REPOSITORY##*/}}:${INPUTS_TAG:-${GITHUB_REF##*/}}" | tr '[:upper:]' '[:lower:]')" # логигимся в докер echo "${INPUTS_PASSWORD:-${GITHUB_TOKEN}}" | docker login --username "${INPUTS_USERNAME:-${GITHUB_REPOSITORY_OWNER}}" --password-stdin "${INPUTS_REGISTRY:-ghcr.io}" # собираем образ docker build --progress=plain --tag "${REGISTRY_USERNAME_IMAGE_TAG}" . # и публикуем docker push "${REGISTRY_USERNAME_IMAGE_TAG}"

Используем действие так:

.github/workflows/action.yml

... on: ... jobs:   job:     concurrency: # если одновременно запущено несколько дейсвий       cancel-in-progress: true # отменяем все старые       group: ${{ github.ref }} # группируя по ветке     env:       GITHUB_TOKEN: ${{ github.token }}     # задаём название работы     name: ${{ github.event.client_payload.repository }} ${{ github.event_name }} ${{ github.event.branch }}     runs-on: ubuntu-latest     steps:     # клонируем репозиторий       - uses: rekgrpth/git-clone-shell-action@v1       # собираем и публикуем образ       - uses: rekgrpth/docker-login-build-push-shell-action@v1       # релизим       - uses: rekgrpth/github-publish-action-shell-action@v1


ссылка на оригинал статьи https://habr.com/ru/articles/582312/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *