~bzr-pqm/bzr/bzr.dev

2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
1
# Copyright (C) 2005, 2006 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1246 by Martin Pool
- add very simple commit tests
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1246 by Martin Pool
- add very simple commit tests
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1246 by Martin Pool
- add very simple commit tests
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
18
import os
19
1472 by Robert Collins
post commit hook, first pass implementation
20
import bzrlib
1957.1.17 by John Arbash Meinel
Change tests that expect locking to fail to timeout sooner.
21
from bzrlib import (
22
    errors,
23
    lockdir,
24
    )
1246 by Martin Pool
- add very simple commit tests
25
from bzrlib.branch import Branch
1614.1.1 by Aaron Bentley
Fixed master locking in commit
26
from bzrlib.bzrdir import BzrDir, BzrDirMetaFormat1
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
27
from bzrlib.commit import Commit, NullCommitReporter
1442.1.60 by Robert Collins
gpg sign commits if the policy says we need to
28
from bzrlib.config import BranchConfig
1614.1.1 by Aaron Bentley
Fixed master locking in commit
29
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed, 
30
                           LockContention)
1957.1.17 by John Arbash Meinel
Change tests that expect locking to fail to timeout sooner.
31
from bzrlib.tests import TestCaseWithTransport
32
from bzrlib.workingtree import WorkingTree
1246 by Martin Pool
- add very simple commit tests
33
34
1257 by Martin Pool
doc
35
# TODO: Test commit with some added, and added-but-missing files
36
1442.1.60 by Robert Collins
gpg sign commits if the policy says we need to
37
class MustSignConfig(BranchConfig):
38
39
    def signature_needed(self):
40
        return True
41
42
    def gpg_signing_command(self):
43
        return ['cat', '-']
44
45
1472 by Robert Collins
post commit hook, first pass implementation
46
class BranchWithHooks(BranchConfig):
47
48
    def post_commit(self):
49
        return "bzrlib.ahook bzrlib.ahook"
50
51
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
52
class CapturingReporter(NullCommitReporter):
53
    """This reporter captures the calls made to it for evaluation later."""
54
55
    def __init__(self):
56
        # a list of the calls this received
57
        self.calls = []
58
59
    def snapshot_change(self, change, path):
60
        self.calls.append(('change', change, path))
61
62
    def deleted(self, file_id):
63
        self.calls.append(('deleted', file_id))
64
65
    def missing(self, path):
66
        self.calls.append(('missing', path))
67
68
    def renamed(self, change, old_path, new_path):
69
        self.calls.append(('renamed', change, old_path, new_path))
70
71
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
72
class TestCommit(TestCaseWithTransport):
1390 by Robert Collins
pair programming worx... merge integration and weave
73
1246 by Martin Pool
- add very simple commit tests
74
    def test_simple_commit(self):
75
        """Commit and check two versions of a single file."""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
76
        wt = self.make_branch_and_tree('.')
77
        b = wt.branch
1246 by Martin Pool
- add very simple commit tests
78
        file('hello', 'w').write('hello world')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
79
        wt.add('hello')
80
        wt.commit(message='add hello')
81
        file_id = wt.path2id('hello')
1246 by Martin Pool
- add very simple commit tests
82
83
        file('hello', 'w').write('version 2')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
84
        wt.commit(message='commit 2')
1246 by Martin Pool
- add very simple commit tests
85
86
        eq = self.assertEquals
87
        eq(b.revno(), 2)
88
        rh = b.revision_history()
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
89
        rev = b.repository.get_revision(rh[0])
1246 by Martin Pool
- add very simple commit tests
90
        eq(rev.message, 'add hello')
91
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
92
        tree1 = b.repository.revision_tree(rh[0])
1246 by Martin Pool
- add very simple commit tests
93
        text = tree1.get_file_text(file_id)
94
        eq(text, 'hello world')
95
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
96
        tree2 = b.repository.revision_tree(rh[1])
1246 by Martin Pool
- add very simple commit tests
97
        eq(tree2.get_file_text(file_id), 'version 2')
98
99
    def test_delete_commit(self):
100
        """Test a commit with a deleted file"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
101
        wt = self.make_branch_and_tree('.')
102
        b = wt.branch
1247 by Martin Pool
- tests for deletion and removal of files in commits
103
        file('hello', 'w').write('hello world')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
104
        wt.add(['hello'], ['hello-id'])
105
        wt.commit(message='add hello')
1247 by Martin Pool
- tests for deletion and removal of files in commits
106
107
        os.remove('hello')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
108
        wt.commit('removed hello', rev_id='rev2')
1247 by Martin Pool
- tests for deletion and removal of files in commits
109
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
110
        tree = b.repository.revision_tree('rev2')
1247 by Martin Pool
- tests for deletion and removal of files in commits
111
        self.assertFalse(tree.has_id('hello-id'))
112
1253 by Martin Pool
- test that pointless commits are trapped
113
    def test_pointless_commit(self):
114
        """Commit refuses unless there are changes or it's forced."""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
