~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

Merge bzr.dev, update to use new hooks.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2011 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
33
from bzrlib.bzrdir import BzrDir
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('.')
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
142
        open(file_name, 'w').write('hello world')
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('.')
307
350
        tree = self.make_branch_and_tree('.')
308
351
        self.build_tree_contents([('foo.c', 'int main() {}')])
309
352
        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.')
 
353
        self.run_bzr('commit -m ""')
331
354
 
332
355
    def test_other_branch_commit(self):
333
356
        # this branch is to ensure consistent behaviour, whether we're run
594
617
            'commit -m add-b --fixes=xxx:123',
595
618
            working_dir='tree')
596
619
 
 
620
    def test_fixes_bug_with_default_tracker(self):
 
621
        """commit --fixes=234 uses the default bug tracker."""
 
622
        tree = self.make_branch_and_tree('tree')
 
623
        self.build_tree(['tree/hello.txt'])
 
624
        tree.add('hello.txt')
 
625
        self.run_bzr_error(
 
626
            ["bzr: ERROR: No tracker specified for bug 123. Use the form "
 
627
            "'tracker:id' or specify a default bug tracker using the "
 
628
            "`bugtracker` option.\n"
 
629
            "See \"bzr help bugs\" for more information on this feature. "
 
630
            "Commit refused."],
 
631
            'commit -m add-b --fixes=123',
 
632
            working_dir='tree')
 
633
        tree.branch.get_config().set_user_option("bugtracker", "lp")
 
634
        self.run_bzr('commit -m hello --fixes=234 tree/hello.txt')
 
635
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
 
636
        self.assertEqual('https://launchpad.net/bugs/234 fixed',
 
637
                         last_rev.properties['bugs'])
 
638
 
597
639
    def test_fixes_invalid_bug_number(self):
598
640
        tree = self.make_branch_and_tree('tree')
599
641
        self.build_tree(['tree/hello.txt'])
611
653
        self.build_tree(['tree/hello.txt'])
612
654
        tree.add('hello.txt')
613
655
        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',
 
656
            [r"Invalid bug orange:apples:bananas. Must be in the form of "
 
657
             r"'tracker:id'\. See \"bzr help bugs\" for more information on "
 
658
             r"this feature.\nCommit refused\."],
 
659
            'commit -m add-b --fixes=orange:apples:bananas',
618
660
            working_dir='tree')
619
661
 
620
662
    def test_no_author(self):
683
725
        self.assertStartsWith(
684
726
            err, "bzr: ERROR: Could not parse --commit-time:")
685
727
 
 
728
    def test_commit_time_missing_tz(self):
 
729
        tree = self.make_branch_and_tree('tree')
 
730
        self.build_tree(['tree/hello.txt'])
 
731
        tree.add('hello.txt')
 
732
        out, err = self.run_bzr("commit -m hello "
 
733
            "--commit-time='2009-10-10 08:00:00' tree/hello.txt", retcode=3)
 
734
        self.assertStartsWith(
 
735
            err, "bzr: ERROR: Could not parse --commit-time:")
 
736
        # Test that it is actually checking and does not simply crash with
 
737
        # some other exception
 
738
        self.assertContainsString(err, "missing a timezone offset")
 
739
 
686
740
    def test_partial_commit_with_renames_in_tree(self):
687
741
        # this test illustrates bug #140419
688
742
        t = self.make_branch_and_tree('.')
719
773
            f = file('fed.bat', 'w')
720
774
            f.write('@rem dummy fed')
721
775
            f.close()
722
 
            osutils.set_or_unset_env('BZR_EDITOR', "fed.bat")
 
776
            self.overrideEnv('BZR_EDITOR', "fed.bat")
723
777
        else:
724
778
            f = file('fed.sh', 'wb')
725
779
            f.write('#!/bin/sh\n')
726
780
            f.close()
727
781
            os.chmod('fed.sh', 0755)
728
 
            osutils.set_or_unset_env('BZR_EDITOR', "./fed.sh")
 
782
            self.overrideEnv('BZR_EDITOR', "./fed.sh")
729
783
 
730
784
    def setup_commit_with_template(self):
731
785
        self.setup_editor()
