Merge lp:~cjwatson/bzr/remove-register-branch into lp:bzr

Proposed by Colin Watson
Status: Needs review
Proposed branch: lp:~cjwatson/bzr/remove-register-branch
Merge into: lp:bzr
Diff against target: 641 lines (+33/-431)
5 files modified
bzrlib/plugins/launchpad/__init__.py (+1/-8)
bzrlib/plugins/launchpad/cmds.py (+1/-110)
bzrlib/plugins/launchpad/lp_registration.py (+11/-116)
bzrlib/plugins/launchpad/test_register.py (+11/-197)
doc/en/release-notes/bzr-2.8.txt (+9/-0)
To merge this branch: bzr merge lp:~cjwatson/bzr/remove-register-branch
Reviewer Review Type Date Requested Status
bzr-core Pending
Review via email: mp+324472@code.launchpad.net

Commit message

Remove `bzr register-branch`, since it has not worked for a long time.

Description of the change

The `bzr register-branch` command has been broken for a long time with no bug reports:

 * It relies on password authentication to Launchpad, which was deprecated in favour of SSO many years ago and disabled entirely in January 2012.
 * Its entire purpose is to create mirrored branches, which are generally deprecated in favour of code imports, and the mirroring of those branches no longer works because the relevant systems haven't had firewall-level access to the outside world for quite some time.

There's really not much point trying to resurrect this command and convert it to create code imports with modern authentication. It should just be removed.

To post a comment you must log in.

Unmerged revisions

6623. By Colin Watson

