-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathautoissue.py
207 lines (174 loc) · 6.44 KB
/
autoissue.py
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#!/usr/bin/python
#from os import listdir, path
import os, argparse, re, errno, globals
from util import debug_print
basePath = ""
#issue class, just has the content and lineNumber fields right now.
class Issue:
def __init__(self, title, issueContent, lineNumber, fileName, label, inum):
self.data = {}
self.title = title
self.issue = issueContent
self.line = lineNumber
self.fileName = fileName
self.label = label
self.issue_num = inum
def __str__(self):
return "Issue: {}\n\tIssue#: {}\n\tFile: {}\n\tLine: {}\n\tLabels: {}\n\tContent: {}\n".format(self.title, self.issue_num, self.fileName, self.line, self.label, self.issue)
def __cmp__(self, other):
return self.title == other.title \
and self.issue == other.issue \
and self.line == other.line \
and self.fileName == other.fileName \
and self.label == other.label \
and self.issue_num == other.issue_num \
# Returns whitelist in regex form
def getWhitelistRegex():
whitelistinfile = None
while whitelistinfile is None:
try:
with open("autoissue.whitelist") as file:
whitelistinfile = [item.strip() for item in file.readlines()]
except IOError as (eno, strerror):
if eno == errno.ENOENT:
open("autoissue.whitelist", "w")
whitelist = []
for entry in whitelistinfile:
e = os.path.join(basePath, entry)
if os.path.isdir(e):
entry += "/*"
whitelist.append(entry.replace("*", "(.*)"))
return whitelist
#Function that gets all of the whitelisted files (and folders) in a folder
def getFiles():
fileList = []
for root, dirs, files in os.walk(basePath):
for fileName in files:
relDir = os.path.relpath(root, basePath)
relFile = os.path.join(relDir, fileName)
print "RELFILE:", relFile
if any([re.match(pattern + "$", relFile) is not None for pattern in getWhitelistRegex()]):
fileList.append(os.path.join(basePath, relFile))
#print "##################"
#print "ROOT", root
#print "FILENAME:", fileName
#print "JOINED PATH:", os.path.join(basePath, relFile)
#print "##################"
return fileList
def getIssues():
files = getFiles()
issues = []
for file in files:
issues += findIssuesInFile(file)
return issues
# returns a list of the Issues in this file
def findIssuesInFile(file):
lineNumber = 0
issueList = []
with open(file, 'r') as f:
data = f.readlines()
debug_print("Searching for issues in:", file, "(lines: {})".format(len(data)))
while lineNumber < len(data):
issueString = ""
if globals.startToken in data[lineNumber]:
# TODO: change to check if // comes just before startToken. This will cover the case where the comment comes after code in the line. Also, handle this case.
if data[lineNumber].strip().startswith("//"):
startingLine = lineNumber
issueString += data[lineNumber]
lineNumber += 1
while lineNumber < len(data):
line = data[lineNumber]
if line.strip(): # if the line is not empty
if line.startswith("//"):
issueString += line[2:]
else:
lineNumber -= 1 # since we increment outside of this loop
break
lineNumber += 1
elif data[lineNumber].strip().startswith("/*"):
startingLine = lineNumber
issueString += data[lineNumber]
if not issueString.strip().endswith("*/"):
lineNumber += 1
while lineNumber < len(data):
line = data[lineNumber]
if line.strip():
issueString += line
if line.strip().endswith("*/"):
break
lineNumber += 1
else:
lineNumber += 1
break
issueList.append(parseIssueFromRawComment(issueString, startingLine, file))
lineNumber += 1
return issueList
# returns an Issue
def parseIssueFromRawComment(comment, line, file):
data = {}
title = None
labels = []
inum = None
tags_regex = "\[(.*?)\]"
r = re.compile(tags_regex)
tags = r.findall(comment)
# If no [title:] tag is specified, then the first line is autmatically the title
for tag in tags:
if ":" not in tag:
# This is the issue number tag
inum = int(tag) # Should eventually check to be sure there are only numbers in here
else:
t, v = tag.split(":")
if t.lower() == "title":
title = v
elif t.lower() == "label":
labels = [x.strip() for x in v.split(",")]
if title is None:
title = comment.splitlines()[0] # Make the title the first line of the comment
content = re.sub(tags_regex, "", comment)
content = re.sub("(//(\s*)TODO)|(/\*(\s*)TODO)|(\*/)", "", content).strip()
issue = Issue(title, content, line + 1, file, labels, inum)
issue.data = data
return issue
def injectNumber(issue, number):
with open(issue.fileName, 'r') as file:
data = file.readlines()
print "Starttoken:", globals.startToken
lineNumber = issue.line - 1
line = data[lineNumber]
startIndex = line.index(globals.startToken) + len(globals.startToken)
data[lineNumber] = line[:startIndex] + " [" + str(number) + "] " + line[startIndex:]
with open(issue.fileName, 'w') as file:
file.writelines(data)
def main():
from github import createIssues
parser = argparse.ArgumentParser(description="Auto-Issue-Creator argument parser")
parser.add_argument("-s", "--start", help="the token that begins the TODO: (ie. 'TODO')", default="TODO")
parser.add_argument("-d", "--debug", action='store_true', help="enable debug mode (no POSTing to github)")
parser.add_argument("-p", "--path", help="the base path of the project to be scanned", default=".")
parser.add_argument("-i", "--interactive", action='store_true', help="enable interactive mode (pick and choose which issues get POSTed to github)")
globals.init()
args = vars(parser.parse_args())
globals.startToken = args["start"]
print "Using start token:", globals.startToken
#see if we're in debug mode
if args["debug"]:
debug = True
print "Debug mode enabled"
else:
debug = False
global basePath
basePath = os.path.abspath(os.path.expanduser(args['path']))
print "Base path of project:", basePath
issueList = getIssues()
print "Found {} {}:".format(len(issueList), "issue" if len(issueList) is 1 else "issues")
for issue in list(issueList):
print issue
if args["interactive"]:
post = raw_input('Create this issue in github? (y/n) ')
if post.lower() == 'n' or post.lower() == 'no':
issueList.remove(issue)
print "Creating {} issues".format(len(issueList))
createIssues(issueList, debug)
if __name__ == "__main__":
main()