115
        wt = self.make_branch_and_tree('.')
116
        b = wt.branch
1253 by Martin Pool
- test that pointless commits are trapped
117
        file('hello', 'w').write('hello')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
118
        wt.add(['hello'])
119
        wt.commit(message='add hello')
1253 by Martin Pool
- test that pointless commits are trapped
120
        self.assertEquals(b.revno(), 1)
121
        self.assertRaises(PointlessCommit,
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
122
                          wt.commit,
1253 by Martin Pool
- test that pointless commits are trapped
123
                          message='fails',
124
                          allow_pointless=False)
125
        self.assertEquals(b.revno(), 1)
126
        
1252 by Martin Pool
- add test for commit of an empty tree
127
    def test_commit_empty(self):
1253 by Martin Pool
- test that pointless commits are trapped
128
        """Commiting an empty tree works."""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
129
        wt = self.make_branch_and_tree('.')
130
        b = wt.branch
131
        wt.commit(message='empty tree', allow_pointless=True)
1253 by Martin Pool
- test that pointless commits are trapped
132
        self.assertRaises(PointlessCommit,
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
133
                          wt.commit,
1253 by Martin Pool
- test that pointless commits are trapped
134
                          message='empty tree',
135
                          allow_pointless=False)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
136
        wt.commit(message='empty tree', allow_pointless=True)
1252 by Martin Pool
- add test for commit of an empty tree
137
        self.assertEquals(b.revno(), 2)
138
139
    def test_selective_delete(self):
140
        """Selective commit in tree with deletions"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
141
        wt = self.make_branch_and_tree('.')
142
        b = wt.branch
1254 by Martin Pool
- fix handling of selective commit with deleted files
143
        file('hello', 'w').write('hello')
144
        file('buongia', 'w').write('buongia')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
145
        wt.add(['hello', 'buongia'],
1255 by Martin Pool
- more tests for selective commit of deletion
146
              ['hello-id', 'buongia-id'])
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
147
        wt.commit(message='add files',
1255 by Martin Pool
- more tests for selective commit of deletion
148
                 rev_id='test@rev-1')
1254 by Martin Pool
- fix handling of selective commit with deleted files
149
        
150
        os.remove('hello')
151
        file('buongia', 'w').write('new text')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
152
        wt.commit(message='update text',
1254 by Martin Pool
- fix handling of selective commit with deleted files
153
                 specific_files=['buongia'],
1255 by Martin Pool
- more tests for selective commit of deletion
154
                 allow_pointless=False,
155
                 rev_id='test@rev-2')
1254 by Martin Pool
- fix handling of selective commit with deleted files
156
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
157
        wt.commit(message='remove hello',
1254 by Martin Pool
- fix handling of selective commit with deleted files
158
                 specific_files=['hello'],
1255 by Martin Pool
- more tests for selective commit of deletion
159
                 allow_pointless=False,
160
                 rev_id='test@rev-3')
1254 by Martin Pool
- fix handling of selective commit with deleted files
161
162
        eq = self.assertEquals
163
        eq(b.revno(), 3)
1255 by Martin Pool
- more tests for selective commit of deletion
164
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
165
        tree2 = b.repository.revision_tree('test@rev-2')
1255 by Martin Pool
- more tests for selective commit of deletion
166
        self.assertTrue(tree2.has_filename('hello'))
167
        self.assertEquals(tree2.get_file_text('hello-id'), 'hello')
168
        self.assertEquals(tree2.get_file_text('buongia-id'), 'new text')
169
        
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
170
        tree3 = b.repository.revision_tree('test@rev-3')
1255 by Martin Pool
- more tests for selective commit of deletion
171
        self.assertFalse(tree3.has_filename('hello'))
172
        self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
1285 by Martin Pool
- fix bug in committing files that are renamed but not modified
173
174
    def test_commit_rename(self):
175
        """Test commit of a revision where a file is renamed."""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
176
        tree = self.make_branch_and_tree('.')
177
        b = tree.branch
1185.38.7 by John Arbash Meinel
Updated build_tree to use fixed line-endings for tests which read the file contents and compare
178
        self.build_tree(['hello'], line_endings='binary')
1508.1.7 by Robert Collins
Move rename_one from Branch to WorkingTree. (Robert Collins).
179
        tree.add(['hello'], ['hello-id'])
180
        tree.commit(message='one', rev_id='test@rev-1', allow_pointless=False)
1285 by Martin Pool
- fix bug in committing files that are renamed but not modified
181
1508.1.7 by Robert Collins
Move rename_one from Branch to WorkingTree. (Robert Collins).
182
        tree.rename_one('hello', 'fruity')
183
        tree.commit(message='renamed', rev_id='test@rev-2', allow_pointless=False)
1285 by Martin Pool
- fix bug in committing files that are renamed but not modified
184
1303 by Martin Pool
- commit updates entry_version
185
        eq = self.assertEquals
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
186
        tree1 = b.repository.revision_tree('test@rev-1')
1303 by Martin Pool
- commit updates entry_version
187
        eq(tree1.id2path('hello-id'), 'hello')
188
        eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
1285 by Martin Pool
- fix bug in committing files that are renamed but not modified
189
        self.assertFalse(tree1.has_filename('fruity'))
1291 by Martin Pool
- add test for moving files between directories
190
        self.check_inventory_shape(tree1.inventory, ['hello'])
1303 by Martin Pool
- commit updates entry_version
191
        ie = tree1.inventory['hello-id']
1092.2.21 by Robert Collins
convert name_version to revision in inventory entries
192
        eq(ie.revision, 'test@rev-1')
1285 by Martin Pool
- fix bug in committing files that are renamed but not modified
193
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
194
        tree2 = b.repository.revision_tree('test@rev-2')
1303 by Martin Pool
- commit updates entry_version
195
        eq(tree2.id2path('hello-id'), 'fruity')
196
        eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
1291 by Martin Pool
- add test for moving files between directories
197
        self.check_inventory_shape(tree2.inventory, ['fruity'])
1303 by Martin Pool
- commit updates entry_version
198
        ie = tree2.inventory['hello-id']
1092.2.21 by Robert Collins
convert name_version to revision in inventory entries
199
        eq(ie.revision, 'test@rev-2')
1291 by Martin Pool
- add test for moving files between directories
200
201
    def test_reused_rev_id(self):
1292 by Martin Pool
- add check that revision ids cannot be committed twice
202
        """Test that a revision id cannot be reused in a branch"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
203
        wt = self.make_branch_and_tree('.')
204
        b = wt.branch
205
        wt.commit('initial', rev_id='test@rev-1', allow_pointless=True)
1292 by Martin Pool
- add check that revision ids cannot be committed twice
206
        self.assertRaises(Exception,
1534.4.35 by Robert Collins
Give branch its own basis tree and last_revision methods; deprecated branch.working_tree()
207
                          wt.commit,
1292 by Martin Pool
- add check that revision ids cannot be committed twice
208
                          message='reused id',
209
                          rev_id='test@rev-1',
210
                          allow_pointless=True)
1291 by Martin Pool
- add test for moving files between directories
211
212
    def test_commit_move(self):
213
        """Test commit of revisions with moved files and directories"""
1306 by Martin Pool
- tests that name_version is updated properly in renames/moves
214
        eq = self.assertEquals
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
215
        wt = self.make_branch_and_tree('.')
216
        b = wt.branch
1306 by Martin Pool
- tests that name_version is updated properly in renames/moves
217
        r1 = 'test@rev-1'
1291 by Martin Pool
- add test for moving files between directories
218
        self.build_tree(['hello', 'a/', 'b/'])
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
219
        wt.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
220
        wt.commit('initial', rev_id=r1, allow_pointless=False)
221
        wt.move(['hello'], 'a')
1306 by Martin Pool
- tests that name_version is updated properly in renames/moves
222
        r2 = 'test@rev-2'
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
223
        wt.commit('two', rev_id=r2, allow_pointless=False)
1534.4.35 by Robert Collins
Give branch its own basis tree and last_revision methods; deprecated branch.working_tree()
224
        self.check_inventory_shape(wt.read_working_inventory(),
1291 by Martin Pool
- add test for moving files between directories
225
                                   ['a', 'a/hello', 'b'])
226
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
227
        wt.move(['b'], 'a')
1306 by Martin Pool
- tests that name_version is updated properly in renames/moves
228
        r3 = 'test@rev-3'
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
229
        wt.commit('three', rev_id=r3, allow_pointless=False)
230
        self.check_inventory_shape(wt.read_working_inventory(),
1291 by Martin Pool
- add test for moving files between directories
231
                                   ['a', 'a/hello', 'a/b'])
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
232
        self.check_inventory_shape(b.repository.get_revision_inventory(r3),
1291 by Martin Pool
- add test for moving files between directories
233
                                   ['a', 'a/hello', 'a/b'])
