Gitlab Custom_hooks集代碼規則&註釋校驗腳本(pre-receive)

#!/bin/bash

##腳本提供功能:Commit提交的Message和代碼規範是否符合統一規範
##分三個部分:
# 1.變量定義部分
# 2.校驗部分:註釋校驗&代碼分析
# 3.初始化入口
## 校驗流程:
# 1.先做提交註釋校驗,校驗的規則:是否已${TYPE_LIST}定義的開頭,且內容長度是否大於${COMMIT_MESSAGE_MIN_LENGTH}
# 2.如果是master分之,修改了pom文件還會校驗是否存在snapshot版本的jar
# 3.最後代碼規範校驗

####### 初始化變量部分 #########

## 定義java_home變量 需要修改你配置的java_home
JAVA_HOME=/usr/local/jdk1.8.0_141
## 是否開啓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
## 註釋內容最小長度,默認20
COMMIT_MESSAGE_MIN_LENGTH=20
### 代碼校驗規則:0使用阿里雲P3C規則,1使用checkStyle
CODE_RULE_TYPE=0

## 定義提交開頭類型字符規則
## e.g: fix:測試提交bug修復,Bug編號#12 
TYPE_LIST=(
         'feat:'   #新功能feature
         'update:' #在feat內修改
         'fix:'  #修補bug
         'docs:'  #文檔
         'style:' #格式化,不影響代碼運行的變動
         'refactor:' #重構 
         'pref:'  #性能優化
         'test:'  #增加測試
         'chore:'  #構建過程或輔助工具的變動
         #'[ci skip]'  #忽略校驗
)

## 獲取當前路徑
BASE_PATH=$(cd `dirname $0`; pwd)

#定義和組裝校驗規則
declare -a regex_list
arrLen=${#TYPE_LIST[@]}
for ((i=0;i<$arrLen;i++)) do
  regex_list[i]='^'${TYPE_LIST[i]}
done
regex_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: "$regex

## 定義註釋出錯提示信息
tips_msg="$( printf "${separator}%s" "${TYPE_LIST[@]}" )"
tips_msg=${tips_msg:${#separator}}
####### 初始化變量部分 #########

####### 校驗部分:註釋校驗&代碼分析###########
## 校驗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
      #獲取提交內容
      msg=`git cat-file commit $s | sed '1,/^$/d'`
      #echo 'msg: '$msg
	  
	    ## merge合併分之直接放行
	    if [[ $msg == *"Merge 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}"
            exit 1
          fi

          ### 找到匹配內容做相應處理,如fix ,校驗pom文件等
          #if [[ "${match}" =~ "fix:" ]]; then
            ## 如果是修補bug,規範有點獲取到fix中的ID,然後調用禪道對外的API關閉,其他場景類似
          #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 "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 master branch!"
                exit 1
              fi
            fi
          fi

          ## 其他操作
          echo "Commit Success!"
        else
          echo -e "Error: Commit comments message should be started with [${tips_msg}]..."
          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
   
   FILES=`git diff --name-only ${oldrev} ${newrev}  | grep -e "\.java$"`

   if [ -n "$FILES" ]; then
      TEMPDIR=$BASE_PATH/"tmp"
      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 [[ $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 -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-other.xml,rulesets/java/ali-set.xml -f text
       RESULT=$?
       #echo $RESULT
       if [ $RESULT -gt 0 ]; then
          exit 1;
       fi
      elif [[ $CODE_RULE_TYPE == 1 ]]; then
         ## 需要CheckStyle插件包checkstyle-8.16-all與該腳本在同級目錄下,並且需要對應的CheckStyle.xml模板文件e.g:Cheetah_Checkstyle_ruleset.xml
         echo 'Code analysis for CheckStyle..'
           CHECK_RESULT=`$JAVA_HOME/bin/java -jar $BASE_PATH/checkstyle-8.16-all.jar -c $BASE_PATH/Cheetah_Checkstyle_ruleset.xml $MAIN_JAVA_PATH`
       if [[ $CHECK_RESULT =~ "[WARN]" ]]; then
         echo $CHECK_RESULT | sed 's/\[WARN\]/\n/g'
         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!"
         exit 1
      fi
      
      echo 'End code analysis!'

      rm -rf $TEMPDIR
   fi
}
####### 校驗部分:註釋校驗&代碼分析###########

####### 執行入口###########
pre_receive()
{
    #commit message 校驗
	if [[ $CHECK_COMMIT_MESSAGE_ON == 0 ]]; then
	   validate_commit_message $1 $2 $3
	fi
    
    #代碼規則檢查
	if [[ $CHECK_CODE_RULE_ON == 0 ]]; then
	   validate_code_rules $1 $2 $3
	fi
}

# 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'+'$3
else
    while read oldrev newrev refname
    do
       pre_receive $oldrev $newrev $refname
       #echo $oldrev' '$newrev' '$refname
    done
fi
####### 執行入口###########
exit 0

### 參考文獻:
# https://www.jianshu.com/p/73073bab7337
# https://www.jianshu.com/p/b87ca8615c9c
# https://blog.csdn.net/u012465508/article/details/80788557

相關安裝文檔Github地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章