Merge lp:~james-w/tarmac/break-up-do-merges into lp:tarmac

Proposed by James Westby
Status: Rejected
Rejected by: dobey
Proposed branch: lp:~james-w/tarmac/break-up-do-merges
Merge into: lp:tarmac
Prerequisite: lp:~james-w/tarmac/utf8
Diff against target: 454 lines (+206/-192)
1 file modified
tarmac/bin/commands.py (+206/-192)
To merge this branch: bzr merge lp:~james-w/tarmac/break-up-do-merges
Reviewer Review Type Date Requested Status
dobey Disapprove
Paul Hummer Approve
Review via email: mp+145269@code.launchpad.net

This proposal supersedes a proposal from 2013-01-24.

Commit message

Break up the _do_merges method.

Description of the change

This branch breaks up the _do_merges method a little, as it was huge.

I tried to keep changes to a minimum while moving the code around, but it
used "continue" for flow control, so I had to change it a little to
use return values.

(from the u1 fork)

To post a comment you must log in.
Revision history for this message
Paul Hummer (rockstar) wrote :

The prerequisite lp:~james-w/tarmac/utf8 has not yet been merged into lp:tarmac.

Revision history for this message
Paul Hummer (rockstar) :
review: Approve
Revision history for this message
Paul Hummer (rockstar) wrote :

The prerequisite lp:~james-w/tarmac/utf8 has not yet been merged into lp:tarmac.

Revision history for this message
Paul Hummer (rockstar) wrote :

The prerequisite lp:~james-w/tarmac/utf8 has not yet been merged into lp:tarmac.

Revision history for this message
dobey (dobey) wrote :

Please create bugs for the issues, include tests, and split the changes into a branch or two which do not have unnecessary dependencies on other unrelated changes.

review: Disapprove

Unmerged revisions

425. By James Westby

Merged commit-message into break-up-do-merges.

424. By James Westby

Merged commit-message into break-up-do-merges.

423. By James Westby

Merge commit-message.

422. By James Westby

Merged commit-message into break-up-do-merges.

421. By James Westby

Merge commit-message.

420. By James Westby

Merge commit message.

419. By James Westby

Properly check the statuses of the merges when merging just one branch.

418. By James Westby

Remove the option that isn't defined yet.

417. By James Westby

Break up the very large do_merges method somewhat.

416. By James Westby

