diff options
-rw-r--r-- | examples/commit-message-2 | 3 | ||||
-rw-r--r-- | gitlint/config.py | 13 | ||||
-rw-r--r-- | gitlint/lint.py | 23 | ||||
-rw-r--r-- | gitlint/rules.py | 52 |
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" |