summaryrefslogtreecommitdiffstats
path: root/qa
diff options
context:
space:
mode:
Diffstat (limited to 'qa')
-rw-r--r--qa/base.py43
-rw-r--r--qa/expected/test_commits/test_lint_staged_msg_filename_13
-rw-r--r--qa/expected/test_commits/test_lint_staged_stdin_13
-rw-r--r--qa/expected/test_config/test_config_from_env_13
-rw-r--r--qa/expected/test_config/test_config_from_env_23
-rw-r--r--qa/expected/test_config/test_config_from_file_debug_13
-rw-r--r--qa/expected/test_gitlint/test_commit_binary_file_13
-rw-r--r--qa/expected/test_rules/test_ignore_rules_13
-rw-r--r--qa/expected/test_rules/test_ignore_rules_22
-rw-r--r--qa/expected/test_rules/test_match_regex_rules_12
-rw-r--r--qa/expected/test_user_defined/test_user_defined_rules_examples_21
-rw-r--r--qa/requirements.txt4
-rw-r--r--qa/samples/user_rules/extra/extra_rules.py10
-rw-r--r--qa/shell.py83
-rw-r--r--qa/test_commits.py10
-rw-r--r--qa/test_config.py10
-rw-r--r--qa/test_contrib.py3
-rw-r--r--qa/test_gitlint.py14
-rw-r--r--qa/test_hooks.py22
-rw-r--r--qa/test_named_rules.py2
-rw-r--r--qa/test_rules.py61
-rw-r--r--qa/test_stdin.py12
-rw-r--r--qa/test_user_defined.py5
-rw-r--r--qa/utils.py46
24 files changed, 218 insertions, 133 deletions
diff --git a/qa/base.py b/qa/base.py
index ce66fbf..2b83778 100644
--- a/qa/base.py
+++ b/qa/base.py
@@ -1,20 +1,16 @@
-# pylint: disable=bad-option-value,unidiomatic-typecheck,undefined-variable,no-else-return,
-# pylint: disable=too-many-function-args,unexpected-keyword-arg
-
import os
import platform
import shutil
import sys
import tempfile
-from datetime import datetime
-from uuid import uuid4
+from datetime import datetime, timezone
from unittest import TestCase
+from uuid import uuid4
import arrow
-
-from qa.shell import git, gitlint, RunningCommand
-from qa.utils import DEFAULT_ENCODING
+from qa.shell import RunningCommand, git, gitlint
+from qa.utils import FILE_ENCODING, PLATFORM_IS_WINDOWS, TERMINAL_ENCODING
class BaseTestCase(TestCase):
@@ -40,18 +36,19 @@ class BaseTestCase(TestCase):
for tmpfile in self.tmpfiles:
os.remove(tmpfile)
for repo in self.tmp_git_repos:
- shutil.rmtree(repo)
+ # On windows we need to ignore errors because git might still be holding on to some files
+ shutil.rmtree(repo, ignore_errors=PLATFORM_IS_WINDOWS)
- def assertEqualStdout(self, output, expected): # pylint: disable=invalid-name
+ def assertEqualStdout(self, output, expected):
self.assertIsInstance(output, RunningCommand)
- output = output.stdout.decode(DEFAULT_ENCODING)
+ output = output.stdout.decode(TERMINAL_ENCODING)
output = output.replace("\r", "")
self.assertMultiLineEqual(output, expected)
@staticmethod
def generate_temp_path():
- timestamp = datetime.now().strftime("%Y%m%d-%H%M%S-%f")
- return os.path.realpath(f"/tmp/gitlint-test-{timestamp}")
+ timestamp = datetime.now(timezone.utc).strftime("%Y%m%d-%H%M%S-%f")
+ return os.path.realpath(f"/tmp/gitlint-test-{timestamp}") # noqa
def create_tmp_git_repo(self):
"""Creates a temporary git repository and returns its directory path"""
@@ -72,6 +69,9 @@ class BaseTestCase(TestCase):
# http://stackoverflow.com/questions/5581857/git-and-the-umlaut-problem-on-mac-os-x
git("config", "core.precomposeunicode", "true", _cwd=tmp_git_repo)
+ # Git now does commit message cleanup by default (e.g. removing trailing whitespace), disable that for testing
+ git("config", "commit.cleanup", "verbatim", _cwd=tmp_git_repo)
+
return tmp_git_repo
@staticmethod
@@ -84,13 +84,12 @@ class BaseTestCase(TestCase):
if isinstance(content, bytes):
open_kwargs = {"mode": "wb"}
else:
- open_kwargs = {"mode": "w", "encoding": DEFAULT_ENCODING}
+ open_kwargs = {"mode": "w", "encoding": FILE_ENCODING}
- with open(full_path, **open_kwargs) as f: # pylint: disable=unspecified-encoding
+ with open(full_path, **open_kwargs) as f:
f.write(content)
else:
- # pylint: disable=consider-using-with
- open(full_path, "a", encoding=DEFAULT_ENCODING).close()
+ open(full_path, "a", encoding=FILE_ENCODING).close() # noqa: SIM115 (Use context handler for opening files)
return test_filename
@@ -150,9 +149,9 @@ class BaseTestCase(TestCase):
if isinstance(content, bytes):
open_kwargs = {"mode": "wb"}
else:
- open_kwargs = {"mode": "w", "encoding": DEFAULT_ENCODING}
+ open_kwargs = {"mode": "w", "encoding": FILE_ENCODING}
- with open(tmpfile, **open_kwargs) as f: # pylint: disable=unspecified-encoding
+ with open(tmpfile, **open_kwargs) as f:
f.write(content)
return tmpfilepath
@@ -181,7 +180,8 @@ class BaseTestCase(TestCase):
specified by variable_dict."""
expected_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "expected")
expected_path = os.path.join(expected_dir, filename)
- with open(expected_path, encoding=DEFAULT_ENCODING) as file:
+ # Expected files are UTF-8 encoded (not dependent on the system's default encoding)
+ with open(expected_path, encoding=FILE_ENCODING) as file:
expected = file.read()
if variable_dict:
@@ -199,7 +199,8 @@ class BaseTestCase(TestCase):
"git_version": expected_git_version,
"gitlint_version": expected_gitlint_version,
"GITLINT_USE_SH_LIB": BaseTestCase.GITLINT_USE_SH_LIB,
- "DEFAULT_ENCODING": DEFAULT_ENCODING,
+ "TERMINAL_ENCODING": TERMINAL_ENCODING,
+ "FILE_ENCODING": FILE_ENCODING,
}
def get_debug_vars_last_commit(self, git_repo=None):
diff --git a/qa/expected/test_commits/test_lint_staged_msg_filename_1 b/qa/expected/test_commits/test_lint_staged_msg_filename_1
index f2ab49e..03a558c 100644
--- a/qa/expected/test_commits/test_lint_staged_msg_filename_1
+++ b/qa/expected/test_commits/test_lint_staged_msg_filename_1
@@ -5,7 +5,8 @@ DEBUG: gitlint.git ('--version',)
DEBUG: gitlint.cli Git version: {git_version}
DEBUG: gitlint.cli Gitlint version: {gitlint_version}
DEBUG: gitlint.cli GITLINT_USE_SH_LIB: {GITLINT_USE_SH_LIB}
-DEBUG: gitlint.cli DEFAULT_ENCODING: {DEFAULT_ENCODING}
+DEBUG: gitlint.cli TERMINAL_ENCODING: {TERMINAL_ENCODING}
+DEBUG: gitlint.cli FILE_ENCODING: {FILE_ENCODING}
DEBUG: gitlint.cli Configuration
config-path: None
[GENERAL]
diff --git a/qa/expected/test_commits/test_lint_staged_stdin_1 b/qa/expected/test_commits/test_lint_staged_stdin_1
index cf34b8b..7892865 100644
--- a/qa/expected/test_commits/test_lint_staged_stdin_1
+++ b/qa/expected/test_commits/test_lint_staged_stdin_1
@@ -5,7 +5,8 @@ DEBUG: gitlint.git ('--version',)
DEBUG: gitlint.cli Git version: {git_version}
DEBUG: gitlint.cli Gitlint version: {gitlint_version}
DEBUG: gitlint.cli GITLINT_USE_SH_LIB: {GITLINT_USE_SH_LIB}
-DEBUG: gitlint.cli DEFAULT_ENCODING: {DEFAULT_ENCODING}
+DEBUG: gitlint.cli TERMINAL_ENCODING: {TERMINAL_ENCODING}
+DEBUG: gitlint.cli FILE_ENCODING: {FILE_ENCODING}
DEBUG: gitlint.cli Configuration
config-path: None
[GENERAL]
diff --git a/qa/expected/test_config/test_config_from_env_1 b/qa/expected/test_config/test_config_from_env_1
index 38fba21..91eee40 100644
--- a/qa/expected/test_config/test_config_from_env_1
+++ b/qa/expected/test_config/test_config_from_env_1
@@ -5,7 +5,8 @@ DEBUG: gitlint.git ('--version',)
DEBUG: gitlint.cli Git version: {git_version}
DEBUG: gitlint.cli Gitlint version: {gitlint_version}
DEBUG: gitlint.cli GITLINT_USE_SH_LIB: {GITLINT_USE_SH_LIB}
-DEBUG: gitlint.cli DEFAULT_ENCODING: {DEFAULT_ENCODING}
+DEBUG: gitlint.cli TERMINAL_ENCODING: {TERMINAL_ENCODING}
+DEBUG: gitlint.cli FILE_ENCODING: {FILE_ENCODING}
DEBUG: gitlint.cli Configuration
config-path: None
[GENERAL]
diff --git a/qa/expected/test_config/test_config_from_env_2 b/qa/expected/test_config/test_config_from_env_2
index 50d1e3f..06b0c1b 100644
--- a/qa/expected/test_config/test_config_from_env_2
+++ b/qa/expected/test_config/test_config_from_env_2
@@ -5,7 +5,8 @@ DEBUG: gitlint.git ('--version',)
DEBUG: gitlint.cli Git version: {git_version}
DEBUG: gitlint.cli Gitlint version: {gitlint_version}
DEBUG: gitlint.cli GITLINT_USE_SH_LIB: {GITLINT_USE_SH_LIB}
-DEBUG: gitlint.cli DEFAULT_ENCODING: {DEFAULT_ENCODING}
+DEBUG: gitlint.cli TERMINAL_ENCODING: {TERMINAL_ENCODING}
+DEBUG: gitlint.cli FILE_ENCODING: {FILE_ENCODING}
DEBUG: gitlint.cli Configuration
config-path: None
[GENERAL]
diff --git a/qa/expected/test_config/test_config_from_file_debug_1 b/qa/expected/test_config/test_config_from_file_debug_1
index 39bdf52..279fb32 100644
--- a/qa/expected/test_config/test_config_from_file_debug_1
+++ b/qa/expected/test_config/test_config_from_file_debug_1
@@ -5,7 +5,8 @@ DEBUG: gitlint.git ('--version',)
DEBUG: gitlint.cli Git version: {git_version}
DEBUG: gitlint.cli Gitlint version: {gitlint_version}
DEBUG: gitlint.cli GITLINT_USE_SH_LIB: {GITLINT_USE_SH_LIB}
-DEBUG: gitlint.cli DEFAULT_ENCODING: {DEFAULT_ENCODING}
+DEBUG: gitlint.cli TERMINAL_ENCODING: {TERMINAL_ENCODING}
+DEBUG: gitlint.cli FILE_ENCODING: {FILE_ENCODING}
DEBUG: gitlint.cli Configuration
config-path: {config_path}
[GENERAL]
diff --git a/qa/expected/test_gitlint/test_commit_binary_file_1 b/qa/expected/test_gitlint/test_commit_binary_file_1
index 6bc119b..83faf1b 100644
--- a/qa/expected/test_gitlint/test_commit_binary_file_1
+++ b/qa/expected/test_gitlint/test_commit_binary_file_1
@@ -5,7 +5,8 @@ DEBUG: gitlint.git ('--version',)
DEBUG: gitlint.cli Git version: {git_version}
DEBUG: gitlint.cli Gitlint version: {gitlint_version}
DEBUG: gitlint.cli GITLINT_USE_SH_LIB: {GITLINT_USE_SH_LIB}
-DEBUG: gitlint.cli DEFAULT_ENCODING: {DEFAULT_ENCODING}
+DEBUG: gitlint.cli TERMINAL_ENCODING: {TERMINAL_ENCODING}
+DEBUG: gitlint.cli FILE_ENCODING: {FILE_ENCODING}
DEBUG: gitlint.cli Configuration
config-path: None
[GENERAL]
diff --git a/qa/expected/test_rules/test_ignore_rules_1 b/qa/expected/test_rules/test_ignore_rules_1
new file mode 100644
index 0000000..f87f303
--- /dev/null
+++ b/qa/expected/test_rules/test_ignore_rules_1
@@ -0,0 +1,3 @@
+1: T5 Title contains the word 'WIP' (case-insensitive): "WIP: Commït Tïtle"
+3: B3 Line contains hard tab characters (\t): "Sïmple commit body"
+4: B2 Line has trailing whitespace: "Anōther Line "
diff --git a/qa/expected/test_rules/test_ignore_rules_2 b/qa/expected/test_rules/test_ignore_rules_2
new file mode 100644
index 0000000..dc6428c
--- /dev/null
+++ b/qa/expected/test_rules/test_ignore_rules_2
@@ -0,0 +1,2 @@
+1: T5 Title contains the word 'WIP' (case-insensitive): "WIP: Commït Tïtle"
+3: B3 Line contains hard tab characters (\t): "Sïmple commit body"
diff --git a/qa/expected/test_rules/test_match_regex_rules_1 b/qa/expected/test_rules/test_match_regex_rules_1
new file mode 100644
index 0000000..3bfaa58
--- /dev/null
+++ b/qa/expected/test_rules/test_match_regex_rules_1
@@ -0,0 +1,2 @@
+1: T7 Title does not match regex (foo): "Thåt dûr bår"
+4: B8 Body does not match regex (bar)
diff --git a/qa/expected/test_user_defined/test_user_defined_rules_examples_2 b/qa/expected/test_user_defined/test_user_defined_rules_examples_2
index 9b96423..d706b12 100644
--- a/qa/expected/test_user_defined/test_user_defined_rules_examples_2
+++ b/qa/expected/test_user_defined/test_user_defined_rules_examples_2
@@ -2,3 +2,4 @@
1: UC3 Branch name 'main' does not start with one of ['feature/', 'hotfix/', 'release/']
1: UL1 Title contains the special character '$'
2: B4 Second line is not empty
+3: B3 Line contains hard tab characters (\t)
diff --git a/qa/requirements.txt b/qa/requirements.txt
deleted file mode 100644
index cf6baa5..0000000
--- a/qa/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-sh==1.14.3
-pytest==7.0.1;
-arrow==1.2.3;
-gitlint # no version as you want to test the currently installed version
diff --git a/qa/samples/user_rules/extra/extra_rules.py b/qa/samples/user_rules/extra/extra_rules.py
index cad531b..7996590 100644
--- a/qa/samples/user_rules/extra/extra_rules.py
+++ b/qa/samples/user_rules/extra/extra_rules.py
@@ -1,5 +1,5 @@
-from gitlint.rules import CommitRule, RuleViolation, ConfigurationRule
-from gitlint.options import IntOption, StrOption, ListOption
+from gitlint.options import IntOption, ListOption, StrOption
+from gitlint.rules import CommitRule, ConfigurationRule, RuleViolation
class GitContextRule(CommitRule):
@@ -64,9 +64,9 @@ class ConfigurableCommitRule(CommitRule):
def validate(self, _):
violations = [
- RuleViolation(self.id, f"int-öption: {self.options[u'int-öption'].value}", line_nr=1),
- RuleViolation(self.id, f"str-öption: {self.options[u'str-öption'].value}", line_nr=1),
- RuleViolation(self.id, f"list-öption: {self.options[u'list-öption'].value}", line_nr=1),
+ RuleViolation(self.id, f"int-öption: {self.options['int-öption'].value}", line_nr=1),
+ RuleViolation(self.id, f"str-öption: {self.options['str-öption'].value}", line_nr=1),
+ RuleViolation(self.id, f"list-öption: {self.options['list-öption'].value}", line_nr=1),
]
return violations
diff --git a/qa/shell.py b/qa/shell.py
index 44716c0..3ef874d 100644
--- a/qa/shell.py
+++ b/qa/shell.py
@@ -2,24 +2,31 @@
# on gitlint internals for our integration testing framework.
import subprocess
-from qa.utils import USE_SH_LIB, DEFAULT_ENCODING
+
+from qa.utils import TERMINAL_ENCODING, USE_SH_LIB
if USE_SH_LIB:
- from sh import git, echo, gitlint # pylint: disable=unused-import,no-name-in-module,import-error
+ from sh import (
+ echo,
+ git,
+ gitlint,
+ )
- gitlint = gitlint.bake(_unify_ttys=True, _tty_in=True) # pylint: disable=invalid-name
+ gitlint = gitlint.bake(_unify_ttys=True, _tty_in=True)
# import exceptions separately, this makes it a little easier to mock them out in the unit tests
- from sh import CommandNotFound, ErrorReturnCode, RunningCommand # pylint: disable=import-error
+ from sh import (
+ CommandNotFound,
+ ErrorReturnCode,
+ RunningCommand,
+ )
else:
class CommandNotFound(Exception):
"""Exception indicating a command was not found during execution"""
- pass
-
class RunningCommand:
- pass
+ ...
class ShResult(RunningCommand):
"""Result wrapper class. We use this to more easily migrate from using https://amoffat.github.io/sh/ to using
@@ -29,18 +36,35 @@ else:
self.full_cmd = full_cmd
# TODO(jorisroovers): The 'sh' library by default will merge stdout and stderr. We mimic this behavior
# for now until we fully remove the 'sh' library.
- self.stdout = stdout + stderr.decode(DEFAULT_ENCODING)
- self.stderr = stderr
+ self._stdout = stdout + stderr
+ self._stderr = stderr
self.exit_code = exitcode
def __str__(self):
+ return self.stdout.decode(TERMINAL_ENCODING)
+
+ def __unicode__(self):
return self.stdout
+ @property
+ def stdout(self):
+ return self._stdout
+
+ @property
+ def stderr(self):
+ return self._stderr
+
+ def __getattr__(self, p):
+ # https://github.com/amoffat/sh/blob/e0ed8e244e9d973ef4e0749b2b3c2695e7b5255b/sh.py#L952=
+ _unicode_methods = set(dir(str())) # noqa
+ if p in _unicode_methods:
+ return getattr(str(self), p)
+
+ raise AttributeError
+
class ErrorReturnCode(ShResult, Exception):
"""ShResult subclass for unexpected results (acts as an exception)."""
- pass
-
def git(*command_parts, **kwargs):
return run_command("git", *command_parts, **kwargs)
@@ -51,31 +75,36 @@ else:
return run_command("gitlint", *command_parts, **kwargs)
def run_command(command, *args, **kwargs):
- args = [command] + list(args)
- result = _exec(*args, **kwargs)
- # If we reach this point and the result has an exit_code that is larger than 0, this means that we didn't
- # get an exception (which is the default sh behavior for non-zero exit codes) and so the user is expecting
- # a non-zero exit code -> just return the entire result
- if hasattr(result, "exit_code") and result.exit_code > 0:
- return result
- return str(result)
+ args = [command, *list(args)]
+ return _exec(*args, **kwargs)
def _exec(*args, **kwargs):
- pipe = subprocess.PIPE
- popen_kwargs = {"stdout": pipe, "stderr": pipe, "shell": kwargs.get("_tty_out", False)}
- if "_cwd" in kwargs:
- popen_kwargs["cwd"] = kwargs["_cwd"]
- if "_env" in kwargs:
- popen_kwargs["env"] = kwargs["_env"]
+ popen_kwargs = {
+ "stdout": subprocess.PIPE,
+ "stderr": subprocess.PIPE,
+ "stdin": subprocess.PIPE,
+ "shell": kwargs.get("_tty_out", False),
+ "cwd": kwargs.get("_cwd", None),
+ "env": kwargs.get("_env", None),
+ }
+
+ stdin_input = None
+ if len(args) > 1 and isinstance(args[1], ShResult):
+ stdin_input = args[1].stdout
+ # pop args[1] from the array and use it as stdin
+ args = list(args)
+ args.pop(1)
+ popen_kwargs["stdin"] = subprocess.PIPE
try:
with subprocess.Popen(args, **popen_kwargs) as p:
- result = p.communicate()
+ result = p.communicate(stdin_input)
+
except FileNotFoundError as exc:
raise CommandNotFound from exc
exit_code = p.returncode
- stdout = result[0].decode(DEFAULT_ENCODING)
+ stdout = result[0]
stderr = result[1] # 'sh' does not decode the stderr bytes to unicode
full_cmd = "" if args is None else " ".join(args)
diff --git a/qa/test_commits.py b/qa/test_commits.py
index d40c211..11d1851 100644
--- a/qa/test_commits.py
+++ b/qa/test_commits.py
@@ -1,10 +1,9 @@
-# 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
+from qa.shell import echo, git, gitlint
class CommitsTests(BaseTestCase):
@@ -111,6 +110,11 @@ class CommitsTests(BaseTestCase):
self.assertEqual(output.exit_code, 2)
self.assertEqualStdout(output, expected)
+ # Lint using --commits <commit sha>,
+ output = gitlint("--commits", f"{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)
@@ -129,7 +133,7 @@ class CommitsTests(BaseTestCase):
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
+ """Tests linting a staged commit. Gitint should lint the passed commit message and fetch 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
diff --git a/qa/test_config.py b/qa/test_config.py
index 1225f6a..d051686 100644
--- a/qa/test_config.py
+++ b/qa/test_config.py
@@ -1,10 +1,8 @@
-# pylint: disable=too-many-function-args,unexpected-keyword-arg
-
+import os
import re
-from qa.shell import gitlint
from qa.base import BaseTestCase
-from qa.utils import DEFAULT_ENCODING
+from qa.shell import gitlint
class ConfigTests(BaseTestCase):
@@ -69,7 +67,7 @@ class ConfigTests(BaseTestCase):
"This line of the body is here because we need it"
)
filename = self.create_simple_commit(commit_msg, git_repo=target_repo)
- config_path = self.get_sample_path("config/gitlintconfig")
+ config_path = self.get_sample_path(os.path.join("config", "gitlintconfig"))
output = gitlint("--config", config_path, "--debug", _cwd=target_repo, _tty_in=True, _ok_code=[5])
expected_kwargs = self.get_debug_vars_last_commit(git_repo=target_repo)
@@ -128,7 +126,7 @@ class ConfigTests(BaseTestCase):
# Extract date from actual output to insert it into the expected output
# We have to do this since there's no way for us to deterministically know that date otherwise
p = re.compile("Date: (.*)\n", re.UNICODE | re.MULTILINE)
- result = p.search(output.stdout.decode(DEFAULT_ENCODING))
+ result = p.search(str(output))
date = result.group(1).strip()
expected_kwargs.update({"date": date})
diff --git a/qa/test_contrib.py b/qa/test_contrib.py
index 129e576..d3a45ba 100644
--- a/qa/test_contrib.py
+++ b/qa/test_contrib.py
@@ -1,6 +1,5 @@
-# pylint: disable=
-from qa.shell import gitlint
from qa.base import BaseTestCase
+from qa.shell import gitlint
class ContribRuleTests(BaseTestCase):
diff --git a/qa/test_gitlint.py b/qa/test_gitlint.py
index 6c45196..7a04a39 100644
--- a/qa/test_gitlint.py
+++ b/qa/test_gitlint.py
@@ -1,8 +1,8 @@
-# pylint: disable=too-many-function-args,unexpected-keyword-arg
import os
-from qa.shell import echo, git, gitlint
+
from qa.base import BaseTestCase
-from qa.utils import DEFAULT_ENCODING
+from qa.shell import echo, git, gitlint
+from qa.utils import FILE_ENCODING
class IntegrationTests(BaseTestCase):
@@ -58,7 +58,7 @@ class IntegrationTests(BaseTestCase):
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=DEFAULT_ENCODING) as fh:
+ 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)
@@ -87,7 +87,7 @@ class IntegrationTests(BaseTestCase):
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=DEFAULT_ENCODING) as fh:
+ 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)
@@ -133,7 +133,7 @@ class IntegrationTests(BaseTestCase):
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=DEFAULT_ENCODING) as fh:
+ 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
@@ -252,7 +252,7 @@ class IntegrationTests(BaseTestCase):
binary_filename = self.create_simple_commit("Sïmple commit", file_contents=bytes([0x48, 0x00, 0x49, 0x00]))
output = gitlint(
"--debug",
- _ok_code=1,
+ _ok_code=[1],
_cwd=self.tmp_git_repo,
)
diff --git a/qa/test_hooks.py b/qa/test_hooks.py
index 19edeb2..99e76dd 100644
--- a/qa/test_hooks.py
+++ b/qa/test_hooks.py
@@ -1,7 +1,7 @@
-# pylint: disable=too-many-function-args,unexpected-keyword-arg
import os
-from qa.shell import git, gitlint
+
from qa.base import BaseTestCase
+from qa.shell import git, gitlint
class HookTests(BaseTestCase):
@@ -30,18 +30,16 @@ class HookTests(BaseTestCase):
# install git commit-msg hook and assert output
output_installed = gitlint("install-hook", _cwd=self.tmp_git_repo)
- expected_installed = (
- f"Successfully installed gitlint commit-msg hook in {self.tmp_git_repo}/.git/hooks/commit-msg\n"
- )
+ commit_msg_hook_path = os.path.join(self.tmp_git_repo, ".git", "hooks", "commit-msg")
+ expected_installed = f"Successfully installed gitlint commit-msg hook in {commit_msg_hook_path}\n"
self.assertEqualStdout(output_installed, expected_installed)
def tearDown(self):
# uninstall git commit-msg hook and assert output
output_uninstalled = gitlint("uninstall-hook", _cwd=self.tmp_git_repo)
- expected_uninstalled = (
- f"Successfully uninstalled gitlint commit-msg hook from {self.tmp_git_repo}/.git/hooks/commit-msg\n"
- )
+ commit_msg_hook_path = os.path.join(self.tmp_git_repo, ".git", "hooks", "commit-msg")
+ expected_uninstalled = f"Successfully uninstalled gitlint commit-msg hook from {commit_msg_hook_path}\n"
self.assertEqualStdout(output_uninstalled, expected_uninstalled)
super().tearDown()
@@ -171,10 +169,10 @@ class HookTests(BaseTestCase):
output_installed = gitlint("install-hook", _cwd=worktree_dir)
expected_hook_path = os.path.join(tmp_git_repo, ".git", "hooks", "commit-msg")
- expected_msg = f"Successfully installed gitlint commit-msg hook in {expected_hook_path}\r\n"
- self.assertEqual(output_installed, expected_msg)
+ expected_msg = f"Successfully installed gitlint commit-msg hook in {expected_hook_path}\n"
+ self.assertEqualStdout(output_installed, expected_msg)
output_uninstalled = gitlint("uninstall-hook", _cwd=worktree_dir)
expected_hook_path = os.path.join(tmp_git_repo, ".git", "hooks", "commit-msg")
- expected_msg = f"Successfully uninstalled gitlint commit-msg hook from {expected_hook_path}\r\n"
- self.assertEqual(output_uninstalled, expected_msg)
+ expected_msg = f"Successfully uninstalled gitlint commit-msg hook from {expected_hook_path}\n"
+ self.assertEqualStdout(output_uninstalled, expected_msg)
diff --git a/qa/test_named_rules.py b/qa/test_named_rules.py
index 75cd9a1..e3c6908 100644
--- a/qa/test_named_rules.py
+++ b/qa/test_named_rules.py
@@ -1,5 +1,5 @@
-from qa.shell import gitlint
from qa.base import BaseTestCase
+from qa.shell import gitlint
class NamedRuleTests(BaseTestCase):
diff --git a/qa/test_rules.py b/qa/test_rules.py
new file mode 100644
index 0000000..218a13a
--- /dev/null
+++ b/qa/test_rules.py
@@ -0,0 +1,61 @@
+from qa.base import BaseTestCase
+from qa.shell import gitlint
+
+
+class RuleTests(BaseTestCase):
+ """
+ Tests for specific rules that are worth testing as integration tests.
+ It's not a goal to test every edge case of each rule, that's what the unit tests do.
+ """
+
+ def test_match_regex_rules(self):
+ """
+ Test that T7 (title-match-regex) and B8 (body-match-regex) work as expected.
+ By default, these rules don't do anything, only when setting a custom regex will they run.
+ """
+
+ commit_msg = "Thåt dûr bår\n\nSïmple commit message body"
+ self.create_simple_commit(commit_msg)
+
+ # Assert violations when T7 and B8 regexes don't match
+ output = gitlint("-c", "T7.regex=foo", "-c", "B8.regex=bar", _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[2])
+ self.assertEqualStdout(output, self.get_expected("test_rules/test_match_regex_rules_1"))
+
+ # Assert no violations when T7 and B8 regexes do match
+ output = gitlint("-c", "T7.regex=^Thåt", "-c", "B8.regex=commit message", _cwd=self.tmp_git_repo, _tty_in=True)
+ self.assertEqualStdout(output, "")
+
+ def test_ignore_rules(self):
+ """
+ Test that ignore rules work as expected:
+ ignore-by-title, ignore-by-body, ignore-by-author-name, ignore-body-lines
+ By default, these rules don't do anything, only when setting a custom regex will they run.
+ """
+ commit_msg = "WIP: Commït Tïtle\n\nSïmple commit\tbody\nAnōther Line \nLåst Line"
+ self.create_simple_commit(commit_msg)
+
+ # Assert violations when not ignoring anything
+ output = gitlint(_cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[3])
+ self.assertEqualStdout(output, self.get_expected("test_rules/test_ignore_rules_1"))
+
+ # Simple convenience function that passes in common arguments for this test
+ def invoke_gitlint(*args, **kwargs):
+ return gitlint(
+ *args, "-c", "general.regex-style-search=True", **kwargs, _cwd=self.tmp_git_repo, _tty_in=True
+ )
+
+ # ignore-by-title
+ output = invoke_gitlint("-c", "ignore-by-title.regex=Commït")
+ self.assertEqualStdout(output, "")
+
+ # ignore-by-body
+ output = invoke_gitlint("-c", "ignore-by-body.regex=Anōther Line")
+ self.assertEqualStdout(output, "")
+
+ # ignore-by-author-name
+ output = invoke_gitlint("-c", "ignore-by-author-name.regex=gitlint-test-user")
+ self.assertEqualStdout(output, "")
+
+ # ignore-body-lines
+ output = invoke_gitlint("-c", "ignore-body-lines.regex=^Anōther", _ok_code=[2])
+ self.assertEqualStdout(output, self.get_expected("test_rules/test_ignore_rules_2"))
diff --git a/qa/test_stdin.py b/qa/test_stdin.py
index 8ed4cb1..04a3de9 100644
--- a/qa/test_stdin.py
+++ b/qa/test_stdin.py
@@ -1,8 +1,8 @@
-# pylint: disable=too-many-function-args,unexpected-keyword-arg
import subprocess
-from qa.shell import echo, gitlint
+
from qa.base import BaseTestCase
-from qa.utils import DEFAULT_ENCODING
+from qa.shell import echo, gitlint
+from qa.utils import FILE_ENCODING, TERMINAL_ENCODING
class StdInTests(BaseTestCase):
@@ -33,7 +33,7 @@ class StdInTests(BaseTestCase):
# http://amoffat.github.io/sh/sections/special_arguments.html?highlight=_tty_in#err-to-out
output = gitlint(echo("-n", ""), _cwd=self.tmp_git_repo, _tty_in=False, _err_to_out=True, _ok_code=[3])
- self.assertEqual(output, self.get_expected("test_stdin/test_stdin_pipe_empty_1"))
+ self.assertEqualStdout(output, self.get_expected("test_stdin/test_stdin_pipe_empty_1"))
def test_stdin_file(self):
"""Test the scenario where STDIN is a regular file (stat.S_ISREG = True)
@@ -42,7 +42,7 @@ class StdInTests(BaseTestCase):
"""
tmp_commit_msg_file = self.create_tmpfile("WIP: STDIN ïs a file test.")
- with open(tmp_commit_msg_file, encoding=DEFAULT_ENCODING) as file_handle:
+ with open(tmp_commit_msg_file, encoding=FILE_ENCODING) as file_handle: # noqa: SIM117
# We need to use subprocess.Popen() here instead of sh because when passing a file_handle to sh, it will
# deal with reading the file itself instead of passing it on to gitlint as a STDIN. Since we're trying to
# test for the condition where stat.S_ISREG == True that won't work for us here.
@@ -50,4 +50,4 @@ class StdInTests(BaseTestCase):
"gitlint", stdin=file_handle, cwd=self.tmp_git_repo, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
) as p:
output, _ = p.communicate()
- self.assertEqual(output.decode(DEFAULT_ENCODING), self.get_expected("test_stdin/test_stdin_file_1"))
+ self.assertEqual(output.decode(TERMINAL_ENCODING), self.get_expected("test_stdin/test_stdin_file_1"))
diff --git a/qa/test_user_defined.py b/qa/test_user_defined.py
index a003f3e..718766c 100644
--- a/qa/test_user_defined.py
+++ b/qa/test_user_defined.py
@@ -1,6 +1,5 @@
-# pylint: disable=too-many-function-args,unexpected-keyword-arg
-from qa.shell import gitlint
from qa.base import BaseTestCase
+from qa.shell import gitlint
class UserDefinedRuleTests(BaseTestCase):
@@ -19,7 +18,7 @@ class UserDefinedRuleTests(BaseTestCase):
extra_path = self.get_example_path()
commit_msg = "Release: Thi$ is å title\nContent on the second line\n$This line is ignored \nThis isn't\t\n"
self.create_simple_commit(commit_msg)
- output = gitlint("--extra-path", extra_path, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[4])
+ output = gitlint("--extra-path", extra_path, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[5])
self.assertEqualStdout(output, self.get_expected("test_user_defined/test_user_defined_rules_examples_2"))
def test_user_defined_rules_examples_with_config(self):
diff --git a/qa/utils.py b/qa/utils.py
index 89292cd..d560d86 100644
--- a/qa/utils.py
+++ b/qa/utils.py
@@ -1,8 +1,6 @@
-# pylint: disable=bad-option-value,unidiomatic-typecheck,undefined-variable,no-else-return
-import platform
-import os
-
import locale
+import os
+import platform
########################################################################################################################
# PLATFORM_IS_WINDOWS
@@ -31,32 +29,20 @@ def use_sh_library():
USE_SH_LIB = use_sh_library()
########################################################################################################################
-# DEFAULT_ENCODING
+# TERMINAL_ENCODING
+# Encoding for reading gitlint command output
def getpreferredencoding():
- """Modified version of local.getpreferredencoding() that takes into account LC_ALL, LC_CTYPE, LANG env vars
- on windows and falls back to UTF-8."""
- default_encoding = locale.getpreferredencoding() or "UTF-8"
-
- # On Windows, we mimic git/linux by trying to read the LC_ALL, LC_CTYPE, LANG env vars manually
- # (on Linux/MacOS the `getpreferredencoding()` call will take care of this).
- # We fallback to UTF-8
- if PLATFORM_IS_WINDOWS:
- default_encoding = "UTF-8"
- for env_var in ["LC_ALL", "LC_CTYPE", "LANG"]:
- encoding = os.environ.get(env_var, False)
- if encoding:
- # Support dotted (C.UTF-8) and non-dotted (C or UTF-8) charsets:
- # If encoding contains a dot: split and use second part, otherwise use everything
- dot_index = encoding.find(".")
- if dot_index != -1:
- default_encoding = encoding[dot_index + 1 :]
- else:
- default_encoding = encoding
- break
-
- return default_encoding
-
-
-DEFAULT_ENCODING = getpreferredencoding()
+ """Use local.getpreferredencoding() or fallback to UTF-8."""
+ return locale.getpreferredencoding() or "UTF-8"
+
+
+TERMINAL_ENCODING = getpreferredencoding()
+
+
+########################################################################################################################
+# FILE_ENCODING
+
+# Encoding for reading/writing files within the tests, this is always UTF-8
+FILE_ENCODING = "UTF-8"