Adding upstream version 0.18.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
9e88905bdf
commit
fe56d9f685
118 changed files with 4146 additions and 2087 deletions
97
qa/base.py
97
qa/base.py
|
@ -1,8 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=bad-option-value,unidiomatic-typecheck,undefined-variable,no-else-return,
|
||||
# pylint: disable=too-many-function-args,unexpected-keyword-arg
|
||||
|
||||
import io
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
|
@ -20,8 +18,8 @@ from qa.utils import DEFAULT_ENCODING
|
|||
|
||||
|
||||
class BaseTestCase(TestCase):
|
||||
""" Base class of which all gitlint integration test classes are derived.
|
||||
Provides a number of convenience methods. """
|
||||
"""Base class of which all gitlint integration test classes are derived.
|
||||
Provides a number of convenience methods."""
|
||||
|
||||
# In case of assert failures, print the full error message
|
||||
maxDiff = None
|
||||
|
@ -32,7 +30,7 @@ class BaseTestCase(TestCase):
|
|||
GITLINT_USAGE_ERROR = 253
|
||||
|
||||
def setUp(self):
|
||||
""" Sets up the integration tests by creating a new temporary git repository """
|
||||
"""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()
|
||||
|
@ -47,7 +45,7 @@ class BaseTestCase(TestCase):
|
|||
def assertEqualStdout(self, output, expected): # pylint: disable=invalid-name
|
||||
self.assertIsInstance(output, RunningCommand)
|
||||
output = output.stdout.decode(DEFAULT_ENCODING)
|
||||
output = output.replace('\r', '')
|
||||
output = output.replace("\r", "")
|
||||
self.assertMultiLineEqual(output, expected)
|
||||
|
||||
@staticmethod
|
||||
|
@ -56,11 +54,11 @@ class BaseTestCase(TestCase):
|
|||
return os.path.realpath(f"/tmp/gitlint-test-{timestamp}")
|
||||
|
||||
def create_tmp_git_repo(self):
|
||||
""" Creates a temporary git repository and returns its directory path """
|
||||
"""Creates a temporary git repository and returns its directory path"""
|
||||
tmp_git_repo = self.generate_temp_path()
|
||||
self.tmp_git_repos.append(tmp_git_repo)
|
||||
|
||||
git("init", tmp_git_repo)
|
||||
git("init", "--initial-branch", "main", tmp_git_repo)
|
||||
# configuring name and email is required in every git repot
|
||||
git("config", "user.name", "gitlint-test-user", _cwd=tmp_git_repo)
|
||||
git("config", "user.email", "gitlint@test.com", _cwd=tmp_git_repo)
|
||||
|
@ -77,29 +75,43 @@ class BaseTestCase(TestCase):
|
|||
return tmp_git_repo
|
||||
|
||||
@staticmethod
|
||||
def create_file(parent_dir):
|
||||
""" Creates a file inside a passed directory. Returns filename."""
|
||||
def create_file(parent_dir, content=None):
|
||||
"""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()
|
||||
full_path = os.path.join(parent_dir, test_filename)
|
||||
|
||||
if content:
|
||||
if isinstance(content, bytes):
|
||||
open_kwargs = {"mode": "wb"}
|
||||
else:
|
||||
open_kwargs = {"mode": "w", "encoding": DEFAULT_ENCODING}
|
||||
|
||||
with open(full_path, **open_kwargs) as f: # pylint: disable=unspecified-encoding
|
||||
f.write(content)
|
||||
else:
|
||||
# pylint: disable=consider-using-with
|
||||
open(full_path, "a", encoding=DEFAULT_ENCODING).close()
|
||||
|
||||
return test_filename
|
||||
|
||||
@staticmethod
|
||||
def create_environment(envvars=None):
|
||||
""" Creates a copy of the current os.environ and adds/overwrites a given set of variables to it """
|
||||
"""Creates a copy of the current os.environ and adds/overwrites a given set of variables to it"""
|
||||
environment = os.environ.copy()
|
||||
if envvars:
|
||||
environment.update(envvars)
|
||||
return environment
|
||||
|
||||
def create_tmp_git_config(self, contents):
|
||||
""" Creates an environment with the GIT_CONFIG variable set to a file with the given contents. """
|
||||
"""Creates an environment with the GIT_CONFIG variable set to a file with the given contents."""
|
||||
tmp_config = self.create_tmpfile(contents)
|
||||
return self.create_environment({"GIT_CONFIG": tmp_config})
|
||||
|
||||
def create_simple_commit(self, message, out=None, ok_code=None, env=None, git_repo=None, tty_in=False):
|
||||
""" Creates a simple commit with an empty test file.
|
||||
:param message: Commit message for the commit. """
|
||||
def create_simple_commit(
|
||||
self, message, *, file_contents=None, out=None, ok_code=None, env=None, git_repo=None, tty_in=False
|
||||
):
|
||||
"""Creates a simple commit with an empty test file.
|
||||
:param message: Commit message for the commit."""
|
||||
|
||||
git_repo = self.tmp_git_repo if git_repo is None else git_repo
|
||||
|
||||
|
@ -110,23 +122,39 @@ class BaseTestCase(TestCase):
|
|||
environment = self.create_environment(env)
|
||||
|
||||
# Create file and add to git
|
||||
test_filename = self.create_file(git_repo)
|
||||
test_filename = self.create_file(git_repo, file_contents)
|
||||
git("add", test_filename, _cwd=git_repo)
|
||||
# https://amoffat.github.io/sh/#interactive-callbacks
|
||||
if not ok_code:
|
||||
ok_code = [0]
|
||||
|
||||
git("commit", "-m", message, _cwd=git_repo, _err_to_out=True, _out=out, _tty_in=tty_in,
|
||||
_ok_code=ok_code, _env=environment)
|
||||
git(
|
||||
"commit",
|
||||
"-m",
|
||||
message,
|
||||
_cwd=git_repo,
|
||||
_err_to_out=True,
|
||||
_out=out,
|
||||
_tty_in=tty_in,
|
||||
_ok_code=ok_code,
|
||||
_env=environment,
|
||||
)
|
||||
return test_filename
|
||||
|
||||
def create_tmpfile(self, content):
|
||||
""" Utility method to create temp files. These are cleaned at the end of the test """
|
||||
# Not using a context manager to avoid unneccessary identation in test code
|
||||
"""Utility method to create temp files. These are cleaned at the end of the test"""
|
||||
# Not using a context manager to avoid unnecessary indentation in test code
|
||||
tmpfile, tmpfilepath = tempfile.mkstemp()
|
||||
self.tmpfiles.append(tmpfilepath)
|
||||
with io.open(tmpfile, "w", encoding=DEFAULT_ENCODING) as f:
|
||||
|
||||
if isinstance(content, bytes):
|
||||
open_kwargs = {"mode": "wb"}
|
||||
else:
|
||||
open_kwargs = {"mode": "w", "encoding": DEFAULT_ENCODING}
|
||||
|
||||
with open(tmpfile, **open_kwargs) as f: # pylint: disable=unspecified-encoding
|
||||
f.write(content)
|
||||
|
||||
return tmpfilepath
|
||||
|
||||
@staticmethod
|
||||
|
@ -149,11 +177,11 @@ class BaseTestCase(TestCase):
|
|||
|
||||
@staticmethod
|
||||
def get_expected(filename="", variable_dict=None):
|
||||
""" Utility method to read an 'expected' file and return it as a string. Optionally replace template variables
|
||||
specified by variable_dict. """
|
||||
"""Utility method to read an 'expected' file and return it as a string. Optionally replace template variables
|
||||
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 io.open(expected_path, encoding=DEFAULT_ENCODING) as file:
|
||||
with open(expected_path, encoding=DEFAULT_ENCODING) as file:
|
||||
expected = file.read()
|
||||
|
||||
if variable_dict:
|
||||
|
@ -162,20 +190,25 @@ class BaseTestCase(TestCase):
|
|||
|
||||
@staticmethod
|
||||
def get_system_info_dict():
|
||||
""" Returns a dict with items related to system values logged by `gitlint --debug` """
|
||||
"""Returns a dict with items related to system values logged by `gitlint --debug`"""
|
||||
expected_gitlint_version = gitlint("--version").replace("gitlint, version ", "").strip()
|
||||
expected_git_version = git("--version").strip()
|
||||
return {'platform': platform.platform(), 'python_version': sys.version,
|
||||
'git_version': expected_git_version, 'gitlint_version': expected_gitlint_version,
|
||||
'GITLINT_USE_SH_LIB': BaseTestCase.GITLINT_USE_SH_LIB, 'DEFAULT_ENCODING': DEFAULT_ENCODING}
|
||||
return {
|
||||
"platform": platform.platform(),
|
||||
"python_version": sys.version,
|
||||
"git_version": expected_git_version,
|
||||
"gitlint_version": expected_gitlint_version,
|
||||
"GITLINT_USE_SH_LIB": BaseTestCase.GITLINT_USE_SH_LIB,
|
||||
"DEFAULT_ENCODING": DEFAULT_ENCODING,
|
||||
}
|
||||
|
||||
def get_debug_vars_last_commit(self, git_repo=None):
|
||||
""" Returns a dict with items related to `gitlint --debug` output for the last commit. """
|
||||
"""Returns a dict with items related to `gitlint --debug` output for the last commit."""
|
||||
target_repo = git_repo if git_repo else self.tmp_git_repo
|
||||
commit_sha = self.get_last_commit_hash(git_repo=target_repo)
|
||||
expected_date = git("log", "-1", "--pretty=%ai", _tty_out=False, _cwd=target_repo)
|
||||
expected_date = arrow.get(str(expected_date), "YYYY-MM-DD HH:mm:ss Z").format("YYYY-MM-DD HH:mm:ss Z")
|
||||
|
||||
expected_kwargs = self.get_system_info_dict()
|
||||
expected_kwargs.update({'target': target_repo, 'commit_sha': commit_sha, 'commit_date': expected_date})
|
||||
expected_kwargs.update({"target": target_repo, "commit_sha": commit_sha, "commit_date": expected_date})
|
||||
return expected_kwargs
|
||||
|
|
11
qa/expected/test_commits/test_csv_hash_list_1
Normal file
11
qa/expected/test_commits/test_csv_hash_list_1
Normal file
|
@ -0,0 +1,11 @@
|
|||
Commit {commit_sha2}:
|
||||
1: T3 Title has trailing punctuation (.): "Sïmple title2."
|
||||
3: B6 Body message is missing
|
||||
|
||||
Commit {commit_sha1}:
|
||||
1: T3 Title has trailing punctuation (.): "Sïmple title1."
|
||||
3: B6 Body message is missing
|
||||
|
||||
Commit {commit_sha4}:
|
||||
1: T3 Title has trailing punctuation (.): "Sïmple title4."
|
||||
3: B6 Body message is missing
|
|
@ -1,3 +1,5 @@
|
|||
WARNING: I1 - ignore-by-title: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-by-title.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
|
||||
WARNING: I2 - ignore-by-body: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-by-body.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
|
||||
Commit {commit_sha0}:
|
||||
1: T3 Title has trailing punctuation (.): "Sïmple title4."
|
||||
|
||||
|
|
|
@ -14,11 +14,13 @@ contrib: []
|
|||
ignore:
|
||||
ignore-merge-commits: True
|
||||
ignore-fixup-commits: True
|
||||
ignore-fixup-amend-commits: True
|
||||
ignore-squash-commits: True
|
||||
ignore-revert-commits: True
|
||||
ignore-stdin: False
|
||||
staged: True
|
||||
fail-without-commits: False
|
||||
regex-style-search: False
|
||||
verbosity: 3
|
||||
debug: True
|
||||
target: {target}
|
||||
|
@ -60,17 +62,17 @@ target: {target}
|
|||
B8: body-match-regex
|
||||
regex=None
|
||||
M1: author-valid-email
|
||||
regex=[^@ ]+@[^@ ]+\.[^@ ]+
|
||||
regex=^[^@ ]+@[^@ ]+\.[^@ ]+
|
||||
|
||||
DEBUG: gitlint.cli Fetching additional meta-data from staged commit
|
||||
DEBUG: gitlint.cli Using --msg-filename.
|
||||
DEBUG: gitlint.git ('config', '--get', 'core.commentchar')
|
||||
DEBUG: gitlint.cli Linting 1 commit(s)
|
||||
DEBUG: gitlint.lint Linting commit [SHA UNKNOWN]
|
||||
DEBUG: gitlint.git ('diff', '--staged', '--numstat', '-r')
|
||||
DEBUG: gitlint.git ('config', '--get', 'user.name')
|
||||
DEBUG: gitlint.git ('config', '--get', 'user.email')
|
||||
DEBUG: gitlint.git ('rev-parse', '--abbrev-ref', 'HEAD')
|
||||
DEBUG: gitlint.git ('diff', '--staged', '--name-only', '-r')
|
||||
DEBUG: gitlint.lint Commit Object
|
||||
--- Commit Message ----
|
||||
WIP: from fïle test.
|
||||
|
@ -79,10 +81,14 @@ Author: gitlint-test-user <gitlint@test.com>
|
|||
Date: {staged_date}
|
||||
is-merge-commit: False
|
||||
is-fixup-commit: False
|
||||
is-fixup-amend-commit: False
|
||||
is-squash-commit: False
|
||||
is-revert-commit: False
|
||||
Branches: ['master']
|
||||
Parents: []
|
||||
Branches: ['main']
|
||||
Changed Files: {changed_files}
|
||||
Changed Files Stats:
|
||||
{changed_files_stats}
|
||||
-----------------------
|
||||
1: T3 Title has trailing punctuation (.): "WIP: from fïle test."
|
||||
1: T5 Title contains the word 'WIP' (case-insensitive): "WIP: from fïle test."
|
||||
|
|
|
@ -14,11 +14,13 @@ contrib: []
|
|||
ignore:
|
||||
ignore-merge-commits: True
|
||||
ignore-fixup-commits: True
|
||||
ignore-fixup-amend-commits: True
|
||||
ignore-squash-commits: True
|
||||
ignore-revert-commits: True
|
||||
ignore-stdin: False
|
||||
staged: True
|
||||
fail-without-commits: False
|
||||
regex-style-search: False
|
||||
verbosity: 3
|
||||
debug: True
|
||||
target: {target}
|
||||
|
@ -60,7 +62,7 @@ target: {target}
|
|||
B8: body-match-regex
|
||||
regex=None
|
||||
M1: author-valid-email
|
||||
regex=[^@ ]+@[^@ ]+\.[^@ ]+
|
||||
regex=^[^@ ]+@[^@ ]+\.[^@ ]+
|
||||
|
||||
DEBUG: gitlint.cli Fetching additional meta-data from staged commit
|
||||
DEBUG: gitlint.cli Stdin data: 'WIP: Pïpe test.
|
||||
|
@ -69,10 +71,10 @@ DEBUG: gitlint.cli Stdin detected and not ignored. Using as input.
|
|||
DEBUG: gitlint.git ('config', '--get', 'core.commentchar')
|
||||
DEBUG: gitlint.cli Linting 1 commit(s)
|
||||
DEBUG: gitlint.lint Linting commit [SHA UNKNOWN]
|
||||
DEBUG: gitlint.git ('diff', '--staged', '--numstat', '-r')
|
||||
DEBUG: gitlint.git ('config', '--get', 'user.name')
|
||||
DEBUG: gitlint.git ('config', '--get', 'user.email')
|
||||
DEBUG: gitlint.git ('rev-parse', '--abbrev-ref', 'HEAD')
|
||||
DEBUG: gitlint.git ('diff', '--staged', '--name-only', '-r')
|
||||
DEBUG: gitlint.lint Commit Object
|
||||
--- Commit Message ----
|
||||
WIP: Pïpe test.
|
||||
|
@ -81,10 +83,14 @@ Author: gitlint-test-user <gitlint@test.com>
|
|||
Date: {staged_date}
|
||||
is-merge-commit: False
|
||||
is-fixup-commit: False
|
||||
is-fixup-amend-commit: False
|
||||
is-squash-commit: False
|
||||
is-revert-commit: False
|
||||
Branches: ['master']
|
||||
Parents: []
|
||||
Branches: ['main']
|
||||
Changed Files: {changed_files}
|
||||
Changed Files Stats:
|
||||
{changed_files_stats}
|
||||
-----------------------
|
||||
1: T3 Title has trailing punctuation (.): "WIP: Pïpe test."
|
||||
1: T5 Title contains the word 'WIP' (case-insensitive): "WIP: Pïpe test."
|
||||
|
|
|
@ -14,11 +14,13 @@ contrib: ['CC1', 'CT1']
|
|||
ignore: T1,T2
|
||||
ignore-merge-commits: True
|
||||
ignore-fixup-commits: True
|
||||
ignore-fixup-amend-commits: True
|
||||
ignore-squash-commits: True
|
||||
ignore-revert-commits: True
|
||||
ignore-stdin: True
|
||||
staged: False
|
||||
fail-without-commits: True
|
||||
regex-style-search: False
|
||||
verbosity: 2
|
||||
debug: True
|
||||
target: {target}
|
||||
|
@ -60,7 +62,7 @@ target: {target}
|
|||
B8: body-match-regex
|
||||
regex=None
|
||||
M1: author-valid-email
|
||||
regex=[^@ ]+@[^@ ]+\.[^@ ]+
|
||||
regex=^[^@ ]+@[^@ ]+\.[^@ ]+
|
||||
CC1: contrib-body-requires-signed-off-by
|
||||
CT1: contrib-title-conventional-commits
|
||||
types=fix,feat,chore,docs,style,refactor,perf,test,revert,ci,build
|
||||
|
@ -71,8 +73,8 @@ DEBUG: gitlint.cli Linting 1 commit(s)
|
|||
DEBUG: gitlint.git ('log', '{commit_sha}', '-1', '--pretty=%aN%x00%aE%x00%ai%x00%P%n%B')
|
||||
DEBUG: gitlint.git ('config', '--get', 'core.commentchar')
|
||||
DEBUG: gitlint.lint Linting commit {commit_sha}
|
||||
DEBUG: gitlint.git ('diff-tree', '--no-commit-id', '--numstat', '-r', '--root', '{commit_sha}')
|
||||
DEBUG: gitlint.git ('branch', '--contains', '{commit_sha}')
|
||||
DEBUG: gitlint.git ('diff-tree', '--no-commit-id', '--name-only', '-r', '--root', '{commit_sha}')
|
||||
DEBUG: gitlint.lint Commit Object
|
||||
--- Commit Message ----
|
||||
WIP: Thïs is a title thåt is a bit longer.
|
||||
|
@ -84,10 +86,14 @@ Author: gitlint-test-user <gitlint@test.com>
|
|||
Date: {commit_date}
|
||||
is-merge-commit: False
|
||||
is-fixup-commit: False
|
||||
is-fixup-amend-commit: False
|
||||
is-squash-commit: False
|
||||
is-revert-commit: False
|
||||
Branches: ['master']
|
||||
Parents: []
|
||||
Branches: ['main']
|
||||
Changed Files: {changed_files}
|
||||
Changed Files Stats:
|
||||
{changed_files_stats}
|
||||
-----------------------
|
||||
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
|
||||
|
|
|
@ -14,11 +14,13 @@ contrib: []
|
|||
ignore:
|
||||
ignore-merge-commits: True
|
||||
ignore-fixup-commits: True
|
||||
ignore-fixup-amend-commits: True
|
||||
ignore-squash-commits: True
|
||||
ignore-revert-commits: True
|
||||
ignore-stdin: False
|
||||
staged: True
|
||||
fail-without-commits: False
|
||||
regex-style-search: False
|
||||
verbosity: 0
|
||||
debug: True
|
||||
target: {target}
|
||||
|
@ -60,17 +62,17 @@ target: {target}
|
|||
B8: body-match-regex
|
||||
regex=None
|
||||
M1: author-valid-email
|
||||
regex=[^@ ]+@[^@ ]+\.[^@ ]+
|
||||
regex=^[^@ ]+@[^@ ]+\.[^@ ]+
|
||||
|
||||
DEBUG: gitlint.cli Fetching additional meta-data from staged commit
|
||||
DEBUG: gitlint.cli Using --msg-filename.
|
||||
DEBUG: gitlint.git ('config', '--get', 'core.commentchar')
|
||||
DEBUG: gitlint.cli Linting 1 commit(s)
|
||||
DEBUG: gitlint.lint Linting commit [SHA UNKNOWN]
|
||||
DEBUG: gitlint.git ('diff', '--staged', '--numstat', '-r')
|
||||
DEBUG: gitlint.git ('config', '--get', 'user.name')
|
||||
DEBUG: gitlint.git ('config', '--get', 'user.email')
|
||||
DEBUG: gitlint.git ('rev-parse', '--abbrev-ref', 'HEAD')
|
||||
DEBUG: gitlint.git ('diff', '--staged', '--name-only', '-r')
|
||||
DEBUG: gitlint.lint Commit Object
|
||||
--- Commit Message ----
|
||||
WIP: msg-fïlename test.
|
||||
|
@ -79,9 +81,12 @@ Author: gitlint-test-user <gitlint@test.com>
|
|||
Date: {date}
|
||||
is-merge-commit: False
|
||||
is-fixup-commit: False
|
||||
is-fixup-amend-commit: False
|
||||
is-squash-commit: False
|
||||
is-revert-commit: False
|
||||
Branches: ['master']
|
||||
Parents: []
|
||||
Branches: ['main']
|
||||
Changed Files: []
|
||||
Changed Files Stats: {{}}
|
||||
-----------------------
|
||||
DEBUG: gitlint.cli Exit Code = 3
|
||||
|
|
|
@ -14,11 +14,13 @@ contrib: []
|
|||
ignore: title-trailing-punctuation,B2
|
||||
ignore-merge-commits: True
|
||||
ignore-fixup-commits: True
|
||||
ignore-fixup-amend-commits: True
|
||||
ignore-squash-commits: True
|
||||
ignore-revert-commits: True
|
||||
ignore-stdin: False
|
||||
staged: False
|
||||
fail-without-commits: False
|
||||
regex-style-search: False
|
||||
verbosity: 2
|
||||
debug: True
|
||||
target: {target}
|
||||
|
@ -60,7 +62,7 @@ target: {target}
|
|||
B8: body-match-regex
|
||||
regex=None
|
||||
M1: author-valid-email
|
||||
regex=[^@ ]+@[^@ ]+\.[^@ ]+
|
||||
regex=^[^@ ]+@[^@ ]+\.[^@ ]+
|
||||
|
||||
DEBUG: gitlint.cli No --msg-filename flag, no or empty data passed to stdin. Using the local repo.
|
||||
DEBUG: gitlint.git ('log', '-1', '--pretty=%H')
|
||||
|
@ -68,8 +70,8 @@ DEBUG: gitlint.cli Linting 1 commit(s)
|
|||
DEBUG: gitlint.git ('log', '{commit_sha}', '-1', '--pretty=%aN%x00%aE%x00%ai%x00%P%n%B')
|
||||
DEBUG: gitlint.git ('config', '--get', 'core.commentchar')
|
||||
DEBUG: gitlint.lint Linting commit {commit_sha}
|
||||
DEBUG: gitlint.git ('diff-tree', '--no-commit-id', '--numstat', '-r', '--root', '{commit_sha}')
|
||||
DEBUG: gitlint.git ('branch', '--contains', '{commit_sha}')
|
||||
DEBUG: gitlint.git ('diff-tree', '--no-commit-id', '--name-only', '-r', '--root', '{commit_sha}')
|
||||
DEBUG: gitlint.lint Commit Object
|
||||
--- Commit Message ----
|
||||
WIP: Thïs is a title thåt is a bit longer.
|
||||
|
@ -81,10 +83,14 @@ Author: gitlint-test-user <gitlint@test.com>
|
|||
Date: {commit_date}
|
||||
is-merge-commit: False
|
||||
is-fixup-commit: False
|
||||
is-fixup-amend-commit: False
|
||||
is-squash-commit: False
|
||||
is-revert-commit: False
|
||||
Branches: ['master']
|
||||
Parents: []
|
||||
Branches: ['main']
|
||||
Changed Files: {changed_files}
|
||||
Changed Files Stats:
|
||||
{changed_files_stats}
|
||||
-----------------------
|
||||
1: T1 Title exceeds max length (42>20)
|
||||
1: T5 Title contains the word 'WIP' (case-insensitive)
|
||||
|
|
94
qa/expected/test_gitlint/test_commit_binary_file_1
Normal file
94
qa/expected/test_gitlint/test_commit_binary_file_1
Normal file
|
@ -0,0 +1,94 @@
|
|||
DEBUG: gitlint.cli To report issues, please visit https://github.com/jorisroovers/gitlint/issues
|
||||
DEBUG: gitlint.cli Platform: {platform}
|
||||
DEBUG: gitlint.cli Python version: {python_version}
|
||||
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 Configuration
|
||||
config-path: None
|
||||
[GENERAL]
|
||||
extra-path: None
|
||||
contrib: []
|
||||
ignore:
|
||||
ignore-merge-commits: True
|
||||
ignore-fixup-commits: True
|
||||
ignore-fixup-amend-commits: True
|
||||
ignore-squash-commits: True
|
||||
ignore-revert-commits: True
|
||||
ignore-stdin: False
|
||||
staged: False
|
||||
fail-without-commits: False
|
||||
regex-style-search: False
|
||||
verbosity: 3
|
||||
debug: True
|
||||
target: {target}
|
||||
[RULES]
|
||||
I1: ignore-by-title
|
||||
ignore=all
|
||||
regex=None
|
||||
I2: ignore-by-body
|
||||
ignore=all
|
||||
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
|
||||
T6: title-leading-whitespace
|
||||
T3: title-trailing-punctuation
|
||||
T4: title-hard-tab
|
||||
T5: title-must-not-contain-word
|
||||
words=WIP
|
||||
T7: title-match-regex
|
||||
regex=None
|
||||
T8: title-min-length
|
||||
min-length=5
|
||||
B1: body-max-line-length
|
||||
line-length=80
|
||||
B5: body-min-length
|
||||
min-length=20
|
||||
B6: body-is-missing
|
||||
ignore-merge-commits=True
|
||||
B2: body-trailing-whitespace
|
||||
B3: body-hard-tab
|
||||
B4: body-first-line-empty
|
||||
B7: body-changed-file-mention
|
||||
files=
|
||||
B8: body-match-regex
|
||||
regex=None
|
||||
M1: author-valid-email
|
||||
regex=^[^@ ]+@[^@ ]+\.[^@ ]+
|
||||
|
||||
DEBUG: gitlint.cli No --msg-filename flag, no or empty data passed to stdin. Using the local repo.
|
||||
DEBUG: gitlint.git ('log', '-1', '--pretty=%H')
|
||||
DEBUG: gitlint.cli Linting 1 commit(s)
|
||||
DEBUG: gitlint.git ('log', '{commit_sha}', '-1', '--pretty=%aN%x00%aE%x00%ai%x00%P%n%B')
|
||||
DEBUG: gitlint.git ('config', '--get', 'core.commentchar')
|
||||
DEBUG: gitlint.lint Linting commit {commit_sha}
|
||||
DEBUG: gitlint.git ('diff-tree', '--no-commit-id', '--numstat', '-r', '--root', '{commit_sha}')
|
||||
DEBUG: gitlint.git ('branch', '--contains', '{commit_sha}')
|
||||
DEBUG: gitlint.lint Commit Object
|
||||
--- Commit Message ----
|
||||
Sïmple commit
|
||||
|
||||
--- Meta info ---------
|
||||
Author: gitlint-test-user <gitlint@test.com>
|
||||
Date: {commit_date}
|
||||
is-merge-commit: False
|
||||
is-fixup-commit: False
|
||||
is-fixup-amend-commit: False
|
||||
is-squash-commit: False
|
||||
is-revert-commit: False
|
||||
Parents: []
|
||||
Branches: ['main']
|
||||
Changed Files: {changed_files}
|
||||
Changed Files Stats:
|
||||
{changed_files_stats}
|
||||
-----------------------
|
||||
3: B6 Body message is missing
|
||||
DEBUG: gitlint.cli Exit Code = 1
|
|
@ -1,5 +1,5 @@
|
|||
1: T5 Title contains the word 'WIP' (case-insensitive): "WIP: Thi$ is å title"
|
||||
1: UC2 Body does not contain a 'Signed-off-by' line
|
||||
1: UC3 Branch name 'master' does not start with one of ['feature/', 'hotfix/', 'release/']
|
||||
1: UC3 Branch name 'main' does not start with one of ['feature/', 'hotfix/', 'release/']
|
||||
1: UL1 Title contains the special character '$': "WIP: Thi$ is å title"
|
||||
2: B4 Second line is not empty: "Content on the second line"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
1: UC2 Body does not contain a 'Signed-off-by' line
|
||||
1: UC3 Branch name 'master' does not start with one of ['feature/', 'hotfix/', 'release/']
|
||||
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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
1: T5 Title contains the word 'WIP' (case-insensitive): "WIP: Thi$ is å title"
|
||||
1: UC1 Body contains too many lines (2 > 1)
|
||||
1: UC2 Body does not contain a 'Signed-off-by' line
|
||||
1: UC3 Branch name 'master' does not start with one of ['feature/', 'hotfix/', 'release/']
|
||||
1: UC3 Branch name 'main' does not start with one of ['feature/', 'hotfix/', 'release/']
|
||||
1: UL1 Title contains the special character '$': "WIP: Thi$ is å title"
|
||||
2: B4 Second line is not empty: "Content on the second line"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
1: T5 Title contains the word 'WIP' (case-insensitive): "WIP: Thi$ is å title"
|
||||
1: UC1 GitContext.current_branch: master
|
||||
1: UC1 GitContext.current_branch: main
|
||||
1: UC1 GitContext.commentchar: #
|
||||
1: UC2 GitCommit.branches: ['master']
|
||||
1: UC2 GitCommit.branches: ['main']
|
||||
1: UC2 GitCommit.custom_prop: foöbar
|
||||
1: UC4 int-öption: 2
|
||||
1: UC4 str-öption: föo
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
sh==1.14.2
|
||||
pytest==6.2.5;
|
||||
arrow==1.2.1;
|
||||
sh==1.14.3
|
||||
pytest==7.0.1;
|
||||
arrow==1.2.3;
|
||||
gitlint # no version as you want to test the currently installed version
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from gitlint.rules import CommitRule, RuleViolation, ConfigurationRule
|
||||
from gitlint.options import IntOption, StrOption, ListOption
|
||||
|
||||
|
||||
class GitContextRule(CommitRule):
|
||||
""" Rule that tests whether we can correctly access certain gitcontext properties """
|
||||
"""Rule that tests whether we can correctly access certain gitcontext properties"""
|
||||
|
||||
name = "gïtcontext"
|
||||
id = "UC1"
|
||||
|
||||
def validate(self, commit):
|
||||
violations = [
|
||||
RuleViolation(self.id, f"GitContext.current_branch: {commit.context.current_branch}", line_nr=1),
|
||||
RuleViolation(self.id, f"GitContext.commentchar: {commit.context.commentchar}", line_nr=1)
|
||||
RuleViolation(self.id, f"GitContext.commentchar: {commit.context.commentchar}", line_nr=1),
|
||||
]
|
||||
|
||||
return violations
|
||||
|
||||
|
||||
class GitCommitRule(CommitRule):
|
||||
""" Rule that tests whether we can correctly access certain commit properties """
|
||||
"""Rule that tests whether we can correctly access certain commit properties"""
|
||||
|
||||
name = "gïtcommit"
|
||||
id = "UC2"
|
||||
|
||||
|
@ -33,7 +33,8 @@ class GitCommitRule(CommitRule):
|
|||
|
||||
|
||||
class GitlintConfigurationRule(ConfigurationRule):
|
||||
""" Rule that tests whether we can correctly access the config as well as modify the commit message """
|
||||
"""Rule that tests whether we can correctly access the config as well as modify the commit message"""
|
||||
|
||||
name = "cönfigrule"
|
||||
id = "UC3"
|
||||
|
||||
|
@ -50,13 +51,16 @@ class GitlintConfigurationRule(ConfigurationRule):
|
|||
|
||||
|
||||
class ConfigurableCommitRule(CommitRule):
|
||||
""" Rule that tests that we can add configuration to user-defined rules """
|
||||
"""Rule that tests that we can add configuration to user-defined rules"""
|
||||
|
||||
name = "configürable"
|
||||
id = "UC4"
|
||||
|
||||
options_spec = [IntOption("int-öption", 2, "int-öption description"),
|
||||
StrOption("str-öption", "föo", "int-öption description"),
|
||||
ListOption("list-öption", ["foo", "bar"], "list-öption description")]
|
||||
options_spec = [
|
||||
IntOption("int-öption", 2, "int-öption description"),
|
||||
StrOption("str-öption", "föo", "int-öption description"),
|
||||
ListOption("list-öption", ["foo", "bar"], "list-öption description"),
|
||||
]
|
||||
|
||||
def validate(self, _):
|
||||
violations = [
|
||||
|
|
30
qa/shell.py
30
qa/shell.py
|
@ -1,4 +1,3 @@
|
|||
|
||||
# This code is mostly duplicated from the `gitlint.shell` module. We consciously duplicate this code as to not depend
|
||||
# on gitlint internals for our integration testing framework.
|
||||
|
||||
|
@ -7,6 +6,7 @@ from qa.utils import USE_SH_LIB, DEFAULT_ENCODING
|
|||
|
||||
if USE_SH_LIB:
|
||||
from sh import git, echo, gitlint # pylint: disable=unused-import,no-name-in-module,import-error
|
||||
|
||||
gitlint = gitlint.bake(_unify_ttys=True, _tty_in=True) # pylint: disable=invalid-name
|
||||
|
||||
# import exceptions separately, this makes it a little easier to mock them out in the unit tests
|
||||
|
@ -14,17 +14,18 @@ if USE_SH_LIB:
|
|||
else:
|
||||
|
||||
class CommandNotFound(Exception):
|
||||
""" Exception indicating a command was not found during execution """
|
||||
"""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
|
||||
the builtin subprocess module. """
|
||||
"""Result wrapper class. We use this to more easily migrate from using https://amoffat.github.io/sh/ to using
|
||||
the builtin subprocess module."""
|
||||
|
||||
def __init__(self, full_cmd, stdout, stderr='', exitcode=0):
|
||||
def __init__(self, full_cmd, stdout, stderr="", exitcode=0):
|
||||
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.
|
||||
|
@ -36,7 +37,8 @@ else:
|
|||
return self.stdout
|
||||
|
||||
class ErrorReturnCode(ShResult, Exception):
|
||||
""" ShResult subclass for unexpected results (acts as an exception). """
|
||||
"""ShResult subclass for unexpected results (acts as an exception)."""
|
||||
|
||||
pass
|
||||
|
||||
def git(*command_parts, **kwargs):
|
||||
|
@ -54,17 +56,17 @@ else:
|
|||
# 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:
|
||||
if hasattr(result, "exit_code") and result.exit_code > 0:
|
||||
return result
|
||||
return str(result)
|
||||
|
||||
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": 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"]
|
||||
|
||||
try:
|
||||
with subprocess.Popen(args, **popen_kwargs) as p:
|
||||
|
@ -75,10 +77,10 @@ else:
|
|||
exit_code = p.returncode
|
||||
stdout = result[0].decode(DEFAULT_ENCODING)
|
||||
stderr = result[1] # 'sh' does not decode the stderr bytes to unicode
|
||||
full_cmd = '' if args is None else ' '.join(args)
|
||||
full_cmd = "" if args is None else " ".join(args)
|
||||
|
||||
# If not _ok_code is specified, then only a 0 exit code is allowed
|
||||
ok_exit_codes = kwargs.get('_ok_code', [0])
|
||||
ok_exit_codes = kwargs.get("_ok_code", [0])
|
||||
|
||||
if exit_code in ok_exit_codes:
|
||||
return ShResult(full_cmd, stdout, stderr, exit_code)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=too-many-function-args,unexpected-keyword-arg
|
||||
import re
|
||||
|
||||
|
@ -9,22 +8,22 @@ 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
|
||||
"""
|
||||
"""Integration tests for the --commits argument, i.e. linting multiple commits or linting specific commits"""
|
||||
|
||||
def test_successful(self):
|
||||
""" Test linting multiple commits without violations """
|
||||
"""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)
|
||||
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 """
|
||||
"""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)
|
||||
|
@ -33,15 +32,46 @@ class CommitsTests(BaseTestCase):
|
|||
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])
|
||||
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}
|
||||
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_csv_hash_list(self):
|
||||
"""Test linting multiple commits (comma-separated) with violations"""
|
||||
git("checkout", "-b", "test-branch-commits-violations-base", _cwd=self.tmp_git_repo)
|
||||
self.create_simple_commit("Sïmple title1.\n")
|
||||
commit_sha1 = self.get_last_commit_hash()[:10]
|
||||
git("checkout", "-b", "test-branch-commits-violations", _cwd=self.tmp_git_repo)
|
||||
|
||||
self.create_simple_commit("Sïmple title2.\n")
|
||||
commit_sha2 = self.get_last_commit_hash()[:10]
|
||||
self.create_simple_commit("Sïmple title3.\n")
|
||||
self.create_simple_commit("Sïmple title4.\n")
|
||||
commit_sha4 = self.get_last_commit_hash()[:10]
|
||||
|
||||
# Lint subset of the commits in a specific order, passed in via csv list
|
||||
output = gitlint(
|
||||
"--commits",
|
||||
f"{commit_sha2},{commit_sha1},{commit_sha4}",
|
||||
_cwd=self.tmp_git_repo,
|
||||
_tty_in=True,
|
||||
_ok_code=[6],
|
||||
)
|
||||
|
||||
self.assertEqual(output.exit_code, 6)
|
||||
expected_kwargs = {"commit_sha1": commit_sha1, "commit_sha2": commit_sha2, "commit_sha4": commit_sha4}
|
||||
self.assertEqualStdout(output, self.get_expected("test_commits/test_csv_hash_list_1", expected_kwargs))
|
||||
|
||||
def test_lint_empty_commit_range(self):
|
||||
""" Tests `gitlint --commits <sha>^...<sha>` --fail-without-commits where the provided range is empty. """
|
||||
"""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()
|
||||
|
@ -54,13 +84,19 @@ class CommitsTests(BaseTestCase):
|
|||
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])
|
||||
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")
|
||||
self.assertEqualStdout(output, f'Error: No commits in range "{refspec}"\n')
|
||||
|
||||
def test_lint_single_commit(self):
|
||||
""" Tests `gitlint --commits <sha>^...<same 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")
|
||||
|
@ -68,8 +104,7 @@ class CommitsTests(BaseTestCase):
|
|||
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")
|
||||
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])
|
||||
|
@ -83,8 +118,7 @@ class CommitsTests(BaseTestCase):
|
|||
|
||||
# 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")
|
||||
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)
|
||||
|
@ -95,10 +129,10 @@ 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
|
||||
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
|
||||
"""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")
|
||||
|
@ -109,30 +143,45 @@ class CommitsTests(BaseTestCase):
|
|||
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])
|
||||
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])})
|
||||
filenames = sorted([filename1, filename2])
|
||||
expected_kwargs.update(
|
||||
{
|
||||
"changed_files": filenames,
|
||||
"changed_files_stats": (
|
||||
f"{filenames[0]}: 0 additions, 0 deletions\n {filenames[1]}: 0 additions, 0 deletions"
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
# 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)
|
||||
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_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
|
||||
"""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")
|
||||
|
@ -145,28 +194,44 @@ class CommitsTests(BaseTestCase):
|
|||
|
||||
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])
|
||||
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])})
|
||||
filenames = sorted([filename1, filename2])
|
||||
expected_kwargs.update(
|
||||
{
|
||||
"changed_files": filenames,
|
||||
"changed_files_stats": (
|
||||
f"{filenames[0]}: 0 additions, 0 deletions\n {filenames[1]}: 0 additions, 0 deletions"
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
# 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)
|
||||
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_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' """
|
||||
"""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)
|
||||
|
@ -174,13 +239,16 @@ class CommitsTests(BaseTestCase):
|
|||
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]}
|
||||
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 """
|
||||
"""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)
|
||||
|
@ -188,14 +256,17 @@ class CommitsTests(BaseTestCase):
|
|||
# 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 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]}
|
||||
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))
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=too-many-function-args,unexpected-keyword-arg
|
||||
|
||||
import re
|
||||
|
@ -9,19 +8,24 @@ from qa.utils import DEFAULT_ENCODING
|
|||
|
||||
|
||||
class ConfigTests(BaseTestCase):
|
||||
""" Integration tests for gitlint configuration and configuration precedence. """
|
||||
"""Integration tests for gitlint configuration and configuration precedence."""
|
||||
|
||||
def test_ignore_by_id(self):
|
||||
self.create_simple_commit("WIP: Thïs is a title.\nContënt on the second line")
|
||||
output = gitlint("--ignore", "T5,B4", _tty_in=True, _cwd=self.tmp_git_repo, _ok_code=[1])
|
||||
expected = "1: T3 Title has trailing punctuation (.): \"WIP: Thïs is a title.\"\n"
|
||||
expected = '1: T3 Title has trailing punctuation (.): "WIP: Thïs is a title."\n'
|
||||
self.assertEqualStdout(output, expected)
|
||||
|
||||
def test_ignore_by_name(self):
|
||||
self.create_simple_commit("WIP: Thïs is a title.\nContënt on the second line")
|
||||
output = gitlint("--ignore", "title-must-not-contain-word,body-first-line-empty",
|
||||
_cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[1])
|
||||
expected = "1: T3 Title has trailing punctuation (.): \"WIP: Thïs is a title.\"\n"
|
||||
output = gitlint(
|
||||
"--ignore",
|
||||
"title-must-not-contain-word,body-first-line-empty",
|
||||
_cwd=self.tmp_git_repo,
|
||||
_tty_in=True,
|
||||
_ok_code=[1],
|
||||
)
|
||||
expected = '1: T3 Title has trailing punctuation (.): "WIP: Thïs is a title."\n'
|
||||
self.assertEqualStdout(output, expected)
|
||||
|
||||
def test_verbosity(self):
|
||||
|
@ -47,8 +51,10 @@ class ConfigTests(BaseTestCase):
|
|||
self.assertEqualStdout(output, self.get_expected("test_config/test_set_rule_option_1"))
|
||||
|
||||
def test_config_from_file(self):
|
||||
commit_msg = "WIP: Thïs is a title thåt is a bit longer.\nContent on the second line\n" + \
|
||||
"This line of the body is here because we need it"
|
||||
commit_msg = (
|
||||
"WIP: Thïs is a title thåt is a bit longer.\nContent on the second line\n"
|
||||
"This line of the body is here because we need it"
|
||||
)
|
||||
self.create_simple_commit(commit_msg)
|
||||
config_path = self.get_sample_path("config/gitlintconfig")
|
||||
output = gitlint("--config", config_path, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[5])
|
||||
|
@ -58,44 +64,66 @@ class ConfigTests(BaseTestCase):
|
|||
# Test both on existing and new repo (we've had a bug in the past that was unique to empty repos)
|
||||
repos = [self.tmp_git_repo, self.create_tmp_git_repo()]
|
||||
for target_repo in repos:
|
||||
commit_msg = "WIP: Thïs is a title thåt is a bit longer.\nContent on the second line\n" + \
|
||||
"This line of the body is here because we need it"
|
||||
commit_msg = (
|
||||
"WIP: Thïs is a title thåt is a bit longer.\nContent on the second line\n"
|
||||
"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")
|
||||
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)
|
||||
expected_kwargs.update({'config_path': config_path, 'changed_files': [filename]})
|
||||
self.assertEqualStdout(output, self.get_expected("test_config/test_config_from_file_debug_1",
|
||||
expected_kwargs))
|
||||
expected_kwargs.update(
|
||||
{
|
||||
"config_path": config_path,
|
||||
"changed_files": [filename],
|
||||
"changed_files_stats": f"{filename}: 0 additions, 0 deletions",
|
||||
}
|
||||
)
|
||||
self.assertEqualStdout(
|
||||
output, self.get_expected("test_config/test_config_from_file_debug_1", expected_kwargs)
|
||||
)
|
||||
|
||||
def test_config_from_env(self):
|
||||
""" Test for configuring gitlint from environment variables """
|
||||
"""Test for configuring gitlint from environment variables"""
|
||||
|
||||
# We invoke gitlint, configuring it via env variables, we can check whether gitlint picks these up correctly
|
||||
# by comparing the debug output with what we'd expect
|
||||
target_repo = self.create_tmp_git_repo()
|
||||
commit_msg = "WIP: Thïs is a title thåt is a bit longer.\nContent on the second line\n" + \
|
||||
"This line of the body is here because we need it"
|
||||
commit_msg = (
|
||||
"WIP: Thïs is a title thåt is a bit longer.\nContent on the second line\n"
|
||||
"This line of the body is here because we need it"
|
||||
)
|
||||
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_FAIL_WITHOUT_COMMITS": "1", "GITLINT_IGNORE_STDIN": "1",
|
||||
"GITLINT_TARGET": target_repo,
|
||||
"GITLINT_COMMITS": self.get_last_commit_hash(git_repo=target_repo)})
|
||||
env = self.create_environment(
|
||||
{
|
||||
"GITLINT_DEBUG": "1",
|
||||
"GITLINT_VERBOSITY": "2",
|
||||
"GITLINT_IGNORE": "T1,T2",
|
||||
"GITLINT_CONTRIB": "CC1,CT1",
|
||||
"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)
|
||||
expected_kwargs.update({'changed_files': [filename]})
|
||||
expected_kwargs.update(
|
||||
{"changed_files": [filename], "changed_files_stats": f"{filename}: 0 additions, 0 deletions"}
|
||||
)
|
||||
|
||||
self.assertEqualStdout(output, self.get_expected("test_config/test_config_from_env_1", expected_kwargs))
|
||||
|
||||
# For some env variables, we need a separate test ast they are mutually exclusive with the ones tested above
|
||||
tmp_commit_msg_file = self.create_tmpfile("WIP: msg-fïlename test.")
|
||||
env = self.create_environment({"GITLINT_DEBUG": "1", "GITLINT_TARGET": target_repo,
|
||||
"GITLINT_SILENT": "1", "GITLINT_STAGED": "1"})
|
||||
env = self.create_environment(
|
||||
{"GITLINT_DEBUG": "1", "GITLINT_TARGET": target_repo, "GITLINT_SILENT": "1", "GITLINT_STAGED": "1"}
|
||||
)
|
||||
|
||||
output = gitlint("--msg-filename", tmp_commit_msg_file,
|
||||
_env=env, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[3])
|
||||
output = gitlint(
|
||||
"--msg-filename", tmp_commit_msg_file, _env=env, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[3]
|
||||
)
|
||||
|
||||
# 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
|
||||
|
|
|
@ -1,23 +1,29 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=
|
||||
from qa.shell import gitlint
|
||||
from qa.base import BaseTestCase
|
||||
|
||||
|
||||
class ContribRuleTests(BaseTestCase):
|
||||
""" Integration tests for contrib rules."""
|
||||
"""Integration tests for contrib rules."""
|
||||
|
||||
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=[3])
|
||||
output = gitlint(
|
||||
"--contrib", "contrib-title-conventional-commits,CC1", _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=[3])
|
||||
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=[3],
|
||||
)
|
||||
self.assertEqualStdout(output, self.get_expected("test_contrib/test_contrib_rules_with_config_1"))
|
||||
|
||||
def test_invalid_contrib_rules(self):
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=too-many-function-args,unexpected-keyword-arg
|
||||
import io
|
||||
import os
|
||||
from qa.shell import echo, git, gitlint
|
||||
from qa.base import BaseTestCase
|
||||
|
@ -8,7 +6,7 @@ from qa.utils import DEFAULT_ENCODING
|
|||
|
||||
|
||||
class IntegrationTests(BaseTestCase):
|
||||
""" Simple set of integration tests for gitlint """
|
||||
"""Simple set of integration tests for gitlint"""
|
||||
|
||||
def test_successful(self):
|
||||
# Test for STDIN with and without a TTY attached
|
||||
|
@ -17,8 +15,8 @@ class IntegrationTests(BaseTestCase):
|
|||
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. """
|
||||
"""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)
|
||||
|
@ -27,8 +25,8 @@ class IntegrationTests(BaseTestCase):
|
|||
self.assertEqualStdout(output, "")
|
||||
|
||||
def test_successful_merge_commit(self):
|
||||
# Create branch on master
|
||||
self.create_simple_commit("Cömmit on master\n\nSimple bödy")
|
||||
# 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)
|
||||
|
@ -37,10 +35,10 @@ class IntegrationTests(BaseTestCase):
|
|||
self.create_simple_commit(f"{commit_title}\n\nSïmple body")
|
||||
hash = self.get_last_commit_hash()
|
||||
|
||||
# Checkout master and merge the commit
|
||||
# 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", "master", _cwd=self.tmp_git_repo)
|
||||
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
|
||||
|
@ -54,18 +52,14 @@ class IntegrationTests(BaseTestCase):
|
|||
|
||||
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 master\n\nSimple bödy that is long enough")
|
||||
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 master\"\n"
|
||||
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 io.open(os.path.join(self.tmp_git_repo, test_filename), "a", encoding=DEFAULT_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")
|
||||
with open(os.path.join(self.tmp_git_repo, test_filename), "a", encoding=DEFAULT_ENCODING) as fh:
|
||||
fh.write("Appending söme stuff\n")
|
||||
|
||||
git("add", test_filename, _cwd=self.tmp_git_repo)
|
||||
|
||||
|
@ -78,13 +72,44 @@ class IntegrationTests(BaseTestCase):
|
|||
|
||||
# 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 master\"\n" + \
|
||||
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=DEFAULT_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 master.\n\nSimple bödy")
|
||||
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)
|
||||
|
||||
|
@ -93,21 +118,22 @@ class IntegrationTests(BaseTestCase):
|
|||
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])
|
||||
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 master.\"\"\n"
|
||||
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 master\n\nSimple bödy that is long enough")
|
||||
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 master\"\n"
|
||||
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 io.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=DEFAULT_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
|
||||
|
@ -124,10 +150,13 @@ class IntegrationTests(BaseTestCase):
|
|||
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 master\"\n" + \
|
||||
"3: B5 Body message is too short (14<20): \"Töo short body\"\n"
|
||||
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)
|
||||
|
||||
|
@ -139,11 +168,11 @@ class IntegrationTests(BaseTestCase):
|
|||
|
||||
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, _ok_code=[3])
|
||||
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 """
|
||||
"""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
|
||||
|
@ -151,34 +180,51 @@ class IntegrationTests(BaseTestCase):
|
|||
# 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, _in=" ",
|
||||
_tty_in=False, _err_to_out=True, _ok_code=[3])
|
||||
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 """
|
||||
"""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)
|
||||
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 """
|
||||
"""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)
|
||||
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_errors(self):
|
||||
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])
|
||||
|
@ -186,7 +232,36 @@ class IntegrationTests(BaseTestCase):
|
|||
expected = "Current branch has no commits. Gitlint requires at least one commit to function.\n"
|
||||
self.assertEqualStdout(output, expected)
|
||||
|
||||
# Repo has no commits: caused by `git rev-parse`
|
||||
output = gitlint(echo("WIP: Pïpe test."), "--staged", _cwd=empty_git_repo, _tty_in=False,
|
||||
_err_to_out=True, _ok_code=[self.GIT_CONTEXT_ERROR_CODE])
|
||||
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)
|
||||
|
|
126
qa/test_hooks.py
126
qa/test_hooks.py
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=too-many-function-args,unexpected-keyword-arg
|
||||
import os
|
||||
from qa.shell import git, gitlint
|
||||
|
@ -6,15 +5,17 @@ from qa.base import BaseTestCase
|
|||
|
||||
|
||||
class HookTests(BaseTestCase):
|
||||
""" Integration tests for gitlint commitmsg hooks"""
|
||||
"""Integration tests for gitlint commitmsg hooks"""
|
||||
|
||||
VIOLATIONS = ['gitlint: checking commit message...\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']
|
||||
VIOLATIONS = [
|
||||
"gitlint: checking commit message...\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()
|
||||
|
@ -29,16 +30,18 @@ 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 "
|
||||
f"{self.tmp_git_repo}/.git/hooks/commit-msg\n")
|
||||
expected_installed = (
|
||||
f"Successfully installed gitlint commit-msg hook in {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 "
|
||||
f"{self.tmp_git_repo}/.git/hooks/commit-msg\n")
|
||||
expected_uninstalled = (
|
||||
f"Successfully uninstalled gitlint commit-msg hook from {self.tmp_git_repo}/.git/hooks/commit-msg\n"
|
||||
)
|
||||
|
||||
self.assertEqualStdout(output_uninstalled, expected_uninstalled)
|
||||
super().tearDown()
|
||||
|
@ -58,63 +61,72 @@ class HookTests(BaseTestCase):
|
|||
self.response_index = (self.response_index + 1) % len(self.responses)
|
||||
|
||||
def test_commit_hook_no_violations(self):
|
||||
test_filename = self.create_simple_commit("This ïs a title\n\nBody contënt that should work",
|
||||
out=self._interact, tty_in=True)
|
||||
test_filename = self.create_simple_commit(
|
||||
"This ïs a title\n\nBody contënt that should work", out=self._interact, tty_in=True
|
||||
)
|
||||
|
||||
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",
|
||||
f"[master {short_hash}] This ïs a title\n",
|
||||
" 1 file changed, 0 insertions(+), 0 deletions(-)\n",
|
||||
f" create mode 100644 {test_filename}\n"]
|
||||
self.assertListEqual(expected_output, self.githook_output)
|
||||
expected_output = [
|
||||
"gitlint: checking commit message...\n",
|
||||
"gitlint: \x1b[32mOK\x1b[0m (no violations in commit message)\n",
|
||||
f"[main {short_hash}] This ïs a title\n",
|
||||
" 1 file changed, 0 insertions(+), 0 deletions(-)\n",
|
||||
f" create mode 100644 {test_filename}\n",
|
||||
]
|
||||
for output, expected in zip(self.githook_output, expected_output):
|
||||
self.assertMultiLineEqual(output.replace("\r", ""), expected.replace("\r", ""))
|
||||
|
||||
def test_commit_hook_continue(self):
|
||||
self.responses = ["y"]
|
||||
test_filename = self.create_simple_commit("WIP: This ïs a title.\nContënt on the second line",
|
||||
out=self._interact, tty_in=True)
|
||||
test_filename = self.create_simple_commit(
|
||||
"WIP: This ïs a title.\nContënt on the second line", out=self._interact, tty_in=True
|
||||
)
|
||||
|
||||
# Determine short commit-msg hash, needed to determine expected output
|
||||
short_hash = self.get_last_commit_short_hash()
|
||||
|
||||
expected_output = self._violations()
|
||||
expected_output += ["Continue with commit anyways (this keeps the current commit message)? " +
|
||||
"[y(es)/n(no)/e(dit)] " +
|
||||
f"[master {short_hash}] WIP: This ïs a title. Contënt on the second line\n",
|
||||
" 1 file changed, 0 insertions(+), 0 deletions(-)\n",
|
||||
f" create mode 100644 {test_filename}\n"]
|
||||
expected_output += [
|
||||
"Continue with commit anyways (this keeps the current commit message)? "
|
||||
"[y(es)/n(no)/e(dit)] "
|
||||
f"[main {short_hash}] WIP: This ïs a title. Contënt on the second line\n",
|
||||
" 1 file changed, 0 insertions(+), 0 deletions(-)\n",
|
||||
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):
|
||||
self.assertMultiLineEqual(
|
||||
output.replace('\r', ''),
|
||||
expected.replace('\r', ''))
|
||||
self.assertMultiLineEqual(output.replace("\r", ""), expected.replace("\r", ""))
|
||||
|
||||
def test_commit_hook_abort(self):
|
||||
self.responses = ["n"]
|
||||
test_filename = self.create_simple_commit("WIP: This ïs a title.\nContënt on the second line",
|
||||
out=self._interact, ok_code=1, tty_in=True)
|
||||
test_filename = self.create_simple_commit(
|
||||
"WIP: This ïs a title.\nContënt on the second line", out=self._interact, ok_code=1, tty_in=True
|
||||
)
|
||||
git("rm", "-f", test_filename, _cwd=self.tmp_git_repo)
|
||||
|
||||
# Determine short commit-msg hash, needed to determine expected output
|
||||
|
||||
expected_output = self._violations()
|
||||
expected_output += ["Continue with commit anyways (this keeps the current commit message)? " +
|
||||
"[y(es)/n(no)/e(dit)] " +
|
||||
"Commit aborted.\n",
|
||||
"Your commit message: \n",
|
||||
"-----------------------------------------------\n",
|
||||
"WIP: This ïs a title.\n",
|
||||
"Contënt on the second line\n",
|
||||
"-----------------------------------------------\n"]
|
||||
expected_output += [
|
||||
"Continue with commit anyways (this keeps the current commit message)? "
|
||||
"[y(es)/n(no)/e(dit)] "
|
||||
"Commit aborted.\n",
|
||||
"Your commit message: \n",
|
||||
"-----------------------------------------------\n",
|
||||
"WIP: This ïs a title.\n",
|
||||
"Contënt on the second line\n",
|
||||
"-----------------------------------------------\n",
|
||||
]
|
||||
|
||||
self.assertListEqual(expected_output, self.githook_output)
|
||||
for output, expected in zip(self.githook_output, expected_output):
|
||||
self.assertMultiLineEqual(output.replace("\r", ""), expected.replace("\r", ""))
|
||||
|
||||
def test_commit_hook_edit(self):
|
||||
self.responses = ["e", "y"]
|
||||
env = {"EDITOR": ":"}
|
||||
test_filename = self.create_simple_commit("WIP: This ïs a title.\nContënt on the second line",
|
||||
out=self._interact, env=env, tty_in=True)
|
||||
test_filename = self.create_simple_commit(
|
||||
"WIP: This ïs a title.\nContënt on the second line", out=self._interact, env=env, tty_in=True
|
||||
)
|
||||
git("rm", "-f", test_filename, _cwd=self.tmp_git_repo)
|
||||
|
||||
short_hash = git("rev-parse", "--short", "HEAD", _cwd=self.tmp_git_repo, _tty_in=True).replace("\n", "")
|
||||
|
@ -122,23 +134,23 @@ class HookTests(BaseTestCase):
|
|||
# Determine short commit-msg hash, needed to determine expected output
|
||||
|
||||
expected_output = self._violations()
|
||||
expected_output += ['Continue with commit anyways (this keeps the current commit message)? ' +
|
||||
'[y(es)/n(no)/e(dit)] ' + self._violations()[0]]
|
||||
expected_output += [
|
||||
"Continue with commit anyways (this keeps the current commit message)? [y(es)/n(no)/e(dit)] "
|
||||
+ self._violations()[0]
|
||||
]
|
||||
expected_output += self._violations()[1:]
|
||||
expected_output += ['Continue with commit anyways (this keeps the current commit message)? ' +
|
||||
"[y(es)/n(no)/e(dit)] " +
|
||||
f"[master {short_hash}] WIP: This ïs a title. Contënt on the second line\n",
|
||||
" 1 file changed, 0 insertions(+), 0 deletions(-)\n",
|
||||
f" create mode 100644 {test_filename}\n"]
|
||||
expected_output += [
|
||||
"Continue with commit anyways (this keeps the current commit message)? [y(es)/n(no)/e(dit)] "
|
||||
f"[main {short_hash}] WIP: This ïs a title. Contënt on the second line\n",
|
||||
" 1 file changed, 0 insertions(+), 0 deletions(-)\n",
|
||||
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):
|
||||
self.assertMultiLineEqual(
|
||||
output.replace('\r', ''),
|
||||
expected.replace('\r', ''))
|
||||
self.assertMultiLineEqual(output.replace("\r", ""), expected.replace("\r", ""))
|
||||
|
||||
def test_commit_hook_worktree(self):
|
||||
""" Tests that hook installation and un-installation also work in git worktrees.
|
||||
"""Tests that hook installation and un-installation also work in git worktrees.
|
||||
Test steps:
|
||||
```sh
|
||||
git init <tmpdir>
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from qa.shell import gitlint
|
||||
from qa.base import BaseTestCase
|
||||
|
||||
|
||||
class NamedRuleTests(BaseTestCase):
|
||||
""" Integration tests for named rules."""
|
||||
"""Integration tests for named rules."""
|
||||
|
||||
def test_named_rule(self):
|
||||
commit_msg = "WIP: thåt dûr bår\n\nSïmple commit body"
|
||||
|
@ -18,6 +17,7 @@ class NamedRuleTests(BaseTestCase):
|
|||
self.create_simple_commit(commit_msg)
|
||||
config_path = self.get_sample_path("config/named-user-rules")
|
||||
extra_path = self.get_sample_path("user_rules/extra")
|
||||
output = gitlint("--extra-path", extra_path, "--config", config_path, _cwd=self.tmp_git_repo, _tty_in=True,
|
||||
_ok_code=[9])
|
||||
output = gitlint(
|
||||
"--extra-path", extra_path, "--config", config_path, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[9]
|
||||
)
|
||||
self.assertEqualStdout(output, self.get_expected("test_named_rules/test_named_user_rule_1"))
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=too-many-function-args,unexpected-keyword-arg
|
||||
import io
|
||||
import subprocess
|
||||
from qa.shell import echo, gitlint
|
||||
from qa.base import BaseTestCase
|
||||
|
@ -8,25 +6,24 @@ from qa.utils import DEFAULT_ENCODING
|
|||
|
||||
|
||||
class StdInTests(BaseTestCase):
|
||||
""" Integration tests for various STDIN scenarios for gitlint """
|
||||
"""Integration tests for various STDIN scenarios for gitlint"""
|
||||
|
||||
def test_stdin_pipe(self):
|
||||
""" Test piping input into gitlint.
|
||||
This is the equivalent of doing:
|
||||
$ echo "foo" | gitlint
|
||||
"""Test piping input into gitlint.
|
||||
This is the equivalent of doing:
|
||||
$ echo "foo" | gitlint
|
||||
"""
|
||||
# NOTE: There is no use in testing this with _tty_in=True, because if you pipe something into a command
|
||||
# there never is a TTY connected to stdin (per definition). We're setting _tty_in=False here to be explicit
|
||||
# but note that this is always true when piping something into a command.
|
||||
output = gitlint(echo("WIP: Pïpe test."),
|
||||
_cwd=self.tmp_git_repo, _tty_in=False, _err_to_out=True, _ok_code=[3])
|
||||
output = gitlint(echo("WIP: Pïpe test."), _cwd=self.tmp_git_repo, _tty_in=False, _err_to_out=True, _ok_code=[3])
|
||||
self.assertEqualStdout(output, self.get_expected("test_stdin/test_stdin_pipe_1"))
|
||||
|
||||
def test_stdin_pipe_empty(self):
|
||||
""" Test the scenario where no TTY is attached and nothing is piped into gitlint. This occurs in
|
||||
CI runners like Jenkins and Gitlab, see https://github.com/jorisroovers/gitlint/issues/42 for details.
|
||||
This is the equivalent of doing:
|
||||
$ echo -n "" | gitlint
|
||||
"""Test the scenario where no TTY is attached and nothing is piped into gitlint. This occurs in
|
||||
CI runners like Jenkins and Gitlab, see https://github.com/jorisroovers/gitlint/issues/42 for details.
|
||||
This is the equivalent of doing:
|
||||
$ echo -n "" | gitlint
|
||||
"""
|
||||
commit_msg = "WIP: This ïs a title.\nContent on the sëcond line"
|
||||
self.create_simple_commit(commit_msg)
|
||||
|
@ -39,18 +36,18 @@ class StdInTests(BaseTestCase):
|
|||
self.assertEqual(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)
|
||||
This is the equivalent of doing:
|
||||
$ gitlint < myfile
|
||||
"""Test the scenario where STDIN is a regular file (stat.S_ISREG = True)
|
||||
This is the equivalent of doing:
|
||||
$ gitlint < myfile
|
||||
"""
|
||||
tmp_commit_msg_file = self.create_tmpfile("WIP: STDIN ïs a file test.")
|
||||
|
||||
with io.open(tmp_commit_msg_file, encoding=DEFAULT_ENCODING) as file_handle:
|
||||
|
||||
with open(tmp_commit_msg_file, encoding=DEFAULT_ENCODING) as file_handle:
|
||||
# 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.
|
||||
with subprocess.Popen("gitlint", stdin=file_handle, cwd=self.tmp_git_repo,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as p:
|
||||
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"))
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=too-many-function-args,unexpected-keyword-arg
|
||||
from qa.shell import gitlint
|
||||
from qa.base import BaseTestCase
|
||||
|
||||
|
||||
class UserDefinedRuleTests(BaseTestCase):
|
||||
""" Integration tests for user-defined rules."""
|
||||
"""Integration tests for user-defined rules."""
|
||||
|
||||
def test_user_defined_rules_examples1(self):
|
||||
""" Test the user defined rules in the top-level `examples/` directory """
|
||||
"""Test the user defined rules in the top-level `examples/` directory"""
|
||||
extra_path = self.get_example_path()
|
||||
commit_msg = "WIP: Thi$ is å title\nContent on the second line"
|
||||
self.create_simple_commit(commit_msg)
|
||||
|
@ -16,7 +15,7 @@ class UserDefinedRuleTests(BaseTestCase):
|
|||
self.assertEqualStdout(output, self.get_expected("test_user_defined/test_user_defined_rules_examples_1"))
|
||||
|
||||
def test_user_defined_rules_examples2(self):
|
||||
""" Test the user defined rules in the top-level `examples/` directory """
|
||||
"""Test the user defined rules in the top-level `examples/` directory"""
|
||||
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)
|
||||
|
@ -24,12 +23,19 @@ class UserDefinedRuleTests(BaseTestCase):
|
|||
self.assertEqualStdout(output, self.get_expected("test_user_defined/test_user_defined_rules_examples_2"))
|
||||
|
||||
def test_user_defined_rules_examples_with_config(self):
|
||||
""" Test the user defined rules in the top-level `examples/` directory """
|
||||
"""Test the user defined rules in the top-level `examples/` directory"""
|
||||
extra_path = self.get_example_path()
|
||||
commit_msg = "WIP: Thi$ is å title\nContent on the second line"
|
||||
self.create_simple_commit(commit_msg)
|
||||
output = gitlint("--extra-path", extra_path, "-c", "body-max-line-count.max-line-count=1",
|
||||
_cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[6])
|
||||
output = gitlint(
|
||||
"--extra-path",
|
||||
extra_path,
|
||||
"-c",
|
||||
"body-max-line-count.max-line-count=1",
|
||||
_cwd=self.tmp_git_repo,
|
||||
_tty_in=True,
|
||||
_ok_code=[6],
|
||||
)
|
||||
expected_path = "test_user_defined/test_user_defined_rules_examples_with_config_1"
|
||||
self.assertEqualStdout(output, self.get_expected(expected_path))
|
||||
|
||||
|
@ -38,12 +44,15 @@ class UserDefinedRuleTests(BaseTestCase):
|
|||
commit_msg = "WIP: Thi$ is å title\nContent on the second line"
|
||||
self.create_simple_commit(commit_msg)
|
||||
output = gitlint("--extra-path", extra_path, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[9])
|
||||
self.assertEqualStdout(output, self.get_expected("test_user_defined/test_user_defined_rules_extra_1",
|
||||
{'repo-path': self.tmp_git_repo}))
|
||||
self.assertEqualStdout(
|
||||
output,
|
||||
self.get_expected("test_user_defined/test_user_defined_rules_extra_1", {"repo-path": self.tmp_git_repo}),
|
||||
)
|
||||
|
||||
def test_invalid_user_defined_rules(self):
|
||||
extra_path = self.get_sample_path("user_rules/incorrect_linerule")
|
||||
self.create_simple_commit("WIP: test")
|
||||
output = gitlint("--extra-path", extra_path, _cwd=self.tmp_git_repo, _tty_in=True, _ok_code=[255])
|
||||
self.assertEqualStdout(output,
|
||||
"Config Error: User-defined rule class 'MyUserLineRule' must have a 'validate' method\n")
|
||||
self.assertEqualStdout(
|
||||
output, "Config Error: User-defined rule class 'MyUserLineRule' must have a 'validate' method\n"
|
||||
)
|
||||
|
|
|
@ -22,7 +22,7 @@ PLATFORM_IS_WINDOWS = platform_is_windows()
|
|||
|
||||
|
||||
def use_sh_library():
|
||||
gitlint_use_sh_lib_env = os.environ.get('GITLINT_QA_USE_SH_LIB', None)
|
||||
gitlint_use_sh_lib_env = os.environ.get("GITLINT_QA_USE_SH_LIB", None)
|
||||
if gitlint_use_sh_lib_env:
|
||||
return gitlint_use_sh_lib_env == "1"
|
||||
return not PLATFORM_IS_WINDOWS
|
||||
|
@ -35,8 +35,8 @@ USE_SH_LIB = use_sh_library()
|
|||
|
||||
|
||||
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. """
|
||||
"""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
|
||||
|
@ -51,7 +51,7 @@ def getpreferredencoding():
|
|||
# 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:]
|
||||
default_encoding = encoding[dot_index + 1 :]
|
||||
else:
|
||||
default_encoding = encoding
|
||||
break
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue