summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/commit-message-23
-rw-r--r--gitlint/config.py13
-rw-r--r--gitlint/lint.py23
-rw-r--r--gitlint/rules.py52
4 files changed, 76 insertions, 15 deletions
diff --git a/examples/commit-message-2 b/examples/commit-message-2
new file mode 100644
index 0000000..aa87167
--- /dev/null
+++ b/examples/commit-message-2
@@ -0,0 +1,3 @@
+WIP: This is the title of a commit message that is over 80 characters and contains hard tabs and trailing whitespace
+The second line should typically be empty
+Lines typically need to have a max length, meaning that they can't exceed a preset number of characters, usually 80 or 120.
diff --git a/gitlint/config.py b/gitlint/config.py
index f30856c..0ec7f7c 100644
--- a/gitlint/config.py
+++ b/gitlint/config.py
@@ -11,15 +11,20 @@ class LintConfigError(Exception):
class LintConfig(object):
""" Class representing gitlint configuration """
- default_rule_classes = [rules.MaxLineLengthRule, rules.TrailingWhiteSpace, rules.HardTab]
+ default_rule_classes = [rules.TitleMaxLengthRule, rules.TitleTrailingWhitespace, rules.TitleHardTab,
+ rules.BodyMaxLengthRule, rules.BodyTrailingWhitespace, rules.BodyHardTab]
def __init__(self):
# Use an ordered dict so that the order in which rules are applied is always the same
self._rules = OrderedDict([(rule_cls.id, rule_cls()) for rule_cls in self.default_rule_classes])
@property
- def rules(self):
- return self._rules.values()
+ def body_rules(self):
+ return [rule for rule in self._rules.values() if isinstance(rule, rules.CommitMessageBodyRule)]
+
+ @property
+ def title_rules(self):
+ return [rule for rule in self._rules.values() if isinstance(rule, rules.CommitMessageTitleRule)]
def disable_rule_by_id(self, rule_id):
del self._rules[rule_id]
@@ -29,7 +34,7 @@ class LintConfig(object):
rule = self._rules.get(rule_id_or_name)
# if not found, try finding rule by name
if not rule:
- rule = next((rule for rule in self.rules if rule.name == rule_id_or_name), None)
+ rule = next((rule for rule in self._rules.values() if rule.name == rule_id_or_name), None)
return rule
def disable_rule(self, rule_id_or_name):
diff --git a/gitlint/lint.py b/gitlint/lint.py
index fac435f..3a0f515 100644
--- a/gitlint/lint.py
+++ b/gitlint/lint.py
@@ -7,18 +7,20 @@ class GitLinter(object):
self.config = config
@property
- def line_rules(self):
- return [rule for rule in self.config.rules if isinstance(rule, rules.LineRule)]
+ def body_line_rules(self):
+ return [rule for rule in self.config.body_rules if isinstance(rule, rules.LineRule)]
- def _apply_line_rules(self, commit_message):
+ @property
+ def title_line_rules(self):
+ return [rule for rule in self.config.title_rules if isinstance(rule, rules.LineRule)]
+
+ def _apply_line_rules(self, lines, rules, line_nr_start):
""" Iterates over the lines in a given git commit message and applies all the enabled line rules to
each line """
all_violations = []
- lines = commit_message.split("\n")
- line_rules = self.line_rules
- line_nr = 1
+ line_nr = line_nr_start
for line in lines:
- for rule in line_rules:
+ for rule in rules:
violation = rule.validate(line)
if violation:
violation.line_nr = line_nr
@@ -27,7 +29,12 @@ class GitLinter(object):
return all_violations
def lint_commit_message(self, commit_message):
- violations = self._apply_line_rules(commit_message)
+ lines = commit_message.split("\n")
+ commit_message_title = [lines[0]]
+ commit_message_body = lines[1:] if len(lines) > 1 else []
+ title_violations = self._apply_line_rules(commit_message_title, self.title_line_rules, 1)
+ body_violations = self._apply_line_rules(commit_message_body, self.body_line_rules, 2)
+ violations = title_violations + body_violations
for v in violations:
print("{}: {} {}: \"{}\"".format(v.line_nr, v.rule_id, v.message, v.content))
return len(violations)
diff --git a/gitlint/rules.py b/gitlint/rules.py
index daa485b..6df2ffd 100644
--- a/gitlint/rules.py
+++ b/gitlint/rules.py
@@ -37,6 +37,16 @@ class LineRule(Rule):
pass
+class CommitMessageTitleRule(Rule):
+ """ 'Tagging' class representing rules that apply to a commit message title """
+ pass
+
+
+class CommitMessageBodyRule(Rule):
+ """ 'Tagging' class representing rules that apply to a commit message body """
+ pass
+
+
class RuleViolation(object):
def __init__(self, rule_id, message, content=None, line_nr=None):
self.rule_id = rule_id
@@ -61,27 +71,63 @@ class MaxLineLengthRule(LineRule):
name = "max-line-length"
id = "R1"
options_spec = [IntOption('line-length', 80, "Max line length")]
+ violation_message = "Line exceeds max length ({0}>{1})"
def validate(self, line):
max_length = self.options['line-length'].value
if len(line) > max_length:
- return RuleViolation(self.id, "Line exceeds max length ({0}>{1})".format(len(line), max_length), line)
+ return RuleViolation(self.id, self.violation_message.format(len(line), max_length), line)
class TrailingWhiteSpace(LineRule):
name = "trailing-whitespace"
id = "R2"
+ violation_message = "Line has trailing whitespace"
def validate(self, line):
pattern = re.compile(r"\s$")
if pattern.search(line):
- return RuleViolation(self.id, "Line has trailing whitespace", line)
+ return RuleViolation(self.id, self.violation_message, line)
class HardTab(LineRule):
name = "hard-tab"
id = "R3"
+ violation_message = "Line contains hard tab characters (\\t)"
def validate(self, line):
if "\t" in line:
- return RuleViolation(self.id, "Line contains hard tab characters (\\t)", line)
+ return RuleViolation(self.id, self.violation_message, line)
+
+
+class TitleMaxLengthRule(MaxLineLengthRule, CommitMessageTitleRule):
+ name = "title-max-length"
+ id = "T1"
+ violation_message = "Title exceeds max length ({0}>{1})"
+
+
+class TitleTrailingWhitespace(TrailingWhiteSpace, CommitMessageTitleRule):
+ name = "title-trailing-whitespace"
+ id = "T2"
+ violation_message = "Title has trailing whitespace"
+
+
+class TitleHardTab(HardTab, CommitMessageTitleRule):
+ name = "title-hard-tab"
+ id = "T3"
+ violation_message = "Title contains hard tab characters (\\t)"
+
+
+class BodyMaxLengthRule(MaxLineLengthRule, CommitMessageBodyRule):
+ name = "body-max-line-length"
+ id = "B1"
+
+
+class BodyTrailingWhitespace(TrailingWhiteSpace, CommitMessageBodyRule):
+ name = "body-trailing-whitespace"
+ id = "B2"
+
+
+class BodyHardTab(HardTab, CommitMessageBodyRule):
+ name = "body-hard-tab"
+ id = "B3"