From 4fee3e091a8d79a40f70ff9c1f87b29b9340049a Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 25 Jan 2021 14:26:11 +0100 Subject: Merging upstream version 0.15.0. Signed-off-by: Daniel Baumann --- gitlint/__init__.py | 2 +- gitlint/cache.py | 24 +-- gitlint/cli.py | 100 ++++----- gitlint/config.py | 117 +++++------ gitlint/contrib/rules/conventional_commit.py | 7 +- gitlint/display.py | 13 +- gitlint/exception.py | 4 + gitlint/git.py | 118 +++++------ gitlint/hooks.py | 19 +- gitlint/lint.py | 18 +- gitlint/options.py | 58 +++-- gitlint/rule_finder.py | 49 ++--- gitlint/rules.py | 62 ++---- gitlint/shell.py | 15 +- gitlint/tests/base.py | 60 ++---- gitlint/tests/cli/test_cli.py | 234 ++++++++++----------- gitlint/tests/cli/test_cli_hooks.py | 121 ++++++----- gitlint/tests/config/test_config.py | 69 +++--- gitlint/tests/config/test_config_builder.py | 80 +++---- gitlint/tests/config/test_config_precedence.py | 30 +-- gitlint/tests/config/test_rule_collection.py | 22 +- .../contrib/rules/test_conventional_commit.py | 20 +- gitlint/tests/contrib/rules/test_signedoff_by.py | 6 +- gitlint/tests/contrib/test_contrib_rules.py | 9 +- .../cli/test_cli_hooks/test_run_hook_negative_1 | 2 + .../cli/test_cli_hooks/test_run_hook_negative_2 | 2 + gitlint/tests/git/test_git.py | 45 ++-- gitlint/tests/git/test_git_commit.py | 230 ++++++++++---------- gitlint/tests/git/test_git_context.py | 55 +++-- gitlint/tests/rules/test_body_rules.py | 92 ++++---- gitlint/tests/rules/test_configuration_rules.py | 46 ++-- gitlint/tests/rules/test_meta_rules.py | 30 +-- gitlint/tests/rules/test_rules.py | 8 +- gitlint/tests/rules/test_title_rules.py | 90 ++++---- gitlint/tests/rules/test_user_rules.py | 48 ++--- .../tests/samples/user_rules/my_commit_rules.py | 6 +- .../samples/user_rules/parent_package/__init__.py | 2 +- .../user_rules/parent_package/my_commit_rules.py | 2 +- gitlint/tests/test_cache.py | 22 +- gitlint/tests/test_display.py | 55 ++--- gitlint/tests/test_hooks.py | 35 ++- gitlint/tests/test_lint.py | 110 +++++----- gitlint/tests/test_options.py | 113 +++++----- gitlint/tests/test_utils.py | 39 ++-- gitlint/utils.py | 47 ----- 45 files changed, 1056 insertions(+), 1280 deletions(-) create mode 100644 gitlint/exception.py create mode 100644 gitlint/tests/expected/cli/test_cli_hooks/test_run_hook_negative_1 create mode 100644 gitlint/tests/expected/cli/test_cli_hooks/test_run_hook_negative_2 (limited to 'gitlint') diff --git a/gitlint/__init__.py b/gitlint/__init__.py index 9e78220..9da2f8f 100644 --- a/gitlint/__init__.py +++ b/gitlint/__init__.py @@ -1 +1 @@ -__version__ = "0.14.0" +__version__ = "0.15.0" diff --git a/gitlint/cache.py b/gitlint/cache.py index b7f9e6c..1b6558f 100644 --- a/gitlint/cache.py +++ b/gitlint/cache.py @@ -1,4 +1,4 @@ -class PropertyCache(object): +class PropertyCache: """ Mixin class providing a simple cache. """ def __init__(self): @@ -13,7 +13,7 @@ class PropertyCache(object): return self._cache[cache_key] -def cache(original_func=None, cachekey=None): +def cache(original_func=None, cachekey=None): # pylint: disable=unused-argument """ Cache decorator. Caches function return values. Requires the parent class to extend and initialize PropertyCache. Usage: @@ -28,27 +28,23 @@ def cache(original_func=None, cachekey=None): ... """ - # Decorators with optional arguments are a bit convoluted in python, especially if you want to support both - # Python 2 and 3. See some of the links below for details. + # Decorators with optional arguments are a bit convoluted in python, see some of the links below for details. def cache_decorator(func): - - # If no specific cache key is given, use the function name as cache key - if not cache_decorator.cachekey: - cache_decorator.cachekey = func.__name__ + # Use 'nonlocal' keyword to access parent function variable: + # https://stackoverflow.com/a/14678445/381010 + nonlocal cachekey + if not cachekey: + cachekey = func.__name__ def wrapped(*args): def cache_func_result(): # Call decorated function and store its result in the cache - args[0]._cache[cache_decorator.cachekey] = func(*args) - return args[0]._try_cache(cache_decorator.cachekey, cache_func_result) + args[0]._cache[cachekey] = func(*args) + return args[0]._try_cache(cachekey, cache_func_result) return wrapped - # Passing parent function variables to child functions requires special voodoo in python2: - # https://stackoverflow.com/a/14678445/381010 - cache_decorator.cachekey = cachekey # attribute on the function - # To support optional kwargs for decorators, we need to check if a function is passed as first argument or not. # https://stackoverflow.com/a/24617244/381010 if original_func: diff --git a/gitlint/cli.py b/gitlint/cli.py index f284792..b162e5b 100644 --- a/gitlint/cli.py +++ b/gitlint/cli.py @@ -8,19 +8,20 @@ import stat import sys import click -# Error codes -MAX_VIOLATION_ERROR_CODE = 252 # noqa -USAGE_ERROR_CODE = 253 # noqa -GIT_CONTEXT_ERROR_CODE = 254 # noqa -CONFIG_ERROR_CODE = 255 # noqa - import gitlint from gitlint.lint import GitLinter from gitlint.config import LintConfigBuilder, LintConfigError, LintConfigGenerator from gitlint.git import GitContext, GitContextError, git_version from gitlint import hooks from gitlint.shell import shell -from gitlint.utils import ustr, LOG_FORMAT, IS_PY2 +from gitlint.utils import LOG_FORMAT +from gitlint.exception import GitlintError + +# Error codes +MAX_VIOLATION_ERROR_CODE = 252 +USAGE_ERROR_CODE = 253 +GIT_CONTEXT_ERROR_CODE = 254 +CONFIG_ERROR_CODE = 255 DEFAULT_CONFIG_FILE = ".gitlint" # -n: disable swap files. This fixes a vim error on windows (E303: Unable to open swap file for ) @@ -34,7 +35,7 @@ click.UsageError.exit_code = USAGE_ERROR_CODE LOG = logging.getLogger("gitlint.cli") -class GitLintUsageError(Exception): +class GitLintUsageError(GitlintError): """ Exception indicating there is an issue with how gitlint is used. """ pass @@ -134,7 +135,7 @@ def get_stdin_data(): # Only return the input data if there's actually something passed # i.e. don't consider empty piped data if input_data: - return ustr(input_data) + return str(input_data) return False @@ -151,7 +152,7 @@ def build_git_context(lint_config, msg_filename, refspec): # 1. Any data specified via --msg-filename if msg_filename: LOG.debug("Using --msg-filename.") - return from_commit_msg(ustr(msg_filename.read())) + return from_commit_msg(str(msg_filename.read())) # 2. Any data sent to stdin (unless stdin is being ignored) if not lint_config.ignore_stdin: @@ -162,15 +163,28 @@ def build_git_context(lint_config, msg_filename, refspec): return from_commit_msg(stdin_input) if lint_config.staged: - raise GitLintUsageError(u"The 'staged' option (--staged) can only be used when using '--msg-filename' or " - u"when piping data to gitlint via stdin.") + raise GitLintUsageError("The 'staged' option (--staged) can only be used when using '--msg-filename' or " + "when piping data to gitlint via stdin.") # 3. Fallback to reading from local repository LOG.debug("No --msg-filename flag, no or empty data passed to stdin. Using the local repo.") return GitContext.from_local_repository(lint_config.target, refspec) -class ContextObj(object): +def handle_gitlint_error(ctx, exc): + """ Helper function to handle exceptions """ + if isinstance(exc, GitContextError): + click.echo(exc) + ctx.exit(GIT_CONTEXT_ERROR_CODE) + elif isinstance(exc, GitLintUsageError): + click.echo(f"Error: {exc}") + ctx.exit(USAGE_ERROR_CODE) + elif isinstance(exc, LintConfigError): + click.echo(f"Config Error: {exc}") + ctx.exit(CONFIG_ERROR_CODE) + + +class ContextObj: """ Simple class to hold data that is passed between Click commands via the Click context. """ def __init__(self, config, config_builder, refspec, msg_filename, gitcontext=None): @@ -187,7 +201,7 @@ class ContextObj(object): type=click.Path(exists=True, resolve_path=True, file_okay=False, readable=True), help="Path of the target git repository. [default: current working directory]") @click.option('-C', '--config', type=click.Path(exists=True, dir_okay=False, readable=True, resolve_path=True), - help="Config file location [default: {0}]".format(DEFAULT_CONFIG_FILE)) + help=f"Config file location [default: {DEFAULT_CONFIG_FILE}]") @click.option('-c', multiple=True, help="Config flags in format .