234
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
235
        wt.move(['a/hello'], 'a/b')
1306 by Martin Pool
- tests that name_version is updated properly in renames/moves
236
        r4 = 'test@rev-4'
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
237
        wt.commit('four', rev_id=r4, allow_pointless=False)
238
        self.check_inventory_shape(wt.read_working_inventory(),
1291 by Martin Pool
- add test for moving files between directories
239
                                   ['a', 'a/b/hello', 'a/b'])
1306 by Martin Pool
- tests that name_version is updated properly in renames/moves
240
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
241
        inv = b.repository.get_revision_inventory(r4)
1092.2.21 by Robert Collins
convert name_version to revision in inventory entries
242
        eq(inv['hello-id'].revision, r4)
243
        eq(inv['a-id'].revision, r1)
244
        eq(inv['b-id'].revision, r3)
1306 by Martin Pool
- tests that name_version is updated properly in renames/moves
245
        
1246 by Martin Pool
- add very simple commit tests
246
    def test_removed_commit(self):
1185.16.72 by Martin Pool
[merge] from robert and fix up tests
247
        """Commit with a removed file"""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
248
        wt = self.make_branch_and_tree('.')
249
        b = wt.branch
1247 by Martin Pool
- tests for deletion and removal of files in commits
250
        file('hello', 'w').write('hello world')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
251
        wt.add(['hello'], ['hello-id'])
252
        wt.commit(message='add hello')
1185.16.72 by Martin Pool
[merge] from robert and fix up tests
253
        wt.remove('hello')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
254
        wt.commit('removed hello', rev_id='rev2')
1247 by Martin Pool
- tests for deletion and removal of files in commits
255
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
256
        tree = b.repository.revision_tree('rev2')
1247 by Martin Pool
- tests for deletion and removal of files in commits
257
        self.assertFalse(tree.has_id('hello-id'))
1246 by Martin Pool
- add very simple commit tests
258
1256 by Martin Pool
- test that commits append to the tree's ancestry
259
    def test_committed_ancestry(self):
260
        """Test commit appends revisions to ancestry."""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
261
        wt = self.make_branch_and_tree('.')
262
        b = wt.branch
1256 by Martin Pool
- test that commits append to the tree's ancestry
263
        rev_ids = []
264
        for i in range(4):
265
            file('hello', 'w').write((str(i) * 4) + '\n')
266
            if i == 0:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
267
                wt.add(['hello'], ['hello-id'])
1256 by Martin Pool
- test that commits append to the tree's ancestry
268
            rev_id = 'test@rev-%d' % (i+1)
269
            rev_ids.append(rev_id)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
270
            wt.commit(message='rev %d' % (i+1),
1256 by Martin Pool
- test that commits append to the tree's ancestry
271
                     rev_id=rev_id)
272
        eq = self.assertEquals
273
        eq(b.revision_history(), rev_ids)
274
        for i in range(4):
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
275
            anc = b.repository.get_ancestry(rev_ids[i])
1390 by Robert Collins
pair programming worx... merge integration and weave
276
            eq(anc, [None] + rev_ids[:i+1])
1416 by Robert Collins
when committing a specific file, include all its parents
277
278
    def test_commit_new_subdir_child_selective(self):
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
279
        wt = self.make_branch_and_tree('.')
280
        b = wt.branch
1416 by Robert Collins
when committing a specific file, include all its parents
281
        self.build_tree(['dir/', 'dir/file1', 'dir/file2'])
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
282
        wt.add(['dir', 'dir/file1', 'dir/file2'],
1416 by Robert Collins
when committing a specific file, include all its parents
283
              ['dirid', 'file1id', 'file2id'])
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
284
        wt.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
285
        inv = b.repository.get_inventory('1')
1416 by Robert Collins
when committing a specific file, include all its parents
286
        self.assertEqual('1', inv['dirid'].revision)
287
        self.assertEqual('1', inv['file1id'].revision)
288
        # FIXME: This should raise a KeyError I think, rbc20051006
289
        self.assertRaises(BzrError, inv.__getitem__, 'file2id')
1185.16.65 by mbp at sourcefrog
- new commit --strict option
290
291
    def test_strict_commit(self):
292
        """Try and commit with unknown files and strict = True, should fail."""
293
        from bzrlib.errors import StrictCommitFailed
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
294
        wt = self.make_branch_and_tree('.')
295
        b = wt.branch
1185.16.65 by mbp at sourcefrog
- new commit --strict option
296
        file('hello', 'w').write('hello world')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
297
        wt.add('hello')
