summaryrefslogtreecommitdiffstats
path: root/qa
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2021-10-13 05:34:57 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2021-10-13 05:34:57 +0000
commite2d38cd54491535f409372393baeed787c77388d (patch)
treee9f823c384ee487d30de5ae84c8d3755f6974baa /qa
parentReleasing debian version 0.15.1-3. (diff)
downloadgitlint-e2d38cd54491535f409372393baeed787c77388d.tar.xz
gitlint-e2d38cd54491535f409372393baeed787c77388d.zip
Merging upstream version 0.16.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'qa')
-rw-r--r--qa/base.py40
-rw-r--r--qa/expected/test_commits/test_lint_staged_msg_filename_14
-rw-r--r--qa/expected/test_commits/test_lint_staged_stdin_14
-rw-r--r--qa/expected/test_config/test_config_from_env_14
-rw-r--r--qa/expected/test_config/test_config_from_env_24
-rw-r--r--qa/expected/test_config/test_config_from_file_debug_14
-rw-r--r--qa/expected/test_contrib/test_contrib_rules_11
-rw-r--r--qa/expected/test_contrib/test_contrib_rules_with_config_11
-rw-r--r--qa/requirements.txt6
-rw-r--r--qa/shell.py4
-rw-r--r--qa/test_commits.py47
-rw-r--r--qa/test_config.py3
-rw-r--r--qa/test_contrib.py4
-rw-r--r--qa/test_hooks.py31
-rw-r--r--qa/test_stdin.py8
15 files changed, 112 insertions, 53 deletions
diff --git a/qa/base.py b/qa/base.py
index acb921d..d3c8e81 100644
--- a/qa/base.py
+++ b/qa/base.py
@@ -29,25 +29,20 @@ class BaseTestCase(TestCase):
GITLINT_USE_SH_LIB = os.environ.get("GITLINT_USE_SH_LIB", "[NOT SET]")
GIT_CONTEXT_ERROR_CODE = 254
-
- @classmethod
- def setUpClass(cls):
- """ Sets up the integration tests by creating a new temporary git repository """
- cls.tmp_git_repos = []
- cls.tmp_git_repo = cls.create_tmp_git_repo()
-
- @classmethod
- def tearDownClass(cls):
- """ Cleans up the temporary git repositories """
- for repo in cls.tmp_git_repos:
- shutil.rmtree(repo)
+ GITLINT_USAGE_ERROR = 253
def setUp(self):
+ """ Sets up the integration tests by creating a new temporary git repository """
self.tmpfiles = []
+ self.tmp_git_repos = []
+ self.tmp_git_repo = self.create_tmp_git_repo()
def tearDown(self):
+ # Clean up temporary files and repos
for tmpfile in self.tmpfiles:
os.remove(tmpfile)
+ for repo in self.tmp_git_repos:
+ shutil.rmtree(repo)
def assertEqualStdout(self, output, expected): # pylint: disable=invalid-name
self.assertIsInstance(output, RunningCommand)
@@ -55,16 +50,15 @@ class BaseTestCase(TestCase):
output = output.replace('\r', '')
self.assertMultiLineEqual(output, expected)
- @classmethod
- def generate_temp_path(cls):
+ @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}")
- @classmethod
- def create_tmp_git_repo(cls):
+ def create_tmp_git_repo(self):
""" Creates a temporary git repository and returns its directory path """
- tmp_git_repo = cls.generate_temp_path()
- cls.tmp_git_repos.append(tmp_git_repo)
+ tmp_git_repo = self.generate_temp_path()
+ self.tmp_git_repos.append(tmp_git_repo)
git("init", tmp_git_repo)
# configuring name and email is required in every git repot
@@ -86,6 +80,7 @@ class BaseTestCase(TestCase):
def create_file(parent_dir):
""" Creates a file inside a passed directory. Returns filename."""
test_filename = "test-fïle-" + str(uuid4())
+ # pylint: disable=consider-using-with
io.open(os.path.join(parent_dir, test_filename), 'a', encoding=DEFAULT_ENCODING).close()
return test_filename
@@ -158,11 +153,12 @@ 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)
- expected = io.open(expected_path, encoding=DEFAULT_ENCODING).read()
+ with io.open(expected_path, encoding=DEFAULT_ENCODING) as file:
+ expected = file.read()
- if variable_dict:
- expected = expected.format(**variable_dict)
- return expected
+ if variable_dict:
+ expected = expected.format(**variable_dict)
+ return expected
@staticmethod
def get_system_info_dict():
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 eb2682f..901ea27 100644
--- a/qa/expected/test_commits/test_lint_staged_msg_filename_1
+++ b/qa/expected/test_commits/test_lint_staged_msg_filename_1
@@ -18,6 +18,7 @@ ignore-squash-commits: True
ignore-revert-commits: True
ignore-stdin: False
staged: True
+fail-without-commits: False
verbosity: 3
debug: True
target: {target}
@@ -30,6 +31,9 @@ target: {target}
regex=None
I3: ignore-body-lines
regex=None
+ I4: ignore-by-author-name
+ ignore=all
+ regex=None
T1: title-max-length
line-length=72
T2: title-trailing-whitespace
diff --git a/qa/expected/test_commits/test_lint_staged_stdin_1 b/qa/expected/test_commits/test_lint_staged_stdin_1
index 76b5048..e4677c3 100644
--- a/qa/expected/test_commits/test_lint_staged_stdin_1
+++ b/qa/expected/test_commits/test_lint_staged_stdin_1
@@ -18,6 +18,7 @@ ignore-squash-commits: True
ignore-revert-commits: True
ignore-stdin: False
staged: True
+fail-without-commits: False
verbosity: 3
debug: True
target: {target}
@@ -30,6 +31,9 @@ target: {target}
regex=None
I3: ignore-body-lines
regex=None
+ I4: ignore-by-author-name
+ ignore=all
+ regex=None
T1: title-max-length
line-length=72
T2: title-trailing-whitespace
diff --git a/qa/expected/test_config/test_config_from_env_1 b/qa/expected/test_config/test_config_from_env_1
index f3947bb..60f6690 100644
--- a/qa/expected/test_config/test_config_from_env_1
+++ b/qa/expected/test_config/test_config_from_env_1
@@ -18,6 +18,7 @@ ignore-squash-commits: True
ignore-revert-commits: True
ignore-stdin: True
staged: False
+fail-without-commits: True
verbosity: 2
debug: True
target: {target}
@@ -30,6 +31,9 @@ target: {target}
regex=None
I3: ignore-body-lines
regex=None
+ I4: ignore-by-author-name
+ ignore=all
+ regex=None
T1: title-max-length
line-length=72
T2: title-trailing-whitespace
diff --git a/qa/expected/test_config/test_config_from_env_2 b/qa/expected/test_config/test_config_from_env_2
index 8d36672..e9ebd67 100644
--- a/qa/expected/test_config/test_config_from_env_2
+++ b/qa/expected/test_config/test_config_from_env_2
@@ -18,6 +18,7 @@ ignore-squash-commits: True
ignore-revert-commits: True
ignore-stdin: False
staged: True
+fail-without-commits: False
verbosity: 0
debug: True
target: {target}
@@ -30,6 +31,9 @@ target: {target}
regex=None
I3: ignore-body-lines
regex=None
+ I4: ignore-by-author-name
+ ignore=all
+ regex=None
T1: title-max-length
line-length=72
T2: title-trailing-whitespace
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 540c3a0..6ad5ec4 100644
--- a/qa/expected/test_config/test_config_from_file_debug_1
+++ b/qa/expected/test_config/test_config_from_file_debug_1
@@ -18,6 +18,7 @@ ignore-squash-commits: True
ignore-revert-commits: True
ignore-stdin: False
staged: False
+fail-without-commits: False
verbosity: 2
debug: True
target: {target}
@@ -30,6 +31,9 @@ target: {target}
regex=None
I3: ignore-body-lines
regex=None
+ I4: ignore-by-author-name
+ ignore=all
+ regex=None
T1: title-max-length
line-length=20
T2: title-trailing-whitespace
diff --git a/qa/expected/test_contrib/test_contrib_rules_1 b/qa/expected/test_contrib/test_contrib_rules_1
index 6876c80..6ab7512 100644
--- a/qa/expected/test_contrib/test_contrib_rules_1
+++ b/qa/expected/test_contrib/test_contrib_rules_1
@@ -1,4 +1,3 @@
1: CC1 Body does not contain a 'Signed-off-by' line
-1: CT1 Title does not start with one of fix, feat, chore, docs, style, refactor, perf, test, revert, ci, build: "WIP Thi$ is å title"
1: CT1 Title does not follow ConventionalCommits.org format 'type(optional-scope): description': "WIP Thi$ is å title"
1: T5 Title contains the word 'WIP' (case-insensitive): "WIP Thi$ is å title"
diff --git a/qa/expected/test_contrib/test_contrib_rules_with_config_1 b/qa/expected/test_contrib/test_contrib_rules_with_config_1
index d5b5cf8..6ab7512 100644
--- a/qa/expected/test_contrib/test_contrib_rules_with_config_1
+++ b/qa/expected/test_contrib/test_contrib_rules_with_config_1
@@ -1,4 +1,3 @@
1: CC1 Body does not contain a 'Signed-off-by' line
-1: CT1 Title does not start with one of föo, bår: "WIP Thi$ is å title"
1: CT1 Title does not follow ConventionalCommits.org format 'type(optional-scope): description': "WIP Thi$ is å title"
1: T5 Title contains the word 'WIP' (case-insensitive): "WIP Thi$ is å title"
diff --git a/qa/requirements.txt b/qa/requirements.txt
index 95d49d4..5a4f660 100644
--- a/qa/requirements.txt
+++ b/qa/requirements.txt
@@ -1,4 +1,4 @@
-sh==1.14.1
-pytest==6.2.3;
-arrow==1.0.3;
+sh==1.14.2
+pytest==6.2.5;
+arrow==1.2.0;
gitlint # no version as you want to test the currently installed version
diff --git a/qa/shell.py b/qa/shell.py
index 97dcd2c..630843f 100644
--- a/qa/shell.py
+++ b/qa/shell.py
@@ -67,8 +67,8 @@ else:
popen_kwargs['env'] = kwargs['_env']
try:
- p = subprocess.Popen(args, **popen_kwargs)
- result = p.communicate()
+ with subprocess.Popen(args, **popen_kwargs) as p:
+ result = p.communicate()
except FileNotFoundError as exc:
raise CommandNotFound from exc
diff --git a/qa/test_commits.py b/qa/test_commits.py
index 389ad66..92e1087 100644
--- a/qa/test_commits.py
+++ b/qa/test_commits.py
@@ -40,19 +40,60 @@ class CommitsTests(BaseTestCase):
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>` """
+ """ 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")
- output = gitlint("--commits", refspec, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[2])
+
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.
@@ -139,7 +180,7 @@ class CommitsTests(BaseTestCase):
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 igonored because of ignore-* rules """
+ """ 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)
diff --git a/qa/test_config.py b/qa/test_config.py
index 9c00b95..432a2c5 100644
--- a/qa/test_config.py
+++ b/qa/test_config.py
@@ -80,7 +80,8 @@ class ConfigTests(BaseTestCase):
filename = self.create_simple_commit(commit_msg, git_repo=target_repo)
env = self.create_environment({"GITLINT_DEBUG": "1", "GITLINT_VERBOSITY": "2",
"GITLINT_IGNORE": "T1,T2", "GITLINT_CONTRIB": "CC1,CT1",
- "GITLINT_IGNORE_STDIN": "1", "GITLINT_TARGET": target_repo,
+ "GITLINT_FAIL_WITHOUT_COMMITS": "1", "GITLINT_IGNORE_STDIN": "1",
+ "GITLINT_TARGET": target_repo,
"GITLINT_COMMITS": self.get_last_commit_hash(git_repo=target_repo)})
output = gitlint(_env=env, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[5])
expected_kwargs = self.get_debug_vars_last_commit(git_repo=target_repo)
diff --git a/qa/test_contrib.py b/qa/test_contrib.py
index e599d50..d71229a 100644
--- a/qa/test_contrib.py
+++ b/qa/test_contrib.py
@@ -10,14 +10,14 @@ class ContribRuleTests(BaseTestCase):
def test_contrib_rules(self):
self.create_simple_commit("WIP Thi$ is å title\n\nMy bödy that is a bit longer than 20 chars")
output = gitlint("--contrib", "contrib-title-conventional-commits,CC1",
- _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[4])
+ _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[3])
self.assertEqualStdout(output, self.get_expected("test_contrib/test_contrib_rules_1"))
def test_contrib_rules_with_config(self):
self.create_simple_commit("WIP Thi$ is å title\n\nMy bödy that is a bit longer than 20 chars")
output = gitlint("--contrib", "contrib-title-conventional-commits,CC1",
"-c", "contrib-title-conventional-commits.types=föo,bår",
- _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[4])
+ _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[3])
self.assertEqualStdout(output, self.get_expected("test_contrib/test_contrib_rules_with_config_1"))
def test_invalid_contrib_rules(self):
diff --git a/qa/test_hooks.py b/qa/test_hooks.py
index 32abcb0..b78100e 100644
--- a/qa/test_hooks.py
+++ b/qa/test_hooks.py
@@ -9,14 +9,15 @@ class HookTests(BaseTestCase):
""" Integration tests for gitlint commitmsg hooks"""
VIOLATIONS = ['gitlint: checking commit message...\n',
- u'1: T3 Title has trailing punctuation (.): "WIP: This ïs a title."\n',
- u'1: T5 Title contains the word \'WIP\' (case-insensitive): "WIP: This ïs a title."\n',
- u'2: B4 Second line is not empty: "Contënt on the second line"\n',
+ '1: T3 Title has trailing punctuation (.): "WIP: This ïs a title."\n',
+ '1: T5 Title contains the word \'WIP\' (case-insensitive): "WIP: This ïs a title."\n',
+ '2: B4 Second line is not empty: "Contënt on the second line"\n',
'3: B6 Body message is missing\n',
'-----------------------------------------------\n',
'gitlint: \x1b[31mYour commit message contains violations.\x1b[0m\n']
def setUp(self):
+ super().setUp()
self.responses = []
self.response_index = 0
self.githook_output = []
@@ -28,16 +29,19 @@ class HookTests(BaseTestCase):
# install git commit-msg hook and assert output
output_installed = gitlint("install-hook", _cwd=self.tmp_git_repo)
- expected_installed = "Successfully installed gitlint commit-msg hook in %s/.git/hooks/commit-msg\n" % \
- self.tmp_git_repo
+ expected_installed = ("Successfully installed gitlint commit-msg hook in "
+ f"{self.tmp_git_repo}/.git/hooks/commit-msg\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 = "Successfully uninstalled gitlint commit-msg hook from %s/.git/hooks/commit-msg\n" % \
- self.tmp_git_repo
+ expected_uninstalled = ("Successfully uninstalled gitlint commit-msg hook from "
+ f"{self.tmp_git_repo}/.git/hooks/commit-msg\n")
+
self.assertEqualStdout(output_uninstalled, expected_uninstalled)
+ super().tearDown()
def _violations(self):
# Make a copy of the violations array so that we don't inadvertently edit it in the test (like I did :D)
@@ -60,9 +64,9 @@ class HookTests(BaseTestCase):
short_hash = self.get_last_commit_short_hash()
expected_output = ["gitlint: checking commit message...\n",
"gitlint: \x1b[32mOK\x1b[0m (no violations in commit message)\n",
- "[master %s] This ïs a title\n" % short_hash,
+ f"[master {short_hash}] This ïs a title\n",
" 1 file changed, 0 insertions(+), 0 deletions(-)\n",
- " create mode 100644 %s\n" % test_filename]
+ f" create mode 100644 {test_filename}\n"]
self.assertListEqual(expected_output, self.githook_output)
def test_commit_hook_continue(self):
@@ -76,10 +80,9 @@ class HookTests(BaseTestCase):
expected_output = self._violations()
expected_output += ["Continue with commit anyways (this keeps the current commit message)? " +
"[y(es)/n(no)/e(dit)] " +
- "[master %s] WIP: This ïs a title. Contënt on the second line\n"
- % short_hash,
+ f"[master {short_hash}] WIP: This ïs a title. Contënt on the second line\n",
" 1 file changed, 0 insertions(+), 0 deletions(-)\n",
- " create mode 100644 %s\n" % test_filename]
+ f" create mode 100644 {test_filename}\n"]
assert len(self.githook_output) == len(expected_output)
for output, expected in zip(self.githook_output, expected_output):
@@ -124,9 +127,9 @@ class HookTests(BaseTestCase):
expected_output += self._violations()[1:]
expected_output += ['Continue with commit anyways (this keeps the current commit message)? ' +
"[y(es)/n(no)/e(dit)] " +
- "[master %s] WIP: This ïs a title. Contënt on the second line\n" % short_hash,
+ f"[master {short_hash}] WIP: This ïs a title. Contënt on the second line\n",
" 1 file changed, 0 insertions(+), 0 deletions(-)\n",
- " create mode 100644 %s\n" % test_filename]
+ f" create mode 100644 {test_filename}\n"]
assert len(self.githook_output) == len(expected_output)
for output, expected in zip(self.githook_output, expected_output):
diff --git a/qa/test_stdin.py b/qa/test_stdin.py
index 18d6e7e..c98580e 100644
--- a/qa/test_stdin.py
+++ b/qa/test_stdin.py
@@ -50,7 +50,7 @@ class StdInTests(BaseTestCase):
# 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.
- p = subprocess.Popen("gitlint", stdin=file_handle, cwd=self.tmp_git_repo,
- stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
- output, _ = p.communicate()
- self.assertEqual(output.decode(DEFAULT_ENCODING), self.get_expected("test_stdin/test_stdin_file_1"))
+ with subprocess.Popen("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"))