-
Notifications
You must be signed in to change notification settings - Fork 2
/
commit-msg
162 lines (114 loc) · 3.95 KB
/
commit-msg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#!/usr/bin/env python
"""The commit-msg hook runs when the commit message is entered.
The only argument passed to this hook is the name of the file that contains
the commit message.
"""
import sys
def main():
if len(sys.argv) == 1:
print 'The file containing the commit msg is not given'
print 'You should only see this when you are testing the script\n'
return
print 'Doing a quick check on your commit message'
file_contents = parse_commit_msg_file(sys.argv[1])
if not has_valid_commit_msg(file_contents):
print 'Your commit is not saved'
sys.exit(1)
def parse_commit_msg_file(path):
with open(path, 'r') as f:
return f.read()
def has_valid_commit_msg(file_contents):
subject, body = extract_subject_and_body(file_contents)
return has_valid_subject(subject) and has_valid_body(body)
def extract_subject_and_body(file_contents):
msg = remove_lines_starting_with_hashtag(file_contents)
msg = msg.strip()
if not msg:
return None, None
subject_and_body = msg.split('\n\n', 1)
subject = subject_and_body[0]
if len(subject_and_body) == 2:
body = subject_and_body[1]
else:
body = None
return subject, body
def remove_lines_starting_with_hashtag(file_contents):
output = ''
contents_list = file_contents.split('\n')
length = len(contents_list)
for i in xrange(length):
if not contents_list[i].startswith('#'):
output += contents_list[i]
if i < (length - 1):
output += '\n'
return output
def has_valid_subject(subject):
if not subject:
print 'Type in a subject'
return False
if not subject[0].isupper():
print 'Start the first letter of the subject in uppercase'
return False
first_word = subject.split(' ', 1)[0]
if is_likely_plural(first_word):
print 'Avoid plural form for the first word of the subject'
print 'The first word should be a simple verb'
return False
if is_likely_present_continuous(first_word):
print 'Avoid present continuous for the first word of the subject'
print 'The first word should be a simple verb'
return False
if is_likely_past_tense(first_word):
print 'Avoid past tense for the first word of the subject'
print 'The first word should be a simple verb'
return False
if len(subject) > 70:
print 'The subject should not exceed 70 chars'
return False
if subject[-1] == '.':
print 'Do not end the subject with a period'
return False
if '. ' in subject:
print 'Do not write multiple sentences in the subject'
return False
if '\n' in subject:
print 'The subject should fit on a single line'
print 'If there is a body, put 1 blank line between ' \
'the subject and the body'
return False
return True
def is_likely_plural(word):
w = word.lower()
return len(w) > 3 and (w[-2:] == 'es' or (w[-1] == 's' and w[-2] != 's'))
def is_likely_present_continuous(word):
return len(word) > 3 and word[-3:].lower() == 'ing'
def is_likely_past_tense(word):
return len(word) > 2 and word[-2:].lower() == 'ed'
def has_valid_body(body):
if not body:
return True
lines = body.split('\n')
if has_long_lines(lines):
return False
if has_consecutive_blank_lines(lines):
print 'There should not be consecutive blank lines'
return False
return True
def has_long_lines(lines):
for line in lines:
if len(line) > 72:
print 'The line below exceeds 72 chars'
print line
return True
return False
def has_consecutive_blank_lines(lines):
blank_lines = 0
for line in lines:
if line == '':
blank_lines += 1
if blank_lines > 1:
return True
else:
blank_lines = 0
return False
main()