summaryrefslogtreecommitdiffstats
path: root/qa/test_commits.py
blob: 92e108732db21718142021ea0baa5ec67f51816b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# -*- coding: utf-8 -*-
# pylint: disable=too-many-function-args,unexpected-keyword-arg
import re

import arrow

from qa.shell import echo, git, gitlint
from qa.base import BaseTestCase


class CommitsTests(BaseTestCase):
    """ Integration tests for the --commits argument, i.e. linting multiple commits at once or linting specific commits
    """

    def test_successful(self):
        """ Test linting multiple commits without violations """
        git("checkout", "-b", "test-branch-commits-base", _cwd=self.tmp_git_repo)
        self.create_simple_commit("Sïmple title\n\nSimple bödy describing the commit")
        git("checkout", "-b", "test-branch-commits", _cwd=self.tmp_git_repo)
        self.create_simple_commit("Sïmple title2\n\nSimple bödy describing the commit2")
        self.create_simple_commit("Sïmple title3\n\nSimple bödy describing the commit3")
        output = gitlint("--commits", "test-branch-commits-base...test-branch-commits",
                         _cwd=self.tmp_git_repo, _tty_in=True)
        self.assertEqualStdout(output, "")

    def test_violations(self):
        """ Test linting multiple commits with violations """
        git("checkout", "-b", "test-branch-commits-violations-base", _cwd=self.tmp_git_repo)
        self.create_simple_commit("Sïmple title.\n")
        git("checkout", "-b", "test-branch-commits-violations", _cwd=self.tmp_git_repo)

        self.create_simple_commit("Sïmple title2.\n")
        commit_sha1 = self.get_last_commit_hash()[:10]
        self.create_simple_commit("Sïmple title3.\n")
        commit_sha2 = self.get_last_commit_hash()[:10]
        output = gitlint("--commits", "test-branch-commits-violations-base...test-branch-commits-violations",
                         _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[4])

        self.assertEqual(output.exit_code, 4)
        expected_kwargs = {'commit_sha1': commit_sha1, 'commit_sha2': commit_sha2}
        self.assertEqualStdout(output, self.get_expected("test_commits/test_violations_1", expected_kwargs))

    def test_lint_empty_commit_range(self):
        """ Tests `gitlint --commits <sha>^...<sha>` --fail-without-commits where the provided range is empty. """
        self.create_simple_commit("Sïmple title.\n")
        self.create_simple_commit("Sïmple title2.\n")
        commit_sha = self.get_last_commit_hash()
        # git revspec -> 2 dots: <exclusive sha>..<inclusive sha> -> empty range when using same start and end sha
        refspec = f"{commit_sha}..{commit_sha}"

        # Regular gitlint invocation should run without issues
        output = gitlint("--commits", refspec, _cwd=self.tmp_git_repo, _tty_in=True)
        self.assertEqual(output.exit_code, 0)
        self.assertEqualStdout(output, "")

        # Gitlint should fail when --fail-without-commits is used
        output = gitlint("--commits", refspec, "--fail-without-commits", _cwd=self.tmp_git_repo, _tty_in=True,
                         _ok_code=[self.GITLINT_USAGE_ERROR])
        self.assertEqual(output.exit_code, self.GITLINT_USAGE_ERROR)
        self.assertEqualStdout(output, f"Error: No commits in range \"{refspec}\"\n")

    def test_lint_single_commit(self):
        """ Tests `gitlint --commits <sha>^...<same sha>` """
        self.create_simple_commit("Sïmple title.\n")
        first_commit_sha = self.get_last_commit_hash()
        self.create_simple_commit("Sïmple title2.\n")
        commit_sha = self.get_last_commit_hash()
        refspec = f"{commit_sha}^...{commit_sha}"
        self.create_simple_commit("Sïmple title3.\n")

        expected = ("1: T3 Title has trailing punctuation (.): \"Sïmple title2.\"\n" +
                    "3: B6 Body message is missing\n")

        # Lint using --commit <commit sha>
        output = gitlint("--commit", commit_sha, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[2])
        self.assertEqual(output.exit_code, 2)
        self.assertEqualStdout(output, expected)

        # Lint a single commit using --commits <refspec> pointing to the single commit
        output = gitlint("--commits", refspec, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[2])
        self.assertEqual(output.exit_code, 2)
        self.assertEqualStdout(output, expected)

        # Lint the first commit in the repository. This is a use-case that is not supported by --commits
        # As <sha>^...<sha> is not correct refspec in case <sha> points to the initial commit (which has no parents)
        expected = ("1: T3 Title has trailing punctuation (.): \"Sïmple title.\"\n" +
                    "3: B6 Body message is missing\n")
        output = gitlint("--commit", first_commit_sha, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[2])
        self.assertEqual(output.exit_code, 2)
        self.assertEqualStdout(output, expected)

        # Assert that indeed --commits <refspec> is not supported when <refspec> points the the first commit
        refspec = f"{first_commit_sha}^...{first_commit_sha}"
        output = gitlint("--commits", refspec, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[254])
        self.assertEqual(output.exit_code, 254)

    def test_lint_staged_stdin(self):
        """ Tests linting a staged commit. Gitint should lint the passed commit message andfetch additional meta-data
            from the underlying repository. The easiest way to test this is by inspecting `--debug` output.
            This is the equivalent of doing:
            echo "WIP: Pïpe test." | gitlint --staged --debug
        """
        # Create a commit first, before we stage changes. This ensures the repo is properly initialized.
        self.create_simple_commit("Sïmple title.\n")

        # Add some files, stage them: they should show up in the debug output as changed file
        filename1 = self.create_file(self.tmp_git_repo)
        git("add", filename1, _cwd=self.tmp_git_repo)
        filename2 = self.create_file(self.tmp_git_repo)
        git("add", filename2, _cwd=self.tmp_git_repo)

        output = gitlint(echo("WIP: Pïpe test."), "--staged", "--debug",
                         _cwd=self.tmp_git_repo, _tty_in=False, _err_to_out=True, _ok_code=[3])

        # Determine variable parts of expected output
        expected_kwargs = self.get_debug_vars_last_commit()
        expected_kwargs.update({'changed_files': sorted([filename1, filename2])})

        # It's not really possible to determine the "Date: ..." line that is part of the debug output as this date
        # is not taken from git but instead generated by gitlint itself. As a workaround, we extract the date from the
        # gitlint output using a regex, parse the date to ensure the format is correct, and then pass that as an
        # expected variable.
        matches = re.search(r'^Date:\s+(.*)', str(output), re.MULTILINE)
        if matches:
            expected_date = arrow.get(str(matches.group(1)), "YYYY-MM-DD HH:mm:ss Z").format("YYYY-MM-DD HH:mm:ss Z")
            expected_kwargs['staged_date'] = expected_date

        self.assertEqualStdout(output, self.get_expected("test_commits/test_lint_staged_stdin_1", expected_kwargs))
        self.assertEqual(output.exit_code, 3)

    def test_lint_staged_msg_filename(self):
        """ Tests linting a staged commit. Gitint should lint the passed commit message andfetch additional meta-data
            from the underlying repository. The easiest way to test this is by inspecting `--debug` output.
            This is the equivalent of doing:
            gitlint --msg-filename /tmp/my-commit-msg --staged --debug
        """
        # Create a commit first, before we stage changes. This ensures the repo is properly initialized.
        self.create_simple_commit("Sïmple title.\n")

        # Add some files, stage them: they should show up in the debug output as changed file
        filename1 = self.create_file(self.tmp_git_repo)
        git("add", filename1, _cwd=self.tmp_git_repo)
        filename2 = self.create_file(self.tmp_git_repo)
        git("add", filename2, _cwd=self.tmp_git_repo)

        tmp_commit_msg_file = self.create_tmpfile("WIP: from fïle test.")

        output = gitlint("--msg-filename", tmp_commit_msg_file, "--staged", "--debug",
                         _cwd=self.tmp_git_repo, _tty_in=False, _err_to_out=True, _ok_code=[3])

        # Determine variable parts of expected output
        expected_kwargs = self.get_debug_vars_last_commit()
        expected_kwargs.update({'changed_files': sorted([filename1, filename2])})

        # It's not really possible to determine the "Date: ..." line that is part of the debug output as this date
        # is not taken from git but instead generated by gitlint itself. As a workaround, we extract the date from the
        # gitlint output using a regex, parse the date to ensure the format is correct, and then pass that as an
        # expected variable.
        matches = re.search(r'^Date:\s+(.*)', str(output), re.MULTILINE)
        if matches:
            expected_date = arrow.get(str(matches.group(1)), "YYYY-MM-DD HH:mm:ss Z").format("YYYY-MM-DD HH:mm:ss Z")
            expected_kwargs['staged_date'] = expected_date

        expected = self.get_expected("test_commits/test_lint_staged_msg_filename_1", expected_kwargs)
        self.assertEqualStdout(output, expected)
        self.assertEqual(output.exit_code, 3)

    def test_lint_head(self):
        """ Testing whether we can also recognize special refs like 'HEAD' """
        tmp_git_repo = self.create_tmp_git_repo()
        self.create_simple_commit("Sïmple title.\n\nSimple bödy describing the commit", git_repo=tmp_git_repo)
        self.create_simple_commit("Sïmple title", git_repo=tmp_git_repo)
        self.create_simple_commit("WIP: Sïmple title\n\nSimple bödy describing the commit", git_repo=tmp_git_repo)
        output = gitlint("--commits", "HEAD", _cwd=tmp_git_repo, _tty_in=True, _ok_code=[3])
        revlist = git("rev-list", "HEAD", _tty_in=True, _cwd=tmp_git_repo).split()

        expected_kwargs = {"commit_sha0": revlist[0][:10], "commit_sha1": revlist[1][:10],
                           "commit_sha2": revlist[2][:10]}

        self.assertEqualStdout(output, self.get_expected("test_commits/test_lint_head_1", expected_kwargs))

    def test_ignore_commits(self):
        """ Tests multiple commits of which some rules get ignored because of ignore-* rules """
        # Create repo and some commits
        tmp_git_repo = self.create_tmp_git_repo()
        self.create_simple_commit("Sïmple title.\n\nSimple bödy describing the commit", git_repo=tmp_git_repo)
        # Normally, this commit will give T3 (trailing-punctuation), T5 (WIP) and B5 (bod-too-short) violations
        # But in this case only B5 because T3 and T5 are being ignored because of config
        self.create_simple_commit("Release: WIP tïtle.\n\nShort", git_repo=tmp_git_repo)
        # In the following 2 commits, the T3 violations are as normal
        self.create_simple_commit(
            "Sïmple WIP title3.\n\nThis is \ta relëase commit\nMore info", git_repo=tmp_git_repo)
        self.create_simple_commit("Sïmple title4.\n\nSimple bödy describing the commit4", git_repo=tmp_git_repo)
        revlist = git("rev-list", "HEAD", _tty_in=True, _cwd=tmp_git_repo).split()

        config_path = self.get_sample_path("config/ignore-release-commits")
        output = gitlint("--commits", "HEAD", "--config", config_path, _cwd=tmp_git_repo, _tty_in=True, _ok_code=[4])

        expected_kwargs = {"commit_sha0": revlist[0][:10], "commit_sha1": revlist[1][:10],
                           "commit_sha2": revlist[2][:10], "commit_sha3": revlist[3][:10]}
        self.assertEqualStdout(output, self.get_expected("test_commits/test_ignore_commits_1", expected_kwargs))