• Gitlab+P3C-PMD(阿里云插件)标准化你团队的代码和提交信息


    1、背景简介

    项目越来越大,代码越来越多,然后就是各种五花八门的代码格式、代码规范。可用自查或者交叉检查,但是都是人工需要费事费力,还不一定能面面俱到,所以必须有一种强制的手段,不折不扣的执行代码规范,不符合规范的无法提交到代码仓库,从而杜绝了不符合规范的代码产生。同时,团队内的代码提交信息也需要遵循一定的格式,一并做校验。

    2、gitlab 服务端hooks机制

    利用gitlab的 (钩子)hooks机制,关于钩子有客户端、服务端的,本文仅描述服务端的钩子,更多关于钩子的资料参考:

    https://blog.csdn.net/allensandy/article/details/121422607

    gitlab服务端会有三个主要钩子:

    1. pre-receive(处理客户端push动作时最先被调用的脚本,以非0值退出拒绝Push,可以用来做注释标准化、代码标准化等);
    2. update(与pre-receive功能类似,为每个准备更新的分支各运行一次);
    3. post-receive(是在push之后执行的脚本,可以用来调用后续的持续集成、发邮件通知等)。

    而本文的用到的做代码规则校验的就是pre-receive的钩子,通过此钩子执行java –cp命令调用aliyun p3c-pmd的规则校验,然后检查如不符合规范返回错误信息到客户端(idea,git bash等)。

    3、P3C-PMD

    P3C阿里云的插件,github地址:https://github.com/alibaba/p3c

    此处我们用到p3c-pmd插件,需要打包成jar文件,以便gitlab服务端使用,下载源码之后,直接打包(gradlemaven均可),得到 p3c-pmd-2.1.1-jar-with-dependencies.jar ,后面备用;已经打包好的可以直接下载使用:p3c-pmd-2.1.1.jarP3c阿里云的插件-Java文档类资源-CSDN文库

    4、代码提交信息格式

    提交信息即 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)}}: {{任务描述}}

    任务分类:

    • feat:新增功能
    • fix:bug修复
    • docs:仅仅修改了文档,比如README,CHANGELOG等等
    • style:代码格式改变(修改空白字符,格式缩进,补全缺失的分号等,没有改代码的逻辑)
    • refactor:重构代码(没有新增功能或bug修复)
    • perf:优化,比如:提升性能、体验、算法等
    • test:增加/修改测试用例,包括单元测试、集成测试等
    • build:改变了build工具
    • revert:还原先前提交的更改
    • chore:改变构建流程或者增加依赖库、工具等
    • merge:代码合并
    • ci:与CI(持续集成)有关的改动

    5、配置钩子(所有项目生效,如只需针对单个项目,请自行看网上教程)

    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文库):

    1. ## 校验commit message
    2. validate_commit_message()
    3. {
    4. oldrev=$(git rev-parse $1)
    5. newrev=$(git rev-parse $2)
    6. refname="$3"
    7. #echo 'Old version: '$oldrev
    8. #echo 'New version: '$newrev
    9. #echo 'Branch: '$refname
    10. ## git 命令
    11. #GITCMD="git"
    12. ## 按时间倒序列出 commit 找出两个版本之间差异的版本号集合 oldrev~newrev
    13. commitList=`git rev-list $oldrev..$newrev`
    14. #echo 'commitList: '$commitList
    15. split=($commitList)
    16. #echo 'split: '$split
    17. # 遍历数组
    18. for s in ${split[@]}
    19. do
    20. #echo “$s”
    21. #通过版本号获取仓库中对象实体的类型、大小和内容的信息
    22. #比如提交人、作者、邮件、提交时间、提交内容等
    23. currentContent=`git cat-file commit $s`
    24. #echo 'Commit obj: '$currentContent
    25. #echo 's==: '$s
    26. #获取提交内容
    27. msg=`git cat-file commit $s | sed '1,/^$/d'`
    28. echo 'commitid:'$s',msg: '$msg
    29. ## merge合并分之直接放行
    30. if [[ $msg == *"Merge branch"* ]] || [[ $msg == *"Merge remote-tracking branch"* ]]; then
    31. echo "Merge branch...skip the checking"
    32. else
    33. ## 做内容校验
    34. match=`echo $msg | grep -nE "(${regex})"`
    35. #echo 'Match result: '$match
    36. ## 找到匹配说明是符合规范的
    37. if [ "${match}" != "" ]; then
    38. ## 校验注释长度
    39. msg_length=${#msg}
    40. #echo "Msg length: ${msg_length}"
    41. if [[ ${msg_length} -lt ${COMMIT_MESSAGE_MIN_LENGTH} ]]; then
    42. #echo -e "Error: Commit message should be bigger than ${COMMIT_MESSAGE_MIN_LENGTH} and current commit message length: ${msg_length}"
    43. echo -e "错误: 提交备注信息的长度应该大于 ${COMMIT_MESSAGE_MIN_LENGTH} ,本次提交的备注长度为: ${msg_length} ,请修改后再提交!"
    44. exit 1
    45. fi
    46. ### 找到匹配内容做相应处理,如fix ,校验pom文件等
    47. #if [[ "${match}" =~ "fix:" ]]; then
    48. ## 如果是修补bug,规范有点获取到fix中的ID,然后调用禅道对外的API关闭,其他场景类似
    49. #fi
    50. # 是否开启校验和main分支
    51. isMaster=$(echo $refname | grep "main$")
    52. if [ $CHECK_MASTER_POM_SNAPSHOT_ON == 0 ] && [ -n "$isMaster" ]; then
    53. # 如果是main分之,并且pom文件发生了变更,判断pom文件是否含有sonapshot的引用
    54. pomfile=`git diff --name-only ${oldrev} ${newrev} | grep -e "pom\.xml"`
    55. if [[ "${pomfile}" != "" ]]; then
    56. #echo $pomfile
    57. ## 获取pom文件更新的内容
    58. pomcontent=`git show $newrev:$pomfile`
    59. #echo $pomcontent
    60. ## 校验pom文件是否包含snapshot版本
    61. if [[ $pomcontent =~ 'SNAPSHOT' ]]; then
    62. #echo -e "Error: Snapshot version cannot exist in main branch!"
    63. echo -e "错误: main 分支中不能存在快照版本!"
    64. exit 1
    65. fi
    66. fi
    67. fi
    68. ## 其他操作
    69. #echo "Commit comments validate Success!"
    70. echo "提交备注格式检查通过!"
    71. else
    72. #echo -e "Error: Commit comments message should be started with [${tips_msg}]..."
    73. echo -e "错误: 提交备注格式错误,请修改后再提交,具体规范请参考团队规范文档"
    74. exit 1
    75. fi
    76. fi
    77. done
    78. }

     

    1. ## 代码校验
    2. validate_code_rules()
    3. {
    4. echo 'Start code analysis!'
    5. oldrev=$(git rev-parse $1)
    6. newrev=$(git rev-parse $2)
    7. refname="$3"
    8. #echo 'Old version: '$oldrev
    9. #echo 'New version: '$newrev
    10. #echo 'Branch: '$refname
    11. TEMPDIR=$BASE_PATH/"tmp"
    12. FILES=`git diff --name-only ${oldrev} ${newrev} | grep -e "\.java$"`
    13. committer=`git log -1 $newrev --pretty=%ce`
    14. if [ -n "$FILES" ]; then
    15. for FILE in ${FILES}; do
    16. mkdir -p "${TEMPDIR}/`dirname ${FILE}`" >/dev/null
    17. git show $newrev:$FILE > ${TEMPDIR}/${FILE}
    18. done;
    19. MAIN_JAVA_PATH=$TEMPDIR'/src/main'
    20. #echo 'Temp update files path: '$MAIN_JAVA_PATH
    21. #FILES_TO_CHECK=`find $MAIN_JAVA_PATH -name '*.java'`
    22. #echo 'Check files:'${FILES_TO_CHECK}
    23. echo 'Aliyun p3c-pmd check starting.....'
    24. #echo 'Current shell Path:' $BASE_PATH
    25. #echo 'JAVA_HOME:' $JAVA_HOME
    26. #echo 'Root directory for java sources: '$MAIN_JAVA_PATH
    27. #管理员提交暂时过滤掉检查
    28. if [ $committer != 'tangkai2009fei@163.com' ]; then
    29. if [[ $CODE_RULE_TYPE == 0 ]]; then
    30. ## 需要阿里云P3C的插件包p3c-pmd-2.0.0.jar与该脚本在同级目录下
    31. echo 'Code analysis for Aliyun-p3c..'
    32. #$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
    33. $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
    34. RESULT=$?
    35. #echo $RESULT
    36. if [ $RESULT -gt 0 ]; then
    37. echo "代码质量检测不通过,请修改后重试,请参考规范文档:https://github.com/alibaba/p3c"
    38. rm -rf $TEMPDIR
    39. exit 1
    40. fi
    41. echo 'Code analysis success!'
    42. else
    43. echo "在白名单中,临时允许通过"
    44. fi
    45. else
    46. echo 'No java code, analysis end!'
    47. fi
    48. rm -rf $TEMPDIR
    49. }

    4、给 pre-receive 文件增加执行权限

    chmod +777 pre-receive

    5、客户端提交代码进行测试

     

  • 相关阅读:
    二次封装这几个 element-ui 组件后,让代码更加优雅了
    单向链表模版实现(c++)
    笔记本外接显示器,edge浏览器播放视频黑屏
    WPF动画
    Xilinx DDR4 MIG 的调试
    嵌入式实时操作系统的设计与开发(任意大小的内存管理)
    01.cesium简介
    前端周刊第三十七期
    源码中的设计模式--单例模式
    Unity学习笔记[一] RollBall小游戏
  • 原文地址:https://blog.csdn.net/TangKai_java/article/details/126867721