1185.16.65 by mbp at sourcefrog
- new commit --strict option
298
        file('goodbye', 'w').write('goodbye cruel world!')
1534.4.35 by Robert Collins
Give branch its own basis tree and last_revision methods; deprecated branch.working_tree()
299
        self.assertRaises(StrictCommitFailed, wt.commit,
1185.16.65 by mbp at sourcefrog
- new commit --strict option
300
            message='add hello but not goodbye', strict=True)
301
1185.22.4 by Michael Ellerman
Strict commit was a little .. ah .. too strict, oops :}
302
    def test_strict_commit_without_unknowns(self):
303
        """Try and commit with no unknown files and strict = True,
304
        should work."""
305
        from bzrlib.errors import StrictCommitFailed
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
306
        wt = self.make_branch_and_tree('.')
307
        b = wt.branch
1185.22.4 by Michael Ellerman
Strict commit was a little .. ah .. too strict, oops :}
308
        file('hello', 'w').write('hello world')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
309
        wt.add('hello')
310
        wt.commit(message='add hello', strict=True)
1185.22.4 by Michael Ellerman
Strict commit was a little .. ah .. too strict, oops :}
311
1185.16.65 by mbp at sourcefrog
- new commit --strict option
312
    def test_nonstrict_commit(self):
313
        """Try and commit with unknown files and strict = False, should work."""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
314
        wt = self.make_branch_and_tree('.')
315
        b = wt.branch
1185.16.65 by mbp at sourcefrog
- new commit --strict option
316
        file('hello', 'w').write('hello world')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
317
        wt.add('hello')
1185.16.65 by mbp at sourcefrog
- new commit --strict option
318
        file('goodbye', 'w').write('goodbye cruel world!')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
319
        wt.commit(message='add hello but not goodbye', strict=False)
1185.16.72 by Martin Pool
[merge] from robert and fix up tests
320
1185.22.4 by Michael Ellerman
Strict commit was a little .. ah .. too strict, oops :}
321
    def test_nonstrict_commit_without_unknowns(self):
322
        """Try and commit with no unknown files and strict = False,
323
        should work."""
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
324
        wt = self.make_branch_and_tree('.')
325
        b = wt.branch
1185.22.4 by Michael Ellerman
Strict commit was a little .. ah .. too strict, oops :}
326
        file('hello', 'w').write('hello world')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
327
        wt.add('hello')
328
        wt.commit(message='add hello', strict=False)
1185.22.4 by Michael Ellerman
Strict commit was a little .. ah .. too strict, oops :}
329
1442.1.60 by Robert Collins
gpg sign commits if the policy says we need to
330
    def test_signed_commit(self):
331
        import bzrlib.gpg
332
        import bzrlib.commit as commit
333
        oldstrategy = bzrlib.gpg.GPGStrategy
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
334
        wt = self.make_branch_and_tree('.')
335
        branch = wt.branch
336
        wt.commit("base", allow_pointless=True, rev_id='A')
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
337
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
1442.1.60 by Robert Collins
gpg sign commits if the policy says we need to
338
        try:
339
            from bzrlib.testament import Testament
340
            # monkey patch gpg signing mechanism
341
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
2149.1.3 by Aaron Bentley
Updates from review comments
342
            commit.Commit(config=MustSignConfig(branch)).commit(message="base",
343
                                                      allow_pointless=True,
344
                                                      rev_id='B',
345
                                                      working_tree=wt)
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
346
            self.assertEqual(Testament.from_revision(branch.repository,
1185.65.1 by Aaron Bentley
Refactored out ControlFiles and RevisionStore from _Branch
347
                             'B').as_short_text(),
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
348
                             branch.repository.get_signature_text('B'))
1442.1.60 by Robert Collins
gpg sign commits if the policy says we need to
349
        finally:
350
            bzrlib.gpg.GPGStrategy = oldstrategy
1442.1.62 by Robert Collins
Allow creation of testaments from uncommitted data, and use that to get signatures before committing revisions.
351
352
    def test_commit_failed_signature(self):
353
        import bzrlib.gpg
354
        import bzrlib.commit as commit
355
        oldstrategy = bzrlib.gpg.GPGStrategy
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
356
        wt = self.make_branch_and_tree('.')
357
        branch = wt.branch
358
        wt.commit("base", allow_pointless=True, rev_id='A')
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
359
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
1442.1.62 by Robert Collins
Allow creation of testaments from uncommitted data, and use that to get signatures before committing revisions.
360
        try:
361
            from bzrlib.testament import Testament
362
            # monkey patch gpg signing mechanism
363
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
364
            config = MustSignConfig(branch)
