gitlab pre-receive hook服务端配置限制提交代码的备注长度

前言

开发人员在使用git提交(commit)代码的时候,需要添加备注信息,但是很多人偷懒不愿意写或者写的很短。为了限制开发人员写过短的备注信息,需要在gitlab服务器端进行配置(客户端也可以,但这里配置的是服务端)

配置

服务端有两种配置方式,一种是全局的配置,一种是各个项目独立的配置。这里讲各个项目独立的配置:

  1. 选择一个项目,比如叫testGit
  2. 在git所在服务器后台,切换到git项目源代码存储的目录:如果使用的是docker镜像启动的gitlab, 源代码库目录一般位于/var/opt/gitlab/git-data/repositories//.git,假设group叫test, 则路径就是/var/opt/gitlab/git-data/repositories/test/testGit.git目录。
  3. 在testGit.git目录创建一个新目录custom_hooks
  4. 在custom_hooks目录创建一个文件命名为pre-receive,并且可执行权限设置为777(或者设置其所在用户组和拥有者为gitlab)
  5. 添加脚本内容到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个英文字符,就会提示报错:
gitlab pre-receive hook服务端配置限制提交代码的备注长度_第1张图片
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 ""`
                        codeCoverageKeyword=`git  diff --unified=0 ${oldrev}..${currentrev} | grep -n ""`
                        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

下图中第一个是第二行添加了空行右边会有三个点意思是可以点击这三个点查看更多信息,第二个是只有一行时的效果:
gitlab pre-receive hook服务端配置限制提交代码的备注长度_第2张图片
image.png

备注

  1. pre-receive会响应以任何形式的代码提交,比如命令行,比如通过gitlab网页
  2. 如果在pre-receive里`touch testme.txt", 默认会在pre-receive脚本所在目录的上一级目录里生成。
  3. 也可以在pre-receive里使用curl调用REST接口,比如gitlab的各种restful api
  4. 在linux下面提交多行备注的方法很简单,在备注内容中敲回车即可,但在windows中如果使用的是https://git-scm.com/, 方法就相对繁琐一点,要使用多个 -m
    gitlab pre-receive hook服务端配置限制提交代码的备注长度_第3张图片
    image.png

你可能感兴趣的:(gitlab pre-receive hook服务端配置限制提交代码的备注长度)