52
59
tree_b.commit('commit c')
53
60
# initial push location must be empty
54
61
self.assertEqual(None, branch_b.get_push_location())
55
63
# test push for failure without push location set
56
64
os.chdir('branch_a')
57
out = self.runbzr('push', retcode=3)
65
out = self.run_bzr('push', retcode=3)
58
66
self.assertEquals(out,
59
67
('','bzr: ERROR: No push location known or specified.\n'))
69
# test not remembered if cannot actually push
70
self.run_bzr('push ../path/which/doesnt/exist', retcode=3)
71
out = self.run_bzr('push', retcode=3)
73
('', 'bzr: ERROR: No push location known or specified.\n'),
60
76
# test implicit --remember when no push location set, push fails
61
out = self.runbzr('push ../branch_b', retcode=3)
77
out = self.run_bzr('push ../branch_b', retcode=3)
62
78
self.assertEquals(out,
63
79
('','bzr: ERROR: These branches have diverged. '
64
'Try a merge then push with overwrite.\n'))
80
'Try using "merge" and then "push".\n'))
65
81
self.assertEquals(abspath(branch_a.get_push_location()),
66
82
abspath(branch_b.bzrdir.root_transport.base))
67
84
# test implicit --remember after resolving previous failure
68
85
uncommit(branch=branch_b, tree=tree_b)
69
86
transport.delete('branch_b/c')
71
self.assertEquals(abspath(branch_a.get_push_location()),
72
abspath(branch_b.bzrdir.root_transport.base))
87
out, err = self.run_bzr('push')
88
path = branch_a.get_push_location()
89
self.assertEquals(out,
90
'Using saved push location: %s\n'
91
'Pushed up to revision 2.\n'
92
% local_path_from_url(path))
94
'All changes applied successfully.\n')
95
self.assertEqual(path,
96
branch_b.bzrdir.root_transport.base)
73
97
# 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))
98
self.run_bzr('push ../branch_c --remember')
99
self.assertEquals(branch_a.get_push_location(),
100
branch_c.bzrdir.root_transport.base)
78
102
def test_push_without_tree(self):
79
103
# bzr push from a branch that does not have a checkout should work.
80
104
b = self.make_branch('.')
81
out, err = self.run_bzr('push', 'pushed-location')
105
out, err = self.run_bzr('push pushed-location')
82
106
self.assertEqual('', out)
83
self.assertEqual('0 revision(s) pushed.\n', err)
84
b2 = bzrlib.branch.Branch.open('pushed-location')
107
self.assertEqual('Created new branch.\n', err)
108
b2 = Branch.open('pushed-location')
85
109
self.assertEndsWith(b2.base, 'pushed-location/')
87
111
def test_push_new_branch_revision_count(self):
130
154
# Now that we have a repository with shared files, make sure
131
155
# that things aren't copied out by a 'push'
132
156
os.chdir('repo/b')
133
self.run_bzr('push', '../../push-b')
157
self.run_bzr('push ../../push-b')
134
158
pushed_tree = WorkingTree.open('../../push-b')
135
159
pushed_repo = pushed_tree.branch.repository
136
160
self.assertFalse(pushed_repo.has_revision('a-1'))
137
161
self.assertFalse(pushed_repo.has_revision('a-2'))
138
162
self.assertTrue(pushed_repo.has_revision('b-1'))
164
def test_push_funky_id(self):
165
t = self.make_branch_and_tree('tree')
167
self.build_tree(['filename'])
168
t.add('filename', 'funky-chars<>%&;"\'')
169
t.commit('commit filename')
170
self.run_bzr('push ../new-tree')
172
def test_push_dash_d(self):
173
t = self.make_branch_and_tree('from')
174
t.commit(allow_pointless=True,
175
message='first commit')
176
self.run_bzr('push -d from to-one')
177
self.failUnlessExists('to-one')
178
self.run_bzr('push -d %s %s'
179
% tuple(map(urlutils.local_path_to_url, ['from', 'to-two'])))
180
self.failUnlessExists('to-two')
182
def create_simple_tree(self):
183
tree = self.make_branch_and_tree('tree')
184
self.build_tree(['tree/a'])
185
tree.add(['a'], ['a-id'])
186
tree.commit('one', rev_id='r1')
189
def test_push_create_prefix(self):
190
"""'bzr push --create-prefix' will create leading directories."""
191
tree = self.create_simple_tree()
193
self.run_bzr_error(['Parent directory of ../new/tree does not exist'],
196
self.run_bzr('push ../new/tree --create-prefix',
198
new_tree = WorkingTree.open('new/tree')
199
self.assertEqual(tree.last_revision(), new_tree.last_revision())
200
self.failUnlessExists('new/tree/a')
202
def test_push_use_existing(self):
203
"""'bzr push --use-existing-dir' can push into an existing dir.
205
By default, 'bzr push' will not use an existing, non-versioned dir.
207
tree = self.create_simple_tree()
208
self.build_tree(['target/'])
210
self.run_bzr_error(['Target directory ../target already exists',
211
'Supply --use-existing-dir',
213
'push ../target', working_dir='tree')
215
self.run_bzr('push --use-existing-dir ../target',
218
new_tree = WorkingTree.open('target')
219
self.assertEqual(tree.last_revision(), new_tree.last_revision())
220
# The push should have created target/a
221
self.failUnlessExists('target/a')
223
def test_push_onto_repo(self):
224
"""We should be able to 'bzr push' into an existing bzrdir."""
225
tree = self.create_simple_tree()
226
repo = self.make_repository('repo', shared=True)
228
self.run_bzr('push ../repo',
231
# Pushing onto an existing bzrdir will create a repository and
232
# branch as needed, but will only create a working tree if there was
234
self.assertRaises(errors.NoWorkingTree, WorkingTree.open, 'repo')
235
new_branch = Branch.open('repo')
236
self.assertEqual(tree.last_revision(), new_branch.last_revision())
238
def test_push_onto_just_bzrdir(self):
239
"""We don't handle when the target is just a bzrdir.
241
Because you shouldn't be able to create *just* a bzrdir in the wild.
243
# TODO: jam 20070109 Maybe it would be better to create the repository
245
tree = self.create_simple_tree()
246
a_bzrdir = self.make_bzrdir('dir')
248
self.run_bzr_error(['At ../dir you have a valid .bzr control'],
252
def test_push_with_revisionspec(self):
253
"""We should be able to push a revision older than the tip."""
254
tree_from = self.make_branch_and_tree('from')
255
tree_from.commit("One.", rev_id="from-1")
256
tree_from.commit("Two.", rev_id="from-2")
258
self.run_bzr('push -r1 ../to', working_dir='from')
260
tree_to = WorkingTree.open('to')
261
repo_to = tree_to.branch.repository
262
self.assertTrue(repo_to.has_revision('from-1'))
263
self.assertFalse(repo_to.has_revision('from-2'))
264
self.assertEqual(tree_to.branch.last_revision_info()[1], 'from-1')
267
"bzr: ERROR: bzr push --revision takes one value.\n",
268
'push -r0..2 ../to', working_dir='from')
270
def create_trunk_and_feature_branch(self):
272
trunk_tree = self.make_branch_and_tree('target',
273
format='development')
274
trunk_tree.commit('mainline')
275
# and a branch from it
276
branch_tree = self.make_branch_and_tree('branch',
277
format='development')
278
branch_tree.pull(trunk_tree.branch)
279
branch_tree.branch.set_parent(trunk_tree.branch.base)
280
# with some work on it
281
branch_tree.commit('moar work plz')
282
return trunk_tree, branch_tree
284
def assertPublished(self, branch_revid, stacked_on):
285
"""Assert that the branch 'published' has been published correctly."""
286
published_branch = Branch.open('published')
287
# The published branch refers to the mainline
288
self.assertEqual(stacked_on, published_branch.get_stacked_on_url())
289
# and the branch's work was pushed
290
self.assertTrue(published_branch.repository.has_revision(branch_revid))
292
def test_push_new_branch_stacked_on(self):
293
"""Pushing a new branch with --stacked-on creates a stacked branch."""
294
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
295
# we publish branch_tree with a reference to the mainline.
296
out, err = self.run_bzr(['push', '--stacked-on', trunk_tree.branch.base,
297
self.get_url('published')], working_dir='branch')
298
self.assertEqual('', out)
299
self.assertEqual('Created new stacked branch referring to %s.\n' %
300
trunk_tree.branch.base, err)
301
self.assertPublished(branch_tree.last_revision(),
302
trunk_tree.branch.base)
304
def test_push_new_branch_stacked_uses_parent_when_no_public_url(self):
305
"""When the parent has no public url the parent is used as-is."""
306
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
307
# now we do a stacked push, which should determine the public location
309
out, err = self.run_bzr(['push', '--stacked',
310
self.get_url('published')], working_dir='branch')
311
self.assertEqual('', out)
312
self.assertEqual('Created new stacked branch referring to %s.\n' %
313
trunk_tree.branch.base, err)
314
self.assertPublished(branch_tree.last_revision(), trunk_tree.branch.base)
316
def test_push_new_branch_stacked_uses_parent_public(self):
317
"""Pushing a new branch with --stacked creates a stacked branch."""
318
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
319
# the trunk is published on a web server
320
self.transport_readonly_server = HttpServer
321
trunk_public = self.make_branch('public_trunk', format='development')
322
trunk_public.pull(trunk_tree.branch)
323
trunk_public_url = self.get_readonly_url('public_trunk')
324
trunk_tree.branch.set_public_branch(trunk_public_url)
325
# now we do a stacked push, which should determine the public location
327
out, err = self.run_bzr(['push', '--stacked',
328
self.get_url('published')], working_dir='branch')
329
self.assertEqual('', out)
330
self.assertEqual('Created new stacked branch referring to %s.\n' %
331
trunk_public_url, err)
332
self.assertPublished(branch_tree.last_revision(), trunk_public_url)
334
def test_push_new_branch_stacked_no_parent(self):
335
"""Pushing with --stacked and no parent branch errors."""
336
branch = self.make_branch_and_tree('branch', format='development')
337
# now we do a stacked push, which should fail as the place to refer too
338
# cannot be determined.
339
out, err = self.run_bzr_error(
340
['Could not determine branch to refer to\\.'], ['push', '--stacked',
341
self.get_url('published')], working_dir='branch')
342
self.assertEqual('', out)
343
self.assertFalse(self.get_transport('published').has('.'))
345
def test_push_notifies_default_stacking(self):
346
self.make_branch('stack_on', format='development1')
347
self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
348
self.make_branch('from', format='development1')
349
out, err = self.run_bzr('push -d from to')
350
self.assertContainsRe(err,
351
'Using default stacking branch stack_on at .*')
354
class RedirectingMemoryTransport(MemoryTransport):
356
def mkdir(self, path, mode=None):
357
path = self.abspath(path)[len(self._scheme):]
358
if path == '/source':
359
raise errors.RedirectRequested(
360
path, self._scheme + '/target', is_permanent=True)
361
elif path == '/infinite-loop':
362
raise errors.RedirectRequested(
363
path, self._scheme + '/infinite-loop', is_permanent=True)
365
return super(RedirectingMemoryTransport, self).mkdir(
369
class RedirectingMemoryServer(MemoryServer):
372
self._dirs = {'/': None}
375
self._scheme = 'redirecting-memory+%s:///' % id(self)
376
register_transport(self._scheme, self._memory_factory)
378
def _memory_factory(self, url):
379
result = RedirectingMemoryTransport(url)
380
result._dirs = self._dirs
381
result._files = self._files
382
result._locks = self._locks
386
unregister_transport(self._scheme, self._memory_factory)
389
class TestPushRedirect(ExternalBase):
392
ExternalBase.setUp(self)
393
self.memory_server = RedirectingMemoryServer()
394
self.memory_server.setUp()
395
self.addCleanup(self.memory_server.tearDown)
397
# Make the branch and tree that we'll be pushing.
398
t = self.make_branch_and_tree('tree')
399
self.build_tree(['tree/file'])
403
def test_push_redirects_on_mkdir(self):
404
"""If the push requires a mkdir, push respects redirect requests.
406
This is added primarily to handle lp:/ URI support, so that users can
407
push to new branches by specifying lp:/ URIs.
410
destination_url = self.memory_server.get_url() + 'source'
411
self.run_bzr('push %s' % destination_url)
414
local_revision = Branch.open('tree').last_revision()
415
remote_revision = Branch.open(
416
self.memory_server.get_url() + 'target').last_revision()
417
self.assertEqual(remote_revision, local_revision)
419
def test_push_gracefully_handles_too_many_redirects(self):
420
"""Push fails gracefully if the mkdir generates a large number of
424
destination_url = self.memory_server.get_url() + 'infinite-loop'
425
out, err = self.run_bzr_error(
426
['Too many redirections trying to make %s\\.\n'
427
% re.escape(destination_url)],
428
'push %s' % destination_url, retcode=3)
430
self.assertEqual('', out)