项目越来越大,代码越来越多,然后就是各种五花八门的代码格式、代码规范。可用自查或者交叉检查,但是都是人工需要费事费力,还不一定能面面俱到,所以必须有一种强制的手段,不折不扣的执行代码规范,不符合规范的无法提交到代码仓库,从而杜绝了不符合规范的代码产生。同时,团队内的代码提交信息也需要遵循一定的格式,一并做校验。
利用gitlab的 (钩子)hooks机制,关于钩子有客户端、服务端的,本文仅描述服务端的钩子,更多关于钩子的资料参考:
https://blog.csdn.net/allensandy/article/details/121422607
gitlab服务端会有三个主要钩子:
而本文的用到的做代码规则校验的就是pre-receive的钩子,通过此钩子执行java –cp命令调用aliyun p3c-pmd的规则校验,然后检查如不符合规范返回错误信息到客户端(idea,git bash等)。
P3C阿里云的插件,github地址:https://github.com/alibaba/p3c
此处我们用到p3c-pmd插件,需要打包成jar文件,以便gitlab服务端使用,下载源码之后,直接打包(gradle或maven均可),得到 p3c-pmd-2.1.1-jar-with-dependencies.jar ,后面备用;已经打包好的可以直接下载使用:p3c-pmd-2.1.1.jarP3c阿里云的插件-Java文档类资源-CSDN文库
提交信息即 git commit message,在常规开发中,可能很多人会忽略提交信息的重要性,对于提交信息的内容会相当随意地进行输入,其实这样在很大的程度上会影响后续的维护和必要情况下的故障的追踪。所以,在此我们需要对提交信息做一个初步规范。
首先,提交信息必须格式化,即提交信息需要按照一定的格式来撰写,当团队中的所有成员都遵循一定的格式的时候,团队的其他成员可以非常方便的阅读内容。且不允许多个task一个提交,可以一个task完整提交,也可以局部提交,但是不允许跨task提交,每次提交不能让项目跑不起来,养成每日多次提交的习惯,我们约定提交信息的格式为:(任务类型后的为英文冒号!!!)
{{Task #}} // 项目管理软件中的任务 ID
{{任务类型 (feat/fix/docs/style/refactor/perf/test/build/chore/revert/merge)}}:{{任务描述}}
再者,我们可以通过项目管理软件中自动从提交信息中完成和任务的关联,提高大家的工作效率。
针对日常开发中可能存在一些并没有实际task的零碎的工作,引入了NOTASK标识,即在提交时备注信息的地方原本需要填入task编号的地方填入NOTASK,用以和普通开发任务进行区分,如:
NOTASK // 没有实际任务情况下的细小改动
{{任务类型 (feat/fix/docs/style/refactor/perf/test/build/chore/revert/merge)}}: {{任务描述}}
任务分类:
1、gitlab所在服务器创建目录:/opt/gitlab/embedded/service/gitlab-shell/hooks/pre-receive.d ;
2、将 p3c-pmd-2.1.1-jar-with-dependencies.jar上传到该目录;
3、在该目录新建 pre-receive 文件,文件内容如下(完整文件:gitlab服务器端代码格式以及git提交信息格式检查钩子文件,可以拿来直接使用-Java文档类资源-CSDN文库):
- ## 校验commit message
- validate_commit_message()
- {
- oldrev=$(git rev-parse $1)
- newrev=$(git rev-parse $2)
- refname="$3"
- #echo 'Old version: '$oldrev
- #echo 'New version: '$newrev
- #echo 'Branch: '$refname
-
- ## git 命令
- #GITCMD="git"
- ## 按时间倒序列出 commit 找出两个版本之间差异的版本号集合 oldrev~newrev
- commitList=`git rev-list $oldrev..$newrev`
- #echo 'commitList: '$commitList
-
- split=($commitList)
- #echo 'split: '$split
-
- # 遍历数组
- for s in ${split[@]}
- do
- #echo “$s”
- #通过版本号获取仓库中对象实体的类型、大小和内容的信息
- #比如提交人、作者、邮件、提交时间、提交内容等
- currentContent=`git cat-file commit $s`
- #echo 'Commit obj: '$currentContent
- #echo 's==: '$s
- #获取提交内容
- msg=`git cat-file commit $s | sed '1,/^$/d'`
- echo 'commitid:'$s',msg: '$msg
-
- ## merge合并分之直接放行
- if [[ $msg == *"Merge branch"* ]] || [[ $msg == *"Merge remote-tracking branch"* ]]; then
- echo "Merge branch...skip the checking"
- else
- ## 做内容校验
- match=`echo $msg | grep -nE "(${regex})"`
- #echo 'Match result: '$match
-
- ## 找到匹配说明是符合规范的
- if [ "${match}" != "" ]; then
- ## 校验注释长度
- msg_length=${#msg}
- #echo "Msg length: ${msg_length}"
- if [[ ${msg_length} -lt ${COMMIT_MESSAGE_MIN_LENGTH} ]]; then
- #echo -e "Error: Commit message should be bigger than ${COMMIT_MESSAGE_MIN_LENGTH} and current commit message length: ${msg_length}"
- echo -e "错误: 提交备注信息的长度应该大于 ${COMMIT_MESSAGE_MIN_LENGTH} ,本次提交的备注长度为: ${msg_length} ,请修改后再提交!"
- exit 1
- fi
-
- ### 找到匹配内容做相应处理,如fix ,校验pom文件等
- #if [[ "${match}" =~ "fix:" ]]; then
- ## 如果是修补bug,规范有点获取到fix中的ID,然后调用禅道对外的API关闭,其他场景类似
- #fi
-
- # 是否开启校验和main分支
- isMaster=$(echo $refname | grep "main$")
- if [ $CHECK_MASTER_POM_SNAPSHOT_ON == 0 ] && [ -n "$isMaster" ]; then
- # 如果是main分之,并且pom文件发生了变更,判断pom文件是否含有sonapshot的引用
- pomfile=`git diff --name-only ${oldrev} ${newrev} | grep -e "pom\.xml"`
- if [[ "${pomfile}" != "" ]]; then
- #echo $pomfile
- ## 获取pom文件更新的内容
- pomcontent=`git show $newrev:$pomfile`
- #echo $pomcontent
- ## 校验pom文件是否包含snapshot版本
- if [[ $pomcontent =~ 'SNAPSHOT' ]]; then
- #echo -e "Error: Snapshot version cannot exist in main branch!"
- echo -e "错误: main 分支中不能存在快照版本!"
- exit 1
- fi
- fi
- fi
-
- ## 其他操作
- #echo "Commit comments validate Success!"
- echo "提交备注格式检查通过!"
- else
- #echo -e "Error: Commit comments message should be started with [${tips_msg}]..."
- echo -e "错误: 提交备注格式错误,请修改后再提交,具体规范请参考团队规范文档"
- exit 1
- fi
-
- fi
- done
- }
- ## 代码校验
- validate_code_rules()
- {
- echo 'Start code analysis!'
- oldrev=$(git rev-parse $1)
- newrev=$(git rev-parse $2)
- refname="$3"
- #echo 'Old version: '$oldrev
- #echo 'New version: '$newrev
- #echo 'Branch: '$refname
-
- TEMPDIR=$BASE_PATH/"tmp"
-
- FILES=`git diff --name-only ${oldrev} ${newrev} | grep -e "\.java$"`
-
- committer=`git log -1 $newrev --pretty=%ce`
-
- if [ -n "$FILES" ]; then
- for FILE in ${FILES}; do
- mkdir -p "${TEMPDIR}/`dirname ${FILE}`" >/dev/null
- git show $newrev:$FILE > ${TEMPDIR}/${FILE}
- done;
-
- MAIN_JAVA_PATH=$TEMPDIR'/src/main'
- #echo 'Temp update files path: '$MAIN_JAVA_PATH
-
- #FILES_TO_CHECK=`find $MAIN_JAVA_PATH -name '*.java'`
-
- #echo 'Check files:'${FILES_TO_CHECK}
- echo 'Aliyun p3c-pmd check starting.....'
-
- #echo 'Current shell Path:' $BASE_PATH
- #echo 'JAVA_HOME:' $JAVA_HOME
- #echo 'Root directory for java sources: '$MAIN_JAVA_PATH
-
- #管理员提交暂时过滤掉检查
- if [ $committer != 'tangkai2009fei@163.com' ]; then
- if [[ $CODE_RULE_TYPE == 0 ]]; then
- ## 需要阿里云P3C的插件包p3c-pmd-2.0.0.jar与该脚本在同级目录下
- echo 'Code analysis for Aliyun-p3c..'
- #$JAVA_HOME/bin/java -Dpmd.language=en -cp $BASE_PATH/p3c-pmd-2.0.0.jar net.sourceforge.pmd.PMD -d $MAIN_JAVA_PATH -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
- $JAVA_HOME/bin/java -Dfile.encoding=$FILE_ENCODING -Dpmd.language=$PMD_LANGUAGE -cp $BASE_PATH/p3c-pmd-2.1.1-jar-with-dependencies.jar net.sourceforge.pmd.PMD -d $TEMPDIR -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-other.xml,rulesets/java/ali-set.xml -f text
- RESULT=$?
- #echo $RESULT
- if [ $RESULT -gt 0 ]; then
- echo "代码质量检测不通过,请修改后重试,请参考规范文档:https://github.com/alibaba/p3c"
- rm -rf $TEMPDIR
- exit 1
- fi
-
- echo 'Code analysis success!'
- else
- echo "在白名单中,临时允许通过"
- fi
-
- else
- echo 'No java code, analysis end!'
- fi
-
-
- rm -rf $TEMPDIR
- }
4、给 pre-receive 文件增加执行权限
chmod +777 pre-receive
5、客户端提交代码进行测试