Remove `bzr register-branch`, since it has not worked for a long time.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bzrlib/plugins/launchpad/__init__.py'
--- bzrlib/plugins/launchpad/__init__.py 2012-03-10 19:11:06 +0000
+++ bzrlib/plugins/launchpad/__init__.py 2017-05-23 12:36:28 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2006-2011 Canonical Ltd1# Copyright (C) 2006-2017 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -30,7 +30,6 @@
30 launchpad-login: Show or set the Launchpad user ID30 launchpad-login: Show or set the Launchpad user ID
31 launchpad-open: Open a Launchpad branch page in your web browser31 launchpad-open: Open a Launchpad branch page in your web browser
32 lp-propose-merge: Propose merging a branch on Launchpad32 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 now33 launchpad-mirror: Ask Launchpad to mirror a branch now
3534
36"""35"""
@@ -57,7 +56,6 @@
57from bzrlib.help_topics import topic_registry56from bzrlib.help_topics import topic_registry
5857
59for klsname, aliases in [58for klsname, aliases in [
60 ("cmd_register_branch", []),
61 ("cmd_launchpad_open", ["lp-open"]),59 ("cmd_launchpad_open", ["lp-open"]),
62 ("cmd_launchpad_login", ["lp-login"]),60 ("cmd_launchpad_login", ["lp-login"]),
63 ("cmd_launchpad_mirror", ["lp-mirror"]),61 ("cmd_launchpad_mirror", ["lp-mirror"]),
@@ -177,11 +175,6 @@
177 Launchpad bug 12345. When you push that branch to Launchpad it will175 Launchpad bug 12345. When you push that branch to Launchpad it will
178 automatically be linked to the bug report.176 automatically be linked to the bug report.
179177
180 * The register-branch command tells Launchpad about the url of a
181 public branch. Launchpad will then mirror the branch, display
182 its contents and allow it to be attached to bugs and other
183 objects.
184
185For more information see http://help.launchpad.net/178For more information see http://help.launchpad.net/
186"""179"""
187topic_registry.register('launchpad',180topic_registry.register('launchpad',
188181
=== modified file 'bzrlib/plugins/launchpad/cmds.py'
--- bzrlib/plugins/launchpad/cmds.py 2012-10-22 15:51:31 +0000
+++ bzrlib/plugins/launchpad/cmds.py 2017-05-23 12:36:28 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2006-2012 Canonical Ltd1# Copyright (C) 2006-2017 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -29,7 +29,6 @@
29from bzrlib.errors import (29from bzrlib.errors import (
30 BzrCommandError,30 BzrCommandError,
31 InvalidURL,31 InvalidURL,
32 NoPublicBranch,
33 NotBranchError,32 NotBranchError,
34 )33 )
35from bzrlib.i18n import gettext34from bzrlib.i18n import gettext
@@ -39,114 +38,6 @@
39 )38 )
4039
4140
42class cmd_register_branch(Command):
43 __doc__ = """Register a branch with launchpad.net.
44
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.
48
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.
51
52 arguments:
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
59 otherwise error.
60
61 example:
62 bzr register-branch http://foo.com/bzr/fooproject.mine \\
63 --project fooproject
64 """
65 takes_args = ['public_url?']
66 takes_options = [
67 Option('project',
68 'Launchpad project short name to associate with the branch.',
69 unicode),
70 Option('product',
71 'Launchpad product short name to associate with the branch.',
72 unicode,
73 hidden=True),
74 Option('branch-name',
75 'Short name for the branch; '
76 'by default taken from the last component of the url.',
77 unicode),
78 Option('branch-title',
79 'One-sentence description of the branch.',
80 unicode),
81 Option('branch-description',
82 'Longer description of the purpose or contents of the branch.',
83 unicode),
84 Option('author',
85 "Branch author's email address, if not yourself.",
86 unicode),
87 Option('link-bug',
88 'The bug this branch fixes.',
89 int),
90 Option('dry-run',
91 'Prepare the request but don\'t actually send it.')
92 ]
93
94
95 def run(self,
96 public_url=None,
97 project='',
98 product=None,
99 branch_name='',
100 branch_title='',
101 branch_description='',
102 author='',
103 link_bug=None,
104 dry_run=False):
105 from bzrlib.plugins.launchpad.lp_registration import (
106 BranchRegistrationRequest, BranchBugLinkRequest,
107 DryRunLaunchpadService, LaunchpadService)
108 if public_url is None:
109 try:
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:
119 project = product
120 trace.note(gettext(
121 '--product is deprecated; please use --project.'))
122
123
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,
129 author_email=author,
130 )
131 linko = BranchBugLinkRequest(branch_url=public_url,
132 bug_id=link_bug)
133 if not dry_run:
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
139 # well.
140 else:
141 # Run on service entirely in memory
142 service = DryRunLaunchpadService()
143 service.gather_user_credentials()
144 rego.submit(service)
145 if link_bug:
146 linko.submit(service)
147 self.outf.write('Branch registered.\n')
148
149
150class cmd_launchpad_open(Command):41class cmd_launchpad_open(Command):
151 __doc__ = """Open a Launchpad branch page in your web browser."""42 __doc__ = """Open a Launchpad branch page in your web browser."""
15243
15344
=== modified file 'bzrlib/plugins/launchpad/lp_registration.py'
--- bzrlib/plugins/launchpad/lp_registration.py 2012-01-20 13:07:10 +0000
+++ bzrlib/plugins/launchpad/lp_registration.py 2017-05-23 12:36:28 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2006-2011 Canonical Ltd1# Copyright (C) 2006-2017 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -144,51 +144,13 @@
144 raise errors.InvalidURL(path=url)144 raise errors.InvalidURL(path=url)
145 return cls(lp_instance=lp_instance, **kwargs)145 return cls(lp_instance=lp_instance, **kwargs)
146146
147 def get_proxy(self, authenticated):147 def get_proxy(self):
148 """Return the proxy for XMLRPC requests."""148 """Return the proxy for XMLRPC requests."""
149 if authenticated:149 url = self.service_url
150 # auth info must be in url
151 # TODO: if there's no registrant email perhaps we should
152 # just connect anonymously?
153 scheme, hostinfo, path = urlsplit(self.service_url)[:3]
154 if '@' in hostinfo:
155 raise AssertionError(hostinfo)
156 if self.registrant_email is None:
157 raise AssertionError()
158 if self.registrant_password is None:
159 raise AssertionError()
160 # TODO: perhaps fully quote the password to make it very slightly
161 # obscured
162 # TODO: can we perhaps add extra Authorization headers
163 # directly to the request, rather than putting this into
164 # the url? perhaps a bit more secure against accidentally
165 # revealing it. std66 s3.2.1 discourages putting the
166 # password in the url.
167 hostinfo = '%s:%s@%s' % (urlutils.quote(self.registrant_email),
168 urlutils.quote(self.registrant_password),
169 hostinfo)
170 url = urlunsplit((scheme, hostinfo, path, '', ''))
171 else:
172 url = self.service_url
173 return xmlrpclib.ServerProxy(url, transport=self.transport)150 return xmlrpclib.ServerProxy(url, transport=self.transport)
174151
175 def gather_user_credentials(self):152 def send_request(self, method_name, method_params):
176 """Get the password from the user."""153 proxy = self.get_proxy()
177 the_config = config.GlobalConfig()
178 self.registrant_email = the_config.user_email()
179 if self.registrant_password is None:
180 auth = config.AuthenticationConfig()
181 scheme, hostinfo = urlsplit(self.service_url)[:2]
182 prompt = 'launchpad.net password for %s: ' % \
183 self.registrant_email
184 # We will reuse http[s] credentials if we can, prompt user
185 # otherwise
186 self.registrant_password = auth.get_password(scheme, hostinfo,
187 self.registrant_email,
188 prompt=prompt)
189
190 def send_request(self, method_name, method_params, authenticated):
191 proxy = self.get_proxy(authenticated)
192 method = getattr(proxy, method_name)154 method = getattr(proxy, method_name)
193 try:155 try:
194 result = method(*method_params)156 result = method(*method_params)
@@ -255,7 +217,6 @@
255217
256 # Set this to the XMLRPC method name.218 # Set this to the XMLRPC method name.
257 _methodname = None219 _methodname = None
258 _authenticated = True
259220
260 def _request_params(self):221 def _request_params(self):
261 """Return the arguments to pass to the method"""222 """Return the arguments to pass to the method"""
@@ -264,88 +225,22 @@
264 def submit(self, service):225 def submit(self, service):
265 """Submit request to Launchpad XMLRPC server.226 """Submit request to Launchpad XMLRPC server.
266227
267 :param service: LaunchpadService indicating where to send228 :param service: LaunchpadService indicating where to send the request.
268 the request and the authentication credentials.
269 """229 """
270 return service.send_request(self._methodname, self._request_params(),230 return service.send_request(self._methodname, self._request_params())
271 self._authenticated)
272231
273232
274class DryRunLaunchpadService(LaunchpadService):233class DryRunLaunchpadService(LaunchpadService):
275 """Service that just absorbs requests without sending to server.234 """Service that just absorbs requests without sending to server."""
276235
277 The dummy service does not need authentication.236 def send_request(self, method_name, method_params):
278 """237 pass
279
280 def send_request(self, method_name, method_params, authenticated):
281 pass
282
283 def gather_user_credentials(self):
284 pass
285
286
287class BranchRegistrationRequest(BaseRequest):
288 """Request to tell Launchpad about a bzr branch."""
289
290 _methodname = 'register_branch'
291
292 def __init__(self, branch_url,
293 branch_name='',
294 branch_title='',
295 branch_description='',
296 author_email='',
297 product_name='',
298 ):
299 if not branch_url:
300 raise errors.InvalidURL(branch_url, "You need to specify a non-empty branch URL.")
301 self.branch_url = branch_url
302 if branch_name:
303 self.branch_name = branch_name
304 else:
305 self.branch_name = self._find_default_branch_name(self.branch_url)
306 self.branch_title = branch_title
307 self.branch_description = branch_description
308 self.author_email = author_email
309 self.product_name = product_name
310
311 def _request_params(self):
312 """Return xmlrpc request parameters"""
313 # This must match the parameter tuple expected by Launchpad for this
314 # method
315 return (self.branch_url,
316 self.branch_name,
317 self.branch_title,
318 self.branch_description,
319 self.author_email,
320 self.product_name,
321 )
322
323 def _find_default_branch_name(self, branch_url):
324 i = branch_url.rfind('/')
325 return branch_url[i+1:]
326
327
328class BranchBugLinkRequest(BaseRequest):
329 """Request to link a bzr branch in Launchpad to a bug."""
330
331 _methodname = 'link_branch_to_bug'
332
333 def __init__(self, branch_url, bug_id):
334 self.bug_id = bug_id
335 self.branch_url = branch_url
336
337 def _request_params(self):
338 """Return xmlrpc request parameters"""
339 # This must match the parameter tuple expected by Launchpad for this
340 # method
341 return (self.branch_url, self.bug_id, '')
342238
343239
344class ResolveLaunchpadPathRequest(BaseRequest):240class ResolveLaunchpadPathRequest(BaseRequest):
345 """Request to resolve the path component of an lp: URL."""241 """Request to resolve the path component of an lp: URL."""
346242
347 _methodname = 'resolve_lp_path'243 _methodname = 'resolve_lp_path'
348 _authenticated = False
349244
350 def __init__(self, path):245 def __init__(self, path):
351 if not path:246 if not path:
352247
=== modified file 'bzrlib/plugins/launchpad/test_register.py'
--- bzrlib/plugins/launchpad/test_register.py 2016-02-01 18:06:32 +0000
+++ bzrlib/plugins/launchpad/test_register.py 2017-05-23 12:36:28 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2006-2012, 2016 Canonical Ltd1# Copyright (C) 2006-2012, 2016-2017 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -16,21 +16,13 @@
1616
17import base6417import base64
18from StringIO import StringIO18from StringIO import StringIO
19import urlparse
20import xmlrpclib19import xmlrpclib
2120
22from bzrlib import (
23 config,
24 tests,
25 ui,
26 )
27from bzrlib.tests import TestCaseWithTransport21from bzrlib.tests import TestCaseWithTransport
2822
29# local import23# local import
30from bzrlib.plugins.launchpad.lp_registration import (24from bzrlib.plugins.launchpad.lp_registration import (
31 BaseRequest,25 BaseRequest,
32 BranchBugLinkRequest,
33 BranchRegistrationRequest,
34 ResolveLaunchpadPathRequest,26 ResolveLaunchpadPathRequest,
35 LaunchpadService,27 LaunchpadService,
36 )28 )
@@ -41,11 +33,6 @@
41# the results passed in. Not sure how to get the transport object back out to33# the results passed in. Not sure how to get the transport object back out to
42# validate that its OK - may not be necessary.34# validate that its OK - may not be necessary.
4335
44# TODO: Add test for (and implement) other command-line options to set
45# project, author_email, description.
46
47# TODO: project_id is not properly handled -- must be passed in rpc or path.
48
49class InstrumentedXMLRPCConnection(object):36class InstrumentedXMLRPCConnection(object):
50 """Stands in place of an http connection for the purposes of testing"""37 """Stands in place of an http connection for the purposes of testing"""
5138
@@ -102,25 +89,15 @@
102 # Python 2.5's xmlrpclib looks for this.89 # Python 2.5's xmlrpclib looks for this.
103 _use_datetime = False90 _use_datetime = False
10491
105 def __init__(self, testcase, expect_auth):92 def __init__(self, testcase):
106 self.testcase = testcase93 self.testcase = testcase
107 self.expect_auth = expect_auth
108 self._connection = (None, None)94 self._connection = (None, None)
10995
110 def make_connection(self, host):96 def make_connection(self, host):
111 host, http_headers, x509 = self.get_host_info(host)97 host, http_headers, x509 = self.get_host_info(host)
112 test = self.testcase98 test = self.testcase
113 self.connected_host = host99 self.connected_host = host
114 if self.expect_auth:100 if http_headers:
115 auth_hdrs = [v for k,v in http_headers if k == 'Authorization']
116 if len(auth_hdrs) != 1:
117 raise AssertionError("multiple auth headers: %r"
118 % (auth_hdrs,))
119 authinfo = auth_hdrs[0]
120 expected_auth = 'testuser@launchpad.net:testpassword'
121 test.assertEqual(authinfo,
122 'Basic ' + base64.encodestring(expected_auth).strip())
123 elif http_headers:
124 raise AssertionError()101 raise AssertionError()
125 return InstrumentedXMLRPCConnection(test)102 return InstrumentedXMLRPCConnection(test)
126103
@@ -146,80 +123,22 @@
146123
147class MockLaunchpadService(LaunchpadService):124class MockLaunchpadService(LaunchpadService):
148125
149 def send_request(self, method_name, method_params, authenticated):126 def send_request(self, method_name, method_params):
150 """Stash away the method details rather than sending them to a real server"""127 """Stash away the method details rather than sending them to a real server"""
151 self.called_method_name = method_name128 self.called_method_name = method_name
152 self.called_method_params = method_params129 self.called_method_params = method_params
153 self.called_authenticated = authenticated130
154131
155132class TestResolveLaunchpadPathRequest(TestCaseWithTransport):
156class TestBranchRegistration(TestCaseWithTransport):
157133
158 def setUp(self):134 def setUp(self):
159 super(TestBranchRegistration, self).setUp()135 super(TestResolveLaunchpadPathRequest, self).setUp()
160 # make sure we have a reproducible standard environment136 # make sure we have a reproducible standard environment
161 self.overrideEnv('BZR_LP_XMLRPC_URL', None)137 self.overrideEnv('BZR_LP_XMLRPC_URL', None)
162138
163 def test_register_help(self):
164 """register-branch accepts --help"""
165 out, err = self.run_bzr(['register-branch', '--help'])
166 self.assertContainsRe(out, r'Register a branch')
167
168 def test_register_no_url_no_branch(self):
169 """register-branch command requires parameters"""
170 self.make_repository('.')
171 self.run_bzr_error(
172 ['register-branch requires a public branch url - '
173 'see bzr help register-branch'],
174 'register-branch')
175
176 def test_register_no_url_in_published_branch_no_error(self):
177 b = self.make_branch('.')
178 b.set_public_branch('http://test-server.com/bzr/branch')
179 out, err = self.run_bzr(['register-branch', '--dry-run'])
180 self.assertEqual('Branch registered.\n', out)
181 self.assertEqual('', err)
182
183 def test_register_no_url_in_unpublished_branch_errors(self):
184 b = self.make_branch('.')
185 out, err = self.run_bzr_error(['no public branch'],
186 ['register-branch', '--dry-run'])
187 self.assertEqual('', out)
188
189 def test_register_dry_run(self):
190 out, err = self.run_bzr(['register-branch',
191 'http://test-server.com/bzr/branch',
192 '--dry-run'])
193 self.assertEqual(out, 'Branch registered.\n')
194
195 def test_onto_transport(self):139 def test_onto_transport(self):
196 """How the request is sent by transmitting across a mock Transport"""140 """A request is transmitted across a mock Transport"""
197 # use a real transport, but intercept at the http/xml layer141 transport = InstrumentedXMLRPCTransport(self)
198 transport = InstrumentedXMLRPCTransport(self, expect_auth=True)
199 service = LaunchpadService(transport)
200 service.registrant_email = 'testuser@launchpad.net'
201 service.registrant_password = 'testpassword'
202 rego = BranchRegistrationRequest('http://test-server.com/bzr/branch',
203 'branch-id',
204 'my test branch',
205 'description',
206 'author@launchpad.net',
207 'product')
208 rego.submit(service)
209 self.assertEqual(transport.connected_host, 'xmlrpc.launchpad.net')
210 self.assertEqual(len(transport.sent_params), 6)
211 self.assertEqual(transport.sent_params,
212 ('http://test-server.com/bzr/branch', # branch_url
213 'branch-id', # branch_name
214 'my test branch', # branch_title
215 'description',
216 'author@launchpad.net',
217 'product'))
218 self.assertTrue(transport.got_request)
219
220 def test_onto_transport_unauthenticated(self):
221 """An unauthenticated request is transmitted across a mock Transport"""
222 transport = InstrumentedXMLRPCTransport(self, expect_auth=False)
223 service = LaunchpadService(transport)142 service = LaunchpadService(transport)
224 resolve = ResolveLaunchpadPathRequest('bzr')143 resolve = ResolveLaunchpadPathRequest('bzr')
225 resolve.submit(service)144 resolve.submit(service)
@@ -243,59 +162,12 @@
243 self.assertEqual(service.called_method_name, 'dummy_request')162 self.assertEqual(service.called_method_name, 'dummy_request')
244 self.assertEqual(service.called_method_params, (42,))163 self.assertEqual(service.called_method_params, (42,))
245164
246 def test_mock_server_registration(self):
247 """Send registration to mock server"""
248 test_case = self
249 class MockRegistrationService(MockLaunchpadService):
250 def send_request(self, method_name, method_params, authenticated):
251 test_case.assertEqual(method_name, "register_branch")
252 test_case.assertEqual(list(method_params),
253 ['url', 'name', 'title', 'description', 'email', 'name'])
254 test_case.assertEqual(authenticated, True)
255 return 'result'
256 service = MockRegistrationService()
257 rego = BranchRegistrationRequest('url', 'name', 'title',
258 'description', 'email', 'name')
259 result = rego.submit(service)
260 self.assertEqual(result, 'result')
261
262 def test_mock_server_registration_with_defaults(self):
263 """Send registration to mock server"""
264 test_case = self
265 class MockRegistrationService(MockLaunchpadService):
266 def send_request(self, method_name, method_params, authenticated):
267 test_case.assertEqual(method_name, "register_branch")
268 test_case.assertEqual(list(method_params),
269 ['http://server/branch', 'branch', '', '', '', ''])
270 test_case.assertEqual(authenticated, True)
271 return 'result'
272 service = MockRegistrationService()
273 rego = BranchRegistrationRequest('http://server/branch')
274 result = rego.submit(service)
275 self.assertEqual(result, 'result')
276
277 def test_mock_bug_branch_link(self):
278 """Send bug-branch link to mock server"""
279 test_case = self
280 class MockService(MockLaunchpadService):
281 def send_request(self, method_name, method_params, authenticated):
282 test_case.assertEqual(method_name, "link_branch_to_bug")
283 test_case.assertEqual(list(method_params),
284 ['http://server/branch', 1234, ''])
285 test_case.assertEqual(authenticated, True)
286 return 'http://launchpad.net/bug/1234'
287 service = MockService()
288 rego = BranchBugLinkRequest('http://server/branch', 1234)
289 result = rego.submit(service)
290 self.assertEqual(result, 'http://launchpad.net/bug/1234')
291
292 def test_mock_resolve_lp_url(self):165 def test_mock_resolve_lp_url(self):
293 test_case = self166 test_case = self
294 class MockService(MockLaunchpadService):167 class MockService(MockLaunchpadService):
295 def send_request(self, method_name, method_params, authenticated):168 def send_request(self, method_name, method_params):
296 test_case.assertEqual(method_name, "resolve_lp_path")169 test_case.assertEqual(method_name, "resolve_lp_path")
297 test_case.assertEqual(list(method_params), ['bzr'])170 test_case.assertEqual(list(method_params), ['bzr'])
298 test_case.assertEqual(authenticated, False)
299 return dict(urls=[171 return dict(urls=[
300 'bzr+ssh://bazaar.launchpad.net~bzr/bzr/trunk',172 'bzr+ssh://bazaar.launchpad.net~bzr/bzr/trunk',
301 'sftp://bazaar.launchpad.net~bzr/bzr/trunk',173 'sftp://bazaar.launchpad.net~bzr/bzr/trunk',
@@ -310,61 +182,3 @@
310 'sftp://bazaar.launchpad.net~bzr/bzr/trunk',182 'sftp://bazaar.launchpad.net~bzr/bzr/trunk',
311 'bzr+http://bazaar.launchpad.net~bzr/bzr/trunk',183 'bzr+http://bazaar.launchpad.net~bzr/bzr/trunk',
312 'http://bazaar.launchpad.net~bzr/bzr/trunk'])184 'http://bazaar.launchpad.net~bzr/bzr/trunk'])
313
314
315class TestGatherUserCredentials(tests.TestCaseInTempDir):
316
317 def setUp(self):
318 super(TestGatherUserCredentials, self).setUp()
319 # make sure we have a reproducible standard environment
320 self.overrideEnv('BZR_LP_XMLRPC_URL', None)
321
322 def test_gather_user_credentials_has_password(self):
323 service = LaunchpadService()
324 service.registrant_password = 'mypassword'
325 # This should be a basic no-op, since we already have the password
326 service.gather_user_credentials()
327 self.assertEqual('mypassword', service.registrant_password)
328
329 def test_gather_user_credentials_from_auth_conf(self):
330 auth_path = config.authentication_config_filename()
331 service = LaunchpadService()
332 g_conf = config.GlobalStack()
333 g_conf.set('email', 'Test User <test@user.com>')
334 g_conf.store.save()
335 # FIXME: auth_path base dir exists only because bazaar.conf has just
336 # been saved, brittle... -- vila 20120731
337 f = open(auth_path, 'wb')
338 try:
339 scheme, hostinfo = urlparse.urlsplit(service.service_url)[:2]
340 f.write('[section]\n'
341 'scheme=%s\n'
342 'host=%s\n'
343 'user=test@user.com\n'
344 'password=testpass\n'
345 % (scheme, hostinfo))
346 finally:
347 f.close()
348 self.assertIs(None, service.registrant_password)
349 service.gather_user_credentials()
350 self.assertEqual('test@user.com', service.registrant_email)
351 self.assertEqual('testpass', service.registrant_password)
352
353 def test_gather_user_credentials_prompts(self):
354 service = LaunchpadService()
355 self.assertIs(None, service.registrant_password)
356 g_conf = config.GlobalStack()
357 g_conf.set('email', 'Test User <test@user.com>')
358 g_conf.store.save()
359 stdout = tests.StringIOWrapper()
360 stderr = tests.StringIOWrapper()
361 ui.ui_factory = tests.TestUIFactory(stdin='userpass\n',
362 stdout=stdout, stderr=stderr)
363 self.assertIs(None, service.registrant_password)
364 service.gather_user_credentials()
365 self.assertEqual('test@user.com', service.registrant_email)
366 self.assertEqual('userpass', service.registrant_password)
367 self.assertEqual('', stdout.getvalue())
368 self.assertContainsRe(stderr.getvalue(),
369 'launchpad.net password for test@user\\.com')
370
371185
=== modified file 'doc/en/release-notes/bzr-2.8.txt'
--- doc/en/release-notes/bzr-2.8.txt 2017-03-17 10:39:02 +0000
+++ doc/en/release-notes/bzr-2.8.txt 2017-05-23 12:36:28 +0000
@@ -15,6 +15,15 @@
1515
16.. These may require users to change the way they use Bazaar.16.. These may require users to change the way they use Bazaar.
1717
18 * The ``bzr register-branch`` command from the Launchpad plugin has been
19 removed, because it has not worked for at least five years: it relies on
20 password authentication rather than SSO, the relevant systems no longer
21 have firewall-level access to the outside world, and in general the
22 Mirrored branch type is deprecated. Either just push the branch to
23 Launchpad or use code imports instead
24 (https://help.launchpad.net/VcsImports).
25 (Colin Watson, #254567, #483689)
26
18New Features27New Features
19************28************
2029