Add the commit message plugin that sets [r=<reviewer>] and bug info.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'tarmac/bin/commands.py'
--- tarmac/bin/commands.py 2013-02-01 17:17:21 +0000
+++ tarmac/bin/commands.py 2013-02-01 17:17:21 +0000
@@ -134,6 +134,194 @@
134 help_commands(self.outf)134 help_commands(self.outf)
135135
136136
137def _get_mergable_proposals_for_branch(lp_branch, logger, imply_commit_message=False):
138 """Return a list of the mergable proposals for the given branch."""
139 proposals = []
140 for entry in lp_branch.landing_candidates:
141 logger.debug("Considering merge proposal: {0}".format(entry.web_link))
142
143 if entry.queue_status != u'Approved':
144 logger.debug(
145 " Skipping proposal: status is {0}, not "
146 "'Approved'".format(entry.queue_status))
147 continue
148
149 if (not imply_commit_message and not entry.commit_message):
150 logger.debug(
151 " Skipping proposal: proposal has no commit message")
152 continue
153
154 proposals.append(entry)
155 return proposals
156
157
158def _get_reviews(proposal):
159 """Get the set of reviews from the proposal."""
160 reviews = []
161 for vote in proposal.votes:
162 if not vote.comment:
163 continue
164 else:
165 reviews.append('%s;%s' % (vote.reviewer.display_name,
166 vote.comment.vote))
167
168 if len(reviews) == 0:
169 return None
170
171 return reviews
172
173
174def setup(logger, debug=False, http_debug=False):
175 if debug:
176 set_up_debug_logging()
177 logger.debug('Debug logging enabled')
178 if http_debug:
179 httplib2.debuglevel = 1
180 logger.debug('HTTP debugging enabled.')
181 logger.debug('Loading plugins')
182 load_plugins()
183 logger.debug('Plugins loaded')
184
185
186def merge_proposals(target, proposals, logger, config, command):
187 logger.debug('Firing tarmac_pre_merge hook')
188 tarmac_hooks.fire('tarmac_pre_merge',
189 command, target)
190
191 statuses = []
192 try:
193 for proposal in proposals:
194 status = merge_proposal(target, proposal, logger,
195 config, command)
196 statuses.append(status)
197 # This except is here because we need the else and can't have it
198 # without an except as well.
199 except:
200 raise
201 else:
202 logger.debug('Firing tarmac_post_merge hook')
203 tarmac_hooks.fire('tarmac_post_merge',
204 command, target)
205 finally:
206 target.cleanup()
207 return statuses
208
209
210def merge_proposal(target, proposal, logger, config, command):
211 target.cleanup()
212 logger.debug(
213 u'Preparing to merge %(source_branch)s' % {
214 'source_branch': proposal.source_branch.web_link})
215 try:
216 prerequisite = proposal.prerequisite_branch
217 if prerequisite:
218 merges = [x for x in prerequisite.landing_targets
219 if x.target_branch == target.lp_branch and
220 x.queue_status != u'Superseded']
221 if len(merges) == 0:
222 raise TarmacMergeError(
223 u'No proposals of prerequisite branch.',
224 u'No proposals found for merge of %s '
225 u'into %s.' % (
226 prerequisite.web_link,
227 target.lp_branch.web_link))
228 elif len(merges) > 1:
229 raise TarmacMergeError(
230 u'Too many proposals of prerequisite.',
231 u'More than one proposal found for merge '
232 u'of %s into %s, which is not Superseded.' % (
233 prerequisite.web_link,
234 target.lp_branch.web_link))
235 elif len(merges) == 1:
236 if merges[0].queue_status != u'Merged':
237 raise TarmacMergeError(
238 u'Prerequisite not yet merged.',
239 u'The prerequisite %s has not yet been '
240 u'merged into %s.' % (
241 prerequisite.web_link,
242 target.lp_branch.web_link))
243
244 if not proposal.reviewed_revid:
245 raise TarmacMergeError(
246 u'No approved revision specified.')
247
248
249 source = Branch.create(
250 proposal.source_branch, config, target=target)
251
252 source_bzr_branch = source.get_bzr_branch()
253 approved = source_bzr_branch.revision_id_to_revno(
254 str(proposal.reviewed_revid))
255 tip = source_bzr_branch.revno()
256
257 if tip > approved:
258 message = u'Unapproved changes made after approval'
259 lp_comment = (
260 u'There are additional revisions which have not '
261 u'been approved in review. Please seek review and '
262 u'approval of these new revisions.')
263 raise UnapprovedChanges(message, lp_comment)
264
265 logger.debug(
266 'Merging %(source)s at revision %(revision)s' % {
267 'source': proposal.source_branch.web_link,
268 'revision': proposal.reviewed_revid})
269
270 target.merge(source, str(proposal.reviewed_revid))
271
272 logger.debug('Firing tarmac_pre_commit hook')
273 tarmac_hooks.fire('tarmac_pre_commit',
274 command, target, source, proposal)
275
276 except TarmacMergeError, failure:
277 logger.warn(
278 u'Merging %(source)s into %(target)s failed: %(msg)s' %
279 {'source': proposal.source_branch.web_link,
280 'target': proposal.target_branch.web_link,
281 'msg': str(failure)})
282
283 subject = u'Re: [Merge] %(source)s into %(target)s' % {
284 "source": proposal.source_branch.display_name,
285 "target": proposal.target_branch.display_name}
286
287 if failure.comment:
288 comment = failure.comment
289 else:
290 comment = str(failure)
291
292 proposal.createComment(subject=subject, content=comment)
293 try:
294 proposal.setStatus(
295 status=config.rejected_branch_status)
296 except AttributeError:
297 proposal.setStatus(status=u'Needs review')
298 proposal.lp_save()
299 return False
300
301 except PointlessMerge:
302 logger.warn(
303 'Merging %(source)s into %(target)s would be '
304 'pointless.' % {
305 'source': proposal.source_branch.web_link,
306 'target': proposal.target_branch.web_link})
307 return False
308
309 merge_url = get_review_url(proposal)
310 revprops = {'merge_url': merge_url}
311
312 commit_message = proposal.commit_message
313 if commit_message is None and config.imply_commit_message:
314 commit_message = proposal.description
315
316 target.commit(commit_message,
317 reviews=_get_reviews(proposal))
318
319 logger.debug('Firing tarmac_post_commit hook')
320 tarmac_hooks.fire('tarmac_post_commit',
321 command, target, source, proposal)
322 return True
323
324
137class cmd_merge(TarmacCommand):325class cmd_merge(TarmacCommand):
138 '''Automatically merge approved merge proposal branches.'''326 '''Automatically merge approved merge proposal branches.'''
139327
@@ -143,7 +331,8 @@
143 options.http_debug_option,331 options.http_debug_option,
144 options.debug_option,332 options.debug_option,
145 options.imply_commit_message_option,333 options.imply_commit_message_option,
146 options.one_option]334 options.one_option,
335 ]
147336
148 def _do_merges(self, branch_url):337 def _do_merges(self, branch_url):
149338
@@ -152,205 +341,29 @@
152 self.logger.info('Not a valid branch: {0}'.format(branch_url))341 self.logger.info('Not a valid branch: {0}'.format(branch_url))
153 return342 return
154343
155 proposals = self._get_mergable_proposals_for_branch(lp_branch)344 proposals = _get_mergable_proposals_for_branch(lp_branch, self.logger,
345 imply_commit_message=self.config.imply_commit_message)
156346
157 if not proposals:347 if not proposals:
158 self.logger.info(348 self.logger.info(
159 'No approved proposals found for %(branch_url)s' % {349 'No approved proposals found for %(branch_url)s' % {
160 'branch_url': branch_url})350 'branch_url': branch_url})
161 return351 return []
352
353 if self.config.one:
354 proposals = proposals[0]
162355
163 target = Branch.create(lp_branch, self.config, create_tree=True)356 target = Branch.create(lp_branch, self.config, create_tree=True)
164357 statuses = merge_proposals(target, proposals, self.logger, self.config, self)
165 self.logger.debug('Firing tarmac_pre_merge hook')358 return statuses
166 tarmac_hooks.fire('tarmac_pre_merge',359
167 self, target)
168
169 success_count = 0
170 try:
171 for proposal in proposals:
172 target.cleanup()
173 self.logger.debug(
174 u'Preparing to merge %(source_branch)s' % {
175 'source_branch': proposal.source_branch.web_link})
176 try:
177 prerequisite = proposal.prerequisite_branch
178 if prerequisite:
179 merges = [x for x in prerequisite.landing_targets
180 if x.target_branch == target.lp_branch and
181 x.queue_status != u'Superseded']
182 if len(merges) == 0:
183 raise TarmacMergeError(
184 u'No proposals of prerequisite branch.',
185 u'No proposals found for merge of %s '
186 u'into %s.' % (
187 prerequisite.web_link,
188 target.lp_branch.web_link))
189 elif len(merges) > 1:
190 raise TarmacMergeError(
191 u'Too many proposals of prerequisite.',
192 u'More than one proposal found for merge '
193 u'of %s into %s, which is not Superseded.' % (
194 prerequisite.web_link,
195 target.lp_branch.web_link))
196 elif len(merges) == 1:
197 if merges[0].queue_status != u'Merged':
198 raise TarmacMergeError(
199 u'Prerequisite not yet merged.',
200 u'The prerequisite %s has not yet been '
201 u'merged into %s.' % (
202 prerequisite.web_link,
203 target.lp_branch.web_link))
204
205 if not proposal.reviewed_revid:
206 raise TarmacMergeError(
207 u'No approved revision specified.')
208
209
210 source = Branch.create(
211 proposal.source_branch, self.config, target=target)
212
213 source_bzr_branch = source.get_bzr_branch()
214 approved = source_bzr_branch.revision_id_to_revno(
215 str(proposal.reviewed_revid))
216 tip = source_bzr_branch.revno()
217
218 if tip > approved:
219 message = u'Unapproved changes made after approval'
220 lp_comment = (
221 u'There are additional revisions which have not '
222 u'been approved in review. Please seek review and '
223 u'approval of these new revisions.')
224 raise UnapprovedChanges(message, lp_comment)
225
226 self.logger.debug(
227 'Merging %(source)s at revision %(revision)s' % {
228 'source': proposal.source_branch.web_link,
229 'revision': proposal.reviewed_revid})
230
231 target.merge(source, str(proposal.reviewed_revid))
232
233 self.logger.debug('Firing tarmac_pre_commit hook')
234 tarmac_hooks.fire('tarmac_pre_commit',
235 self, target, source, proposal)
236
237 except TarmacMergeError, failure:
238 self.logger.warn(
239 u'Merging %(source)s into %(target)s failed: %(msg)s' %
240 {'source': proposal.source_branch.web_link,
241 'target': proposal.target_branch.web_link,
242 'msg': str(failure)})
243
244 subject = u'Re: [Merge] %(source)s into %(target)s' % {
245 "source": proposal.source_branch.display_name,
246 "target": proposal.target_branch.display_name}
247
248 if failure.comment:
249 comment = failure.comment
250 else:
251 comment = str(failure)
252
253 proposal.createComment(subject=subject, content=comment)
254 try:
255 proposal.setStatus(
256 status=self.config.rejected_branch_status)
257 except AttributeError:
258 proposal.setStatus(status=u'Needs review')
259 proposal.lp_save()
260
261 # If we've been asked to only merge one branch, then exit.
262 if self.config.one:
263 return True
264
265 continue
266 except PointlessMerge:
267 self.logger.warn(
268 'Merging %(source)s into %(target)s would be '
269 'pointless.' % {
270 'source': proposal.source_branch.web_link,
271 'target': proposal.target_branch.web_link})
272 continue
273
274 merge_url = get_review_url(proposal)
275 revprops = {'merge_url': merge_url}
276
277 commit_message = proposal.commit_message
278 if commit_message is None and self.config.imply_commit_message:
279 commit_message = proposal.description
280
281 target.commit(commit_message,
282 revprops=revprops,
283 authors=source.authors,
284 reviews=self._get_reviews(proposal))
285
286 self.logger.debug('Firing tarmac_post_commit hook')
287 tarmac_hooks.fire('tarmac_post_commit',
288 self, target, source, proposal)
289 success_count += 1
290 target.cleanup()
291 if self.config.one:
292 return True
293
294 # This except is here because we need the else and can't have it
295 # without an except as well.
296 except:
297 raise
298 else:
299 self.logger.debug('Firing tarmac_post_merge hook')
300 tarmac_hooks.fire('tarmac_post_merge',
301 self, target, success_count=success_count)
302 finally:
303 target.cleanup()
304
305 def _get_mergable_proposals_for_branch(self, lp_branch):
306 """Return a list of the mergable proposals for the given branch."""
307 proposals = []
308 for entry in lp_branch.landing_candidates:
309 self.logger.debug("Considering merge proposal: {0}".format(entry.web_link))
310
311 if entry.queue_status != u'Approved':
312 self.logger.debug(
313 " Skipping proposal: status is {0}, not "
314 "'Approved'".format(entry.queue_status))
315 continue
316
317 if (not self.config.imply_commit_message and
318 not entry.commit_message):
319 self.logger.debug(
320 " Skipping proposal: proposal has no commit message")
321 continue
322
323 proposals.append(entry)
324 return proposals
325
326 def _get_reviews(self, proposal):
327 """Get the set of reviews from the proposal."""
328 reviews = []
329 for vote in proposal.votes:
330 if not vote.comment:
331 continue
332 else:
333 reviews.append('%s;%s' % (vote.reviewer.display_name,
334 vote.comment.vote))
335
336 if len(reviews) == 0:
337 return None
338
339 return reviews
340360
341 def run(self, branch_url=None, launchpad=None, **kwargs):361 def run(self, branch_url=None, launchpad=None, **kwargs):
342 for key, value in kwargs.iteritems():362 for key, value in kwargs.iteritems():
343 self.config.set('Tarmac', key, value)363 self.config.set('Tarmac', key, value)
344364
345 if self.config.debug:365 setup(self.logger, debug=self.config.debug,
346 set_up_debug_logging()366 http_debug=self.config.http_debug)
347 self.logger.debug('Debug logging enabled')
348 if self.config.http_debug:
349 httplib2.debuglevel = 1
350 self.logger.debug('HTTP debugging enabled.')
351 self.logger.debug('Loading plugins')
352 load_plugins()
353 self.logger.debug('Plugins loaded')
354367
355 self.launchpad = launchpad368 self.launchpad = launchpad
356 if self.launchpad is None:369 if self.launchpad is None:
@@ -358,23 +371,24 @@
358 self.launchpad = self.get_launchpad_object()371 self.launchpad = self.get_launchpad_object()
359 self.logger.debug('launchpad object loaded')372 self.logger.debug('launchpad object loaded')
360373
374 statuses = []
375
361 if branch_url:376 if branch_url:
362 self.logger.debug('%(branch_url)s specified as branch_url' % {377 self.logger.debug('%(branch_url)s specified as branch_url' % {
363 'branch_url': branch_url})378 'branch_url': branch_url})
364 if not branch_url.startswith('lp:'):379 if not branch_url.startswith('lp:'):
365 raise TarmacCommandError('Branch urls must start with lp:')380 raise TarmacCommandError('Branch urls must start with lp:')
366 self._do_merges(branch_url)381 statuses.extend(self._do_merges(branch_url))
367
368 else:382 else:
369 for branch in self.config.branches:383 for branch in self.config.branches:
370 self.logger.debug(384 self.logger.debug(
371 'Merging approved branches against %(branch)s' % {385 'Merging approved branches against %(branch)s' % {
372 'branch': branch})386 'branch': branch})
373 try:387 try:
374 merged = self._do_merges(branch)388 statuses.extend(self._do_merges(branch))
375389
376 # If we've been asked to only merge one branch, then exit.390 # If we've been asked to only merge one branch, then exit.
377 if merged and self.config.one:391 if statuses and self.config.one:
378 break392 break
379 except LockContention:393 except LockContention:
380 continue394 continue

Subscribers

People subscribed via source and target branches