summaryrefslogtreecommitdiffstats
path: root/gitlint/tests/cli
diff options
context:
space:
mode:
Diffstat (limited to 'gitlint/tests/cli')
-rw-r--r--gitlint/tests/cli/test_cli.py78
-rw-r--r--gitlint/tests/cli/test_cli_hooks.py172
2 files changed, 214 insertions, 36 deletions
diff --git a/gitlint/tests/cli/test_cli.py b/gitlint/tests/cli/test_cli.py
index 4d47f35..88bcfb7 100644
--- a/gitlint/tests/cli/test_cli.py
+++ b/gitlint/tests/cli/test_cli.py
@@ -1,12 +1,10 @@
# -*- coding: utf-8 -*-
-import contextlib
+
import io
import os
import sys
import platform
-import shutil
-import tempfile
import arrow
@@ -34,15 +32,6 @@ from gitlint import __version__
from gitlint.utils import DEFAULT_ENCODING
-@contextlib.contextmanager
-def tempdir():
- tmpdir = tempfile.mkdtemp()
- try:
- yield tmpdir
- finally:
- shutil.rmtree(tmpdir)
-
-
class CLITests(BaseTestCase):
USAGE_ERROR_CODE = 253
GIT_CONTEXT_ERROR_CODE = 254
@@ -64,7 +53,8 @@ class CLITests(BaseTestCase):
def get_system_info_dict():
""" Returns a dict with items related to system values logged by `gitlint --debug` """
return {'platform': platform.platform(), "python_version": sys.version, 'gitlint_version': __version__,
- 'GITLINT_USE_SH_LIB': BaseTestCase.GITLINT_USE_SH_LIB, 'target': os.path.realpath(os.getcwd())}
+ 'GITLINT_USE_SH_LIB': BaseTestCase.GITLINT_USE_SH_LIB, 'target': os.path.realpath(os.getcwd()),
+ 'DEFAULT_ENCODING': DEFAULT_ENCODING}
def test_version(self):
""" Test for --version option """
@@ -118,7 +108,7 @@ class CLITests(BaseTestCase):
with patch('gitlint.display.stderr', new=StringIO()) as stderr:
result = self.cli.invoke(cli.cli, ["--commits", "foo...bar"])
- self.assertEqual(stderr.getvalue(), self.get_expected("test_cli/test_lint_multiple_commits_1"))
+ self.assertEqual(stderr.getvalue(), self.get_expected("cli/test_cli/test_lint_multiple_commits_1"))
self.assertEqual(result.exit_code, 3)
@patch('gitlint.cli.get_stdin_data', return_value=False)
@@ -152,7 +142,7 @@ class CLITests(BaseTestCase):
with patch('gitlint.display.stderr', new=StringIO()) as stderr:
result = self.cli.invoke(cli.cli, ["--commits", "foo...bar"])
# We expect that the second commit has no failures because of 'gitlint-ignore: T3' in its commit msg body
- self.assertEqual(stderr.getvalue(), self.get_expected("test_cli/test_lint_multiple_commits_config_1"))
+ self.assertEqual(stderr.getvalue(), self.get_expected("cli/test_cli/test_lint_multiple_commits_config_1"))
self.assertEqual(result.exit_code, 3)
@patch('gitlint.cli.get_stdin_data', return_value=False)
@@ -205,7 +195,7 @@ class CLITests(BaseTestCase):
""" Test for linting when a message is passed via stdin """
with patch('gitlint.display.stderr', new=StringIO()) as stderr:
result = self.cli.invoke(cli.cli)
- self.assertEqual(stderr.getvalue(), self.get_expected("test_cli/test_input_stream_1"))
+ self.assertEqual(stderr.getvalue(), self.get_expected("cli/test_cli/test_input_stream_1"))
self.assertEqual(result.exit_code, 3)
self.assertEqual(result.output, "")
@@ -215,11 +205,11 @@ class CLITests(BaseTestCase):
This tests specifically that git commit meta is not fetched when not passing --staged """
with patch('gitlint.display.stderr', new=StringIO()) as stderr:
result = self.cli.invoke(cli.cli, ["--debug"])
- self.assertEqual(stderr.getvalue(), self.get_expected("test_cli/test_input_stream_debug_1"))
+ self.assertEqual(stderr.getvalue(), self.get_expected("cli/test_cli/test_input_stream_debug_1"))
self.assertEqual(result.exit_code, 3)
self.assertEqual(result.output, "")
expected_kwargs = self.get_system_info_dict()
- expected_logs = self.get_expected('test_cli/test_input_stream_debug_2', expected_kwargs)
+ expected_logs = self.get_expected('cli/test_cli/test_input_stream_debug_2', expected_kwargs)
self.assert_logged(expected_logs)
@patch('gitlint.cli.get_stdin_data', return_value="Should be ignored\n")
@@ -259,12 +249,12 @@ class CLITests(BaseTestCase):
with patch('gitlint.display.stderr', new=StringIO()) as stderr:
result = self.cli.invoke(cli.cli, ["--debug", "--staged"])
- self.assertEqual(stderr.getvalue(), self.get_expected("test_cli/test_lint_staged_stdin_1"))
+ self.assertEqual(stderr.getvalue(), self.get_expected("cli/test_cli/test_lint_staged_stdin_1"))
self.assertEqual(result.exit_code, 3)
self.assertEqual(result.output, "")
expected_kwargs = self.get_system_info_dict()
- expected_logs = self.get_expected('test_cli/test_lint_staged_stdin_2', expected_kwargs)
+ expected_logs = self.get_expected('cli/test_cli/test_lint_staged_stdin_2', expected_kwargs)
self.assert_logged(expected_logs)
@patch('arrow.now', return_value=arrow.get("2020-02-19T12:18:46.675182+01:00"))
@@ -280,19 +270,19 @@ class CLITests(BaseTestCase):
u"commit-1/file-1\ncommit-1/file-2\n", # git diff-tree
]
- with tempdir() as tmpdir:
+ with self.tempdir() as tmpdir:
msg_filename = os.path.join(tmpdir, "msg")
with io.open(msg_filename, 'w', encoding=DEFAULT_ENCODING) as f:
f.write(u"WIP: msg-filename tïtle\n")
with patch('gitlint.display.stderr', new=StringIO()) as stderr:
result = self.cli.invoke(cli.cli, ["--debug", "--staged", "--msg-filename", msg_filename])
- self.assertEqual(stderr.getvalue(), self.get_expected("test_cli/test_lint_staged_msg_filename_1"))
+ self.assertEqual(stderr.getvalue(), self.get_expected("cli/test_cli/test_lint_staged_msg_filename_1"))
self.assertEqual(result.exit_code, 2)
self.assertEqual(result.output, "")
expected_kwargs = self.get_system_info_dict()
- expected_logs = self.get_expected('test_cli/test_lint_staged_msg_filename_2', expected_kwargs)
+ expected_logs = self.get_expected('cli/test_cli/test_lint_staged_msg_filename_2', expected_kwargs)
self.assert_logged(expected_logs)
@patch('gitlint.cli.get_stdin_data', return_value=False)
@@ -306,7 +296,7 @@ class CLITests(BaseTestCase):
def test_msg_filename(self, _):
expected_output = u"3: B6 Body message is missing\n"
- with tempdir() as tmpdir:
+ with self.tempdir() as tmpdir:
msg_filename = os.path.join(tmpdir, "msg")
with io.open(msg_filename, 'w', encoding=DEFAULT_ENCODING) as f:
f.write(u"Commït title\n")
@@ -375,7 +365,7 @@ class CLITests(BaseTestCase):
u"commit-2-branch-1\ncommit-2-branch-2\n", # git branch --contains <sha>
u"commit-2/file-1\ncommit-2/file-2\n", # git diff-tree
u"test åuthor3\x00test-email3@föo.com\x002016-12-05 15:28:15 +0100\x00abc\n"
- u"föo\nbar",
+ u"föobar\nbar",
u"commit-3-branch-1\ncommit-3-branch-2\n", # git branch --contains <sha>
u"commit-3/file-1\ncommit-3/file-2\n", # git diff-tree
]
@@ -394,7 +384,7 @@ class CLITests(BaseTestCase):
expected_kwargs = self.get_system_info_dict()
expected_kwargs.update({'config_path': config_path})
- expected_logs = self.get_expected('test_cli/test_debug_1', expected_kwargs)
+ expected_logs = self.get_expected('cli/test_cli/test_debug_1', expected_kwargs)
self.assert_logged(expected_logs)
@patch('gitlint.cli.get_stdin_data', return_value=u"Test tïtle\n")
@@ -403,7 +393,7 @@ class CLITests(BaseTestCase):
# Test extra-path pointing to a directory
with patch('gitlint.display.stderr', new=StringIO()) as stderr:
extra_path = self.get_sample_path("user_rules")
- result = self.cli.invoke(cli.cli, ["--extra-path", extra_path, "--debug"])
+ result = self.cli.invoke(cli.cli, ["--extra-path", extra_path])
expected_output = u"1: UC1 Commit violåtion 1: \"Contënt 1\"\n" + \
"3: B6 Body message is missing\n"
self.assertEqual(stderr.getvalue(), expected_output)
@@ -412,7 +402,7 @@ class CLITests(BaseTestCase):
# Test extra-path pointing to a file
with patch('gitlint.display.stderr', new=StringIO()) as stderr:
extra_path = self.get_sample_path(os.path.join("user_rules", "my_commit_rules.py"))
- result = self.cli.invoke(cli.cli, ["--extra-path", extra_path, "--debug"])
+ result = self.cli.invoke(cli.cli, ["--extra-path", extra_path])
expected_output = u"1: UC1 Commit violåtion 1: \"Contënt 1\"\n" + \
"3: B6 Body message is missing\n"
self.assertEqual(stderr.getvalue(), expected_output)
@@ -423,7 +413,7 @@ class CLITests(BaseTestCase):
# Test enabled contrib rules
with patch('gitlint.display.stderr', new=StringIO()) as stderr:
result = self.cli.invoke(cli.cli, ["--contrib", "contrib-title-conventional-commits,CC1"])
- expected_output = self.get_expected('test_cli/test_contrib_1')
+ expected_output = self.get_expected('cli/test_cli/test_contrib_1')
self.assertEqual(stderr.getvalue(), expected_output)
self.assertEqual(result.exit_code, 3)
@@ -469,13 +459,14 @@ class CLITests(BaseTestCase):
@patch('gitlint.cli.get_stdin_data', return_value=False)
def test_target(self, _):
""" Test for the --target option """
- os.environ["LANGUAGE"] = "C" # Force language to english so we can check for error message
- result = self.cli.invoke(cli.cli, ["--target", "/tmp"])
- # We expect gitlint to tell us that /tmp is not a git repo (this proves that it takes the target parameter
- # into account).
- expected_path = os.path.realpath("/tmp")
- self.assertEqual(result.output, "%s is not a git repository.\n" % expected_path)
- self.assertEqual(result.exit_code, self.GIT_CONTEXT_ERROR_CODE)
+ with self.tempdir() as tmpdir:
+ tmpdir_path = os.path.realpath(tmpdir)
+ os.environ["LANGUAGE"] = "C" # Force language to english so we can check for error message
+ result = self.cli.invoke(cli.cli, ["--target", tmpdir_path])
+ # We expect gitlint to tell us that /tmp is not a git repo (this proves that it takes the target parameter
+ # into account).
+ self.assertEqual(result.output, "%s is not a git repository.\n" % tmpdir_path)
+ self.assertEqual(result.exit_code, self.GIT_CONTEXT_ERROR_CODE)
def test_target_negative(self):
""" Negative test for the --target option """
@@ -539,3 +530,18 @@ class CLITests(BaseTestCase):
self.assert_log_contains(u"DEBUG: gitlint.cli No commits in range \"master...HEAD\"")
self.assertEqual(result.exit_code, 0)
+
+ @patch('gitlint.cli.get_stdin_data', return_value=u"WIP: tëst tïtle")
+ def test_named_rules(self, _):
+ with patch('gitlint.display.stderr', new=StringIO()) as stderr:
+ config_path = self.get_sample_path(os.path.join("config", "named-rules"))
+ result = self.cli.invoke(cli.cli, ["--config", config_path, "--debug"])
+ self.assertEqual(result.output, "")
+ self.assertEqual(stderr.getvalue(), self.get_expected("cli/test_cli/test_named_rules_1"))
+ self.assertEqual(result.exit_code, 4)
+
+ # Assert debug logs are correct
+ expected_kwargs = self.get_system_info_dict()
+ expected_kwargs.update({'config_path': config_path})
+ expected_logs = self.get_expected('cli/test_cli/test_named_rules_2', expected_kwargs)
+ self.assert_logged(expected_logs)
diff --git a/gitlint/tests/cli/test_cli_hooks.py b/gitlint/tests/cli/test_cli_hooks.py
index 0564808..b5e7fc4 100644
--- a/gitlint/tests/cli/test_cli_hooks.py
+++ b/gitlint/tests/cli/test_cli_hooks.py
@@ -1,11 +1,19 @@
# -*- coding: utf-8 -*-
+import io
import os
from click.testing import CliRunner
try:
# python 2.x
+ from StringIO import StringIO
+except ImportError:
+ # python 3.x
+ from io import StringIO # pylint: disable=ungrouped-imports
+
+try:
+ # python 2.x
from mock import patch
except ImportError:
# python 3.x
@@ -16,6 +24,8 @@ from gitlint import cli
from gitlint import hooks
from gitlint import config
+from gitlint.utils import DEFAULT_ENCODING
+
class CLIHookTests(BaseTestCase):
USAGE_ERROR_CODE = 253
@@ -94,3 +104,165 @@ class CLIHookTests(BaseTestCase):
expected_config = config.LintConfig()
expected_config.target = os.path.realpath(os.getcwd())
uninstall_hook.assert_called_once_with(expected_config)
+
+ def test_hook_no_tty(self):
+ """ Test for run-hook subcommand.
+ When no TTY is available (like is the case for this test), the hook will abort after the first check.
+ """
+
+ # No need to patch git as we're passing a msg-filename to run-hook, so no git calls are made.
+ # Note that this is the case when passing --staged as well, but that's tested as part of the integration tests
+ # (=end-to-end scenario).
+
+ # Ideally we'd be able to assert that run-hook internally calls the lint cli command, but couldn't make
+ # that work. Have tried many different variatons of mocking and patching without avail. For now, we just
+ # check the output which indirectly proves the same thing.
+
+ with self.tempdir() as tmpdir:
+ msg_filename = os.path.join(tmpdir, u"hür")
+ with io.open(msg_filename, 'w', encoding=DEFAULT_ENCODING) as f:
+ f.write(u"WIP: tïtle\n")
+
+ with patch('gitlint.display.stderr', new=StringIO()) as stderr:
+ result = self.cli.invoke(cli.cli, ["--msg-filename", msg_filename, "run-hook"])
+ self.assertEqual(result.output, self.get_expected('cli/test_cli_hooks/test_hook_no_tty_1_stdout'))
+ self.assertEqual(stderr.getvalue(), self.get_expected("cli/test_cli_hooks/test_hook_no_tty_1_stderr"))
+
+ # exit code is 1 because aborted (no stdin available)
+ self.assertEqual(result.exit_code, 1)
+
+ @patch('gitlint.cli.shell')
+ def test_hook_edit(self, shell):
+ """ Test for run-hook subcommand, answering 'e(dit)' after commit-hook """
+
+ set_editors = [None, u"myeditor"]
+ expected_editors = [u"vim -n", u"myeditor"]
+ commit_messages = [u"WIP: höok edit 1", u"WIP: höok edit 2"]
+
+ for i in range(0, len(set_editors)):
+ if set_editors[i]:
+ os.environ['EDITOR'] = set_editors[i]
+
+ with self.patch_input(['e', 'e', 'n']):
+ with self.tempdir() as tmpdir:
+ msg_filename = os.path.realpath(os.path.join(tmpdir, u"hür"))
+ with io.open(msg_filename, 'w', encoding=DEFAULT_ENCODING) as f:
+ f.write(commit_messages[i] + "\n")
+
+ with patch('gitlint.display.stderr', new=StringIO()) as stderr:
+ result = self.cli.invoke(cli.cli, ["--msg-filename", msg_filename, "run-hook"])
+ self.assertEqual(result.output, self.get_expected('cli/test_cli_hooks/test_hook_edit_1_stdout',
+ {"commit_msg": commit_messages[i]}))
+ expected = self.get_expected("cli/test_cli_hooks/test_hook_edit_1_stderr",
+ {"commit_msg": commit_messages[i]})
+ self.assertEqual(stderr.getvalue(), expected)
+
+ # exit code = number of violations
+ self.assertEqual(result.exit_code, 2)
+
+ shell.assert_called_with(expected_editors[i] + " " + msg_filename)
+ self.assert_log_contains(u"DEBUG: gitlint.cli run-hook: editing commit message")
+ self.assert_log_contains(u"DEBUG: gitlint.cli run-hook: {0} {1}".format(expected_editors[i],
+ msg_filename))
+
+ def test_hook_no(self):
+ """ Test for run-hook subcommand, answering 'n(o)' after commit-hook """
+
+ with self.patch_input(['n']):
+ with self.tempdir() as tmpdir:
+ msg_filename = os.path.join(tmpdir, u"hür")
+ with io.open(msg_filename, 'w', encoding=DEFAULT_ENCODING) as f:
+ f.write(u"WIP: höok no\n")
+
+ with patch('gitlint.display.stderr', new=StringIO()) as stderr:
+ result = self.cli.invoke(cli.cli, ["--msg-filename", msg_filename, "run-hook"])
+ self.assertEqual(result.output, self.get_expected('cli/test_cli_hooks/test_hook_no_1_stdout'))
+ self.assertEqual(stderr.getvalue(), self.get_expected("cli/test_cli_hooks/test_hook_no_1_stderr"))
+
+ # We decided not to keep the commit message: hook returns number of violations (>0)
+ # This will cause git to abort the commit
+ self.assertEqual(result.exit_code, 2)
+ self.assert_log_contains("DEBUG: gitlint.cli run-hook: commit message declined")
+
+ def test_hook_yes(self):
+ """ Test for run-hook subcommand, answering 'y(es)' after commit-hook """
+ with self.patch_input(['y']):
+ with self.tempdir() as tmpdir:
+ msg_filename = os.path.join(tmpdir, u"hür")
+ with io.open(msg_filename, 'w', encoding=DEFAULT_ENCODING) as f:
+ f.write(u"WIP: höok yes\n")
+
+ with patch('gitlint.display.stderr', new=StringIO()) as stderr:
+ result = self.cli.invoke(cli.cli, ["--msg-filename", msg_filename, "run-hook"])
+ self.assertEqual(result.output, self.get_expected('cli/test_cli_hooks/test_hook_yes_1_stdout'))
+ self.assertEqual(stderr.getvalue(), self.get_expected("cli/test_cli_hooks/test_hook_yes_1_stderr"))
+
+ # Exit code is 0 because we decide to keep the commit message
+ # This will cause git to keep the commit
+ self.assertEqual(result.exit_code, 0)
+ self.assert_log_contains("DEBUG: gitlint.cli run-hook: commit message accepted")
+
+ @patch('gitlint.cli.get_stdin_data', return_value=u"WIP: Test hook stdin tïtle\n")
+ def test_hook_stdin_violations(self, _):
+ """ Test for passing stdin data to run-hook, expecting some violations. Equivalent of:
+ $ echo "WIP: Test hook stdin tïtle" | gitlint run-hook
+ """
+
+ with patch('gitlint.display.stderr', new=StringIO()) as stderr:
+ result = self.cli.invoke(cli.cli, ["run-hook"])
+ expected_stderr = self.get_expected('cli/test_cli_hooks/test_hook_stdin_violations_1_stderr')
+ self.assertEqual(stderr.getvalue(), expected_stderr)
+ self.assertEqual(result.output, self.get_expected('cli/test_cli_hooks/test_hook_stdin_violations_1_stdout'))
+ # Hook will auto-abort because we're using stdin. Abort = exit code 1
+ self.assertEqual(result.exit_code, 1)
+
+ @patch('gitlint.cli.get_stdin_data', return_value=u"Test tïtle\n\nTest bödy that is long enough")
+ def test_hook_stdin_no_violations(self, _):
+ """ Test for passing stdin data to run-hook, expecting *NO* violations, Equivalent of:
+ $ echo -e "Test tïtle\n\nTest bödy that is long enough" | gitlint run-hook
+ """
+
+ with patch('gitlint.display.stderr', new=StringIO()) as stderr:
+ result = self.cli.invoke(cli.cli, ["run-hook"])
+ self.assertEqual(stderr.getvalue(), "") # no errors = no stderr output
+ expected_stdout = self.get_expected('cli/test_cli_hooks/test_hook_stdin_no_violations_1_stdout')
+ self.assertEqual(result.output, expected_stdout)
+ self.assertEqual(result.exit_code, 0)
+
+ @patch('gitlint.cli.get_stdin_data', return_value=u"WIP: Test hook config tïtle\n")
+ def test_hook_config(self, _):
+ """ Test that gitlint still respects config when running run-hook, equivalent of:
+ $ echo "WIP: Test hook config tïtle" | gitlint -c title-max-length.line-length=5 --ignore B6 run-hook
+ """
+
+ with patch('gitlint.display.stderr', new=StringIO()) as stderr:
+ result = self.cli.invoke(cli.cli, ["-c", "title-max-length.line-length=5", "--ignore", "B6", "run-hook"])
+ self.assertEqual(stderr.getvalue(), self.get_expected('cli/test_cli_hooks/test_hook_config_1_stderr'))
+ self.assertEqual(result.output, self.get_expected('cli/test_cli_hooks/test_hook_config_1_stdout'))
+ # Hook will auto-abort because we're using stdin. Abort = exit code 1
+ self.assertEqual(result.exit_code, 1)
+
+ @patch('gitlint.cli.get_stdin_data', return_value=False)
+ @patch('gitlint.git.sh')
+ def test_hook_local_commit(self, sh, _):
+ """ Test running the hook on the last commit-msg from the local repo, equivalent of:
+ $ gitlint run-hook
+ and then choosing 'e'
+ """
+ sh.git.side_effect = [
+ "6f29bf81a8322a04071bb794666e48c443a90360",
+ u"test åuthor\x00test-email@föo.com\x002016-12-03 15:28:15 +0100\x00åbc\n"
+ u"WIP: commït-title\n\ncommït-body",
+ u"#", # git config --get core.commentchar
+ u"commit-1-branch-1\ncommit-1-branch-2\n",
+ u"file1.txt\npåth/to/file2.txt\n"
+ ]
+
+ with self.patch_input(['e']):
+ with patch('gitlint.display.stderr', new=StringIO()) as stderr:
+ result = self.cli.invoke(cli.cli, ["run-hook"])
+ expected = self.get_expected('cli/test_cli_hooks/test_hook_local_commit_1_stderr')
+ self.assertEqual(stderr.getvalue(), expected)
+ self.assertEqual(result.output, self.get_expected('cli/test_cli_hooks/test_hook_local_commit_1_stdout'))
+ # If we can't edit the message, run-hook follows regular gitlint behavior and exit code = # violations
+ self.assertEqual(result.exit_code, 2)