365
            self.assertRaises(SigningFailed,
366
                              commit.Commit(config=config).commit,
1534.4.34 by Robert Collins
Fix remaining uses of deprecated apis within bzrlib.
367
                              message="base",
1442.1.62 by Robert Collins
Allow creation of testaments from uncommitted data, and use that to get signatures before committing revisions.
368
                              allow_pointless=True,
1534.4.34 by Robert Collins
Fix remaining uses of deprecated apis within bzrlib.
369
                              rev_id='B',
370
                              working_tree=wt)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
371
            branch = Branch.open(self.get_url('.'))
1442.1.62 by Robert Collins
Allow creation of testaments from uncommitted data, and use that to get signatures before committing revisions.
372
            self.assertEqual(branch.revision_history(), ['A'])
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
373
            self.failIf(branch.repository.has_revision('B'))
1442.1.62 by Robert Collins
Allow creation of testaments from uncommitted data, and use that to get signatures before committing revisions.
374
        finally:
375
            bzrlib.gpg.GPGStrategy = oldstrategy
1472 by Robert Collins
post commit hook, first pass implementation
376
377
    def test_commit_invokes_hooks(self):
378
        import bzrlib.commit as commit
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
379
        wt = self.make_branch_and_tree('.')
380
        branch = wt.branch
1472 by Robert Collins
post commit hook, first pass implementation
381
        calls = []
382
        def called(branch, rev_id):
383
            calls.append('called')
384
        bzrlib.ahook = called
385
        try:
386
            config = BranchWithHooks(branch)
387
            commit.Commit(config=config).commit(
2149.1.3 by Aaron Bentley
Updates from review comments
388
                            message = "base",
1472 by Robert Collins
post commit hook, first pass implementation
389
                            allow_pointless=True,
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
390
                            rev_id='A', working_tree = wt)
1472 by Robert Collins
post commit hook, first pass implementation
391
            self.assertEqual(['called', 'called'], calls)
392
        finally:
393
            del bzrlib.ahook
1593.1.1 by Robert Collins
Move responsibility for setting branch nickname in commits to the WorkingTree convenience function.
394
395
    def test_commit_object_doesnt_set_nick(self):
396
        # using the Commit object directly does not set the branch nick.
397
        wt = self.make_branch_and_tree('.')
398
        c = Commit()
2149.1.3 by Aaron Bentley
Updates from review comments
399
        c.commit(working_tree=wt, message='empty tree', allow_pointless=True)
1593.1.1 by Robert Collins
Move responsibility for setting branch nickname in commits to the WorkingTree convenience function.
400
        self.assertEquals(wt.branch.revno(), 1)
401
        self.assertEqual({},
402
                         wt.branch.repository.get_revision(
403
                            wt.branch.last_revision()).properties)
404
1614.1.1 by Aaron Bentley
Fixed master locking in commit
405
    def test_safe_master_lock(self):
406
        os.mkdir('master')
407
        master = BzrDirMetaFormat1().initialize('master')
408
        master.create_repository()
409
        master_branch = master.create_branch()
410
        master.create_workingtree()
411
        bound = master.sprout('bound')
412
        wt = bound.open_workingtree()
413
        wt.branch.set_bound_location(os.path.realpath('master'))
1957.1.17 by John Arbash Meinel
Change tests that expect locking to fail to timeout sooner.
414
415
        orig_default = lockdir._DEFAULT_TIMEOUT_SECONDS
1614.1.1 by Aaron Bentley
Fixed master locking in commit
416
        master_branch.lock_write()
1658.1.5 by Martin Pool
Release more locks taken during test suite
417
        try:
1957.1.17 by John Arbash Meinel
Change tests that expect locking to fail to timeout sooner.
418
            lockdir._DEFAULT_TIMEOUT_SECONDS = 1
1658.1.5 by Martin Pool
Release more locks taken during test suite
419
            self.assertRaises(LockContention, wt.commit, 'silly')
420
        finally:
1957.1.17 by John Arbash Meinel
Change tests that expect locking to fail to timeout sooner.
421
            lockdir._DEFAULT_TIMEOUT_SECONDS = orig_default
1658.1.5 by Martin Pool
Release more locks taken during test suite
422
            master_branch.unlock()
