summaryrefslogtreecommitdiffstats
path: root/bugzilla/rhbugzilla.py
diff options
context:
space:
mode:
Diffstat (limited to 'bugzilla/rhbugzilla.py')
-rw-r--r--bugzilla/rhbugzilla.py189
1 files changed, 189 insertions, 0 deletions
diff --git a/bugzilla/rhbugzilla.py b/bugzilla/rhbugzilla.py
new file mode 100644
index 0000000..5bfaabb
--- /dev/null
+++ b/bugzilla/rhbugzilla.py
@@ -0,0 +1,189 @@
+# rhbugzilla.py - a Python interface to Red Hat Bugzilla using xmlrpclib.
+#
+# Copyright (C) 2008 Red Hat Inc.
+# Author: Will Woods <wwoods@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version. See http://www.gnu.org/copyleft/gpl.html for
+# the full text of the license.
+
+import bugzilla.base
+
+version = '0.1'
+user_agent = bugzilla.base.user_agent + ' RHBugzilla/%s' % version
+
+class RHBugzilla(bugzilla.base.BugzillaBase):
+ '''Concrete implementation of the Bugzilla protocol. This one uses the
+ methods provided by Red Hat's Bugzilla 2.18 variant.'''
+ def __init__(self,**kwargs):
+ bugzilla.base.BugzillaBase.__init__(self,**kwargs)
+ self.user_agent = user_agent
+
+ #---- Methods and properties with basic bugzilla info
+
+ # Connect the backend methods to the XMLRPC methods
+ def _getbugfields(self):
+ return self._proxy.bugzilla.getBugFields(self.user,self.password)
+ def _getqueryinfo(self):
+ return self._proxy.bugzilla.getQueryInfo(self.user,self.password)
+ def _getproducts(self):
+ return self._proxy.bugzilla.getProdInfo(self.user, self.password)
+ def _getcomponents(self,product):
+ return self._proxy.bugzilla.getProdCompInfo(product,self.user,self.password)
+ def _getcomponentsdetails(self,product):
+ return self._proxy.bugzilla.getProdCompDetails(product,self.user,self.password)
+
+ #---- Methods for reading bugs and bug info
+
+ def _getbug(self,id):
+ '''Return a dict of full bug info for the given bug id'''
+ return self._proxy.bugzilla.getBug(id, self.user, self.password)
+ def _getbugsimple(self,id):
+ '''Return a short dict of simple bug info for the given bug id'''
+ r = self._proxy.bugzilla.getBugSimple(id, self.user, self.password)
+ if r and 'bug_id' not in r:
+ # XXX hurr. getBugSimple doesn't fault if the bug is missing.
+ # Let's synthesize one ourselves.
+ raise xmlrpclib.Fault("Server","Could not load bug %s" % id)
+ else:
+ return r
+ 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'].
+ Returns a dict like this: {'bugs':buglist,
+ 'displaycolumns':columnlist,
+ 'sql':querystring}
+ buglist is a list of dicts describing bugs. 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']). The list of columns will be
+ in 'displaycolumns', and the SQL query used by this query will be in
+ 'sql'.
+ '''
+ return self._proxy.bugzilla.runQuery(query,self.user,self.password)
+
+ #---- Methods for modifying existing bugs.
+
+ # Most of these will probably also be available as Bug methods, e.g.:
+ # Bugzilla.setstatus(id,status) ->
+ # Bug.setstatus(status): self.bugzilla.setstatus(self.bug_id,status)
+
+ 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"
+ worktime: amount of time spent on this comment (undoc in upstream)
+ 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.bugzilla.addComment(id,comment,
+ self.user,self.password,private,timestamp,worktime,bz_gid)
+ def _setstatus(self,id,status,comment='',private=False,private_in_it=False,nomail=False):
+ '''Set the status of the bug with the given ID. You may optionally
+ include a comment to be added, and may further choose to mark that
+ comment as private.
+ The status may be anything from querydefaults['bug_status_list'].
+ Common statuses: 'NEW','ASSIGNED','MODIFIED','NEEDINFO'
+ Less common: 'VERIFIED','ON_DEV','ON_QA','REOPENED'
+ 'CLOSED' is not valid with this method; use closebug() instead.
+ '''
+ return self._proxy.bugzilla.changeStatus(id,status,
+ self.user,self.password,comment,private,private_in_it,nomail)
+ def _closebug(self,id,resolution,dupeid,fixedin,comment,isprivate,private_in_it,nomail):
+ '''Raw xmlrpc call for closing bugs. Documentation from Bug.pm is
+ below. Note that we drop the username and password fields because the
+ Bugzilla object contains them already.
+
+ closeBug($bugid, $new_resolution, $username, $password, $dupeid,
+ $new_fixed_in, $comment, $isprivate, $private_in_it, $nomail)
+
+ Close a current Bugzilla bug report with a specific resolution. This will eventually be done in Bugzilla/Bug.pm
+ instead and is meant to only be a quick fix. Please use bugzilla.changesStatus to changed to an opened state.
+ This method will change the bug report's status to CLOSED.
+
+ $bugid
+ # ID of bug report to add comment to.
+ $new_resolution
+ # Valid Bugzilla resolution to transition the report into.
+ # DUPLICATE requires $dupeid to be passed in.
+ $dupeid
+ # Bugzilla report ID that this bug is being closed as
+ # duplicate of.
+ # Requires $new_resolution to be DUPLICATE.
+ $new_fixed_in
+ # OPTIONAL String representing version of product/component
+ # that bug is fixed in.
+ $comment
+ # OPTIONAL Text string containing comment to add.
+ $isprivate
+ # OPTIONAL Whether the comment will be private to the
+ # 'private_comment' Bugzilla group.
+ # Default: false
+ $private_in_it
+ # OPTIONAL if true will make the comment private in
+ # Issue Tracker
+ # Default: follows $isprivate
+ $nomail
+ # OPTIONAL Flag that is either 1 or 0 if you want email to be sent or not for this change
+ '''
+ return self._proxy.bugzilla.closeBug(id,resolution,self.user,self.password,
+ dupeid,fixedin,comment,isprivate,private_in_it,nomail)
+ 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]'''
+ return self._proxy.bugzilla.changeAssignment(id,data,self.user,self.password)
+ 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
+ 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.
+ '''
+ data = {'id':id, 'action':action, 'cc':','.join(cclist),
+ 'comment':comment, 'nomail':nomail}
+ return self._proxy.bugzilla.updateCC(data,self.user,self.password)
+ 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}
+ return self._proxy.bugzilla.updateWhiteboard(id,data,self.user,self.password)
+ # 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 smartguy@answers.com). Alas.'''
+ return self._proxy.bugzilla.updateFlags(id,flags,self.user,self.password)
+
+ #---- 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):
+ return self._proxy.bugzilla.addAttachment(id,attachdata,self.user,self.password)
+
+ #---- createbug - call to create a new bug
+
+ def _createbug(self,**data):
+ '''Raw xmlrpc call for createBug() Doesn't bother guessing defaults
+ or checking argument validity. Use with care.
+ Returns [bug_id, mailresults]'''
+ return self._proxy.bugzilla.createBug(data,self.user,self.password)