利用Gitlab钩子实现代码规范管控

利用Gitlab钩子实现代码规范管控

2023年7月7日发(作者:)

利⽤Gitlab钩⼦实现代码规范管控利⽤Gitlab钩⼦实现代码规范管控1、前⾔在⼀个开发团队中通常会碰到这样⼀个问题,那就是很多⼈的代码不够规范,导致可读性差甚⾄引发⼀些bug,然后就会有⼈出来制定代码规范了,制定完了开始推⾏,可是⼀段时间后却发现没⼈提了,于是代码⼜开始逐渐不够规范起来。那我们要怎么解决这个难题呢?那就需要引⼊⼀套强制规范要求的机制了,如果代码不够规范就不准提交到仓库⾥去,这样就不会让规范慢慢失去味道了,⽽是会⼀直强制执⾏下去。这就是本⽂将会提到的,利⽤Gitlab钩⼦来实现代码规范管控,将不合规范的代码挡之门外!2、规范简介3、Gitlab钩⼦简介4、流程图5、实施步骤1.

/* * This file was generated by the Gradle 'init' task. */plugins { id 'java' id 'maven-publish'}repositories { mavenLocal() maven { url = uri('/content/repositories/snapshots') } maven { url = uri('/maven2/') }}}dependencies { implementation ':pmd-java:6.15.0' implementation ':pmd-vm:6.15.0' implementation 'tion:tion-api:1.3.2' testImplementation ':pmd-test:6.15.0'}group = 'a.p3c'version = '2.0.0'description = 'p3c-pmd'Compatibility = N_1_8java { withJavadocJar()}publishing { publications { maven(MavenPublication) { from() } }}pe(JavaCompile) { ng = 'UTF-8'}jar { from { t{zipTree(it)} }}2. 客户端钩⼦脚本如下,需要拷贝到本地代码⽬录的.git/hook/,并且去掉.sample后缀,钩⼦就可以执⾏了。#!/bin/sh## An example hook script to check the commit log message.# Called by "git commit" with one argument, the name of the file# that has the commit message. The hook should exit with non-zero# status after issuing an appropriate message if it wants to stop the# commit. The hook is allowed to edit the commit message file.## To enable this hook, rename this file to "commit-msg".# Uncomment the below to add a Signed-off-by line to the message.# Doing this in a hook is a bad idea in general, but the prepare-commit-msg# hook is more suited to it.## SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^(.*>).*$/Signed-off-by: 1/p')# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"# This example catches duplicate Signed-off-by lines.# @author amzheng@# @date 2021-04-09# @description 在提交时预检查备注信息是否符合规范,如不符合规范会被退回echo 'commit-msg 'msg_file=$1msg=`cat ${msg_file} | grep -v "^$"`TYPE_LIST=( 'feat:' #新功能feature 'update:' #在feat内修改 'fix:' #修补bug 'docs:' #⽂档 'style:' #格式化,不影响代码运⾏的变动 'refactor:' #重构 'pref:' #性能优化 'test:' #增加测试 'chore:' #构建过程或辅助⼯具的变动 #'[ci skip]' #忽略校验)COMMIT_MESSAGE_MIN_LENGTH=10declare -a regex_listarrLen=${#TYPE_LIST[@]}for ((i=0;i<$arrLen;i++)) do regex_list[i]='^'${TYPE_LIST[i]}doneregex_list[$arrLen+1]='^[ci skip]:'#echo "reg_list=== "${regex_list[@]}separator="|"## 合并成⼀个完整的正则表达式regex="$( printf "${separator}%s" "${regex_list[@]}" )"#echo "type regex: "$regex## 去除头部的 |regex=${regex:${#separator}}#echo "regex: "$regextips_msg="$( printf "${separator}%s" "${TYPE_LIST[@]}" )"tips_msg=${tips_msg:${#separator}}echo 'Start validate commit comment:'$msgmatch=`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 "pre-commit Error: Commit message should be bigger than ${COMMIT_MESSAGE_MIN_LENGTH} and current commit message length: ${msg_length}" exit 1 fi ## 其他操作 echo "commit-msg: Commit comments validate Success!"else echo -e "commit-msg Error: Commit comments message should be started with [${tips_msg}]..." exit 1fi3. 服务端钩⼦脚本如下。需要把代码拷贝到:/opt/gitlab/embedded/service/gitlab-shell/hooks⽬录下的pre-receive钩⼦中,这个⽬录是每个代码仓库共享的,相当于添加的是公共钩⼦,每个代码库的代码都会检测,如果需要只添加到某个库,可以把脚本放到仓库⽬录:/var/opt/gitlab/git-data/repositories/xxx//custom_hooks。#!/bin/bash##脚本提供功能:Commit提交的Message和代码规范是否符合统⼀规范##分三个部分:##分三个部分:# 1.变量定义部分# 2.校验部分:注释校验&代码分析# 3.初始化⼊⼝## 校验流程:# 1.先做提交注释校验,校验的规则:是否已${TYPE_LIST}定义的开头,且内容长度是否⼤于 ${COMMIT_MESSAGE_MIN_LENGTH}# 2.如果是master分之,修改了pom⽂件还会校验是否存在snapshot版本的jar# 3.最后代码规范校验## (单个项⽬校验)⽂件放置⽬录# 1./var/opt/gitlab/git-data/repositories/@hashed/xx/xx/或者/var/opt/gitlab/git-data/repositories/${group}/${project_name}.git/# 2.创建custom_hooks⽬录# 3.在custom_hooks⽬录下创建pre-receive⽂件,并保持776可执⾏权限,且保持该⽂件权限:chown git:git pre-receive 以及阿⾥云的p3c-pmd的jar包权限# 4.给chown -R git:git custom_hooks# 5.官⽅⽂档说明:/ee/administration/custom_#setup# @author amzheng@# @date 2021-04-09# @description 在服务端接收提交⽂件时检查备注规范以及代码规范,如不符合规范会被退回####### 初始化变量部分 ########### 定义java_home变量 需要修改你配置的java_homeJAVA_HOME=/usr/local/jdk/jdk1.8.0_191## 是否开启commit message的校验:0是,1否CHECK_COMMIT_MESSAGE_ON=0## 是否开启代码检查:0是,1否CHECK_CODE_RULE_ON=0## 是否校验master上的pom⽂件是否包含snapshot:0是,1否CHECK_MASTER_POM_SNAPSHOT_ON=1## 注释内容最⼩长度,默认20COMMIT_MESSAGE_MIN_LENGTH=20### 代码校验规则:0使⽤阿⾥云P3C规则,1使⽤checkStyleCODE_RULE_TYPE=0## 定义提交开头类型字符规则## e.g: fix:测试提交bug修复,Bug编号#12TYPE_LIST=( 'feat:' #新功能feature 'update:' #在feat内修改 'fix:' #修补bug 'docs:' #⽂档 'style:' #格式化,不影响代码运⾏的变动 'refactor:' #重构 'pref:' #性能优化 'test:' #增加测试 'chore:' #构建过程或辅助⼯具的变动 #'[ci skip]' #忽略校验)## 获取当前路径BASE_PATH=$(cd `dirname $0`; pwd)#echo 'BASE_PATH: '$BASE_PATH#定义和组装校验规则declare -a regex_listarrLen=${#TYPE_LIST[@]}for ((i=0;i<$arrLen;i++)) do regex_list[i]='^'${TYPE_LIST[i]}doneregex_list[$arrLen+1]='^[ci skip]:'#echo "reg_list=== "${regex_list[@]}separator="|"## 合并成⼀个完整的正则表达式regex="$( printf "${separator}%s" "${regex_list[@]}" )"regex="$( printf "${separator}%s" "${regex_list[@]}" )"#echo "type regex: "$regex## 去除头部的 |regex=${regex:${#separator}}#echo "regex: "$regex## 定义注释出错提⽰信息tips_msg="$( printf "${separator}%s" "${TYPE_LIST[@]}" )"tips_msg=${tips_msg:${#separator}}####### 初始化变量部分 ################ 校验部分:注释校验&代码分析############# 校验commit messagevalidate_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 #获取提交内容 msg=`git cat-file commit $s | sed '1,/^$/d'` echo 'msg: '$msg ## merge合并分之直接放⾏ if [[ $msg == *"Merge branch"* ]]; then echo "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}" exit 1 fi ### 找到匹配内容做相应处理,如fix ,校验pom⽂件等 #if [[ "${match}" =~ "fix:" ]]; then ## 如果是修补bug,规范有点获取到fix中的ID,然后调⽤禅道对外的API关闭,其他场景类似 #fi #fi # 是否开启校验和master分之 isMaster=$(echo $refname | grep "master$") if [ $CHECK_MASTER_POM_SNAPSHOT_ON == 0 ] && [ -n "$isMaster" ]; then # 如果是master分之,并且pom⽂件发⽣了变更,判断pom⽂件是否含有sonapshot的引⽤ pomfile=`git diff --name-only ${oldrev} ${newrev} | grep -e ""` 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 master branch!" exit 1 fi fi fi ## 其他操作 echo "Commit comments validate Success!" else echo -e "Error: Commit comments message should be started with [${tips_msg}]..." exit 1 fi fidone}## 代码校验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: '$refnameTEMPDIR=$BASE_PATH/"tmp"FILES=`git diff --name-only ${oldrev} ${newrev} | grep -e ".java$"`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 ' #echo 'Current shell Path:' $BASE_PATH #echo 'JAVA_HOME:' $JAVA_HOME #echo 'Root directory for java sources: '$MAIN_JAVA_PATH if [[ $CODE_RULE_TYPE == 0 ]]; then ## 需要阿⾥云P3C的插件包与该脚本在同级⽬录下 echo 'Code analysis for Aliyun-p3c..' echo 'Code analysis for Aliyun-p3c..' #$JAVA_HOME/bin/java -ge=en -cp $BASE_PATH/ -d $MAIN_JAVA_PATH -R rulesets/java/,rulesets/java/,rulesets/java/,rulesets/java/,rulesets/java/,rulesets/java/,rulesets/java/,rulesets/java/,rulesets/java/,rulesets/java/ -f text $JAVA_HOME/bin/java -ge=en -cp $BASE_PATH/ -d $TEMPDIR -R rulesets/java/,rulesets/java/,rulesets/java/,rulesets/java/,rulesets/java/,rulesets/java/,rulesets/java/,rulesets/java/,rulesets/java/ -f text RESULT=$? #echo $RESULT if [ $RESULT -gt 0 ]; then rm -rf $TEMPDIR exit 1; fi elif [[ $CODE_RULE_TYPE == 1 ]]; then ## 需要CheckStyle插件包checkstyle-8.16-all与该脚本在同级⽬录下,并且需要对应的模板⽂件e.g:Cheetah_Checkstyle_ echo 'Code analysis for CheckStyle..' CHECK_RESULT=`$JAVA_HOME/bin/java -jar $BASE_PATH/ -c $BASE_PATH/Cheetah_Checkstyle_ $MAIN_JAVA_PATH` echo 'Check_style check result:' #echo $CHECK_RESULT

