Введение
Тэги в git используется для фиксирования каких-либо изменений. Как правило, данная функциональность применяется для версионирования. В данной заметке будет рассмотрена настройка pipeline Gitlab CI, в котором выполняется тэгирование версии разработанного кода напрямую из pipeline.
Примеры будут выполняться на базе приложения, написанного на NodeJS. В корне репозитория располагается файл package.json, в котором вручную указывается версия разрабатываемого приложения – эта версия и будет служить в качестве тэга.
Схема работы
- Изменения отправляются в ветку master\main, срабатывает pipeline
- На сервере с gitlub-runner выполняется клонирование репозитория в домашнюю директорию gitlab-runner
- Из package.json считывается версия, фиксируется в файле variables.txt как артефакт для возможности передачи сведений в следующие стадии
- Локально создаётся тэг и пушится в Gitlab
Одной из проблем, с которой придётся столкнуться при выполнении данной задачи, является вызов pipeline из pipeline при выполнении команды git tag. Возможные решения этой проблемы будут описаны ниже.
Реализация
В веб-интерфейсе Gitlab необходимо пользователя, добавить его в проект, и создать токен пользователю с правами на чтение\запись через API. После создать переменную, содержащую токен, по пути Settings->CI\CD->Variables с токеном. Важно не забыть обеспечить минимальную приватность переменной, поставив галку Mask variable:
В .gitlab-ci.yaml используется следующий код:
check_version:
stage: check_version
artifacts:
paths:
- vars.txt
expire_in: 1 week
before_script:
- echo export APP_VERSION=$(node -p "require('./package.json').version") >> vars.txt
- echo export APP_NAME="${CI_PROJECT_NAME}" >> vars.txt
- source vars.txt
script:
- "git config --global user.email 'robot@domain.ru'"
- "git config --global user.name 'robot'"
- "git remote set-url origin https://oauth2:${CI_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}.git"
- >
if [ $(git tag -l v"${APP_VERSION}") ]; then
echo "Tag for v${APP_VERSION} already exists, increment version number" && exit 1
else
echo "Create tag v${APP_VERSION}"
git tag -a v${APP_VERSION} -m ${CI_COMMIT_SHA}
git push -o ci.skip origin v${APP_VERSION}
fi
rules:
- if: "$CI_COMMIT_REF_NAME == 'master' && $CI_PIPELINE_SOURCE != 'merge_request_event'"
Небольшое пояснение:
- В блоке before_script парсится версия приложения и отправляется в артефакт vars.txt. Туда же отправляется имя репозитория из встроенной переменной Gitlab CI. В дальнейшем этот артефакт подключается в других job.
- В блоке script опять же из встроенных переменных Gitlab CI формируется удаленный репозиторий в .git/config, проверяется наличие уже созданного тэга во избежание ошибок
- Создание тэга выполняется через простую команду git tag, но используется конструкция
-o skip.ci
– это фича git версии 2+, которая формирует переменные, а Gitlab CI их перехватывает и тем самым в данном месте не триггерится новый pipeline
Заключение
Рассмотрен простой вариант создания тэга в gitlab CI. Существует несколько возможностей реализации, git tag – самая простейшая из имеющихся, но также есть возможность тэгирования через API гитлаба. Например, так:
curl -X POST --silent "${CI_SERVER_URL}/api/v4/projects/${CI_PROJECT_ID}/repository/tags?tag_name=${APP_VERSION}&ref=${CI_COMMIT_SHA}&private_token=${CI_TOKEN}"