Skip to content

Instantly share code, notes, and snippets.

@dopuskh3
Created September 22, 2016 13:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dopuskh3/71a5b2be2f502e829d7ef06626f92a32 to your computer and use it in GitHub Desktop.
Save dopuskh3/71a5b2be2f502e829d7ef06626f92a32 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
from nltk.corpus import verbnet
import sys
class CommitException(Exception):
def __init__(self, msg, line, start, end, fatal=False):
Exception.__init__(self,msg)
self._line = line
self._start = start
self._end = end
self._fatal = fatal
def formatError(self):
return "%d:%d:%s" % (self._line, self._start, str(self))
def isFatal(self):
return self._fatal
class NoDescriptionException(CommitException):
pass
class InvalidTitleException(CommitException):
pass
class TrailingSpaceException(CommitException):
pass
class LineTooLongException(CommitException):
pass
class InvalidMessageException(CommitException):
pass
class ContextInfo(object):
def __init__(self, line):
self.line = line
class Validator(object):
def __init__(self, content, contextInfo=None):
self._content = content
self._context = contextInfo
def context(self, lineNumber):
if not self._context:
return lineNumber
return lineNumber + self._context.line
def validate(self, *args, **kwargs):
try:
self.run(*args, **kwargs)
return True
except CommitException, e:
print >>sys.stderr, e.formatError()
if e.isFatal():
raise e
return False
class TrailingSpaceValidator(Validator):
def run(self):
for line, l in enumerate(self._content):
if l.rstrip(' ') != l:
raise TrailingSpaceException("Tailing space: [%s]" % l,
self.context(line+1),
len(l.rstrip(' '))+1,
len(l)+1)
class LineLengthValidator(Validator):
def __init__(self, content, max_len, context=None):
Validator.__init__(self, content, context)
self._max_len = max_len
def run(self):
for line, l in enumerate(self._content):
if len(l) > self._max_len:
raise LineTooLongException("Line [%s] is too long (max=%d, length=%d)" % (l, self._max_len, len(l)),
self.context(line+1),
self._max_len,
len(l))
class TitleValidator(Validator):
def run(self):
TrailingSpaceValidator(self._content, self._context).validate()
LineLengthValidator(self._content, 50, self._context).validate()
firstWord = self._content[0].split(' ')[0]
if not firstWord[0].isupper():
raise InvalidTitleException("First title character must be a capital letter: [%s]" % self._content[0],
self.context(1),
1, 2)
vclass = verbnet.classids(firstWord.lower())
if not vclass:
raise InvalidTitleException("First title work must begin with an infinitive verb [%s]" % self._content[0],
self.context(1),
1, len(firstWord))
class EmptyLinesValidator(Validator):
def run(self):
if self._content and self._content[0]:
if not self._content[0].strip(' ').strip('\t'):
raise CommitException("Too much empty lines", self.context(1), 1, 2)
class DescriptionValidator(Validator):
def run(self):
EmptyLinesValidator(self._content, self._context).validate()
TrailingSpaceValidator(self._content, self._context).validate()
LineLengthValidator(self._content, 72, self._context).validate()
class CommitValidator(Validator):
def __init__(self, msg):
self._msg = msg
def run(self):
lines = self._msg.splitlines()
if len(lines) < 3:
raise NoDescriptionException("Commit message do not contains a description", 0, 1,
len(lines[0]), fatal=True)
if lines[1]:
raise InvalidMessageException("Second commit line must be empty", 1, 1, 2, fatal=True)
title, description = [lines[0]], lines[2:]
self._validateTitle(title)
self._validateDescription(description)
def _validateTitle(self, title):
TitleValidator(title).validate()
def _validateDescription(self, description):
DescriptionValidator(description, ContextInfo(2)).validate()
def validateFromFile(filename):
with open(filename, 'r') as fd:
msg = fd.read()
CommitValidator(msg).validate()
if __name__ == "__main__":
validateFromFile(sys.argv[1])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment