|
| 1 | +# bugzilla4.py - a really simple Python interface to Bugzilla 4.x using xmlrpclib. |
| 2 | +# |
| 3 | +# Copyright (C) 2008-2012 Red Hat Inc. |
| 4 | +# Author: Michal Novotny <[email protected]> |
| 5 | +# |
| 6 | +# This program is free software; you can redistribute it and/or modify it |
| 7 | +# under the terms of the GNU General Public License as published by the |
| 8 | +# Free Software Foundation; either version 2 of the License, or (at your |
| 9 | +# option) any later version. See http://www.gnu.org/copyleft/gpl.html for |
| 10 | +# the full text of the license. |
| 11 | + |
| 12 | +import bugzilla.base |
| 13 | + |
| 14 | +class Bugzilla4(bugzilla.base.BugzillaBase): |
| 15 | + '''Concrete implementation of the Bugzilla protocol. This one uses the |
| 16 | + methods provided by standard Bugzilla 4.0.x releases.''' |
| 17 | + |
| 18 | + version = '0.1' |
| 19 | + user_agent = bugzilla.base.user_agent + ' Bugzilla4/%s' % version |
| 20 | + #createbug_required = ('product','component','summary','version') |
| 21 | + |
| 22 | + createbug_required = ('product','component','summary','version', |
| 23 | + 'op_sys','platform') |
| 24 | + |
| 25 | + def __init__(self,**kwargs): |
| 26 | + bugzilla.base.BugzillaBase.__init__(self,**kwargs) |
| 27 | + self.user_agent = self.__class__.user_agent |
| 28 | + |
| 29 | + def _login(self,user,password): |
| 30 | + '''Backend login method for Bugzilla4''' |
| 31 | + return self._proxy.User.login({'login':user,'password':password}) |
| 32 | + |
| 33 | + def _logout(self): |
| 34 | + '''Backend login method for Bugzilla4''' |
| 35 | + return self._proxy.User.logout() |
| 36 | + |
| 37 | + #---- Methods and properties with basic bugzilla info |
| 38 | + |
| 39 | + def _getuserforid(self,userid): |
| 40 | + '''Get the username for the given userid''' |
| 41 | + # STUB FIXME |
| 42 | + return str(userid) |
| 43 | + |
| 44 | + def _getproducts(self): |
| 45 | + '''This throws away a bunch of data that RH's getProdInfo |
| 46 | + didn't return. Ah, abstraction.''' |
| 47 | + product_ids = self._proxy.Product.get_accessible_products() |
| 48 | + r = self._proxy.Product.get_products(product_ids) |
| 49 | + return r['products'] |
| 50 | + def _getcomponents(self,product): |
| 51 | + if type(product) == str: |
| 52 | + product = self._product_name_to_id(product) |
| 53 | + r = self._proxy.Bug.legal_values({'product_id':product,'field':'component'}) |
| 54 | + return r['values'] |
| 55 | + |
| 56 | + #---- Methods for reading bugs and bug info |
| 57 | + |
| 58 | + def _getbugs(self,idlist): |
| 59 | + '''Return a list of dicts of full bug info for each given bug id. |
| 60 | + bug ids that couldn't be found will return None instead of a dict.''' |
| 61 | + idlist = map(lambda i: int(i), idlist) |
| 62 | + r = self._proxy.Bug.get_bugs({'ids':idlist, 'permissive': 1}) |
| 63 | + bugdict = dict([(b['id'], b) for b in r['bugs']]) |
| 64 | + return [bugdict.get(i) for i in idlist] |
| 65 | + def _getbug(self,id): |
| 66 | + '''Return a dict of full bug info for the given bug id''' |
| 67 | + return self._getbugs([id])[0] |
| 68 | + |
| 69 | + # TODO: Bugzilla4 should support getbugsimple, needs to be implemented |
| 70 | + _getbugsimple = _getbug |
| 71 | + _getbugssimple = _getbugs |
| 72 | + |
| 73 | + #---- createbug - call to create a new bug |
| 74 | + |
| 75 | + def _createbug(self,**data): |
| 76 | + '''Raw xmlrpc call for createBug() Doesn't bother guessing defaults |
| 77 | + or checking argument validity. Use with care. |
| 78 | + Returns bug_id''' |
| 79 | + r = self._proxy.Bug.create(data) |
| 80 | + return r['id'] |
| 81 | + |
| 82 | + #---- Methods for interacting with users |
| 83 | + |
| 84 | + def _createuser(self, email, name=None, password=None): |
| 85 | + '''Create a new bugzilla user directly. |
| 86 | +
|
| 87 | + :arg email: email address for the new user |
| 88 | + :kwarg name: full name for the user |
| 89 | + :kwarg password: a password to use with the account |
| 90 | + ''' |
| 91 | + userid = self._proxy.User.create(email, name, password) |
| 92 | + return userid |
| 93 | + |
| 94 | + def _addcomment(self,id,comment,private=False, |
| 95 | + timestamp='',worktime='',bz_gid=''): |
| 96 | + '''Add a comment to the bug with the given ID. Other optional |
| 97 | + arguments are as follows: |
| 98 | + private: if True, mark this comment as private. |
| 99 | + timestamp: Ignored by BZ32. |
| 100 | + worktime: amount of time spent on this comment, in hours |
| 101 | + bz_gid: Ignored by BZ32. |
| 102 | + ''' |
| 103 | + return self._proxy.Bug.add_comment({'id':id, |
| 104 | + 'comment':comment, |
| 105 | + 'private':private, |
| 106 | + 'work_time':worktime}) |
| 107 | + |
| 108 | + def _getusers(self, ids=None, names=None, match=None): |
| 109 | + '''Return a list of users that match criteria. |
| 110 | +
|
| 111 | + :kwarg ids: list of user ids to return data on |
| 112 | + :kwarg names: list of user names to return data on |
| 113 | + :kwarg match: list of patterns. Returns users whose real name or |
| 114 | + login name match the pattern. |
| 115 | + :raises xmlrpclib.Fault: Code 51: if a Bad Login Name was sent to the |
| 116 | + names array. |
| 117 | + Code 304: if the user was not authorized to see user they |
| 118 | + requested. |
| 119 | + Code 505: user is logged out and can't use the match or ids |
| 120 | + parameter. |
| 121 | +
|
| 122 | + Available in Bugzilla-3.4+ |
| 123 | + ''' |
| 124 | + params = {} |
| 125 | + if ids: |
| 126 | + params['ids'] = ids |
| 127 | + if names: |
| 128 | + params['names'] = names |
| 129 | + if match: |
| 130 | + params['match'] = match |
| 131 | + if not params: |
| 132 | + raise bugzilla.base.NeedParamError('_get() needs one of ids,' |
| 133 | + ' names, or match kwarg.') |
| 134 | + |
| 135 | + return self._proxy.User.get(params) |
| 136 | + |
| 137 | + def _query(self,query): |
| 138 | + '''Query bugzilla and return a list of matching bugs. |
| 139 | + query must be a dict with fields like those in in querydata['fields']. |
| 140 | + You can also pass in keys called 'quicksearch' or 'savedsearch' - |
| 141 | + 'quicksearch' will do a quick keyword search like the simple search |
| 142 | + on the Bugzilla home page. |
| 143 | + 'savedsearch' should be the name of a previously-saved search to |
| 144 | + execute. You need to be logged in for this to work. |
| 145 | + Returns a dict like this: {'bugs':buglist, |
| 146 | + 'sql':querystring} |
| 147 | + buglist is a list of dicts describing bugs, and 'sql' contains the SQL |
| 148 | + generated by executing the search. |
| 149 | + You can also pass 'limit:[int]' to limit the number of results. |
| 150 | + For more info, see: |
| 151 | + http://www.bugzilla.org/docs/4.0/en/html/api/Bugzilla/WebService/Bug.html |
| 152 | + ''' |
| 153 | + return self._proxy.Bug.search(query) |
| 154 | + |
| 155 | + # Hooray, a proper _getbugfields implementation |
| 156 | + def _getbugfields(self): |
| 157 | + '''Get the list of valid fields for Bug objects''' |
| 158 | + r = self._proxy.Bug.fields({'include_fields':['name']}) |
| 159 | + return [f['name'] for f in r['fields']] |
| 160 | + # NOTE: the RHBZ version lists 'comments' and 'groups', and strips |
| 161 | + # the 'cf_' from the beginning of custom fields. |
0 commit comments