本文讲述如何在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 方法检查
执行结果如图