使用git hook实现提交前自动检查Python代码语法
客户端项目钩子
git hook 可以实现在提交代码前执行代码检查等操作,下面实现在执行git commit
时检查 Python 代码:
在项目的 .git/hooks/
创建 pre-commit
文件,写入如下内容:
#!/usr/bin/python
# coding=utf-8
""" 代码提交前实现自动语法检测 """
import os
import sys
import subprocess
def syntax_checker():
"""
pyflakes 与 pep8 进行语法与代码风格检查。
有严重语法错误时提交会被直接拒绝;
如果有风格问题,会询问提交人员是否继续进行提交
"""
errors = ''
warning = ''
info = ''
pep8_info = ''
# 获取有改动的文档
staged_cmd = 'git diff --staged --name-only HEAD'
proc = subprocess.Popen(staged_cmd, shell=True, stdout=subprocess.PIPE)
with proc.stdout as std_out:
for staged_file in std_out.readlines():
staged_file = staged_file.strip()
if not is_python_file(staged_file):
continue
stdout, stderr = process('pyflakes %s' % staged_file)
warning += stdout
errors += stderr
# stdout, _ = process('pep8 %s' % staged_file)
# pep8_info += stdout
stdout, _ = process('cat %s' % staged_file)
for i, line in enumerate(stdout.split('\n'), start=1):
line = line.strip()
if line.startswith('#'):
continue
if 'print' in line:
info += "{}:{}: It seems you have commit test code: '{}'\n".format(
staged_file, i, line)
if line.startswith('if __name__'):
break
failed = False
if is_error(errors) or is_warning(warning) or is_warning(
pep8_info) or is_warning(info):
failed = True
return failed
def is_python_file(filename):
if filename.endswith('.py') and os.path.exists(filename):
return True
return False
def process(cmd):
""" 执行命令, 返回标准输出与错误信息 """
proc = subprocess.Popen(
cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return proc.communicate()
def is_error(errors):
""" 严重错误,如语法错误等 """
failed = False
if errors:
failed = True
print("\033[0;31mError:\033[0m You cann't commit, please fix the errors "
"or run `pyflakes xxx.py` view details:"
"\n-------------------------------------------")
print errors
return failed
def is_warning(warning):
""" 代码规范建议信息 """
failed = False
if warning:
print '\033[0;33mWarning:\033[0m', warning
# 从终端输入
sys.stdin = open('/dev/tty')
input_row = raw_input("Encounter some non-standard syntax! "
"Do you want to continue commit? [Y/n]: ")
while True:
# input_row = sys.stdin.readline().strip().lower()
input_row = input_row.strip().lower()
if input_row in ('y', 'yes'):
failed = False
break
elif input_row in ('n', 'no'):
failed = True
break
input_row = raw_input("Do you want to continue commit? [Y/n]: ")
return failed
failed = syntax_checker()
sys.exit(1 if failed else 0)
全局钩子
如果想让钩子对所有的项目目录生效,只需要把pre-commit
移到 ~/.git/hooks
目录下(没有就创建一个),然后执行命令
git config --global core.hooksPath ~/.git/hooks
效果
代码有错误时直接禁止提交:
代码语法不规范时,提示建议信息:
关注微信公众账号「曹当家的」,订阅最新文章推送