1
# Copyright (C) 2005-2011 Canonical Ltd
1
# Copyright (C) 2005-2012, 2016 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
21
21
from bzrlib import (
25
26
from bzrlib.branch import Branch
26
27
from bzrlib.bzrdir import BzrDirMetaFormat1
27
28
from bzrlib.commit import Commit, NullCommitReporter
28
from bzrlib.config import BranchConfig
29
29
from bzrlib.errors import (
35
35
from bzrlib.tests import (
37
36
TestCaseWithTransport,
39
from bzrlib.tests.features import (
40
42
from bzrlib.tests.matchers import MatchesAncestry
43
45
# TODO: Test commit with some added, and added-but-missing files
45
class MustSignConfig(BranchConfig):
47
def signature_needed(self):
50
def gpg_signing_command(self):
54
class BranchWithHooks(BranchConfig):
56
def post_commit(self):
57
return "bzrlib.ahook bzrlib.ahook"
47
class MustSignConfig(config.MemoryStack):
50
super(MustSignConfig, self).__init__('''
51
gpg_signing_command=cat -
52
create_signatures=always
60
56
class CapturingReporter(NullCommitReporter):
86
82
"""Commit and check two versions of a single file."""
87
83
wt = self.make_branch_and_tree('.')
89
file('hello', 'w').write('hello world')
85
with file('hello', 'w') as f: f.write('hello world')
91
wt.commit(message='add hello')
87
rev1 = wt.commit(message='add hello')
92
88
file_id = wt.path2id('hello')
94
file('hello', 'w').write('version 2')
95
wt.commit(message='commit 2')
90
with file('hello', 'w') as f: f.write('version 2')
91
rev2 = wt.commit(message='commit 2')
97
eq = self.assertEquals
99
rh = b.revision_history()
100
rev = b.repository.get_revision(rh[0])
95
rev = b.repository.get_revision(rev1)
101
96
eq(rev.message, 'add hello')
103
tree1 = b.repository.revision_tree(rh[0])
98
tree1 = b.repository.revision_tree(rev1)
105
100
text = tree1.get_file_text(file_id)
107
102
self.assertEqual('hello world', text)
109
tree2 = b.repository.revision_tree(rh[1])
104
tree2 = b.repository.revision_tree(rev2)
110
105
tree2.lock_read()
111
106
text = tree2.get_file_text(file_id)
116
111
"""Attempt a lossy commit to a native branch."""
117
112
wt = self.make_branch_and_tree('.')
119
file('hello', 'w').write('hello world')
114
with file('hello', 'w') as f: f.write('hello world')
121
116
revid = wt.commit(message='add hello', rev_id='revid', lossy=True)
122
self.assertEquals('revid', revid)
117
self.assertEqual('revid', revid)
124
119
def test_commit_lossy_foreign(self):
125
120
"""Attempt a lossy commit to a foreign branch."""
127
122
wt = self.make_branch_and_tree('.',
128
123
format=test_foreign.DummyForeignVcsDirFormat())
130
file('hello', 'w').write('hello world')
125
with file('hello', 'w') as f: f.write('hello world')
132
127
revid = wt.commit(message='add hello', lossy=True,
133
128
timestamp=1302659388, timezone=0)
134
self.assertEquals('dummy-v1:1302659388.0-0-UNKNOWN', revid)
129
self.assertEqual('dummy-v1:1302659388.0-0-UNKNOWN', revid)
136
131
def test_commit_bound_lossy_foreign(self):
137
132
"""Attempt a lossy commit to a bzr branch bound to a foreign branch."""
140
135
format=test_foreign.DummyForeignVcsDirFormat())
141
136
wt = foreign_branch.create_checkout("local")
143
file('local/hello', 'w').write('hello world')
138
with file('local/hello', 'w') as f: f.write('hello world')
145
140
revid = wt.commit(message='add hello', lossy=True,
146
141
timestamp=1302659388, timezone=0)
147
self.assertEquals('dummy-v1:1302659388.0-0-0', revid)
148
self.assertEquals('dummy-v1:1302659388.0-0-0',
142
self.assertEqual('dummy-v1:1302659388.0-0-0', revid)
143
self.assertEqual('dummy-v1:1302659388.0-0-0',
149
144
foreign_branch.last_revision())
150
self.assertEquals('dummy-v1:1302659388.0-0-0',
145
self.assertEqual('dummy-v1:1302659388.0-0-0',
151
146
wt.branch.last_revision())
153
148
def test_missing_commit(self):
154
149
"""Test a commit with a missing file"""
155
150
wt = self.make_branch_and_tree('.')
157
file('hello', 'w').write('hello world')
152
with file('hello', 'w') as f: f.write('hello world')
158
153
wt.add(['hello'], ['hello-id'])
159
154
wt.commit(message='add hello')
161
156
os.remove('hello')
162
wt.commit('removed hello', rev_id='rev2')
157
reporter = CapturingReporter()
158
wt.commit('removed hello', rev_id='rev2', reporter=reporter)
160
[('missing', u'hello'), ('deleted', u'hello')],
164
163
tree = b.repository.revision_tree('rev2')
165
164
self.assertFalse(tree.has_id('hello-id'))
188
187
"""Commit refuses unless there are changes or it's forced."""
189
188
wt = self.make_branch_and_tree('.')
191
file('hello', 'w').write('hello')
190
with file('hello', 'w') as f: f.write('hello')
192
191
wt.add(['hello'])
193
192
wt.commit(message='add hello')
194
self.assertEquals(b.revno(), 1)
193
self.assertEqual(b.revno(), 1)
195
194
self.assertRaises(PointlessCommit,
198
197
allow_pointless=False)
199
self.assertEquals(b.revno(), 1)
198
self.assertEqual(b.revno(), 1)
201
200
def test_commit_empty(self):
202
201
"""Commiting an empty tree works."""
208
207
message='empty tree',
209
208
allow_pointless=False)
210
209
wt.commit(message='empty tree', allow_pointless=True)
211
self.assertEquals(b.revno(), 2)
210
self.assertEqual(b.revno(), 2)
213
212
def test_selective_delete(self):
214
213
"""Selective commit in tree with deletions"""
215
214
wt = self.make_branch_and_tree('.')
217
file('hello', 'w').write('hello')
218
file('buongia', 'w').write('buongia')
216
with file('hello', 'w') as f: f.write('hello')
217
with file('buongia', 'w') as f: f.write('buongia')
219
218
wt.add(['hello', 'buongia'],
220
219
['hello-id', 'buongia-id'])
221
220
wt.commit(message='add files',
222
221
rev_id='test@rev-1')
224
223
os.remove('hello')
225
file('buongia', 'w').write('new text')
224
with file('buongia', 'w') as f: f.write('new text')
226
225
wt.commit(message='update text',
227
226
specific_files=['buongia'],
228
227
allow_pointless=False,
233
232
allow_pointless=False,
234
233
rev_id='test@rev-3')
236
eq = self.assertEquals
235
eq = self.assertEqual
239
238
tree2 = b.repository.revision_tree('test@rev-2')
240
239
tree2.lock_read()
241
240
self.addCleanup(tree2.unlock)
242
241
self.assertTrue(tree2.has_filename('hello'))
243
self.assertEquals(tree2.get_file_text('hello-id'), 'hello')
244
self.assertEquals(tree2.get_file_text('buongia-id'), 'new text')
242
self.assertEqual(tree2.get_file_text('hello-id'), 'hello')
243
self.assertEqual(tree2.get_file_text('buongia-id'), 'new text')
246
245
tree3 = b.repository.revision_tree('test@rev-3')
247
246
tree3.lock_read()
248
247
self.addCleanup(tree3.unlock)
249
248
self.assertFalse(tree3.has_filename('hello'))
250
self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
249
self.assertEqual(tree3.get_file_text('buongia-id'), 'new text')
252
251
def test_commit_rename(self):
253
252
"""Test commit of a revision where a file is renamed."""
260
259
tree.rename_one('hello', 'fruity')
261
260
tree.commit(message='renamed', rev_id='test@rev-2', allow_pointless=False)
263
eq = self.assertEquals
262
eq = self.assertEqual
264
263
tree1 = b.repository.revision_tree('test@rev-1')
265
264
tree1.lock_read()
266
265
self.addCleanup(tree1.unlock)
337
336
"""Commit with a removed file"""
338
337
wt = self.make_branch_and_tree('.')
340
file('hello', 'w').write('hello world')
339
with file('hello', 'w') as f: f.write('hello world')
341
340
wt.add(['hello'], ['hello-id'])
342
341
wt.commit(message='add hello')
343
342
wt.remove('hello')
354
353
for i in range(4):
355
file('hello', 'w').write((str(i) * 4) + '\n')
354
with file('hello', 'w') as f: f.write((str(i) * 4) + '\n')
357
356
wt.add(['hello'], ['hello-id'])
358
357
rev_id = 'test@rev-%d' % (i+1)
359
358
rev_ids.append(rev_id)
360
359
wt.commit(message='rev %d' % (i+1),
362
eq = self.assertEquals
363
eq(b.revision_history(), rev_ids)
364
361
for i in range(4):
365
362
self.assertThat(rev_ids[:i+1],
366
363
MatchesAncestry(b.repository, rev_ids[i]))
383
380
from bzrlib.errors import StrictCommitFailed
384
381
wt = self.make_branch_and_tree('.')
386
file('hello', 'w').write('hello world')
383
with file('hello', 'w') as f: f.write('hello world')
388
file('goodbye', 'w').write('goodbye cruel world!')
385
with file('goodbye', 'w') as f: f.write('goodbye cruel world!')
389
386
self.assertRaises(StrictCommitFailed, wt.commit,
390
387
message='add hello but not goodbye', strict=True)
395
392
wt = self.make_branch_and_tree('.')
397
file('hello', 'w').write('hello world')
394
with file('hello', 'w') as f: f.write('hello world')
399
396
wt.commit(message='add hello', strict=True)
402
399
"""Try and commit with unknown files and strict = False, should work."""
403
400
wt = self.make_branch_and_tree('.')
405
file('hello', 'w').write('hello world')
402
with file('hello', 'w') as f: f.write('hello world')
407
file('goodbye', 'w').write('goodbye cruel world!')
404
with file('goodbye', 'w') as f: f.write('goodbye cruel world!')
408
405
wt.commit(message='add hello but not goodbye', strict=False)
410
407
def test_nonstrict_commit_without_unknowns(self):
413
410
wt = self.make_branch_and_tree('.')
415
file('hello', 'w').write('hello world')
412
with file('hello', 'w') as f: f.write('hello world')
417
414
wt.commit(message='add hello', strict=False)
428
425
from bzrlib.testament import Testament
429
426
# monkey patch gpg signing mechanism
430
427
bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
431
commit.Commit(config=MustSignConfig(branch)).commit(message="base",
432
allow_pointless=True,
428
conf = config.MemoryStack('''
429
gpg_signing_command=cat -
430
create_signatures=always
432
commit.Commit(config_stack=conf).commit(
433
message="base", allow_pointless=True, rev_id='B',
436
436
return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
437
437
self.assertEqual(sign(Testament.from_revision(branch.repository,
438
'B').as_short_text()),
438
'B').as_short_text()),
439
439
branch.repository.get_signature_text('B'))
441
441
bzrlib.gpg.GPGStrategy = oldstrategy
452
452
# monkey patch gpg signing mechanism
453
453
bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
454
config = MustSignConfig(branch)
454
conf = config.MemoryStack('''
455
gpg_signing_command=cat -
456
create_signatures=always
455
458
self.assertRaises(SigningFailed,
456
commit.Commit(config=config).commit,
459
commit.Commit(config_stack=conf).commit,
458
461
allow_pointless=True,
461
464
branch = Branch.open(self.get_url('.'))
462
self.assertEqual(branch.revision_history(), ['A'])
465
self.assertEqual(branch.last_revision(), 'A')
463
466
self.assertFalse(branch.repository.has_revision('B'))
465
468
bzrlib.gpg.GPGStrategy = oldstrategy
473
476
calls.append('called')
474
477
bzrlib.ahook = called
476
config = BranchWithHooks(branch)
477
commit.Commit(config=config).commit(
479
allow_pointless=True,
480
rev_id='A', working_tree = wt)
479
conf = config.MemoryStack('post_commit=bzrlib.ahook bzrlib.ahook')
480
commit.Commit(config_stack=conf).commit(
481
message = "base", allow_pointless=True, rev_id='A',
481
483
self.assertEqual(['called', 'called'], calls)
487
489
wt = self.make_branch_and_tree('.')
489
491
c.commit(working_tree=wt, message='empty tree', allow_pointless=True)
490
self.assertEquals(wt.branch.revno(), 1)
492
self.assertEqual(wt.branch.revno(), 1)
491
493
self.assertEqual({},
492
494
wt.branch.repository.get_revision(
493
495
wt.branch.last_revision()).properties)
833
835
def test_commit_with_checkout_and_branch_sharing_repo(self):
834
836
repo = self.make_repository('repo', shared=True)
835
837
# make_branch_and_tree ignores shared repos
836
branch = bzrdir.BzrDir.create_branch_convenience('repo/branch')
838
branch = controldir.ControlDir.create_branch_convenience('repo/branch')
837
839
tree2 = branch.create_checkout('repo/tree2')
838
840
tree2.commit('message', rev_id='rev1')
839
841
self.assertTrue(tree2.branch.repository.has_revision('rev1'))