summaryrefslogtreecommitdiffstats
path: root/qa/test_gitlint.py
diff options
context:
space:
mode:
Diffstat (limited to 'qa/test_gitlint.py')
-rw-r--r--qa/test_gitlint.py267
1 files changed, 267 insertions, 0 deletions
diff --git a/qa/test_gitlint.py b/qa/test_gitlint.py
new file mode 100644
index 0000000..7a04a39
--- /dev/null
+++ b/qa/test_gitlint.py
@@ -0,0 +1,267 @@
+import os
+
+from qa.base import BaseTestCase
+from qa.shell import echo, git, gitlint
+from qa.utils import FILE_ENCODING
+
+
+class IntegrationTests(BaseTestCase):
+ """Simple set of integration tests for gitlint"""
+
+ def test_successful(self):
+ # Test for STDIN with and without a TTY attached
+ self.create_simple_commit("Sïmple title\n\nSimple bödy describing the commit")
+ output = gitlint(_cwd=self.tmp_git_repo, _tty_in=True, _err_to_out=True)
+ self.assertEqualStdout(output, "")
+
+ def test_successful_gitconfig(self):
+ """Test gitlint when the underlying repo has specific git config set.
+ In the past, we've had issues with gitlint failing on some of these, so this acts as a regression test."""
+
+ # Different commentchar (Note: tried setting this to a special unicode char, but git doesn't like that)
+ git("config", "--add", "core.commentchar", "$", _cwd=self.tmp_git_repo)
+ self.create_simple_commit("Sïmple title\n\nSimple bödy describing the commit\n$after commentchar\t ignored")
+ output = gitlint(_cwd=self.tmp_git_repo, _tty_in=True, _err_to_out=True)
+ self.assertEqualStdout(output, "")
+
+ def test_successful_merge_commit(self):
+ # Create branch on main
+ self.create_simple_commit("Cömmit on main\n\nSimple bödy")
+
+ # Create test branch, add a commit and determine the commit hash
+ git("checkout", "-b", "test-branch", _cwd=self.tmp_git_repo)
+ git("checkout", "test-branch", _cwd=self.tmp_git_repo)
+ commit_title = "Commit on test-brånch with a pretty long title that will cause issues when merging"
+ self.create_simple_commit(f"{commit_title}\n\nSïmple body")
+ hash = self.get_last_commit_hash()
+
+ # Checkout main and merge the commit
+ # We explicitly set the title of the merge commit to the title of the previous commit as this or similar
+ # behavior is what many tools do that handle merges (like github, gerrit, etc).
+ git("checkout", "main", _cwd=self.tmp_git_repo)
+ git("merge", "--no-ff", "-m", f"Merge '{commit_title}'", hash, _cwd=self.tmp_git_repo)
+
+ # Run gitlint and assert output is empty
+ output = gitlint(_cwd=self.tmp_git_repo, _tty_in=True)
+ self.assertEqualStdout(output, "")
+
+ # Assert that we do see the error if we disable the ignore-merge-commits option
+ output = gitlint("-c", "general.ignore-merge-commits=false", _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[1])
+ self.assertEqual(output.exit_code, 1)
+ self.assertEqualStdout(output, f"1: T1 Title exceeds max length (90>72): \"Merge '{commit_title}'\"\n")
+
+ def test_fixup_commit(self):
+ # Create a normal commit and assert that it has a violation
+ test_filename = self.create_simple_commit("Cömmit on WIP main\n\nSimple bödy that is long enough")
+ output = gitlint(_cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[1])
+ expected = "1: T5 Title contains the word 'WIP' (case-insensitive): \"Cömmit on WIP main\"\n"
+ self.assertEqualStdout(output, expected)
+
+ # Make a small modification to the commit and commit it using fixup commit
+ with open(os.path.join(self.tmp_git_repo, test_filename), "a", encoding=FILE_ENCODING) as fh:
+ fh.write("Appending söme stuff\n")
+
+ git("add", test_filename, _cwd=self.tmp_git_repo)
+
+ git("commit", "--fixup", self.get_last_commit_hash(), _cwd=self.tmp_git_repo)
+
+ # Assert that gitlint does not show an error for the fixup commit
+ output = gitlint(_cwd=self.tmp_git_repo, _tty_in=True)
+ # No need to check exit code, the command above throws an exception on > 0 exit codes
+ self.assertEqualStdout(output, "")
+
+ # Make sure that if we set the ignore-fixup-commits option to false that we do still see the violations
+ output = gitlint("-c", "general.ignore-fixup-commits=false", _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[2])
+ expected = (
+ "1: T5 Title contains the word 'WIP' (case-insensitive): \"fixup! Cömmit on WIP main\"\n"
+ "3: B6 Body message is missing\n"
+ )
+
+ self.assertEqualStdout(output, expected)
+
+ def test_fixup_amend_commit(self):
+ # Create a normal commit and assert that it has a violation
+ test_filename = self.create_simple_commit("Cömmit on WIP main\n\nSimple bödy that is long enough")
+ output = gitlint(_cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[1])
+ expected = "1: T5 Title contains the word 'WIP' (case-insensitive): \"Cömmit on WIP main\"\n"
+ self.assertEqualStdout(output, expected)
+
+ # Make a small modification to the commit and commit it using fixup=amend commit
+ with open(os.path.join(self.tmp_git_repo, test_filename), "a", encoding=FILE_ENCODING) as fh:
+ fh.write("Appending söme stuff\n")
+
+ git("add", test_filename, _cwd=self.tmp_git_repo)
+
+ # We have to use --no-edit to avoid git starting $EDITOR to modify the commit message that is being amended
+ git("commit", "--no-edit", f"--fixup=amend:{self.get_last_commit_hash()}", _cwd=self.tmp_git_repo)
+
+ # Assert that gitlint does not show an error for the fixup commit
+ output = gitlint(_cwd=self.tmp_git_repo, _tty_in=True)
+ # No need to check exit code, the command above throws an exception on > 0 exit codes
+ self.assertEqualStdout(output, "")
+
+ # Make sure that if we set the ignore-fixup-commits option to false that we do still see the violations
+ output = gitlint(
+ "-c", "general.ignore-fixup-amend-commits=false", _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[1]
+ )
+ expected = "1: T5 Title contains the word 'WIP' (case-insensitive): \"amend! Cömmit on WIP main\"\n"
+
+ self.assertEqualStdout(output, expected)
+
+ def test_revert_commit(self):
+ self.create_simple_commit("WIP: Cömmit on main.\n\nSimple bödy")
+ hash = self.get_last_commit_hash()
+ git("revert", hash, _cwd=self.tmp_git_repo)
+
+ # Run gitlint and assert output is empty
+ output = gitlint(_cwd=self.tmp_git_repo, _tty_in=True)
+ self.assertEqualStdout(output, "")
+
+ # Assert that we do see the error if we disable the ignore-revert-commits option
+ output = gitlint(
+ "-c", "general.ignore-revert-commits=false", _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[1]
+ )
+ self.assertEqual(output.exit_code, 1)
+ expected = '1: T5 Title contains the word \'WIP\' (case-insensitive): "Revert "WIP: Cömmit on main.""\n'
+ self.assertEqualStdout(output, expected)
+
+ def test_squash_commit(self):
+ # Create a normal commit and assert that it has a violation
+ test_filename = self.create_simple_commit("Cömmit on WIP main\n\nSimple bödy that is long enough")
+ output = gitlint(_cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[1])
+ expected = "1: T5 Title contains the word 'WIP' (case-insensitive): \"Cömmit on WIP main\"\n"
+ self.assertEqualStdout(output, expected)
+
+ # Make a small modification to the commit and commit it using squash commit
+ with open(os.path.join(self.tmp_git_repo, test_filename), "a", encoding=FILE_ENCODING) as fh:
+ # Wanted to write a unicode string, but that's obnoxious if you want to do it across Python 2 and 3.
+ # https://stackoverflow.com/questions/22392377/
+ # error-writing-a-file-with-file-write-in-python-unicodeencodeerror
+ # So just keeping it simple - ASCII will here
+ fh.write("Appending some stuff\n")
+
+ git("add", test_filename, _cwd=self.tmp_git_repo)
+
+ git("commit", "--squash", self.get_last_commit_hash(), "-m", "Töo short body", _cwd=self.tmp_git_repo)
+
+ # Assert that gitlint does not show an error for the fixup commit
+ output = gitlint(_cwd=self.tmp_git_repo, _tty_in=True)
+ # No need to check exit code, the command above throws an exception on > 0 exit codes
+ self.assertEqualStdout(output, "")
+
+ # Make sure that if we set the ignore-squash-commits option to false that we do still see the violations
+ output = gitlint(
+ "-c", "general.ignore-squash-commits=false", _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[2]
+ )
+ expected = (
+ "1: T5 Title contains the word 'WIP' (case-insensitive): \"squash! Cömmit on WIP main\"\n"
+ '3: B5 Body message is too short (14<20): "Töo short body"\n'
+ )
+
+ self.assertEqualStdout(output, expected)
+
+ def test_violations(self):
+ commit_msg = "WIP: This ïs a title.\nContent on the sëcond line"
+ self.create_simple_commit(commit_msg)
+ output = gitlint(_cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[3])
+ self.assertEqualStdout(output, self.get_expected("test_gitlint/test_violations_1"))
+
+ def test_msg_filename(self):
+ tmp_commit_msg_file = self.create_tmpfile("WIP: msg-fïlename test.")
+ output = gitlint("--msg-filename", tmp_commit_msg_file, _tty_in=True, _cwd=self.tmp_git_repo, _ok_code=[3])
+ self.assertEqualStdout(output, self.get_expected("test_gitlint/test_msg_filename_1"))
+
+ def test_msg_filename_no_tty(self):
+ """Make sure --msg-filename option also works with no TTY attached"""
+ tmp_commit_msg_file = self.create_tmpfile("WIP: msg-fïlename NO TTY test.")
+
+ # We need to set _err_to_out explicitly for sh to merge stdout and stderr output in case there's
+ # no TTY attached to STDIN
+ # http://amoffat.github.io/sh/sections/special_arguments.html?highlight=_tty_in#err-to-out
+ # We need to pass some whitespace to _in as sh will otherwise hang, see
+ # https://github.com/amoffat/sh/issues/427
+ output = gitlint(
+ "--msg-filename",
+ tmp_commit_msg_file,
+ _cwd=self.tmp_git_repo,
+ _in=" ",
+ _tty_in=False,
+ _err_to_out=True,
+ _ok_code=[3],
+ )
+
+ self.assertEqualStdout(output, self.get_expected("test_gitlint/test_msg_filename_no_tty_1"))
+
+ def test_no_git_name_set(self):
+ """Ensure we print out a helpful message if user.name is not set"""
+ tmp_commit_msg_file = self.create_tmpfile("WIP: msg-fïlename NO name test.")
+ # Name is checked before email so this isn't strictly
+ # necessary but seems good for consistency.
+ env = self.create_tmp_git_config("[user]\n email = test-emåil@foo.com\n")
+ output = gitlint(
+ "--staged",
+ "--msg-filename",
+ tmp_commit_msg_file,
+ _ok_code=[self.GIT_CONTEXT_ERROR_CODE],
+ _env=env,
+ _cwd=self.tmp_git_repo,
+ )
+ expected = "Missing git configuration: please set user.name\n"
+ self.assertEqualStdout(output, expected)
+
+ def test_no_git_email_set(self):
+ """Ensure we print out a helpful message if user.email is not set"""
+ tmp_commit_msg_file = self.create_tmpfile("WIP: msg-fïlename NO email test.")
+ env = self.create_tmp_git_config("[user]\n name = test åuthor\n")
+ output = gitlint(
+ "--staged",
+ "--msg-filename",
+ tmp_commit_msg_file,
+ _ok_code=[self.GIT_CONTEXT_ERROR_CODE],
+ _env=env,
+ _cwd=self.tmp_git_repo,
+ )
+ expected = "Missing git configuration: please set user.email\n"
+ self.assertEqualStdout(output, expected)
+
+ def test_git_empty_repo(self):
+ # Repo has no commits: caused by `git log`
+ empty_git_repo = self.create_tmp_git_repo()
+ output = gitlint(_cwd=empty_git_repo, _tty_in=True, _ok_code=[self.GIT_CONTEXT_ERROR_CODE])
+
+ expected = "Current branch has no commits. Gitlint requires at least one commit to function.\n"
+ self.assertEqualStdout(output, expected)
+
+ def test_git_empty_repo_staged(self):
+ """When repo is empty, we can still use gitlint when using --staged flag and piping a message into it"""
+ empty_git_repo = self.create_tmp_git_repo()
+ expected = (
+ '1: T3 Title has trailing punctuation (.): "WIP: Pïpe test."\n'
+ "1: T5 Title contains the word 'WIP' (case-insensitive): \"WIP: Pïpe test.\"\n"
+ "3: B6 Body message is missing\n"
+ )
+
+ output = gitlint(
+ echo("WIP: Pïpe test."), "--staged", _cwd=empty_git_repo, _tty_in=False, _err_to_out=True, _ok_code=[3]
+ )
+ self.assertEqualStdout(output, expected)
+
+ def test_commit_binary_file(self):
+ """When committing a binary file, git shows somewhat different output in diff commands,
+ this test ensures gitlint deals with that correctly"""
+ binary_filename = self.create_simple_commit("Sïmple commit", file_contents=bytes([0x48, 0x00, 0x49, 0x00]))
+ output = gitlint(
+ "--debug",
+ _ok_code=[1],
+ _cwd=self.tmp_git_repo,
+ )
+
+ expected_kwargs = self.get_debug_vars_last_commit()
+ expected_kwargs.update(
+ {
+ "changed_files": [binary_filename],
+ "changed_files_stats": (f"{binary_filename}: None additions, None deletions"),
+ }
+ )
+ expected = self.get_expected("test_gitlint/test_commit_binary_file_1", expected_kwargs)
+ self.assertEqualStdout(output, expected)