blob: d5cc3f85ab9aaede5658c026a704f16db07ea21a [file] [log] [blame]
Ed Tanousfb9948a2022-06-21 09:10:24 -07001import re
Patrick Williamse08ffba2022-12-05 10:33:46 -06002
Ed Tanousfb9948a2022-06-21 09:10:24 -07003from gitlint.options import IntOption
Patrick Williamse08ffba2022-12-05 10:33:46 -06004from gitlint.rules import CommitRule, RuleViolation
Ed Tanousfb9948a2022-06-21 09:10:24 -07005
6
7class BodyMaxLineLengthWithExceptions(CommitRule):
8 name = "body-max-line-length-with-exceptions"
9 id = "UC1"
10
11 options_spec = [IntOption("line-length", 80, "Max line length")]
12 line_length_violation_message = """Line exceeds max length ({0}>{1}).
13 It's possible you intended to use one of the following exceptions:
Patrick Williamse08ffba2022-12-05 10:33:46 -060014 1. Put logs or shell script in a quoted section with triple quotes (''')
15 before and after the section
16 2. Put a long link at the bottom in a footnote.
17 example: [1] https://my_long_link.com
Ed Tanousfb9948a2022-06-21 09:10:24 -070018 Line that was too long:
19"""
20 tabs_violation_message = "Line contains hard tab characters (\\t)"
21
22 def validate(self, commit):
23 in_block_comment = False
24 for line in commit.message.body:
25 # allow a quoted string to be over the line limit
26 if (
27 line.startswith("'''")
28 or line.startswith('"""')
29 or line.startswith("```")
30 ):
31 in_block_comment = not in_block_comment
32
33 if in_block_comment:
34 continue
35
36 if "\t" in line:
Patrick Williamse08ffba2022-12-05 10:33:46 -060037 return [
38 RuleViolation(self.id, self.tabs_violation_message, line)
39 ]
Ed Tanousfb9948a2022-06-21 09:10:24 -070040
41 # allow footnote url links to be as long as needed example
42 # [1] http://www.myspace.com
43 ret = re.match(r"^\[\d+\]:? ", line)
44 if ret is not None:
45 continue
46
47 # allow signed-off-by
48 if line.startswith("Signed-off-by:"):
49 continue
50
51 max_length = self.options["line-length"].value
52 if len(line) > max_length:
53 return [
54 RuleViolation(
55 self.id,
56 self.line_length_violation_message.format(
57 len(line), max_length
58 ),
59 line,
60 )
61 ]
62 return None