186
171
message='first commit')
187
172
self.run_bzr('push -d from to-one')
188
173
self.failUnlessExists('to-one')
189
self.run_bzr('push -d %s %s'
174
self.run_bzr('push -d %s %s'
190
175
% tuple(map(urlutils.local_path_to_url, ['from', 'to-two'])))
191
176
self.failUnlessExists('to-two')
193
def test_push_smart_non_stacked_streaming_acceptance(self):
194
self.setup_smart_server_with_call_log()
195
t = self.make_branch_and_tree('from')
196
t.commit(allow_pointless=True, message='first commit')
197
self.reset_smart_call_log()
198
self.run_bzr(['push', self.get_url('to-one')], working_dir='from')
199
# This figure represent the amount of work to perform this use case. It
200
# is entirely ok to reduce this number if a test fails due to rpc_count
201
# being too low. If rpc_count increases, more network roundtrips have
202
# become necessary for this use case. Please do not adjust this number
203
# upwards without agreement from bzr's network support maintainers.
204
self.assertLength(20, self.hpss_calls)
206
def test_push_smart_stacked_streaming_acceptance(self):
207
self.setup_smart_server_with_call_log()
208
parent = self.make_branch_and_tree('parent', format='1.9')
209
parent.commit(message='first commit')
210
local = parent.bzrdir.sprout('local').open_workingtree()
211
local.commit(message='local commit')
212
self.reset_smart_call_log()
213
self.run_bzr(['push', '--stacked', '--stacked-on', '../parent',
214
self.get_url('public')], working_dir='local')
215
# This figure represent the amount of work to perform this use case. It
216
# is entirely ok to reduce this number if a test fails due to rpc_count
217
# being too low. If rpc_count increases, more network roundtrips have
218
# become necessary for this use case. Please do not adjust this number
219
# upwards without agreement from bzr's network support maintainers.
220
self.assertLength(42, self.hpss_calls)
221
remote = Branch.open('public')
222
self.assertEndsWith(remote.get_stacked_on_url(), '/parent')
224
178
def create_simple_tree(self):
225
179
tree = self.make_branch_and_tree('tree')
226
180
self.build_tree(['tree/a'])
290
244
self.run_bzr_error(['At ../dir you have a valid .bzr control'],
292
246
working_dir='tree')
294
def test_push_with_revisionspec(self):
295
"""We should be able to push a revision older than the tip."""
296
tree_from = self.make_branch_and_tree('from')
297
tree_from.commit("One.", rev_id="from-1")
298
tree_from.commit("Two.", rev_id="from-2")
300
self.run_bzr('push -r1 ../to', working_dir='from')
302
tree_to = WorkingTree.open('to')
303
repo_to = tree_to.branch.repository
304
self.assertTrue(repo_to.has_revision('from-1'))
305
self.assertFalse(repo_to.has_revision('from-2'))
306
self.assertEqual(tree_to.branch.last_revision_info()[1], 'from-1')
309
"bzr: ERROR: bzr push --revision takes one value.\n",
310
'push -r0..2 ../to', working_dir='from')
312
def create_trunk_and_feature_branch(self):
314
trunk_tree = self.make_branch_and_tree('target',
315
format='development')
316
trunk_tree.commit('mainline')
317
# and a branch from it
318
branch_tree = self.make_branch_and_tree('branch',
319
format='development')
320
branch_tree.pull(trunk_tree.branch)
321
branch_tree.branch.set_parent(trunk_tree.branch.base)
322
# with some work on it
323
branch_tree.commit('moar work plz')
324
return trunk_tree, branch_tree
326
def assertPublished(self, branch_revid, stacked_on):
327
"""Assert that the branch 'published' has been published correctly."""
328
published_branch = Branch.open('published')
329
# The published branch refers to the mainline
330
self.assertEqual(stacked_on, published_branch.get_stacked_on_url())
331
# and the branch's work was pushed
332
self.assertTrue(published_branch.repository.has_revision(branch_revid))
334
def test_push_new_branch_stacked_on(self):
335
"""Pushing a new branch with --stacked-on creates a stacked branch."""
336
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
337
# we publish branch_tree with a reference to the mainline.
338
out, err = self.run_bzr(['push', '--stacked-on', trunk_tree.branch.base,
339
self.get_url('published')], working_dir='branch')
340
self.assertEqual('', out)
341
self.assertEqual('Created new stacked branch referring to %s.\n' %
342
trunk_tree.branch.base, err)
343
self.assertPublished(branch_tree.last_revision(),
344
trunk_tree.branch.base)
346
def test_push_new_branch_stacked_uses_parent_when_no_public_url(self):
347
"""When the parent has no public url the parent is used as-is."""
348
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
349
# now we do a stacked push, which should determine the public location
351
out, err = self.run_bzr(['push', '--stacked',
352
self.get_url('published')], working_dir='branch')
353
self.assertEqual('', out)
354
self.assertEqual('Created new stacked branch referring to %s.\n' %
355
trunk_tree.branch.base, err)
356
self.assertPublished(branch_tree.last_revision(), trunk_tree.branch.base)
358
def test_push_new_branch_stacked_uses_parent_public(self):
359
"""Pushing a new branch with --stacked creates a stacked branch."""
360
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
361
# the trunk is published on a web server
362
self.transport_readonly_server = HttpServer
363
trunk_public = self.make_branch('public_trunk', format='development')
364
trunk_public.pull(trunk_tree.branch)
365
trunk_public_url = self.get_readonly_url('public_trunk')
366
trunk_tree.branch.set_public_branch(trunk_public_url)
367
# now we do a stacked push, which should determine the public location
369
out, err = self.run_bzr(['push', '--stacked',
370
self.get_url('published')], working_dir='branch')
371
self.assertEqual('', out)
372
self.assertEqual('Created new stacked branch referring to %s.\n' %
373
trunk_public_url, err)
374
self.assertPublished(branch_tree.last_revision(), trunk_public_url)
376
def test_push_new_branch_stacked_no_parent(self):
377
"""Pushing with --stacked and no parent branch errors."""
378
branch = self.make_branch_and_tree('branch', format='development')
379
# now we do a stacked push, which should fail as the place to refer too
380
# cannot be determined.
381
out, err = self.run_bzr_error(
382
['Could not determine branch to refer to\\.'], ['push', '--stacked',
383
self.get_url('published')], working_dir='branch')
384
self.assertEqual('', out)
385
self.assertFalse(self.get_transport('published').has('.'))
387
def test_push_notifies_default_stacking(self):
388
self.make_branch('stack_on', format='1.6')
389
self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
390
self.make_branch('from', format='1.6')
391
out, err = self.run_bzr('push -d from to')
392
self.assertContainsRe(err,
393
'Using default stacking branch stack_on at .*')
395
def test_push_stacks_with_default_stacking_if_target_is_stackable(self):
396
self.make_branch('stack_on', format='1.6')
397
self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
398
self.make_branch('from', format='pack-0.92')
399
out, err = self.run_bzr('push -d from to')
400
branch = Branch.open('to')
401
self.assertEqual('../stack_on', branch.get_stacked_on_url())
403
def test_push_does_not_change_format_with_default_if_target_cannot(self):
404
self.make_branch('stack_on', format='pack-0.92')
405
self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
406
self.make_branch('from', format='pack-0.92')
407
out, err = self.run_bzr('push -d from to')
408
branch = Branch.open('to')
409
self.assertRaises(errors.UnstackableBranchFormat,
410
branch.get_stacked_on_url)
412
def test_push_doesnt_create_broken_branch(self):
413
"""Pushing a new standalone branch works even when there's a default
414
stacking policy at the destination.
416
The new branch will preserve the repo format (even if it isn't the
417
default for the branch), and will be stacked when the repo format
418
allows (which means that the branch format isn't necessarly preserved).
420
self.make_repository('repo', shared=True, format='1.6')
421
builder = self.make_branch_builder('repo/local', format='pack-0.92')
422
builder.start_series()
423
builder.build_snapshot('rev-1', None, [
424
('add', ('', 'root-id', 'directory', '')),
425
('add', ('filename', 'f-id', 'file', 'content\n'))])
426
builder.build_snapshot('rev-2', ['rev-1'], [])
427
builder.build_snapshot('rev-3', ['rev-2'],
428
[('modify', ('f-id', 'new-content\n'))])
429
builder.finish_series()
430
branch = builder.get_branch()
431
# Push rev-1 to "trunk", so that we can stack on it.
432
self.run_bzr('push -d repo/local trunk -r 1')
433
# Set a default stacking policy so that new branches will automatically
435
self.make_bzrdir('.').get_config().set_default_stack_on('trunk')
436
# Push rev-2 to a new branch "remote". It will be stacked on "trunk".
437
out, err = self.run_bzr('push -d repo/local remote -r 2')
438
self.assertContainsRe(
439
err, 'Using default stacking branch trunk at .*')
440
# Push rev-3 onto "remote". If "remote" not stacked and is missing the
441
# fulltext record for f-id @ rev-1, then this will fail.
442
out, err = self.run_bzr('push -d repo/local remote -r 3')
444
def test_push_verbose_shows_log(self):
445
tree = self.make_branch_and_tree('source')
447
out, err = self.run_bzr('push -v -d source target')
448
# initial push contains log
449
self.assertContainsRe(out, 'rev1')
451
out, err = self.run_bzr('push -v -d source target')
452
# subsequent push contains log
453
self.assertContainsRe(out, 'rev2')
454
# subsequent log is accurate
455
self.assertNotContainsRe(out, 'rev1')
458
class RedirectingMemoryTransport(MemoryTransport):
460
def mkdir(self, relpath, mode=None):
461
from bzrlib.trace import mutter
462
mutter('cwd: %r, rel: %r, abs: %r' % (self._cwd, relpath, abspath))
463
if self._cwd == '/source/':
464
raise errors.RedirectRequested(self.abspath(relpath),
465
self.abspath('../target'),
467
elif self._cwd == '/infinite-loop/':
468
raise errors.RedirectRequested(self.abspath(relpath),
469
self.abspath('../infinite-loop'),
472
return super(RedirectingMemoryTransport, self).mkdir(
475
def _redirected_to(self, source, target):
476
# We do accept redirections
477
return transport.get_transport(target)
480
class RedirectingMemoryServer(MemoryServer):
483
self._dirs = {'/': None}
486
self._scheme = 'redirecting-memory+%s:///' % id(self)
487
transport.register_transport(self._scheme, self._memory_factory)
489
def _memory_factory(self, url):
490
result = RedirectingMemoryTransport(url)
491
result._dirs = self._dirs
492
result._files = self._files
493
result._locks = self._locks
497
transport.unregister_transport(self._scheme, self._memory_factory)
500
class TestPushRedirect(ExternalBase):
503
ExternalBase.setUp(self)
504
self.memory_server = RedirectingMemoryServer()
505
self.memory_server.setUp()
506
self.addCleanup(self.memory_server.tearDown)
508
# Make the branch and tree that we'll be pushing.
509
t = self.make_branch_and_tree('tree')
510
self.build_tree(['tree/file'])
514
def test_push_redirects_on_mkdir(self):
515
"""If the push requires a mkdir, push respects redirect requests.
517
This is added primarily to handle lp:/ URI support, so that users can
518
push to new branches by specifying lp:/ URIs.
520
destination_url = self.memory_server.get_url() + 'source'
521
self.run_bzr(['push', '-d', 'tree', destination_url])
523
local_revision = Branch.open('tree').last_revision()
524
remote_revision = Branch.open(
525
self.memory_server.get_url() + 'target').last_revision()
526
self.assertEqual(remote_revision, local_revision)
528
def test_push_gracefully_handles_too_many_redirects(self):
529
"""Push fails gracefully if the mkdir generates a large number of
532
destination_url = self.memory_server.get_url() + 'infinite-loop'
533
out, err = self.run_bzr_error(
534
['Too many redirections trying to make %s\\.\n'
535
% re.escape(destination_url)],
536
['push', '-d', 'tree', destination_url], retcode=3)
537
self.assertEqual('', out)