~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/blackbox/test_commit.py

  • Committer: Kit Randel
  • Date: 2014-12-15 20:24:42 UTC
  • mto: This revision was merged to the branch mainline in revision 6602.
  • Revision ID: kit.randel@canonical.com-20141215202442-usf2ixhypqg8yh6q
added a note for bug-1400567 to the 2.7b release notes

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2012 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
17
17
 
18
18
"""Tests for the commit CLI of bzr."""
19
19
 
 
20
import doctest
20
21
import os
21
22
import re
22
23
import sys
23
24
 
 
25
from testtools.matchers import DocTestMatches
 
26
 
24
27
from bzrlib import (
25
 
    bzrdir,
 
28
    config,
26
29
    osutils,
27
30
    ignores,
28
31
    msgeditor,
29
 
    osutils,
30
 
    tests,
31
32
    )
32
 
from bzrlib.bzrdir import BzrDir
 
33
from bzrlib.controldir import ControlDir
33
34
from bzrlib.tests import (
34
 
    probe_bad_non_ascii,
35
 
    TestSkipped,
36
 
    UnicodeFilenameFeature,
 
35
    test_foreign,
 
36
    features,
37
37
    )
38
38
from bzrlib.tests import TestCaseWithTransport
 
39
from bzrlib.tests.matchers import ContainsNoVfsCalls
39
40
 
40
41
 
41
42
class TestCommit(TestCaseWithTransport):
47
48
        self.build_tree(['hello.txt'])
48
49
        out,err = self.run_bzr('commit -m empty', retcode=3)
49
50
        self.assertEqual('', out)
50
 
        self.assertContainsRe(err, 'bzr: ERROR: No changes to commit\.'
51
 
                                  ' Use --unchanged to commit anyhow.\n')
 
51
        # Two ugly bits here.
 
52
        # 1) We really don't want 'aborting commit write group' anymore.
 
53
        # 2) bzr: ERROR: is a really long line, so we wrap it with '\'
 
54
        self.assertThat(
 
55
            err,
 
56
            DocTestMatches("""\
 
57
Committing to: ...
 
58
bzr: ERROR: No changes to commit.\
 
59
 Please 'bzr add' the files you want to commit,\
 
60
 or use --unchanged to force an empty commit.
 
61
""", flags=doctest.ELLIPSIS|doctest.REPORT_UDIFF))
52
62
 
53
63
    def test_commit_success(self):
54
64
        """Successful commit should not leave behind a bzr-commit-* file"""
60
70
        self.run_bzr(["commit", "--unchanged", "-m", u'foo\xb5'])
61
71
        self.assertEqual('', self.run_bzr('unknowns')[0])
62
72
 
 
73
    def test_commit_lossy_native(self):
 
74
        """A --lossy option to commit is supported."""
 
75
        self.make_branch_and_tree('.')
 
76
        self.run_bzr('commit --lossy --unchanged -m message')
 
77
        self.assertEqual('', self.run_bzr('unknowns')[0])
 
78
 
 
79
    def test_commit_lossy_foreign(self):
 
80
        test_foreign.register_dummy_foreign_for_test(self)
 
81
        self.make_branch_and_tree('.',
 
82
            format=test_foreign.DummyForeignVcsDirFormat())
 
83
        self.run_bzr('commit --lossy --unchanged -m message')
 
84
        output = self.run_bzr('revision-info')[0]
 
85
        self.assertTrue(output.startswith('1 dummy-'))
 
86
 
63
87
    def test_commit_with_path(self):
64
88
        """Commit tree with path of root specified"""
65
89
        a_tree = self.make_branch_and_tree('a')
79
103
        self.run_bzr('resolved b/a_file')
80
104
        self.run_bzr(['commit', '-m', 'merge into b', 'b'])
81
105
 
82
 
 
83
106
    def test_10_verbose_commit(self):
84
107
        """Add one file and examine verbose commit output"""
85
108
        tree = self.make_branch_and_tree('.')
94
117
    def prepare_simple_history(self):
95
118
        """Prepare and return a working tree with one commit of one file"""
96
119
        # Commit with modified file should say so
97
 
        wt = BzrDir.create_standalone_workingtree('.')
 
120
        wt = ControlDir.create_standalone_workingtree('.')
98
121
        self.build_tree(['hello.txt', 'extra.txt'])
99
122
        wt.add(['hello.txt'])
100
123
        wt.commit(message='added')
