13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
"""Launchpad.net integration plugin for Bazaar."""
19
19
# The XMLRPC server address can be overridden by setting the environment
20
# variable $BZR_LP_XMLRPL_URL
20
# variable $BZR_LP_XMLRPC_URL
22
22
# see http://bazaar-vcs.org/Specs/BranchRegistrationTool
24
from bzrlib.branch import Branch
25
from bzrlib.commands import Command, Option, register_command
24
# Since we are a built-in plugin we share the bzrlib version
25
from bzrlib import version_info
27
from bzrlib.lazy_import import lazy_import
28
lazy_import(globals(), """
30
branch as _mod_branch,
35
from bzrlib import bzrdir
36
from bzrlib.commands import (
26
40
from bzrlib.directory_service import directories
27
from bzrlib.errors import BzrCommandError, NoPublicBranch, NotBranchError
41
from bzrlib.errors import (
28
48
from bzrlib.help_topics import topic_registry
49
from bzrlib.option import (
31
55
class cmd_register_branch(Command):
89
118
from bzrlib.plugins.launchpad.lp_registration import (
90
LaunchpadService, BranchRegistrationRequest, BranchBugLinkRequest,
91
DryRunLaunchpadService)
119
BranchRegistrationRequest, BranchBugLinkRequest,
120
DryRunLaunchpadService, LaunchpadService)
92
121
if public_url is None:
94
b = Branch.open_containing('.')[0]
123
b = _mod_branch.Branch.open_containing('.')[0]
95
124
except NotBranchError:
96
125
raise BzrCommandError('register-branch requires a public '
97
126
'branch url - see bzr help register-branch.')
98
127
public_url = b.get_public_branch()
99
128
if public_url is None:
100
129
raise NoPublicBranch(b)
130
if product is not None:
132
trace.note('--product is deprecated; please use --project.')
102
135
rego = BranchRegistrationRequest(branch_url=public_url,
103
136
branch_name=branch_name,
104
137
branch_title=branch_title,
105
138
branch_description=branch_description,
106
product_name=product,
139
product_name=project,
107
140
author_email=author,
109
142
linko = BranchBugLinkRequest(branch_url=public_url,
119
152
# Run on service entirely in memory
120
153
service = DryRunLaunchpadService()
121
154
service.gather_user_credentials()
122
branch_object_url = rego.submit(service)
124
link_bug_url = linko.submit(service)
157
linko.submit(service)
125
158
print 'Branch registered.'
127
160
register_command(cmd_register_branch)
163
class cmd_launchpad_open(Command):
164
"""Open a Launchpad branch page in your web browser."""
166
aliases = ['lp-open']
169
'Do not actually open the browser. Just say the URL we would '
172
takes_args = ['location?']
174
def _possible_locations(self, location):
175
"""Yield possible external locations for the branch at 'location'."""
178
branch = _mod_branch.Branch.open_containing(location)[0]
179
except NotBranchError:
181
branch_url = branch.get_public_branch()
182
if branch_url is not None:
184
branch_url = branch.get_push_location()
185
if branch_url is not None:
188
def _get_web_url(self, service, location):
189
from bzrlib.plugins.launchpad.lp_registration import (
191
for branch_url in self._possible_locations(location):
193
return service.get_web_url_from_branch_url(branch_url)
194
except (NotLaunchpadBranch, InvalidURL):
196
raise NotLaunchpadBranch(branch_url)
198
def run(self, location=None, dry_run=False):
199
from bzrlib.plugins.launchpad.lp_registration import (
203
web_url = self._get_web_url(LaunchpadService(), location)
204
trace.note('Opening %s in web browser' % web_url)
206
import webbrowser # this import should not be lazy
207
# otherwise bzr.exe lacks this module
208
webbrowser.open(web_url)
210
register_command(cmd_launchpad_open)
130
213
class cmd_launchpad_login(Command):
131
214
"""Show or set the Launchpad user ID.
160
245
if check_account:
161
246
account.check_lp_login(username)
249
"Launchpad user ID exists and has SSH keys.\n")
162
250
self.outf.write(username + '\n')
164
252
self.outf.write('No Launchpad user ID configured.\n')
167
256
if check_account:
168
257
account.check_lp_login(name)
260
"Launchpad user ID exists and has SSH keys.\n")
169
261
account.set_lp_login(name)
263
self.outf.write("Launchpad user ID set to '%s'.\n" % (name,))
171
265
register_command(cmd_launchpad_login)
268
# XXX: cmd_launchpad_mirror is untested
269
class cmd_launchpad_mirror(Command):
270
"""Ask Launchpad to mirror a branch now."""
272
aliases = ['lp-mirror']
273
takes_args = ['location?']
275
def run(self, location='.'):
276
from bzrlib.plugins.launchpad import lp_api
277
from bzrlib.plugins.launchpad.lp_registration import LaunchpadService
278
branch = _mod_branch.Branch.open(location)
279
service = LaunchpadService()
280
launchpad = lp_api.login(service)
281
lp_branch = lp_api.load_branch(launchpad, branch)
282
lp_branch.requestMirror()
285
register_command(cmd_launchpad_mirror)
288
class cmd_lp_propose_merge(Command):
289
"""Propose merging a branch on Launchpad.
291
This will open your usual editor to provide the initial comment. When it
292
has created the proposal, it will open it in your default web browser.
294
The branch will be proposed to merge into SUBMIT_BRANCH. If SUBMIT_BRANCH
295
is not supplied, the remembered submit branch will be used. If no submit
296
branch is remembered, the development focus will be used.
298
By default, the SUBMIT_BRANCH's review team will be requested to review
299
the merge proposal. This can be overriden by specifying --review (-R).
300
The parameter the launchpad account name of the desired reviewer. This
301
may optionally be followed by '=' and the review type. For example:
303
bzr lp-propose-merge --review jrandom --review review-team=qa
305
This will propose a merge, request "jrandom" to perform a review of
306
unspecified type, and request "review-team" to perform a "qa" review.
309
takes_options = [Option('staging',
310
help='Propose the merge on staging.'),
311
Option('message', short_name='m', type=unicode,
312
help='Commit message.'),
313
ListOption('review', short_name='R', type=unicode,
314
help='Requested reviewer and optional type.')]
316
takes_args = ['submit_branch?']
318
aliases = ['lp-submit', 'lp-propose']
320
def run(self, submit_branch=None, review=None, staging=False,
322
from bzrlib.plugins.launchpad import lp_propose
323
tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
329
for review in review:
331
reviews.append(review.split('=', 2))
333
reviews.append((review, ''))
334
if submit_branch is None:
335
submit_branch = branch.get_submit_branch()
336
if submit_branch is None:
339
target = _mod_branch.Branch.open(submit_branch)
340
proposer = lp_propose.Proposer(tree, branch, target, message,
342
proposer.check_proposal()
343
proposer.create_proposal()
346
register_command(cmd_lp_propose_merge)
174
349
def _register_directory():
175
350
directories.register_lazy('lp:', 'bzrlib.plugins.launchpad.lp_directory',
176
351
'LaunchpadDirectory',
178
353
_register_directory()
182
"""Called by bzrlib to fetch tests for this plugin"""
183
from unittest import TestSuite, TestLoader
184
from bzrlib.plugins.launchpad import (
185
test_account, test_lp_directory, test_lp_service, test_register,
356
def load_tests(basic_tests, module, loader):
366
basic_tests.addTest(loader.loadTestsFromModuleNames(
367
["%s.%s" % (__name__, tmn) for tmn in testmod_names]))
188
loader = TestLoader()
196
suite.addTests(loader.loadTestsFromModule(module))
199
371
_launchpad_help = """Integration with Launchpad.net
208
380
is then used by the 'lp:' transport to download your branches using
383
* The 'lp:' transport uses Launchpad as a directory service: for example
384
'lp:bzr' and 'lp:python' refer to the main branches of the relevant
385
projects and may be branched, logged, etc. You can also use the 'lp:'
386
transport to refer to specific branches, e.g. lp:~bzr/bzr/trunk.
388
* The 'lp:' bug tracker alias can expand launchpad bug numbers to their
389
URLs for use with 'bzr commit --fixes', e.g. 'bzr commit --fixes lp:12345'
390
will record a revision property that marks that revision as fixing
391
Launchpad bug 12345. When you push that branch to Launchpad it will
392
automatically be linked to the bug report.
211
394
* The register-branch command tells Launchpad about the url of a
212
395
public branch. Launchpad will then mirror the branch, display
213
396
its contents and allow it to be attached to bugs and other
216
* The 'lp:' transport uses Launchpad as a directory service: for example
217
'lp:bzr' and 'lp:python' refer to the main branches of the relevant
218
projects and may be branched, logged, etc. You can also use the 'lp:'
219
transport to refer to specific branches, e.g. lp:///~bzr/bzr/trunk.
221
399
For more information see http://help.launchpad.net/
223
401
topic_registry.register('launchpad',