cobalt.py

changeset 29
5767ee263b12
parent 28
30257c78904f
child 30
114afc110afd
equal deleted inserted replaced
28:30257c78904f 29:5767ee263b12
101 return True if value == 'true' else False 101 return True if value == 'true' else False
102 102
103 if suds_active: 103 if suds_active:
104 try: 104 try:
105 sys.stdout.write ('Retrieving latest tracker ticket... ') 105 sys.stdout.write ('Retrieving latest tracker ticket... ')
106 btannounce_id = suds_client.service.mc_issue_get_biggest_id (g_config['trackeruser'], g_config ['trackerpassword'], 0) 106 btannounce_id = suds_client.service.mc_issue_get_biggest_id (g_config['trackeruser'], g_config['trackerpassword'], 0)
107 btannounce_active = True 107 btannounce_active = True
108 bt_updatechecktimeout() 108 bt_updatechecktimeout()
109 print btannounce_id 109 print btannounce_id
110 except Exception as e: 110 except Exception as e:
111 pass 111 pass
121 121
122 if time.time() >= btannounce_timeout: 122 if time.time() >= btannounce_timeout:
123 bt_updatechecktimeout() 123 bt_updatechecktimeout()
124 newid = btannounce_id 124 newid = btannounce_id
125 try: 125 try:
126 newid = suds_client.service.mc_issue_get_biggest_id (g_config['trackeruser'], g_config ['trackerpassword'], 0) 126 newid = suds_client.service.mc_issue_get_biggest_id (g_config['trackeruser'], g_config['trackerpassword'], 0)
127 except Exception as e: 127 except Exception as e:
128 pass 128 pass
129 129
130 while newid > btannounce_id: 130 while newid > btannounce_id:
131 try: 131 try:
203 203
204 # from http://www.daniweb.com/software-development/python/code/260268/restart-your-python-program 204 # from http://www.daniweb.com/software-development/python/code/260268/restart-your-python-program
205 def restart_self(): 205 def restart_self():
206 python = sys.executable 206 python = sys.executable
207 os.execl (python, python, * sys.argv) 207 os.execl (python, python, * sys.argv)
208
209 ' Retrieves hg incoming from zandronum repository '
210 def get_incoming_data (zanrepo, rev, template):
211 try:
212 if rev != '':
213 return zanrepo.hg_command ('incoming', '../zanstablecopy', '--quiet', '-r', rev, '--template', template)
214 else:
215 return zanrepo.hg_command ('incoming', '../zanstablecopy', '--quiet', '--template', template)
216 #fi
217 except:
218 pass
219 return ""
220 #enddef
221
222 ' Check if a repository exists '
223 def check_repo_exists (repo_name):
224 print 'Checking that %s exists...' % repo_name
225 repo_url = 'https://bitbucket.org/Torr_Samaho/' + repo_name
226 zanrepo = hgapi.Repo (repo_name)
227
228 try:
229 zanrepo.hg_command ('id', '.')
230 except hgapi.hgapi.HgException:
231 # If the repo does not exist, clone it. After cloning, there obviously
232 # are no more updates, so we'll be done.
233 try:
234 print 'Cloning %s...' % repo_name
235 zanrepo.hg_clone (repo_url, repo_name)
236 print 'Cloning done. No update checking needed.'
237 except Exception as e:
238 print 'Unable to clone %s from %s: %s' % (repo_name, repo_url, str (`e`))
239 quit(1)
240 #tried
241 #enddef
242
243 check_repo_exists ('zandronum')
244 check_repo_exists ('zandronum-stable')
245
246 repocheck_timeout = {'zandronum':(time.time()) + 15, 'zandronum-stable':(time.time() + 15)}
247
248 ' Retrieves and processes commits for zandronum repositories '
249 ' Ensure both repositories are OK before using this! '
250 def process_zan_repo_updates (usestable):
251 global repocheck_timeout
252 global suds_client
253 global g_config
254 global g_clients
255
256 repo_name = 'zandronum' if usestable == False else 'zandronum-stable'
257 repo_url = 'https://bitbucket.org/Torr_Samaho/' + repo_name
258
259 if time.time() < repocheck_timeout[repo_name]:
260 return
261
262 repocheck_timeout[repo_name] = time.time() + (cfg ('hg_checkinterval', 15) * 60)
263 zanrepo = hgapi.Repo (repo_name)
264 data = get_incoming_data (zanrepo, '', '{node|short} {desc}\n')
265 commits_to_pull = [];
266
267 for line in data.split ('\n'):
268 if line == '':
269 continue
270 #fi
271
272 rex = re.compile (r'^([^ ]+) (.+)$')
273 match = rex.match (line)
274 failed = False
275
276 if not match:
277 chanlog ('malformed hg data: %s' % line)
278 continue
279 #fi
280
281 try:
282 commit_node = match.group (1)
283 commit_message = match.group (2)
284
285 rex = re.compile (r'^.*(fixes|resolves|addresses) ([0-9]+).*$')
286 match = rex.match (commit_message)
287
288 if not match:
289 continue # no "fixes" message in the commit
290 #fi
291
292 ticket_id = int (match.group (2))
293
294 # Acquire additional data
295 moredata = get_incoming_data (zanrepo, commit_node,
296 '{author|nonempty}\n{date(date, \'%A %d %B %Y %T\')}\n{diffstat|nonempty}').split('\n')
297
298 if len (moredata) != 3:
299 chanlog ('commit %s: malformed hg data' % commit_node)
300 #fi
301
302 commit_author = moredata[0]
303 commit_date = moredata[1]
304 commit_diffstat = moredata[2]
305 commit_email = ""
306
307 ticket_data = suds_client.service.mc_issue_get (g_config['trackeruser'], g_config['trackerpassword'], ticket_id)
308 if not ticket_data:
309 chanlog ("error: commit %s: ticket %s not found" % (commit_node, ticket_id))
310 continue
311 #fi
312
313 # Remove the email address from the author if possible
314 rex = re.compile (r'^(.+) <([^>]+)>$.*')
315 match = rex.match (commit_author)
316 if match:
317 commit_author = match.group (1)
318 commit_email = match.group (2)
319 #fi
320
321 rex = re.compile (r'([0-9]+): \+([0-9]+)/-([0-9]+)')
322 match = rex.match (commit_diffstat)
323
324 if match:
325 modded = int (match.group (1))
326 added = int (match.group (2))
327 deleted = int (match.group (3))
328 commit_diffstat = "%s file%s modified, %s line%s added, %s line%s removed" % \
329 (modded if modded != 0 else 'no',
330 's' if modded != 1 else '',
331 added if added != 0 else 'no',
332 's' if added != 1 else '',
333 deleted if deleted != 0 else 'no',
334 's' if deleted != 1 else '')
335 #fi
336
337 files_added = filter (None, get_incoming_data (zanrepo, commit_node, '{file_adds}').split ('\n'))
338 files_removed = filter (None, get_incoming_data (zanrepo, commit_node, '{file_dels}').split ('\n'))
339 files_changed = filter (None, get_incoming_data (zanrepo, commit_node, '{file_mods}').split ('\n'))
340
341 # Compare the email addresses against known developer usernames
342 commit_trackeruser = ''
343
344 for developer, emails in g_config['developer_emails'].iteritems():
345 for email in emails:
346 if commit_email == email:
347 commit_trackeruser = developer
348 break;
349 #fi
350 else:
351 continue
352 #done
353 break
354 #done
355
356 if commit_trackeruser != '':
357 commit_author += ' [%s]' % commit_trackeruser
358 #fi
359
360 message = 'Issue addressed by commit %s: [b][url="%s/commits/%s"]%s[/url][/b]' \
361 % (commit_node, repo_url, commit_node, commit_message)
362 message += "\nCommitted by %s on %s\n\n%s" \
363 % (commit_author, commit_date, commit_diffstat)
364
365 if len (files_added) > 0:
366 message += "\nFiles added: %s" % ', '.join (files_added)
367 #fi
368
369 if len (files_removed) > 0:
370 message += "\nFiles removed: %s" % ', '.join (files_removed)
371 #fi
372
373 if len (files_changed) > 0:
374 message += "\nFiles changed: %s" % ', '.join (files_changed)
375 #fi
376
377 need_update = False
378
379 # If not already set, set handler
380 if not 'handler' in ticket_data:
381 ticket_data['handler'] = {'name': commit_trackeruser}
382 need_update = True
383 #fi
384
385 # Find out the status level of the ticket
386 needs_testing_level = 70
387
388 if ticket_data['status']['id'] < needs_testing_level:
389 ticket_data.status['id'] = needs_testing_level
390 need_update = True
391 #fi
392
393 # Announce on IRC
394 for irc_client in g_clients:
395 for channel in irc_client.cfg['channels']:
396 if 'btannounce' in channel and channel['btannounce'] == True:
397 irc_client.privmsg (channel['name'],
398 "%s: commit %s fixes issue %d: %s"
399 % (repo_name, commit_node, ticket_id, commit_message))
400 irc_client.privmsg (channel['name'],
401 "Read all about it here: " + irc_client.get_ticket_url (ticket_id))
402 #fi
403 #done
404 #done
405
406 if need_update:
407 suds_client.service.mc_issue_update (g_config['trackeruser'], g_config['trackerpassword'], ticket_id, ticket_data)
408 #fi
409
410 suds_client.service.mc_issue_note_add (g_config['trackeruser'], g_config['trackerpassword'], ticket_id, { 'text': message })
411 except Exception as e:
412 chanlog ('Error: %s' % `e`)
413 failed = True
414 #tried
415
416 if not failed:
417 commits_to_pull.append (commit_node)
418 #fi
419 #done
420
421 if len (commits_to_pull) > 0:
422 pull_args = ['pull', '../zanstablecopy']
423
424 for commit in commits_to_pull:
425 pull_args.append ('-r');
426 pull_args.append (commit);
427 #done
428
429 try:
430 zanrepo.hg_command (*pull_args)
431
432 # Also pull these commits to the zandronum main repository
433 if usestable:
434 devrepo = hgapi.Repo ('zandronum')
435 devrepo.hg_command (*pull_args)
436 #fi
437 except Exception as e:
438 chanlog ('Warning: unable to pull: %s' % `e`)
439 #tried
440 #fi
441 #enddef
208 442
209 # 443 #
210 # Main IRC client class 444 # Main IRC client class
211 # 445 #
212 class irc_client (asyncore.dispatcher): 446 class irc_client (asyncore.dispatcher):
327 self.mynick = '%s%s' % (self.mynick, self.cfg['conflictsuffix']) 561 self.mynick = '%s%s' % (self.mynick, self.cfg['conflictsuffix'])
328 self.write ("NICK %s" % self.mynick) 562 self.write ("NICK %s" % self.mynick)
329 563
330 # Check for new issues on the bugtracker 564 # Check for new issues on the bugtracker
331 bt_checklatest() 565 bt_checklatest()
566
567 # Check for new commits in the repositories
568 # note: stable (i.e. True) goes first!
569 for n in [True, False]:
570 process_zan_repo_updates (n)
332 571
333 def channel_by_name (self, name): 572 def channel_by_name (self, name):
334 for channel in self.channels: 573 for channel in self.channels:
335 if channel['name'].upper() == args[0].upper(): 574 if channel['name'].upper() == args[0].upper():
336 return channel 575 return channel
550 raise logical_exception ('unknown key ' + key) 789 raise logical_exception ('unknown key ' + key)
551 790
552 self.privmsg (replyto, '%s is now %s' % (key, channel[key])) 791 self.privmsg (replyto, '%s is now %s' % (key, channel[key]))
553 792
554 save_config() 793 save_config()
794 elif command == 'devemail':
795 check_admin (sender, ident, host, command)
796
797 if len(args) < 2:
798 raise logical_exception ("usage: .%s <user> <email>" % command)
799 #fi
800
801 if not 'developer_emails' in g_config:
802 g_config['developer_emails'] = {}
803 #fi
804
805 user = ' '.join (args[0:-1])
806
807 if args[0] in g_config['developer_emails']:
808 g_config['developer_emails'][user].append (args[-1])
809 else:
810 g_config['developer_emails'][user] = [args[-1]]
811 #fi
812
813 self.privmsg (replyto, 'Developer emails for %s are now %s' %
814 (user, ', '.join (g_config['developer_emails'][user])))
815 save_config()
816 elif command == 'deldevemail':
817 check_admin (sender, ident, host, command)
818
819 if len(args) < 2:
820 raise logical_exception ("usage: .%s <user> <email>" % command)
821 #fi
822
823 if not 'developer_emails' in g_config:
824 g_config['developer_emails'] = {}
825 #fi
826
827 user = ' '.join (args[0:-1])
828
829 if user in g_config['developer_emails']:
830 try:
831 g_config['developer_emails'][user].remove (args[-1])
832 except:
833 pass
834 #tried
835
836 if len (g_config['developer_emails'][user]) == 0:
837 g_config['developer_emails'].pop (user)
838 self.privmsg (replyto, 'No more developer emails for %s' % user)
839 else:
840 self.privmsg (replyto, 'Developer emails for %s are now %s' %
841 (user, ', '.join (g_config['developer_emails'][user])))
842 #fi
843 save_config()
844 else:
845 self.privmsg (replyto, 'There is no developer \'%s\'' % user)
846 #fi
847 elif command == 'listdevemails':
848 check_admin (sender, ident, host, command)
849
850 for dev, emails in g_config['developer_emails'].iteritems():
851 self.privmsg (replyto, 'Emails for %s: %s' % (dev, ', '.join (emails)))
852 #done
853 elif command == 'checkhg':
854 check_admin (sender, ident, host, command)
855 global repocheck_timeout
856 repocheck_timeout = {'zandronum':0, 'zandronum-stable':0}
857 process_zan_repo_updates (True)
858 process_zan_repo_updates (False)
555 elif command == 'die': 859 elif command == 'die':
556 check_admin (sender, ident, host, command) 860 check_admin (sender, ident, host, command)
557 quit() 861 quit()
558 elif command == 'convert': 862 elif command == 'convert':
559 if len(args) != 3 or args[1] != 'as': 863 if len(args) != 3 or args[1] != 'as':
652 if conndata['name'] == aconn: 956 if conndata['name'] == aconn:
653 irc_client (conndata, 0) 957 irc_client (conndata, 0)
654 break 958 break
655 else: 959 else:
656 raise logical_exception ("unknown autoconnect entry %s" % (aconn)) 960 raise logical_exception ("unknown autoconnect entry %s" % (aconn))
657 961
658 g_BotActive = True 962 g_BotActive = True
659 asyncore.loop() 963 asyncore.loop()
660 except KeyboardInterrupt: 964 except KeyboardInterrupt:
661 for client in g_clients: 965 for client in g_clients:
662 client.keyboardinterrupt() 966 client.keyboardinterrupt()

mercurial