Skip to content

Commit 1812f55

Browse files
committed
gitlint: add giltlint configuration files
Add gitlint configuration to allow contributor to check its commit message compliance before sending its pull request. The configuration files has been copied from Zephyr project. Signed-off-by: Arnaud Pouliquen <[email protected]>
1 parent 4cc431a commit 1812f55

File tree

2 files changed

+218
-0
lines changed

2 files changed

+218
-0
lines changed

.gitlint

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# All these sections are optional, edit this file as you like.
2+
[general]
3+
# Ignore certain rules, you can reference them by their id or by their full name
4+
ignore=title-trailing-punctuation, T3, title-max-length, T1, body-hard-tab, B1, B3
5+
6+
# verbosity should be a value between 1 and 3, the commandline -v flags take precedence over this
7+
verbosity = 3
8+
9+
# By default gitlint will ignore merge commits. Set to 'false' to disable.
10+
ignore-merge-commits=true
11+
12+
# By default gitlint will ignore fixup commits. Set to 'false' to disable.
13+
# ignore-fixup-commits=false
14+
15+
# By default gitlint will ignore squash commits. Set to 'false' to disable.
16+
# ignore-squash-commits=true
17+
18+
# Ignore any data send to gitlint via stdin
19+
# ignore-stdin=true
20+
21+
# Enable debug mode (prints more output). Disabled by default.
22+
debug=true
23+
24+
# Enable community contributed rules
25+
# See http://jorisroovers.github.io/gitlint/contrib_rules for details
26+
# contrib=contrib-title-conventional-commits,CC1
27+
28+
# Set the extra-path where gitlint will search for user defined rules
29+
# See http://jorisroovers.github.io/gitlint/user_defined_rules for details
30+
extra-path=scripts/gitlint
31+
32+
[title-max-length]
33+
line-length=75
34+
35+
[body-min-line-count]
36+
min-line-count=1
37+
38+
[body-max-line-count]
39+
max-line-count=200
40+
41+
[title-must-not-contain-word]
42+
# Comma-separated list of words that should not occur in the title. Matching is case
43+
# insensitive. It's fine if the keyword occurs as part of a larger word (so "WIPING"
44+
# will not cause a violation, but "WIP: my title" will.
45+
words=wip
46+
47+
# [title-match-regex]
48+
# python like regex (https://docs.python.org/2/library/re.html) that the
49+
# commit-msg title must be matched to.
50+
# Note that the regex can contradict with other rules if not used correctly
51+
# (e.g. title-must-not-contain-word).
52+
# regex=^US[0-9]*
53+
54+
[body-max-line-length]
55+
# B1 = body-max-line-length
56+
line-length=80
57+
58+
[body-min-length]
59+
min-length=3
60+
61+
[body-is-missing]
62+
# Whether to ignore this rule on merge commits (which typically only have a title)
63+
# default = True
64+
ignore-merge-commits=false
65+
66+
# [body-changed-file-mention]
67+
# List of files that need to be explicitly mentioned in the body when they are changed
68+
# This is useful for when developers often erroneously edit certain files or git submodules.
69+
# By specifying this rule, developers can only change the file when they explicitly reference
70+
# it in the commit message.
71+
# files=gitlint/rules.py,README.md
72+
73+
# [author-valid-email]
74+
# python like regex (https://docs.python.org/2/library/re.html) that the
75+
# commit author email address should be matched to
76+
# For example, use the following regex if you only want to allow email addresses from foo.com
77+
# regex=[^@][email protected]
78+
79+
# [ignore-by-title]
80+
# Ignore certain rules for commits of which the title matches a regex
81+
# E.g. Match commit titles that start with "Release"
82+
# regex=^Release(.*)
83+
#
84+
# Ignore certain rules, you can reference them by their id or by their full name
85+
# Use 'all' to ignore all rules
86+
# ignore=T1,body-min-length
87+
88+
# [ignore-by-body]
89+
# Ignore certain rules for commits of which the body has a line that matches a regex
90+
# E.g. Match bodies that have a line that that contain "release"
91+
# regex=(.*)release(.*)
92+
#
93+
# Ignore certain rules, you can reference them by their id or by their full name
94+
# Use 'all' to ignore all rules
95+
# ignore=T1,body-min-length
96+
97+
# [contrib-title-conventional-commits]
98+
# Specify allowed commit types. For details see: https://www.conventionalcommits.org/
99+
# types = bugfix,user-story,epic

