1 # Copyright (C) 2008-2012 Chris Ball <cjb@laptop.org>
2 # Gianluca Montecchi <gian@grys.it>
3 # W. Trevor King <wking@tremily.us>
5 # This file is part of Bugs Everywhere.
7 # Bugs Everywhere is free software: you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by the Free
9 # Software Foundation, either version 2 of the License, or (at your option) any
12 # Bugs Everywhere is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 # You should have received a copy of the GNU General Public License along with
18 # Bugs Everywhere. If not, see <http://www.gnu.org/licenses/>.
25 import libbe.command.util
28 class Merge (libbe.command.Command):
29 """Merge duplicate bugs
32 >>> import libbe.bugdir
33 >>> import libbe.comment
34 >>> bd = libbe.bugdir.SimpleBugDir(memory=False)
35 >>> io = libbe.command.StringInputOutput()
36 >>> io.stdout = sys.stdout
37 >>> ui = libbe.command.UserInterface(io=io)
38 >>> ui.storage_callbacks.set_storage(bd.storage)
39 >>> cmd = Merge(ui=ui)
41 >>> a = bd.bug_from_uuid('a')
42 >>> a.comment_root.time = 0
43 >>> dummy = a.new_comment('Testing')
45 >>> dummy = dummy.new_reply('Testing...')
47 >>> b = bd.bug_from_uuid('b')
49 >>> b.comment_root.time = 0
50 >>> dummy = b.new_comment('1 2')
52 >>> dummy = dummy.new_reply('1 2 3 4')
55 >>> ret = ui.run(cmd, args=['/a', '/b'])
56 Merged bugs #abc/a# and #abc/b#
58 >>> a = bd.bug_from_uuid('a')
60 >>> a_comments = sorted([c for c in a.comments()],
61 ... cmp=libbe.comment.cmp_time)
62 >>> mergeA = a_comments[0]
64 >>> print a.string(show_comments=True)
65 ... # doctest: +ELLIPSIS, +REPORT_UDIFF
72 Creator : John Doe <jdoe@example.com>
75 --------- Comment ---------
81 --------- Comment ---------
87 --------- Comment ---------
92 Merged from bug #abc/b#
93 --------- Comment ---------
99 --------- Comment ---------
105 >>> b = bd.bug_from_uuid('b')
106 >>> b.load_comments()
107 >>> b_comments = sorted([c for c in b.comments()],
108 ... libbe.comment.cmp_time)
109 >>> mergeB = b_comments[0]
111 >>> print b.string(show_comments=True)
112 ... # doctest: +ELLIPSIS, +REPORT_UDIFF
119 Creator : Jane Doe <jdoe@example.com>
122 --------- Comment ---------
128 --------- Comment ---------
134 --------- Comment ---------
139 Merged into bug #abc/a#
147 def __init__(self, *args, **kwargs):
148 libbe.command.Command.__init__(self, *args, **kwargs)
150 libbe.command.Argument(
151 name='bug-id', metavar='BUG-ID', default=None,
152 completion_callback=libbe.command.util.complete_bug_id),
153 libbe.command.Argument(
154 name='bug-id-to-merge', metavar='BUG-ID', default=None,
155 completion_callback=libbe.command.util.complete_bug_id),
158 def _run(self, **params):
159 storage = self._get_storage()
160 bugdirs = self._get_bugdirs()
161 bugdirA,bugA,comment = (
162 libbe.command.util.bugdir_bug_comment_from_user_id(
163 bugdirs, params['bug-id']))
165 bugdirB,bugB,dummy_comment = (
166 libbe.command.util.bugdir_bug_comment_from_user_id(
167 bugdirs, params['bug-id-to-merge']))
169 mergeA = bugA.new_comment('Merged from bug #%s#' % bugB.id.long_user())
170 newCommTree = copy.deepcopy(bugB.comment_root)
171 for comment in newCommTree.traverse(): # all descendant comments
173 # uuids must be unique in storage
174 if comment.alt_id == None:
175 comment.storage = None
176 comment.alt_id = comment.uuid
177 comment.storage = storage
178 comment.uuid = libbe.util.id.uuid_gen()
179 comment.save() # force onto disk under bugA
181 for comment in newCommTree: # just the child comments
182 mergeA.add_reply(comment, allow_time_inversion=True)
183 bugB.new_comment('Merged into bug #%s#' % bugA.id.long_user())
184 bugB.status = 'closed'
185 print >> self.stdout, 'Merged bugs #%s# and #%s#' \
186 % (bugA.id.user(), bugB.id.user())
189 def _long_help(self):
191 The second bug (B) is merged into the first (A). This adds merge
192 comments to both bugs, closes B, and appends B's comment tree to A's