本文講述如何在gitlab 服務器上,拒絕用戶推送不合規范的 java 代碼
1、一般在倉庫的/var/opt/gitlab/git-data/repositories/<group>/<project>.git目錄 下創建目錄:custom_hooks
2、新增 可執行文件:pre-receive (腳本可以是任何ruby python shell可執行腳本,沒有后綴名)輸入內容如下:
#!/usr/bin/python #coding=utf-8 import os import sys import subprocess import tempfile import shutil from shutil import copyfile __author__ = "lance" class Trigger(object): def __init__(self): ''' 初始化文件列表信息,提交者信息,提交時間,當前操作的分支 ''' self.pushAuthor = "" self.pushTime = "" self.fileList = [] self.ref = "" def __getGitInfo(self): value = sys.stdin.readline().strip() self.oldObject, self.newObject,self.ref = value.split(' ') def __getPushInfo(self): ''' git show命令獲取push作者,時間,以及文件列表 文件的路徑為相對於版本庫根目錄的一個相對路徑 ''' rev = subprocess.Popen('git rev-list '+self.newObject,shell=True,stdout=subprocess.PIPE) revList = rev.stdout.readlines() revList = [x.strip() for x in revList] #查找從上次提交self.oldObject之后還有多少次提交,即本次push提交的object列表 indexOld = revList.index(self.oldObject) pushList = revList[:indexOld] pushList.reverse() # temp file tempdir = tempfile.mkdtemp('git_hook') #循環獲取每次提交的文件列表i diff_file_list = [] for pObject in pushList: p = subprocess.Popen('git show '+pObject,shell=True,stdout=subprocess.PIPE) pipe = p.stdout.readlines() pipe = [x.strip() for x in pipe] #print("===>",pipe) #驗證是否java文件 file = pipe[6].strip("diff").strip() if not file.lower().endswith('.java'): continue filename = file.split('/')[-1] #git get Tree print(pipe) content_hash = pipe[7].strip("index").strip()[9:16] content_p = subprocess.Popen('git cat-file -p '+content_hash,shell=True,stdout=subprocess.PIPE) cpipe = content_p.stdout.readlines() #print(cpipe) with open(os.path.join(tempdir, filename), 'w+') as fp: fp.writelines(cpipe) self.handler_checkstyle(tempdir+"/"+content_hash+'.java') # checkstyle self.handler_checkstyle(tempdir) def handler_checkstyle(self, file): try: #print(file) cmd = r'java -jar /data/gitlab.checkstyle/lib/checkstyle-8.20-all.jar -c /data/gitlab.checkstyle/style/checkstyle.xml ' + file+'/' #print(cmd) result = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) rpipe = result.stdout.readlines() stuerr_message = result.stderr.readlines() #print(stuerr_message) for index in range(0,len(rpipe)): # print('\n') print(rpipe[index]) if len(rpipe) > 2: exit(1) except Exception as e: print('error message:'+e.message) exit(1) finally: #shutil.rmtree(file) pass def getGitPushInfo(self): self.__getGitInfo() self.__getPushInfo() if __name__ == "__main__": #print("argv: ", sys.argv) t = Trigger() t.getGitPushInfo() print('success') exit(0)
注:如果這些腳本在window中編輯后上傳到服務器;vim編輯時:set ff=unix 來重新編輯文件格式
3、使用的jar包的位置:/data/gitlab.checkstyle/lib/checkstyle-8.20-all.jar
4、使用的xml的位置:/data/gitlab.checkstyle/style/checkstyle.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd"> <!-- This is a checkstyle configuration file. For descriptions of what the following rules do, please see the checkstyle configuration page at http://checkstyle.sourceforge.net/config.html --> <module name="Checker"> <!-- 重復代碼的檢查,超過20行就認為重復,UTF-8格式--> <module name="TreeWalker"> <!-- 命名方面的檢查,它們都使用了Sun官方定的規則。 --> <!-- 局部的final變量,包括catch中的參數的檢查 --> <module name="LocalFinalVariableName" /> <!-- 局部的非final型的變量,包括catch中的參數的檢查 --> <!--<module name="LocalVariableName" />--> <!-- 包名的檢查(只允許小寫字母) --> <module name="PackageName"> <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$" /> </module> <!-- 僅僅是static型的變量(不包括static final型)的檢查 --> <module name="StaticVariableName" /> <!-- 類型(Class或Interface)名的檢查 --> <module name="TypeName" /> <!-- 非static型變量的檢查 --> <module name="MemberName" /> <!-- 方法名的檢查 --> <module name="MethodName" /> <!-- 方法的參數名 --> <!--<module name="ParameterName " />--> <!-- 常量名的檢查 --> <module name="ConstantName" /> <!-- 對區域的檢查 --> <!-- 不能出現空白區域 --> <module name="EmptyBlock" /> <!-- 所有區域都要使用大括號。 --> <module name="NeedBraces" /> <!-- 多余的括號 --> <module name="AvoidNestedBlocks"> <property name="allowInSwitchCase" value="true" /> </module> <!-- String的比較不能用!= 和 == --> <module name="StringLiteralEquality" /> <!-- 同一行不能有多個聲明 --> <module name="MultipleVariableDeclarations" /> <!-- 不必要的圓括號 --> <module name="UnnecessaryParentheses" /> <module name="UncommentedMain" /> <!-- 檢查並確保所有的常量中的L都是大寫的。因為小寫的字母l跟數字1太象了 --> <module name="UpperEll" /> <!-- 檢查數組類型的定義是String[] args,而不是String args[] --> <module name="ArrayTypeStyle" /> <module name="MagicNumber"> <property name="tokens" value="NUM_DOUBLE, NUM_FLOAT"/> <property name="ignoreNumbers" value="0,1"/> <property name="ignoreAnnotation" value="true"/> </module> </module> </module>
開始測試:
1.包名必須匹配正則:(反例中包含大寫)
^[a-z]+(\.[a-z][a-z0-9]*)*$
2.變量名必須匹配正則:(反例中以$開頭)
^[a-z]+(\.[a-z][a-z0-9]*)*$
3.字符串數字匹配 Sring[] args 而不是 String args[]
4.字符串的比較用 equals 不能用 ==
5.空的main 方法檢查
執行結果如圖