最近几天一直在了解git 如何提交前做git强制校验。因为项目使用的是coding,之前的gitlab 是有hook的设置的。可以在push时候做校验,但是coding 我看了他们 的官网,没找到设置hook的地方。于是决定换一种方式:在本地commit前做强制校验。
思路是这样的:本地项目的.git/hook目录下面是默认的提交前校验,里面有pre-commit.example、pre-commit-msg.example等shell脚本文件。带example默认是不执行的,去掉后缀example就会做对应的校验。那么 是不是可以利用这点,在本地commit前来做校验呢?
好的 ,思路有了。首先是去掉pre-commit.example的后缀,随便写点shell脚本,发现git commit 前 是可以执行的(简单的加上一句echo 什么内容不重要)。但是如何在commit前让本地走阿里规范呢?
带着这个问题,继续去思考。阿里规范本身是一套p3c的标准,在网上看到别人已经有写好的现成的方案。于是借助现成的方案:(参考 https://www.jianshu.com/p/b87ca8615c9c、https://www.jianshu.com/p/048627b20860 感谢作者)就是把阿里规范的源码 通过maven达成了jar包,然后使用 java jar的命令 来实现的。再然后把这行命令写在本地的pre-commit脚本里面,这样就可以实现commit 前校验代码是否走阿里规范了。
具体操作就是:去gitlab上下载 cp3的源码(地址:https://github.com/alibaba/p3c)下载到本地,通过maven命令打成jar包:如下
mvn clean package -Dmaven.test.skip=true
打的jar包有好几个,主要是使用 p3c-pmd-2.1.1-jar-with-dependencies.jar 。使用命令行:
java -Dpmd.language=en -cp /d/p3c-pmd-2.1.1-jar-with-dependencies.jar net.sourceforge.pmd.PMD -d /d/workspace/community -R rulesets/ali-p3c.xml -f text -shortnames
参数解释:
- -d 源码目录,多个文件或者目录以,号分开
- -R 指定规则,多个规则以,号分开。阿里规则路径在包中rulesets/java/ali-*.xml
- -f 报告格式,text html xml等。
#!/bin/sh #本地提交前自动触发阿里巴巴p3c规范脚本 EJECT=0 #REJECT变量,初始化为0 GIT_ROOT=$(cd $(dirname ${BASH_SOURCE[0]}); pwd) # 获取.git/hooks/根目录 HOOKS_DIR="$GIT_ROOT/.git/hooks" # 没有时创建该目录 if [ ! -d "$HOOKS_DIR" ]; then mkdir "$HOOKS_DIR" fi # 所有需要hook的git hooks文件名 hook_names=( pre-commit ) # 在.git/hooks/下生成这些执行文件 for hook_name in ${hook_names[@]} do # 生成hook文件 REAL_HOOK_FILE=$HOOKS_DIR/$hook_name # 将模板文件内容copy进去 cp $GIT_ROOT/check.sh $REAL_HOOK_FILE # 替换模板文件中的hook-tmp为正确的hook文件名 #sed -i "" "s/check.sh/$hook_name/g" $REAL_HOOK_FILE # 修改hook文件权限 chmod a+x $REAL_HOOK_FILE done
#!/bin/sh # # An example hook script to make use of push options. # The example simply echoes all push options that start with 'echoback=' # and rejects all pushes when the "reject" push option is used. # # To enable this hook, rename this file to "pre-receive". EJECT=0 #REJECT变量,初始化为0 BASE_PATH=$(cd `dirname $0`; pwd) #BASE_PATH变量中为当前脚本存放的路径,比如当前脚本路径为/usr/local/script/shell.sh,则BASE_PATH=/usr/local/script/ PROJECT_ROOT=$(cd $(dirname ${BASH_SOURCE[0]})/../..; pwd) java -Dpmd.language=en -cp $PROJECT_ROOT/p3c-pmd-2.1.1-jar-with-dependencies.jar net.sourceforge.pmd.PMD -d $PROJECT_ROOT -R rulesets/java/ali-comment.xml,rulesets/java/ali-concurrent.xml,rulesets/java/ali-constant.xml,rulesets/java/ali-exception.xml,rulesets/java/ali-flowcontrol.xml,rulesets/java/ali-naming.xml,rulesets/java/ali-oop.xml,rulesets/java/ali-orm.xml,rulesets/java/ali-other.xml,rulesets/java/ali-set.xml -f text #执行校验 REJECT=$? #REJECT变量接收上面的java命令执行的结果返回值 if test $[REJECT] -eq 0 then echo -e "\033[36m commit success!!! \033[1m" #蓝色打印提交成功 else echo -e "\033[31m 代码提交未通过阿里规范,不允许提交!!! \033[1m" #红色打印未通过 fi exit $REJECT
这样就可以了,因为是本地commit,如果想要跳过本地commit,直接在git base 后面 加上 git commit -m "注释" --no-verify 或者手动 删除.git/commit 目录下的即可。
这样是可以了,还有个问题就是:能不能做成一个无感知的、因为每次要手动执行才能使用。这样也不方便,而且如果别人不执行的话,也不知道啊。