1668.1.3 by Martin Pool
[patch] use the correct transaction when committing snapshot (Malone: #43959)
423
424
    def test_commit_bound_merge(self):
425
        # see bug #43959; commit of a merge in a bound branch fails to push
426
        # the new commit into the master
427
        master_branch = self.make_branch('master')
428
        bound_tree = self.make_branch_and_tree('bound')
429
        bound_tree.branch.bind(master_branch)
430
431
        self.build_tree_contents([('bound/content_file', 'initial contents\n')])
432
        bound_tree.add(['content_file'])
433
        bound_tree.commit(message='woo!')
434
435
        other_bzrdir = master_branch.bzrdir.sprout('other')
436
        other_tree = other_bzrdir.open_workingtree()
437
438
        # do a commit to the the other branch changing the content file so
439
        # that our commit after merging will have a merged revision in the
440
        # content file history.
441
        self.build_tree_contents([('other/content_file', 'change in other\n')])
442
        other_tree.commit('change in other')
443
444
        # do a merge into the bound branch from other, and then change the
445
        # content file locally to force a new revision (rather than using the
446
        # revision from other). This forces extra processing in commit.
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
447
        bound_tree.merge_from_branch(other_tree.branch)
1668.1.3 by Martin Pool
[patch] use the correct transaction when committing snapshot (Malone: #43959)
448
        self.build_tree_contents([('bound/content_file', 'change in bound\n')])
449
450
        # before #34959 was fixed, this failed with 'revision not present in
451
        # weave' when trying to implicitly push from the bound branch to the master
452
        bound_tree.commit(message='commit of merge in bound tree')
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
453
454
    def test_commit_reporting_after_merge(self):
455
        # when doing a commit of a merge, the reporter needs to still 
456
        # be called for each item that is added/removed/deleted.
457
        this_tree = self.make_branch_and_tree('this')
458
        # we need a bunch of files and dirs, to perform one action on each.
459
        self.build_tree([
460
            'this/dirtorename/',
461
            'this/dirtoreparent/',
462
            'this/dirtoleave/',
463
            'this/dirtoremove/',
464
            'this/filetoreparent',
465
            'this/filetorename',
466
            'this/filetomodify',
467
            'this/filetoremove',
468
            'this/filetoleave']
469
            )
470
        this_tree.add([
471
            'dirtorename',
472
            'dirtoreparent',
473
            'dirtoleave',
474
            'dirtoremove',
475
            'filetoreparent',
476
            'filetorename',
477
            'filetomodify',
478
            'filetoremove',
479
            'filetoleave']
480
            )
481
        this_tree.commit('create_files')
482
        other_dir = this_tree.bzrdir.sprout('other')
483
        other_tree = other_dir.open_workingtree()
484
        other_tree.lock_write()
485
        # perform the needed actions on the files and dirs.
486
        try:
487
            other_tree.rename_one('dirtorename', 'renameddir')
488
            other_tree.rename_one('dirtoreparent', 'renameddir/reparenteddir')
489
            other_tree.rename_one('filetorename', 'renamedfile')
490
            other_tree.rename_one('filetoreparent', 'renameddir/reparentedfile')
491
            other_tree.remove(['dirtoremove', 'filetoremove'])
492
            self.build_tree_contents([
493
                ('other/newdir/', ),
494
                ('other/filetomodify', 'new content'),
495
                ('other/newfile', 'new file content')])
496
            other_tree.add('newfile')
497
            other_tree.add('newdir/')
498
            other_tree.commit('modify all sample files and dirs.')
499
        finally:
500
            other_tree.unlock()
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
501
        this_tree.merge_from_branch(other_tree.branch)
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
502
        reporter = CapturingReporter()
503
        this_tree.commit('do the commit', reporter=reporter)
504
        self.assertEqual([
1910.2.3 by Aaron Bentley
All tests pass
505
            ('change', 'unchanged', ''),
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
506
            ('change', 'unchanged', 'dirtoleave'),
507
            ('change', 'unchanged', 'filetoleave'),
508
            ('change', 'modified', 'filetomodify'),
509
            ('change', 'added', 'newdir'),
510
            ('change', 'added', 'newfile'),
511
            ('renamed', 'renamed', 'dirtorename', 'renameddir'),
512
            ('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
513
            ('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
514
            ('renamed', 'renamed', 'filetorename', 'renamedfile'),
515
            ('deleted', 'dirtoremove'),
516
            ('deleted', 'filetoremove'),
517
            ],
518
            reporter.calls)
1551.7.24 by Aaron Bentley
Ensure commit respects file spec when committing removals
519
520
    def test_commit_removals_respects_filespec(self):
521
        """Commit respects the specified_files for removals."""
522
        tree = self.make_branch_and_tree('.')
523
        self.build_tree(['a', 'b'])
524
        tree.add(['a', 'b'])
525
        tree.commit('added a, b')
526
        tree.remove(['a', 'b'])
1906.1.1 by Robert Collins
(robertc) Trivial change to test_commit_removals_respects_filespec to be easir to read.
527
        tree.commit('removed a', specific_files='a')
1551.7.24 by Aaron Bentley
Ensure commit respects file spec when committing removals
528
        basis = tree.basis_tree().inventory
529
        self.assertIs(None, basis.path2id('a'))
530
        self.assertFalse(basis.path2id('b') is None)
1864.2.1 by John Arbash Meinel
Commit timestamp restricted to 1ms precision.
531
532
    def test_commit_saves_1ms_timestamp(self):
533
        """Passing in a timestamp is saved with 1ms resolution"""
534
        tree = self.make_branch_and_tree('.')
535
        self.build_tree(['a'])
536
        tree.add('a')
537
        tree.commit('added a', timestamp=1153248633.4186721, timezone=0,
538
                    rev_id='a1')
539
540
        rev = tree.branch.repository.get_revision('a1')
541
        self.assertEqual(1153248633.419, rev.timestamp)
542
543
    def test_commit_has_1ms_resolution(self):
544
        """Allowing commit to generate the timestamp also has 1ms resolution"""
545
        tree = self.make_branch_and_tree('.')
546
        self.build_tree(['a'])
547
        tree.add('a')
548
        tree.commit('added a', rev_id='a1')
549
550
        rev = tree.branch.repository.get_revision('a1')
551
        timestamp = rev.timestamp
552
        timestamp_1ms = round(timestamp, 3)
553
        self.assertEqual(timestamp_1ms, timestamp)
1551.8.29 by Aaron Bentley
Stop accepting non-existant files in commit (#50793)
554
555
    def test_commit_unversioned_specified(self):
556
        """Commit should raise if specified files isn't in basis or worktree"""
557
        tree = self.make_branch_and_tree('.')
558
        self.assertRaises(errors.PathsNotVersionedError, tree.commit, 
559
                          'message', specific_files=['bogus'])
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
560
561
    class Callback(object):
562
        
2149.1.4 by Aaron Bentley
Add additional test that callback is called with a Commit instance
563
        def __init__(self, message, testcase):
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
564
            self.called = False
565
            self.message = message
2149.1.4 by Aaron Bentley
Add additional test that callback is called with a Commit instance
566
            self.testcase = testcase
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
567
2149.1.4 by Aaron Bentley
Add additional test that callback is called with a Commit instance
568
        def __call__(self, commit_obj):
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
569
            self.called = True
2149.1.4 by Aaron Bentley
Add additional test that callback is called with a Commit instance
570
            self.testcase.assertTrue(isinstance(commit_obj, Commit))
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
571
            return self.message
572
573
    def test_commit_callback(self):
574
        """Commit should invoke a callback to get the message"""
575
576
        tree = self.make_branch_and_tree('.')
577
        try:
578
            tree.commit()
579
        except Exception, e:
580
            self.assertTrue(isinstance(e, BzrError))
2149.1.3 by Aaron Bentley
Updates from review comments
581
            self.assertEqual('The message or message_callback keyword'
582
                             ' parameter is required for commit().', str(e))
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
583
        else:
584
            self.fail('exception not raised')
2149.1.4 by Aaron Bentley
Add additional test that callback is called with a Commit instance
585
        cb = self.Callback(u'commit 1', self)
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
586
        tree.commit(message_callback=cb)
587
        self.assertTrue(cb.called)
588
        repository = tree.branch.repository
589
        message = repository.get_revision(tree.last_revision()).message
590
        self.assertEqual('commit 1', message)
591
592
    def test_no_callback_pointless(self):
593
        """Callback should not be invoked for pointless commit"""
594
        tree = self.make_branch_and_tree('.')
2149.1.4 by Aaron Bentley
Add additional test that callback is called with a Commit instance
595
        cb = self.Callback(u'commit 2', self)
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
596
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb, 
597
                          allow_pointless=False)
598
        self.assertFalse(cb.called)
599
600
    def test_no_callback_netfailure(self):
601
        """Callback should not be invoked if connectivity fails"""
2149.1.3 by Aaron Bentley
Updates from review comments
602
        tree = self.make_branch_and_tree('.')
2149.1.4 by Aaron Bentley
Add additional test that callback is called with a Commit instance
603
        cb = self.Callback(u'commit 2', self)
2149.1.3 by Aaron Bentley
Updates from review comments
604
        repository = tree.branch.repository
2149.1.1 by Aaron Bentley
Provide a message_callback parameter to tree.commit
605
        # simulate network failure
606
        def raise_(self, arg, arg2):
607
            raise errors.NoSuchFile('foo')
608
        repository.add_inventory = raise_
609
        self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
610
        self.assertFalse(cb.called)