113
136
    def test_unicode_commit_message_is_filename(self):
114
137
        """Unicode commit message same as a filename (Bug #563646).
115
138
        """
116
 
        self.requireFeature(UnicodeFilenameFeature)
 
139
        self.requireFeature(features.UnicodeFilenameFeature)
117
140
        file_name = u'\N{euro sign}'
118
141
        self.run_bzr(['init'])
119
 
        open(file_name, 'w').write('hello world')
 
142
        with open(file_name, 'w') as f: f.write('hello world')
120
143
        self.run_bzr(['add'])
121
144
        out, err = self.run_bzr(['commit', '-m', file_name])
122
145
        reflags = re.MULTILINE|re.DOTALL|re.UNICODE
134
157
        try:
135
158
            osutils.get_terminal_encoding = lambda trace=None: 'ascii'
136
159
            file_name = u'foo\u1234'
137
 
            open(file_name, 'w').write('hello world')
 
160
            with open(file_name, 'w') as f: f.write('hello world')
138
161
            self.run_bzr(['add'])
139
162
            out, err = self.run_bzr(['commit', '-m', file_name])
140
163
            reflags = re.MULTILINE|re.DOTALL|re.UNICODE
145
168
        finally:
146
169
            osutils.get_terminal_encoding = default_get_terminal_enc
147
170
 
 
171
    def test_non_ascii_file_unversioned_utf8(self):
 
172
        self.requireFeature(features.UnicodeFilenameFeature)
 
173
        tree = self.make_branch_and_tree(".")
 
174
        self.build_tree(["f"])
 
175
        tree.add(["f"])
 
176
        out, err = self.run_bzr(["commit", "-m", "Wrong filename", u"\xa7"],
 
177
            encoding="utf-8", retcode=3)
 
178
        self.assertContainsRe(err, "(?m)not versioned: \"\xc2\xa7\"$")
 
179
 
 
180
    def test_non_ascii_file_unversioned_iso_8859_5(self):
 
181
        self.requireFeature(features.UnicodeFilenameFeature)
 
182
        tree = self.make_branch_and_tree(".")
 
183
        self.build_tree(["f"])
 
184
        tree.add(["f"])
 
185
        out, err = self.run_bzr(["commit", "-m", "Wrong filename", u"\xa7"],
 
186
            encoding="iso-8859-5", retcode=3)
 
187
        self.expectFailure("Error messages are always written as UTF-8",
 
188
            self.assertNotContainsString, err, "\xc2\xa7")
 
189
        self.assertContainsRe(err, "(?m)not versioned: \"\xfd\"$")
 
190
 
148
191
    def test_warn_about_forgotten_commit_message(self):
149
192
        """Test that the lack of -m parameter is caught"""
150
193
        wt = self.make_branch_and_tree('.')
182
225
    def test_verbose_commit_with_unknown(self):
183
226
        """Unknown files should not be listed by default in verbose output"""
184
227
        # Is that really the best policy?
185
 
        wt = BzrDir.create_standalone_workingtree('.')
 
228
        wt = ControlDir.create_standalone_workingtree('.')
186
229
        self.build_tree(['hello.txt', 'extra.txt'])
187
230
        wt.add(['hello.txt'])
188
231
        out,err = self.run_bzr('commit -m added')
285
328
        finally:
286
329
            other_tree.unlock()
287
330
        this_tree.merge_from_branch(other_tree.branch)
288
 
        os.chdir('this')
289
 
        out,err = self.run_bzr('commit -m added')
 
331
        out, err = self.run_bzr('commit -m added', working_dir='this')
290
332
        self.assertEqual('', out)
