mirror of
https://github.com/pre-commit/pre-commit-hooks.git
synced 2024-11-22 14:37:12 +08:00
Initial commit.
This commit is contained in:
commit
27291ffa31
19
.coveragerc
Normal file
19
.coveragerc
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[report]
|
||||||
|
exclude_lines =
|
||||||
|
# Don't complain about defensive assertions
|
||||||
|
raise NotImplementedError
|
||||||
|
raise AssertionError
|
||||||
|
|
||||||
|
# Don't complain about non-runnable code
|
||||||
|
if __name__ == .__main__.:
|
||||||
|
|
||||||
|
omit =
|
||||||
|
/usr/*
|
||||||
|
py_env/*
|
||||||
|
*/__init__.py
|
||||||
|
|
||||||
|
# Ignore test coverage
|
||||||
|
tests/*
|
||||||
|
|
||||||
|
# Don't complain about our pre-commit file
|
||||||
|
pre-commit.py
|
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
*.pyc
|
||||||
|
.pydevproject
|
||||||
|
.project
|
||||||
|
.coverage
|
||||||
|
/py_env
|
||||||
|
*.db
|
||||||
|
.idea
|
||||||
|
build
|
||||||
|
dist
|
||||||
|
*.egg-info
|
8
.travis.yml
Normal file
8
.travis.yml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
language: python
|
||||||
|
|
||||||
|
python:
|
||||||
|
- 2.6
|
||||||
|
- 2.7
|
||||||
|
|
||||||
|
install: pip install virtualenv
|
||||||
|
script: make
|
40
Makefile
Normal file
40
Makefile
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
TEST_TARGETS =
|
||||||
|
ITEST_TARGETS = -m integration
|
||||||
|
UTEST_TARGETS = -m "not(integration)"
|
||||||
|
|
||||||
|
all: _tests
|
||||||
|
|
||||||
|
integration:
|
||||||
|
$(eval TEST_TARGETS := $(ITEST_TARGETS))
|
||||||
|
|
||||||
|
unit:
|
||||||
|
$(eval TEST_TARGETS := $(UTEST_TARGETS))
|
||||||
|
|
||||||
|
utests: test
|
||||||
|
utest: test
|
||||||
|
tests: test
|
||||||
|
test: unit _tests
|
||||||
|
itests: itest
|
||||||
|
itest: integration _tests
|
||||||
|
|
||||||
|
_tests: py_env
|
||||||
|
bash -c 'source py_env/bin/activate && py.test tests $(TEST_TARGETS)'
|
||||||
|
|
||||||
|
ucoverage: unit coverage
|
||||||
|
icoverage: integration coverage
|
||||||
|
|
||||||
|
coverage: py_env
|
||||||
|
bash -c 'source py_env/bin/activate && \
|
||||||
|
coverage erase && \
|
||||||
|
coverage run `which py.test` tests $(TEST_TARGETS) && \
|
||||||
|
coverage report -m'
|
||||||
|
|
||||||
|
py_env: requirements.txt
|
||||||
|
rm -rf py_env
|
||||||
|
virtualenv py_env
|
||||||
|
bash -c 'source py_env/bin/activate && \
|
||||||
|
pip install -r requirements.txt'
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf py_env
|
6
README.md
Normal file
6
README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
pre-commit-hooks
|
||||||
|
==========
|
||||||
|
|
||||||
|
Some out-of-the-box hooks for pre-commit.
|
||||||
|
|
||||||
|
See also: https://github.com/asottile/pre-commit
|
225
pre-commit.py
Executable file
225
pre-commit.py
Executable file
@ -0,0 +1,225 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import optparse
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def __backport_check_output():
|
||||||
|
def check_output(*popenargs, **kwargs):
|
||||||
|
r"""Run command with arguments and return its output as a byte string.
|
||||||
|
|
||||||
|
Backported from Python 2.7 as it's implemented as pure python on stdlib.
|
||||||
|
|
||||||
|
>>> check_output(['/usr/bin/python', '--version'])
|
||||||
|
Python 2.6.2
|
||||||
|
"""
|
||||||
|
process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
|
||||||
|
output, unused_err = process.communicate()
|
||||||
|
retcode = process.poll()
|
||||||
|
if retcode:
|
||||||
|
cmd = kwargs.get("args")
|
||||||
|
if cmd is None:
|
||||||
|
cmd = popenargs[0]
|
||||||
|
error = subprocess.CalledProcessError(retcode, cmd)
|
||||||
|
error.output = output
|
||||||
|
raise error
|
||||||
|
return output
|
||||||
|
|
||||||
|
if not hasattr(subprocess, 'check_output'):
|
||||||
|
setattr(subprocess, 'check_output', check_output)
|
||||||
|
|
||||||
|
__backport_check_output()
|
||||||
|
del __backport_check_output
|
||||||
|
|
||||||
|
|
||||||
|
FILE_LIST = 'git ls-files | egrep "\.%s$"'
|
||||||
|
|
||||||
|
ALL_FILES = FILE_LIST % '(php|sql|py|js|htm|c|cpp|h|sh|css)'
|
||||||
|
JS_FILES = FILE_LIST % 'js'
|
||||||
|
PY_FILES = FILE_LIST % 'py'
|
||||||
|
CPP_FILES = FILE_LIST % '(cc|cpp|h)'
|
||||||
|
C_FILES = FILE_LIST % '(c|h)'
|
||||||
|
C_LIKE_FILES = FILE_LIST % '(c|cc|cpp|h)'
|
||||||
|
HEADER_FILES = FILE_LIST % 'h'
|
||||||
|
|
||||||
|
RED = '\033[41m'
|
||||||
|
GREEN = '\033[42m'
|
||||||
|
NORMAL = '\033[0m'
|
||||||
|
COLS = int(subprocess.check_output(['tput', 'cols']))
|
||||||
|
|
||||||
|
Test = collections.namedtuple('Test', ['command', 'name', 'nonzero', 'config'])
|
||||||
|
|
||||||
|
TESTS = [
|
||||||
|
Test(
|
||||||
|
"%s | xargs pyflakes" % PY_FILES,
|
||||||
|
'Py - Pyflakes',
|
||||||
|
False, 'testpyflakes',
|
||||||
|
),
|
||||||
|
Test(
|
||||||
|
"%s | xargs grep 'import\sipdb'" % PY_FILES,
|
||||||
|
'Py - ipdb',
|
||||||
|
True, 'testipdb',
|
||||||
|
),
|
||||||
|
Test(
|
||||||
|
"%s | grep 'tests' | grep -v '_test.py$' | grep -v '__init__.py' | grep -v '/conftest.py'" % PY_FILES,
|
||||||
|
'Py - Test files should end in _test.py',
|
||||||
|
True, 'testtestnames',
|
||||||
|
),
|
||||||
|
Test(
|
||||||
|
"%s | xargs egrep 'split\(.\\\\n.\)'" % PY_FILES,
|
||||||
|
'Py - Use s.splitlines over s.split',
|
||||||
|
True, 'testsplitlines',
|
||||||
|
),
|
||||||
|
Test(
|
||||||
|
"%s | xargs grep -H -n -P '\t'" % ALL_FILES,
|
||||||
|
"All - No tabs",
|
||||||
|
True, 'testtabs',
|
||||||
|
),
|
||||||
|
Test(
|
||||||
|
"make test",
|
||||||
|
"Py - Tests",
|
||||||
|
False, 'testtests',
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_git_config(config_name):
|
||||||
|
config_result = ''
|
||||||
|
try:
|
||||||
|
config_result = subprocess.check_output([
|
||||||
|
'git', 'config', config_name
|
||||||
|
])
|
||||||
|
except subprocess.CalledProcessError: pass
|
||||||
|
|
||||||
|
return config_result.strip()
|
||||||
|
|
||||||
|
def get_pre_commit_path():
|
||||||
|
git_top = subprocess.check_output(
|
||||||
|
['git', 'rev-parse', '--show-toplevel']
|
||||||
|
).strip()
|
||||||
|
return os.path.join(git_top, '.git/hooks/pre-commit')
|
||||||
|
|
||||||
|
class FixAllBase(object):
|
||||||
|
name = None
|
||||||
|
matching_files_command = None
|
||||||
|
|
||||||
|
def get_all_files(self):
|
||||||
|
try:
|
||||||
|
files = subprocess.check_output(
|
||||||
|
self.matching_files_command,
|
||||||
|
shell=True,
|
||||||
|
)
|
||||||
|
files_split = files.splitlines()
|
||||||
|
return [file.strip() for file in files_split]
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
return []
|
||||||
|
|
||||||
|
def fix_file(self, file):
|
||||||
|
'''Implement to fix the file.'''
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
'''Runs the process to fix the files. Returns True if nothign to fix.'''
|
||||||
|
print '%s...' % self.name
|
||||||
|
all_files = self.get_all_files()
|
||||||
|
for file in all_files:
|
||||||
|
print 'Fixing %s' % file
|
||||||
|
self.fix_file(file)
|
||||||
|
return not all_files
|
||||||
|
|
||||||
|
class FixTrailingWhitespace(FixAllBase):
|
||||||
|
name = 'Trimming trailing whitespace'
|
||||||
|
matching_files_command = '%s | xargs egrep -l "[[:space:]]$"' % ALL_FILES
|
||||||
|
|
||||||
|
def fix_file(self, file):
|
||||||
|
subprocess.check_call(['sed', '-i', '-e', 's/[[:space:]]*$//', file])
|
||||||
|
|
||||||
|
class FixLineEndings(FixAllBase):
|
||||||
|
name = 'Fixing line endings'
|
||||||
|
matching_files_command = "%s | xargs egrep -l $'\\r'\\$" % ALL_FILES
|
||||||
|
|
||||||
|
def fix_file(self, file):
|
||||||
|
subprocess.check_call(['dos2unix', file])
|
||||||
|
subprocess.check_call(['mac2unix', file])
|
||||||
|
|
||||||
|
FIXERS = [
|
||||||
|
FixTrailingWhitespace,
|
||||||
|
FixLineEndings,
|
||||||
|
]
|
||||||
|
|
||||||
|
def run_tests():
|
||||||
|
passed = True
|
||||||
|
for test in TESTS:
|
||||||
|
run_test = get_git_config('hooks.%s' % test.config)
|
||||||
|
if run_test == 'false':
|
||||||
|
print 'Skipping "%s" due to git config.' % test.name
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
retcode = 0
|
||||||
|
output = subprocess.check_output(
|
||||||
|
test.command, shell=True, stderr=subprocess.STDOUT
|
||||||
|
)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
retcode = e.returncode
|
||||||
|
output = e.output
|
||||||
|
|
||||||
|
pass_fail = '%sSuccess%s' % (GREEN, NORMAL)
|
||||||
|
failed_test = False
|
||||||
|
if (retcode and not test.nonzero) or (not retcode and test.nonzero):
|
||||||
|
pass_fail = '%sFailure(%s)%s' % (RED, retcode, NORMAL)
|
||||||
|
failed_test = True
|
||||||
|
|
||||||
|
dots = COLS - len(pass_fail) - len(test.name)
|
||||||
|
print '%s%s%s' % (test.name, '.' * dots, pass_fail)
|
||||||
|
|
||||||
|
if failed_test:
|
||||||
|
print
|
||||||
|
print output
|
||||||
|
passed = False
|
||||||
|
|
||||||
|
return passed
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = optparse.OptionParser()
|
||||||
|
parser.add_option(
|
||||||
|
'-u', '--uninstall',
|
||||||
|
action='store_true', dest='uninstall', default=False,
|
||||||
|
help='Uninstall pre-commit script.'
|
||||||
|
)
|
||||||
|
parser.add_option(
|
||||||
|
'-i', '--install',
|
||||||
|
action='store_true', dest='install', default=False,
|
||||||
|
help='Install pre-commit script.'
|
||||||
|
)
|
||||||
|
opts, args = parser.parse_args()
|
||||||
|
|
||||||
|
if opts.install:
|
||||||
|
pre_commit_path = get_pre_commit_path()
|
||||||
|
shutil.copyfile(__file__, pre_commit_path)
|
||||||
|
os.chmod(pre_commit_path, 0755)
|
||||||
|
print 'Installed pre commit to %s' % pre_commit_path
|
||||||
|
sys.exit(0)
|
||||||
|
elif opts.uninstall:
|
||||||
|
pre_commit_path = get_pre_commit_path()
|
||||||
|
if os.path.exists(pre_commit_path):
|
||||||
|
os.remove(pre_commit_path)
|
||||||
|
print 'Removed pre-commit scripts.'
|
||||||
|
|
||||||
|
passed = True
|
||||||
|
for fixer in FIXERS:
|
||||||
|
passed &= fixer().run()
|
||||||
|
passed &= run_tests()
|
||||||
|
|
||||||
|
if not passed:
|
||||||
|
print '%sFailures / Fixes detected.%s' % (RED, NORMAL)
|
||||||
|
print 'Please fix and commit again.'
|
||||||
|
print "You could also pass --no-verify, but you probably shouldn't."
|
||||||
|
print
|
||||||
|
print "Here's git status for convenience: "
|
||||||
|
print
|
||||||
|
os.system('git status')
|
||||||
|
sys.exit(-1)
|
0
pre_commit_hooks/__init__.py
Normal file
0
pre_commit_hooks/__init__.py
Normal file
10
requirements.txt
Normal file
10
requirements.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
argparse
|
||||||
|
pyyaml
|
||||||
|
simplejson
|
||||||
|
|
||||||
|
# Testing requirements
|
||||||
|
coverage
|
||||||
|
ipdb
|
||||||
|
mock
|
||||||
|
pyflakes
|
||||||
|
pytest
|
12
setup.py
Normal file
12
setup.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
from setuptools import find_packages
|
||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='pre_commit_hooks',
|
||||||
|
version='0.0.0',
|
||||||
|
packages=find_packages('.', exclude=('tests*', 'testing*')),
|
||||||
|
install_requires=[
|
||||||
|
'argparse',
|
||||||
|
'simplejson',
|
||||||
|
],
|
||||||
|
)
|
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
Loading…
Reference in New Issue
Block a user