if [[ $CHECK_RESULT =~ "[WARN]" ]]; then echo $CHECK_RESULT | sed 's/[WARN]/n/g' rm -rf $TEMPDIR exit 1 fi else ## 不⽀持的检查操作 echo "Unsupported code validation rule,Please contact the administrator to check the configuration of [CODE_RULE_TYPE] in pre-receive script!" rm -rf $TEMPDIR exit 1 fi echo 'Code analysis success!'

else echo 'No java code, analysis end!'fiFRONT_FILES=`git diff --name-only ${oldrev} ${newrev} | grep -e ".vue|.js$"`echo 'Start analysis vue & 'if [ -n "$FRONT_FILES" ];then PASS=true for FILE in $FRONT_FILES; do mkdir -p "${TEMPDIR}/`dirname ${FILE}`" >/dev/null git show $newrev:$FILE > ${TEMPDIR}/${FILE} done;

eslint $TEMPDIR/**/*.vue eslint $TEMPDIR/**/*.js check_result=`eslint $TEMPDIR/**/*.vue` if [ ${#check_result[*]} -gt 0 ]; then echo "vue & js code analysis failed!" rm -rf $TEMPDIR exit 1 fi

check_result=`eslint $TEMPDIR/**/*.js` if [ ${#check_result[*]} -gt 0 ]; then echo "vue & js code analysis failed!" rm -rf $TEMPDIR exit 1 fi echo "vue & js code analysis success!" echo "vue & js code analysis success!"else echo 'No vue & js code, analysis end!'firm -rf $TEMPDIR}####### 校验部分:注释校验&代码分析################## 执⾏⼊⼝###########pre_receive(){#commit message 校验if [[ $CHECK_COMMIT_MESSAGE_ON == 0 ]]; then validate_commit_message $1 $2 $3fi#代码规则检查if [[ $CHECK_CODE_RULE_ON == 0 ]]; then validate_code_rules $1 $2 $3fi}# update hook触发会带参数执⾏if逻辑# hooks脚本触发⽆参数执⾏else逻辑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 pre_receive $2 $3 $1 #echo $1'+'$2'+'$3elsewhile read oldrev newrev refnamedo pre_receive $oldrev $newrev $refname #echo $oldrev' '$newrev' '$refnamedonefi####### 执⾏⼊⼝###########exit 04. Eslint配置⽂件:.s = {root: true,parserOptions: { parser: 'babel-eslint' }, env: { browser: true, }, extends: [ // /vuejs/eslint-plugin-vue#priority-a-essential-error-prevention // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules. 'plugin:vue/essential',

// /standard/standard/blob/master/docs/ 'standard' ], // required to lint *.vue files plugins: [ 'html' ], // add your custom rules here rules: { // allow async-await 'generator-star-spacing': 'off', 'generator-star-spacing': 'off', // allow debugger during development 'no-debugger': _ENV === 'production' ? 'error' : 'off', 'no-console': 2, // js语句结尾必须使⽤ ; // 'semi': ['off', 'always'], 'semi': ['error', 'always'], //

三等号 'eqeqeq': 0, //

强制在注释中 //

或 /*

使⽤⼀致的空格 'spaced-comment': 0, //

关键字后⾯使⽤⼀致的空格 'keyword-spacing': 0, //

强制在 function的左括号之前使⽤⼀致的空格 'space-before-function-paren': 0, //

引号类型 "quotes": [0, "single"], "vue/no-parsing-error": [2, { "x-invalid-end-tag": false }] }}5. 拷贝完后需要执⾏以下命令:在/opt/gitlab/embedded/service/gitlab-shell/hooks⽬录下添加pre-receive、、.,并赋予执⾏权限:chmode –R 777在/opt/gitlab/embedded/service/gitlab-shell/hooks⽬录下执⾏如下命令:npm install -g eslint-plugin-vuenpm install eslint-plugin-vue@latest --save-devnpm install vue@latest --save-devnpm install eslint@latest --save-devnpm install eslint-config-standard@latest --save-devnpm install eslint-plugin-html@latest --save-devnpm install eslint-plugin-import@latest --save-devnpm install eslint-plugin-node@latest --save-devnpm install eslint-plugin-promise@latest --save-devnpm install eslint babel-eslint --save-dev在/opt/gitlab/embedded/service/gitlab-shell/hooks⽬录下新建临时⽬录tmp,执⾏如下命令:chown git:git ./hookschown git:git tmp/chown git:git tmp/*

6. ⼤公告成,可以测试⼀下看看了。

发布者:admin,转转请注明出处:http://www.yc00.com/xiaochengxu/1688702028a163741.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信