hgpoll.py

changeset 72
2266d6d73de3
child 73
d67cc4fbc3f1
equal deleted inserted replaced
67:f8cc57c608e2 72:2266d6d73de3
1 impot hgapi
2 from configfile import Config
3 g_needCommitsTxtRebuild = True
4
5 def make_commits_txt():
6 global g_needCommitsTxtRebuild
7
8 if g_needCommitsTxtRebuild == False:
9 return
10
11 print 'Building commits.txt...'
12 # Update zandronum-everything
13 repo = hgapi.Repo ('zandronum-everything')
14 repo.hg_command ('pull', '../zandronum-sandbox')
15 repo.hg_command ('pull', '../zandronum-sandbox-stable')
16
17 data = repo.hg_command ('log', '--template', '{node} {date|hgdate}\n')
18
19 f = open ('commits.txt', 'w')
20
21 for line in data.split ('\n'):
22 if line == '':
23 continue
24
25 words = line.split (' ')
26 timestamp = int (words[1])
27 f.write ('%s %s\n' % (words[0], datetime.utcfromtimestamp (timestamp).strftime ('%y%m%d-%H%M')))
28 f.close()
29 g_needCommitsTxtRebuild = False
30 #enddef
31
32 ' Check if a repository exists '
33 def check_repo_exists (repo_name, repo_owner):
34 print 'Checking that %s exists...' % repo_name
35 repo_url = 'https://bitbucket.org/%s/%s' % (repo_owner, repo_name)
36 zanrepo = hgapi.Repo (repo_name)
37
38 try:
39 zanrepo.hg_command ('id', '.')
40 except hgapi.hgapi.HgException:
41 # If the repo does not exist, clone it. zandronum-everything can be spawned off other repos though
42 if repo_name == 'zandronum-everything':
43 if not os.path.exists (repo_name):
44 os.makedirs (repo_name)
45
46 global g_needCommitsTxtRebuild
47 g_needCommitsTxtRebuild = True
48 print 'Init %s' % repo_name
49 zanrepo.hg_command ('init')
50 print 'Cloning zandronum-sandbox into %s' % repo_name
51 zanrepo.hg_command ('pull', '../zandronum-sandbox')
52 print 'Cloning zandronum-sandbox-stable into %s' % repo_name
53 zanrepo.hg_command ('pull', '../zandronum-sandbox-stable')
54 print 'Done'
55 make_commits_txt()
56 return
57 #fi
58
59 try:
60 print 'Cloning %s...' % repo_name
61 zanrepo.hg_clone (repo_url, repo_name)
62 print 'Cloning done.'
63 except Exception as e:
64 print 'Unable to clone %s from %s: %s' % (repo_name, repo_url, str (`e`))
65 quit(1)
66 #tried
67 #enddef
68
69 check_repo_exists ('zandronum', 'Torr_Samaho')
70 check_repo_exists ('zandronum-stable', 'Torr_Samaho')
71 check_repo_exists ('zandronum-sandbox', 'crimsondusk')
72 check_repo_exists ('zandronum-sandbox-stable', 'crimsondusk')
73 check_repo_exists ('zandronum-everything', '')
74
75 repocheck_timeout = (time.time()) + 15
76
77 def get_commit_data (zanrepo, rev, template):
78 return zanrepo.hg_command ('log', '-l', '1', '-r', rev, '--template', template)
79 #enddef
80
81 def decipher_hgapi_error (e):
82 # Blah, hgapi, why must your error messages be so mangled?
83 try:
84 rawmsg = e.message.replace('\n', '').replace('" +','').replace('\t','')
85 errmsg = re.compile (r'.*: tErr: (.*)Out:.*').match (rawmsg).group (1)
86 return [True, errmsg]
87 except:
88 return [False, '']
89 #endtry
90 #enddef
91
92 def bbcodify(commit_diffstat):
93 result=''
94 for line in commit_diffstat.split('\n'):
95 # Add green color-tags for the ++++++++++ stream
96 rex = re.compile (r'^(.*)\|(.*) (\+*)(-*)(.*)$')
97 match = rex.match (line)
98 if match:
99 line = '%s|%s [color=#5F7]%s[/color][color=#F53]%s[/color]%s\n' \
100 % (match.group (1), match.group (2), match.group (3), match.group (4), match.group (5))
101
102 # Tracker doesn't seem to like empty color tags
103 line = line.replace ('[color=#5F7][/color]', '').replace ('[color=#F53][/color]', '')
104 #else:
105 #rex = re.compile (r'^(.*) ([0-9]+) insertions\(\+\), ([0-9]+) deletions\(\-\)$')
106 #match = rex.match (line)
107 #if match:
108 #line = '%s [b][color=green]%s[/color][/b] insertions, [b][color=red]%s[/color][/b] deletions\n' \
109 #% (match.group (1), match.group (2), match.group (3))
110
111 result += line
112 #done
113
114 return result
115 #enddef
116
117 def find_developer_by_email (commit_email):
118 for developer, emails in Config.get_value ('developer_emails', default={}).iteritems():
119 for email in emails:
120 if commit_email == email:
121 return developer
122 #fi
123 #done
124 #done
125
126 return ''
127 #enddef
128
129 ' Retrieves and processes commits for zandronum repositories '
130 ' Ensure both repositories are OK before using this! '
131 def poll():
132 for n in ['zandronum-stable', 'zandronum', 'zandronum-sandbox', 'zandronum-sandbox-stable']:
133 process_one_repo (n)
134
135 def process_one_repo (repo_name):
136 global repocheck_timeout
137 global g_clients
138
139 hgns = Config.get_node ('hg')
140
141 if not hgns.get_value ('track', default=True):
142 return
143
144 usestable = repo_name == 'zandronum-stable'
145 usesandbox = repo_name == 'zandronum-sandbox' or repo_name == 'zandronum-sandbox-stable'
146 repo_owner = 'Torr_Samaho' if not usesandbox else 'crimsondusk'
147 repo_url = 'https://bitbucket.org/%s/%s' % (repo_owner, repo_name)
148 num_commits = 0
149 btuser, btpassword = bt_credentials()
150
151 if time.time() < repocheck_timeout:
152 return
153
154 repocheck_timeout = time.time() + hgns.get_value ('checkinterval', default=15) * 60
155 zanrepo = hgapi.Repo (repo_name)
156 commit_data = []
157 delimeter = '@@@@@@@@@@'
158
159 try:
160 data = zanrepo.hg_command ('incoming', '--quiet', '--template',
161 '{node|short} {desc}' + delimeter)
162 except hgapi.hgapi.HgException as e:
163 deciphered = decipher_hgapi_error (e)
164
165 if deciphered[0] and len(deciphered[1]) > 0:
166 chanlog ("error while using hg import on %s: %s" % (repo_name, deciphered[1]))
167 #fi
168
169 return
170 except Exception as e:
171 chanlog ("%s" % `e`)
172 return
173 #tried
174
175 for line in data.split (delimeter):
176 if line == '':
177 continue
178 #fi
179
180 rex = re.compile (r'([^ ]+) (.+)')
181 match = rex.match (line)
182 failed = False
183
184 if not match:
185 chanlog ('malformed hg data: %s' % line)
186 continue
187 #fi
188
189 commit_node = match.group (1)
190 commit_message = match.group (2)
191 commit_data.append ([commit_node, commit_message])
192 #done
193
194 if len (commit_data) > 0:
195 pull_args = [];
196
197 for commit in commit_data:
198 pull_args.append ('-r');
199 pull_args.append (commit[0]);
200 #done
201
202 try:
203 zanrepo.hg_command ('pull', *pull_args)
204
205 # Also pull these commits to the zandronum main repository
206 if usestable:
207 devrepo = hgapi.Repo ('zandronum')
208 devrepo.hg_command ('pull', '../zandronum-stable', *pull_args)
209 #fi
210
211 # Pull everything into sandboxes too
212 if not usesandbox:
213 devrepo = hgapi.Repo ('zandronum-sandbox')
214 devrepo.hg_command ('pull', '../%s' % repo_name, *pull_args)
215
216 devrepo = hgapi.Repo ('zandronum-sandbox-stable')
217 devrepo.hg_command ('pull', '../%s' % repo_name, *pull_args)
218 #fi
219
220 devrepo = hgapi.Repo ('zandronum-everything')
221 devrepo.hg_command ('pull', '../%s' % repo_name, *pull_args)
222
223 global g_needCommitsTxtRebuild
224 g_needCommitsTxtRebuild = True
225 except Exception as e:
226 chanlog ('Warning: unable to pull: %s' % `e`)
227 return
228 #tried
229 #fi
230
231 for commit in commit_data:
232 commit_node = commit[0]
233 commit_message = commit[1]
234
235 try:
236 if usesandbox:
237 commit_author = get_commit_data (zanrepo, commit_node, '{author}')
238 commit_url = '%s/commits/%s' % (repo_url, commit_node)
239 commit_email = ''
240
241 # Remove the email address from the author if possible
242 rex = re.compile (r'^(.+) <([^>]+)>$.*')
243 match = rex.match (commit_author)
244 if match:
245 commit_author = match.group (1)
246 commit_email = match.group (2)
247 #fi
248
249 commit_trackeruser = find_developer_by_email (commit_email)
250 committer = commit_trackeruser if commit_trackeruser != '' else commit_author
251
252 for irc_client in g_clients:
253 for channel in irc_client.cfg['channels']:
254 if 'btprivate' in channel and channel['btprivate'] == True:
255 irc_client.privmsg (channel['name'],
256 "%s: new commit %s by %s: %s"
257 % (repo_name, commit_node, committer, commit_url))
258
259 for line in commit_message.split ('\n'):
260 irc_client.privmsg (channel['name'], line)
261 #fi
262 #done
263 #done
264
265 num_commits += 1
266 continue
267 #fi
268
269 rex = re.compile (r'^.*(fixes|resolves|addresses|should fix) ([0-9]+).*$')
270 match = rex.match (commit_message)
271
272 if not match:
273 continue # no "fixes" message in the commit
274 #fi
275
276 ticket_id = int (match.group (2))
277
278 # Acquire additional data
279 moredata = get_commit_data (zanrepo, commit_node,
280 '{author|nonempty}\n{date(date, \'%A %d %B %Y %T\')}').split('\n')
281
282 if len (moredata) != 2:
283 chanlog ('error while processing %s: malformed hg data' % commit_node)
284 continue
285 #fi
286
287 commit_author = moredata[0]
288 commit_date = moredata[1]
289 commit_email = ""
290
291 try:
292 ticket_data = suds_client.service.mc_issue_get (btuser, btpassword, ticket_id)
293 except Exception as e:
294 chanlog ('error while processing %s: %s' % (commit_node, `e`))
295 continue
296 #tried
297
298 # Remove the email address from the author if possible
299 rex = re.compile (r'^(.+) <([^>]+)>$.*')
300 match = rex.match (commit_author)
301 if match:
302 commit_author = match.group (1)
303 commit_email = match.group (2)
304 #fi
305
306 commit_diffstat = zanrepo.hg_command ('diff', '--change', commit_node, '--stat')
307
308 if len(commit_diffstat) > 0:
309 # commit_diffstat = 'Changes in files:\n[code]\n' + commit_diffstat + '\n[/code]'
310 commit_diffstat = 'Changes in files:\n' + bbcodify(commit_diffstat)
311 else:
312 commit_diffstat = 'No changes in files.'
313
314 # Compare the email addresses against known developer usernames
315 commit_trackeruser = find_developer_by_email (commit_email)
316
317 if commit_trackeruser != '':
318 commit_author += ' [%s]' % commit_trackeruser
319 #fi
320
321 message = 'Issue addressed by commit %s: [b][url=%s/commits/%s]%s[/url][/b]' \
322 % (commit_node, repo_url, commit_node, commit_message)
323 message += "\nCommitted by %s on %s\n\n%s" \
324 % (commit_author, commit_date, commit_diffstat)
325
326 need_update = False
327
328 # If not already set, set handler
329 if not 'handler' in ticket_data:
330 ticket_data['handler'] = {'name': commit_trackeruser}
331 need_update = True
332 #fi
333
334 # Find out the status level of the ticket
335 needs_testing_level = 70
336
337 if ticket_data['status']['id'] < needs_testing_level:
338 ticket_data.status['id'] = needs_testing_level
339 need_update = True
340 #fi
341
342 # Set target version if not set
343 if not 'target_version' in ticket_data:
344 ticket_data['target_version'] = '1.4' if repo_name == 'zandronum-stable' else '2.0'
345 need_update = True
346 elif (ticket_data['target_version'] == '2.0' or ticket_data['target_version'] == '2.0-beta') \
347 and repo_name == 'zandronum-stable':
348 # Target version was 2.0 but this was just committed to zandronum-stable, adjust
349 ticket_data['target_version'] = '1.4'
350 need_update = True
351 elif ticket_data['target_version'] == '2.0-beta':
352 # Fix target version from 2.0-beta to 2.0
353 ticket_data['target_version'] = '2.0'
354 need_update = True
355 #fi
356
357 # Announce on IRC
358 for irc_client in g_clients:
359 for channel in irc_client.channels:
360 if channel.get_value ('btannounce', default=True):
361 irc_client.privmsg (channel.get_value ('name'),
362 "%s: commit %s fixes issue %d: %s"
363 % (repo_name, commit_node, ticket_id, commit_message))
364 irc_client.privmsg (channel.get_value ('name'),
365 "Read all about it here: " + irc_client.get_ticket_url (ticket_id))
366 #fi
367 #done
368 #done
369
370 if need_update:
371 # We need to remove the note data, otherwise the ticket notes
372 # will get unnecessary updates. WTF, MantisBT?
373 ticket_data.notes = []
374 suds_client.service.mc_issue_update (btuser, btpassword, ticket_id, ticket_data)
375 #fi
376
377 suds_client.service.mc_issue_note_add (btuser, btpassword, ticket_id, { 'text': message })
378 num_commits += 1
379 except Exception as e:
380 chanlog ('Error while processing %s: %s' % (commit_node, `e`))
381 continue
382 #tried
383 #done
384 #enddef
385
386 def force_poll():
387 repocheck_timeout = 0
388 poll()

mercurial