Adding a check for readability.
This commit is contained in:
parent
efd187e955
commit
1db5feac16
22
README.rst
22
README.rst
|
@ -12,26 +12,30 @@ checkers against changed files in your current working directory or
|
|||
staging area. It can be configured to work with any `lint` command.
|
||||
Some commands may require shell wrappers.
|
||||
|
||||
While it may be possible to create a custom lint command in your npm,
|
||||
grunt, Make, CMake, or whatever, the fact is we all use a VCS, and
|
||||
most of us use git. Having a centralized repository for what we want
|
||||
checked and how we want it checked, associated with git (and by
|
||||
extension, as a pre-commit hook), that can be run at any time for any
|
||||
reason.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Highly configurable - configuration files, both for git-lint and
|
||||
individual linters, can be global or per-project.
|
||||
|
||||
* Only checks what has been changed, but this can be overriden from the
|
||||
command line.
|
||||
|
||||
* For some linters, can lint both full-files and or only the parts that
|
||||
have changed.
|
||||
* Only checks files that have been changed, but this can be overriden
|
||||
from the command line.
|
||||
|
||||
* Can be used directly as a pre-commit hook, to ensure you personally
|
||||
don't check in anything broken.
|
||||
|
||||
* Used this way, it checks the *staging* area, not your workspace.
|
||||
* Used this way, it checks the *staging* area, not your workspace.
|
||||
|
||||
* When using the staging area, it stashes your current work. Upon
|
||||
restoration of your workspace, it ensures the timestamps are the
|
||||
same, so as not to confuse your build system or IDE.
|
||||
* When using the staging area, it stashes your current work. Upon
|
||||
restoration of your workspace, it ensures the timestamps are the
|
||||
same, so as not to confuse your build system or IDE.
|
||||
|
||||
Credits
|
||||
-------
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
#!/usr/bin/env python
|
||||
from __future__ import print_function
|
||||
from functools import reduce
|
||||
import subprocess
|
||||
import os.path
|
||||
import getopt
|
||||
import sys
|
||||
import re
|
||||
import os
|
||||
|
||||
import gettext
|
||||
_ = gettext.gettext
|
||||
|
||||
|
||||
def fullshell(cmd):
|
||||
process = subprocess.Popen(cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
(stdout, stderr) = process.communicate()
|
||||
return (stdout, stderr, process.returncode)
|
||||
|
||||
|
||||
def path_which(scriptname):
|
||||
def is_executable(path):
|
||||
return os.path.exists(path) and os.access(path, os.X_OK)
|
||||
|
||||
possibles = [path for path in
|
||||
[os.path.join(path, scriptname)
|
||||
for path in os.environ.get('PATH').split(':')]
|
||||
if is_executable(path)]
|
||||
|
||||
return (len(possibles) and possibles.pop(0)) or False
|
||||
|
||||
|
||||
def main(*args):
|
||||
(opts, filenames) = getopt.getopt(args[1:], '', ['min=', 'max='])
|
||||
options = {re.sub('^\-+', '', i[0]): i[1] for i in opts}
|
||||
style = path_which('style')
|
||||
if not style:
|
||||
sys.exit(_('Could not find the style program'))
|
||||
if len(filenames) == 0:
|
||||
sys.exit(_('No files specifed to scan'))
|
||||
(values, error, returncode) = fullshell([style, filenames[0]])
|
||||
if returncode != 0:
|
||||
print(error)
|
||||
return returncode
|
||||
kincaid = re.search(r'Kincaid:\s*([\d\.]+)', values, re.MULTILINE)
|
||||
val = float(kincaid.group(1))
|
||||
|
||||
msg = ""
|
||||
if options.get('min', None):
|
||||
if val < int(options.get('min')):
|
||||
msg = _('Readability too low')
|
||||
if options.get('max', None):
|
||||
if val > int(options.get('max')):
|
||||
msg = _('Readability too high')
|
||||
print(_("{}: {} {}").format(filenames[0], val, msg))
|
||||
return (msg != "" and 1) or 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
sys.exit(main(*sys.argv))
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,17 +1,38 @@
|
|||
#!/usr/bin/env python
|
||||
from git_lint import load_config, run_linters, git_base
|
||||
|
||||
import gettext
|
||||
_ = gettext.gettext
|
||||
|
||||
|
||||
def main(*args):
|
||||
if git_base is None:
|
||||
sys.exit(_('A git repository was not found.'))
|
||||
|
||||
pre_commit_config = {
|
||||
pre_commit_options = {
|
||||
'staging': True,
|
||||
'base': True
|
||||
}
|
||||
|
||||
config = load_config(pre_commit_config, git_base)
|
||||
return run_linters(pre_commit_config, config, [])
|
||||
config = load_config(pre_commit_options, git_base)
|
||||
|
||||
(results,
|
||||
unlintable_filenames,
|
||||
cant_lint_filenames,
|
||||
broken_linter_names,
|
||||
unfindable_filenames) = run_linters(options, config)
|
||||
|
||||
print_report(results,
|
||||
unlintable_filenames,
|
||||
cant_lint_filenames,
|
||||
broken_linter_names,
|
||||
unfindable_filenames,
|
||||
options)
|
||||
|
||||
if not len(results):
|
||||
return 0
|
||||
|
||||
return max([i[2] for i in results if len(i)])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -188,6 +188,7 @@ def executable_exists(script, label):
|
|||
if scriptname.startswith('/'):
|
||||
return (is_executable(scriptname) and scriptname) or None
|
||||
|
||||
# shutil.which() doesn't appear until Python 3, darnit.
|
||||
possibles = [path for path in
|
||||
[os.path.join(path, scriptname)
|
||||
for path in os.environ.get('PATH').split(':')]
|
||||
|
@ -253,6 +254,9 @@ def get_filelist(options, extras):
|
|||
stream = [entry for entry in get_git_response(cmd).split(u'\x00')
|
||||
if len(entry) > 0]
|
||||
|
||||
# Yeah, baby, recursion, the way this is meant to be handled.
|
||||
# If you have more than 999 files that need linting, you have
|
||||
# a bigger problem...
|
||||
def parse_stream(acc, stream):
|
||||
"""Parse the list of files. T
|
||||
|
||||
|
@ -420,7 +424,7 @@ class Linters:
|
|||
return reduce(operator.add, [dryrunonce(linter, self.filenames) for linter in self.linters], [])
|
||||
|
||||
|
||||
def run_linters(options, config, extras):
|
||||
def run_linters(options, config, extras=[]):
|
||||
|
||||
def build_config_subset(keys):
|
||||
""" Returns a subset of the configuration, with only those linters mentioned in keys """
|
||||
|
|
Loading…
Reference in New Issue