~bzr-pqm/bzr/bzr.dev

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