21
from bzrlib.tests import TestCaseWithTransport
20
from bzrlib.selftest import TestCaseInTempDir
22
21
from bzrlib.branch import Branch
23
from bzrlib.workingtree import WorkingTree
24
22
from bzrlib.commit import Commit
25
from bzrlib.config import BranchConfig
26
from bzrlib.errors import PointlessCommit, BzrError, SigningFailed
23
from bzrlib.errors import PointlessCommit, BzrError
29
26
# TODO: Test commit with some added, and added-but-missing files
31
class MustSignConfig(BranchConfig):
33
def signature_needed(self):
36
def gpg_signing_command(self):
40
class BranchWithHooks(BranchConfig):
42
def post_commit(self):
43
return "bzrlib.ahook bzrlib.ahook"
46
class TestCommit(TestCaseWithTransport):
28
class TestCommit(TestCaseInTempDir):
48
30
def test_simple_commit(self):
49
31
"""Commit and check two versions of a single file."""
50
wt = self.make_branch_and_tree('.')
32
b = Branch.initialize('.')
52
33
file('hello', 'w').write('hello world')
54
wt.commit(message='add hello')
55
file_id = wt.path2id('hello')
35
b.commit(message='add hello')
36
file_id = b.working_tree().path2id('hello')
57
38
file('hello', 'w').write('version 2')
58
wt.commit(message='commit 2')
39
b.commit(message='commit 2')
60
41
eq = self.assertEquals
62
43
rh = b.revision_history()
63
rev = b.repository.get_revision(rh[0])
44
rev = b.get_revision(rh[0])
64
45
eq(rev.message, 'add hello')
66
tree1 = b.repository.revision_tree(rh[0])
47
tree1 = b.revision_tree(rh[0])
67
48
text = tree1.get_file_text(file_id)
68
49
eq(text, 'hello world')
70
tree2 = b.repository.revision_tree(rh[1])
51
tree2 = b.revision_tree(rh[1])
71
52
eq(tree2.get_file_text(file_id), 'version 2')
73
55
def test_delete_commit(self):
74
56
"""Test a commit with a deleted file"""
75
wt = self.make_branch_and_tree('.')
57
b = Branch.initialize('.')
77
58
file('hello', 'w').write('hello world')
78
wt.add(['hello'], ['hello-id'])
79
wt.commit(message='add hello')
59
b.add(['hello'], ['hello-id'])
60
b.commit(message='add hello')
82
wt.commit('removed hello', rev_id='rev2')
63
b.commit('removed hello', rev_id='rev2')
84
tree = b.repository.revision_tree('rev2')
65
tree = b.revision_tree('rev2')
85
66
self.assertFalse(tree.has_id('hello-id'))
87
69
def test_pointless_commit(self):
88
70
"""Commit refuses unless there are changes or it's forced."""
89
wt = self.make_branch_and_tree('.')
71
b = Branch.initialize('.')
91
72
file('hello', 'w').write('hello')
93
wt.commit(message='add hello')
74
b.commit(message='add hello')
94
75
self.assertEquals(b.revno(), 1)
95
76
self.assertRaises(PointlessCommit,
98
79
allow_pointless=False)
99
80
self.assertEquals(b.revno(), 1)
101
84
def test_commit_empty(self):
102
85
"""Commiting an empty tree works."""
103
wt = self.make_branch_and_tree('.')
105
wt.commit(message='empty tree', allow_pointless=True)
86
b = Branch.initialize('.')
87
b.commit(message='empty tree', allow_pointless=True)
106
88
self.assertRaises(PointlessCommit,
108
90
message='empty tree',
109
91
allow_pointless=False)
110
wt.commit(message='empty tree', allow_pointless=True)
92
b.commit(message='empty tree', allow_pointless=True)
111
93
self.assertEquals(b.revno(), 2)
113
96
def test_selective_delete(self):
114
97
"""Selective commit in tree with deletions"""
115
wt = self.make_branch_and_tree('.')
98
b = Branch.initialize('.')
117
99
file('hello', 'w').write('hello')
118
100
file('buongia', 'w').write('buongia')
119
wt.add(['hello', 'buongia'],
101
b.add(['hello', 'buongia'],
120
102
['hello-id', 'buongia-id'])
121
wt.commit(message='add files',
103
b.commit(message='add files',
122
104
rev_id='test@rev-1')
124
106
os.remove('hello')
125
107
file('buongia', 'w').write('new text')
126
wt.commit(message='update text',
108
b.commit(message='update text',
127
109
specific_files=['buongia'],
128
110
allow_pointless=False,
129
111
rev_id='test@rev-2')
131
wt.commit(message='remove hello',
113
b.commit(message='remove hello',
132
114
specific_files=['hello'],
133
115
allow_pointless=False,
134
116
rev_id='test@rev-3')
165
147
ie = tree1.inventory['hello-id']
166
148
eq(ie.revision, 'test@rev-1')
168
tree2 = b.repository.revision_tree('test@rev-2')
150
tree2 = b.revision_tree('test@rev-2')
169
151
eq(tree2.id2path('hello-id'), 'fruity')
170
152
eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
171
153
self.check_inventory_shape(tree2.inventory, ['fruity'])
172
154
ie = tree2.inventory['hello-id']
173
155
eq(ie.revision, 'test@rev-2')
175
158
def test_reused_rev_id(self):
176
159
"""Test that a revision id cannot be reused in a branch"""
177
wt = self.make_branch_and_tree('.')
179
wt.commit('initial', rev_id='test@rev-1', allow_pointless=True)
160
b = Branch.initialize('.')
161
b.commit('initial', rev_id='test@rev-1', allow_pointless=True)
180
162
self.assertRaises(Exception,
182
164
message='reused id',
183
165
rev_id='test@rev-1',
184
166
allow_pointless=True)
186
170
def test_commit_move(self):
187
171
"""Test commit of revisions with moved files and directories"""
188
172
eq = self.assertEquals
189
wt = self.make_branch_and_tree('.')
173
b = Branch.initialize('.')
191
174
r1 = 'test@rev-1'
192
175
self.build_tree(['hello', 'a/', 'b/'])
193
wt.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
194
wt.commit('initial', rev_id=r1, allow_pointless=False)
195
wt.move(['hello'], 'a')
176
b.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
177
b.commit('initial', rev_id=r1, allow_pointless=False)
179
b.move(['hello'], 'a')
196
180
r2 = 'test@rev-2'
197
wt.commit('two', rev_id=r2, allow_pointless=False)
198
self.check_inventory_shape(wt.read_working_inventory(),
181
b.commit('two', rev_id=r2, allow_pointless=False)
182
self.check_inventory_shape(b.inventory,
199
183
['a', 'a/hello', 'b'])
202
186
r3 = 'test@rev-3'
203
wt.commit('three', rev_id=r3, allow_pointless=False)
204
self.check_inventory_shape(wt.read_working_inventory(),
187
b.commit('three', rev_id=r3, allow_pointless=False)
188
self.check_inventory_shape(b.inventory,
205
189
['a', 'a/hello', 'a/b'])
206
self.check_inventory_shape(b.repository.get_revision_inventory(r3),
190
self.check_inventory_shape(b.get_revision_inventory(r3),
207
191
['a', 'a/hello', 'a/b'])
209
wt.move(['a/hello'], 'a/b')
193
b.move([os.sep.join(['a', 'hello'])],
194
os.sep.join(['a', 'b']))
210
195
r4 = 'test@rev-4'
211
wt.commit('four', rev_id=r4, allow_pointless=False)
212
self.check_inventory_shape(wt.read_working_inventory(),
196
b.commit('four', rev_id=r4, allow_pointless=False)
197
self.check_inventory_shape(b.inventory,
213
198
['a', 'a/b/hello', 'a/b'])
215
inv = b.repository.get_revision_inventory(r4)
200
inv = b.get_revision_inventory(r4)
216
201
eq(inv['hello-id'].revision, r4)
217
202
eq(inv['a-id'].revision, r1)
218
203
eq(inv['b-id'].revision, r3)
220
206
def test_removed_commit(self):
221
"""Commit with a removed file"""
222
wt = self.make_branch_and_tree('.')
207
"""Test a commit with a removed file"""
208
b = Branch.initialize('.')
224
209
file('hello', 'w').write('hello world')
225
wt.add(['hello'], ['hello-id'])
226
wt.commit(message='add hello')
228
wt.commit('removed hello', rev_id='rev2')
230
tree = b.repository.revision_tree('rev2')
210
b.add(['hello'], ['hello-id'])
211
b.commit(message='add hello')
214
b.commit('removed hello', rev_id='rev2')
216
tree = b.revision_tree('rev2')
231
217
self.assertFalse(tree.has_id('hello-id'))
233
220
def test_committed_ancestry(self):
234
221
"""Test commit appends revisions to ancestry."""
235
wt = self.make_branch_and_tree('.')
222
b = Branch.initialize('.')
238
224
for i in range(4):
239
225
file('hello', 'w').write((str(i) * 4) + '\n')
241
wt.add(['hello'], ['hello-id'])
227
b.add(['hello'], ['hello-id'])
242
228
rev_id = 'test@rev-%d' % (i+1)
243
229
rev_ids.append(rev_id)
244
wt.commit(message='rev %d' % (i+1),
230
b.commit(message='rev %d' % (i+1),
246
232
eq = self.assertEquals
247
233
eq(b.revision_history(), rev_ids)
248
234
for i in range(4):
249
anc = b.repository.get_ancestry(rev_ids[i])
235
anc = b.get_ancestry(rev_ids[i])
250
236
eq(anc, [None] + rev_ids[:i+1])
252
238
def test_commit_new_subdir_child_selective(self):
253
wt = self.make_branch_and_tree('.')
239
b = Branch.initialize('.')
255
240
self.build_tree(['dir/', 'dir/file1', 'dir/file2'])
256
wt.add(['dir', 'dir/file1', 'dir/file2'],
241
b.add(['dir', 'dir/file1', 'dir/file2'],
257
242
['dirid', 'file1id', 'file2id'])
258
wt.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
259
inv = b.repository.get_inventory('1')
243
b.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
244
inv = b.get_inventory('1')
260
245
self.assertEqual('1', inv['dirid'].revision)
261
246
self.assertEqual('1', inv['file1id'].revision)
262
247
# FIXME: This should raise a KeyError I think, rbc20051006
263
248
self.assertRaises(BzrError, inv.__getitem__, 'file2id')
265
def test_strict_commit(self):
266
"""Try and commit with unknown files and strict = True, should fail."""
267
from bzrlib.errors import StrictCommitFailed
268
wt = self.make_branch_and_tree('.')
270
file('hello', 'w').write('hello world')
272
file('goodbye', 'w').write('goodbye cruel world!')
273
self.assertRaises(StrictCommitFailed, wt.commit,
274
message='add hello but not goodbye', strict=True)
276
def test_strict_commit_without_unknowns(self):
277
"""Try and commit with no unknown files and strict = True,
279
from bzrlib.errors import StrictCommitFailed
280
wt = self.make_branch_and_tree('.')
282
file('hello', 'w').write('hello world')
284
wt.commit(message='add hello', strict=True)
286
def test_nonstrict_commit(self):
287
"""Try and commit with unknown files and strict = False, should work."""
288
wt = self.make_branch_and_tree('.')
290
file('hello', 'w').write('hello world')
292
file('goodbye', 'w').write('goodbye cruel world!')
293
wt.commit(message='add hello but not goodbye', strict=False)
295
def test_nonstrict_commit_without_unknowns(self):
296
"""Try and commit with no unknown files and strict = False,
298
wt = self.make_branch_and_tree('.')
300
file('hello', 'w').write('hello world')
302
wt.commit(message='add hello', strict=False)
304
def test_signed_commit(self):
306
import bzrlib.commit as commit
307
oldstrategy = bzrlib.gpg.GPGStrategy
308
wt = self.make_branch_and_tree('.')
310
wt.commit("base", allow_pointless=True, rev_id='A')
311
self.failIf(branch.repository.revision_store.has_id('A', 'sig'))
313
from bzrlib.testament import Testament
314
# monkey patch gpg signing mechanism
315
bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
316
commit.Commit(config=MustSignConfig(branch)).commit(message="base",
317
allow_pointless=True,
320
self.assertEqual(Testament.from_revision(branch.repository,
321
'B').as_short_text(),
322
branch.repository.revision_store.get('B',
325
bzrlib.gpg.GPGStrategy = oldstrategy
327
def test_commit_failed_signature(self):
329
import bzrlib.commit as commit
330
oldstrategy = bzrlib.gpg.GPGStrategy
331
wt = self.make_branch_and_tree('.')
333
wt.commit("base", allow_pointless=True, rev_id='A')
334
self.failIf(branch.repository.revision_store.has_id('A', 'sig'))
336
from bzrlib.testament import Testament
337
# monkey patch gpg signing mechanism
338
bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
339
config = MustSignConfig(branch)
340
self.assertRaises(SigningFailed,
341
commit.Commit(config=config).commit,
343
allow_pointless=True,
346
branch = Branch.open(self.get_url('.'))
347
self.assertEqual(branch.revision_history(), ['A'])
348
self.failIf(branch.repository.revision_store.has_id('B'))
350
bzrlib.gpg.GPGStrategy = oldstrategy
352
def test_commit_invokes_hooks(self):
353
import bzrlib.commit as commit
354
wt = self.make_branch_and_tree('.')
357
def called(branch, rev_id):
358
calls.append('called')
359
bzrlib.ahook = called
361
config = BranchWithHooks(branch)
362
commit.Commit(config=config).commit(
364
allow_pointless=True,
365
rev_id='A', working_tree = wt)
366
self.assertEqual(['called', 'called'], calls)