Skip to content

Commit 29f6a11

Browse files
committed
Apply format with black
1 parent bf10cab commit 29f6a11

File tree

2 files changed

+146
-105
lines changed

2 files changed

+146
-105
lines changed

bad_commit_message_blocker.py

Lines changed: 71 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
'''
1+
"""
22
The `bad commit message blocker` intends to inhibit commits with bad
33
messages from getting merged into a project.
44
@@ -14,7 +14,8 @@
1414
The final rule (#7) about explaining what and why instead of how in the
1515
body of a commit message, very subjective and therefore is left up to
1616
the code reviewer to ensure it is being adhered to.
17-
'''
17+
"""
18+
1819
import argparse
1920
import sys
2021
from textblob import TextBlob
@@ -24,14 +25,14 @@
2425

2526

2627
class CliColors:
27-
HEADER = '\033[95m'
28-
OKBLUE = '\033[94m'
29-
OKGREEN = '\033[92m'
30-
WARNING = '\033[93m'
31-
FAIL = '\033[91m'
32-
ENDC = '\033[0m'
33-
BOLD = '\033[1m'
34-
UNDERLINE = '\033[4m'
28+
HEADER = "\033[95m"
29+
OKBLUE = "\033[94m"
30+
OKGREEN = "\033[92m"
31+
WARNING = "\033[93m"
32+
FAIL = "\033[91m"
33+
ENDC = "\033[0m"
34+
BOLD = "\033[1m"
35+
UNDERLINE = "\033[4m"
3536

3637

3738
def check_subject_is_separated_from_body(commit_message):
@@ -50,8 +51,9 @@ def check_subject_is_separated_from_body(commit_message):
5051
def check_subject_is_not_too_long(commit_message, subject_limit):
5152
lines = commit_message.splitlines()
5253
check_result = len(lines[0]) <= subject_limit
53-
print_result(check_result, "Limit the subject line to " +
54-
str(subject_limit) + " characters")
54+
print_result(
55+
check_result, "Limit the subject line to " + str(subject_limit) + " characters"
56+
)
5557

5658
return check_result
5759

@@ -87,17 +89,20 @@ def check_subject_uses_imperative(commit_message):
8789
third_person_prefix = "It "
8890
words_in_third_person_prefix_blob = len(third_person_prefix.split())
8991
non_third_person_prefix = "You "
90-
words_in_non_third_person_prefix_blob = len(
91-
non_third_person_prefix.split())
92+
words_in_non_third_person_prefix_blob = len(non_third_person_prefix.split())
9293
# Turn the first character into a lowercase so to make it easier for
9394
# the parser to determine whether the word is a verb and its tense
9495
first_character_in_lowercase = first_line[0].lower()
9596
first_line = first_character_in_lowercase + first_line[1:]
9697
third_person_blob = TextBlob(third_person_prefix + first_line)
9798
non_third_person_blob = TextBlob(non_third_person_prefix + first_line)
9899

99-
first_word, third_person_result = third_person_blob.tags[words_in_third_person_prefix_blob]
100-
_, non_third_person_result = non_third_person_blob.tags[words_in_non_third_person_prefix_blob]
100+
first_word, third_person_result = third_person_blob.tags[
101+
words_in_third_person_prefix_blob
102+
]
103+
_, non_third_person_result = non_third_person_blob.tags[
104+
words_in_non_third_person_prefix_blob
105+
]
101106

102107
# We need to determine whether the first word is a non-third person verb
103108
# when parsed in a non-third person blob. However, there were some
@@ -107,8 +112,13 @@ def check_subject_uses_imperative(commit_message):
107112
# third person, when parsed in the third person blob.
108113
# So, we ultimately check if the verb ends with an 's' which is a pretty
109114
# good indicator of a third person, simple present tense verb.
110-
check_result = non_third_person_result == non_third_person_singular_present_verb and (
111-
third_person_result != third_person_singular_present_verb or not first_word.endswith("s"))
115+
check_result = (
116+
non_third_person_result == non_third_person_singular_present_verb
117+
and (
118+
third_person_result != third_person_singular_present_verb
119+
or not first_word.endswith("s")
120+
)
121+
)
112122
print_result(check_result, "Use the imperative mood in the subject line")
113123

114124
return check_result
@@ -121,66 +131,75 @@ def check_body_lines_are_not_too_long(commit_message, body_limit):
121131
if len(line) > body_limit:
122132
check_result = False
123133
break
124-
print_result(check_result, "Wrap the body at " +
125-
str(body_limit) + " characters")
134+
print_result(check_result, "Wrap the body at " + str(body_limit) + " characters")
126135

127136
return check_result
128137

129138

130139
def check_body_explains_what_and_why(commit_message):
131140
what_vs_how_rule = "Use the body to explain what and why vs. how"
132-
print("[" + CliColors.OKBLUE + " NA " +
133-
CliColors.ENDC + "] " + what_vs_how_rule)
141+
print("[" + CliColors.OKBLUE + " NA " + CliColors.ENDC + "] " + what_vs_how_rule)
134142

135143
return True
136144

137145

138146
def print_result(check_passed, rule):
139-
print("[" + (CliColors.OKGREEN +
140-
"PASSED" if check_passed else CliColors.FAIL + "FAILED") + CliColors.ENDC + "] " + rule)
141-
142-
143-
def check(commit_message, subject_limit=DEFAULT_SUBJECT_LIMIT, body_limit=DEFAULT_BODY_LIMIT):
144-
all_rules_verified = check_subject_is_separated_from_body(
145-
commit_message)
146-
all_rules_verified &= check_subject_is_not_too_long(
147-
commit_message, subject_limit)
147+
print(
148+
"["
149+
+ (CliColors.OKGREEN + "PASSED" if check_passed else CliColors.FAIL + "FAILED")
150+
+ CliColors.ENDC
151+
+ "] "
152+
+ rule
153+
)
154+
155+
156+
def check(
157+
commit_message, subject_limit=DEFAULT_SUBJECT_LIMIT, body_limit=DEFAULT_BODY_LIMIT
158+
):
159+
all_rules_verified = check_subject_is_separated_from_body(commit_message)
160+
all_rules_verified &= check_subject_is_not_too_long(commit_message, subject_limit)
148161
all_rules_verified &= check_subject_is_capitalized(commit_message)
149-
all_rules_verified &= check_subject_does_not_end_with_period(
150-
commit_message)
162+
all_rules_verified &= check_subject_does_not_end_with_period(commit_message)
151163
all_rules_verified &= check_subject_uses_imperative(commit_message)
152-
all_rules_verified &= check_body_lines_are_not_too_long(
153-
commit_message, body_limit)
164+
all_rules_verified &= check_body_lines_are_not_too_long(commit_message, body_limit)
154165
all_rules_verified &= check_body_explains_what_and_why(commit_message)
155166

156167
return all_rules_verified
157168

158169

159170
def main():
160-
parser_description = "Bad commit message blocker: Avoid bad commit messages in your repository"
171+
parser_description = (
172+
"Bad commit message blocker: Avoid bad commit messages in your repository"
173+
)
161174
parser = argparse.ArgumentParser(description=parser_description)
162-
parser.add_argument("--message",
163-
help="The commit message to check",
164-
required=True)
165-
parser.add_argument("--subject-limit",
166-
help="The maximum allowed length for a commit subject",
167-
default=DEFAULT_SUBJECT_LIMIT)
168-
parser.add_argument("--body-limit",
169-
help="The maximum allowed length for a line in the commit body",
170-
default=DEFAULT_BODY_LIMIT)
175+
parser.add_argument("--message", help="The commit message to check", required=True)
176+
parser.add_argument(
177+
"--subject-limit",
178+
help="The maximum allowed length for a commit subject",
179+
default=DEFAULT_SUBJECT_LIMIT,
180+
)
181+
parser.add_argument(
182+
"--body-limit",
183+
help="The maximum allowed length for a line in the commit body",
184+
default=DEFAULT_BODY_LIMIT,
185+
)
171186
args = parser.parse_args()
172187

173188
commit_message = args.message.strip()
174-
print(CliColors.HEADER + CliColors.BOLD +
175-
"Your commit message: " + CliColors.ENDC)
189+
print(CliColors.HEADER + CliColors.BOLD + "Your commit message: " + CliColors.ENDC)
176190
print("===========================")
177191
print(commit_message)
178192
print("===========================")
179-
print(CliColors.HEADER + CliColors.BOLD +
180-
"Conformance to the 7 rules of a great Git commit message:" + CliColors.ENDC)
181-
182-
all_rules_verified = check(commit_message, int(
183-
args.subject_limit), int(args.body_limit))
193+
print(
194+
CliColors.HEADER
195+
+ CliColors.BOLD
196+
+ "Conformance to the 7 rules of a great Git commit message:"
197+
+ CliColors.ENDC
198+
)
199+
200+
all_rules_verified = check(
201+
commit_message, int(args.subject_limit), int(args.body_limit)
202+
)
184203

185204
sys.exit(0 if all_rules_verified else 1)
186205

bad_commit_message_blocker_tests.py

Lines changed: 75 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
'''
1+
"""
22
A set of unit tests for the Bad Commit Message Blocker.
33
44
The most interesting (and prone to fail) part is the imperative mood rule.
55
This is why most tests are focused a round it. If you want to introduce
66
improvements/changes to the script, make sure that there are no regressions
77
and your newly introduced change is also covered by unit tests.
8-
'''
8+
"""
9+
910
import unittest
1011
import bad_commit_message_blocker as blocker
1112

@@ -16,64 +17,83 @@ def setUp(self):
1617
pass
1718

1819
def test_checkSubjectUsesImperative_WhenImperative_WillReturnTrue(self):
19-
test_input = ["Refactor subsystem X for readability",
20-
"Update getting started documentation",
21-
"Remove deprecated methods",
22-
"Release version 1.0.0",
23-
"Add cool method to class"]
20+
test_input = [
21+
"Refactor subsystem X for readability",
22+
"Update getting started documentation",
23+
"Remove deprecated methods",
24+
"Release version 1.0.0",
25+
"Add cool method to class",
26+
]
2427
for input in test_input:
25-
self.assertTrue(blocker.check_subject_uses_imperative(
26-
input), "\"" + input + "\" did not produce the expected result")
28+
self.assertTrue(
29+
blocker.check_subject_uses_imperative(input),
30+
'"' + input + '" did not produce the expected result',
31+
)
2732

2833
def test_checkSubjectUsesImperative_WhenThirdPerson_WillReturnFalse(self):
29-
test_input = ["Refactors subsystem X for readability",
30-
"Updates getting started documentation",
31-
"Removes deprecated methods",
32-
"Releases version 1.0.0",
33-
"Adds cool method to class"]
34+
test_input = [
35+
"Refactors subsystem X for readability",
36+
"Updates getting started documentation",
37+
"Removes deprecated methods",
38+
"Releases version 1.0.0",
39+
"Adds cool method to class",
40+
]
3441
for input in test_input:
35-
self.assertFalse(blocker.check_subject_uses_imperative(
36-
input), "\"" + input + "\" did not produce the expected result")
42+
self.assertFalse(
43+
blocker.check_subject_uses_imperative(input),
44+
'"' + input + '" did not produce the expected result',
45+
)
3746

3847
def test_checkSubjectUsesImperative_WhenPresentContinuous_WillReturnFalse(self):
39-
test_input = ["Refactoring subsystem X for readability",
40-
"Updating getting started documentation",
41-
"Removing deprecated methods",
42-
"Releasing version 1.0.0",
43-
"Adding cool method to class"]
48+
test_input = [
49+
"Refactoring subsystem X for readability",
50+
"Updating getting started documentation",
51+
"Removing deprecated methods",
52+
"Releasing version 1.0.0",
53+
"Adding cool method to class",
54+
]
4455
for input in test_input:
45-
self.assertFalse(blocker.check_subject_uses_imperative(
46-
input), "\"" + input + "\" did not produce the expected result")
56+
self.assertFalse(
57+
blocker.check_subject_uses_imperative(input),
58+
'"' + input + '" did not produce the expected result',
59+
)
4760

4861
def test_checkSubjectUsesImperative_WhenSimplePast_WillReturnFalse(self):
49-
test_input = ["Refactored subsystem X for readability",
50-
"Updated getting started documentation",
51-
"Removed deprecated methods",
52-
"Released version 1.0.0",
53-
"Added cool method to class"]
62+
test_input = [
63+
"Refactored subsystem X for readability",
64+
"Updated getting started documentation",
65+
"Removed deprecated methods",
66+
"Released version 1.0.0",
67+
"Added cool method to class",
68+
]
5469
for input in test_input:
55-
self.assertFalse(blocker.check_subject_uses_imperative(
56-
input), "\"" + input + "\" did not produce the expected result")
70+
self.assertFalse(
71+
blocker.check_subject_uses_imperative(input),
72+
'"' + input + '" did not produce the expected result',
73+
)
5774

5875
def test_checkSubjectUsesImperative_WhenRandom_WillReturnFalse(self):
59-
test_input = ["Documentation is updated",
60-
"Addition of new class"]
76+
test_input = ["Documentation is updated", "Addition of new class"]
6177
for input in test_input:
62-
self.assertFalse(blocker.check_subject_uses_imperative(
63-
input), "\"" + input + "\" did not produce the expected result")
64-
65-
def test_checkSubjectSeparateFromBody_WhenLineBetweenBodyAndSubject_WillReturnTrue(self):
78+
self.assertFalse(
79+
blocker.check_subject_uses_imperative(input),
80+
'"' + input + '" did not produce the expected result',
81+
)
82+
83+
def test_checkSubjectSeparateFromBody_WhenLineBetweenBodyAndSubject_WillReturnTrue(
84+
self,
85+
):
6686
test_input = """Add this cool feature
6787
6888
This cool feature is implemented because X and Y."""
69-
self.assertTrue(
70-
blocker.check_subject_is_separated_from_body(test_input))
89+
self.assertTrue(blocker.check_subject_is_separated_from_body(test_input))
7190

72-
def test_checkSubjectSeparateFromBody_WhenNoLineBetweenBodyAndSubject_WillReturnFalse(self):
91+
def test_checkSubjectSeparateFromBody_WhenNoLineBetweenBodyAndSubject_WillReturnFalse(
92+
self,
93+
):
7394
test_input = """Add this cool feature
7495
This cool feature is implemented because X and Y."""
75-
self.assertFalse(
76-
blocker.check_subject_is_separated_from_body(test_input))
96+
self.assertFalse(blocker.check_subject_is_separated_from_body(test_input))
7797

7898
def test_checkSubjectNotTooLong_WhenSubjectTooLong_WillReturnFalse(self):
7999
test_input = "This is a very very very, really long, humongous subject for a commit message"
@@ -83,38 +103,40 @@ def test_checkSubjectTooLong_WhenSubjectNotTooLong_WillReturnTrue(self):
83103
test_input = "Add this neat commit message"
84104
self.assertTrue(blocker.check_subject_is_not_too_long(test_input, 60))
85105

86-
def test_checkSubjectIsCapitalized_WhenSubjectBeginsWithCapital_WillReturnTrue(self):
106+
def test_checkSubjectIsCapitalized_WhenSubjectBeginsWithCapital_WillReturnTrue(
107+
self,
108+
):
87109
test_input = "Add this cool new feature"
88110
self.assertTrue(blocker.check_subject_is_capitalized(test_input))
89111

90112
def test_checkSubjectIsCapitalized_WhenSubjectBeginsWithLower_WillReturnFalse(self):
91113
test_input = "add this weird-looking commit message"
92114
self.assertFalse(blocker.check_subject_is_capitalized(test_input))
93115

94-
def test_checkSubjectDoesNotEndWithPeriod_WhenSubjectEndsWithPeriod_WillReturnFalse(self):
116+
def test_checkSubjectDoesNotEndWithPeriod_WhenSubjectEndsWithPeriod_WillReturnFalse(
117+
self,
118+
):
95119
test_input = "I am a strange person and do such things."
96-
self.assertFalse(
97-
blocker.check_subject_does_not_end_with_period(test_input))
120+
self.assertFalse(blocker.check_subject_does_not_end_with_period(test_input))
98121

99-
def test_checkSubjectDoesNotEndWithPeriod_WhenSubjectEndsWithoutPeriod_WillReturnTrue(self):
122+
def test_checkSubjectDoesNotEndWithPeriod_WhenSubjectEndsWithoutPeriod_WillReturnTrue(
123+
self,
124+
):
100125
test_input = "I am a strange person and don't end commit messages with a period"
101-
self.assertTrue(
102-
blocker.check_subject_does_not_end_with_period(test_input))
126+
self.assertTrue(blocker.check_subject_does_not_end_with_period(test_input))
103127

104128
def test_checkBodyLinesAreNotTooLong_WhenLinesTooLong_WillReturnFalse(self):
105129
test_input = """Add this cool new feature
106130
107131
But damn...
108132
I feel like adding some pretty huge lines and forget to insert \\n's. This is just sad!"""
109-
self.assertFalse(
110-
blocker.check_body_lines_are_not_too_long(test_input, 72))
133+
self.assertFalse(blocker.check_body_lines_are_not_too_long(test_input, 72))
111134

112135
def test_checkBodyLinesAreNotTooLong_WhenLinesNotTooLong_WillReturnTrue(self):
113136
test_input = """Add this cool new feature
114137
115138
And nicely explain why it was added."""
116-
self.assertTrue(
117-
blocker.check_body_lines_are_not_too_long(test_input, 72))
139+
self.assertTrue(blocker.check_body_lines_are_not_too_long(test_input, 72))
118140

119141
def test_checkBodyExplainsWhatAndWhy_WhenCalled_WillReturnTrue(self):
120142
# We cannot currently check this, so we always return true
@@ -123,5 +145,5 @@ def test_checkBodyExplainsWhatAndWhy_WhenCalled_WillReturnTrue(self):
123145
self.assertTrue(blocker.check_body_explains_what_and_why(test_input))
124146

125147

126-
if __name__ == '__main__':
148+
if __name__ == "__main__":
127149
unittest.main()

0 commit comments

Comments
 (0)