Gitlab钩子脚本

gitlab可以结合钩子脚本来对git的各个流程进行定制化操作

我们现在生产环境需要在服务器端来对客户端push上来的xml文件进行校验.

如果不满足规则,则拒绝push到服务器端.

因为公司的ORM框架统一用的Mybatis,所以指定规则的时候比较方便

主要是看标签中是否包含了更新时间字段

updated_date 或者 update_date 或者 modify_date

服务器脚本

单独仓库脚本

对单独某个仓库制定特殊的规则

1.找到仓库位置

安装gitlab之后,可以通过查看配置文件中的‘git_data_dirs’参数来确定仓库地址

一般默认是在**/var/opt/gitlab/git-data**目录下

2.编写Shell脚本

进入需要制定规则流程的仓库地址**/var/opt/gitlab/git-data/repositories/root/githooks.git**

创建脚本文件夹 必须是custom_hooks这个名字

mkdir custom_hooks
mkdir pre-receive.d
vi start.sh

我们需要在代码push到服务端之前进行校验,就需要在pre-receive这个阶段进行校验(其它的参考文末的链接)

start.sh脚本

#!/bin/bash
export LANG="en_US.UTF-8"
REJECT=0
while read oldrev newrev refname; do
    if [ "$oldrev" = "0000000000000000000000000000000000000000" ];then
        oldrev="${newrev}^"
    fi

    files=`git diff --name-only ${oldrev} ${newrev}  | grep -e ".xml$"`

    if [ -n "$files" ]; then
	  TEMPDIR="./tmp"
          for file in $files; do
			#echo "${file}"
		if [[ $file == *"/"* ]]; then
			mkdir -p "${TEMPDIR}/${file%/*}" > /dev/null
			#echo "${file}"	
		else
			#echo "${file}"
			mkdir -p "${TEMPDIR}" > /dev/null
		fi
		touch ${TEMPDIR}/${file}
	  	git show $newrev:$file > ${TEMPDIR}/${file}
	  done;
	 
	 ./script/updateCheck.sh

 	 REJECT=$?

        
	  #if [ $REJECT -eq 0 ]; then
	  #	echo "success!"
	  #	else echo "error!" 
	  #fi
     
        rm -rf $TEMPDIR
    fi
done

exit $REJECT

这个脚本中需要注意的地方是 ./script/updateCheck.sh

为了以后还需要增加其它定制化流程. 这里就把脚本校验抽象出来了.

start脚本执行的环境默认是在githooks.git目录下的.

所以我们需要在仓库目录下创建一个script目录,里边写一个被调用的脚本

mkdir script
cd script/
vi updateCheck.sh

updateCheck.sh脚本内容

#!/bin/bash

TEMP_FILE='temp.sql'
REJECT=0

read_file() {
  for file in $(ls -a $1); do
    if [ -d $1"/"$file ]; then
      if [[ $file != '.' && $file != '..' ]]; then
        read_file $1"/"$file
      fi
    else
      if [ ${file##*.} == "xml" ]; then
        FLAG=0
        while read line; do
          if [[ $line =~ "<update" ]]; then
            FLAG=1
          fi
          if [[ $FLAG -eq 1 ]]; then
            echo $line >>$TEMP_FILE
          fi
          if [[ $line =~ "</update>" ]]; then
            FLAG=0
            result1=$(sed -n '/\<update id=/{p;:a;n;H;/<\/update>/{x;s/\n//p;z;h};ba}' $TEMP_FILE | grep -i -E 'UPDATED_DATE|UPDATE_DATE|MODIFY_DATE' | wc -l)

            if [[ result1 -eq 0 ]]; then
              REJECT=1
		TMP_PATH=$1
              echo "请修改下列文件${TMP_PATH#*/tmp}"/"${file}, update sql语句中未包含'updated_date' or 'update_date' or 'modify_date' 字段!"
              #echo "请修改下列文件${file}, update sql语句中未包含'updated_date' or 'update_date' or 'modify_date' 字段!" >>test.log
              echo "SQL片段:"
			  cat $TEMP_FILE
              #echo "SQL片段:" $(cat $TEMP_FILE) >>test.log
            fi
            rm -rf $TEMP_FILE

          fi
        done <$1"/"$file
      fi
    fi
  done

}
read_file $(pwd)"/tmp"
exit $REJECT

这个脚本主要是校验提交的xml格式文件内的标签内是否有'updated_date' or 'update_date' or 'modify_date' 字段之一

3.验证

gitlab

全局脚本

如果有一些要对全部仓库的规则 则可以在全局脚本内配置

例如我们把上边的规则应用到全局仓库

1.查找全局脚本地址

一般默认是在**/opt/gitlab/embedded/service/gitlab-shell/hooks**下边的

可以通过查看配置文件中的custom_hooks_dir参数来确定位置, 记得把前边的#注释删掉让全局配置生效噢

2.编写shell脚本

gitlab1

可以看到有三个文件. 三个文件分别对应不同的生命周期

pre-receive是在push之前
post-receive是在push之后
update是在push之前但是和分支有关系
具体可以参考文末的git钩子链接

我们现在来修改pre-receive钩子

vi pre-receive

#!/bin/bash
export LANG="en_US.UTF-8"
REJECT=0
while read oldrev newrev refname; do
    if [ "$oldrev" = "0000000000000000000000000000000000000000" ];then
        oldrev="${newrev}^"
    fi

    files=`git diff --name-only ${oldrev} ${newrev}  | grep -e ".xml$"`

    if [ -n "$files" ]; then
	  TEMPDIR="./tmp"
          for file in $files; do
			#echo "${file}"
		if [[ $file == *"/"* ]]; then
			mkdir -p "${TEMPDIR}/${file%/*}" > /dev/null
			#echo "${file}"	
		else
			#echo "${file}"
			mkdir -p "${TEMPDIR}" > /dev/null
		fi
		touch ${TEMPDIR}/${file}
	  	git show $newrev:$file > ${TEMPDIR}/${file}
	  done;
	 
	 ./script/updateCheck.sh

 	 REJECT=$?

        
	  #if [ $REJECT -eq 0 ]; then
	  #	echo "success!"
	  #	else echo "error!" 
	  #fi
     
        rm -rf $TEMPDIR
    fi
done

exit $REJECT

这里要注意 钩子脚本执行的当前目录永远是提交的仓库目录
所以还是需要在当前仓库目录下边 创建/script/updateCheck.sh这个脚本
但是,也可以直接把脚本内容写到这个pre-receive钩子里边.
这样就不需要在每个仓库目录下创建这个文件了.

全局脚本和单一仓库脚本的关系

全局脚本优先级高于单一仓库脚本

同时开启的话, 会先走全局脚本,再走单一仓库脚本

客户端脚本

1.查看客户端脚本位置

我们在把项目clone到本地之后

打开win平台的隐藏文件功能
gitlab3

可以发现有个.git隐藏文件夹
gitlab4

2.编写shell文件

可以看到hooks文件夹中有很多sample文件,

如果要使用其中的某个钩子就把.sample后缀去掉即可生效.

脚本内容和上边的类似.

上边的所有钩子脚本都可以用脚本语言来写. python ruby 都可以的.非常灵活

参考:

Git 钩子

git 钩子:自定义你的工作流

Q.E.D.


今天也要加油鸭~