scripts/gitlint/commit_rules.py

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
"""
4+
The classes below are examples of user-defined CommitRules. Commit rules are gitlint rules that
5+
act on the entire commit at once. Once the rules are discovered, gitlint will automatically take care of applying them
6+
to the entire commit. This happens exactly once per commit.
7+
8+
A CommitRule contrasts with a LineRule (see examples/my_line_rules.py) in that a commit rule is only applied once on
9+
an entire commit. This allows commit rules to implement more complex checks that span multiple lines and/or checks
10+
that should only be done once per gitlint run.
11+
12+
While every LineRule can be implemented as a CommitRule, it's usually easier and more concise to go with a LineRule if
13+
that fits your needs.
14+
"""
15+
16+
from gitlint.rules import CommitRule, RuleViolation, CommitMessageTitle, LineRule, CommitMessageBody
17+
from gitlint.options import IntOption, StrOption
18+
import re
19+
20+
class BodyMinLineCount(CommitRule):
21+
# A rule MUST have a human friendly name
22+
name = "body-min-line-count"
23+
24+
# A rule MUST have an *unique* id, we recommend starting with UC (for User-defined Commit-rule).
25+
id = "UC6"
26+
27+
# A rule MAY have an option_spec if its behavior should be configurable.
28+
options_spec = [IntOption('min-line-count', 2, "Minimum body line count excluding Signed-off-by")]
29+
30+
def validate(self, commit):
31+
filtered = [x for x in commit.message.body if not x.lower().startswith("signed-off-by") and x != '']
32+
line_count = len(filtered)
33+
min_line_count = self.options['min-line-count'].value
34+
if line_count < min_line_count:
35+
message = "Body has no content, should at least have {} line.".format(min_line_count)
36+
return [RuleViolation(self.id, message, line_nr=1)]
37+
38+
class BodyMaxLineCount(CommitRule):
39+
# A rule MUST have a human friendly name
40+
name = "body-max-line-count"
41+
42+
# A rule MUST have an *unique* id, we recommend starting with UC (for User-defined Commit-rule).
43+
id = "UC1"
44+
45+
# A rule MAY have an option_spec if its behavior should be configurable.
46+
options_spec = [IntOption('max-line-count', 3, "Maximum body line count")]
47+
48+
def validate(self, commit):
49+
line_count = len(commit.message.body)
50+
max_line_count = self.options['max-line-count'].value
51+
if line_count > max_line_count:
52+
message = "Body contains too many lines ({0} > {1})".format(line_count, max_line_count)
53+
return [RuleViolation(self.id, message, line_nr=1)]
54+
55+
class SignedOffBy(CommitRule):
56+
""" This rule will enforce that each commit contains a "Signed-off-by" line.
57+
We keep things simple here and just check whether the commit body contains a line that starts with "Signed-off-by".
58+
"""
59+
60+
# A rule MUST have a human friendly name
61+
name = "body-requires-signed-off-by"
62+
63+
# A rule MUST have an *unique* id, we recommend starting with UC (for User-defined Commit-rule).
64+
id = "UC2"
65+
66+
def validate(self, commit):
67+
flags = re.UNICODE
68+
flags |= re.IGNORECASE
69+
for line in commit.message.body:
70+
if line.lower().startswith("signed-off-by"):
71+
if not re.search(r"(^)Signed-off-by: ([-'\w.]+) ([-'\w.]+) (.*)", line, flags=flags):
72+
return [RuleViolation(self.id, "Signed-off-by: must have a full name", line_nr=1)]
73+
else:
74+
return
75+
return [RuleViolation(self.id, "Body does not contain a 'Signed-off-by:' line", line_nr=1)]
76+
77+
class TitleMaxLengthRevert(LineRule):
78+
name = "title-max-length-no-revert"
79+
id = "UC5"
80+
target = CommitMessageTitle
81+
options_spec = [IntOption('line-length', 72, "Max line length")]
82+
violation_message = "Title exceeds max length ({0}>{1})"
83+
84+
def validate(self, line, _commit):
85+
max_length = self.options['line-length'].value
86+
if len(line) > max_length and not line.startswith("Revert"):
87+
return [RuleViolation(self.id, self.violation_message.format(len(line), max_length), line)]
88+
89+
class TitleStartsWithSubsystem(LineRule):
90+
name = "title-starts-with-subsystem"
91+
id = "UC3"
92+
target = CommitMessageTitle
93+
options_spec = [StrOption('regex', ".*", "Regex the title should match")]
94+
95+
def validate(self, title, _commit):
96+
regex = self.options['regex'].value
97+
pattern = re.compile(regex, re.UNICODE)
98+
violation_message = "Title does not follow [subsystem]: [subject] (and should not start with literal subsys:)"
99+
if not pattern.search(title):
100+
return [RuleViolation(self.id, violation_message, title)]
101+
102+
class MaxLineLengthExceptions(LineRule):
103+
name = "max-line-length-with-exceptions"
104+
id = "UC4"
105+
target = CommitMessageBody
106+
options_spec = [IntOption('line-length', 80, "Max line length")]
107+
violation_message = "Line exceeds max length ({0}>{1})"
108+
109+
def validate(self, line, _commit):
110+
max_length = self.options['line-length'].value
111+
urls = re.findall(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', line)
112+
if line.startswith('Signed-off-by'):
113+
return
114+
115+
if urls:
116+
return
117+
118+
if len(line) > max_length:
119+
return [RuleViolation(self.id, self.violation_message.format(len(line), max_length), line)]

0 commit comments

Comments
 (0)