Patch for Python 3 Support
by Ralph Bean
Hello all,
I created a patch to update python-bugzilla to work on both python 2
and python 3. The unit tests all pass under both py2.7 and py3.2.
I have tested the login and query commands by hand on py2.6, py2.7,
and py3.2.
http://threebean.org/patches/python-bugzilla-Python3-support.patch
The patch is against the master branch (7ca8a60). If I should
recreate it against another branch, please let me know.
I'm also willing to update and maintain a spec file supporting both
versions if and when that time comes.
Cheers-
-Ralph
10 years, 10 months
[PATCH] Bug cloning
by Martin Cermak
Hi, I belive that cloning a bug is a useful feature. Below I'm
attaching a patch that should do the trick. I attempted to follow
the behaviour of Bugzilla's web UI:
----------------8<---------------------------------------------
diff --git a/bugzilla/base.py b/bugzilla/base.py
index 7748e2b..7e148c4 100644
--- a/bugzilla/base.py
+++ b/bugzilla/base.py
@@ -618,6 +618,17 @@ class BugzillaBase(object):
You may also add a "nomail":1 item, which will suppress email if set.'''
raise NotImplementedError
+ #---- Methods for cloning bugs.
+
+ def _clonebug(self,id,product=None,component=None,version=None):
+ '''IMPLEMENT ME: Clone the given bug. This is the raw call, and no data checking is
+ done here. That's up to the clonebug method.'''
+ raise NotImplementedError
+
+ def clonebug(self,product=None,component=None,version=None):
+ '''Clone the given bug.'''
+ return self.bugzilla._clonebug(self.bug_id,product,component,version)
+
#---- Methods for working with attachments
def _attachment_encode(self,fh):
@@ -1305,6 +1316,11 @@ class _Bug(object):
'''An alias for refresh()'''
self.refresh()
+ def clonebug(self,product=None,component=None,version=None):
+ '''Clone the given bug. This is the raw call, and no data checking is
+ done here. That's up to the clonebug method.'''
+ return self.bugzilla._clonebug(self.bug_id,product,component,version)
+
def setstatus(self,status,comment='',private=False,private_in_it=False,nomail=False):
'''Update the status for this bug report.
Valid values for status are listed in querydefaults['bug_status_list']
diff --git a/bugzilla/rhbugzilla.py b/bugzilla/rhbugzilla.py
index 4233d32..59fb418 100644
--- a/bugzilla/rhbugzilla.py
+++ b/bugzilla/rhbugzilla.py
@@ -130,6 +130,17 @@ class RHBugzilla(Bugzilla4):
requestee (as in: needinfo from smartguy(a)answers.com). Alas.'''
return self._proxy.bugzilla.updateFlags(id,flags)
+ #---- Methods for cloning bugs.
+
+ def _clonebug(self,id,product=None,component=None,version=None):
+ '''IMPLEMENT MEClone the given bug. This is the raw call, and no data checking is
+ done here. That's up to the clonebug method.'''
+ raise NotImplementedError
+
+ def clonebug(self,product=None,component=None,version=None):
+ '''Clone the given bug.'''
+ return self.bugzilla._clonebug(self.bug_id,product,component,version)
+
#---- Methods for working with attachments
# If your bugzilla wants attachments in something other than base64, you
@@ -281,6 +292,94 @@ class RHBugzilla(Bugzilla4):
return self._close_bug(id, update)
#return self._update_bug(id,update)
+ def _clonebug(self,id,product=None,component=None,version=None):
+ '''Clone this bug similarly as one can do it in the webui'''
+ origbug = self.getbug(id)
+ clone_message = '+++ This bug was initially created as a clone of Bug #%s +++\n\n' % (origbug.id)
+ isprivate = False
+ isadditional = False
+ for rec in origbug.longdescs:
+ if isadditional:
+ clone_message += '\n--- Additional comment from '
+ clone_message += rec['author']['realname']
+ clone_message += ' on '
+ clone_message += rec['time']
+ clone_message += ' EDT ---\n\n'
+ if 'extra_data' in rec.keys():
+ clone_message += '\n\n*** This bug has been marked as a duplicate of bug %s ***\n' % (rec['extra_data'])
+ else:
+ clone_message += rec['body'] + "\n"
+ isadditional = True
+ if rec['isprivate'] == 1:
+ isprivate = True
+ cc = origbug.cc
+ cc.append(origbug.reporter)
+ depends_on = str(origbug.bug_id) + ' '
+ depends_on += ' '.join([str(i) for i in origbug.dependson])
+ new_product = product
+ if new_product == None: new_product = origbug.product
+ new_component = component
+ if new_component == None: new_component = origbug.component
+ new_version = version
+ new_target_release = None
+ if new_version == None and new_product != origbug.product:
+ releases = self._proxy.Product.get({'names': new_product, 'include_fields': ['releases']})
+ prodinfo = releases['products'][0]['releases']
+ versions = [p['name'] for p in prodinfo]
+ new_version = versions[-1]
+ elif new_version == None:
+ new_target_release = origbug.target_release
+ new_version = origbug.version
+ kwargs = {
+ 'product': new_product,
+ 'component': new_component,
+ 'version': new_version,
+ 'op_sys': origbug.op_sys,
+ 'platform': origbug.platform,
+ 'summary': origbug.summary,
+ 'description': clone_message,
+ 'comment_is_private': isprivate,
+ 'priority': origbug.priority,
+ 'bug_severity': origbug.bug_severity,
+ 'depends_on': depends_on,
+ 'blocked': origbug.blocked,
+ 'whiteboard': origbug.whiteboard,
+ 'keywords': origbug.keywords,
+ 'cc': cc,
+ 'estimated_time': origbug.estimated_time,
+ 'remaining_time': origbug.remaining_time,
+ 'deadline': origbug.deadline,
+ 'url': origbug.bug_file_loc,
+ 'target_release': new_target_release
+ }
+ for key in kwargs.keys():
+ if kwargs[key] == None:
+ del kwargs[key]
+ newbug = self.createbug(**kwargs)
+ origgroups = [grp['name'] for grp in origbug.groups if grp['ison'] == 1]
+ update = dict(
+ cf_clone_of = str(origbug.id),
+ groups = dict(add = origgroups),
+ cf_qa_whiteboard = origbug.qa_whiteboard,
+ cf_cust_facing = origbug.cust_facing,
+ cf_devel_whiteboard = origbug.devel_whiteboard,
+ cf_internal_whiteboard = origbug.internal_whiteboard,
+ cf_build_id = origbug.build_id,
+ cf_partner = origbug.partner,
+ cf_verified = ['Any'],
+ cf_environment = origbug.cf_environment
+ )
+ changes = self._update_bug(newbug.id,update)
+ # external tracker references
+ extbugs = []
+ for eb in origbug.external_bugs:
+ neb = {}
+ neb['ext_bz_bug_id'] = eb['ext_bz_bug_id']
+ neb['ext_type_id'] = eb['type']['id']
+ extbugs.append(neb)
+ self._proxy.ExternalBugs.add_external_bug({'bug_ids': [newbug.id], 'external_bugs': extbugs})
+ return newbug
+
def _setassignee(self,id,**data):
'''Raw xmlrpc call to set one of the assignee fields on a bug.
changeAssignment($id, $data, $username, $password)
----------------8<---------------------------------------------
Martin
11 years, 1 month
[PATCH] Detection of the RH Bugzilla by the extension() call
by Lukas Zachar
Part of the planed upgrade to the v4.4 of RH Bugzilla is the removal of
mirrored XMLRPC calls (rhbz#822007). Among others the
bugzilla.getProdInfo() which is currently used as indicator of RH
Bugzilla.
I believe the Bugzilla.extensions() call can be used as a indicator
instead, although it is marked as unstable.
---
bugzilla/__init__.py | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/bugzilla/__init__.py b/bugzilla/__init__.py
index 1c9f3f5..2f354d9 100644
--- a/bugzilla/__init__.py
+++ b/bugzilla/__init__.py
@@ -29,11 +29,12 @@ def getBugzillaClassForURL(url):
bzversion = ''
c = None
- # Check for a RH-only method
+ # Check for a Red Hat extension
try:
- log.debug("Checking for RH Bugzilla method bugzilla.getProdInfo()")
- prodinfo = s.bugzilla.getProdInfo()
- rhbz = True
+ log.debug("Checking for Red Hat Bugzilla extension")
+ extensions = s.Bugzilla.extensions()
+ if extensions.get('extensions', {}).get('RedHat', False):
+ rhbz = True
except xmlrpclib.Fault:
pass
log.debug("rhbz=%s" % str(rhbz))
--
1.7.1
11 years, 3 months