gitlab pre-receive hook服務端配置限制提交代碼的備注長度
前言
開發人員在使用git提交(commit)代碼的時候,需要添加備注信息,但是很多人偷懶不願意寫或者寫的很短。為了限制開發人員寫過短的備注信息,需要在gitlab服務器端進行配置(客戶端也可以,但這里配置的是服務端)
配置
服務端有兩種配置方式,一種是全局的配置,一種是各個項目獨立的配置。這里講各個項目獨立的配置:
- 選擇一個項目,比如叫testGit
- 在git所在服務器后台,切換到git項目源代碼存儲的目錄:如果使用的是docker鏡像啟動的gitlab, 源代碼庫目錄一般位於/var/opt/gitlab/git-data/repositories/<group>/<project>.git,假設group叫test, 則路徑就是/var/opt/gitlab/git-data/repositories/test/testGit.git目錄。
- 在testGit.git目錄創建一個新目錄custom_hooks
- 在custom_hooks目錄創建一個文件命名為pre-receive,並且可執行權限設置為777(或者設置其所在用戶組和擁有者為gitlab)
- 添加腳本內容到pre-receive, 保存腳本內容,不用重啟gitlab會立刻生效
腳本
下面是pre-receive文件的腳本內容,設置提交代碼時的備注長度至少為5個英文字符(如果是中文字符,一個中文字符相當於3個英文字符)
#!/bin/bash
#pre-receive script
#set -x #for debugging
validate_ref()
{
# --- Arguments
oldrev=$(git rev-parse $1)
newrev=$(git rev-parse $2)
refname="$3"
commitList=`git rev-list $oldrev..$newrev`
#echo $commitList
split=($commitList)
for s in ${split[@]}
do
echo "@@@@@@@"
echo "$s"
msg=`git cat-file commit $s | sed '1,/^$/d'`
echo $msg
if [ ${#msg} -lt 5 ];then
echo "!!! Commit message length less than 5"
exit 1
else
echo "bigger than 5"
fi
done
}
fail=""
# Allow dual mode: run from the command line just like the update hook, or
# if no arguments are given then run as a hook script
if [ -n "$1" -a -n "$2" -a -n "$3" ]; then
# Output to the terminal in command line mode - if someone wanted to
# resend an email; they could redirect the output to sendmail
# themselves
PAGER= validate_ref $2 $3 $1
else
while read oldrev newrev refname
do
validate_ref $oldrev $newrev $refname
done
fi
if [ -n "$fail" ]; then
exit $fail
fi
開發人員在push代碼(pull, commit的時候不會報錯)的時候如果備注長度小於5個英文字符,就會提示報錯:

image.png
改進
限制提交的comments備注必須為三行,第一行至少18個英文字符,第二行為空,第三行為30個英文字符
root@bob-k8s3:/srv/gitlab/data/git-data/repositories/root/pets.git/custom_hooks# cat pre-receive
#!/bin/bash
#pre-receive script
#set -x #for debugging
RED='\033[0;31m'
NC='\033[0m' # No Color
reverse() {
# first argument is the array to reverse
# second is the output array
declare -n arr="$1" rev="$2"
for i in "${arr[@]}"
do
rev=("$i" "${rev[@]}")
done
}
regex_list=(
'^test'
'^fix '
'^docs'
'^task'
'^refactor'
'^revert'
'^style'
'^chore'
'^Merge'
'^merge'
'^[ci skip]'
)
# Concatenate regex_list
separator="|"
regex="$( printf "${separator}%s" "${regex_list[@]}" )"
# remove leading separator
regex="${regex:${#separator}}"
validate_ref()
{
# --- Arguments
oldrev=$(git rev-parse $1)
newrev=$(git rev-parse $2)
refname="$3"
#echo $oldrev
#echo $newrev
GITCMD="git"
commitList=`git rev-list $oldrev..$newrev`
split=($commitList)
reverse split split2
for s in ${split2[@]}
do
#echo "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
echo "$s"
currentrev=$s
msg=`git cat-file commit $s | sed '1,/^$/d'`
#echo $msg
match=`echo $msg | grep -nE "(${regex})"`
if [ "${match}" != "" ]; then
#show all the changed files, between this push and last push, maybe one or more commits
changedFiles=$($GITCMD diff --stat --name-only --diff-filter=ACMRT ${oldrev}..${currentrev})
#echo $changedFiles
#if it is bug fixing
if [[ "${match}" =~ "fix" ]]; then
#check if there is unit testing commiting
if ! [[ $changedFiles =~ "src/test/" ]]; then
echo -e "${RED}Error: Need unit testing cases ${NC}"
#exit 1
fi
fi
# if pom.xml changed, make sure it can not chang the code coverage threshold
if [[ $changedFiles =~ "pom.xml" ]]; then
#check file contents, make sure no body change code coverage threshold
#codeCoverageKeyword=`git diff-tree -r -p --no-color --no-commit-id --diff-filter=d $s | grep -n "<minimum>"`
codeCoverageKeyword=`git diff --unified=0 ${oldrev}..${currentrev} | grep -n "<minimum>"`
if [ "${codeCoverageKeyword}" != "" ]; then
echo -e "${RED}Error: you can not change code coverage rate ${NC}"
#exit 1
fi
fi
else
echo -e "Error:${RED} comments should be started wih test or fix or task... ${NC}"
fi
# validate the git comments
if [[ $msg == *"Merge branch"* ]];
then
echo "Merge branch...skip the checking"
else
n=0
while read -r line; do
((n++))
# 1st line at least 18 english characters
if [ $n -eq 1 ] && [ ${#line} -lt 3 ];then
echo -e "Error:${RED} 1st line length should be bigger than 18${NC}: ${#line}"
#exit 1
fi
# 2nd line must be empty
if [ $n -eq 2 ] && [ ${#line} -gt 0 ];then
echo -e "Error:${RED} 2nd line length should be 0${NC}: ${#line}"
#exit 1
fi
# 3rd line at least 30 english characters
if [ $n -eq 3 ] && [ ${#line} -lt 30 ];then
echo -e "Error:${RED} 3rd line length should be bigger than 30${NC}: ${#line}"
#exit 1
fi
done <<< "$msg"
if [ $n -lt 3 ];then
echo -e "Error:${RED} You should commit with 3 lines comments${NC}: $n"
# exit 1
fi
fi
#change the oldrev to show file list and file contents between 2 commits
oldrev=$currentrev
done
}
fail=""
# Allow dual mode: run from the command line just like the update hook, or
# if no arguments are given then run as a hook script
if [ -n "$1" -a -n "$2" -a -n "$3" ]; then
# Output to the terminal in command line mode - if someone wanted to
# resend an email; they could redirect the output to sendmail
# themselves
PAGER= validate_ref $2 $3 $1
else
while read oldrev newrev refname
do
validate_ref $oldrev $newrev $refname
done
fi
if [ -n "$fail" ]; then
exit $fail
fi
第二行的空行是必須, 否則使用如下兩個命令時就會格式錯亂
$git log --oneline
$git shortlog
下圖中第一個是第二行添加了空行右邊會有三個點意思是可以點擊這三個點查看更多信息,第二個是只有一行時的效果:

image.png
備注
- pre-receive會響應以任何形式的代碼提交,比如命令行,比如通過gitlab網頁
- 如果在pre-receive里`touch testme.txt", 默認會在pre-receive腳本所在目錄的上一級目錄里生成。
- 也可以在pre-receive里使用curl調用REST接口,比如gitlab的各種restful api
- 在linux下面提交多行備注的方法很簡單,在備注內容中敲回車即可,但在windows中如果使用的是https://git-scm.com/, 方法就相對繁瑣一點,要使用多個 -m