57
99
self.assertEqual(None, branch_b.get_push_location())
59
101
# test push for failure without push location set
61
out = self.runbzr('push', retcode=3)
102
out = self.run_bzr('push', working_dir='branch_a', retcode=3)
62
103
self.assertEquals(out,
63
104
('','bzr: ERROR: No push location known or specified.\n'))
65
106
# test not remembered if cannot actually push
66
self.run_bzr('push', '../path/which/doesnt/exist', retcode=3)
67
out = self.run_bzr('push', retcode=3)
107
self.run_bzr('push path/which/doesnt/exist',
108
working_dir='branch_a', retcode=3)
109
out = self.run_bzr('push', working_dir='branch_a', retcode=3)
68
110
self.assertEquals(
69
111
('', 'bzr: ERROR: No push location known or specified.\n'),
72
114
# test implicit --remember when no push location set, push fails
73
out = self.run_bzr('push', '../branch_b', retcode=3)
115
out = self.run_bzr('push ../branch_b',
116
working_dir='branch_a', retcode=3)
74
117
self.assertEquals(out,
75
118
('','bzr: ERROR: These branches have diverged. '
76
'Try using "merge" and then "push".\n'))
77
self.assertEquals(abspath(branch_a.get_push_location()),
78
abspath(branch_b.bzrdir.root_transport.base))
119
'See "bzr help diverged-branches" for more information.\n'))
120
# Refresh the branch as 'push' modified it
121
branch_a = branch_a.bzrdir.open_branch()
122
self.assertEquals(osutils.abspath(branch_a.get_push_location()),
123
osutils.abspath(branch_b.bzrdir.root_transport.base))
80
125
# test implicit --remember after resolving previous failure
81
uncommit(branch=branch_b, tree=tree_b)
126
uncommit.uncommit(branch=branch_b, tree=tree_b)
82
127
transport.delete('branch_b/c')
83
out = self.run_bzr('push')
128
out, err = self.run_bzr('push', working_dir='branch_a')
129
# Refresh the branch as 'push' modified it
130
branch_a = branch_a.bzrdir.open_branch()
84
131
path = branch_a.get_push_location()
85
self.assertEquals(('Using saved location: %s\n'
86
% (local_path_from_url(path),)
87
, 'All changes applied successfully.\n'
88
'1 revision(s) pushed.\n'), out)
132
self.assertEqual(err,
133
'Using saved push location: %s\n'
134
'All changes applied successfully.\n'
135
'Pushed up to revision 2.\n'
136
% urlutils.local_path_from_url(path))
89
137
self.assertEqual(path,
90
138
branch_b.bzrdir.root_transport.base)
91
139
# test explicit --remember
92
self.run_bzr('push', '../branch_c', '--remember')
140
self.run_bzr('push ../branch_c --remember', working_dir='branch_a')
141
# Refresh the branch as 'push' modified it
142
branch_a = branch_a.bzrdir.open_branch()
93
143
self.assertEquals(branch_a.get_push_location(),
94
144
branch_c.bzrdir.root_transport.base)
96
146
def test_push_without_tree(self):
97
147
# bzr push from a branch that does not have a checkout should work.
98
148
b = self.make_branch('.')
99
out, err = self.run_bzr('push', 'pushed-location')
149
out, err = self.run_bzr('push pushed-location')
100
150
self.assertEqual('', out)
101
self.assertEqual('0 revision(s) pushed.\n', err)
102
b2 = Branch.open('pushed-location')
151
self.assertEqual('Created new branch.\n', err)
152
b2 = branch.Branch.open('pushed-location')
103
153
self.assertEndsWith(b2.base, 'pushed-location/')
155
def test_push_no_tree(self):
156
# bzr push --no-tree of a branch with working trees
157
b = self.make_branch_and_tree('push-from')
158
self.build_tree(['push-from/file'])
161
out, err = self.run_bzr('push --no-tree -d push-from push-to')
162
self.assertEqual('', out)
163
self.assertEqual('Created new branch.\n', err)
164
self.assertPathDoesNotExist('push-to/file')
105
166
def test_push_new_branch_revision_count(self):
106
# bzr push of a branch with revisions to a new location
107
# should print the number of revisions equal to the length of the
167
# bzr push of a branch with revisions to a new location
168
# should print the number of revisions equal to the length of the
109
170
t = self.make_branch_and_tree('tree')
110
171
self.build_tree(['tree/file'])
112
173
t.commit('commit 1')
114
out, err = self.run_bzr('push', 'pushed-to')
116
self.assertEqual('', out)
117
self.assertEqual('1 revision(s) pushed.\n', err)
174
out, err = self.run_bzr('push -d tree pushed-to')
175
self.assertEqual('', out)
176
self.assertEqual('Created new branch.\n', err)
178
def test_push_quiet(self):
179
# test that using -q makes output quiet
180
t = self.make_branch_and_tree('tree')
181
self.build_tree(['tree/file'])
184
self.run_bzr('push -d tree pushed-to')
185
# Refresh the branch as 'push' modified it and get the push location
186
push_loc = t.branch.bzrdir.open_branch().get_push_location()
187
out, err = self.run_bzr('push', working_dir="tree")
188
self.assertEqual('Using saved push location: %s\n'
189
'No new revisions or tags to push.\n' %
190
urlutils.local_path_from_url(push_loc), err)
191
out, err = self.run_bzr('push -q', working_dir="tree")
192
self.assertEqual('', out)
193
self.assertEqual('', err)
119
195
def test_push_only_pushes_history(self):
120
196
# Knit branches should only push the history for the current revision.
121
format = BzrDirMetaFormat1()
122
format.repository_format = RepositoryFormatKnit1()
197
format = bzrdir.BzrDirMetaFormat1()
198
format.repository_format = knitrepo.RepositoryFormatKnit1()
123
199
shared_repo = self.make_repository('repo', format=format, shared=True)
124
200
shared_repo.set_make_working_trees(True)
126
202
def make_shared_tree(path):
127
203
shared_repo.bzrdir.root_transport.mkdir(path)
128
shared_repo.bzrdir.create_branch_convenience('repo/' + path)
129
return WorkingTree.open('repo/' + path)
204
controldir.ControlDir.create_branch_convenience('repo/' + path)
205
return workingtree.WorkingTree.open('repo/' + path)
130
206
tree_a = make_shared_tree('a')
131
207
self.build_tree(['repo/a/file'])
132
208
tree_a.add('file')
158
233
def test_push_funky_id(self):
159
234
t = self.make_branch_and_tree('tree')
161
self.build_tree(['filename'])
235
self.build_tree(['tree/filename'])
162
236
t.add('filename', 'funky-chars<>%&;"\'')
163
237
t.commit('commit filename')
164
self.run_bzr('push', '../new-tree')
238
self.run_bzr('push -d tree new-tree')
166
240
def test_push_dash_d(self):
167
241
t = self.make_branch_and_tree('from')
168
242
t.commit(allow_pointless=True,
169
243
message='first commit')
170
self.runbzr('push -d from to-one')
171
self.failUnlessExists('to-one')
172
self.runbzr('push -d %s %s'
244
self.run_bzr('push -d from to-one')
245
self.assertPathExists('to-one')
246
self.run_bzr('push -d %s %s'
173
247
% tuple(map(urlutils.local_path_to_url, ['from', 'to-two'])))
174
self.failUnlessExists('to-two')
248
self.assertPathExists('to-two')
250
def test_push_repository_no_branch_doesnt_fetch_all_revs(self):
251
# See https://bugs.launchpad.net/bzr/+bug/465517
252
target_repo = self.make_repository('target')
253
source = self.make_branch_builder('source')
254
source.start_series()
255
source.build_snapshot('A', None, [
256
('add', ('', 'root-id', 'directory', None))])
257
source.build_snapshot('B', ['A'], [])
258
source.build_snapshot('C', ['A'], [])
259
source.finish_series()
260
self.run_bzr('push target -d source')
261
self.addCleanup(target_repo.lock_read().unlock)
262
# We should have pushed 'C', but not 'B', since it isn't in the
264
self.assertEqual([('A',), ('C',)], sorted(target_repo.revisions.keys()))
266
def test_push_smart_non_stacked_streaming_acceptance(self):
267
self.setup_smart_server_with_call_log()
268
t = self.make_branch_and_tree('from')
269
t.commit(allow_pointless=True, message='first commit')
270
self.reset_smart_call_log()
271
self.run_bzr(['push', self.get_url('to-one')], working_dir='from')
272
# This figure represent the amount of work to perform this use case. It
273
# is entirely ok to reduce this number if a test fails due to rpc_count
274
# being too low. If rpc_count increases, more network roundtrips have
275
# become necessary for this use case. Please do not adjust this number
276
# upwards without agreement from bzr's network support maintainers.
277
self.assertLength(9, self.hpss_calls)
278
self.assertLength(1, self.hpss_connections)
279
self.assertThat(self.hpss_calls, ContainsNoVfsCalls)
281
def test_push_smart_stacked_streaming_acceptance(self):
282
self.setup_smart_server_with_call_log()
283
parent = self.make_branch_and_tree('parent', format='1.9')
284
parent.commit(message='first commit')
285
local = parent.bzrdir.sprout('local').open_workingtree()
286
local.commit(message='local commit')
287
self.reset_smart_call_log()
288
self.run_bzr(['push', '--stacked', '--stacked-on', '../parent',
289
self.get_url('public')], working_dir='local')
290
# This figure represent the amount of work to perform this use case. It
291
# is entirely ok to reduce this number if a test fails due to rpc_count
292
# being too low. If rpc_count increases, more network roundtrips have
293
# become necessary for this use case. Please do not adjust this number
294
# upwards without agreement from bzr's network support maintainers.
295
self.assertLength(15, self.hpss_calls)
296
self.assertLength(1, self.hpss_connections)
297
self.assertThat(self.hpss_calls, ContainsNoVfsCalls)
298
remote = branch.Branch.open('public')
299
self.assertEndsWith(remote.get_stacked_on_url(), '/parent')
301
def test_push_smart_tags_streaming_acceptance(self):
302
self.setup_smart_server_with_call_log()
303
t = self.make_branch_and_tree('from')
304
rev_id = t.commit(allow_pointless=True, message='first commit')
305
t.branch.tags.set_tag('new-tag', rev_id)
306
self.reset_smart_call_log()
307
self.run_bzr(['push', self.get_url('to-one')], working_dir='from')
308
# This figure represent the amount of work to perform this use case. It
309
# is entirely ok to reduce this number if a test fails due to rpc_count
310
# being too low. If rpc_count increases, more network roundtrips have
311
# become necessary for this use case. Please do not adjust this number
312
# upwards without agreement from bzr's network support maintainers.
313
self.assertLength(11, self.hpss_calls)
314
self.assertLength(1, self.hpss_connections)
315
self.assertThat(self.hpss_calls, ContainsNoVfsCalls)
317
def test_push_smart_incremental_acceptance(self):
318
self.setup_smart_server_with_call_log()
319
t = self.make_branch_and_tree('from')
320
rev_id1 = t.commit(allow_pointless=True, message='first commit')
321
rev_id2 = t.commit(allow_pointless=True, message='second commit')
323
['push', self.get_url('to-one'), '-r1'], working_dir='from')
324
self.reset_smart_call_log()
325
self.run_bzr(['push', self.get_url('to-one')], working_dir='from')
326
# This figure represent the amount of work to perform this use case. It
327
# is entirely ok to reduce this number if a test fails due to rpc_count
328
# being too low. If rpc_count increases, more network roundtrips have
329
# become necessary for this use case. Please do not adjust this number
330
# upwards without agreement from bzr's network support maintainers.
331
self.assertLength(11, self.hpss_calls)
332
self.assertLength(1, self.hpss_connections)
333
self.assertThat(self.hpss_calls, ContainsNoVfsCalls)
335
def test_push_smart_with_default_stacking_url_path_segment(self):
336
# If the default stacked-on location is a path element then branches
337
# we push there over the smart server are stacked and their
338
# stacked_on_url is that exact path segment. Added to nail bug 385132.
339
self.setup_smart_server_with_call_log()
340
self.make_branch('stack-on', format='1.9')
341
self.make_bzrdir('.').get_config().set_default_stack_on(
343
self.make_branch('from', format='1.9')
344
out, err = self.run_bzr(['push', '-d', 'from', self.get_url('to')])
345
b = branch.Branch.open(self.get_url('to'))
346
self.assertEqual('/extra/stack-on', b.get_stacked_on_url())
348
def test_push_smart_with_default_stacking_relative_path(self):
349
# If the default stacked-on location is a relative path then branches
350
# we push there over the smart server are stacked and their
351
# stacked_on_url is a relative path. Added to nail bug 385132.
352
self.setup_smart_server_with_call_log()
353
self.make_branch('stack-on', format='1.9')
354
self.make_bzrdir('.').get_config().set_default_stack_on('stack-on')
355
self.make_branch('from', format='1.9')
356
out, err = self.run_bzr(['push', '-d', 'from', self.get_url('to')])
357
b = branch.Branch.open(self.get_url('to'))
358
self.assertEqual('../stack-on', b.get_stacked_on_url())
176
360
def create_simple_tree(self):
177
361
tree = self.make_branch_and_tree('tree')
240
436
a_bzrdir = self.make_bzrdir('dir')
242
438
self.run_bzr_error(['At ../dir you have a valid .bzr control'],
244
440
working_dir='tree')
442
def test_push_with_revisionspec(self):
443
"""We should be able to push a revision older than the tip."""
444
tree_from = self.make_branch_and_tree('from')
445
tree_from.commit("One.", rev_id="from-1")
446
tree_from.commit("Two.", rev_id="from-2")
448
self.run_bzr('push -r1 ../to', working_dir='from')
450
tree_to = workingtree.WorkingTree.open('to')
451
repo_to = tree_to.branch.repository
452
self.assertTrue(repo_to.has_revision('from-1'))
453
self.assertFalse(repo_to.has_revision('from-2'))
454
self.assertEqual(tree_to.branch.last_revision_info()[1], 'from-1')
457
['bzr: ERROR: bzr push --revision '
458
'takes exactly one revision identifier\n'],
459
'push -r0..2 ../to', working_dir='from')
461
def create_trunk_and_feature_branch(self):
463
trunk_tree = self.make_branch_and_tree('target',
465
trunk_tree.commit('mainline')
466
# and a branch from it
467
branch_tree = self.make_branch_and_tree('branch',
469
branch_tree.pull(trunk_tree.branch)
470
branch_tree.branch.set_parent(trunk_tree.branch.base)
471
# with some work on it
472
branch_tree.commit('moar work plz')
473
return trunk_tree, branch_tree
475
def assertPublished(self, branch_revid, stacked_on):
476
"""Assert that the branch 'published' has been published correctly."""
477
published_branch = branch.Branch.open('published')
478
# The published branch refers to the mainline
479
self.assertEqual(stacked_on, published_branch.get_stacked_on_url())
480
# and the branch's work was pushed
481
self.assertTrue(published_branch.repository.has_revision(branch_revid))
483
def test_push_new_branch_stacked_on(self):
484
"""Pushing a new branch with --stacked-on creates a stacked branch."""
485
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
486
# we publish branch_tree with a reference to the mainline.
487
out, err = self.run_bzr(['push', '--stacked-on', trunk_tree.branch.base,
488
self.get_url('published')], working_dir='branch')
489
self.assertEqual('', out)
490
self.assertEqual('Created new stacked branch referring to %s.\n' %
491
trunk_tree.branch.base, err)
492
self.assertPublished(branch_tree.last_revision(),
493
trunk_tree.branch.base)
495
def test_push_new_branch_stacked_uses_parent_when_no_public_url(self):
496
"""When the parent has no public url the parent is used as-is."""
497
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
498
# now we do a stacked push, which should determine the public location
500
out, err = self.run_bzr(['push', '--stacked',
501
self.get_url('published')], working_dir='branch')
502
self.assertEqual('', out)
503
self.assertEqual('Created new stacked branch referring to %s.\n' %
504
trunk_tree.branch.base, err)
505
self.assertPublished(branch_tree.last_revision(),
506
trunk_tree.branch.base)
508
def test_push_new_branch_stacked_uses_parent_public(self):
509
"""Pushing a new branch with --stacked creates a stacked branch."""
510
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
511
# the trunk is published on a web server
512
self.transport_readonly_server = http_server.HttpServer
513
trunk_public = self.make_branch('public_trunk', format='1.9')
514
trunk_public.pull(trunk_tree.branch)
515
trunk_public_url = self.get_readonly_url('public_trunk')
516
br = trunk_tree.branch
517
br.set_public_branch(trunk_public_url)
518
# now we do a stacked push, which should determine the public location
520
out, err = self.run_bzr(['push', '--stacked',
521
self.get_url('published')], working_dir='branch')
522
self.assertEqual('', out)
523
self.assertEqual('Created new stacked branch referring to %s.\n' %
524
trunk_public_url, err)
525
self.assertPublished(branch_tree.last_revision(), trunk_public_url)
527
def test_push_new_branch_stacked_no_parent(self):
528
"""Pushing with --stacked and no parent branch errors."""
529
branch = self.make_branch_and_tree('branch', format='1.9')
530
# now we do a stacked push, which should fail as the place to refer too
531
# cannot be determined.
532
out, err = self.run_bzr_error(
533
['Could not determine branch to refer to\\.'], ['push', '--stacked',
534
self.get_url('published')], working_dir='branch')
535
self.assertEqual('', out)
536
self.assertFalse(self.get_transport('published').has('.'))
538
def test_push_notifies_default_stacking(self):
539
self.make_branch('stack_on', format='1.6')
540
self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
541
self.make_branch('from', format='1.6')
542
out, err = self.run_bzr('push -d from to')
543
self.assertContainsRe(err,
544
'Using default stacking branch stack_on at .*')
546
def test_push_stacks_with_default_stacking_if_target_is_stackable(self):
547
self.make_branch('stack_on', format='1.6')
548
self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
549
self.make_branch('from', format='pack-0.92')
550
out, err = self.run_bzr('push -d from to')
551
b = branch.Branch.open('to')
552
self.assertEqual('../stack_on', b.get_stacked_on_url())
554
def test_push_does_not_change_format_with_default_if_target_cannot(self):
555
self.make_branch('stack_on', format='pack-0.92')
556
self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
557
self.make_branch('from', format='pack-0.92')
558
out, err = self.run_bzr('push -d from to')
559
b = branch.Branch.open('to')
560
self.assertRaises(errors.UnstackableBranchFormat, b.get_stacked_on_url)
562
def test_push_doesnt_create_broken_branch(self):
563
"""Pushing a new standalone branch works even when there's a default
564
stacking policy at the destination.
566
The new branch will preserve the repo format (even if it isn't the
567
default for the branch), and will be stacked when the repo format
568
allows (which means that the branch format isn't necessarly preserved).
570
self.make_repository('repo', shared=True, format='1.6')
571
builder = self.make_branch_builder('repo/local', format='pack-0.92')
572
builder.start_series()
573
builder.build_snapshot('rev-1', None, [
574
('add', ('', 'root-id', 'directory', '')),
575
('add', ('filename', 'f-id', 'file', 'content\n'))])
576
builder.build_snapshot('rev-2', ['rev-1'], [])
577
builder.build_snapshot('rev-3', ['rev-2'],
578
[('modify', ('f-id', 'new-content\n'))])
579
builder.finish_series()
580
branch = builder.get_branch()
581
# Push rev-1 to "trunk", so that we can stack on it.
582
self.run_bzr('push -d repo/local trunk -r 1')
583
# Set a default stacking policy so that new branches will automatically
585
self.make_bzrdir('.').get_config().set_default_stack_on('trunk')
586
# Push rev-2 to a new branch "remote". It will be stacked on "trunk".
587
out, err = self.run_bzr('push -d repo/local remote -r 2')
588
self.assertContainsRe(
589
err, 'Using default stacking branch trunk at .*')
590
# Push rev-3 onto "remote". If "remote" not stacked and is missing the
591
# fulltext record for f-id @ rev-1, then this will fail.
592
out, err = self.run_bzr('push -d repo/local remote -r 3')
594
def test_push_verbose_shows_log(self):
595
tree = self.make_branch_and_tree('source')
597
out, err = self.run_bzr('push -v -d source target')
598
# initial push contains log
599
self.assertContainsRe(out, 'rev1')
601
out, err = self.run_bzr('push -v -d source target')
602
# subsequent push contains log
603
self.assertContainsRe(out, 'rev2')
604
# subsequent log is accurate
605
self.assertNotContainsRe(out, 'rev1')
607
def test_push_from_subdir(self):
608
t = self.make_branch_and_tree('tree')
609
self.build_tree(['tree/dir/', 'tree/dir/file'])
610
t.add('dir', 'dir/file')
612
out, err = self.run_bzr('push ../../pushloc', working_dir='tree/dir')
613
self.assertEqual('', out)
614
self.assertEqual('Created new branch.\n', err)
616
def test_overwrite_tags(self):
617
"""--overwrite-tags only overwrites tags, not revisions."""
618
from_tree = self.make_branch_and_tree('from')
619
from_tree.branch.tags.set_tag("mytag", "somerevid")
620
to_tree = self.make_branch_and_tree('to')
621
to_tree.branch.tags.set_tag("mytag", "anotherrevid")
622
revid1 = to_tree.commit('my commit')
623
out = self.run_bzr(['push', '-d', 'from', 'to'])
624
self.assertEquals(out,
625
('Conflicting tags:\n mytag\n', 'No new revisions to push.\n'))
626
out = self.run_bzr(['push', '-d', 'from', '--overwrite-tags', 'to'])
627
self.assertEquals(out, ('', '1 tag updated.\n'))
628
self.assertEquals(to_tree.branch.tags.lookup_tag('mytag'),
630
self.assertEquals(to_tree.branch.last_revision(), revid1)
633
class RedirectingMemoryTransport(memory.MemoryTransport):
635
def mkdir(self, relpath, mode=None):
636
if self._cwd == '/source/':
637
raise errors.RedirectRequested(self.abspath(relpath),
638
self.abspath('../target'),
640
elif self._cwd == '/infinite-loop/':
641
raise errors.RedirectRequested(self.abspath(relpath),
642
self.abspath('../infinite-loop'),
645
return super(RedirectingMemoryTransport, self).mkdir(
648
def get(self, relpath):
649
if self.clone(relpath)._cwd == '/infinite-loop/':
650
raise errors.RedirectRequested(self.abspath(relpath),
651
self.abspath('../infinite-loop'),
654
return super(RedirectingMemoryTransport, self).get(relpath)
656
def _redirected_to(self, source, target):
657
# We do accept redirections
658
return transport.get_transport(target)
661
class RedirectingMemoryServer(memory.MemoryServer):
663
def start_server(self):
664
self._dirs = {'/': None}
667
self._scheme = 'redirecting-memory+%s:///' % id(self)
668
transport.register_transport(self._scheme, self._memory_factory)
670
def _memory_factory(self, url):
671
result = RedirectingMemoryTransport(url)
672
result._dirs = self._dirs
673
result._files = self._files
674
result._locks = self._locks
677
def stop_server(self):
678
transport.unregister_transport(self._scheme, self._memory_factory)
681
class TestPushRedirect(tests.TestCaseWithTransport):
684
tests.TestCaseWithTransport.setUp(self)
685
self.memory_server = RedirectingMemoryServer()
686
self.start_server(self.memory_server)
687
# Make the branch and tree that we'll be pushing.
688
t = self.make_branch_and_tree('tree')
689
self.build_tree(['tree/file'])
693
def test_push_redirects_on_mkdir(self):
694
"""If the push requires a mkdir, push respects redirect requests.
696
This is added primarily to handle lp:/ URI support, so that users can
697
push to new branches by specifying lp:/ URIs.
699
destination_url = self.memory_server.get_url() + 'source'
700
self.run_bzr(['push', '-d', 'tree', destination_url])
702
local_revision = branch.Branch.open('tree').last_revision()
703
remote_revision = branch.Branch.open(
704
self.memory_server.get_url() + 'target').last_revision()
705
self.assertEqual(remote_revision, local_revision)
707
def test_push_gracefully_handles_too_many_redirects(self):
708
"""Push fails gracefully if the mkdir generates a large number of
711
destination_url = self.memory_server.get_url() + 'infinite-loop'
712
out, err = self.run_bzr_error(
713
['Too many redirections trying to make %s\\.\n'
714
% re.escape(destination_url)],
715
['push', '-d', 'tree', destination_url], retcode=3)
716
self.assertEqual('', out)
719
class TestPushStrictMixin(object):
721
def make_local_branch_and_tree(self):
722
self.tree = self.make_branch_and_tree('local')
723
self.build_tree_contents([('local/file', 'initial')])
724
self.tree.add('file')
725
self.tree.commit('adding file', rev_id='added')
726
self.build_tree_contents([('local/file', 'modified')])
727
self.tree.commit('modify file', rev_id='modified')
729
def set_config_push_strict(self, value):
730
br = branch.Branch.open('local')
731
br.get_config_stack().set('push_strict', value)
733
_default_command = ['push', '../to']
734
_default_wd = 'local'
735
_default_errors = ['Working tree ".*/local/" has uncommitted '
736
'changes \(See bzr status\)\.',]
737
_default_additional_error = 'Use --no-strict to force the push.\n'
738
_default_additional_warning = 'Uncommitted changes will not be pushed.'
741
def assertPushFails(self, args):
742
out, err = self.run_bzr_error(self._default_errors,
743
self._default_command + args,
744
working_dir=self._default_wd, retcode=3)
745
self.assertContainsRe(err, self._default_additional_error)
747
def assertPushSucceeds(self, args, with_warning=False, revid_to_push=None):
749
error_regexes = self._default_errors
752
out, err = self.run_bzr(self._default_command + args,
753
working_dir=self._default_wd,
754
error_regexes=error_regexes)
756
self.assertContainsRe(err, self._default_additional_warning)
758
self.assertNotContainsRe(err, self._default_additional_warning)
759
branch_from = branch.Branch.open(self._default_wd)
760
if revid_to_push is None:
761
revid_to_push = branch_from.last_revision()
762
branch_to = branch.Branch.open('to')
763
repo_to = branch_to.repository
764
self.assertTrue(repo_to.has_revision(revid_to_push))
765
self.assertEqual(revid_to_push, branch_to.last_revision())
769
class TestPushStrictWithoutChanges(tests.TestCaseWithTransport,
770
TestPushStrictMixin):
773
super(TestPushStrictWithoutChanges, self).setUp()
774
self.make_local_branch_and_tree()
776
def test_push_default(self):
777
self.assertPushSucceeds([])
779
def test_push_strict(self):
780
self.assertPushSucceeds(['--strict'])
782
def test_push_no_strict(self):
783
self.assertPushSucceeds(['--no-strict'])
785
def test_push_config_var_strict(self):
786
self.set_config_push_strict('true')
787
self.assertPushSucceeds([])
789
def test_push_config_var_no_strict(self):
790
self.set_config_push_strict('false')
791
self.assertPushSucceeds([])
794
strict_push_change_scenarios = [
796
dict(_changes_type= '_uncommitted_changes')),
798
dict(_changes_type= '_pending_merges')),
799
('out-of-sync-trees',
800
dict(_changes_type= '_out_of_sync_trees')),
804
class TestPushStrictWithChanges(tests.TestCaseWithTransport,
805
TestPushStrictMixin):
807
scenarios = strict_push_change_scenarios
808
_changes_type = None # Set by load_tests
811
super(TestPushStrictWithChanges, self).setUp()
812
# Apply the changes defined in load_tests: one of _uncommitted_changes,
813
# _pending_merges or _out_of_sync_trees
814
getattr(self, self._changes_type)()
816
def _uncommitted_changes(self):
817
self.make_local_branch_and_tree()
818
# Make a change without committing it
819
self.build_tree_contents([('local/file', 'in progress')])
821
def _pending_merges(self):
822
self.make_local_branch_and_tree()
823
# Create 'other' branch containing a new file
824
other_bzrdir = self.tree.bzrdir.sprout('other')
825
other_tree = other_bzrdir.open_workingtree()
826
self.build_tree_contents([('other/other-file', 'other')])
827
other_tree.add('other-file')
828
other_tree.commit('other commit', rev_id='other')
829
# Merge and revert, leaving a pending merge
830
self.tree.merge_from_branch(other_tree.branch)
831
self.tree.revert(filenames=['other-file'], backups=False)
833
def _out_of_sync_trees(self):
834
self.make_local_branch_and_tree()
835
self.run_bzr(['checkout', '--lightweight', 'local', 'checkout'])
836
# Make a change and commit it
837
self.build_tree_contents([('local/file', 'modified in local')])
838
self.tree.commit('modify file', rev_id='modified-in-local')
839
# Exercise commands from the checkout directory
840
self._default_wd = 'checkout'
841
self._default_errors = ["Working tree is out of date, please run"
844
def test_push_default(self):
845
self.assertPushSucceeds([], with_warning=True)
847
def test_push_with_revision(self):
848
self.assertPushSucceeds(['-r', 'revid:added'], revid_to_push='added')
850
def test_push_no_strict(self):
851
self.assertPushSucceeds(['--no-strict'])
853
def test_push_strict_with_changes(self):
854
self.assertPushFails(['--strict'])
856
def test_push_respect_config_var_strict(self):
857
self.set_config_push_strict('true')
858
self.assertPushFails([])
860
def test_push_bogus_config_var_ignored(self):
861
self.set_config_push_strict("I don't want you to be strict")
862
self.assertPushSucceeds([], with_warning=True)
864
def test_push_no_strict_command_line_override_config(self):
865
self.set_config_push_strict('yES')
866
self.assertPushFails([])
867
self.assertPushSucceeds(['--no-strict'])
869
def test_push_strict_command_line_override_config(self):
870
self.set_config_push_strict('oFF')
871
self.assertPushFails(['--strict'])
872
self.assertPushSucceeds([])
875
class TestPushForeign(tests.TestCaseWithTransport):
878
super(TestPushForeign, self).setUp()
879
test_foreign.register_dummy_foreign_for_test(self)
881
def make_dummy_builder(self, relpath):
882
builder = self.make_branch_builder(
883
relpath, format=test_foreign.DummyForeignVcsDirFormat())
884
builder.build_snapshot('revid', None,
885
[('add', ('', 'TREE_ROOT', 'directory', None)),
886
('add', ('foo', 'fooid', 'file', 'bar'))])
889
def test_no_roundtripping(self):
890
target_branch = self.make_dummy_builder('dp').get_branch()
891
source_tree = self.make_branch_and_tree("dc")
892
output, error = self.run_bzr("push -d dc dp", retcode=3)
893
self.assertEquals("", output)
894
self.assertEquals(error, "bzr: ERROR: It is not possible to losslessly"
895
" push to dummy. You may want to use dpush instead.\n")
898
class TestPushOutput(script.TestCaseWithTransportAndScript):
900
def test_push_log_format(self):
903
Created a standalone tree (format: 2a)
908
$ bzr commit -m 'we need some foo'
909
2>Committing to:...trunk/
911
2>Committed revision 1.
912
$ bzr init ../feature
913
Created a standalone tree (format: 2a)
914
$ bzr push -v ../feature -Olog_format=line
916
1: jrandom@example.com ...we need some foo
917
2>All changes applied successfully.
918
2>Pushed up to revision 1.