14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
"""Launchpad.net integration plugin for Bazaar."""
17
"""Launchpad.net integration plugin for Bazaar.
19
This plugin provides facilities for working with Bazaar branches that are
20
hosted on Launchpad (http://launchpad.net). It provides a directory service
21
for referring to Launchpad branches using the "lp:" prefix. For example,
22
lp:bzr refers to the Bazaar's main development branch and
23
lp:~username/project/branch-name can be used to refer to a specific branch.
25
This plugin provides a bug tracker so that "bzr commit --fixes lp:1234" will
26
record that revision as fixing Launchpad's bug 1234.
28
The plugin also provides the following commands:
30
launchpad-login: Show or set the Launchpad user ID
31
launchpad-open: Open a Launchpad branch page in your web browser
32
lp-propose-merge: Propose merging a branch on Launchpad
33
register-branch: Register a branch with launchpad.net
34
launchpad-mirror: Ask Launchpad to mirror a branch now
19
38
# The XMLRPC server address can be overridden by setting the environment
20
39
# variable $BZR_LP_XMLRPC_URL
22
# see http://bazaar-vcs.org/Specs/BranchRegistrationTool
41
# see http://wiki.bazaar.canonical.com/Specs/BranchRegistrationTool
24
43
# Since we are a built-in plugin we share the bzrlib version
25
44
from bzrlib import version_info
277
306
register_command(cmd_launchpad_mirror)
309
class cmd_lp_propose_merge(Command):
310
__doc__ = """Propose merging a branch on Launchpad.
312
This will open your usual editor to provide the initial comment. When it
313
has created the proposal, it will open it in your default web browser.
315
The branch will be proposed to merge into SUBMIT_BRANCH. If SUBMIT_BRANCH
316
is not supplied, the remembered submit branch will be used. If no submit
317
branch is remembered, the development focus will be used.
319
By default, the SUBMIT_BRANCH's review team will be requested to review
320
the merge proposal. This can be overriden by specifying --review (-R).
321
The parameter the launchpad account name of the desired reviewer. This
322
may optionally be followed by '=' and the review type. For example:
324
bzr lp-propose-merge --review jrandom --review review-team=qa
326
This will propose a merge, request "jrandom" to perform a review of
327
unspecified type, and request "review-team" to perform a "qa" review.
330
takes_options = [Option('staging',
331
help='Propose the merge on staging.'),
332
Option('message', short_name='m', type=unicode,
333
help='Commit message.'),
335
help='Mark the proposal as approved immediately.'),
336
ListOption('review', short_name='R', type=unicode,
337
help='Requested reviewer and optional type.')]
339
takes_args = ['submit_branch?']
341
aliases = ['lp-submit', 'lp-propose']
343
def run(self, submit_branch=None, review=None, staging=False,
344
message=None, approve=False):
345
from bzrlib.plugins.launchpad import lp_propose
346
tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
352
for review in review:
354
reviews.append(review.split('=', 2))
356
reviews.append((review, ''))
357
if submit_branch is None:
358
submit_branch = branch.get_submit_branch()
359
if submit_branch is None:
362
target = _mod_branch.Branch.open(submit_branch)
363
proposer = lp_propose.Proposer(tree, branch, target, message,
364
reviews, staging, approve=approve)
365
proposer.check_proposal()
366
proposer.create_proposal()
369
register_command(cmd_lp_propose_merge)
372
class cmd_lp_find_proposal(Command):
374
__doc__ = """Find the proposal to merge this revision.
376
Finds the merge proposal(s) that discussed landing the specified revision.
377
This works only if the selected branch was the merge proposal target, and
378
if the merged_revno is recorded for the merge proposal. The proposal(s)
379
are opened in a web browser.
381
Any revision involved in the merge may be specified-- the revision in
382
which the merge was performed, or one of the revisions that was merged.
384
So, to find the merge proposal that reviewed line 1 of README::
386
bzr lp-find-proposal -r annotate:README:1
389
takes_options = ['revision']
391
def run(self, revision=None):
392
from bzrlib.plugins.launchpad import lp_api
394
b = _mod_branch.Branch.open_containing('.')[0]
395
pb = ui.ui_factory.nested_progress_bar()
398
revno = self._find_merged_revno(revision, b, pb)
399
merged = self._find_proposals(revno, b, pb)
401
raise BzrCommandError('No review found.')
402
trace.note('%d proposals(s) found.' % len(merged))
404
webbrowser.open(lp_api.canonical_url(mp))
409
def _find_merged_revno(self, revision, b, pb):
412
pb.update('Finding revision-id')
413
revision_id = revision[0].as_revision_id(b)
414
# a revno spec is necessarily on the mainline.
415
if self._is_revno_spec(revision[0]):
416
merging_revision = revision_id
418
graph = b.repository.get_graph()
419
pb.update('Finding merge')
420
merging_revision = graph.find_lefthand_merger(
421
revision_id, b.last_revision())
422
if merging_revision is None:
423
raise errors.InvalidRevisionSpec(revision[0].user_spec, b)
424
pb.update('Finding revno')
425
return b.revision_id_to_revno(merging_revision)
427
def _find_proposals(self, revno, b, pb):
428
launchpad = lp_api.login(lp_registration.LaunchpadService())
429
pb.update('Finding Launchpad branch')
430
lpb = lp_api.LaunchpadBranch.from_bzr(launchpad, b,
431
create_missing=False)
432
pb.update('Finding proposals')
433
return list(lpb.lp.getMergeProposals(status=['Merged'],
434
merged_revnos=[revno]))
438
def _is_revno_spec(spec):
447
register_command(cmd_lp_find_proposal)
280
450
def _register_directory():
281
451
directories.register_lazy('lp:', 'bzrlib.plugins.launchpad.lp_directory',
282
452
'LaunchpadDirectory',
283
453
'Launchpad-based directory service',)
454
directories.register_lazy(
455
'debianlp:', 'bzrlib.plugins.launchpad.lp_directory',
456
'LaunchpadDirectory',
457
'debianlp: shortcut')
458
directories.register_lazy(
459
'ubuntu:', 'bzrlib.plugins.launchpad.lp_directory',
460
'LaunchpadDirectory',
284
463
_register_directory()