736
790
        tree.add('hello.txt')
737
791
        return tree
738
792
 
 
793
    def test_edit_empty_message(self):
 
794
        tree = self.make_branch_and_tree('tree')
 
795
        self.setup_editor()
 
796
        self.build_tree(['tree/hello.txt'])
 
797
        tree.add('hello.txt')
 
798
        out, err = self.run_bzr("commit tree/hello.txt", retcode=3,
 
799
            stdin="y\n")
 
800
        self.assertContainsRe(err,
 
801
            "bzr: ERROR: Empty commit message specified")
 
802
 
739
803
    def test_commit_hook_template_accepted(self):
740
804
        tree = self.setup_commit_with_template()
741
805
        out, err = self.run_bzr("commit tree/hello.txt", stdin="y\n")
745
809
    def test_commit_hook_template_rejected(self):
746
810
        tree = self.setup_commit_with_template()
747
811
        expected = tree.last_revision()
748
 
        out, err = self.run_bzr_error(["empty commit message"],
 
812
        out, err = self.run_bzr_error(["Empty commit message specified."
 
813
                  " Please specify a commit message with either"
 
814
                  " --message or --file or leave a blank message"
 
815
                  " with --message \"\"."],
749
816
            "commit tree/hello.txt", stdin="n\n")
750
817
        self.assertEqual(expected, tree.last_revision())
751
818
 
 
819
    def test_set_commit_message(self):
 
820
        msgeditor.hooks.install_named_hook("set_commit_message",
 
821
                lambda commit_obj, msg: "save me some typing\n", None)
 
822
        tree = self.make_branch_and_tree('tree')
 
823
        self.build_tree(['tree/hello.txt'])
 
824
        tree.add('hello.txt')
 
825
        out, err = self.run_bzr("commit tree/hello.txt")
 
826
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
 
827
        self.assertEqual('save me some typing\n', last_rev.message)
 
828
 
752
829
    def test_commit_without_username(self):
753
830
        """Ensure commit error if username is not set.
754
831
        """
756
833
        os.chdir('foo')
757
834
        open('foo.txt', 'w').write('hello')
758
835
        self.run_bzr(['add'])
759
 
        osutils.set_or_unset_env('EMAIL', None)
760
 
        osutils.set_or_unset_env('BZR_EMAIL', None)
 
836
        self.overrideEnv('EMAIL', None)
 
837
        self.overrideEnv('BZR_EMAIL', None)
 
838
        # Also, make sure that it's not inferred from mailname.
 
839
        self.overrideAttr(config, '_auto_user_id',
 
840
            lambda: (None, None))
761
841
        out, err = self.run_bzr(['commit', '-m', 'initial'], 3)
762
842
        self.assertContainsRe(err, 'Unable to determine your name')
763
843
 
775
855
        self.assertContainsRe(err,
776
856
            'Branch.*test_checkout.*appears to be bound to itself')
777
857
 
 
858
 
 
859
class TestSmartServerCommit(TestCaseWithTransport):
 
860
 
 
861
    def test_commit_to_lightweight(self):
 
862
        self.setup_smart_server_with_call_log()
 
863
        t = self.make_branch_and_tree('from')
 
864
        for count in range(9):
 
865
            t.commit(message='commit %d' % count)
 
866
        out, err = self.run_bzr(['checkout', '--lightweight', self.get_url('from'),
 
867
            'target'])
 
868
        self.reset_smart_call_log()
 
869
        self.build_tree(['target/afile'])
 
870
        self.run_bzr(['add', 'target/afile'])
 
871
        out, err = self.run_bzr(['commit', '-m', 'do something', 'target'])
 
872
        # This figure represent the amount of work to perform this use case. It
 
873
        # is entirely ok to reduce this number if a test fails due to rpc_count
 
874
        # being too low. If rpc_count increases, more network roundtrips have
 
875
        # become necessary for this use case. Please do not adjust this number
 
876
        # upwards without agreement from bzr's network support maintainers.
 
877
        self.assertLength(213, self.hpss_calls)
 
878
        self.expectFailure("commit still uses VFS calls",
 
879
            self.assertThat, self.hpss_calls, ContainsNoVfsCalls)