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
29
def test_simple_commit(self):
49
30
"""Commit and check two versions of a single file."""
50
wt = self.make_branch_and_tree('.')
31
b = Branch('.', init=True)
52
32
file('hello', 'w').write('hello world')
54
wt.commit(message='add hello')
55
file_id = wt.path2id('hello')
34
b.commit(message='add hello')
35
file_id = b.working_tree().path2id('hello')
57
37
file('hello', 'w').write('version 2')
58
wt.commit(message='commit 2')
38
b.commit(message='commit 2')
60
40
eq = self.assertEquals
62
42
rh = b.revision_history()
63
rev = b.repository.get_revision(rh[0])
43
rev = b.get_revision(rh[0])
64
44
eq(rev.message, 'add hello')
66
tree1 = b.repository.revision_tree(rh[0])
46
tree1 = b.revision_tree(rh[0])
67
47
text = tree1.get_file_text(file_id)
68
48
eq(text, 'hello world')
70
tree2 = b.repository.revision_tree(rh[1])
50
tree2 = b.revision_tree(rh[1])
71
51
eq(tree2.get_file_text(file_id), 'version 2')
73
54
def test_delete_commit(self):
74
55
"""Test a commit with a deleted file"""
75
wt = self.make_branch_and_tree('.')
56
b = Branch('.', init=True)
77
57
file('hello', 'w').write('hello world')
78
wt.add(['hello'], ['hello-id'])
79
wt.commit(message='add hello')
58
b.add(['hello'], ['hello-id'])
59
b.commit(message='add hello')
82
wt.commit('removed hello', rev_id='rev2')
62
b.commit('removed hello', rev_id='rev2')
84
tree = b.repository.revision_tree('rev2')
64
tree = b.revision_tree('rev2')
85
65
self.assertFalse(tree.has_id('hello-id'))
87
68
def test_pointless_commit(self):
88
69
"""Commit refuses unless there are changes or it's forced."""
89
wt = self.make_branch_and_tree('.')
70
b = Branch('.', init=True)
91
71
file('hello', 'w').write('hello')
93
wt.commit(message='add hello')
73
b.commit(message='add hello')
94
74
self.assertEquals(b.revno(), 1)
95
75
self.assertRaises(PointlessCommit,
98
78
allow_pointless=False)
99
79
self.assertEquals(b.revno(), 1)
101
83
def test_commit_empty(self):
102
84
"""Commiting an empty tree works."""
103
wt = self.make_branch_and_tree('.')
105
wt.commit(message='empty tree', allow_pointless=True)
85
b = Branch('.', init=True)
86
b.commit(message='empty tree', allow_pointless=True)
106
87
self.assertRaises(PointlessCommit,
108
89
message='empty tree',
109
90
allow_pointless=False)
110
wt.commit(message='empty tree', allow_pointless=True)
91
b.commit(message='empty tree', allow_pointless=True)
111
92
self.assertEquals(b.revno(), 2)
113
95
def test_selective_delete(self):
114
96
"""Selective commit in tree with deletions"""
115
wt = self.make_branch_and_tree('.')
97
b = Branch('.', init=True)
117
98
file('hello', 'w').write('hello')
118
99
file('buongia', 'w').write('buongia')
119
wt.add(['hello', 'buongia'],
100
b.add(['hello', 'buongia'],
120
101
['hello-id', 'buongia-id'])
121
wt.commit(message='add files',
102
b.commit(message='add files',
122
103
rev_id='test@rev-1')
124
105
os.remove('hello')
125
106
file('buongia', 'w').write('new text')
126
wt.commit(message='update text',
107
b.commit(message='update text',
127
108
specific_files=['buongia'],
128
109
allow_pointless=False,
129
110
rev_id='test@rev-2')
131
wt.commit(message='remove hello',
112
b.commit(message='remove hello',
132
113
specific_files=['hello'],
133
114
allow_pointless=False,
134
115
rev_id='test@rev-3')
136
117
eq = self.assertEquals
139
tree2 = b.repository.revision_tree('test@rev-2')
120
tree2 = b.revision_tree('test@rev-2')
140
121
self.assertTrue(tree2.has_filename('hello'))
141
122
self.assertEquals(tree2.get_file_text('hello-id'), 'hello')
142
123
self.assertEquals(tree2.get_file_text('buongia-id'), 'new text')
144
tree3 = b.repository.revision_tree('test@rev-3')
125
tree3 = b.revision_tree('test@rev-3')
145
126
self.assertFalse(tree3.has_filename('hello'))
146
127
self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
148
130
def test_commit_rename(self):
149
131
"""Test commit of a revision where a file is renamed."""
150
tree = self.make_branch_and_tree('.')
152
self.build_tree(['hello'], line_endings='binary')
153
tree.add(['hello'], ['hello-id'])
154
tree.commit(message='one', rev_id='test@rev-1', allow_pointless=False)
132
b = Branch('.', init=True)
133
self.build_tree(['hello'])
134
b.add(['hello'], ['hello-id'])
135
b.commit(message='one', rev_id='test@rev-1', allow_pointless=False)
156
tree.rename_one('hello', 'fruity')
157
tree.commit(message='renamed', rev_id='test@rev-2', allow_pointless=False)
137
b.rename_one('hello', 'fruity')
138
b.commit(message='renamed', rev_id='test@rev-2', allow_pointless=False)
159
140
eq = self.assertEquals
160
tree1 = b.repository.revision_tree('test@rev-1')
141
tree1 = b.revision_tree('test@rev-1')
161
142
eq(tree1.id2path('hello-id'), 'hello')
162
143
eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
163
144
self.assertFalse(tree1.has_filename('fruity'))
164
145
self.check_inventory_shape(tree1.inventory, ['hello'])
165
146
ie = tree1.inventory['hello-id']
166
eq(ie.revision, 'test@rev-1')
147
eq(ie.name_version, 'test@rev-1')
168
tree2 = b.repository.revision_tree('test@rev-2')
149
tree2 = b.revision_tree('test@rev-2')
169
150
eq(tree2.id2path('hello-id'), 'fruity')
170
151
eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
171
152
self.check_inventory_shape(tree2.inventory, ['fruity'])
172
153
ie = tree2.inventory['hello-id']
173
eq(ie.revision, 'test@rev-2')
154
eq(ie.name_version, 'test@rev-2')
175
157
def test_reused_rev_id(self):
176
158
"""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)
159
b = Branch('.', init=True)
160
b.commit('initial', rev_id='test@rev-1', allow_pointless=True)
180
161
self.assertRaises(Exception,
182
163
message='reused id',
183
164
rev_id='test@rev-1',
184
165
allow_pointless=True)
186
169
def test_commit_move(self):
187
170
"""Test commit of revisions with moved files and directories"""
188
171
eq = self.assertEquals
189
wt = self.make_branch_and_tree('.')
172
b = Branch('.', init=True)
191
173
r1 = 'test@rev-1'
192
174
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')
175
b.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
176
b.commit('initial', rev_id=r1, allow_pointless=False)
178
b.move(['hello'], 'a')
196
179
r2 = 'test@rev-2'
197
wt.commit('two', rev_id=r2, allow_pointless=False)
198
self.check_inventory_shape(wt.read_working_inventory(),
180
b.commit('two', rev_id=r2, allow_pointless=False)
181
self.check_inventory_shape(b.inventory,
199
182
['a', 'a/hello', 'b'])
202
185
r3 = 'test@rev-3'
203
wt.commit('three', rev_id=r3, allow_pointless=False)
204
self.check_inventory_shape(wt.read_working_inventory(),
186
b.commit('three', rev_id=r3, allow_pointless=False)
187
self.check_inventory_shape(b.inventory,
205
188
['a', 'a/hello', 'a/b'])
206
self.check_inventory_shape(b.repository.get_revision_inventory(r3),
189
self.check_inventory_shape(b.get_revision_inventory(r3),
207
190
['a', 'a/hello', 'a/b'])
209
wt.move(['a/hello'], 'a/b')
192
b.move([os.sep.join(['a', 'hello'])],
193
os.sep.join(['a', 'b']))
210
194
r4 = 'test@rev-4'
211
wt.commit('four', rev_id=r4, allow_pointless=False)
212
self.check_inventory_shape(wt.read_working_inventory(),
195
b.commit('four', rev_id=r4, allow_pointless=False)
196
self.check_inventory_shape(b.inventory,
213
197
['a', 'a/b/hello', 'a/b'])
215
inv = b.repository.get_revision_inventory(r4)
216
eq(inv['hello-id'].revision, r4)
217
eq(inv['a-id'].revision, r1)
218
eq(inv['b-id'].revision, r3)
199
inv = b.get_revision_inventory(r4)
200
eq(inv['hello-id'].name_version, r4)
201
eq(inv['a-id'].name_version, r1)
202
eq(inv['b-id'].name_version, r3)
220
205
def test_removed_commit(self):
221
"""Commit with a removed file"""
222
wt = self.make_branch_and_tree('.')
206
"""Test a commit with a removed file"""
207
b = Branch('.', init=True)
224
208
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')
209
b.add(['hello'], ['hello-id'])
210
b.commit(message='add hello')
213
b.commit('removed hello', rev_id='rev2')
215
tree = b.revision_tree('rev2')
231
216
self.assertFalse(tree.has_id('hello-id'))
233
219
def test_committed_ancestry(self):
234
220
"""Test commit appends revisions to ancestry."""
235
wt = self.make_branch_and_tree('.')
221
b = Branch('.', init=True)
238
223
for i in range(4):
239
224
file('hello', 'w').write((str(i) * 4) + '\n')
241
wt.add(['hello'], ['hello-id'])
226
b.add(['hello'], ['hello-id'])
242
227
rev_id = 'test@rev-%d' % (i+1)
243
228
rev_ids.append(rev_id)
244
wt.commit(message='rev %d' % (i+1),
229
b.commit(message='rev %d' % (i+1),
246
231
eq = self.assertEquals
247
232
eq(b.revision_history(), rev_ids)
248
233
for i in range(4):
249
anc = b.repository.get_ancestry(rev_ids[i])
250
eq(anc, [None] + rev_ids[:i+1])
252
def test_commit_new_subdir_child_selective(self):
253
wt = self.make_branch_and_tree('.')
255
self.build_tree(['dir/', 'dir/file1', 'dir/file2'])
256
wt.add(['dir', 'dir/file1', 'dir/file2'],
257
['dirid', 'file1id', 'file2id'])
258
wt.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
259
inv = b.repository.get_inventory('1')
260
self.assertEqual('1', inv['dirid'].revision)
261
self.assertEqual('1', inv['file1id'].revision)
262
# FIXME: This should raise a KeyError I think, rbc20051006
263
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)
234
anc = b.get_ancestry(rev_ids[i])
235
eq(anc, rev_ids[:i+1])
240
if __name__ == '__main__':