path: root/bugzilla
diff options
authorWill Woods <>2008-08-15 10:27:40 -0400
committerWill Woods <>2008-08-15 10:27:40 -0400
commit504db87ae33aae1703931a6226058db49d5b99ea (patch)
treebcbf3a25e34d534428a98b7e3a3812a25fdf2fb6 /bugzilla
parent3b1228e764c241f8dc74b930d1a9baef67e0e210 (diff)
Add _update_bugs, implement most of the backend calls for BZ32, add stubs for the rest.
Diffstat (limited to 'bugzilla')
1 files changed, 132 insertions, 4 deletions
diff --git a/bugzilla/ b/bugzilla/
index fae316f..b3c508f 100644
--- a/bugzilla/
+++ b/bugzilla/
@@ -40,8 +40,8 @@ class Bugzilla3(bugzilla.base.BugzillaBase):
# Connect the backend methods to the XMLRPC methods
def _getbugfields(self):
'''Get a list of valid fields for bugs.'''
- #I don't think BZ3 provides a getbugfields() method, so right
- #we fake it by looking at bug #1. Yuck.
+ # XXX BZ3 doesn't currently provide anything like the getbugfields()
+ # method, so we fake it by looking at bug #1. Yuck.
keylist = self._getbug(1).keys()
if 'assigned_to' not in keylist:
@@ -213,7 +213,7 @@ class Bugzilla3(bugzilla.base.BugzillaBase):
r = self._proxy.Bug.create(data)
return r['id']
-# Bugzilla 3.2 adds a whole bunch of new goodies.
+# Bugzilla 3.2 adds a whole bunch of new goodies on top of Bugzilla3.
class Bugzilla32(Bugzilla3):
'''Concrete implementation of the Bugzilla protocol. This one uses the
methods provided by standard Bugzilla 3.2.x releases.'''
@@ -221,4 +221,132 @@ class Bugzilla32(Bugzilla3):
version = '0.1'
user_agent = bugzilla.base.user_agent + ' Bugzilla32/%s' % version
- # TODO: add goodies (_query, etc)
+ def _query(self,query):
+ '''Query bugzilla and return a list of matching bugs.
+ query must be a dict with fields like those in in querydata['fields'].
+ You can also pass in keys called 'quicksearch' or 'savedsearch' -
+ 'quicksearch' will do a quick keyword search like the simple search
+ on the Bugzilla home page.
+ 'savedsearch' should be the name of a previously-saved search to
+ execute. You need to be logged in for this to work.
+ Returns a dict like this: {'bugs':buglist,
+ 'sql':querystring}
+ buglist is a list of dicts describing bugs, and 'sql' contains the SQL
+ generated by executing the search.
+ '''
+ # The following is true for rhbz; not sure if it's the case for BZ3.2
+ #You can specify which columns/keys will be listed in the bugs by
+ #setting 'column_list' in the query; otherwise the default columns are
+ #used (see the list in querydefaults['default_column_list']).
+ return
+ def _update_bug(self,id,updates):
+ '''Update a single bug, specified by integer ID or (string) bug alias.
+ Really just a convenience method for _update_bugs(ids=[id],updates)'''
+ return self._update_bugs(ids=[id],updates=updates)
+ def _update_bugs(self,ids,updates):
+ '''Update the given fields with the given data in one or more bugs.
+ ids should be a list of integers or strings, representing bug ids or
+ aliases.
+ updates is a dict containing pairs like so: {'fieldname':'newvalue'}
+ '''
+ # TODO document changeable fields & return values
+ # TODO I think we need to catch XMLRPC exceptions to get
+ return self._proxy.Bug.update({'ids':ids,'updates':updates})
+ def _addcomment(self,id,comment,private=False,
+ timestamp='',worktime='',bz_gid=''):
+ '''Add a comment to the bug with the given ID. Other optional
+ arguments are as follows:
+ private: if True, mark this comment as private.
+ timestamp: comment timestamp, in the form "YYYY-MM-DD HH:MM:SS"
+ Ignored by BZ32.
+ worktime: amount of time spent on this comment, in hours
+ bz_gid: if present, and the entire bug is *not* already private
+ to this group ID, this comment will be marked private.
+ '''
+ return self._proxy.Bug.add_comment({'id':id,
+ 'comment':comment,
+ 'private':private,
+ 'worktime':worktime})
+ #---- Methods for updating bugs.
+ # Eventually - when RHBugzilla is well and truly obsolete - we'll delete
+ # all of these methods and refactor the Base Bugzilla object so all the bug
+ # modification calls go through _update_bug.
+ # Until then, all of these methods are basically just wrappers around it.
+ def _setstatus(self,id,status,comment='',private=False,private_in_it=False,nomail=False):
+ '''Set the status of the bug with the given ID.'''
+ update={'bug_status':status}
+ if comment:
+ update['comment'] = comment
+ return self._update_bug(ids=[id],updates=update)
+ def _closebug(self,id,resolution,dupeid,fixedin,comment,isprivate,private_in_it,nomail):
+ '''Close the given bug. This is the raw call, and no data checking is
+ done here. That's up to the closebug method.
+ Note that the private_in_it and nomail args are ignored.'''
+ update={'bug_status':'CLOSED','resolution':resolution}
+ if dupeid:
+ update['resolution'] = 'DUPLICATE'
+ update['dupe_id'] = dupeid
+ if fixedin:
+ update['fixed_in'] = fixedin
+ if comment:
+ update['comment'] = comment
+ if isprivate:
+ update['commentprivacy'] = True
+ return self._update_bug(ids=[id],updates=update)
+ def _setassignee(self,id,**data):
+ '''Raw xmlrpc call to set one of the assignee fields on a bug.
+ changeAssignment($id, $data, $username, $password)
+ data: 'assigned_to','reporter','qa_contact','comment'
+ returns: [$id, $mailresults]'''
+ # drop empty items
+ update = dict([(k,v) for k,v in data.iteritems() if v != ''])
+ return self._update_bug(ids=[id],updates=data)
+ def _updatedeps(self,id,deplist):
+ '''IMPLEMENT ME: update the deps (blocked/dependson) for the given bug.
+ updateDepends($bug_id,$data,$username,$password,$nodependencyemail)
+ #data: 'blocked'=>id,'dependson'=>id,'action' => ('add','remove')'''
+ raise NotImplementedError, "wwoods needs to port this method."
+ def _updatecc(self,id,cclist,action,comment='',nomail=False):
+ '''Updates the CC list using the action and account list specified.
+ cclist must be a list (not a tuple!) of addresses.
+ action may be 'add', 'remove', or 'makeexact'.
+ comment specifies an optional comment to add to the bug.
+ if mail is True, email will be generated for this change.
+ '''
+ raise NotImplementedError, "wwoods needs to port this method."
+ def _updatewhiteboard(self,id,text,which,action):
+ '''Update the whiteboard given by 'which' for the given bug.
+ performs the given action (which may be 'append',' prepend', or
+ 'overwrite') using the given text.'''
+ data = {'type':which,'text':text,'action':action}
+ raise NotImplementedError, "wwoods needs to port this method."
+ # TODO: update this when the XMLRPC interface grows requestee support
+ def _updateflags(self,id,flags):
+ '''Updates the flags associated with a bug report.
+ data should be a hash of {'flagname':'value'} pairs, like so:
+ {'needinfo':'?','fedora-cvs':'+'}
+ You may also add a "nomail":1 item, which will suppress email if set.
+ NOTE: the Red Hat XMLRPC interface does not yet support setting the
+ requestee (as in: needinfo from Alas.'''
+ raise NotImplementedError, "wwoods needs to port this method."
+ #---- Methods for working with attachments
+ # If your bugzilla wants attachments in something other than base64, you
+ # should override _attachment_encode here.
+ # If your bugzilla uses non-standard paths for attachment.cgi, you'll
+ # want to override _attachment_uri here.
+ def _attachfile(self,id,**attachdata):
+ raise NotImplementedError, "wwoods needs to port this method."