52
76
tree_b.commit('commit c')
53
77
# initial push location must be empty
54
78
self.assertEqual(None, branch_b.get_push_location())
55
80
# test push for failure without push location set
57
out = self.runbzr('push', retcode=3)
81
out = self.run_bzr('push', working_dir='branch_a', retcode=3)
58
82
self.assertEquals(out,
59
83
('','bzr: ERROR: No push location known or specified.\n'))
85
# test not remembered if cannot actually push
86
self.run_bzr('push path/which/doesnt/exist',
87
working_dir='branch_a', retcode=3)
88
out = self.run_bzr('push', working_dir='branch_a', retcode=3)
90
('', 'bzr: ERROR: No push location known or specified.\n'),
60
93
# test implicit --remember when no push location set, push fails
61
out = self.runbzr('push ../branch_b', retcode=3)
94
out = self.run_bzr('push ../branch_b',
95
working_dir='branch_a', retcode=3)
62
96
self.assertEquals(out,
63
97
('','bzr: ERROR: These branches have diverged. '
64
'Try a merge then push with overwrite.\n'))
65
self.assertEquals(abspath(branch_a.get_push_location()),
66
abspath(branch_b.bzrdir.root_transport.base))
98
'See "bzr help diverged-branches" for more information.\n'))
99
self.assertEquals(osutils.abspath(branch_a.get_push_location()),
100
osutils.abspath(branch_b.bzrdir.root_transport.base))
67
102
# test implicit --remember after resolving previous failure
68
uncommit(branch=branch_b, tree=tree_b)
103
uncommit.uncommit(branch=branch_b, tree=tree_b)
69
104
transport.delete('branch_b/c')
71
self.assertEquals(abspath(branch_a.get_push_location()),
72
abspath(branch_b.bzrdir.root_transport.base))
105
out, err = self.run_bzr('push', working_dir='branch_a')
106
path = branch_a.get_push_location()
107
self.assertEqual(err,
108
'Using saved push location: %s\n'
109
'All changes applied successfully.\n'
110
'Pushed up to revision 2.\n'
111
% urlutils.local_path_from_url(path))
112
self.assertEqual(path,
113
branch_b.bzrdir.root_transport.base)
73
114
# test explicit --remember
74
self.runbzr('push ../branch_c --remember')
75
self.assertEquals(abspath(branch_a.get_push_location()),
76
abspath(branch_c.bzrdir.root_transport.base))
115
self.run_bzr('push ../branch_c --remember', working_dir='branch_a')
116
self.assertEquals(branch_a.get_push_location(),
117
branch_c.bzrdir.root_transport.base)
78
119
def test_push_without_tree(self):
79
120
# bzr push from a branch that does not have a checkout should work.
80
121
b = self.make_branch('.')
81
out, err = self.run_bzr('push', 'pushed-location')
122
out, err = self.run_bzr('push pushed-location')
82
123
self.assertEqual('', out)
83
self.assertEqual('0 revision(s) pushed.\n', err)
84
b2 = bzrlib.branch.Branch.open('pushed-location')
124
self.assertEqual('Created new branch.\n', err)
125
b2 = branch.Branch.open('pushed-location')
85
126
self.assertEndsWith(b2.base, 'pushed-location/')
128
def test_push_no_tree(self):
129
# bzr push --no-tree of a branch with working trees
130
b = self.make_branch_and_tree('push-from')
131
self.build_tree(['push-from/file'])
134
out, err = self.run_bzr('push --no-tree -d push-from push-to')
135
self.assertEqual('', out)
136
self.assertEqual('Created new branch.\n', err)
137
self.assertPathDoesNotExist('push-to/file')
87
139
def test_push_new_branch_revision_count(self):
88
# bzr push of a branch with revisions to a new location
89
# should print the number of revisions equal to the length of the
140
# bzr push of a branch with revisions to a new location
141
# should print the number of revisions equal to the length of the
91
143
t = self.make_branch_and_tree('tree')
92
144
self.build_tree(['tree/file'])
94
146
t.commit('commit 1')
96
out, err = self.run_bzr('push', 'pushed-to')
98
self.assertEqual('', out)
99
self.assertEqual('1 revision(s) pushed.\n', err)
147
out, err = self.run_bzr('push -d tree pushed-to')
148
self.assertEqual('', out)
149
self.assertEqual('Created new branch.\n', err)
151
def test_push_quiet(self):
152
# test that using -q makes output quiet
153
t = self.make_branch_and_tree('tree')
154
self.build_tree(['tree/file'])
157
self.run_bzr('push -d tree pushed-to')
158
path = t.branch.get_push_location()
159
out, err = self.run_bzr('push', working_dir="tree")
160
self.assertEqual('Using saved push location: %s\n'
161
'No new revisions or tags to push.\n' %
162
urlutils.local_path_from_url(path), err)
163
out, err = self.run_bzr('push -q', working_dir="tree")
164
self.assertEqual('', out)
165
self.assertEqual('', err)
101
167
def test_push_only_pushes_history(self):
102
168
# Knit branches should only push the history for the current revision.
103
format = BzrDirMetaFormat1()
104
format.repository_format = RepositoryFormatKnit1()
169
format = bzrdir.BzrDirMetaFormat1()
170
format.repository_format = knitrepo.RepositoryFormatKnit1()
105
171
shared_repo = self.make_repository('repo', format=format, shared=True)
106
172
shared_repo.set_make_working_trees(True)
108
174
def make_shared_tree(path):
109
175
shared_repo.bzrdir.root_transport.mkdir(path)
110
176
shared_repo.bzrdir.create_branch_convenience('repo/' + path)
111
return WorkingTree.open('repo/' + path)
177
return workingtree.WorkingTree.open('repo/' + path)
112
178
tree_a = make_shared_tree('a')
113
179
self.build_tree(['repo/a/file'])
114
180
tree_a.add('file')
130
196
# Now that we have a repository with shared files, make sure
131
197
# that things aren't copied out by a 'push'
133
self.run_bzr('push', '../../push-b')
134
pushed_tree = WorkingTree.open('../../push-b')
198
self.run_bzr('push ../../push-b', working_dir='repo/b')
199
pushed_tree = workingtree.WorkingTree.open('push-b')
135
200
pushed_repo = pushed_tree.branch.repository
136
201
self.assertFalse(pushed_repo.has_revision('a-1'))
137
202
self.assertFalse(pushed_repo.has_revision('a-2'))
138
203
self.assertTrue(pushed_repo.has_revision('b-1'))
205
def test_push_funky_id(self):
206
t = self.make_branch_and_tree('tree')
207
self.build_tree(['tree/filename'])
208
t.add('filename', 'funky-chars<>%&;"\'')
209
t.commit('commit filename')
210
self.run_bzr('push -d tree new-tree')
212
def test_push_dash_d(self):
213
t = self.make_branch_and_tree('from')
214
t.commit(allow_pointless=True,
215
message='first commit')
216
self.run_bzr('push -d from to-one')
217
self.assertPathExists('to-one')
218
self.run_bzr('push -d %s %s'
219
% tuple(map(urlutils.local_path_to_url, ['from', 'to-two'])))
220
self.assertPathExists('to-two')
222
def test_push_repository_no_branch_doesnt_fetch_all_revs(self):
223
# See https://bugs.launchpad.net/bzr/+bug/465517
224
target_repo = self.make_repository('target')
225
source = self.make_branch_builder('source')
226
source.start_series()
227
source.build_snapshot('A', None, [
228
('add', ('', 'root-id', 'directory', None))])
229
source.build_snapshot('B', ['A'], [])
230
source.build_snapshot('C', ['A'], [])
231
source.finish_series()
232
self.run_bzr('push target -d source')
233
self.addCleanup(target_repo.lock_read().unlock)
234
# We should have pushed 'C', but not 'B', since it isn't in the
236
self.assertEqual([('A',), ('C',)], sorted(target_repo.revisions.keys()))
238
def test_push_smart_non_stacked_streaming_acceptance(self):
239
self.setup_smart_server_with_call_log()
240
t = self.make_branch_and_tree('from')
241
t.commit(allow_pointless=True, message='first commit')
242
self.reset_smart_call_log()
243
self.run_bzr(['push', self.get_url('to-one')], working_dir='from')
244
# This figure represent the amount of work to perform this use case. It
245
# is entirely ok to reduce this number if a test fails due to rpc_count
246
# being too low. If rpc_count increases, more network roundtrips have
247
# become necessary for this use case. Please do not adjust this number
248
# upwards without agreement from bzr's network support maintainers.
249
self.assertLength(9, self.hpss_calls)
251
def test_push_smart_stacked_streaming_acceptance(self):
252
self.setup_smart_server_with_call_log()
253
parent = self.make_branch_and_tree('parent', format='1.9')
254
parent.commit(message='first commit')
255
local = parent.bzrdir.sprout('local').open_workingtree()
256
local.commit(message='local commit')
257
self.reset_smart_call_log()
258
self.run_bzr(['push', '--stacked', '--stacked-on', '../parent',
259
self.get_url('public')], working_dir='local')
260
# This figure represent the amount of work to perform this use case. It
261
# is entirely ok to reduce this number if a test fails due to rpc_count
262
# being too low. If rpc_count increases, more network roundtrips have
263
# become necessary for this use case. Please do not adjust this number
264
# upwards without agreement from bzr's network support maintainers.
265
self.assertLength(13, self.hpss_calls)
266
remote = branch.Branch.open('public')
267
self.assertEndsWith(remote.get_stacked_on_url(), '/parent')
269
def test_push_smart_tags_streaming_acceptance(self):
270
self.setup_smart_server_with_call_log()
271
t = self.make_branch_and_tree('from')
272
rev_id = t.commit(allow_pointless=True, message='first commit')
273
t.branch.tags.set_tag('new-tag', rev_id)
274
self.reset_smart_call_log()
275
self.run_bzr(['push', self.get_url('to-one')], working_dir='from')
276
# This figure represent the amount of work to perform this use case. It
277
# is entirely ok to reduce this number if a test fails due to rpc_count
278
# being too low. If rpc_count increases, more network roundtrips have
279
# become necessary for this use case. Please do not adjust this number
280
# upwards without agreement from bzr's network support maintainers.
281
self.assertLength(11, self.hpss_calls)
283
def test_push_smart_incremental_acceptance(self):
284
self.setup_smart_server_with_call_log()
285
t = self.make_branch_and_tree('from')
286
rev_id1 = t.commit(allow_pointless=True, message='first commit')
287
rev_id2 = t.commit(allow_pointless=True, message='second commit')
289
['push', self.get_url('to-one'), '-r1'], working_dir='from')
290
self.reset_smart_call_log()
291
self.run_bzr(['push', self.get_url('to-one')], working_dir='from')
292
# This figure represent the amount of work to perform this use case. It
293
# is entirely ok to reduce this number if a test fails due to rpc_count
294
# being too low. If rpc_count increases, more network roundtrips have
295
# become necessary for this use case. Please do not adjust this number
296
# upwards without agreement from bzr's network support maintainers.
297
self.assertLength(11, self.hpss_calls)
299
def test_push_smart_with_default_stacking_url_path_segment(self):
300
# If the default stacked-on location is a path element then branches
301
# we push there over the smart server are stacked and their
302
# stacked_on_url is that exact path segment. Added to nail bug 385132.
303
self.setup_smart_server_with_call_log()
304
self.make_branch('stack-on', format='1.9')
305
self.make_bzrdir('.').get_config().set_default_stack_on(
307
self.make_branch('from', format='1.9')
308
out, err = self.run_bzr(['push', '-d', 'from', self.get_url('to')])
309
b = branch.Branch.open(self.get_url('to'))
310
self.assertEqual('/extra/stack-on', b.get_stacked_on_url())
312
def test_push_smart_with_default_stacking_relative_path(self):
313
# If the default stacked-on location is a relative path then branches
314
# we push there over the smart server are stacked and their
315
# stacked_on_url is a relative path. Added to nail bug 385132.
316
self.setup_smart_server_with_call_log()
317
self.make_branch('stack-on', format='1.9')
318
self.make_bzrdir('.').get_config().set_default_stack_on('stack-on')
319
self.make_branch('from', format='1.9')
320
out, err = self.run_bzr(['push', '-d', 'from', self.get_url('to')])
321
b = branch.Branch.open(self.get_url('to'))
322
self.assertEqual('../stack-on', b.get_stacked_on_url())
324
def create_simple_tree(self):
325
tree = self.make_branch_and_tree('tree')
326
self.build_tree(['tree/a'])
327
tree.add(['a'], ['a-id'])
328
tree.commit('one', rev_id='r1')
331
def test_push_create_prefix(self):
332
"""'bzr push --create-prefix' will create leading directories."""
333
tree = self.create_simple_tree()
335
self.run_bzr_error(['Parent directory of ../new/tree does not exist'],
338
self.run_bzr('push ../new/tree --create-prefix',
340
new_tree = workingtree.WorkingTree.open('new/tree')
341
self.assertEqual(tree.last_revision(), new_tree.last_revision())
342
self.assertPathExists('new/tree/a')
344
def test_push_use_existing(self):
345
"""'bzr push --use-existing-dir' can push into an existing dir.
347
By default, 'bzr push' will not use an existing, non-versioned dir.
349
tree = self.create_simple_tree()
350
self.build_tree(['target/'])
352
self.run_bzr_error(['Target directory ../target already exists',
353
'Supply --use-existing-dir',
355
'push ../target', working_dir='tree')
357
self.run_bzr('push --use-existing-dir ../target',
360
new_tree = workingtree.WorkingTree.open('target')
361
self.assertEqual(tree.last_revision(), new_tree.last_revision())
362
# The push should have created target/a
363
self.assertPathExists('target/a')
365
def test_push_use_existing_into_empty_bzrdir(self):
366
"""'bzr push --use-existing-dir' into a dir with an empty .bzr dir
369
tree = self.create_simple_tree()
370
self.build_tree(['target/', 'target/.bzr/'])
372
['Target directory ../target already contains a .bzr directory, '
373
'but it is not valid.'],
374
'push ../target --use-existing-dir', working_dir='tree')
376
def test_push_onto_repo(self):
377
"""We should be able to 'bzr push' into an existing bzrdir."""
378
tree = self.create_simple_tree()
379
repo = self.make_repository('repo', shared=True)
381
self.run_bzr('push ../repo',
384
# Pushing onto an existing bzrdir will create a repository and
385
# branch as needed, but will only create a working tree if there was
387
self.assertRaises(errors.NoWorkingTree,
388
workingtree.WorkingTree.open, 'repo')
389
new_branch = branch.Branch.open('repo')
390
self.assertEqual(tree.last_revision(), new_branch.last_revision())
392
def test_push_onto_just_bzrdir(self):
393
"""We don't handle when the target is just a bzrdir.
395
Because you shouldn't be able to create *just* a bzrdir in the wild.
397
# TODO: jam 20070109 Maybe it would be better to create the repository
399
tree = self.create_simple_tree()
400
a_bzrdir = self.make_bzrdir('dir')
402
self.run_bzr_error(['At ../dir you have a valid .bzr control'],
406
def test_push_with_revisionspec(self):
407
"""We should be able to push a revision older than the tip."""
408
tree_from = self.make_branch_and_tree('from')
409
tree_from.commit("One.", rev_id="from-1")
410
tree_from.commit("Two.", rev_id="from-2")
412
self.run_bzr('push -r1 ../to', working_dir='from')
414
tree_to = workingtree.WorkingTree.open('to')
415
repo_to = tree_to.branch.repository
416
self.assertTrue(repo_to.has_revision('from-1'))
417
self.assertFalse(repo_to.has_revision('from-2'))
418
self.assertEqual(tree_to.branch.last_revision_info()[1], 'from-1')
421
['bzr: ERROR: bzr push --revision '
422
'takes exactly one revision identifier\n'],
423
'push -r0..2 ../to', working_dir='from')
425
def create_trunk_and_feature_branch(self):
427
trunk_tree = self.make_branch_and_tree('target',
429
trunk_tree.commit('mainline')
430
# and a branch from it
431
branch_tree = self.make_branch_and_tree('branch',
433
branch_tree.pull(trunk_tree.branch)
434
branch_tree.branch.set_parent(trunk_tree.branch.base)
435
# with some work on it
436
branch_tree.commit('moar work plz')
437
return trunk_tree, branch_tree
439
def assertPublished(self, branch_revid, stacked_on):
440
"""Assert that the branch 'published' has been published correctly."""
441
published_branch = branch.Branch.open('published')
442
# The published branch refers to the mainline
443
self.assertEqual(stacked_on, published_branch.get_stacked_on_url())
444
# and the branch's work was pushed
445
self.assertTrue(published_branch.repository.has_revision(branch_revid))
447
def test_push_new_branch_stacked_on(self):
448
"""Pushing a new branch with --stacked-on creates a stacked branch."""
449
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
450
# we publish branch_tree with a reference to the mainline.
451
out, err = self.run_bzr(['push', '--stacked-on', trunk_tree.branch.base,
452
self.get_url('published')], working_dir='branch')
453
self.assertEqual('', out)
454
self.assertEqual('Created new stacked branch referring to %s.\n' %
455
trunk_tree.branch.base, err)
456
self.assertPublished(branch_tree.last_revision(),
457
trunk_tree.branch.base)
459
def test_push_new_branch_stacked_uses_parent_when_no_public_url(self):
460
"""When the parent has no public url the parent is used as-is."""
461
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
462
# now we do a stacked push, which should determine the public location
464
out, err = self.run_bzr(['push', '--stacked',
465
self.get_url('published')], working_dir='branch')
466
self.assertEqual('', out)
467
self.assertEqual('Created new stacked branch referring to %s.\n' %
468
trunk_tree.branch.base, err)
469
self.assertPublished(branch_tree.last_revision(),
470
trunk_tree.branch.base)
472
def test_push_new_branch_stacked_uses_parent_public(self):
473
"""Pushing a new branch with --stacked creates a stacked branch."""
474
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
475
# the trunk is published on a web server
476
self.transport_readonly_server = http_server.HttpServer
477
trunk_public = self.make_branch('public_trunk', format='1.9')
478
trunk_public.pull(trunk_tree.branch)
479
trunk_public_url = self.get_readonly_url('public_trunk')
480
trunk_tree.branch.set_public_branch(trunk_public_url)
481
# now we do a stacked push, which should determine the public location
483
out, err = self.run_bzr(['push', '--stacked',
484
self.get_url('published')], working_dir='branch')
485
self.assertEqual('', out)
486
self.assertEqual('Created new stacked branch referring to %s.\n' %
487
trunk_public_url, err)
488
self.assertPublished(branch_tree.last_revision(), trunk_public_url)
490
def test_push_new_branch_stacked_no_parent(self):
491
"""Pushing with --stacked and no parent branch errors."""
492
branch = self.make_branch_and_tree('branch', format='1.9')
493
# now we do a stacked push, which should fail as the place to refer too
494
# cannot be determined.
495
out, err = self.run_bzr_error(
496
['Could not determine branch to refer to\\.'], ['push', '--stacked',
497
self.get_url('published')], working_dir='branch')
498
self.assertEqual('', out)
499
self.assertFalse(self.get_transport('published').has('.'))
501
def test_push_notifies_default_stacking(self):
502
self.make_branch('stack_on', format='1.6')
503
self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
504
self.make_branch('from', format='1.6')
505
out, err = self.run_bzr('push -d from to')
506
self.assertContainsRe(err,
507
'Using default stacking branch stack_on at .*')
509
def test_push_stacks_with_default_stacking_if_target_is_stackable(self):
510
self.make_branch('stack_on', format='1.6')
511
self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
512
self.make_branch('from', format='pack-0.92')
513
out, err = self.run_bzr('push -d from to')
514
b = branch.Branch.open('to')
515
self.assertEqual('../stack_on', b.get_stacked_on_url())
517
def test_push_does_not_change_format_with_default_if_target_cannot(self):
518
self.make_branch('stack_on', format='pack-0.92')
519
self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
520
self.make_branch('from', format='pack-0.92')
521
out, err = self.run_bzr('push -d from to')
522
b = branch.Branch.open('to')
523
self.assertRaises(errors.UnstackableBranchFormat, b.get_stacked_on_url)
525
def test_push_doesnt_create_broken_branch(self):
526
"""Pushing a new standalone branch works even when there's a default
527
stacking policy at the destination.
529
The new branch will preserve the repo format (even if it isn't the
530
default for the branch), and will be stacked when the repo format
531
allows (which means that the branch format isn't necessarly preserved).
533
self.make_repository('repo', shared=True, format='1.6')
534
builder = self.make_branch_builder('repo/local', format='pack-0.92')
535
builder.start_series()
536
builder.build_snapshot('rev-1', None, [
537
('add', ('', 'root-id', 'directory', '')),
538
('add', ('filename', 'f-id', 'file', 'content\n'))])
539
builder.build_snapshot('rev-2', ['rev-1'], [])
540
builder.build_snapshot('rev-3', ['rev-2'],
541
[('modify', ('f-id', 'new-content\n'))])
542
builder.finish_series()
543
branch = builder.get_branch()
544
# Push rev-1 to "trunk", so that we can stack on it.
545
self.run_bzr('push -d repo/local trunk -r 1')
546
# Set a default stacking policy so that new branches will automatically
548
self.make_bzrdir('.').get_config().set_default_stack_on('trunk')
549
# Push rev-2 to a new branch "remote". It will be stacked on "trunk".
550
out, err = self.run_bzr('push -d repo/local remote -r 2')
551
self.assertContainsRe(
552
err, 'Using default stacking branch trunk at .*')
553
# Push rev-3 onto "remote". If "remote" not stacked and is missing the
554
# fulltext record for f-id @ rev-1, then this will fail.
555
out, err = self.run_bzr('push -d repo/local remote -r 3')
557
def test_push_verbose_shows_log(self):
558
tree = self.make_branch_and_tree('source')
560
out, err = self.run_bzr('push -v -d source target')
561
# initial push contains log
562
self.assertContainsRe(out, 'rev1')
564
out, err = self.run_bzr('push -v -d source target')
565
# subsequent push contains log
566
self.assertContainsRe(out, 'rev2')
567
# subsequent log is accurate
568
self.assertNotContainsRe(out, 'rev1')
570
def test_push_from_subdir(self):
571
t = self.make_branch_and_tree('tree')
572
self.build_tree(['tree/dir/', 'tree/dir/file'])
573
t.add('dir', 'dir/file')
575
out, err = self.run_bzr('push ../../pushloc', working_dir='tree/dir')
576
self.assertEqual('', out)
577
self.assertEqual('Created new branch.\n', err)
580
class RedirectingMemoryTransport(memory.MemoryTransport):
582
def mkdir(self, relpath, mode=None):
583
if self._cwd == '/source/':
584
raise errors.RedirectRequested(self.abspath(relpath),
585
self.abspath('../target'),
587
elif self._cwd == '/infinite-loop/':
588
raise errors.RedirectRequested(self.abspath(relpath),
589
self.abspath('../infinite-loop'),
592
return super(RedirectingMemoryTransport, self).mkdir(
595
def get(self, relpath):
596
if self.clone(relpath)._cwd == '/infinite-loop/':
597
raise errors.RedirectRequested(self.abspath(relpath),
598
self.abspath('../infinite-loop'),
601
return super(RedirectingMemoryTransport, self).get(relpath)
603
def _redirected_to(self, source, target):
604
# We do accept redirections
605
return transport.get_transport(target)
608
class RedirectingMemoryServer(memory.MemoryServer):
610
def start_server(self):
611
self._dirs = {'/': None}
614
self._scheme = 'redirecting-memory+%s:///' % id(self)
615
transport.register_transport(self._scheme, self._memory_factory)
617
def _memory_factory(self, url):
618
result = RedirectingMemoryTransport(url)
619
result._dirs = self._dirs
620
result._files = self._files
621
result._locks = self._locks
624
def stop_server(self):
625
transport.unregister_transport(self._scheme, self._memory_factory)
628
class TestPushRedirect(tests.TestCaseWithTransport):
631
tests.TestCaseWithTransport.setUp(self)
632
self.memory_server = RedirectingMemoryServer()
633
self.start_server(self.memory_server)
634
# Make the branch and tree that we'll be pushing.
635
t = self.make_branch_and_tree('tree')
636
self.build_tree(['tree/file'])
640
def test_push_redirects_on_mkdir(self):
641
"""If the push requires a mkdir, push respects redirect requests.
643
This is added primarily to handle lp:/ URI support, so that users can
644
push to new branches by specifying lp:/ URIs.
646
destination_url = self.memory_server.get_url() + 'source'
647
self.run_bzr(['push', '-d', 'tree', destination_url])
649
local_revision = branch.Branch.open('tree').last_revision()
650
remote_revision = branch.Branch.open(
651
self.memory_server.get_url() + 'target').last_revision()
652
self.assertEqual(remote_revision, local_revision)
654
def test_push_gracefully_handles_too_many_redirects(self):
655
"""Push fails gracefully if the mkdir generates a large number of
658
destination_url = self.memory_server.get_url() + 'infinite-loop'
659
out, err = self.run_bzr_error(
660
['Too many redirections trying to make %s\\.\n'
661
% re.escape(destination_url)],
662
['push', '-d', 'tree', destination_url], retcode=3)
663
self.assertEqual('', out)
666
class TestPushStrictMixin(object):
668
def make_local_branch_and_tree(self):
669
self.tree = self.make_branch_and_tree('local')
670
self.build_tree_contents([('local/file', 'initial')])
671
self.tree.add('file')
672
self.tree.commit('adding file', rev_id='added')
673
self.build_tree_contents([('local/file', 'modified')])
674
self.tree.commit('modify file', rev_id='modified')
676
def set_config_push_strict(self, value):
677
# set config var (any of bazaar.conf, locations.conf, branch.conf
679
conf = self.tree.branch.get_config_stack()
680
conf.set('push_strict', value)
682
_default_command = ['push', '../to']
683
_default_wd = 'local'
684
_default_errors = ['Working tree ".*/local/" has uncommitted '
685
'changes \(See bzr status\)\.',]
686
_default_additional_error = 'Use --no-strict to force the push.\n'
687
_default_additional_warning = 'Uncommitted changes will not be pushed.'
690
def assertPushFails(self, args):
691
out, err = self.run_bzr_error(self._default_errors,
692
self._default_command + args,
693
working_dir=self._default_wd, retcode=3)
694
self.assertContainsRe(err, self._default_additional_error)
696
def assertPushSucceeds(self, args, with_warning=False, revid_to_push=None):
698
error_regexes = self._default_errors
701
out, err = self.run_bzr(self._default_command + args,
702
working_dir=self._default_wd,
703
error_regexes=error_regexes)
705
self.assertContainsRe(err, self._default_additional_warning)
707
self.assertNotContainsRe(err, self._default_additional_warning)
708
branch_from = branch.Branch.open(self._default_wd)
709
if revid_to_push is None:
710
revid_to_push = branch_from.last_revision()
711
branch_to = branch.Branch.open('to')
712
repo_to = branch_to.repository
713
self.assertTrue(repo_to.has_revision(revid_to_push))
714
self.assertEqual(revid_to_push, branch_to.last_revision())
718
class TestPushStrictWithoutChanges(tests.TestCaseWithTransport,
719
TestPushStrictMixin):
722
super(TestPushStrictWithoutChanges, self).setUp()
723
self.make_local_branch_and_tree()
725
def test_push_default(self):
726
self.assertPushSucceeds([])
728
def test_push_strict(self):
729
self.assertPushSucceeds(['--strict'])
731
def test_push_no_strict(self):
732
self.assertPushSucceeds(['--no-strict'])
734
def test_push_config_var_strict(self):
735
self.set_config_push_strict('true')
736
self.assertPushSucceeds([])
738
def test_push_config_var_no_strict(self):
739
self.set_config_push_strict('false')
740
self.assertPushSucceeds([])
743
strict_push_change_scenarios = [
745
dict(_changes_type= '_uncommitted_changes')),
747
dict(_changes_type= '_pending_merges')),
748
('out-of-sync-trees',
749
dict(_changes_type= '_out_of_sync_trees')),
753
class TestPushStrictWithChanges(tests.TestCaseWithTransport,
754
TestPushStrictMixin):
756
scenarios = strict_push_change_scenarios
757
_changes_type = None # Set by load_tests
760
super(TestPushStrictWithChanges, self).setUp()
761
# Apply the changes defined in load_tests: one of _uncommitted_changes,
762
# _pending_merges or _out_of_sync_trees
763
getattr(self, self._changes_type)()
765
def _uncommitted_changes(self):
766
self.make_local_branch_and_tree()
767
# Make a change without committing it
768
self.build_tree_contents([('local/file', 'in progress')])
770
def _pending_merges(self):
771
self.make_local_branch_and_tree()
772
# Create 'other' branch containing a new file
773
other_bzrdir = self.tree.bzrdir.sprout('other')
774
other_tree = other_bzrdir.open_workingtree()
775
self.build_tree_contents([('other/other-file', 'other')])
776
other_tree.add('other-file')
777
other_tree.commit('other commit', rev_id='other')
778
# Merge and revert, leaving a pending merge
779
self.tree.merge_from_branch(other_tree.branch)
780
self.tree.revert(filenames=['other-file'], backups=False)
782
def _out_of_sync_trees(self):
783
self.make_local_branch_and_tree()
784
self.run_bzr(['checkout', '--lightweight', 'local', 'checkout'])
785
# Make a change and commit it
786
self.build_tree_contents([('local/file', 'modified in local')])
787
self.tree.commit('modify file', rev_id='modified-in-local')
788
# Exercise commands from the checkout directory
789
self._default_wd = 'checkout'
790
self._default_errors = ["Working tree is out of date, please run"
793
def test_push_default(self):
794
self.assertPushSucceeds([], with_warning=True)
796
def test_push_with_revision(self):
797
self.assertPushSucceeds(['-r', 'revid:added'], revid_to_push='added')
799
def test_push_no_strict(self):
800
self.assertPushSucceeds(['--no-strict'])
802
def test_push_strict_with_changes(self):
803
self.assertPushFails(['--strict'])
805
def test_push_respect_config_var_strict(self):
806
self.set_config_push_strict('true')
807
self.assertPushFails([])
809
def test_push_bogus_config_var_ignored(self):
810
self.set_config_push_strict("I don't want you to be strict")
811
self.assertPushSucceeds([], with_warning=True)
813
def test_push_no_strict_command_line_override_config(self):
814
self.set_config_push_strict('yES')
815
self.assertPushFails([])
816
self.assertPushSucceeds(['--no-strict'])
818
def test_push_strict_command_line_override_config(self):
819
self.set_config_push_strict('oFF')
820
self.assertPushFails(['--strict'])
821
self.assertPushSucceeds([])
824
class TestPushForeign(tests.TestCaseWithTransport):
827
super(TestPushForeign, self).setUp()
828
test_foreign.register_dummy_foreign_for_test(self)
830
def make_dummy_builder(self, relpath):
831
builder = self.make_branch_builder(
832
relpath, format=test_foreign.DummyForeignVcsDirFormat())
833
builder.build_snapshot('revid', None,
834
[('add', ('', 'TREE_ROOT', 'directory', None)),
835
('add', ('foo', 'fooid', 'file', 'bar'))])
838
def test_no_roundtripping(self):
839
target_branch = self.make_dummy_builder('dp').get_branch()
840
source_tree = self.make_branch_and_tree("dc")
841
output, error = self.run_bzr("push -d dc dp", retcode=3)
842
self.assertEquals("", output)
843
self.assertEquals(error, "bzr: ERROR: It is not possible to losslessly"
844
" push to dummy. You may want to use dpush instead.\n")