Merge lp:~ubuntuone-hackers/tarmac/trunk into lp:tarmac

Proposed by Jonathan Lange
Status: Rejected
Rejected by: dobey
Proposed branch: lp:~ubuntuone-hackers/tarmac/trunk
Merge into: lp:tarmac
Diff against target: 1069 lines (+532/-80) (has conflicts)
13 files modified
bin/tarmac (+3/-1)
docs/introduction.txt (+5/-0)
tarmac/bin/__init__.py (+1/-1)
tarmac/bin/commands.py (+311/-15)
tarmac/bin/options.py (+12/-3)
tarmac/bin/registry.py (+2/-2)
tarmac/branch.py (+111/-20)
tarmac/plugins/command.py (+4/-3)
tarmac/plugins/commitmessage.py (+10/-6)
tarmac/plugins/tests/test_commitmessage.py (+7/-2)
tarmac/tests/mock.py (+2/-0)
tarmac/tests/test_branch.py (+19/-14)
tarmac/tests/test_commands.py (+45/-13)
Text conflict in tarmac/bin/commands.py
Text conflict in tarmac/bin/options.py
Text conflict in tarmac/branch.py
To merge this branch: bzr merge lp:~ubuntuone-hackers/tarmac/trunk
Reviewer Review Type Date Requested Status
Paul Hummer Pending
Review via email: mp+140435@code.launchpad.net

Description of the change

WIP MP to make the delta visible.

To post a comment you must log in.
lp:~ubuntuone-hackers/tarmac/trunk updated
415. By Jonathan Lange

Fix the test failures in u1's tarmac fork

416. By Jonathan Lange

Oops. Really fix the tests.

417. By Jonathan Lange

Handle unicode output from tests. (~james-w)

418. By Jonathan Lange

Commit message plugin that sets review & bugs fixed (james-w)

419. By Jonathan Lange

Make the tests pass.

420. By Jonathan Lange

Merge James's branch to break up _do_merges, plus changes from my review.

421. By Jonathan Lange

Merge exit-status

422. By Jonathan Lange

Add "check" command.

423. By Jonathan Lange

Allow verify command to be specified on command line.

424. By Sidnei da Silva

- Fix to not turn 'proposals' into a single Entry object.

425. By James Westby

Also rename the other call to set_up.

426. By dobey

Remove the broken commit plug-in.

427. By Jonathan Lange

Better error message when private branches attack

428. By Sidnei da Silva

Use HTTPError directly to make it work in Lucid.

429. By James Westby

Merge trunk.

430. By James Westby

Allow the branch name to be used in the commit message template. (David Britton)

Unmerged revisions

431. By Vincent Ladeuil

Set the MP status to Merged after committing instead of waiting for lp to do so.

430. By James Westby

Allow the branch name to be used in the commit message template. (David Britton)

429. By James Westby

Merge trunk.

428. By Sidnei da Silva

Use HTTPError directly to make it work in Lucid.

427. By Jonathan Lange

Better error message when private branches attack

426. By dobey

Remove the broken commit plug-in.

425. By James Westby

Also rename the other call to set_up.

424. By Sidnei da Silva

- Fix to not turn 'proposals' into a single Entry object.

423. By Jonathan Lange

Allow verify command to be specified on command line.

422. By Jonathan Lange