291
333
        self.assertEqual(set([
292
 
            'Committing to: %s/' % osutils.getcwd(),
 
334
            'Committing to: %s/' % osutils.pathjoin(osutils.getcwd(), 'this'),
293
335
            'modified filetomodify',
294
336
            'added newdir',
295
337
            'added newfile',
307
349
        tree = self.make_branch_and_tree('.')
308
350
        self.build_tree_contents([('foo.c', 'int main() {}')])
309
351
        tree.add('foo.c')
310
 
        self.run_bzr('commit -m ""', retcode=3)
311
 
 
312
 
    def test_unsupported_encoding_commit_message(self):
313
 
        if sys.platform == 'win32':
314
 
            raise tests.TestNotApplicable('Win32 parses arguments directly'
315
 
                ' as Unicode, so we can\'t pass invalid non-ascii')
316
 
        tree = self.make_branch_and_tree('.')
317
 
        self.build_tree_contents([('foo.c', 'int main() {}')])
318
 
        tree.add('foo.c')
319
 
        # LANG env variable has no effect on Windows
320
 
        # but some characters anyway cannot be represented
321
 
        # in default user encoding
322
 
        char = probe_bad_non_ascii(osutils.get_user_encoding())
323
 
        if char is None:
324
 
            raise TestSkipped('Cannot find suitable non-ascii character'
325
 
                'for user_encoding (%s)' % osutils.get_user_encoding())
326
 
        out,err = self.run_bzr_subprocess('commit -m "%s"' % char,
327
 
                                          retcode=1,
328
 
                                          env_changes={'LANG': 'C'})
329
 
        self.assertContainsRe(err, r'bzrlib.errors.BzrError: Parameter.*is '
330
 
                                    'unsupported by the current encoding.')
 
352
        self.run_bzr('commit -m ""')
331
353
 
332
354
    def test_other_branch_commit(self):
333
355
        # this branch is to ensure consistent behaviour, whether we're run
449
471
        t.add(['file-a', 'dir-a', 'dir-a/file-b'])
450
472
        t.commit('Create')
451
473
        t.remove(['file-a', 'dir-a/file-b'])
452
 
        os.chdir('dir-a')
453
 
        result = self.run_bzr('commit . -m removed-file-b')[1]
 
474
        result = self.run_bzr('commit . -m removed-file-b',
 
475
                              working_dir='dir-a')[1]
454
476
        self.assertNotContainsRe(result, 'file-a')
455
 
        result = self.run_bzr('status')[0]
 
477
        result = self.run_bzr('status', working_dir='dir-a')[0]
456
478
        self.assertContainsRe(result, 'removed:\n  file-a')
457
479
 
458
480
    def test_strict_commit(self):
462
484
        self.build_tree(['tree/a'])
463
485
        tree.add('a')
464
486
        # A simple change should just work
465
 
        self.run_bzr('commit --strict -m adding-a',
466
 
                     working_dir='tree')
 
487
        self.run_bzr('commit --strict -m adding-a', working_dir='tree')
467
488
 
468
489
    def test_strict_commit_no_changes(self):
469
490
        """commit --strict gives "no changes" if there is nothing to commit"""
594
615
            'commit -m add-b --fixes=xxx:123',
595
616
            working_dir='tree')
596
617
 
 
618
    def test_fixes_bug_with_default_tracker(self):
 
619
        """commit --fixes=234 uses the default bug tracker."""
 
620
        tree = self.make_branch_and_tree('tree')
 
621
        self.build_tree(['tree/hello.txt'])
 
622
        tree.add('hello.txt')
 
623
        self.run_bzr_error(
 
624
            ["bzr: ERROR: No tracker specified for bug 123. Use the form "
 
625
            "'tracker:id' or specify a default bug tracker using the "
 
626
            "`bugtracker` option.\n"
 
627
            "See \"bzr help bugs\" for more information on this feature. "
 
628
            "Commit refused."],
 
629
            'commit -m add-b --fixes=123',
 
630
            working_dir='tree')
 
631
        tree.branch.get_config_stack().set("bugtracker", "lp")
 
632
        self.run_bzr('commit -m hello --fixes=234 tree/hello.txt')
 
633
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
 
634
        self.assertEqual('https://launchpad.net/bugs/234 fixed',
 
635
                         last_rev.properties['bugs'])
 
636
 
597
637
    def test_fixes_invalid_bug_number(self):
598
638
        tree = self.make_branch_and_tree('tree')
599
639
        self.build_tree(['tree/hello.txt'])
611
651
        self.build_tree(['tree/hello.txt'])
612
652
        tree.add('hello.txt')
613
653
        self.run_bzr_error(
614
 
            [r"Invalid bug orange. Must be in the form of 'tracker:id'\. "
615
 
             r"See \"bzr help bugs\" for more information on this feature.\n"
616
 
             r"Commit refused\."],
617
 
            'commit -m add-b --fixes=orange',
 
654
            [r"Invalid bug orange:apples:bananas. Must be in the form of "
 
655
             r"'tracker:id'\. See \"bzr help bugs\" for more information on "
 
656
             r"this feature.\nCommit refused\."],
 
657
            'commit -m add-b --fixes=orange:apples:bananas',
618
658
            working_dir='tree')
619
659
 
620
660
    def test_no_author(self):
683
723
        self.assertStartsWith(
684
724
            err, "bzr: ERROR: Could not parse --commit-time:")
685
725
 
 
726
    def test_commit_time_missing_tz(self):
 
727
        tree = self.make_branch_and_tree('tree')
 
728
        self.build_tree(['tree/hello.txt'])
 
729
        tree.add('hello.txt')
 
730
        out, err = self.run_bzr("commit -m hello "
 
731
            "--commit-time='2009-10-10 08:00:00' tree/hello.txt", retcode=3)
 
732
        self.assertStartsWith(
 
733
            err, "bzr: ERROR: Could not parse --commit-time:")
 
734
        # Test that it is actually checking and does not simply crash with
 
735
        # some other exception
 
736
        self.assertContainsString(err, "missing a timezone offset")
 
737
 
686
738
    def test_partial_commit_with_renames_in_tree(self):
687
739
        # this test illustrates bug #140419
688
740
        t = self.make_branch_and_tree('.')
705
757
        # "UnlockableTransport error trying to commit in checkout of readonly
706
758
        # branch"
707
759
        self.make_branch('master')
708
 
        master = BzrDir.open_from_transport(
 
760
        master = ControlDir.open_from_transport(
709
761
            self.get_readonly_transport('master')).open_branch()
710
762
        master.create_checkout('checkout')
711
763
        out, err = self.run_bzr(['commit', '--unchanged', '-mfoo', 'checkout'],
719
771
            f = file('fed.bat', 'w')
720
772
            f.write('@rem dummy fed')
721
773
            f.close()
722
 
            osutils.set_or_unset_env('BZR_EDITOR', "fed.bat")
 
774
            self.overrideEnv('BZR_EDITOR', "fed.bat")
723
775
        else:
724
776
            f = file('fed.sh', 'wb')
725
777
            f.write('#!/bin/sh\n')
726
778
            f.close()
727
779
            os.chmod('fed.sh', 0755)
728
 
            osutils.set_or_unset_env('BZR_EDITOR', "./fed.sh")
 
780
            self.overrideEnv('BZR_EDITOR', "./fed.sh")
729
781
 
730
782
    def setup_commit_with_template(self):
731
783
        self.setup_editor()
736
788
        tree.add('hello.txt')
737
789
        return tree
738
790
 
 
791
    def test_edit_empty_message(self):
 
792
        tree = self.make_branch_and_tree('tree')
 
793
        self.setup_editor()
 
794
        self.build_tree(['tree/hello.txt'])
 
795
        tree.add('hello.txt')
 
796
        out, err = self.run_bzr("commit tree/hello.txt", retcode=3,
 
797
            stdin="y\n")
 
798
        self.assertContainsRe(err,
 
799
            "bzr: ERROR: Empty commit message specified")
 
800
 
739
801
    def test_commit_hook_template_accepted(self):
740
802
        tree = self.setup_commit_with_template()
741
803
        out, err = self.run_bzr("commit tree/hello.txt", stdin="y\n")
745
807
    def test_commit_hook_template_rejected(self):
746
808
        tree = self.setup_commit_with_template()
747
809
        expected = tree.last_revision()
748
 
        out, err = self.run_bzr_error(["empty commit message"],
 
810
        out, err = self.run_bzr_error(["Empty commit message specified."
 
811
                  " Please specify a commit message with either"
 
812
                  " --message or --file or leave a blank message"
 
813
                  " with --message \"\"."],
749
814
            "commit tree/hello.txt", stdin="n\n")
750
815
        self.assertEqual(expected, tree.last_revision())
751
816
 
 
817
    def test_set_commit_message(self):
 
818
        msgeditor.hooks.install_named_hook("set_commit_message",
 
819
                lambda commit_obj, msg: "save me some typing\n", None)
 
820
        tree = self.make_branch_and_tree('tree')
 
821
        self.build_tree(['tree/hello.txt'])
 
822
        tree.add('hello.txt')
 
823
        out, err = self.run_bzr("commit tree/hello.txt")
 
824
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
 
825
        self.assertEqual('save me some typing\n', last_rev.message)
 
826
 
752
827
    def test_commit_without_username(self):
753
828
        """Ensure commit error if username is not set.
754
829
        """
755
830
        self.run_bzr(['init', 'foo'])
756
 
        os.chdir('foo')
757
 
        open('foo.txt', 'w').write('hello')
758
 
        self.run_bzr(['add'])
759
 
        osutils.set_or_unset_env('EMAIL', None)
760
 
        osutils.set_or_unset_env('BZR_EMAIL', None)
761
 
        out, err = self.run_bzr(['commit', '-m', 'initial'], 3)
762
 
        self.assertContainsRe(err, 'Unable to determine your name')
 
831
        with open('foo/foo.txt', 'w') as f:
 
832
            f.write('hello')
 
833
        self.run_bzr(['add'], working_dir='foo')
 
834
        self.overrideEnv('EMAIL', None)
 
835
        self.overrideEnv('BZR_EMAIL', None)
 
836
        # Also, make sure that it's not inferred from mailname.
 
837
        self.overrideAttr(config, '_auto_user_id',
 
838
            lambda: (None, None))
 
839
        self.run_bzr_error(
 
840
            ['Unable to determine your name'],
 
841
            ['commit', '-m', 'initial'], working_dir='foo')
763
842
 
764
843
    def test_commit_recursive_checkout(self):
765
844
        """Ensure that a commit to a recursive checkout fails cleanly.
766
845
        """
767
846
        self.run_bzr(['init', 'test_branch'])
768
847
        self.run_bzr(['checkout', 'test_branch', 'test_checkout'])
769
 
        os.chdir('test_checkout')
770
 
        self.run_bzr(['bind', '.']) # bind to self
771
 
        open('foo.txt', 'w').write('hello')
772
 
        self.run_bzr(['add'])
773
 
        out, err = self.run_bzr(['commit', '-m', 'addedfoo'], 3)
774
 
        self.assertEqual(out, '')
775
 
        self.assertContainsRe(err,
776
 
            'Branch.*test_checkout.*appears to be bound to itself')
777
 
 
 
848
        self.run_bzr(['bind', '.'], working_dir='test_checkout') # bind to self
 
849
        with open('test_checkout/foo.txt', 'w') as f:
 
850
            f.write('hello')
 
851
        self.run_bzr(['add'], working_dir='test_checkout')
 
852
        out, err = self.run_bzr_error(
 
853
            ['Branch.*test_checkout.*appears to be bound to itself'],
 
854
            ['commit', '-m', 'addedfoo'], working_dir='test_checkout')
 
855
 
 
856
    def test_mv_dirs_non_ascii(self):
 
857
        """Move directory with non-ascii name and containing files.
 
858
 
 
859
        Regression test for bug 185211.
 
860
        """
 
861
        tree = self.make_branch_and_tree('.')
 
862
        self.build_tree([u'abc\xa7/', u'abc\xa7/foo'])
 
863
 
 
864
        tree.add([u'abc\xa7/', u'abc\xa7/foo'])
 
865
        tree.commit('checkin')
 
866
 
 
867
        tree.rename_one(u'abc\xa7','abc')
 
868
 
 
869
        self.run_bzr('ci -m "non-ascii mv"')
 
870
 
 
871
 
 
872
class TestSmartServerCommit(TestCaseWithTransport):
 
873
 
 
874
    def test_commit_to_lightweight(self):
 
875
        self.setup_smart_server_with_call_log()
 
876
        t = self.make_branch_and_tree('from')
 
877
        for count in range(9):
 
878
            t.commit(message='commit %d' % count)
 
879
        out, err = self.run_bzr(['checkout', '--lightweight', self.get_url('from'),
 
880
            'target'])
 
881
        self.reset_smart_call_log()
 
882
        self.build_tree(['target/afile'])
 
883
        self.run_bzr(['add', 'target/afile'])
 
884
        out, err = self.run_bzr(['commit', '-m', 'do something', 'target'])
 
885
        # This figure represent the amount of work to perform this use case. It
 
886
        # is entirely ok to reduce this number if a test fails due to rpc_count
 
887
        # being too low. If rpc_count increases, more network roundtrips have
 
888
        # become necessary for this use case. Please do not adjust this number
 
889
        # upwards without agreement from bzr's network support maintainers.
 
890
        self.assertLength(211, self.hpss_calls)
 
891
        self.assertLength(2, self.hpss_connections)
 
892
        self.expectFailure("commit still uses VFS calls",
 
893
            self.assertThat, self.hpss_calls, ContainsNoVfsCalls)