17
17
"""Launchpad plugin commands."""
19
from __future__ import absolute_import
22
20
branch as _mod_branch,
26
from bzrlib.commands import (
24
from ...commands import (
29
from bzrlib.errors import (
27
from ...errors import (
35
from bzrlib.i18n import gettext
36
from bzrlib.option import (
31
from ...i18n import gettext
32
from ...option import (
42
class cmd_register_branch(Command):
43
__doc__ = """Register a branch with launchpad.net.
45
This command lists a bzr branch in the directory of branches on
46
launchpad.net. Registration allows the branch to be associated with
47
bugs or specifications.
49
Before using this command you must register the project to which the
50
branch belongs, and create an account for yourself on launchpad.net.
53
public_url: The publicly visible url for the branch to register.
54
This must be an http or https url (which Launchpad can read
55
from to access the branch). Local file urls, SFTP urls, and
56
bzr+ssh urls will not work.
57
If no public_url is provided, bzr will use the configured
58
public_url if there is one for the current branch, and
62
bzr register-branch http://foo.com/bzr/fooproject.mine \\
65
takes_args = ['public_url?']
68
'Launchpad project short name to associate with the branch.',
71
'Launchpad product short name to associate with the branch.',
75
'Short name for the branch; '
76
'by default taken from the last component of the url.',
78
Option('branch-title',
79
'One-sentence description of the branch.',
81
Option('branch-description',
82
'Longer description of the purpose or contents of the branch.',
85
"Branch author's email address, if not yourself.",
88
'The bug this branch fixes.',
91
'Prepare the request but don\'t actually send it.')
101
branch_description='',
105
from bzrlib.plugins.launchpad.lp_registration import (
106
BranchRegistrationRequest, BranchBugLinkRequest,
107
DryRunLaunchpadService, LaunchpadService)
108
if public_url is None:
110
b = _mod_branch.Branch.open_containing('.')[0]
111
except NotBranchError:
112
raise BzrCommandError(gettext(
113
'register-branch requires a public '
114
'branch url - see bzr help register-branch.'))
115
public_url = b.get_public_branch()
116
if public_url is None:
117
raise NoPublicBranch(b)
118
if product is not None:
121
'--product is deprecated; please use --project.'))
124
rego = BranchRegistrationRequest(branch_url=public_url,
125
branch_name=branch_name,
126
branch_title=branch_title,
127
branch_description=branch_description,
128
product_name=project,
131
linko = BranchBugLinkRequest(branch_url=public_url,
134
service = LaunchpadService()
135
# This gives back the xmlrpc url that can be used for future
136
# operations on the branch. It's not so useful to print to the
137
# user since they can't do anything with it from a web browser; it
138
# might be nice for the server to tell us about an html url as
141
# Run on service entirely in memory
142
service = DryRunLaunchpadService()
143
service.gather_user_credentials()
146
linko.submit(service)
147
self.outf.write('Branch registered.\n')
150
38
class cmd_launchpad_open(Command):
151
39
__doc__ = """Open a Launchpad branch page in your web browser."""
246
135
account.set_lp_login(name)
248
137
self.outf.write(gettext("Launchpad user ID set to '%s'.\n") %
252
# XXX: cmd_launchpad_mirror is untested
253
class cmd_launchpad_mirror(Command):
254
__doc__ = """Ask Launchpad to mirror a branch now."""
256
aliases = ['lp-mirror']
257
takes_args = ['location?']
259
def run(self, location='.'):
260
from bzrlib.plugins.launchpad import lp_api
261
from bzrlib.plugins.launchpad.lp_registration import LaunchpadService
262
branch, _ = _mod_branch.Branch.open_containing(location)
263
service = LaunchpadService()
264
launchpad = lp_api.login(service)
265
lp_branch = lp_api.LaunchpadBranch.from_bzr(launchpad, branch,
266
create_missing=False)
267
lp_branch.lp.requestMirror()
270
class cmd_lp_propose_merge(Command):
271
__doc__ = """Propose merging a branch on Launchpad.
273
This will open your usual editor to provide the initial comment. When it
274
has created the proposal, it will open it in your default web browser.
276
The branch will be proposed to merge into SUBMIT_BRANCH. If SUBMIT_BRANCH
277
is not supplied, the remembered submit branch will be used. If no submit
278
branch is remembered, the development focus will be used.
280
By default, the SUBMIT_BRANCH's review team will be requested to review
281
the merge proposal. This can be overriden by specifying --review (-R).
282
The parameter the launchpad account name of the desired reviewer. This
283
may optionally be followed by '=' and the review type. For example:
285
bzr lp-propose-merge --review jrandom --review review-team=qa
287
This will propose a merge, request "jrandom" to perform a review of
288
unspecified type, and request "review-team" to perform a "qa" review.
141
class cmd_launchpad_logout(Command):
142
__doc__ = """Unset the Launchpad user ID.
144
When communicating with Launchpad, some commands need to know your
145
Launchpad user ID. This command will log you out from Launchpad.
146
This means that communication with Launchpad will happen over
147
HTTPS, and will not require one of your SSH keys to be available.
291
takes_options = [Option('staging',
292
help='Propose the merge on staging.'),
293
Option('message', short_name='m', type=unicode,
294
help='Commit message.'),
296
help=('Mark the proposal as approved immediately, '
297
'setting the approved revision to tip.')),
298
Option('fixes', 'The bug this proposal fixes.', str),
299
ListOption('review', short_name='R', type=unicode,
300
help='Requested reviewer and optional type.')]
302
takes_args = ['submit_branch?']
304
aliases = ['lp-submit', 'lp-propose']
306
def run(self, submit_branch=None, review=None, staging=False,
307
message=None, approve=False, fixes=None):
308
from bzrlib.plugins.launchpad import lp_propose
309
tree, branch, relpath = controldir.ControlDir.open_containing_tree_or_branch(
315
for review in review:
317
reviews.append(review.split('=', 2))
319
reviews.append((review, ''))
320
if submit_branch is None:
321
submit_branch = branch.get_submit_branch()
322
if submit_branch is None:
325
target = _mod_branch.Branch.open(submit_branch)
326
proposer = lp_propose.Proposer(tree, branch, target, message,
327
reviews, staging, approve=approve,
329
proposer.check_proposal()
330
proposer.create_proposal()
149
aliases = ['lp-logout']
150
takes_options = ['verbose']
152
def run(self, verbose=False):
153
from . import account
154
old_username = account.get_lp_login()
155
if old_username is None:
156
self.outf.write(gettext('Not logged into Launchpad.\n'))
158
account.set_lp_login(None)
160
self.outf.write(gettext(
161
"Launchpad user ID %s logged out.\n") %
333
165
class cmd_lp_find_proposal(Command):
344
176
So, to find the merge proposal that reviewed line 1 of README::
346
bzr lp-find-proposal -r mainline:annotate:README:1
178
brz lp-find-proposal -r mainline:annotate:README:1
349
181
takes_options = ['revision']
351
183
def run(self, revision=None):
352
from bzrlib import ui
353
from bzrlib.plugins.launchpad import lp_api
354
186
import webbrowser
355
187
b = _mod_branch.Branch.open_containing('.')[0]
356
pb = ui.ui_factory.nested_progress_bar()
188
with ui.ui_factory.nested_progress_bar() as pb, b.lock_read():
359
189
if revision is None:
360
190
revision_id = b.last_revision()
362
192
revision_id = revision[0].as_revision_id(b)
363
193
merged = self._find_proposals(revision_id, pb)
364
194
if len(merged) == 0:
365
raise BzrCommandError(gettext('No review found.'))
195
raise CommandError(gettext('No review found.'))
366
196
trace.note(gettext('%d proposals(s) found.') % len(merged))
367
197
for mp in merged:
368
198
webbrowser.open(lp_api.canonical_url(mp))
373
200
def _find_proposals(self, revision_id, pb):
374
from bzrlib.plugins.launchpad import (lp_api, lp_registration)
201
from launchpadlib import uris
375
203
# "devel" because branches.getMergeProposals is not part of 1.0 API.
376
launchpad = lp_api.login(lp_registration.LaunchpadService(),
204
lp_base_url = uris.LPNET_SERVICE_ROOT
205
launchpad = lp_api.connect_launchpad(lp_base_url, version='devel')
378
206
pb.update(gettext('Finding proposals'))
379
207
return list(launchpad.branches.getMergeProposals(
380
merged_revision=revision_id))
208
merged_revision=revision_id.decode('utf-8')))