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@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
On 01/30/2013 02:24 AM, Martin Cermak wrote:
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:
Thanks for the patch Martin! Idea sounds fine to me. But please rebase this patch against the upstream code base which as changed quite a bit.
git clone git://git.fedorahosted.org/git/python-bugzilla.git
Also, stick all the clone logic into the the BugzillaBase class, since the behavior is not specific to rhbugzilla.
Make sure 'python setup.py test' and 'python setup.py pylint' don't regress.
After that I'll do a closer review.
Thanks, Cole
----- Original Message -----
On 01/30/2013 02:24 AM, Martin Cermak wrote:
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:
Thanks for the patch Martin! Idea sounds fine to me. But please rebase this patch against the upstream code base which as changed quite a bit.
git clone git://git.fedorahosted.org/git/python-bugzilla.git
Also, stick all the clone logic into the the BugzillaBase class, since the behavior is not specific to rhbugzilla.
Make sure 'python setup.py test' and 'python setup.py pylint' don't regress.
After that I'll do a closer review.
Thanks, Cole
Hi Cole,
Patch rebased. Regression tests are passing. Please review.
Thanks, Martin
On 03/19/2013 07:24 AM, Martin Cermak wrote:
----- Original Message -----
On 01/30/2013 02:24 AM, Martin Cermak wrote:
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:
Thanks for the patch Martin! Idea sounds fine to me. But please rebase this patch against the upstream code base which as changed quite a bit.
git clone git://git.fedorahosted.org/git/python-bugzilla.git
Also, stick all the clone logic into the the BugzillaBase class, since the behavior is not specific to rhbugzilla.
Make sure 'python setup.py test' and 'python setup.py pylint' don't regress.
After that I'll do a closer review.
Thanks, Cole
Hi Cole,
Patch rebased. Regression tests are passing. Please review.
Thanks, Martin
Sorry Martin, but after thinking about it some more, I don't think we should carry this in python-bugzilla. Really the proper thing here is that the bugzilla XMLRPC API should expose a clone method so we don't need to duplicate all this logic internally. Not to mention getting this to work consistently across bugzilla versions would suck.
If it's important for your work at RH, I'd suggest filing a bug against Community -> Bugzilla -> WebService requesting an XMLRPC call for bug cloning. RH bugzilla guys are pretty responsive and active upstream so that's your best chance of getting it done quickly.
Thanks, Cole
python-bugzilla@lists.fedorahosted.org