Add "check" command.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bin/tarmac'
--- bin/tarmac 2010-06-17 17:23:37 +0000
+++ bin/tarmac 2013-03-13 16:57:22 +0000
@@ -2,5 +2,7 @@
2# vim:filetype=python2# vim:filetype=python
3'''Main tarmac script.'''3'''Main tarmac script.'''
44
5import sys
6
5from tarmac.bin import main7from tarmac.bin import main
6main()8sys.exit(main())
79
=== modified file 'docs/introduction.txt'
--- docs/introduction.txt 2012-06-25 21:05:28 +0000
+++ docs/introduction.txt 2013-03-13 16:57:22 +0000
@@ -151,6 +151,11 @@
151**reviewer**151**reviewer**
152 The display name of the merge proposal reviewer.152 The display name of the merge proposal reviewer.
153153
154**branch_name**
155 The short branch name. i.e.: branch_name in "lp:~user/project/branch_name"
156
157**\n**
158 A \n in the commit message template will be rendered as a newline character.
154159
155Command160Command
156=======161=======
157162
=== modified file 'tarmac/bin/__init__.py'
--- tarmac/bin/__init__.py 2010-09-02 15:18:07 +0000
+++ tarmac/bin/__init__.py 2013-03-13 16:57:22 +0000
@@ -27,4 +27,4 @@
27 args = sys.argv[1:]27 args = sys.argv[1:]
28 if not args:28 if not args:
29 args = ['help']29 args = ['help']
30 registry.run(args)30 return registry.run(args)
3131
=== modified file 'tarmac/bin/commands.py'
--- tarmac/bin/commands.py 2013-01-31 20:03:27 +0000
+++ tarmac/bin/commands.py 2013-03-13 16:57:22 +0000
@@ -10,6 +10,7 @@
10from launchpadlib.launchpad import Launchpad10from launchpadlib.launchpad import Launchpad
11from launchpadlib.uris import (LPNET_SERVICE_ROOT,11from launchpadlib.uris import (LPNET_SERVICE_ROOT,
12 STAGING_SERVICE_ROOT)12 STAGING_SERVICE_ROOT)
13from lazr.restfulclient.errors import HTTPError
1314
14from tarmac.bin import options15from tarmac.bin import options
15from tarmac.branch import Branch16from tarmac.branch import Branch
@@ -134,6 +135,237 @@
134 help_commands(self.outf)135 help_commands(self.outf)
135136
136137
138def _get_login_name(lp):
139 """Return the name of the user `lp` is logged in as.
140
141 `None` if `lp` is an anonymous connection.
142 """
143 try:
144 me = lp.me
145 except HTTPError, e:
146 # XXX Newer lazr.restfulclient has a proper Unauthorized exception, but
147 # the version in Lucid does not.
148 if e.status == 401:
149 return None
150 raise
151 if me:
152 return me.name
153 return None
154
155
156def _get_mergable_proposals_for_branch(lp_branch, logger, imply_commit_message=False):
157 """Return a list of the mergable proposals for the given branch."""
158 proposals = []
159 for entry in lp_branch.landing_candidates:
160 logger.debug("Considering merge proposal: {0}".format(entry.web_link))
161
162 if entry.queue_status != u'Approved':
163 logger.debug(
164 " Skipping proposal: status is {0}, not "
165 "'Approved'".format(entry.queue_status))
166 continue
167
168 if (not imply_commit_message and not entry.commit_message):
169 logger.debug(
170 " Skipping proposal: proposal has no commit message")
171 continue
172
173 proposals.append(entry)
174 return proposals
175
176
177def _get_branch(branch_url, launchpad, logger):
178 lp_branch = launchpad.branches.getByUrl(url=branch_url)
179 if lp_branch is None:
180 logger.info(
181 'User {0} could not find {1} branch on Launchpad'.format(
182 _get_login_name(launchpad), branch_url))
183 return lp_branch
184
185
186def _get_branch_and_mps(branch_url, launchpad, logger,
187 imply_commit_message=False):
188 """Get branch and merge proposals from Launchpad.
189
190 :param branch_url: The Launchpad URL of the branch. e.g `lp:foo`.
191 :param launchpad: A Launchpad API object.
192 :param logger: A Python logger.
193 :param imply_commit_message: Whether to make up a commit message
194 if the merge proposal lacks an explicit one. Defaults to False.
195 :return: `(lp_branch, [mergable_mp, ...])`
196 """
197 lp_branch = _get_branch(branch_url, launchpad, logger)
198 proposals = []
199
200 if lp_branch:
201 proposals = _get_mergable_proposals_for_branch(
202 lp_branch, logger,
203 imply_commit_message=imply_commit_message)
204
205 if not proposals:
206 logger.info(
207 'No approved proposals found for %(branch_url)s' % {
208 'branch_url': branch_url})
209
210 return lp_branch, proposals
211
212
213
214def _get_reviews(proposal):
215 """Get the set of reviews from the proposal."""
216 votes = [vote for vote in proposal.votes if vote.comment]
217 if not votes:
218 return None
219 return [
220 '%s;%s' % (vote.reviewer.display_name, vote.comment.vote)
221 for vote in votes]
222
223
224def set_up(logger, debug=False, http_debug=False):
225 if debug:
226 set_up_debug_logging()
227 logger.debug('Debug logging enabled')
228 if http_debug:
229 httplib2.debuglevel = 1
230 logger.debug('HTTP debugging enabled.')
231 logger.debug('Loading plugins')
232 load_plugins()
233 logger.debug('Plugins loaded')
234
235
236def merge_proposals(target, proposals, logger, config, command):
237 logger.debug('Firing tarmac_pre_merge hook')
238 tarmac_hooks.fire('tarmac_pre_merge',
239 command, target)
240 try:
241 statuses = [
242 merge_proposal(target, proposal, logger, config, command)
243 for proposal in proposals]
244 logger.debug('Firing tarmac_post_merge hook')
245 tarmac_hooks.fire('tarmac_post_merge',
246 command, target, success_count=sum(statuses))
247 finally:
248 target.cleanup()
249 return statuses
250
251
252def merge_proposal(target, proposal, logger, config, command):
253 target.cleanup()
254 logger.debug(
255 u'Preparing to merge %(source_branch)s' % {
256 'source_branch': proposal.source_branch.web_link})
257 try:
258 prerequisite = proposal.prerequisite_branch
259 if prerequisite:
260 merges = [x for x in prerequisite.landing_targets
261 if x.target_branch == target.lp_branch and
262 x.queue_status != u'Superseded']
263 if len(merges) == 0:
264 raise TarmacMergeError(
265 u'No proposals of prerequisite branch.',
266 u'No proposals found for merge of %s '
267 u'into %s.' % (
268 prerequisite.web_link,
269 target.lp_branch.web_link))
270 elif len(merges) > 1:
271 raise TarmacMergeError(
272 u'Too many proposals of prerequisite.',
273 u'More than one proposal found for merge '
274 u'of %s into %s, which is not Superseded.' % (
275 prerequisite.web_link,
276 target.lp_branch.web_link))
277 elif len(merges) == 1:
278 if merges[0].queue_status != u'Merged':
279 raise TarmacMergeError(
280 u'Prerequisite not yet merged.',
281 u'The prerequisite %s has not yet been '
282 u'merged into %s.' % (
283 prerequisite.web_link,
284 target.lp_branch.web_link))
285
286 if not proposal.reviewed_revid:
287 raise TarmacMergeError(
288 u'No approved revision specified.')
289
290
291 source = Branch.create(
292 proposal.source_branch, config, target=target)
293
294 source_bzr_branch = source.get_bzr_branch()
295 approved = source_bzr_branch.revision_id_to_revno(
296 str(proposal.reviewed_revid))
297 tip = source_bzr_branch.revno()
298
299 if tip > approved:
300 message = u'Unapproved changes made after approval'
301 lp_comment = (
302 u'There are additional revisions which have not '
303 u'been approved in review. Please seek review and '
304 u'approval of these new revisions.')
305 raise UnapprovedChanges(message, lp_comment)
306
307 logger.debug(
308 'Merging %(source)s at revision %(revision)s' % {
309 'source': proposal.source_branch.web_link,
310 'revision': proposal.reviewed_revid})
311
312 target.merge(source, str(proposal.reviewed_revid))
313
314 logger.debug('Firing tarmac_pre_commit hook')
315 tarmac_hooks.fire('tarmac_pre_commit',
316 command, target, source, proposal)
317
318 except TarmacMergeError, failure:
319 logger.warn(
320 u'Merging %(source)s into %(target)s failed: %(msg)s' %
321 {'source': proposal.source_branch.web_link,
322 'target': proposal.target_branch.web_link,
323 'msg': str(failure)})
324
325 subject = u'Re: [Merge] %(source)s into %(target)s' % {
326 "source": proposal.source_branch.display_name,
327 "target": proposal.target_branch.display_name}
328
329 if failure.comment:
330 comment = failure.comment
331 else:
332 comment = str(failure)
333
334 proposal.createComment(subject=subject, content=comment)
335 try:
336 proposal.setStatus(
337 status=config.rejected_branch_status)
338 except AttributeError:
339 proposal.setStatus(status=u'Needs review')
340 proposal.lp_save()
341 return False
342
343 except PointlessMerge:
344 logger.warn(
345 'Merging %(source)s into %(target)s would be '
346 'pointless.' % {
347 'source': proposal.source_branch.web_link,
348 'target': proposal.target_branch.web_link})
349 return False
350
351 merge_url = get_review_url(proposal)
352 revprops = {'merge_url': merge_url}
353
354 commit_message = proposal.commit_message
355 if commit_message is None and config.imply_commit_message:
356 commit_message = proposal.description
357
358 target.commit(commit_message,
359 revprops=revprops,
360 authors=source.authors,
361 reviews=_get_reviews(proposal))
362
363 logger.debug('Firing tarmac_post_commit hook')
364 tarmac_hooks.fire('tarmac_post_commit',
365 command, target, source, proposal)
366 return True
367
368
137class cmd_merge(TarmacCommand):369class cmd_merge(TarmacCommand):
138 '''Automatically merge approved merge proposal branches.'''370 '''Automatically merge approved merge proposal branches.'''
139371
@@ -142,6 +374,7 @@
142 takes_options = [374 takes_options = [
143 options.http_debug_option,375 options.http_debug_option,
144 options.debug_option,376 options.debug_option,
377<<<<<<< TREE
145 options.imply_commit_message_option,378 options.imply_commit_message_option,
146 options.one_option]379 options.one_option]
147380
@@ -153,14 +386,26 @@
153 return386 return
154387
155 proposals = self._get_mergable_proposals_for_branch(lp_branch)388 proposals = self._get_mergable_proposals_for_branch(lp_branch)
389=======
390 options.imply_commit_message_option,
391 options.one_option,
392 options.verify_command_option,
393 ]
394
395 def _do_merges(self, branch_url, verify_command=None):
396 lp_branch, proposals = _get_branch_and_mps(
397 branch_url, self.launchpad, self.logger,
398 self.config.imply_commit_message)
399>>>>>>> MERGE-SOURCE
156400
157 if not proposals:401 if not proposals:
158 self.logger.info(402 return []
159 'No approved proposals found for %(branch_url)s' % {403
160 'branch_url': branch_url})404 if self.config.one:
161 return405 proposals = [proposals[0]]
162406
163 target = Branch.create(lp_branch, self.config, create_tree=True)407 target = Branch.create(lp_branch, self.config, create_tree=True)
408<<<<<<< TREE
164409
165 self.logger.debug('Firing tarmac_pre_merge hook')410 self.logger.debug('Firing tarmac_pre_merge hook')
166 tarmac_hooks.fire('tarmac_pre_merge',411 tarmac_hooks.fire('tarmac_pre_merge',
@@ -337,18 +582,19 @@
337 return reviews582 return reviews
338583
339 def run(self, branch_url=None, launchpad=None, **kwargs):584 def run(self, branch_url=None, launchpad=None, **kwargs):
585=======
586 if verify_command is not None:
587 setattr(target.config, 'verify_command', verify_command)
588 statuses = merge_proposals(target, proposals, self.logger, self.config, self)
589 return statuses
590
591 def run(self, branch_url=None, launchpad=None, verify_command=None, **kwargs):
592>>>>>>> MERGE-SOURCE
340 for key, value in kwargs.iteritems():593 for key, value in kwargs.iteritems():
341 self.config.set('Tarmac', key, value)594 self.config.set('Tarmac', key, value)
342595
343 if self.config.debug:596 set_up(self.logger, debug=self.config.debug,
344 set_up_debug_logging()597 http_debug=self.config.http_debug)
345 self.logger.debug('Debug logging enabled')
346 if self.config.http_debug:
347 httplib2.debuglevel = 1
348 self.logger.debug('HTTP debugging enabled.')
349 self.logger.debug('Loading plugins')
350 load_plugins()
351 self.logger.debug('Plugins loaded')
352598
353 self.launchpad = launchpad599 self.launchpad = launchpad
354 if self.launchpad is None:600 if self.launchpad is None:
@@ -356,19 +602,21 @@
356 self.launchpad = self.get_launchpad_object()602 self.launchpad = self.get_launchpad_object()
357 self.logger.debug('launchpad object loaded')603 self.logger.debug('launchpad object loaded')
358604
605 statuses = []
606
359 if branch_url:607 if branch_url:
360 self.logger.debug('%(branch_url)s specified as branch_url' % {608 self.logger.debug('%(branch_url)s specified as branch_url' % {
361 'branch_url': branch_url})609 'branch_url': branch_url})
362 if not branch_url.startswith('lp:'):610 if not branch_url.startswith('lp:'):
363 raise TarmacCommandError('Branch urls must start with lp:')611 raise TarmacCommandError('Branch urls must start with lp:')
364 self._do_merges(branch_url)612 statuses.extend(self._do_merges(branch_url, verify_command=verify_command))
365
366 else:613 else:
367 for branch in self.config.branches:614 for branch in self.config.branches:
368 self.logger.debug(615 self.logger.debug(
369 'Merging approved branches against %(branch)s' % {616 'Merging approved branches against %(branch)s' % {
370 'branch': branch})617 'branch': branch})
371 try:618 try:
619<<<<<<< TREE
372 merged = self._do_merges(branch)620 merged = self._do_merges(branch)
373621
374 # If we've been asked to only merge one branch, then exit.622 # If we've been asked to only merge one branch, then exit.
@@ -376,8 +624,56 @@
376 break624 break
377 except LockContention:625 except LockContention:
378 continue626 continue
627=======
628 statuses.extend(self._do_merges(branch, verify_command=verify_command))
629
630 # If we've been asked to only merge one branch, then exit.
631 if statuses and self.config.one:
632 break
633 except LockContention:
634 continue
635>>>>>>> MERGE-SOURCE
379 except Exception, error:636 except Exception, error:
380 self.logger.error(637 self.logger.error(
381 'An error occurred trying to merge %s: %s',638 'An error occurred trying to merge %s: %s',
382 branch, error)639 branch, error)
383 raise640 raise
641 if not all(statuses):
642 return 2
643 return 0
644
645
646class cmd_check(TarmacCommand):
647 '''Check whether there are any merge proposals ready to land.'''
648
649 takes_args = ['branch_url']
650 takes_options = [
651 options.http_debug_option,
652 options.debug_option]
653
654 def _any_merges(self, branch_url):
655 lp_branch, proposals = _get_branch_and_mps(
656 branch_url, self.launchpad, self.logger)
657 return bool(proposals)
658
659 def run(self, branch_url, launchpad=None, **kwargs):
660 for key, value in kwargs.iteritems():
661 self.config.set('Tarmac', key, value)
662
663 set_up(self.logger, debug=self.config.debug,
664 http_debug=self.config.http_debug)
665
666 self.launchpad = launchpad
667 if self.launchpad is None:
668 self.logger.debug('Loading launchpad object')
669 self.launchpad = self.get_launchpad_object()
670 self.logger.debug('launchpad object loaded')
671
672 self.logger.debug('%(branch_url)s specified as branch_url' % {
673 'branch_url': branch_url})
674 if not branch_url.startswith('lp:'):
675 raise TarmacCommandError('Branch urls must start with lp:')
676 ret = self._any_merges(branch_url)
677 if ret:
678 return 0
679 return 1
384680
=== modified file 'tarmac/bin/options.py'
--- tarmac/bin/options.py 2012-05-26 04:14:45 +0000
+++ tarmac/bin/options.py 2013-03-13 16:57:22 +0000
@@ -15,6 +15,15 @@
15 'imply-commit-message',15 'imply-commit-message',
16 help=("Use the description as a commit message if the branch "16 help=("Use the description as a commit message if the branch "
17 "doesn't have a message"))17 "doesn't have a message"))
18one_option = Option(18<<<<<<< TREE
19 'one', short_name='1',19one_option = Option(
20 help='Merge only one branch and exit.')20 'one', short_name='1',
21 help='Merge only one branch and exit.')
22=======
23one_option = Option(
24 'one', short_name='1',
25 help='Merge only one branch and exit.')
26verify_command_option = Option(
27 'verify-command', type=str,
28 help='The verify command to run.')
29>>>>>>> MERGE-SOURCE
2130
=== modified file 'tarmac/bin/registry.py'
--- tarmac/bin/registry.py 2010-10-25 20:20:18 +0000
+++ tarmac/bin/registry.py 2013-03-13 16:57:22 +0000
@@ -45,7 +45,7 @@
4545
46 def _run(self, args):46 def _run(self, args):
47 '''Execute the command.'''47 '''Execute the command.'''
48 run_bzr(args)48 return run_bzr(args)
4949
50 def install_hooks(self):50 def install_hooks(self):
51 '''Use the bzrlib Command support for running commands.'''51 '''Use the bzrlib Command support for running commands.'''
@@ -57,7 +57,7 @@
57 def run(self, args):57 def run(self, args):
58 '''Execute the command.'''58 '''Execute the command.'''
59 try:59 try:
60 self._run(args)60 return self._run(args)
61 except BzrCommandError, e:61 except BzrCommandError, e:
62 sys.exit('tarmac: ERROR: ' + str(e))62 sys.exit('tarmac: ERROR: ' + str(e))
6363
6464
=== modified file 'tarmac/branch.py'
--- tarmac/branch.py 2013-02-04 21:07:51 +0000
+++ tarmac/branch.py 2013-03-13 16:57:22 +0000
@@ -37,7 +37,6 @@
3737
38 def __init__(self, lp_branch, config=False, target=None):38 def __init__(self, lp_branch, config=False, target=None):
39 self.lp_branch = lp_branch39 self.lp_branch = lp_branch
40 self.bzr_branch = bzr_branch.Branch.open(self.lp_branch.bzr_identity)
41 if config:40 if config:
42 self.config = BranchConfig(lp_branch.bzr_identity, config)41 self.config = BranchConfig(lp_branch.bzr_identity, config)
43 else:42 else:
@@ -45,15 +44,27 @@
4544
46 self.target = target45 self.target = target
47 self.logger = logging.getLogger('tarmac')46 self.logger = logging.getLogger('tarmac')
47 self.temp_tree_dir = None
48
49 def get_bzr_branch(self):
50 return bzr_branch.Branch.open(self.lp_branch.bzr_identity)
51
52 # For backwards compatibility
53 bzr_branch = property(get_bzr_branch)
54
55 def get_tree(self):
56 if self.temp_tree_dir is not None:
57 return WorkingTree.open(self.temp_tree_dir)
58 if os.path.exists(self.config.tree_dir):
59 return WorkingTree.open(self.config.tree_dir)
60
61 # For backwards compatibility
62 tree = property(get_tree)
4863
49 def __del__(self):64 def __del__(self):
50 """Do some potenetially necessary cleanup during deletion."""65 """Do some potenetially necessary cleanup during deletion."""
51 try:66 if self.temp_tree_dir is not None:
52 # If we were using a temp directory, then remove it
53 shutil.rmtree(self.temp_tree_dir)67 shutil.rmtree(self.temp_tree_dir)
54 except AttributeError:
55 # Not using a tempdir
56 pass
5768
58 @classmethod69 @classmethod
59 def create(cls, lp_branch, config, create_tree=False, target=None):70 def create(cls, lp_branch, config, create_tree=False, target=None):
@@ -62,12 +73,25 @@
62 clazz.create_tree()73 clazz.create_tree()
63 return clazz74 return clazz
6475
76
65 def create_tree(self):77 def create_tree(self):
66 '''Create the dir and working tree.'''78 '''Create the dir and working tree.'''
79 bzr_branch = self.get_bzr_branch()
67 try:80 try:
81 tree = self.get_tree()
82 if tree is None:
83 self.logger.debug('Tree does not exist. Creating dir')
84 # Create the path up to but not including tree_dir if it does
85 # not exist.
86 parent_dir = os.path.dirname(self.config.tree_dir)
87 if not os.path.exists(parent_dir):
88 os.makedirs(parent_dir)
89 tree = bzr_branch.create_checkout(
90 self.config.tree_dir, lightweight=False)
68 self.logger.debug(91 self.logger.debug(
69 'Using tree in %(tree_dir)s' % {92 'Using tree in %(tree_dir)s' % {
70 'tree_dir': self.config.tree_dir})93 'tree_dir': self.config.tree_dir})
94<<<<<<< TREE
71 if os.path.exists(self.config.tree_dir):95 if os.path.exists(self.config.tree_dir):
72 self.tree = WorkingTree.open(self.config.tree_dir)96 self.tree = WorkingTree.open(self.config.tree_dir)
73 else:97 else:
@@ -79,33 +103,43 @@
79 os.makedirs(parent_dir)103 os.makedirs(parent_dir)
80 self.tree = self.bzr_branch.create_checkout(104 self.tree = self.bzr_branch.create_checkout(
81 self.config.tree_dir, lightweight=True)105 self.config.tree_dir, lightweight=True)
106=======
107>>>>>>> MERGE-SOURCE
82 except AttributeError:108 except AttributeError:
83 # Store this so we can rmtree later109 # Store this so we can rmtree later
84 self.temp_tree_dir = tempfile.mkdtemp()110 self.temp_tree_dir = tempfile.mkdtemp()
85 self.logger.debug(111 self.logger.debug(
86 'Using temp dir at %(tree_dir)s' % {112 'Using temp dir at %(tree_dir)s' % {
87 'tree_dir': self.temp_tree_dir})113 'tree_dir': self.temp_tree_dir})
88 self.tree = self.bzr_branch.create_checkout(self.temp_tree_dir)114 tree = bzr_branch.create_checkout(self.temp_tree_dir)
89115
90 self.cleanup()116 self.cleanup()
91117
92 def cleanup(self):118 def cleanup(self):
93 '''Remove the working tree from the temp dir.'''119 '''Remove the working tree from the temp dir.'''
94 assert self.tree120 tree = self.get_tree()
95 self.tree.revert()121 assert tree
96 for filename in [self.tree.abspath(f) for f in self.unmanaged_files]:122 self.logger.info("Running cleanup in %s." % (
123 self.lp_branch.bzr_identity))
124 tree.revert()
125 self.logger.info("Reverted changes in %s." % (
126 self.lp_branch.bzr_identity))
127 for filename in [tree.abspath(f) for f in self.unmanaged_files]:
97 if os.path.isdir(filename) and not os.path.islink(filename):128 if os.path.isdir(filename) and not os.path.islink(filename):
98 shutil.rmtree(filename)129 shutil.rmtree(filename)
99 else:130 else:
100 os.remove(filename)131 os.remove(filename)
101132
102 self.tree.update()133 self.logger.info("Successfully removed extra files from %s." % (
134 self.lp_branch.bzr_identity))
135 tree.update()
103136
104 def merge(self, branch, revid=None):137 def merge(self, branch, revid=None):
105 '''Merge from another tarmac.branch.Branch instance.'''138 '''Merge from another tarmac.branch.Branch instance.'''
106 assert self.tree139 tree = self.get_tree()
107 conflict_list = self.tree.merge_from_branch(140 assert tree
108 branch.bzr_branch, to_revision=revid)141 conflict_list = tree.merge_from_branch(
142 branch.get_bzr_branch(), to_revision=revid)
109 if conflict_list:143 if conflict_list:
110 message = u'Conflicts merging branch.'144 message = u'Conflicts merging branch.'
111 lp_comment = (145 lp_comment = (
@@ -118,6 +152,7 @@
118 @property152 @property
119 def unmanaged_files(self):153 def unmanaged_files(self):
120 """Get the list of ignored and unknown files in the tree."""154 """Get the list of ignored and unknown files in the tree."""
155<<<<<<< TREE
121 unmanaged = []156 unmanaged = []
122 try:157 try:
123 self.tree.lock_read()158 self.tree.lock_read()
@@ -125,20 +160,31 @@
125 unmanaged.extend([x[0] for x in self.tree.ignored_files()])160 unmanaged.extend([x[0] for x in self.tree.ignored_files()])
126 finally:161 finally:
127 self.tree.unlock()162 self.tree.unlock()
163=======
164 tree = self.get_tree()
165 assert tree
166 tree.lock_read()
167 unmanaged = [x for x in tree.unknowns()]
168 unmanaged.extend([x[0] for x in tree.ignored_files()])
169 tree.unlock()
170>>>>>>> MERGE-SOURCE
128 return unmanaged171 return unmanaged
129172
130 @property173 @property
131 def conflicts(self):174 def conflicts(self):
132 '''Print the conflicts.'''175 '''Print the conflicts.'''
133 assert self.tree.conflicts()176 tree = self.get_tree()
177 assert tree
134 conflicts = []178 conflicts = []
135 for conflict in self.tree.conflicts():179 for conflict in tree.conflicts():
136 conflicts.append(180 conflicts.append(
137 u'%s in %s' % (conflict.typestring, conflict.path))181 u'%s in %s' % (conflict.typestring, conflict.path))
138 return '\n'.join(conflicts)182 return '\n'.join(conflicts)
139183
140 def commit(self, commit_message, revprops=None, **kwargs):184 def commit(self, commit_message, revprops=None, **kwargs):
141 '''Commit changes.'''185 '''Commit changes.'''
186 tree = self.get_tree()
187 assert tree
142 if not revprops:188 if not revprops:
143 revprops = {}189 revprops = {}
144190
@@ -155,8 +201,8 @@
155 'review identity or vote.')201 'review identity or vote.')
156 revprops['reviews'] = '\n'.join(reviews)202 revprops['reviews'] = '\n'.join(reviews)
157203
158 self.tree.commit(commit_message, committer='Tarmac',204 tree.commit(commit_message, committer='Tarmac',
159 revprops=revprops, authors=authors)205 revprops=revprops, authors=authors)
160206
161 @property207 @property
162 def landing_candidates(self):208 def landing_candidates(self):
@@ -167,7 +213,9 @@
167 def authors(self):213 def authors(self):
168 author_list = []214 author_list = []
169215
216 bzr_branch = self.get_bzr_branch()
170 if self.target:217 if self.target:
218<<<<<<< TREE
171 try:219 try:
172 self.bzr_branch.lock_read()220 self.bzr_branch.lock_read()
173 self.target.bzr_branch.lock_read()221 self.target.bzr_branch.lock_read()
@@ -190,10 +238,33 @@
190 finally:238 finally:
191 self.target.bzr_branch.unlock()239 self.target.bzr_branch.unlock()
192 self.bzr_branch.unlock()240 self.bzr_branch.unlock()
241=======
242 target_bzr_branch = self.target.get_bzr_branch()
243 bzr_branch.lock_read()
244 target_bzr_branch.lock_read()
245
246 graph = bzr_branch.repository.get_graph(
247 target_bzr_branch.repository)
248
249 unique_ids = graph.find_unique_ancestors(
250 bzr_branch.last_revision(),
251 [target_bzr_branch.last_revision()])
252
253 revs = bzr_branch.repository.get_revisions(unique_ids)
254 for rev in revs:
255 apparent_authors = rev.get_apparent_authors()
256 for author in apparent_authors:
257 author.replace('\n', '')
258 if author not in author_list:
259 author_list.append(author)
260
261 target_bzr_branch.unlock()
262 bzr_branch.unlock()
263>>>>>>> MERGE-SOURCE
193 else:264 else:
194 last_rev = self.bzr_branch.last_revision()265 last_rev = bzr_branch.last_revision()
195 if last_rev != 'null:':266 if last_rev != 'null:':
196 rev = self.bzr_branch.repository.get_revision(last_rev)267 rev = bzr_branch.repository.get_revision(last_rev)
197 apparent_authors = rev.get_apparent_authors()268 apparent_authors = rev.get_apparent_authors()
198 author_list.extend(269 author_list.extend(
199 [a.replace('\n', '') for a in apparent_authors])270 [a.replace('\n', '') for a in apparent_authors])
@@ -205,6 +276,7 @@
205 """Return the list of bugs fixed by the branch."""276 """Return the list of bugs fixed by the branch."""
206 bugs_list = []277 bugs_list = []
207278
279<<<<<<< TREE
208 try:280 try:
209 self.bzr_branch.lock_read()281 self.bzr_branch.lock_read()
210 oldrevid = self.bzr_branch.get_rev_id(self.lp_branch.revision_count)282 oldrevid = self.bzr_branch.get_rev_id(self.lp_branch.revision_count)
@@ -218,7 +290,26 @@
218 'https://launchpad.net/bugs/', ''))290 'https://launchpad.net/bugs/', ''))
219 except NoSuchRevision:291 except NoSuchRevision:
220 continue292 continue
293=======
294 bzr_branch = self.get_bzr_branch()
295 bzr_branch.lock_read()
296 oldrevid = bzr_branch.get_rev_id(self.lp_branch.revision_count)
297 for rev_info in bzr_branch.iter_merge_sorted_revisions(
298 stop_revision_id=oldrevid):
299 try:
300 rev = bzr_branch.repository.get_revision(rev_info[0])
301 for bug in rev.iter_bugs():
302 if bug[0].startswith('https://launchpad.net/bugs/'):
303 bugs_list.append(bug[0].replace(
304 'https://launchpad.net/bugs/', ''))
305 except NoSuchRevision:
306 continue
307>>>>>>> MERGE-SOURCE
221308
309<<<<<<< TREE
222 finally:310 finally:
223 self.bzr_branch.unlock()311 self.bzr_branch.unlock()
312=======
313 bzr_branch.unlock()
314>>>>>>> MERGE-SOURCE
224 return bugs_list315 return bugs_list
225316
=== modified file 'tarmac/plugins/command.py'
--- tarmac/plugins/command.py 2011-09-02 04:06:25 +0000
+++ tarmac/plugins/command.py 2013-03-13 16:57:22 +0000
@@ -103,7 +103,8 @@
103 shell=True,103 shell=True,
104 stdin=subprocess.PIPE,104 stdin=subprocess.PIPE,
105 stdout=subprocess.PIPE,105 stdout=subprocess.PIPE,
106 stderr=subprocess.PIPE)106 stderr=subprocess.PIPE,
107 preexec_fn=os.setsid)
107 proc.stdin.close()108 proc.stdin.close()
108 stdout = tempfile.TemporaryFile()109 stdout = tempfile.TemporaryFile()
109 stderr = tempfile.TemporaryFile()110 stderr = tempfile.TemporaryFile()
@@ -125,7 +126,7 @@
125 killem(proc.pid, signal.SIGTERM)126 killem(proc.pid, signal.SIGTERM)
126 time.sleep(5)127 time.sleep(5)
127128
128 if proc.poll() is not None:129 if proc.poll() is None:
129 self.logger.debug("SIGTERM did not work. Sending SIGKILL.")130 self.logger.debug("SIGTERM did not work. Sending SIGKILL.")
130 killem(proc.pid, signal.SIGKILL)131 killem(proc.pid, signal.SIGKILL)
131132
@@ -184,7 +185,7 @@
184 u'%(output)s') % {185 u'%(output)s') % {
185 'source': self.proposal.source_branch.display_name,186 'source': self.proposal.source_branch.display_name,
186 'target': self.proposal.target_branch.display_name,187 'target': self.proposal.target_branch.display_name,
187 'output': u'\n'.join([stdout_value, stderr_value]),188 'output': u'\n'.join([stdout_value.decode('utf-8', 'ignore'), stderr_value.decode('utf-8', 'ignore')]),
188 }189 }
189 raise VerifyCommandFailed(message, comment)190 raise VerifyCommandFailed(message, comment)
190191
191192
=== modified file 'tarmac/plugins/commitmessage.py'
--- tarmac/plugins/commitmessage.py 2010-10-25 21:27:39 +0000
+++ tarmac/plugins/commitmessage.py 2013-03-13 16:57:22 +0000
@@ -30,18 +30,17 @@
3030
31 def run(self, command, target, source, proposal):31 def run(self, command, target, source, proposal):
32 # pylint: disable-msg=W061332 # pylint: disable-msg=W0613
33
34 try:33 try:
35 template = target.config.commit_message_template34 proposal.commit_message = self.render(
36 template = template.replace('<', '%(').replace('>', ')s')35 target.config.commit_message_template,
36 CommitMessageTemplateInfo(proposal))
37 except AttributeError:37 except AttributeError:
38 return38 return
3939
40 proposal.commit_message = self.render(
41 template, CommitMessageTemplateInfo(proposal))
42
43 def render(self, template, info):40 def render(self, template, info):
44 """Render a template using the given information."""41 """Render a template using the given information."""
42 template = template.replace('<', '%(').replace('>', ')s')
43 template = template.replace('\\n', '\n')
45 return template % info44 return template % info
4645
4746
@@ -77,6 +76,11 @@
77 return self._proposal.commit_message76 return self._proposal.commit_message
7877
79 @property78 @property
79 def branch_name(self):
80 """The branch name under review."""
81 return self._proposal.source_branch.name
82
83 @property
80 def reviewer(self):84 def reviewer(self):
81 """The display name of the merge proposal reviewer.85 """The display name of the merge proposal reviewer.
8286
8387
=== modified file 'tarmac/plugins/tests/test_commitmessage.py'
--- tarmac/plugins/tests/test_commitmessage.py 2010-10-25 21:27:39 +0000
+++ tarmac/plugins/tests/test_commitmessage.py 2013-03-13 16:57:22 +0000
@@ -12,6 +12,7 @@
12 super(TestCommitMessageTemplateInfo, self).setUp()12 super(TestCommitMessageTemplateInfo, self).setUp()
13 self.proposal = Thing(13 self.proposal = Thing(
14 source_branch=Thing(14 source_branch=Thing(
15 name="name",
15 owner=Thing(display_name="Arthur Author", name="arthur"),16 owner=Thing(display_name="Arthur Author", name="arthur"),
16 linked_bugs=[Thing(id=1234), Thing(id=5678)]),17 linked_bugs=[Thing(id=1234), Thing(id=5678)]),
17 commit_message="Awesome",18 commit_message="Awesome",
@@ -83,8 +84,8 @@
83 return "{info:%s}" % name84 return "{info:%s}" % name
8485
8586
86class TestCommitMessageTemplate(TarmacTestCase):87class TestCommitMessageTemplate(TestCommitMessageTemplateInfo):
8788
88 def test_render(self):89 def test_render(self):
89 message_template = CommitMessageTemplate()90 message_template = CommitMessageTemplate()
90 message_info = FakeCommitMessageTemplateInfo()91 message_info = FakeCommitMessageTemplateInfo()
@@ -99,3 +100,7 @@
99 self.assertEqual(100 self.assertEqual(
100 "{info:author} {info:reviewer}",101 "{info:author} {info:reviewer}",
101 render("%(author)s %(reviewer)s", message_info))102 render("%(author)s %(reviewer)s", message_info))
103 self.assertEqual(
104 "{info:author} {info:branch_name} {info:reviewer}",
105 render("<author> <branch_name> <reviewer>", message_info))
106 self.assertEqual("one\ntwo", render("one\\ntwo", message_info))
102107
=== modified file 'tarmac/tests/mock.py'
--- tarmac/tests/mock.py 2010-11-19 18:11:56 +0000
+++ tarmac/tests/mock.py 2013-03-13 16:57:22 +0000
@@ -50,6 +50,8 @@
50 self.revision_count = 050 self.revision_count = 0
51 self.bzr_identity = 'lp:%s' % os.path.basename(self.tree_dir)51 self.bzr_identity = 'lp:%s' % os.path.basename(self.tree_dir)
52 self.project = MockLPProject()52 self.project = MockLPProject()
53 self.web_link = 'http://code.launchpad.net/+branch/%s' % (
54 os.path.basename(self.tree_dir),)
5355
5456
55class cmd_mock(TarmacCommand):57class cmd_mock(TarmacCommand):
5658
=== modified file 'tarmac/tests/test_branch.py'
--- tarmac/tests/test_branch.py 2012-06-29 20:03:55 +0000
+++ tarmac/tests/test_branch.py 2013-03-13 16:57:22 +0000
@@ -38,7 +38,25 @@
38 a_branch = branch.Branch.create(MockLPBranch(tree_dir), self.config)38 a_branch = branch.Branch.create(MockLPBranch(tree_dir), self.config)
39 self.assertTrue(isinstance(a_branch, branch.Branch))39 self.assertTrue(isinstance(a_branch, branch.Branch))
40 self.assertTrue(a_branch.lp_branch.bzr_identity is not None)40 self.assertTrue(a_branch.lp_branch.bzr_identity is not None)
41 self.assertFalse(hasattr(a_branch, 'tree'))41 self.remove_branch_config(tree_dir)
42
43 def test_create_missing_parent_dir(self):
44 '''Test the creation of a TarmacBranch instance in a path that does
45 not fully exist, with a tree'''
46 branch_name = 'test_branch'
47 parent_dir = os.path.join(self.TEST_ROOT, 'missing')
48 tree_dir = os.path.join(parent_dir, branch_name)
49 self.add_branch_config(tree_dir)
50 # Create the mock somewhere other than where the tarmac branch will be
51 # located. Keep it right under TEST_ROOT so the
52 # TarmacDirectoryFactory mocking will work.
53 mock = MockLPBranch(os.path.join(self.TEST_ROOT, branch_name))
54 self.assertFalse(os.path.exists(parent_dir))
55 a_branch = branch.Branch.create(mock, self.config, create_tree=True)
56 self.assertTrue(os.path.exists(parent_dir))
57 self.assertTrue(isinstance(a_branch, branch.Branch))
58 self.assertTrue(a_branch.lp_branch.bzr_identity is not None)
59 self.assertTrue(hasattr(a_branch, 'tree'))
42 self.remove_branch_config(tree_dir)60 self.remove_branch_config(tree_dir)
4361
44 def test_create_missing_parent_dir(self):62 def test_create_missing_parent_dir(self):
@@ -66,19 +84,6 @@
66 self.assertTrue(self.branch1.lp_branch.bzr_identity is not None)84 self.assertTrue(self.branch1.lp_branch.bzr_identity is not None)
67 self.assertTrue(hasattr(self.branch1, 'tree'))85 self.assertTrue(hasattr(self.branch1, 'tree'))
6886
69 def test_merge_raises_exception_with_no_tree(self):
70 '''A merge on a branch with no tree will raise an exception.'''
71 branch3_dir = os.path.join(self.TEST_ROOT, 'branch3')
72 self.add_branch_config(branch3_dir)
73 branch3 = branch.Branch.create(MockLPBranch(
74 branch3_dir, source_branch=self.branch1.lp_branch),
75 self.config)
76
77 self.assertRaises(
78 AttributeError, branch3.merge, self.branch2)
79 self.remove_branch_config(branch3_dir)
80 shutil.rmtree(branch3_dir)
81
82 def test_merge_no_changes(self):87 def test_merge_no_changes(self):
83 '''A merge on a branch with a tree will raise an exception if no88 '''A merge on a branch with a tree will raise an exception if no
84 changes are present.'''89 changes are present.'''
8590
=== modified file 'tarmac/tests/test_commands.py'
--- tarmac/tests/test_commands.py 2012-06-29 20:03:55 +0000
+++ tarmac/tests/test_commands.py 2013-03-13 16:57:22 +0000
@@ -1,5 +1,6 @@
1'''Tests for tarmac.bin.commands.py.'''1'''Tests for tarmac.bin.commands.py.'''
2from cStringIO import StringIO2from cStringIO import StringIO
3import logging
3import os4import os
4import shutil5import shutil
5import sys6import sys
@@ -105,15 +106,20 @@
105 display_name=self.branch2.lp_branch.bzr_identity,106 display_name=self.branch2.lp_branch.bzr_identity,
106 name='source',107 name='source',
107 revision_count=self.branch2.lp_branch.revision_count,108 revision_count=self.branch2.lp_branch.revision_count,
108 landing_candidates=[]),109 landing_candidates=[],
110 linked_bugs=[],
111 web_link=u'http://launchpad.net/branches/source'),
109 Thing(112 Thing(
110 bzr_identity=self.branch1.lp_branch.bzr_identity,113 bzr_identity=self.branch1.lp_branch.bzr_identity,
111 display_name=self.branch1.lp_branch.bzr_identity,114 display_name=self.branch1.lp_branch.bzr_identity,
112 name='target',115 name='target',
113 revision_count=self.branch1.lp_branch.revision_count,116 revision_count=self.branch1.lp_branch.revision_count,
114 landing_candidates=None)]117 landing_candidates=None,
118 linked_bugs=[],
119 web_link=u'http://launchpad.net/branches/target')]
115 self.proposals = [Thing(120 self.proposals = [Thing(
116 self_link=u'http://api.edge.launchpad.net/devel/proposal0',121 self_link=u'http://api.edge.launchpad.net/devel/proposal0',
122 web_link=u'http://edge.launchpad.net/proposal0',
117 queue_status=u'Needs Review',123 queue_status=u'Needs Review',
118 commit_message=u'Commitable.',124 commit_message=u'Commitable.',
119 source_branch=self.branches[0],125 source_branch=self.branches[0],
@@ -128,6 +134,7 @@
128 reviewer=Thing(display_name=u'Reviewer'))]),134 reviewer=Thing(display_name=u'Reviewer'))]),
129 Thing(135 Thing(
130 self_link=u'https://api.launchpad.net/1.0/proposal1',136 self_link=u'https://api.launchpad.net/1.0/proposal1',
137 web_link=u'https://launchpad.net/proposal1',
131 queue_status=u'Approved',138 queue_status=u'Approved',
132 commit_message=u'Commit this.',139 commit_message=u'Commit this.',
133 source_branch=self.branches[0],140 source_branch=self.branches[0],
@@ -137,6 +144,7 @@
137 setStatus=self.lp_save,144 setStatus=self.lp_save,
138 lp_save=self.lp_save,145 lp_save=self.lp_save,
139 reviewed_revid=None,146 reviewed_revid=None,
147 reviewer=Thing(name=u'reviewer', display_name=u'Reviewer'),
140 votes=[Thing(148 votes=[Thing(
141 comment=Thing(vote=u'Approve'),149 comment=Thing(vote=u'Approve'),
142 reviewer=Thing(display_name=u'Reviewer')),150 reviewer=Thing(display_name=u'Reviewer')),
@@ -145,7 +153,8 @@
145 reviewer=Thing(display_name=u'Reviewer2'))])]153 reviewer=Thing(display_name=u'Reviewer2'))])]
146 self.branches[1].landing_candidates = self.proposals154 self.branches[1].landing_candidates = self.proposals
147155
148 self.launchpad = Thing(branches=Thing(getByUrl=self.getBranchByUrl))156 self.launchpad = Thing(branches=Thing(getByUrl=self.getBranchByUrl),
157 me=None)
149 self.error = None158 self.error = None
150 registry = CommandRegistry(config=self.config)159 registry = CommandRegistry(config=self.config)
151 registry.register_command('merge', commands.cmd_merge)160 registry.register_command('merge', commands.cmd_merge)
@@ -167,6 +176,20 @@
167 except IndexError:176 except IndexError:
168 return None177 return None
169178
179 def test__get_branch_exists(self):
180 # _get_branch returns the lp_branch if it exists.
181 branch = commands._get_branch(
182 self.branch2.lp_branch.bzr_identity,
183 self.launchpad,
184 logging.getLogger('tarmac'))
185 self.assertIs(self.branches[0], branch)
186
187 def test__get_branch_doesnt_exist(self):
188 # _get_branch returns None if it doesn't exist.
189 branch = commands._get_branch(
190 'doesntexist', self.launchpad, logging.getLogger('tarmac'))
191 self.assertIs(None, branch)
192
170 def test_run(self):193 def test_run(self):
171 """Test that the merge command merges a branch successfully."""194 """Test that the merge command merges a branch successfully."""
172 self.proposals[1].reviewed_revid = \195 self.proposals[1].reviewed_revid = \
@@ -191,10 +214,12 @@
191214
192 def test_get_reviews(self):215 def test_get_reviews(self):
193 """Test that the _get_reviews method gives the right lists."""216 """Test that the _get_reviews method gives the right lists."""
194 self.assertEqual(self.command._get_reviews(self.proposals[0]),217 self.assertEqual(
195 [u'Reviewer;Needs Fixing'])218 commands._get_reviews(self.proposals[0]),
196 self.assertEqual(self.command._get_reviews(self.proposals[1]),219 [u'Reviewer;Needs Fixing'])
197 [u'Reviewer;Approve', u'Reviewer2;Abstain'])220 self.assertEqual(
221 commands._get_reviews(self.proposals[1]),
222 [u'Reviewer;Approve', u'Reviewer2;Abstain'])
198223
199 def test_run_merge_url_substitution(self):224 def test_run_merge_url_substitution(self):
200 """Test that the merge urls get substituted correctly."""225 """Test that the merge urls get substituted correctly."""
@@ -212,6 +237,7 @@
212 # Make a new commit, approve the propsoal, merge, and verify237 # Make a new commit, approve the propsoal, merge, and verify
213 self.branch2.commit('New commit to merge.')238 self.branch2.commit('New commit to merge.')
214 self.proposals[0].queue_status = u'Approved'239 self.proposals[0].queue_status = u'Approved'
240 self.proposals[0].reviewer = Thing(name=u'reviewer')
215 self.proposals[0].reviewed_revid = \241 self.proposals[0].reviewed_revid = \
216 self.branch2.bzr_branch.last_revision()242 self.branch2.bzr_branch.last_revision()
217 self.command.run(launchpad=self.launchpad)243 self.command.run(launchpad=self.launchpad)
@@ -242,6 +268,7 @@
242 branch3.lp_branch.landing_candidates = []268 branch3.lp_branch.landing_candidates = []
243 b3_proposal = Thing(269 b3_proposal = Thing(
244 self_link=u'http://api.edge.launchpad.net/devel/proposal3',270 self_link=u'http://api.edge.launchpad.net/devel/proposal3',
271 web_link=u'http://edge.launchpad.net/proposal3',
245 queue_status=u'Work in Progress',272 queue_status=u'Work in Progress',
246 commit_message=u'Commitable.',273 commit_message=u'Commitable.',
247 source_branch=branch3.lp_branch,274 source_branch=branch3.lp_branch,
@@ -264,8 +291,9 @@
264 self.command.run(launchpad=self.launchpad)291 self.command.run(launchpad=self.launchpad)
265 shutil.rmtree(branch3_dir)292 shutil.rmtree(branch3_dir)
266 self.assertEqual(self.error.comment,293 self.assertEqual(self.error.comment,
267 u'The prerequisite lp:branch3 has not yet been '294 u'The prerequisite '
268 u'merged into lp:branch1.')295 u'http://code.launchpad.net/+branch/branch3 has not '
296 u'yet been merged into http://launchpad.net/branches/target.')
269297
270 def test_run_merge_with_unproposed_prerequisite_fails(self):298 def test_run_merge_with_unproposed_prerequisite_fails(self):
271 """Test that mereging a branch with an unmerged prerequisite fails."""299 """Test that mereging a branch with an unmerged prerequisite fails."""
@@ -289,6 +317,7 @@
289 branch3.lp_branch.landing_candidates = []317 branch3.lp_branch.landing_candidates = []
290 b3_proposal = Thing(318 b3_proposal = Thing(
291 self_link=u'http://api.edge.launchpad.net/devel/proposal3',319 self_link=u'http://api.edge.launchpad.net/devel/proposal3',
320 web_link=u'http://edge.launchpadnet/proposal3',
292 queue_status=u'Work in Progress',321 queue_status=u'Work in Progress',
293 commit_message=u'Commitable.',322 commit_message=u'Commitable.',
294 source_branch=branch3.lp_branch,323 source_branch=branch3.lp_branch,
@@ -311,8 +340,9 @@
311 self.command.run(launchpad=self.launchpad)340 self.command.run(launchpad=self.launchpad)
312 shutil.rmtree(branch3_dir)341 shutil.rmtree(branch3_dir)
313 self.assertEqual(self.error.comment,342 self.assertEqual(self.error.comment,
314 u'No proposals found for merge of lp:branch3 '343 u'No proposals found for merge of '
315 u'into lp:branch1.')344 u'http://code.launchpad.net/+branch/branch3 '
345 u'into http://launchpad.net/branches/target.')
316346
317 def test_run_merge_with_prerequisite_with_multiple_proposals_fails(self):347 def test_run_merge_with_prerequisite_with_multiple_proposals_fails(self):
318 """Test that mereging a branch with an unmerged prerequisite fails."""348 """Test that mereging a branch with an unmerged prerequisite fails."""
@@ -336,6 +366,7 @@
336 branch3.lp_branch.landing_candidates = []366 branch3.lp_branch.landing_candidates = []
337 b3_proposal = Thing(367 b3_proposal = Thing(
338 self_link=u'http://api.edge.launchpad.net/devel/proposal3',368 self_link=u'http://api.edge.launchpad.net/devel/proposal3',
369 web_link=u'http://edge.launchpadnet/proposal3',
339 queue_status=u'Work in Progress',370 queue_status=u'Work in Progress',
340 commit_message=u'Commitable.',371 commit_message=u'Commitable.',
341 source_branch=branch3.lp_branch,372 source_branch=branch3.lp_branch,
@@ -363,5 +394,6 @@
363 shutil.rmtree(branch3_dir)394 shutil.rmtree(branch3_dir)
364 self.assertEqual(self.error.comment,395 self.assertEqual(self.error.comment,
365 u'More than one proposal found for merge of '396 u'More than one proposal found for merge of '
366 u'lp:branch3 into lp:branch1, which is not '397 u'http://code.launchpad.net/+branch/branch3 into '
367 u'Superseded.')398 u'http://launchpad.net/branches/target, which '
399 u'is not Superseded.')

Subscribers

People subscribed via source and target branches