GitLab: Custom hooks
Jul 10, 2017 09:58 · 584 words · 3 minute read
В GitLab Enterprise Edition существует довольно удобная, а порой и просто необходимая возможность дополнительной настройки правил обновления кода в репозитории под названием Push Rules.
В GitLab CE для реализации подобного функционала приходится использовать кастомные git-хуки — давайте разберемся, как их правильно готовить!
Git изначально поддерживает хуки (hooks), которые выполняются при определенных действиях — например, pre-receive
, post-receive
, update
… Больше о хуках можно прочитать здесь, а мы приступим к рассмотрению конкретного примера настройки кастомного (custom) хука для GitLab CE.
Считаем, что у нас используется docker-установка GitLab, как описано в этой статье. Тогда для создания кастомного git-хука, который запрещает пуш файлов размером больше 5Mb в репозиторий необходимо проделать следующие шаги:
- выбрать проект, для которого необходимо сделать кастомный хук;
- на сервере с GitLab перейти в каталоге репозитория проекта (в нашем случае —
/srv/gitlab/data/repositories/MYGROUP/MYREPO.git/
) создать новый каталог с именемcustom_hooks
:
mkdir -p /srv/gitlab/data/repositories/MYGROUP/MYREPO.git/custom_hooks
- в каталоге …/custom_hooks создать файл с именем, соответствующим типу хука (например, для
pre-receive
хука файл должен называтьсяpre-receive
) без расширения:
touch /srv/gitlab/data/repositories/MYGROUP/MYREPO.git/custom_hooks/pre-receive
- сделать файл исполняемым и рекурсивно сменить владельца директории
custom_hooks
на пользователя, от которого запускаются docker-контейнеры (обычно у него id=1000):
chmod +x /srv/gitlab/data/repositories/MYGROUP/MYREPO.git/custom_hooks/pre-receive
chown -R 1000:1000 /srv/gitlab/data/repositories/MYGROUP/MYREPO.git/custom_hooks/
- в созданном файле написать git-хука (можно использовать любой язык программирования, главное не забыть в первой строке вставить “shebang” —
!#
). В нашем случае хук, выглядит так:
#!/bin/sh
GITCMD="/usr/bin/git"
NULLSHA="0000000000000000000000000000000000000000"
MAXSIZE="5242880" # 5MB limit on file size
EXIT=0
# Read stdin for ref information
while read oldref newref refname; do
# Skip branch deletions
if [ "${newref}" = "${NULLSHA}" ]; then
continue;
fi
# Set oldref properly if this is branch creation.
if [ "${oldref}" = "${NULLSHA}" ]; then
oldref="HEAD"
fi
# Get list of files to look at using git diff
for file in $($GITCMD diff --stat --name-only --diff-filter=ACMRT ${oldref}..${newref}); do
# Get the size of this file
size=$($GITCMD cat-file -s ${newref}:${file})
# Check to see if for some reason we didn't get a size
if [ ! -z ${size} ]; then
# Compare filesize to MAXSIZE
if [ "${size}" -gt "${MAXSIZE}" ]; then
# Send output back to the user about oversized files.
echo "ERROR: ${file} larger than ${MAXSIZE}."
EXIT=1
fi # End size comparison
fi # End check for empty size
done # End list of files
done # End reading stdin
# If we have oversized files, write more information out to the user
if [ "${EXIT}" = "1" ]; then
echo "ERROR: Your commit has been blocked due to certain files being oversized."
echo "ERROR: Check output above for more information."
fi
exit $EXIT
Добавляем в каталог с кодом проекта файл, заведомо большего размера (~12Mb), коммитим его:
git status
On branch docker
Your branch is up-to-date with 'upstream/docker'.
Untracked files:
(use "git add ..." to include in what will be committed)
Apresyan.dict.dz_3
nothing added to commit but untracked files present (use "git add" to track)
git add .
git commit -am 'test commit large file'
[docker 73549ab] test commit large file
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 Apresyan.dict.dz_3
Пробуем запушить в репозиторий:
git push
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 12.69 MiB | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: ERROR: Apresyan.dict.dz_3 larger than 5242880.
remote: ERROR: Your commit has been blocked due to certain files being oversized.
remote: ERROR: Check output above for more information.
To ssh://git@gitlab.lc:23/MYGROUP/MYREPO.git
! [remote rejected] docker -> docker (pre-receive hook declined)
error: failed to push some refs to 'ssh://git@gitlab.lc:23/MYGROUP/MYREPO.git'
Отлично, git-хук отработал как и ожидалось!