forked from sprintly/Sprintly-GitHub
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcommit-msg
executable file
·145 lines (114 loc) · 4.32 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
#!/usr/bin/python
import sys
import re
import os
import subprocess
def process(commit_msg_path):
"""
Process the commit message. If this method returns,
it is assumed the message has been validated. An
Exception is the best way to exit in case of error.
"""
# read in commit message
commit_msg_file = open(commit_msg_path, 'r')
commit_msg = commit_msg_file.read()
commit_msg_file.close()
# check to see if message is properly formatted
valid = validate_message(commit_msg)
if valid and len(valid) == 2:
new_commit_msg = valid[1]
else:
# present sprint.ly items to user
display_sprintly_items()
# prompt user for item(s)
items = get_sprintly_items()
# check if they opted out
if '0' in items:
print 'Proceeding without Sprint.ly item number.'
return
# convert items into string
items_string = ' '.join(map(lambda x: 'References #' + str(x) + '.', items))
# create new commit message
new_commit_msg = items_string + ' ' + commit_msg
# save it (overwrite existing)
commit_msg_file = open(commit_msg_path, 'w')
commit_msg = commit_msg_file.write(new_commit_msg)
commit_msg_file.close()
def validate_message(message):
"""
If the message contains (at any position) a sprint.ly
keyword followed by a space, pound, number, then accept
the message as is and return (True, message).
If the message begins with a pound, number, prepend
message with 'References ' and return (True, modified message).
Otherwise, return false.
"""
messageLower = message.lower()
valid_keywords = ['close', 'closes', 'closed', 'fix', 'fixed', 'fixes', 'addresses', 're', 'ref', 'refs', 'references', 'see', 'breaks', 'unfixes', 'reopen', 'reopens', 're-open', 're-opens']
try:
# match pound-number-(space or period)
result = re.match(r'^(#[0-9]+[\.\s$]).*$', message)
if result:
return (True, 'References %s' % message)
# match any keyword followed by a pound-number-(space or period)
pattern = r'.*\b(' + '|'.join(valid_keywords) + r')\b\s(#[0-9]+([\.\s]|$)).*'
result = re.match(pattern, messageLower)
if result:
return (True, message)
except Exception as e:
pass
return False
def display_sprintly_items():
"""
Use the sprintly command line tool to display a list of sprintly
items.
"""
try:
subprocess.call(['sprintly'], stdin=open('/dev/tty', 'r'))
except:
print 'Command-line tool \'sprintly\' not found. Please ensure it is installed and on your path.'
print '#0 - Proceed without Sprint.ly item number.'
def get_sprintly_items():
"""
Ask the user until they give a list of one or more
integers delimited by space. Only non-negative
integers are allowed. It is acceptable for integers
to be preceded by a # symbol.
"""
# enable user input
sys.stdin = open('/dev/tty', 'r')
while True:
sprintly_items = raw_input('Enter 1 or more item numbers separated by a space: ').split(' ')
result = map(lambda x: parse_item_number(x), sprintly_items)
if not None in result:
return result
def parse_item_number(s):
"""
Returns the item number from strings of format: '12', '#12'
"""
result = re.match('^#?([0-9]+)$', s)
if result:
return result.group(1)
else:
return None
if __name__ == '__main__':
try:
if len(sys.argv) > 1:
process(commit_msg_path=sys.argv[1])
else:
# Should never happen, but just in case...
raise Exception('Commit message was not received.')
except KeyboardInterrupt:
print '\n\nProgram interrupted. Commit aborted.'
sys.exit(1)
except Exception as e:
print '\n\nError occurred. Commit aborted.'
sys.exit(1)
# Execute the original commit hook. Note: We don't want realpath because
# sprintly links /usr/local/share/sprintly/commit-msg to
# .git/hooks/commit-msg and we want to be in the hooks directory.
original_commit_msg = os.path.dirname(__file__) + '/commit-msg.original'
if os.path.exists(original_commit_msg):
sys.exit(subprocess.call([original_commit_msg, sys.argv[1]]))
else:
sys.exit(0)