100
49
tree_b.commit('commit c')
101
50
# initial push location must be empty
102
51
self.assertEqual(None, branch_b.get_push_location())
104
52
# test push for failure without push location set
105
out = self.run_bzr('push', working_dir='branch_a', retcode=3)
106
self.assertEqual(out,
107
('', 'brz: ERROR: No push location known or specified.\n'))
109
# test not remembered if cannot actually push
110
self.run_bzr('push path/which/doesnt/exist',
111
working_dir='branch_a', retcode=3)
112
out = self.run_bzr('push', working_dir='branch_a', retcode=3)
114
('', 'brz: ERROR: No push location known or specified.\n'),
54
out = self.runbzr('push', retcode=3)
55
self.assertEquals(out,
56
('','bzr: ERROR: No push location known or specified.\n'))
117
57
# test implicit --remember when no push location set, push fails
118
out = self.run_bzr('push ../branch_b',
119
working_dir='branch_a', retcode=3)
120
self.assertEqual(out,
121
('', 'brz: ERROR: These branches have diverged. '
122
'See "brz help diverged-branches" for more information.\n'))
123
# Refresh the branch as 'push' modified it
124
branch_a = branch_a.controldir.open_branch()
125
self.assertEqual(osutils.abspath(branch_a.get_push_location()),
126
osutils.abspath(branch_b.controldir.root_transport.base))
58
out = self.runbzr('push ../branch_b', retcode=3)
59
self.assertEquals(out,
60
('','bzr: ERROR: These branches have diverged. '
61
'Try a merge then push with overwrite.\n'))
62
self.assertEquals(abspath(branch_a.get_push_location()),
63
abspath(branch_b.bzrdir.root_transport.base))
128
64
# test implicit --remember after resolving previous failure
129
uncommit.uncommit(branch=branch_b, tree=tree_b)
65
uncommit(branch=branch_b, tree=tree_b)
130
66
transport.delete('branch_b/c')
131
out, err = self.run_bzr('push', working_dir='branch_a')
132
# Refresh the branch as 'push' modified it
133
branch_a = branch_a.controldir.open_branch()
134
path = branch_a.get_push_location()
135
self.assertEqual(err,
136
'Using saved push location: %s\n'
137
'All changes applied successfully.\n'
138
'Pushed up to revision 2.\n'
139
% urlutils.local_path_from_url(path))
140
self.assertEqual(path,
141
branch_b.controldir.root_transport.base)
68
self.assertEquals(abspath(branch_a.get_push_location()),
69
abspath(branch_b.bzrdir.root_transport.base))
142
70
# test explicit --remember
143
self.run_bzr('push ../branch_c --remember', working_dir='branch_a')
144
# Refresh the branch as 'push' modified it
145
branch_a = branch_a.controldir.open_branch()
146
self.assertEqual(branch_a.get_push_location(),
147
branch_c.controldir.root_transport.base)
149
def test_push_without_tree(self):
150
# brz push from a branch that does not have a checkout should work.
151
b = self.make_branch('.')
152
out, err = self.run_bzr('push pushed-location')
153
self.assertEqual('', out)
154
self.assertEqual('Created new branch.\n', err)
155
b2 = branch.Branch.open('pushed-location')
156
self.assertEndsWith(b2.base, 'pushed-location/')
158
def test_push_no_tree(self):
159
# brz push --no-tree of a branch with working trees
160
b = self.make_branch_and_tree('push-from')
161
self.build_tree(['push-from/file'])
164
out, err = self.run_bzr('push --no-tree -d push-from push-to')
165
self.assertEqual('', out)
166
self.assertEqual('Created new branch.\n', err)
167
self.assertPathDoesNotExist('push-to/file')
169
def test_push_new_branch_revision_count(self):
170
# brz push of a branch with revisions to a new location
171
# should print the number of revisions equal to the length of the
173
t = self.make_branch_and_tree('tree')
174
self.build_tree(['tree/file'])
177
out, err = self.run_bzr('push -d tree pushed-to')
178
self.assertEqual('', out)
179
self.assertEqual('Created new branch.\n', err)
181
def test_push_quiet(self):
182
# test that using -q makes output quiet
183
t = self.make_branch_and_tree('tree')
184
self.build_tree(['tree/file'])
187
self.run_bzr('push -d tree pushed-to')
188
# Refresh the branch as 'push' modified it and get the push location
189
push_loc = t.branch.controldir.open_branch().get_push_location()
190
out, err = self.run_bzr('push', working_dir="tree")
191
self.assertEqual('Using saved push location: %s\n'
192
'No new revisions or tags to push.\n' %
193
urlutils.local_path_from_url(push_loc), err)
194
out, err = self.run_bzr('push -q', working_dir="tree")
195
self.assertEqual('', out)
196
self.assertEqual('', err)
198
def test_push_only_pushes_history(self):
199
# Knit branches should only push the history for the current revision.
200
format = bzrdir.BzrDirMetaFormat1()
201
format.repository_format = knitrepo.RepositoryFormatKnit1()
202
shared_repo = self.make_repository('repo', format=format, shared=True)
203
shared_repo.set_make_working_trees(True)
205
def make_shared_tree(path):
206
shared_repo.controldir.root_transport.mkdir(path)
207
controldir.ControlDir.create_branch_convenience('repo/' + path)
208
return workingtree.WorkingTree.open('repo/' + path)
209
tree_a = make_shared_tree('a')
210
self.build_tree(['repo/a/file'])
212
tree_a.commit('commit a-1', rev_id=b'a-1')
213
f = open('repo/a/file', 'ab')
214
f.write(b'more stuff\n')
216
tree_a.commit('commit a-2', rev_id=b'a-2')
218
tree_b = make_shared_tree('b')
219
self.build_tree(['repo/b/file'])
221
tree_b.commit('commit b-1', rev_id=b'b-1')
223
self.assertTrue(shared_repo.has_revision(b'a-1'))
224
self.assertTrue(shared_repo.has_revision(b'a-2'))
225
self.assertTrue(shared_repo.has_revision(b'b-1'))
227
# Now that we have a repository with shared files, make sure
228
# that things aren't copied out by a 'push'
229
self.run_bzr('push ../../push-b', working_dir='repo/b')
230
pushed_tree = workingtree.WorkingTree.open('push-b')
231
pushed_repo = pushed_tree.branch.repository
232
self.assertFalse(pushed_repo.has_revision(b'a-1'))
233
self.assertFalse(pushed_repo.has_revision(b'a-2'))
234
self.assertTrue(pushed_repo.has_revision(b'b-1'))
236
def test_push_funky_id(self):
237
t = self.make_branch_and_tree('tree')
238
self.build_tree(['tree/filename'])
239
t.add('filename', b'funky-chars<>%&;"\'')
240
t.commit('commit filename')
241
self.run_bzr('push -d tree new-tree')
243
def test_push_dash_d(self):
244
t = self.make_branch_and_tree('from')
245
t.commit(allow_pointless=True,
246
message='first commit')
247
self.run_bzr('push -d from to-one')
248
self.assertPathExists('to-one')
249
self.run_bzr('push -d %s %s'
250
% tuple(map(urlutils.local_path_to_url, ['from', 'to-two'])))
251
self.assertPathExists('to-two')
253
def test_push_repository_no_branch_doesnt_fetch_all_revs(self):
254
# See https://bugs.launchpad.net/bzr/+bug/465517
255
target_repo = self.make_repository('target')
256
source = self.make_branch_builder('source')
257
source.start_series()
258
source.build_snapshot(None, [
259
('add', ('', b'root-id', 'directory', None))],
261
source.build_snapshot([b'A'], [], revision_id=b'B')
262
source.build_snapshot([b'A'], [], revision_id=b'C')
263
source.finish_series()
264
self.run_bzr('push target -d source')
265
self.addCleanup(target_repo.lock_read().unlock)
266
# We should have pushed 'C', but not 'B', since it isn't in the
268
self.assertEqual([(b'A',), (b'C',)], sorted(
269
target_repo.revisions.keys()))
271
def test_push_smart_non_stacked_streaming_acceptance(self):
272
self.setup_smart_server_with_call_log()
273
t = self.make_branch_and_tree('from')
274
t.commit(allow_pointless=True, message='first commit')
275
self.reset_smart_call_log()
276
self.run_bzr(['push', self.get_url('to-one')], working_dir='from')
277
# This figure represent the amount of work to perform this use case. It
278
# is entirely ok to reduce this number if a test fails due to rpc_count
279
# being too low. If rpc_count increases, more network roundtrips have
280
# become necessary for this use case. Please do not adjust this number
281
# upwards without agreement from bzr's network support maintainers.
282
self.assertLength(9, self.hpss_calls)
283
self.assertLength(1, self.hpss_connections)
284
self.assertThat(self.hpss_calls, ContainsNoVfsCalls)
286
def test_push_smart_stacked_streaming_acceptance(self):
287
self.setup_smart_server_with_call_log()
288
parent = self.make_branch_and_tree('parent', format='1.9')
289
parent.commit(message='first commit')
290
local = parent.controldir.sprout('local').open_workingtree()
291
local.commit(message='local commit')
292
self.reset_smart_call_log()
293
self.run_bzr(['push', '--stacked', '--stacked-on', '../parent',
294
self.get_url('public')], working_dir='local')
295
# This figure represent the amount of work to perform this use case. It
296
# is entirely ok to reduce this number if a test fails due to rpc_count
297
# being too low. If rpc_count increases, more network roundtrips have
298
# become necessary for this use case. Please do not adjust this number
299
# upwards without agreement from bzr's network support maintainers.
300
self.assertLength(15, self.hpss_calls)
301
self.assertLength(1, self.hpss_connections)
302
self.assertThat(self.hpss_calls, ContainsNoVfsCalls)
303
remote = branch.Branch.open('public')
304
self.assertEndsWith(remote.get_stacked_on_url(), '/parent')
306
def test_push_smart_tags_streaming_acceptance(self):
307
self.setup_smart_server_with_call_log()
308
t = self.make_branch_and_tree('from')
309
rev_id = t.commit(allow_pointless=True, message='first commit')
310
t.branch.tags.set_tag('new-tag', rev_id)
311
self.reset_smart_call_log()
312
self.run_bzr(['push', self.get_url('to-one')], working_dir='from')
313
# This figure represent the amount of work to perform this use case. It
314
# is entirely ok to reduce this number if a test fails due to rpc_count
315
# being too low. If rpc_count increases, more network roundtrips have
316
# become necessary for this use case. Please do not adjust this number
317
# upwards without agreement from bzr's network support maintainers.
318
self.assertLength(11, self.hpss_calls)
319
self.assertLength(1, self.hpss_connections)
320
self.assertThat(self.hpss_calls, ContainsNoVfsCalls)
322
def test_push_smart_incremental_acceptance(self):
323
self.setup_smart_server_with_call_log()
324
t = self.make_branch_and_tree('from')
325
rev_id1 = t.commit(allow_pointless=True, message='first commit')
326
rev_id2 = t.commit(allow_pointless=True, message='second commit')
328
['push', self.get_url('to-one'), '-r1'], working_dir='from')
329
self.reset_smart_call_log()
330
self.run_bzr(['push', self.get_url('to-one')], working_dir='from')
331
# This figure represent the amount of work to perform this use case. It
332
# is entirely ok to reduce this number if a test fails due to rpc_count
333
# being too low. If rpc_count increases, more network roundtrips have
334
# become necessary for this use case. Please do not adjust this number
335
# upwards without agreement from bzr's network support maintainers.
336
self.assertLength(11, self.hpss_calls)
337
self.assertLength(1, self.hpss_connections)
338
self.assertThat(self.hpss_calls, ContainsNoVfsCalls)
340
def test_push_smart_with_default_stacking_url_path_segment(self):
341
# If the default stacked-on location is a path element then branches
342
# we push there over the smart server are stacked and their
343
# stacked_on_url is that exact path segment. Added to nail bug 385132.
344
self.setup_smart_server_with_call_log()
345
self.make_branch('stack-on', format='1.9')
346
self.make_controldir('.').get_config().set_default_stack_on(
348
self.make_branch('from', format='1.9')
349
out, err = self.run_bzr(['push', '-d', 'from', self.get_url('to')])
350
b = branch.Branch.open(self.get_url('to'))
351
self.assertEqual('/extra/stack-on', b.get_stacked_on_url())
353
def test_push_smart_with_default_stacking_relative_path(self):
354
# If the default stacked-on location is a relative path then branches
355
# we push there over the smart server are stacked and their
356
# stacked_on_url is a relative path. Added to nail bug 385132.
357
self.setup_smart_server_with_call_log()
358
self.make_branch('stack-on', format='1.9')
359
self.make_controldir('.').get_config().set_default_stack_on('stack-on')
360
self.make_branch('from', format='1.9')
361
out, err = self.run_bzr(['push', '-d', 'from', self.get_url('to')])
362
b = branch.Branch.open(self.get_url('to'))
363
self.assertEqual('../stack-on', b.get_stacked_on_url())
365
def create_simple_tree(self):
366
tree = self.make_branch_and_tree('tree')
367
self.build_tree(['tree/a'])
368
tree.add(['a'], [b'a-id'])
369
tree.commit('one', rev_id=b'r1')
372
def test_push_create_prefix(self):
373
"""'brz push --create-prefix' will create leading directories."""
374
tree = self.create_simple_tree()
376
self.run_bzr_error(['Parent directory of ../new/tree does not exist'],
379
self.run_bzr('push ../new/tree --create-prefix',
381
new_tree = workingtree.WorkingTree.open('new/tree')
382
self.assertEqual(tree.last_revision(), new_tree.last_revision())
383
self.assertPathExists('new/tree/a')
385
def test_push_use_existing(self):
386
"""'brz push --use-existing-dir' can push into an existing dir.
388
By default, 'brz push' will not use an existing, non-versioned dir.
390
tree = self.create_simple_tree()
391
self.build_tree(['target/'])
393
self.run_bzr_error(['Target directory ../target already exists',
394
'Supply --use-existing-dir',
396
'push ../target', working_dir='tree')
398
self.run_bzr('push --use-existing-dir ../target',
401
new_tree = workingtree.WorkingTree.open('target')
402
self.assertEqual(tree.last_revision(), new_tree.last_revision())
403
# The push should have created target/a
404
self.assertPathExists('target/a')
406
def test_push_use_existing_into_empty_bzrdir(self):
407
"""'brz push --use-existing-dir' into a dir with an empty .bzr dir
410
tree = self.create_simple_tree()
411
self.build_tree(['target/', 'target/.bzr/'])
413
['Target directory ../target already contains a .bzr directory, '
414
'but it is not valid.'],
415
'push ../target --use-existing-dir', working_dir='tree')
417
def test_push_onto_repo(self):
418
"""We should be able to 'brz push' into an existing bzrdir."""
419
tree = self.create_simple_tree()
420
repo = self.make_repository('repo', shared=True)
422
self.run_bzr('push ../repo',
425
# Pushing onto an existing bzrdir will create a repository and
426
# branch as needed, but will only create a working tree if there was
428
self.assertRaises(errors.NoWorkingTree,
429
workingtree.WorkingTree.open, 'repo')
430
new_branch = branch.Branch.open('repo')
431
self.assertEqual(tree.last_revision(), new_branch.last_revision())
433
def test_push_onto_just_bzrdir(self):
434
"""We don't handle when the target is just a bzrdir.
436
Because you shouldn't be able to create *just* a bzrdir in the wild.
438
# TODO: jam 20070109 Maybe it would be better to create the repository
440
tree = self.create_simple_tree()
441
a_controldir = self.make_controldir('dir')
443
self.run_bzr_error(['At ../dir you have a valid .bzr control'],
447
def test_push_with_revisionspec(self):
448
"""We should be able to push a revision older than the tip."""
449
tree_from = self.make_branch_and_tree('from')
450
tree_from.commit("One.", rev_id=b"from-1")
451
tree_from.commit("Two.", rev_id=b"from-2")
453
self.run_bzr('push -r1 ../to', working_dir='from')
455
tree_to = workingtree.WorkingTree.open('to')
456
repo_to = tree_to.branch.repository
457
self.assertTrue(repo_to.has_revision(b'from-1'))
458
self.assertFalse(repo_to.has_revision(b'from-2'))
459
self.assertEqual(tree_to.branch.last_revision_info()[1], b'from-1')
461
tree_to.changes_from(tree_to.basis_tree()).has_changed())
464
['brz: ERROR: brz push --revision '
465
'takes exactly one revision identifier\n'],
466
'push -r0..2 ../to', working_dir='from')
468
def create_trunk_and_feature_branch(self):
470
trunk_tree = self.make_branch_and_tree('target',
472
trunk_tree.commit('mainline')
473
# and a branch from it
474
branch_tree = self.make_branch_and_tree('branch',
476
branch_tree.pull(trunk_tree.branch)
477
branch_tree.branch.set_parent(trunk_tree.branch.base)
478
# with some work on it
479
branch_tree.commit('moar work plz')
480
return trunk_tree, branch_tree
482
def assertPublished(self, branch_revid, stacked_on):
483
"""Assert that the branch 'published' has been published correctly."""
484
published_branch = branch.Branch.open('published')
485
# The published branch refers to the mainline
486
self.assertEqual(stacked_on, published_branch.get_stacked_on_url())
487
# and the branch's work was pushed
488
self.assertTrue(published_branch.repository.has_revision(branch_revid))
490
def test_push_new_branch_stacked_on(self):
491
"""Pushing a new branch with --stacked-on creates a stacked branch."""
492
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
493
# we publish branch_tree with a reference to the mainline.
494
out, err = self.run_bzr(['push', '--stacked-on', trunk_tree.branch.base,
495
self.get_url('published')], working_dir='branch')
496
self.assertEqual('', out)
497
self.assertEqual('Created new stacked branch referring to %s.\n' %
498
trunk_tree.branch.base, err)
499
self.assertPublished(branch_tree.last_revision(),
500
trunk_tree.branch.base)
502
def test_push_new_branch_stacked_on(self):
503
"""Pushing a new branch with --stacked-on can use directory URLs."""
504
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
505
class FooDirectory(object):
506
def look_up(self, name, url, purpose=None):
508
return trunk_tree.branch.base
510
directory_service.directories.register('foo:', FooDirectory, 'Foo directory')
511
self.addCleanup(directory_service.directories.remove, 'foo:')
512
# we publish branch_tree with a reference to the mainline.
513
out, err = self.run_bzr(['push', '--stacked-on', 'foo:',
514
self.get_url('published')], working_dir='branch')
515
self.assertEqual('', out)
516
self.assertEqual('Created new stacked branch referring to %s.\n' %
517
trunk_tree.branch.base, err)
518
self.assertPublished(branch_tree.last_revision(),
519
trunk_tree.branch.base)
521
def test_push_new_branch_stacked_uses_parent_when_no_public_url(self):
522
"""When the parent has no public url the parent is used as-is."""
523
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
524
# now we do a stacked push, which should determine the public location
526
out, err = self.run_bzr(['push', '--stacked',
527
self.get_url('published')], working_dir='branch')
528
self.assertEqual('', out)
529
self.assertEqual('Created new stacked branch referring to %s.\n' %
530
trunk_tree.branch.base, err)
531
self.assertPublished(branch_tree.last_revision(),
532
trunk_tree.branch.base)
534
def test_push_new_branch_stacked_uses_parent_public(self):
535
"""Pushing a new branch with --stacked creates a stacked branch."""
536
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
537
# the trunk is published on a web server
538
self.transport_readonly_server = http_server.HttpServer
539
trunk_public = self.make_branch('public_trunk', format='1.9')
540
trunk_public.pull(trunk_tree.branch)
541
trunk_public_url = self.get_readonly_url('public_trunk')
542
br = trunk_tree.branch
543
br.set_public_branch(trunk_public_url)
544
# now we do a stacked push, which should determine the public location
546
out, err = self.run_bzr(['push', '--stacked',
547
self.get_url('published')], working_dir='branch')
548
self.assertEqual('', out)
549
self.assertEqual('Created new stacked branch referring to %s.\n' %
550
trunk_public_url, err)
551
self.assertPublished(branch_tree.last_revision(), trunk_public_url)
553
def test_push_new_branch_stacked_no_parent(self):
554
"""Pushing with --stacked and no parent branch errors."""
555
branch = self.make_branch_and_tree('branch', format='1.9')
556
# now we do a stacked push, which should fail as the place to refer too
557
# cannot be determined.
558
out, err = self.run_bzr_error(
559
['Could not determine branch to refer to\\.'], ['push', '--stacked',
560
self.get_url('published')], working_dir='branch')
561
self.assertEqual('', out)
562
self.assertFalse(self.get_transport('published').has('.'))
564
def test_push_notifies_default_stacking(self):
565
self.make_branch('stack_on', format='1.6')
566
self.make_controldir('.').get_config().set_default_stack_on('stack_on')
567
self.make_branch('from', format='1.6')
568
out, err = self.run_bzr('push -d from to')
569
self.assertContainsRe(err,
570
'Using default stacking branch stack_on at .*')
572
def test_push_stacks_with_default_stacking_if_target_is_stackable(self):
573
self.make_branch('stack_on', format='1.6')
574
self.make_controldir('.').get_config().set_default_stack_on('stack_on')
575
self.make_branch('from', format='pack-0.92')
576
out, err = self.run_bzr('push -d from to')
577
b = branch.Branch.open('to')
578
self.assertEqual('../stack_on', b.get_stacked_on_url())
580
def test_push_does_not_change_format_with_default_if_target_cannot(self):
581
self.make_branch('stack_on', format='pack-0.92')
582
self.make_controldir('.').get_config().set_default_stack_on('stack_on')
583
self.make_branch('from', format='pack-0.92')
584
out, err = self.run_bzr('push -d from to')
585
b = branch.Branch.open('to')
586
self.assertRaises(branch.UnstackableBranchFormat, b.get_stacked_on_url)
588
def test_push_doesnt_create_broken_branch(self):
589
"""Pushing a new standalone branch works even when there's a default
590
stacking policy at the destination.
592
The new branch will preserve the repo format (even if it isn't the
593
default for the branch), and will be stacked when the repo format
594
allows (which means that the branch format isn't necessarly preserved).
596
self.make_repository('repo', shared=True, format='1.6')
597
builder = self.make_branch_builder('repo/local', format='pack-0.92')
598
builder.start_series()
599
builder.build_snapshot(None, [
600
('add', ('', b'root-id', 'directory', '')),
601
('add', ('filename', b'f-id', 'file', b'content\n'))],
602
revision_id=b'rev-1')
603
builder.build_snapshot([b'rev-1'], [], revision_id=b'rev-2')
604
builder.build_snapshot([b'rev-2'],
605
[('modify', ('filename', b'new-content\n'))],
606
revision_id=b'rev-3')
607
builder.finish_series()
608
branch = builder.get_branch()
609
# Push rev-1 to "trunk", so that we can stack on it.
610
self.run_bzr('push -d repo/local trunk -r 1')
611
# Set a default stacking policy so that new branches will automatically
613
self.make_controldir('.').get_config().set_default_stack_on('trunk')
614
# Push rev-2 to a new branch "remote". It will be stacked on "trunk".
615
out, err = self.run_bzr('push -d repo/local remote -r 2')
616
self.assertContainsRe(
617
err, 'Using default stacking branch trunk at .*')
618
# Push rev-3 onto "remote". If "remote" not stacked and is missing the
619
# fulltext record for f-id @ rev-1, then this will fail.
620
out, err = self.run_bzr('push -d repo/local remote -r 3')
622
def test_push_verbose_shows_log(self):
623
tree = self.make_branch_and_tree('source')
625
out, err = self.run_bzr('push -v -d source target')
626
# initial push contains log
627
self.assertContainsRe(out, 'rev1')
629
out, err = self.run_bzr('push -v -d source target')
630
# subsequent push contains log
631
self.assertContainsRe(out, 'rev2')
632
# subsequent log is accurate
633
self.assertNotContainsRe(out, 'rev1')
635
def test_push_from_subdir(self):
636
t = self.make_branch_and_tree('tree')
637
self.build_tree(['tree/dir/', 'tree/dir/file'])
638
t.add(['dir', 'dir/file'])
640
out, err = self.run_bzr('push ../../pushloc', working_dir='tree/dir')
641
self.assertEqual('', out)
642
self.assertEqual('Created new branch.\n', err)
644
def test_overwrite_tags(self):
645
"""--overwrite-tags only overwrites tags, not revisions."""
646
from_tree = self.make_branch_and_tree('from')
647
from_tree.branch.tags.set_tag("mytag", b"somerevid")
648
to_tree = self.make_branch_and_tree('to')
649
to_tree.branch.tags.set_tag("mytag", b"anotherrevid")
650
revid1 = to_tree.commit('my commit')
651
out = self.run_bzr(['push', '-d', 'from', 'to'])
652
self.assertEqual(out,
653
('Conflicting tags:\n mytag\n', 'No new revisions to push.\n'))
654
out = self.run_bzr(['push', '-d', 'from', '--overwrite-tags', 'to'])
655
self.assertEqual(out, ('', '1 tag updated.\n'))
656
self.assertEqual(to_tree.branch.tags.lookup_tag('mytag'),
658
self.assertEqual(to_tree.branch.last_revision(), revid1)
661
class RedirectingMemoryTransport(memory.MemoryTransport):
663
def mkdir(self, relpath, mode=None):
664
if self._cwd == '/source/':
665
raise errors.RedirectRequested(self.abspath(relpath),
666
self.abspath('../target'),
668
elif self._cwd == '/infinite-loop/':
669
raise errors.RedirectRequested(self.abspath(relpath),
670
self.abspath('../infinite-loop'),
673
return super(RedirectingMemoryTransport, self).mkdir(
676
def get(self, relpath):
677
if self.clone(relpath)._cwd == '/infinite-loop/':
678
raise errors.RedirectRequested(self.abspath(relpath),
679
self.abspath('../infinite-loop'),
682
return super(RedirectingMemoryTransport, self).get(relpath)
684
def _redirected_to(self, source, target):
685
# We do accept redirections
686
return transport.get_transport(target)
689
class RedirectingMemoryServer(memory.MemoryServer):
691
def start_server(self):
692
self._dirs = {'/': None}
695
self._scheme = 'redirecting-memory+%s:///' % id(self)
696
transport.register_transport(self._scheme, self._memory_factory)
698
def _memory_factory(self, url):
699
result = RedirectingMemoryTransport(url)
700
result._dirs = self._dirs
701
result._files = self._files
702
result._locks = self._locks
705
def stop_server(self):
706
transport.unregister_transport(self._scheme, self._memory_factory)
709
class TestPushRedirect(tests.TestCaseWithTransport):
712
super(TestPushRedirect, self).setUp()
713
self.memory_server = RedirectingMemoryServer()
714
self.start_server(self.memory_server)
715
# Make the branch and tree that we'll be pushing.
716
t = self.make_branch_and_tree('tree')
717
self.build_tree(['tree/file'])
721
def test_push_redirects_on_mkdir(self):
722
"""If the push requires a mkdir, push respects redirect requests.
724
This is added primarily to handle lp:/ URI support, so that users can
725
push to new branches by specifying lp:/ URIs.
727
destination_url = self.memory_server.get_url() + 'source'
728
self.run_bzr(['push', '-d', 'tree', destination_url])
730
local_revision = branch.Branch.open('tree').last_revision()
731
remote_revision = branch.Branch.open(
732
self.memory_server.get_url() + 'target').last_revision()
733
self.assertEqual(remote_revision, local_revision)
735
def test_push_gracefully_handles_too_many_redirects(self):
736
"""Push fails gracefully if the mkdir generates a large number of
739
destination_url = self.memory_server.get_url() + 'infinite-loop'
740
out, err = self.run_bzr_error(
741
['Too many redirections trying to make %s\\.\n'
742
% re.escape(destination_url)],
743
['push', '-d', 'tree', destination_url], retcode=3)
744
self.assertEqual('', out)
747
class TestPushStrictMixin(object):
749
def make_local_branch_and_tree(self):
750
self.tree = self.make_branch_and_tree('local')
751
self.build_tree_contents([('local/file', b'initial')])
752
self.tree.add('file')
753
self.tree.commit('adding file', rev_id=b'added')
754
self.build_tree_contents([('local/file', b'modified')])
755
self.tree.commit('modify file', rev_id=b'modified')
757
def set_config_push_strict(self, value):
758
br = branch.Branch.open('local')
759
br.get_config_stack().set('push_strict', value)
761
_default_command = ['push', '../to']
762
_default_wd = 'local'
763
_default_errors = ['Working tree ".*/local/" has uncommitted '
764
'changes \\(See brz status\\)\\.', ]
765
_default_additional_error = 'Use --no-strict to force the push.\n'
766
_default_additional_warning = 'Uncommitted changes will not be pushed.'
768
def assertPushFails(self, args):
769
out, err = self.run_bzr_error(self._default_errors,
770
self._default_command + args,
771
working_dir=self._default_wd, retcode=3)
772
self.assertContainsRe(err, self._default_additional_error)
774
def assertPushSucceeds(self, args, with_warning=False, revid_to_push=None):
776
error_regexes = self._default_errors
779
out, err = self.run_bzr(self._default_command + args,
780
working_dir=self._default_wd,
781
error_regexes=error_regexes)
783
self.assertContainsRe(err, self._default_additional_warning)
785
self.assertNotContainsRe(err, self._default_additional_warning)
786
branch_from = branch.Branch.open(self._default_wd)
787
if revid_to_push is None:
788
revid_to_push = branch_from.last_revision()
789
branch_to = branch.Branch.open('to')
790
repo_to = branch_to.repository
791
self.assertTrue(repo_to.has_revision(revid_to_push))
792
self.assertEqual(revid_to_push, branch_to.last_revision())
795
class TestPushStrictWithoutChanges(tests.TestCaseWithTransport,
796
TestPushStrictMixin):
799
super(TestPushStrictWithoutChanges, self).setUp()
800
self.make_local_branch_and_tree()
802
def test_push_default(self):
803
self.assertPushSucceeds([])
805
def test_push_strict(self):
806
self.assertPushSucceeds(['--strict'])
808
def test_push_no_strict(self):
809
self.assertPushSucceeds(['--no-strict'])
811
def test_push_config_var_strict(self):
812
self.set_config_push_strict('true')
813
self.assertPushSucceeds([])
815
def test_push_config_var_no_strict(self):
816
self.set_config_push_strict('false')
817
self.assertPushSucceeds([])
820
strict_push_change_scenarios = [
822
dict(_changes_type='_uncommitted_changes')),
824
dict(_changes_type='_pending_merges')),
825
('out-of-sync-trees',
826
dict(_changes_type='_out_of_sync_trees')),
830
class TestPushStrictWithChanges(tests.TestCaseWithTransport,
831
TestPushStrictMixin):
833
scenarios = strict_push_change_scenarios
834
_changes_type = None # Set by load_tests
837
super(TestPushStrictWithChanges, self).setUp()
838
# Apply the changes defined in load_tests: one of _uncommitted_changes,
839
# _pending_merges or _out_of_sync_trees
840
getattr(self, self._changes_type)()
842
def _uncommitted_changes(self):
843
self.make_local_branch_and_tree()
844
# Make a change without committing it
845
self.build_tree_contents([('local/file', b'in progress')])
847
def _pending_merges(self):
848
self.make_local_branch_and_tree()
849
# Create 'other' branch containing a new file
850
other_bzrdir = self.tree.controldir.sprout('other')
851
other_tree = other_bzrdir.open_workingtree()
852
self.build_tree_contents([('other/other-file', b'other')])
853
other_tree.add('other-file')
854
other_tree.commit('other commit', rev_id=b'other')
855
# Merge and revert, leaving a pending merge
856
self.tree.merge_from_branch(other_tree.branch)
857
self.tree.revert(filenames=['other-file'], backups=False)
859
def _out_of_sync_trees(self):
860
self.make_local_branch_and_tree()
861
self.run_bzr(['checkout', '--lightweight', 'local', 'checkout'])
862
# Make a change and commit it
863
self.build_tree_contents([('local/file', b'modified in local')])
864
self.tree.commit('modify file', rev_id=b'modified-in-local')
865
# Exercise commands from the checkout directory
866
self._default_wd = 'checkout'
867
self._default_errors = ["Working tree is out of date, please run"
868
" 'brz update'\\.", ]
870
def test_push_default(self):
871
self.assertPushSucceeds([], with_warning=True)
873
def test_push_with_revision(self):
874
self.assertPushSucceeds(['-r', 'revid:added'], revid_to_push=b'added')
876
def test_push_no_strict(self):
877
self.assertPushSucceeds(['--no-strict'])
879
def test_push_strict_with_changes(self):
880
self.assertPushFails(['--strict'])
882
def test_push_respect_config_var_strict(self):
883
self.set_config_push_strict('true')
884
self.assertPushFails([])
886
def test_push_bogus_config_var_ignored(self):
887
self.set_config_push_strict("I don't want you to be strict")
888
self.assertPushSucceeds([], with_warning=True)
890
def test_push_no_strict_command_line_override_config(self):
891
self.set_config_push_strict('yES')
892
self.assertPushFails([])
893
self.assertPushSucceeds(['--no-strict'])
895
def test_push_strict_command_line_override_config(self):
896
self.set_config_push_strict('oFF')
897
self.assertPushFails(['--strict'])
898
self.assertPushSucceeds([])
901
class TestPushForeign(tests.TestCaseWithTransport):
904
super(TestPushForeign, self).setUp()
905
test_foreign.register_dummy_foreign_for_test(self)
907
def make_dummy_builder(self, relpath):
908
builder = self.make_branch_builder(
909
relpath, format=test_foreign.DummyForeignVcsDirFormat())
910
builder.build_snapshot(None,
911
[('add', ('', b'TREE_ROOT', 'directory', None)),
912
('add', ('foo', b'fooid', 'file', b'bar'))],
913
revision_id=b'revid')
916
def test_no_roundtripping(self):
917
target_branch = self.make_dummy_builder('dp').get_branch()
918
source_tree = self.make_branch_and_tree("dc")
919
output, error = self.run_bzr("push -d dc dp", retcode=3)
920
self.assertEqual("", output)
923
"brz: ERROR: It is not possible to losslessly"
924
" push to dummy. You may want to use --lossy.\n")
927
class TestPushOutput(script.TestCaseWithTransportAndScript):
929
def test_push_log_format(self):
932
Created a standalone tree (format: 2a)
937
$ brz commit -m 'we need some foo'
938
2>Committing to:...trunk/
940
2>Committed revision 1.
941
$ brz init ../feature
942
Created a standalone tree (format: 2a)
943
$ brz push -v ../feature -Olog_format=line
945
1: jrandom@example.com ...we need some foo
946
2>All changes applied successfully.
947
2>Pushed up to revision 1.
950
def test_push_with_revspec(self):
952
$ brz init-shared-repo .
953
Shared repository with trees (format: 2a)
957
Created a repository tree (format: 2a)
958
Using shared repository...
960
$ brz commit -m 'first rev' --unchanged
961
2>Committing to:...trunk/
962
2>Committed revision 1.
966
$ brz commit -m 'we need some foo'
967
2>Committing to:...trunk/
969
2>Committed revision 2.
970
$ brz push -r 1 ../other
971
2>Created new branch.
972
$ brz st ../other # checking that file is not created (#484516)
71
self.runbzr('push ../branch_c --remember')
72
self.assertEquals(abspath(branch_a.get_push_location()),
73
abspath(branch_c.bzrdir.root_transport.base))