summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoris Roovers <joris.roovers@gmail.com>2022-09-01 10:04:34 +0200
committerGitHub <noreply@github.com>2022-09-01 10:04:34 +0200
commit871b66a9224af8817e115f6fd8fddab7bf8128c2 (patch)
treee782bf5af010a6af491a034f05f4ad2e5cbbbaf6
parent800f6fd26c72e35388065281bfd8def084440825 (diff)
Black formatting (#327)
- Removes flake8 as code style checker in favor of black - Added fmt:on, fmt:off commenting guards to overrule black in specific scenarios - Updated docs, ./run_tests.sh, removed references to pep8
-rw-r--r--.github/workflows/checks.yml8
-rw-r--r--docs/contributing.md6
-rw-r--r--examples/my_commit_rules.py14
-rw-r--r--examples/my_configuration_rules.py5
-rw-r--r--examples/my_line_rules.py15
-rw-r--r--gitlint-core/gitlint/cache.py33
-rw-r--r--gitlint-core/gitlint/cli.py88
-rw-r--r--gitlint-core/gitlint/config.py233
-rw-r--r--gitlint-core/gitlint/contrib/rules/conventional_commit.py4
-rw-r--r--gitlint-core/gitlint/contrib/rules/disallow_cleanup_commits.py2
-rw-r--r--gitlint-core/gitlint/contrib/rules/signedoff_by.py3
-rw-r--r--gitlint-core/gitlint/display.py6
-rw-r--r--gitlint-core/gitlint/exception.py4
-rw-r--r--gitlint-core/gitlint/git.py199
-rw-r--r--gitlint-core/gitlint/hooks.py15
-rw-r--r--gitlint-core/gitlint/lint.py51
-rw-r--r--gitlint-core/gitlint/options.py34
-rw-r--r--gitlint-core/gitlint/rule_finder.py71
-rw-r--r--gitlint-core/gitlint/rules.py157
-rw-r--r--gitlint-core/gitlint/shell.py30
-rw-r--r--gitlint-core/gitlint/tests/base.py48
-rw-r--r--gitlint-core/gitlint/tests/cli/test_cli.py366
-rw-r--r--gitlint-core/gitlint/tests/cli/test_cli_hooks.py152
-rw-r--r--gitlint-core/gitlint/tests/config/test_config.py96
-rw-r--r--gitlint-core/gitlint/tests/config/test_config_builder.py87
-rw-r--r--gitlint-core/gitlint/tests/config/test_config_precedence.py43
-rw-r--r--gitlint-core/gitlint/tests/config/test_rule_collection.py7
-rw-r--r--gitlint-core/gitlint/tests/contrib/rules/test_conventional_commit.py38
-rw-r--r--gitlint-core/gitlint/tests/contrib/rules/test_disallow_cleanup_commits.py4
-rw-r--r--gitlint-core/gitlint/tests/contrib/rules/test_signedoff_by.py4
-rw-r--r--gitlint-core/gitlint/tests/contrib/test_contrib_rules.py33
-rw-r--r--gitlint-core/gitlint/tests/git/test_git.py47
-rw-r--r--gitlint-core/gitlint/tests/git/test_git_commit.py293
-rw-r--r--gitlint-core/gitlint/tests/git/test_git_context.py39
-rw-r--r--gitlint-core/gitlint/tests/rules/test_body_rules.py22
-rw-r--r--gitlint-core/gitlint/tests/rules/test_configuration_rules.py45
-rw-r--r--gitlint-core/gitlint/tests/rules/test_meta_rules.py37
-rw-r--r--gitlint-core/gitlint/tests/rules/test_rules.py1
-rw-r--r--gitlint-core/gitlint/tests/rules/test_title_rules.py55
-rw-r--r--gitlint-core/gitlint/tests/rules/test_user_rules.py65
-rw-r--r--gitlint-core/gitlint/tests/samples/user_rules/my_commit_rules.py5
-rw-r--r--gitlint-core/gitlint/tests/test_cache.py3
-rw-r--r--gitlint-core/gitlint/tests/test_display.py16
-rw-r--r--gitlint-core/gitlint/tests/test_hooks.py66
-rw-r--r--gitlint-core/gitlint/tests/test_lint.py184
-rw-r--r--gitlint-core/gitlint/tests/test_options.py14
-rw-r--r--gitlint-core/gitlint/tests/test_utils.py7
-rw-r--r--gitlint-core/gitlint/utils.py10
-rw-r--r--gitlint-core/setup.py48
-rw-r--r--pyproject.toml5
-rw-r--r--qa/base.py58
-rw-r--r--qa/samples/user_rules/extra/extra_rules.py22
-rw-r--r--qa/shell.py30
-rw-r--r--qa/test_commits.py131
-rw-r--r--qa/test_config.py71
-rw-r--r--qa/test_contrib.py19
-rw-r--r--qa/test_gitlint.py69
-rw-r--r--qa/test_hooks.py119
-rw-r--r--qa/test_named_rules.py7
-rw-r--r--qa/test_stdin.py31
-rw-r--r--qa/test_user_defined.py30
-rw-r--r--qa/utils.py8
-rwxr-xr-xrun_tests.sh26
-rw-r--r--setup.py18
-rw-r--r--test-requirements.txt3
65 files changed, 1969 insertions, 1491 deletions
diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml
index 588ade0..4e71df4 100644
--- a/.github/workflows/checks.yml
+++ b/.github/workflows/checks.yml
@@ -58,8 +58,8 @@ jobs:
GITLINT_USE_SH_LIB: 0
run: ./run_tests.sh -i
- - name: PEP8
- run: ./run_tests.sh -p
+ - name: Code formatting (black)
+ run: ./run_tests.sh -f
- name: PyLint
run: ./run_tests.sh -l
@@ -136,8 +136,8 @@ jobs:
run: pytest -rw -s qa
continue-on-error: true # Known to fail at this point
- - name: PEP8
- run: flake8 gitlint-core qa examples
+ - name: Code formatting (black)
+ run: black .
- name: PyLint
run: pylint gitlint-core\gitlint qa --rcfile=".pylintrc" -r n
diff --git a/docs/contributing.md b/docs/contributing.md
index 1002676..4798e71 100644
--- a/docs/contributing.md
+++ b/docs/contributing.md
@@ -59,11 +59,11 @@ To run tests:
./run_tests.sh --collect-only --no-coverage # Only collect, don't run unit tests
./run_tests.sh --integration # Run integration tests (requires that you have gitlint installed)
./run_tests.sh --build # Run build tests (=build python package)
-./run_tests.sh --pep8 # pep8 checks
+./run_tests.sh --format # format checks
./run_tests.sh --stats # print some code stats
./run_tests.sh --git # inception: run gitlint against itself
./run_tests.sh --lint # run pylint checks
-./run_tests.sh --all # Run unit, integration, pep8 and gitlint checks
+./run_tests.sh --all # Run unit, integration, format and gitlint checks
```
The `Vagrantfile` comes with `virtualenv`s for python 3.6, 3.7, 3.8, 3.9 and pypy3.6.
@@ -71,7 +71,7 @@ You can easily run tests against specific python environments by using the follo
```sh
./run_tests.sh --envs 36 # Run the unit tests against Python 3.6
./run_tests.sh --envs 36,37,pypy36 # Run the unit tests against Python 3.6, Python 3.7 and Pypy3.6
-./run_tests.sh --envs 36,37 --pep8 # Run pep8 checks against Python 3.6 and Python 3.7 (also works for --git, --integration, --pep8, --stats and --lint.
+./run_tests.sh --envs 36,37 --format # Run format checks against Python 3.6 and Python 3.7 (also works for --git, --integration, --format, --stats and --lint.
./run_tests.sh --envs all --all # Run all tests against all environments
./run_tests.sh --all-env --all # Idem: Run all tests against all environments
```
diff --git a/examples/my_commit_rules.py b/examples/my_commit_rules.py
index 2805501..ad1d21d 100644
--- a/examples/my_commit_rules.py
+++ b/examples/my_commit_rules.py
@@ -27,20 +27,20 @@ class BodyMaxLineCount(CommitRule):
id = "UC1"
# A rule MAY have an option_spec if its behavior should be configurable.
- options_spec = [IntOption('max-line-count', 3, "Maximum body line count")]
+ options_spec = [IntOption("max-line-count", 3, "Maximum body line count")]
def validate(self, commit):
self.log.debug("BodyMaxLineCount: This will be visible when running `gitlint --debug`")
line_count = len(commit.message.body)
- max_line_count = self.options['max-line-count'].value
+ max_line_count = self.options["max-line-count"].value
if line_count > max_line_count:
message = f"Body contains too many lines ({line_count} > {max_line_count})"
return [RuleViolation(self.id, message, line_nr=1)]
class SignedOffBy(CommitRule):
- """ This rule will enforce that each commit contains a "Signed-off-by" line.
+ """This rule will enforce that each commit contains a "Signed-off-by" line.
We keep things simple here and just check whether the commit body contains a line that starts with "Signed-off-by".
"""
@@ -61,8 +61,8 @@ class SignedOffBy(CommitRule):
class BranchNamingConventions(CommitRule):
- """ This rule will enforce that a commit is part of a branch that meets certain naming conventions.
- See GitFlow for real-world example of this: https://nvie.com/posts/a-successful-git-branching-model/
+ """This rule will enforce that a commit is part of a branch that meets certain naming conventions.
+ See GitFlow for real-world example of this: https://nvie.com/posts/a-successful-git-branching-model/
"""
# A rule MUST have a human friendly name
@@ -72,13 +72,13 @@ class BranchNamingConventions(CommitRule):
id = "UC3"
# A rule MAY have an option_spec if its behavior should be configurable.
- options_spec = [ListOption('branch-prefixes', ["feature/", "hotfix/", "release/"], "Allowed branch prefixes")]
+ options_spec = [ListOption("branch-prefixes", ["feature/", "hotfix/", "release/"], "Allowed branch prefixes")]
def validate(self, commit):
self.log.debug("BranchNamingConventions: This line will be visible when running `gitlint --debug`")
violations = []
- allowed_branch_prefixes = self.options['branch-prefixes'].value
+ allowed_branch_prefixes = self.options["branch-prefixes"].value
for branch in commit.branches:
valid_branch_name = False
diff --git a/examples/my_configuration_rules.py b/examples/my_configuration_rules.py
index 7c00707..ee3e981 100644
--- a/examples/my_configuration_rules.py
+++ b/examples/my_configuration_rules.py
@@ -36,7 +36,7 @@ class ReleaseConfigurationRule(ConfigurationRule):
id = "UCR1"
# A rule MAY have an option_spec if its behavior should be configurable.
- options_spec = [IntOption('custom-verbosity', 2, "Gitlint verbosity for release commits")]
+ options_spec = [IntOption("custom-verbosity", 2, "Gitlint verbosity for release commits")]
def apply(self, config, commit):
self.log.debug("ReleaseConfigurationRule: This will be visible when running `gitlint --debug`")
@@ -44,7 +44,6 @@ class ReleaseConfigurationRule(ConfigurationRule):
# If the commit title starts with 'Release', we want to modify
# how all subsequent rules interpret that commit
if commit.message.title.startswith("Release"):
-
# If your Release commit messages are auto-generated, the
# body might contain trailing whitespace. Let's ignore that
config.ignore.append("body-trailing-whitespace")
@@ -60,7 +59,7 @@ class ReleaseConfigurationRule(ConfigurationRule):
# config.set_general_option(<general-option>, <value>)
config.set_general_option("verbosity", 2)
# Wwe can also use custom options to make this configurable
- config.set_general_option("verbosity", self.options['custom-verbosity'].value)
+ config.set_general_option("verbosity", self.options["custom-verbosity"].value)
# Strip any lines starting with $ from the commit message
# (this only affects how gitlint sees your commit message, it does
diff --git a/examples/my_line_rules.py b/examples/my_line_rules.py
index 3a1ef36..777854b 100644
--- a/examples/my_line_rules.py
+++ b/examples/my_line_rules.py
@@ -21,8 +21,8 @@ that fits your needs.
class SpecialChars(LineRule):
- """ This rule will enforce that the commit message title does not contain any of the following characters:
- $^%@!*() """
+ """This rule will enforce that the commit message title does not contain any of the following characters:
+ $^%@!*()"""
# A rule MUST have a human friendly name
name = "title-no-special-chars"
@@ -35,15 +35,20 @@ class SpecialChars(LineRule):
target = CommitMessageTitle
# A rule MAY have an option_spec if its behavior should be configurable.
- options_spec = [ListOption('special-chars', ['$', '^', '%', '@', '!', '*', '(', ')'],
- "Comma separated list of characters that should not occur in the title")]
+ options_spec = [
+ ListOption(
+ "special-chars",
+ ["$", "^", "%", "@", "!", "*", "(", ")"],
+ "Comma separated list of characters that should not occur in the title",
+ )
+ ]
def validate(self, line, _commit):
self.log.debug("SpecialChars: This will be visible when running `gitlint --debug`")
violations = []
# options can be accessed by looking them up by their name in self.options
- for char in self.options['special-chars'].value:
+ for char in self.options["special-chars"].value:
if char in line:
msg = f"Title contains the special character '{char}'"
violation = RuleViolation(self.id, msg, line)
diff --git a/gitlint-core/gitlint/cache.py b/gitlint-core/gitlint/cache.py
index 1b6558f..b84c904 100644
--- a/gitlint-core/gitlint/cache.py
+++ b/gitlint-core/gitlint/cache.py
@@ -1,31 +1,31 @@
class PropertyCache:
- """ Mixin class providing a simple cache. """
+ """Mixin class providing a simple cache."""
def __init__(self):
self._cache = {}
def _try_cache(self, cache_key, cache_populate_func):
- """ Tries to get a value from the cache identified by `cache_key`.
- If no value is found in the cache, do a function call to `cache_populate_func` to populate the cache
- and then return the value from the cache. """
+ """Tries to get a value from the cache identified by `cache_key`.
+ If no value is found in the cache, do a function call to `cache_populate_func` to populate the cache
+ and then return the value from the cache."""
if cache_key not in self._cache:
cache_populate_func()
return self._cache[cache_key]
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:
- # Use function name as cache key
- @cache
- def myfunc(args):
- ...
-
- # Specify cache key
- @cache(cachekey="foobar")
- def myfunc(args):
- ...
+ """Cache decorator. Caches function return values.
+ Requires the parent class to extend and initialize PropertyCache.
+ Usage:
+ # Use function name as cache key
+ @cache
+ def myfunc(args):
+ ...
+
+ # Specify cache key
+ @cache(cachekey="foobar")
+ def myfunc(args):
+ ...
"""
# Decorators with optional arguments are a bit convoluted in python, see some of the links below for details.
@@ -41,6 +41,7 @@ def cache(original_func=None, cachekey=None): # pylint: disable=unused-argument
def cache_func_result():
# Call decorated function and store its result in the cache
args[0]._cache[cachekey] = func(*args)
+
return args[0]._try_cache(cachekey, cache_func_result)
return wrapped
diff --git a/gitlint-core/gitlint/cli.py b/gitlint-core/gitlint/cli.py
index 415a8d3..5ba5d4c 100644
--- a/gitlint-core/gitlint/cli.py
+++ b/gitlint-core/gitlint/cli.py
@@ -37,12 +37,13 @@ LOG = logging.getLogger("gitlint.cli")
class GitLintUsageError(GitlintError):
- """ Exception indicating there is an issue with how gitlint is used. """
+ """Exception indicating there is an issue with how gitlint is used."""
+
pass
def setup_logging():
- """ Setup gitlint logging """
+ """Setup gitlint logging"""
root_log = logging.getLogger("gitlint")
root_log.propagate = False # Don't propagate to child loggers, the gitlint root logger handles everything
handler = logging.StreamHandler()
@@ -62,10 +63,20 @@ def log_system_info():
def build_config( # pylint: disable=too-many-arguments
- target, config_path, c, extra_path, ignore, contrib, ignore_stdin, staged, fail_without_commits, verbose,
- silent, debug
+ target,
+ config_path,
+ c,
+ extra_path,
+ ignore,
+ contrib,
+ ignore_stdin,
+ staged,
+ fail_without_commits,
+ verbose,
+ silent,
+ debug,
):
- """ Creates a LintConfig object based on a set of commandline parameters. """
+ """Creates a LintConfig object based on a set of commandline parameters."""
config_builder = LintConfigBuilder()
# Config precedence:
# First, load default config or config from configfile
@@ -79,33 +90,33 @@ def build_config( # pylint: disable=too-many-arguments
# Finally, overwrite with any convenience commandline flags
if ignore:
- config_builder.set_option('general', 'ignore', ignore)
+ config_builder.set_option("general", "ignore", ignore)
if contrib:
- config_builder.set_option('general', 'contrib', contrib)
+ config_builder.set_option("general", "contrib", contrib)
if ignore_stdin:
- config_builder.set_option('general', 'ignore-stdin', ignore_stdin)
+ config_builder.set_option("general", "ignore-stdin", ignore_stdin)
if silent:
- config_builder.set_option('general', 'verbosity', 0)
+ config_builder.set_option("general", "verbosity", 0)
elif verbose > 0:
- config_builder.set_option('general', 'verbosity', verbose)
+ config_builder.set_option("general", "verbosity", verbose)
if extra_path:
- config_builder.set_option('general', 'extra-path', extra_path)
+ config_builder.set_option("general", "extra-path", extra_path)
if target:
- config_builder.set_option('general', 'target', target)
+ config_builder.set_option("general", "target", target)
if debug:
- config_builder.set_option('general', 'debug', debug)
+ config_builder.set_option("general", "debug", debug)
if staged:
- config_builder.set_option('general', 'staged', staged)
+ config_builder.set_option("general", "staged", staged)
if fail_without_commits:
- config_builder.set_option('general', 'fail-without-commits', fail_without_commits)
+ config_builder.set_option("general", "fail-without-commits", fail_without_commits)
config = config_builder.build()
@@ -113,7 +124,7 @@ def build_config( # pylint: disable=too-many-arguments
def get_stdin_data():
- """ Helper function that returns data sent to stdin or False if nothing is sent """
+ """Helper function that returns data sent to stdin or False if nothing is sent"""
# STDIN can only be 3 different types of things ("modes")
# 1. An interactive terminal device (i.e. a TTY -> sys.stdin.isatty() or stat.S_ISCHR)
# 2. A (named) pipe (stat.S_ISFIFO)
@@ -145,7 +156,7 @@ def get_stdin_data():
def build_git_context(lint_config, msg_filename, commit_hash, refspec):
- """ Builds a git context based on passed parameters and order of precedence """
+ """Builds a git context based on passed parameters and order of precedence"""
# Determine which GitContext method to use if a custom message is passed
from_commit_msg = GitContext.from_commit_msg
@@ -168,8 +179,10 @@ def build_git_context(lint_config, msg_filename, commit_hash, refspec):
return from_commit_msg(stdin_input)
if lint_config.staged:
- raise GitLintUsageError("The 'staged' option (--staged) can only be used when using '--msg-filename' or "
- "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.")
@@ -195,7 +208,7 @@ def build_git_context(lint_config, msg_filename, commit_hash, refspec):
def handle_gitlint_error(ctx, exc):
- """ Helper function to handle exceptions """
+ """Helper function to handle exceptions"""
if isinstance(exc, GitContextError):
click.echo(exc)
ctx.exit(GIT_CONTEXT_ERROR_CODE)
@@ -208,7 +221,7 @@ def handle_gitlint_error(ctx, exc):
class ContextObj:
- """ Simple class to hold data that is passed between Click commands via the Click context. """
+ """Simple class to hold data that is passed between Click commands via the Click context."""
def __init__(self, config, config_builder, commit_hash, refspec, msg_filename, gitcontext=None):
self.config = config
@@ -219,6 +232,7 @@ class ContextObj:
self.gitcontext = gitcontext
+# fmt: off
@click.group(invoke_without_command=True, context_settings={'max_content_width': 120},
epilog="When no COMMAND is specified, gitlint defaults to 'gitlint lint'.")
@click.option('--target', envvar='GITLINT_TARGET',
@@ -263,7 +277,6 @@ def cli( # pylint: disable=too-many-arguments
Documentation: http://jorisroovers.github.io/gitlint
"""
-
try:
if debug:
logging.getLogger("gitlint").setLevel(logging.DEBUG)
@@ -273,8 +286,8 @@ def cli( # pylint: disable=too-many-arguments
# Get the lint config from the commandline parameters and
# store it in the context (click allows storing an arbitrary object in ctx.obj).
- config, config_builder = build_config(target, config, c, extra_path, ignore, contrib, ignore_stdin, staged,
- fail_without_commits, verbose, silent, debug)
+ config, config_builder = build_config(target, config, c, extra_path, ignore, contrib, ignore_stdin,
+ staged, fail_without_commits, verbose, silent, debug)
LOG.debug("Configuration\n%s", config)
ctx.obj = ContextObj(config, config_builder, commit, commits, msg_filename)
@@ -285,12 +298,13 @@ def cli( # pylint: disable=too-many-arguments
except GitlintError as e:
handle_gitlint_error(ctx, e)
+# fmt: on
@cli.command("lint")
@click.pass_context
def lint(ctx):
- """ Lints a git repository [default command] """
+ """Lints a git repository [default command]"""
lint_config = ctx.obj.config
refspec = ctx.obj.refspec
commit_hash = ctx.obj.commit_hash
@@ -312,7 +326,7 @@ def lint(ctx):
raise GitLintUsageError(f'No commits in range "{refspec}"')
ctx.exit(GITLINT_SUCCESS)
- LOG.debug('Linting %d commit(s)', number_of_commits)
+ LOG.debug("Linting %d commit(s)", number_of_commits)
general_config_builder = ctx.obj.config_builder
last_commit = gitcontext.commits[-1]
@@ -351,7 +365,7 @@ def lint(ctx):
@cli.command("install-hook")
@click.pass_context
def install_hook(ctx):
- """ Install gitlint as a git commit-msg hook. """
+ """Install gitlint as a git commit-msg hook."""
try:
hooks.GitHookInstaller.install_commit_msg_hook(ctx.obj.config)
hook_path = hooks.GitHookInstaller.commit_msg_hook_path(ctx.obj.config)
@@ -365,7 +379,7 @@ def install_hook(ctx):
@cli.command("uninstall-hook")
@click.pass_context
def uninstall_hook(ctx):
- """ Uninstall gitlint commit-msg hook. """
+ """Uninstall gitlint commit-msg hook."""
try:
hooks.GitHookInstaller.uninstall_commit_msg_hook(ctx.obj.