1. 概述
对于Git通过Hook实现静态代码检测,大致分为两个方向:
1>借助Client-Side-Hook来实现。
此方法对应于研发人员工作机上的${PROJECT_ROOT}/.git/hooks/pre-commit脚本实现。
2>借助Server-Side-Hook来实现。
此方法分为2个方面,一个是全局性配置(下面会详细介绍),一个是对应对单独项目进行配置,此方法对应于Git服务端的
/var/opt/gitlab/git-data/repositories/<group>/<project>.git/custom_hooks/pre-receive脚本。
相比较之下,两种实现方式之中,第二种方式有点更明显,其无需研发人员进行任何的本地操作,这里详细讲解gitlab的全局配置。
3>使用关键组件包括:
checkstyle8.17+python2.7.5+jdk1.8
python 的版本不能超过3.0
Jdk 版本最低为1.8
2.操作步骤
2.1:上传文件
登录Gitlab服务
1.创建文件路径,执行命令:
mkdir -p /data/gitlab.checkstyle
2.进入文件中
cd /data/gitlab.checkstyle
3.将checkstyle.xml和checkstyle-8.17-all.jar 文件上传到gitlab.checkstyle
4.验证是否正确
可执行命令:
java -jar /data/gitlab.checkstyle/checkstyle-8.17-all.jar -c/data/gitlab.checkstyle/checkstyle.xml /data/gitlab.checkstyle/TestController.java
如有些类似输出内容即表示环境正确。
TestController.java文件可自行上传。
checkstyle.xml文件可自行网上查找,可使用谷歌或阿里的都可以。
2.1.配置gitlab全局钩子
1.创建自定义全局钩子目录
cd /opt/gitlab/embedded/service/gitlab-shell/
mkdir custom_hooks
2.指定全局自定义钩子目录
修改 /etc/gitlab/gitlab.rb 配置文件中的配置项:gitlab_shell['custom_hooks_dir']内容为:
/opt/gitlab/embedded/service/gitlab-shell/custom_hooks
原内容为:
修改内容为:
/opt/gitlab/embedded/service/gitlab-shell/custom_hooks
vi /etc/gitlab/gitlab.rb
3.使自定义内容生效
操作完成后,执行命令使配置生效:
sudo gitlab-ctl reconfigure
2.3上传代码规范检查脚本
1.进入全局自定义钩子目录下:
cd /opt/gitlab/embedded/service/gitlab-shell/custom_hooks
2.创建pre-receive.d文件夹
mkdir pre-receive.d
cd pre-receive.d
3.上传附件中的pre-receive文件到pre-receive.d文件目录下并赋予可执行权限
chmod +777 pre-receive
4.pre-receive脚本内容为:
#!/usr/bin/python
#coding=utf-8
import os
import sys
import subprocess
import tempfile
import shutil
__author__ = "lance"
class Trigger(object):
def __init__(self):
'''
初始化文件列表信息,提交者信息,提交时间,当前操作的分支
'''
self.pushAuthor = ""
self.pushTime = ""
self.fileList = []
self.ref = ""
def __getGitInfo(self):
'''
'''
self.oldObject, self.newObject, self.ref = sys.stdin.readline().strip().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')
#循环获取每次提交的文件列表
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
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 getGitPushInfo(self):
self.__getGitInfo()
self.__getPushInfo()
# 处理java文件
def handler_checkstyle(self, file):
try:
cmd = r'java -jar /data/gitlab.checkstyle/lib/checkstyle-8.17-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()
if len(rpipe)>2:
print(rpipe)
exit(1)
finally:
shutil.rmtree(file)
#pass
if __name__ == "__main__":
#print("argv: ", sys.argv)
t = Trigger()
t.getGitPushInfo()
exit(0)
3.验证
对于不合规的内容输出异常提示:
如果想了解单独配置和全局配置下想单独排查某项目的步骤,欢迎联系。
以上为全部内容。
欢迎关注10W+的微信公众号:
技术难点欢迎咨询,如有需要加我微信:1106915848。
星光不问赶路人,时光不负有心人