GitLab: Custom hooks

Jul 10, 2017 09:58 · 584 words · 3 minute read gitlab

В 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-хук отработал как и ожидалось!

tweet Share