![](https://seccdn.libravatar.org/avatar/e2145bc5cf53dda95c308a3c75e8fef3.jpg?s=120&d=mm&r=g)
Hello community, here is the log from the commit of package gitlint for openSUSE:Factory checked in at 2019-07-05 13:49:11 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/gitlint (Old) and /work/SRC/openSUSE:Factory/.gitlint.new.4615 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "gitlint" Fri Jul 5 13:49:11 2019 rev:2 rq:713565 version:0.11.0 Changes: -------- --- /work/SRC/openSUSE:Factory/gitlint/gitlint.changes 2017-06-26 15:52:30.565578629 +0200 +++ /work/SRC/openSUSE:Factory/.gitlint.new.4615/gitlint.changes 2019-07-05 13:49:14.501501751 +0200 @@ -1,0 +2,11 @@ +Thu Jul 4 11:56:39 UTC 2019 - Rick Salevsky <rick.salevsky@suse.com> + +- Correct download target URL and fix relax-requirements.patch + +------------------------------------------------------------------- +Tue Jul 2 12:12:25 UTC 2019 - Rick Salevsky <rick.salevsky@suse.com> + +- Update to v0.11.0 + * add relax-requirements.patch to make it work with openSUSE + +------------------------------------------------------------------- Old: ---- gitlint-0.8.2.tar.gz New: ---- gitlint-0.11.0.tar.gz relax-requirements.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ gitlint.spec ++++++ --- /var/tmp/diff_new_pack.NBj2HW/_old 2019-07-05 13:49:15.281502953 +0200 +++ /var/tmp/diff_new_pack.NBj2HW/_new 2019-07-05 13:49:15.289502966 +0200 @@ -1,7 +1,7 @@ # -# spec file for package python-gitlint +# spec file for package gitlint # -# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -12,24 +12,30 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# Please submit bugfixes or comments via https://bugs.opensuse.org/ +# %define modname gitlint Name: %{modname} -Version: 0.8.2 +Version: 0.11.0 Release: 0 -License: MIT Summary: Git commit message linter checking -Url: https://github.com/jorisroovers/%{modname} +License: MIT Group: Development/Languages/Python -Source: https://files.pythonhosted.org/packages/source/g/%{modname}/%{modname}-%{version}.tar.gz -BuildRequires: python-rpm-macros +Url: https://github.com/jorisroovers/%{modname} +Source: https://pypi.io/packages/source/g/%{modname}/%{modname}-%{version}.tar.gz +# PATCH-FIX-OPENSUSE relax-requirements.patch -- relax requirements to work with openSUSE +Patch0: relax-requirements.patch BuildRequires: %{python_module devel} BuildRequires: %{python_module setuptools} +BuildRequires: fdupes +BuildRequires: python-rpm-macros Requires(post): update-alternatives Requires(postun): update-alternatives -BuildRequires: fdupes +Requires: python-arrow >= 0.10.0 +Requires: python-click >= 6.7 +Requires: python-sh >= 1.12.14 BuildArch: noarch %python_subpackages @@ -43,6 +49,7 @@ %prep %setup -q -n %{name}-%{version} +%patch0 -p1 %build %python_build ++++++ gitlint-0.8.2.tar.gz -> gitlint-0.11.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlint-0.8.2/PKG-INFO new/gitlint-0.11.0/PKG-INFO --- old/gitlint-0.8.2/PKG-INFO 2017-04-25 13:26:40.000000000 +0200 +++ new/gitlint-0.11.0/PKG-INFO 2019-03-13 14:16:59.000000000 +0100 @@ -1,13 +1,13 @@ Metadata-Version: 1.1 Name: gitlint -Version: 0.8.2 +Version: 0.11.0 Summary: Git commit message linter written in python, checks your commit messages for style. Home-page: https://github.com/jorisroovers/gitlint Author: Joris Roovers Author-email: UNKNOWN License: MIT Description: - Great for use as a commit-msg git hook or as part of your gating script in a CI/CD pipeline (e.g. jenkins). + Great for use as a commit-msg git hook or as part of your gating script in a CI pipeline (e.g. jenkins, gitlab). Many of the gitlint validations are based on `well-known`_ community_ `standards`_, others are based on checks that we've found useful throughout the years. Gitlint has sane defaults, but you can also easily customize it to your own liking. @@ -29,12 +29,12 @@ Classifier: Development Status :: 5 - Production/Stable Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Environment :: Console diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlint-0.8.2/README.md new/gitlint-0.11.0/README.md --- old/gitlint-0.8.2/README.md 2017-04-05 09:42:05.000000000 +0200 +++ new/gitlint-0.11.0/README.md 2019-03-13 14:11:18.000000000 +0100 @@ -5,16 +5,18 @@ [![PyPi Package](https://img.shields.io/pypi/v/gitlint.png)](https://pypi.python.org/pypi/gitlint) ![Supported Python Versions](https://img.shields.io/pypi/pyversions/gitlint.svg) -Git commit message linter written in python, checks your commit messages for style. +Git commit message linter written in python (for Linux and Mac), checks your commit messages for style. -**See [jorisroovers.github.io/gitlint/](http://jorisroovers.github.io/gitlint/) for full documentation.** +**See [jorisroovers.github.io/gitlint](http://jorisroovers.github.io/gitlint/) for full documentation.** <a href="http://jorisroovers.github.io/gitlint/" target="_blank"><img src="https://asciinema.org/a/30477.png" width="640"/></a> ## Contributing ## All contributions are welcome and very much appreciated! +** I'm looking for contributors that are interested in taking a more active co-maintainer role as it's becoming increasingly difficult for me to find time to maintain gitlint. Please open a PR if you're interested - Thanks! ** + See [jorisroovers.github.io/gitlint/contributing](http://jorisroovers.github.io/gitlint/contributing) for details on -how to get started - it's easy! +how to get started - it's easy! FYI, we maintain a [wishlist on our wiki](https://github.com/jorisroovers/gitlint/wiki/Wishlist). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlint-0.8.2/gitlint/__init__.py new/gitlint-0.11.0/gitlint/__init__.py --- old/gitlint-0.8.2/gitlint/__init__.py 2017-04-25 13:03:27.000000000 +0200 +++ new/gitlint-0.11.0/gitlint/__init__.py 2019-03-13 13:53:55.000000000 +0100 @@ -1 +1 @@ -__version__ = "0.8.2" +__version__ = "0.11.0" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlint-0.8.2/gitlint/cli.py new/gitlint-0.11.0/gitlint/cli.py --- old/gitlint-0.8.2/gitlint/cli.py 2017-04-25 12:17:33.000000000 +0200 +++ new/gitlint-0.11.0/gitlint/cli.py 2019-03-13 10:29:52.000000000 +0100 @@ -1,10 +1,11 @@ # pylint: disable=bad-option-value,wrong-import-position # We need to disable the import position checks because of the windows check that we need to do below +import copy import logging import os import platform +import stat import sys - import click # Error codes @@ -23,7 +24,7 @@ import gitlint from gitlint.lint import GitLinter from gitlint.config import LintConfigBuilder, LintConfigError, LintConfigGenerator -from gitlint.git import GitContext, GitContextError +from gitlint.git import GitContext, GitContextError, git_version from gitlint import hooks from gitlint.utils import ustr, LOG_FORMAT @@ -46,6 +47,13 @@ root_log.setLevel(logging.ERROR) +def log_system_info(): + LOG.debug("Platform: %s", platform.platform()) + LOG.debug("Python version: %s", sys.version) + LOG.debug("Git version: %s", git_version()) + LOG.debug("Gitlint version: %s", gitlint.__version__) + + def build_config(ctx, target, config_path, c, extra_path, ignore, verbose, silent, debug): """ Creates a LintConfig object based on a set of commandline parameters. """ config_builder = LintConfigBuilder() @@ -78,8 +86,6 @@ config_builder.set_option('general', 'debug', debug) config = config_builder.build() - if debug: - click.echo(ustr(config), nl=True) return config, config_builder except LintConfigError as e: @@ -87,6 +93,38 @@ ctx.exit(CONFIG_ERROR_CODE) # return CONFIG_ERROR_CODE on config error +def get_stdin_data(): + """ Helper function that returns data send to stdin or False if nothing is send """ + # 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) + # 3. A regular file (stat.S_ISREG) + # Technically, STDIN can also be other device type like a named unix socket (stat.S_ISSOCK), but we don't + # support that in gitlint (at least not today). + # + # Now, the behavior that we want is the following: + # If someone sends something directly to gitlint via a pipe or a regular file, read it. If not, read from the + # local repository. + # Note that we don't care about whether STDIN is a TTY or not, we only care whether data is via a pipe or regular + # file. + # However, in case STDIN is not a TTY, it HAS to be one of the 2 other things (pipe or regular file), even if + # no-one is actually sending anything to gitlint over them. In this case, we still want to read from the local + # repository. + # To support this use-case (which is common in CI runners such as Jenkins and Gitlab), we need to actually attempt + # to read from STDIN in case it's a pipe or regular file. In case that fails, then we'll fall back to reading + # from the local repo. + + mode = os.fstat(sys.stdin.fileno()).st_mode + stdin_is_pipe_or_file = stat.S_ISFIFO(mode) or stat.S_ISREG(mode) + if stdin_is_pipe_or_file: + input_data = sys.stdin.read() + # 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 False + + @click.group(invoke_without_command=True, epilog="When no COMMAND is specified, gitlint defaults to 'gitlint lint'.") @click.option('--target', type=click.Path(exists=True, resolve_path=True, file_okay=False, readable=True), help="Path of the target git repository. [default: current working directory]") @@ -95,31 +133,44 @@ @click.option('-c', multiple=True, help="Config flags in format <rule>.<option>=<value> (e.g.: -c T1.line-length=80). " + "Flag can be used multiple times to set multiple config values.") # pylint: disable=bad-continuation -@click.option('--commits', default="HEAD", help="The range of commits to lint. [default: HEAD]") +@click.option('--commits', default=None, help="The range of commits to lint. [default: HEAD]") @click.option('-e', '--extra-path', help="Path to a directory or python module with extra user-defined rules", type=click.Path(exists=True, resolve_path=True, readable=True)) @click.option('--ignore', default="", help="Ignore rules (comma-separated by id or name).") +@click.option('--msg-filename', type=click.File(), help="Path to a file containing a commit-msg.") @click.option('-v', '--verbose', count=True, default=0, help="Verbosity, more v's for more verbose output (e.g.: -v, -vv, -vvv). [default: -vvv]", ) @click.option('-s', '--silent', help="Silent mode (no output). Takes precedence over -v, -vv, -vvv.", is_flag=True) @click.option('-d', '--debug', help="Enable debugging output.", is_flag=True) @click.version_option(version=gitlint.__version__) @click.pass_context -def cli(ctx, target, config, c, commits, extra_path, ignore, verbose, silent, debug): +def cli( # pylint: disable=too-many-arguments + ctx, target, config, c, commits, extra_path, ignore, msg_filename, + verbose, silent, debug, +): """ Git lint tool, checks your git commit messages for styling issues """ - if debug: - logging.getLogger("gitlint").setLevel(logging.DEBUG) + try: + if debug: + logging.getLogger("gitlint").setLevel(logging.DEBUG) + + log_system_info() + + # 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(ctx, target, config, c, extra_path, ignore, verbose, silent, debug) + + LOG.debug(u"Configuration\n%s", ustr(config)) - # 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(ctx, target, config, c, extra_path, ignore, verbose, silent, debug) - - ctx.obj = (config, config_builder, commits) - - # If no subcommand is specified, then just lint - if ctx.invoked_subcommand is None: - ctx.invoke(lint) + ctx.obj = (config, config_builder, commits, msg_filename) + + # If no subcommand is specified, then just lint + if ctx.invoked_subcommand is None: + ctx.invoke(lint) + + except GitContextError as e: + click.echo(ustr(e)) + ctx.exit(GIT_CONTEXT_ERROR_CODE) @cli.command("lint") @@ -127,23 +178,30 @@ def lint(ctx): """ Lints a git repository [default command] """ lint_config = ctx.obj[0] - try: - if sys.stdin.isatty(): - # If target has not been set explicitly before, fallback to the current directory - gitcontext = GitContext.from_local_repository(lint_config.target, ctx.obj[2]) - else: - stdin_str = ustr(sys.stdin.read()) - gitcontext = GitContext.from_commit_msg(stdin_str) - except GitContextError as e: - click.echo(ustr(e)) - ctx.exit(GIT_CONTEXT_ERROR_CODE) + msg_filename = ctx.obj[3] + + # Let's determine where our input data is coming from: + # Order of precedence: + # 1. Any data specified via --msg-filename + # 2. Any data sent to stdin + # 3. Fallback to reading from local repository + stdin_input = get_stdin_data() + if msg_filename: + LOG.debug("Attempting to read from --msg-filename.") + gitcontext = GitContext.from_commit_msg(ustr(msg_filename.read())) + elif stdin_input: + LOG.debug("No --msg-filename flag. Attempting to read from stdin.") + gitcontext = GitContext.from_commit_msg(stdin_input) + else: + LOG.debug("No --msg-filename flag, no or empty data passed to stdin. Attempting to read from the local repo.") + gitcontext = GitContext.from_local_repository(lint_config.target, ctx.obj[2]) number_of_commits = len(gitcontext.commits) # Exit if we don't have commits in the specified range. Use a 0 exit code, since a popular use-case is one # where users are using --commits in a check job to check the commit messages inside a CI job. By returning 0, we # ensure that these jobs don't fail if for whatever reason the specified commit range is empty. if number_of_commits == 0: - click.echo(u'No commits in range "{0}".'.format(ctx.obj[2])) + LOG.debug(u'No commits in range "%s"', ctx.obj[2]) ctx.exit(0) general_config_builder = ctx.obj[1] @@ -153,13 +211,16 @@ first_violation = True exit_code = 0 for commit in gitcontext.commits: - # Build a config_builder and linter taking into account the commit specific config (if any) + # Build a config_builder taking into account the commit specific config (if any) config_builder = general_config_builder.clone() config_builder.set_config_from_commit(commit) - lint_config = config_builder.build(lint_config) - linter = GitLinter(lint_config) + + # Create a deepcopy from the original config, so we have a unique config object per commit + # This is important for configuration rules to be able to modifying the config on a per commit basis + commit_config = config_builder.build(copy.deepcopy(lint_config)) # Actually do the linting + linter = GitLinter(commit_config) violations = linter.lint(commit) # exit code equals the total number of violations in all commits exit_code += len(violations) @@ -234,4 +295,5 @@ # Let's Party! setup_logging() if __name__ == "__main__": - cli() # pragma: no cover, # pylint: disable=no-value-for-parameter + # pylint: disable=no-value-for-parameter + cli() # pragma: no cover diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlint-0.8.2/gitlint/config.py new/gitlint-0.11.0/gitlint/config.py --- old/gitlint-0.8.2/gitlint/config.py 2017-04-25 11:04:57.000000000 +0200 +++ new/gitlint-0.11.0/gitlint/config.py 2019-03-13 13:17:13.000000000 +0100 @@ -46,7 +46,9 @@ """ # Default tuple of rule classes (tuple because immutable). - default_rule_classes = (rules.TitleMaxLength, + default_rule_classes = (rules.IgnoreByTitle, + rules.IgnoreByBody, + rules.TitleMaxLength, rules.TitleTrailingWhitespace, rules.TitleLeadingWhitespace, rules.TitleTrailingPunctuation, @@ -59,13 +61,16 @@ rules.BodyTrailingWhitespace, rules.BodyHardTab, rules.BodyFirstLineEmpty, - rules.BodyChangedFileMention) + rules.BodyChangedFileMention, + rules.AuthorValidEmail) def __init__(self): # Use an ordered dict so that the order in which rules are applied is always the same self._rules = OrderedDict([(rule_cls.id, rule_cls()) for rule_cls in self.default_rule_classes]) self._verbosity = options.IntOption('verbosity', 3, "Verbosity") self._ignore_merge_commits = options.BoolOption('ignore-merge-commits', True, "Ignore merge commits") + self._ignore_fixup_commits = options.BoolOption('ignore-fixup-commits', True, "Ignore fixup commits") + self._ignore_squash_commits = options.BoolOption('ignore-squash-commits', True, "Ignore squash commits") self._debug = options.BoolOption('debug', False, "Enable debug mode") self._extra_path = None target_description = "Path of the target git repository (default=current working directory)" @@ -103,6 +108,24 @@ return self._ignore_merge_commits.set(value) @property + def ignore_fixup_commits(self): + return self._ignore_fixup_commits.value + + @ignore_fixup_commits.setter + @handle_option_error + def ignore_fixup_commits(self, value): + return self._ignore_fixup_commits.set(value) + + @property + def ignore_squash_commits(self): + return self._ignore_squash_commits.value + + @ignore_squash_commits.setter + @handle_option_error + def ignore_squash_commits(self, value): + return self._ignore_squash_commits.set(value) + + @property def debug(self): return self._debug.value @@ -202,8 +225,9 @@ # only allow setting general options that exist and don't start with an underscore if not hasattr(self, attr_name) or attr_name[0] == "_": raise LintConfigError(u"'{0}' is not a valid gitlint option".format(option_name)) - else: - setattr(self, attr_name, option_value) + + # else: + setattr(self, attr_name, option_value) def __eq__(self, other): return isinstance(other, LintConfig) and \ @@ -212,6 +236,8 @@ self.target == other.target and \ self.extra_path == other.extra_path and \ self.ignore_merge_commits == other.ignore_merge_commits and \ + self.ignore_fixup_commits == other.ignore_fixup_commits and \ + self.ignore_squash_commits == other.ignore_squash_commits and \ self.debug == other.debug and \ self.ignore == other.ignore and \ self._config_path == other._config_path # noqa @@ -223,13 +249,15 @@ return_str += u"extra-path: {0}\n".format(self.extra_path) return_str += u"ignore: {0}\n".format(",".join(self.ignore)) return_str += u"ignore-merge-commits: {0}\n".format(self.ignore_merge_commits) + return_str += u"ignore-fixup-commits: {0}\n".format(self.ignore_fixup_commits) + return_str += u"ignore-squash-commits: {0}\n".format(self.ignore_squash_commits) return_str += u"verbosity: {0}\n".format(self.verbosity) return_str += u"debug: {0}\n".format(self.debug) return_str += u"target: {0}\n".format(self.target) return_str += u"[RULES]\n" for rule in self.rules: return_str += u" {0}: {1}\n".format(rule.id, rule.name) - for option_name, option_value in rule.options.items(): + for option_name, option_value in sorted(rule.options.items()): if isinstance(option_value.value, list): option_val_repr = ",".join(option_value.value) else: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlint-0.8.2/gitlint/files/commit-msg new/gitlint-0.11.0/gitlint/files/commit-msg --- old/gitlint-0.8.2/gitlint/files/commit-msg 2016-12-01 21:37:44.000000000 +0100 +++ new/gitlint-0.11.0/gitlint/files/commit-msg 2018-04-02 11:59:07.000000000 +0200 @@ -26,7 +26,7 @@ run_gitlint(){ echo "gitlint: checking commit message..." - cat "$1" | python -m gitlint.cli + python -m gitlint.cli --msg-filename "$1" gitlint_exit_code=$? } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlint-0.8.2/gitlint/files/gitlint new/gitlint-0.11.0/gitlint/files/gitlint --- old/gitlint-0.8.2/gitlint/files/gitlint 2016-12-02 15:21:52.000000000 +0100 +++ new/gitlint-0.11.0/gitlint/files/gitlint 2018-04-02 11:59:07.000000000 +0200 @@ -1,10 +1,20 @@ # All these sections are optional, edit this file as you like. # [general] +# Ignore certain rules, you can reference them by their id or by their full name # ignore=title-trailing-punctuation, T3 + # verbosity should be a value between 1 and 3, the commandline -v flags take precedence over this # verbosity = 2 + # By default gitlint will ignore merge commits. Set to 'false' to disable. # ignore-merge-commits=true + +# By default gitlint will ignore fixup commits. Set to 'false' to disable. +# ignore-fixup-commits=true + +# By default gitlint will ignore squash commits. Set to 'false' to disable. +# ignore-squash-commits=true + # Enable debug mode (prints more output). Disabled by default. # debug=true @@ -46,3 +56,27 @@ # By specifying this rule, developers can only change the file when they explicitly reference # it in the commit message. # files=gitlint/rules.py,README.md + +# [author-valid-email] +# python like regex (https://docs.python.org/2/library/re.html) that the +# commit author email address should be matched to +# For example, use the following regex if you only want to allow email addresses from foo.com +# regex=[^@]+@foo.com + +# [ignore-by-title] +# Ignore certain rules for commits of which the title matches a regex +# E.g. Match commit titles that start with "Release" +# regex=^Release(.*) +# +# Ignore certain rules, you can reference them by their id or by their full name +# Use 'all' to ignore all rules +# ignore=T1,body-min-length + +# [ignore-by-body] +# Ignore certain rules for commits of which the body has a line that matches a regex +# E.g. Match bodies that have a line that that contain "release" +# regex=(.*)release(.*) +# +# Ignore certain rules, you can reference them by their id or by their full name +# Use 'all' to ignore all rules +# ignore=T1,body-min-length \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlint-0.8.2/gitlint/git.py new/gitlint-0.11.0/gitlint/git.py --- old/gitlint-0.8.2/gitlint/git.py 2017-03-14 10:16:31.000000000 +0100 +++ new/gitlint-0.11.0/gitlint/git.py 2019-03-13 12:27:10.000000000 +0100 @@ -11,6 +11,51 @@ pass +class GitNotInstalledError(GitContextError): + def __init__(self): + super(GitNotInstalledError, self).__init__( + u"'git' command not found. You need to install git to use gitlint on a local repository. " + + u"See https://git-scm.com/book/en/v2/Getting-Started-Installing-Git on how to install git.") + + +def _git(*command_parts, **kwargs): + """ Convenience function for running git commands. Automatically deals with exceptions and unicode. """ + # Special arguments passed to sh: http://amoffat.github.io/sh/special_arguments.html + git_kwargs = {'_tty_out': False} + git_kwargs.update(kwargs) + try: + result = sh.git(*command_parts, **git_kwargs) # pylint: disable=unexpected-keyword-arg + # If we reach this point and the result has an exit_code that is larger than 0, this means that we didn't + # get an exception (which is the default sh behavior for non-zero exit codes) and so the user is expecting + # a non-zero exit code -> just return the entire result + if hasattr(result, 'exit_code') and result.exit_code > 0: + return result + return ustr(result) + except CommandNotFound: + raise GitNotInstalledError() + except ErrorReturnCode as e: # Something went wrong while executing the git command + error_msg = e.stderr.strip() + if '_cwd' in git_kwargs and b"not a git repository" in error_msg.lower(): + error_msg = u"{0} is not a git repository.".format(git_kwargs['_cwd']) + else: + error_msg = u"An error occurred while executing '{0}': {1}".format(e.full_cmd, error_msg) + raise GitContextError(error_msg) + + +def git_version(): + """ Determine the git version installed on this host by calling git --version""" + return _git("--version").replace(u"\n", u"") + + +def git_commentchar(): + """ Shortcut for retrieving comment char from git config """ + commentchar = _git("config", "--get", "core.commentchar", _ok_code=[1]) + # git will return an exit code of 1 if it can't find a config value, in this case we fall-back to # as commentchar + if hasattr(commentchar, 'exit_code') and commentchar.exit_code == 1: # pylint: disable=no-member + commentchar = "#" + return ustr(commentchar).replace(u"\n", u"") + + class GitCommitMessage(object): """ Class representing a git commit message. A commit message consists of the following: - original: The actual commit message as returned by `git log` @@ -18,6 +63,8 @@ - title: the first line of full - body: all lines following the title """ + COMMENT_CHAR = git_commentchar() + CUTLINE = '{0} ------------------------ >8 ------------------------'.format(COMMENT_CHAR) def __init__(self, original=None, full=None, title=None, body=None): self.original = original @@ -28,9 +75,14 @@ @staticmethod def from_full_message(commit_msg_str): """ Parses a full git commit message by parsing a given string into the different parts of a commit message """ - lines = [line for line in commit_msg_str.splitlines() if not line.startswith("#")] + all_lines = commit_msg_str.splitlines() + try: + cutline_index = all_lines.index(GitCommitMessage.CUTLINE) + except ValueError: + cutline_index = None + lines = [line for line in all_lines[:cutline_index] if not line.startswith(GitCommitMessage.COMMENT_CHAR)] full = "\n".join(lines) - title = lines[0] if len(lines) > 0 else "" + title = lines[0] if lines else "" body = lines[1:] if len(lines) > 1 else [] return GitCommitMessage(original=commit_msg_str, full=full, title=title, body=body) @@ -38,7 +90,7 @@ return self.full # pragma: no cover def __str__(self): - return sstr(self) # pragma: no cover + return sstr(self.__unicode__()) # pragma: no cover def __repr__(self): return self.__str__() # pragma: no cover @@ -54,8 +106,9 @@ In the context of gitlint, only the git context and commit message are required. """ - def __init__(self, context, message, sha=None, date=None, author_name=None, author_email=None, parents=None, - is_merge_commit=False, changed_files=None): + def __init__(self, context, message, sha=None, date=None, author_name=None, # pylint: disable=too-many-arguments + author_email=None, parents=None, is_merge_commit=None, is_fixup_commit=None, + is_squash_commit=None, changed_files=None): self.context = context self.message = message self.sha = sha @@ -64,15 +117,19 @@ self.author_email = author_email # parent commit hashes self.parents = parents or [] - self.is_merge_commit = is_merge_commit self.changed_files = changed_files or [] + # If it's not explicitely specified, we consider a commit a merge commit if its title starts with "Merge" + self.is_merge_commit = message.title.startswith(u"Merge") if is_merge_commit is None else is_merge_commit + self.is_fixup_commit = message.title.startswith(u"fixup!") if is_fixup_commit is None else is_fixup_commit + self.is_squash_commit = message.title.startswith(u"squash!") if is_squash_commit is None else is_squash_commit + def __unicode__(self): format_str = u"Author: %s <%s>\nDate: %s\n%s" # pragma: no cover return format_str % (self.author_name, self.author_email, self.date, ustr(self.message)) # pragma: no cover def __str__(self): - return sstr(self) # pragma: no cover + return sstr(self.__unicode__()) # pragma: no cover def __repr__(self): return self.__str__() # pragma: no cover @@ -83,7 +140,8 @@ self.sha == other.sha and self.author_name == other.author_name and \ self.author_email == other.author_email and \ self.date == other.date and self.parents == other.parents and \ - self.is_merge_commit == other.is_merge_commit and self.changed_files == other.changed_files # noqa + self.is_merge_commit == other.is_merge_commit and self.is_fixup_commit == other.is_fixup_commit and \ + self.is_squash_commit == other.is_squash_commit and self.changed_files == other.changed_files # noqa class GitContext(object): @@ -102,73 +160,55 @@ context = GitContext() commit_msg_obj = GitCommitMessage.from_full_message(commit_msg_str) - # For now, we consider a commit a merge commit if its title starts with "Merge" - is_merge_commit = commit_msg_obj.title.startswith("Merge") - commit = GitCommit(context, commit_msg_obj, is_merge_commit=is_merge_commit) + commit = GitCommit(context, commit_msg_obj) context.commits.append(commit) return context @staticmethod - def from_local_repository(repository_path, refspec="HEAD"): + def from_local_repository(repository_path, refspec=None): """ Retrieves the git context from a local git repository. :param repository_path: Path to the git repository to retrieve the context from :param refspec: The commit(s) to retrieve """ context = GitContext() - try: - # Special arguments passed to sh: http://amoffat.github.io/sh/special_arguments.html - sh_special_args = { - '_tty_out': False, - '_cwd': repository_path - } - - sha_list = sh.git("rev-list", - # If refspec contains a dot it is a range - # eg HEAD^.., upstream/master...HEAD - '--max-count={0}'.format(-1 if "." in refspec else 1), - refspec, **sh_special_args).split() - - for sha in sha_list: - # Get info from the local git repository: https://git-scm.com/docs/pretty-formats - raw_commit = sh.git.log(sha, "-1", "--pretty=%aN,%aE,%ai,%P%n%B", - **sh_special_args).split("\n") - - (name, email, date, parents), commit_msg = raw_commit[0].split(","), "\n".join(raw_commit[1:]) - - commit_parents = parents.split(" ") - commit_is_merge_commit = len(commit_parents) > 1 - - # changed files in last commit - changed_files = sh.git("diff-tree", "--no-commit-id", "--name-only", - "-r", sha, **sh_special_args).split() - - # "YYYY-MM-DD HH:mm:ss Z" -> ISO 8601-like format - # Use arrow for datetime parsing, because apparently python is quirky around ISO-8601 dates: - # http://stackoverflow.com/a/30696682/381010 - commit_date = arrow.get(ustr(date), "YYYY-MM-DD HH:mm:ss Z").datetime - - # Create Git commit object with the retrieved info - commit_msg_obj = GitCommitMessage.from_full_message(commit_msg) - commit = GitCommit(context, commit_msg_obj, sha=sha, author_name=name, - author_email=email, date=commit_date, changed_files=changed_files, - parents=commit_parents, is_merge_commit=commit_is_merge_commit) - - context.commits.append(commit) - - except CommandNotFound: - raise GitContextError( - u"'git' command not found. You need to install git to use gitlint on a local repository. " - u"See https://git-scm.com/book/en/v2/Getting-Started-Installing-Git on how to install git." - ) - except ErrorReturnCode as e: # Something went wrong while executing the git command - error_msg = e.stderr.strip() - if b"Not a git repository" in error_msg: - error_msg = u"{0} is not a git repository.".format(repository_path) - else: - error_msg = u"An error occurred while executing '{0}': {1}".format(e.full_cmd, error_msg) - raise GitContextError(error_msg) + + # If no refspec is defined, fallback to the last commit on the current branch + if refspec is None: + # We tried many things here e.g.: defaulting to e.g. HEAD or HEAD^... (incl. dealing with + # repos that only have a single commit - HEAD^... doesn't work there), but then we still get into + # problems with e.g. merge commits. Easiest solution is just taking the SHA from `git log -1`. + sha_list = [_git("log", "-1", "--pretty=%H", _cwd=repository_path).replace(u"\n", u"")] + else: + sha_list = _git("rev-list", refspec, _cwd=repository_path).split() + + for sha in sha_list: + # Get info from the local git repository: https://git-scm.com/docs/pretty-formats + long_format = "--pretty=%aN%x00%aE%x00%ai%x00%P%n%B" + raw_commit = _git("log", sha, "-1", long_format, _cwd=repository_path).split("\n") + + (name, email, date, parents), commit_msg = raw_commit[0].split('\x00'), "\n".join(raw_commit[1:]) + + commit_parents = parents.split(" ") + commit_is_merge_commit = len(commit_parents) > 1 + + # changed files in last commit + changed_files = _git("diff-tree", "--no-commit-id", "--name-only", "-r", sha, _cwd=repository_path).split() + + # "YYYY-MM-DD HH:mm:ss Z" -> ISO 8601-like format + # Use arrow for datetime parsing, because apparently python is quirky around ISO-8601 dates: + # http://stackoverflow.com/a/30696682/381010 + commit_date = arrow.get(ustr(date), "YYYY-MM-DD HH:mm:ss Z").datetime + + # Create Git commit object with the retrieved info + commit_msg_obj = GitCommitMessage.from_full_message(commit_msg) + + commit = GitCommit(context, commit_msg_obj, sha=sha, author_name=name, + author_email=email, date=commit_date, changed_files=changed_files, + parents=commit_parents, is_merge_commit=commit_is_merge_commit) + + context.commits.append(commit) return context diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlint-0.8.2/gitlint/lint.py new/gitlint-0.11.0/gitlint/lint.py --- old/gitlint-0.8.2/gitlint/lint.py 2017-04-25 11:14:33.000000000 +0200 +++ new/gitlint-0.11.0/gitlint/lint.py 2019-03-13 10:29:52.000000000 +0100 @@ -1,6 +1,8 @@ +# pylint: disable=logging-not-lazy import logging from gitlint import rules as gitlint_rules from gitlint import display +from gitlint.utils import ustr LOG = logging.getLogger(__name__) logging.basicConfig() @@ -14,25 +16,31 @@ self.display = display.Display(config) - def ignore_rule(self, rule): + def should_ignore_rule(self, rule): + """ Determines whether a rule should be ignored based on the general list of commits to ignore """ return rule.id in self.config.ignore or rule.name in self.config.ignore @property + def configuration_rules(self): + return [rule for rule in self.config.rules if + isinstance(rule, gitlint_rules.ConfigurationRule) and not self.should_ignore_rule(rule)] + + @property def title_line_rules(self): return [rule for rule in self.config.rules if isinstance(rule, gitlint_rules.LineRule) and - rule.target == gitlint_rules.CommitMessageTitle and not self.ignore_rule(rule)] + rule.target == gitlint_rules.CommitMessageTitle and not self.should_ignore_rule(rule)] @property def body_line_rules(self): return [rule for rule in self.config.rules if isinstance(rule, gitlint_rules.LineRule) and - rule.target == gitlint_rules.CommitMessageBody and not self.ignore_rule(rule)] + rule.target == gitlint_rules.CommitMessageBody and not self.should_ignore_rule(rule)] @property def commit_rules(self): return [rule for rule in self.config.rules if isinstance(rule, gitlint_rules.CommitRule) and - not self.ignore_rule(rule)] + not self.should_ignore_rule(rule)] @staticmethod def _apply_line_rules(lines, commit, rules, line_nr_start): @@ -60,11 +68,20 @@ return all_violations def lint(self, commit): - """ Lint the last commit in a given git context by applying all title, body and general rules. """ + """ Lint the last commit in a given git context by applying all ignore, title, body and commit rules. """ LOG.debug("Linting commit %s", commit.sha or "[SHA UNKNOWN]") - # Skip linting if this is merge commit and if the config is set to ignore those - if commit.is_merge_commit and self.config.ignore_merge_commits: - return [] + LOG.debug("Commit Object\n" + ustr(commit)) + + # Apply config rules + for rule in self.configuration_rules: + rule.apply(self.config, commit) + + # Skip linting if this is a special commit type that is configured to be ignored + ignore_commit_types = ["merge", "squash", "fixup"] + for commit_type in ignore_commit_types: + if getattr(commit, "is_{0}_commit".format(commit_type)) and \ + getattr(self.config, "ignore_{0}_commits".format(commit_type)): + return [] violations = [] # determine violations by applying all rules @@ -72,17 +89,20 @@ violations.extend(self._apply_line_rules(commit.message.body, commit, self.body_line_rules, 2)) violations.extend(self._apply_commit_rules(self.commit_rules, commit)) - # sort violations by line number - violations.sort(key=lambda v: (v.line_nr, v.rule_id)) # sort violations by line number and rule_id + # Sort violations by line number and rule_id. If there's no line nr specified (=common certain commit rules), + # we replace None with -1 so that it always get's placed first. Note that we need this to do this to support + # python 3, as None is not allowed in a list that is being sorted. + violations.sort(key=lambda v: (-1 if v.line_nr is None else v.line_nr, v.rule_id)) return violations def print_violations(self, violations): """ Print a given set of violations to the standard error output """ for v in violations: - self.display.e(u"{0}: {1}".format(v.line_nr, v.rule_id), exact=True) - self.display.ee(u"{0}: {1} {2}".format(v.line_nr, v.rule_id, v.message), exact=True) + line_nr = v.line_nr if v.line_nr else "-" + self.display.e(u"{0}: {1}".format(line_nr, v.rule_id), exact=True) + self.display.ee(u"{0}: {1} {2}".format(line_nr, v.rule_id, v.message), exact=True) if v.content: - self.display.eee(u"{0}: {1} {2}: \"{3}\"".format(v.line_nr, v.rule_id, v.message, v.content), + self.display.eee(u"{0}: {1} {2}: \"{3}\"".format(line_nr, v.rule_id, v.message, v.content), exact=True) else: - self.display.eee(u"{0}: {1} {2}".format(v.line_nr, v.rule_id, v.message), exact=True) + self.display.eee(u"{0}: {1} {2}".format(line_nr, v.rule_id, v.message), exact=True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlint-0.8.2/gitlint/rules.py new/gitlint-0.11.0/gitlint/rules.py --- old/gitlint-0.8.2/gitlint/rules.py 2016-12-30 14:24:17.000000000 +0100 +++ new/gitlint-0.11.0/gitlint/rules.py 2019-03-13 10:29:52.000000000 +0100 @@ -1,9 +1,14 @@ +# pylint: disable=inconsistent-return-statements import copy +import logging import re from gitlint.options import IntOption, BoolOption, StrOption, ListOption from gitlint.utils import sstr +LOG = logging.getLogger(__name__) +logging.basicConfig() + class Rule(object): """ Class representing gitlint rules. """ @@ -36,6 +41,11 @@ return self.__str__() # pragma: no cover +class ConfigurationRule(Rule): + """ Class representing rules that can dynamically change the configuration of gitlint during runtime. """ + pass + + class CommitRule(Rule): """ Class representing rules that act on an entire commit at once """ pass @@ -253,7 +263,7 @@ min_length = self.options['min-length'].value body_message_no_newline = "".join([line for line in commit.message.body if line is not None]) actual_length = len(body_message_no_newline) - if actual_length > 0 and actual_length < min_length: + if 0 < actual_length < min_length: violation_message = "Body message is too short ({0}<{1})".format(actual_length, min_length) return [RuleViolation(self.id, violation_message, body_message_no_newline, 3)] @@ -286,3 +296,57 @@ violation_message = u"Body does not mention changed file '{0}'".format(needs_mentioned_file) violations.append(RuleViolation(self.id, violation_message, None, len(commit.message.body) + 1)) return violations if violations else None + + +class AuthorValidEmail(CommitRule): + name = "author-valid-email" + id = "M1" + options_spec = [StrOption('regex', "[^@ ]+@[^@ ]+\.[^@ ]+", "Regex that author email address should match")] + + def validate(self, commit): + # Note that unicode is allowed in email addresses + # See http://stackoverflow.com/questions/3844431 + # /are-email-addresses-allowed-to-contain-non-alphanumeric-characters + email_regex = re.compile(self.options['regex'].value, re.UNICODE) + + if commit.author_email and not email_regex.match(commit.author_email): + return [RuleViolation(self.id, "Author email for commit is invalid", commit.author_email)] + + +class IgnoreByTitle(ConfigurationRule): + name = "ignore-by-title" + id = "I1" + options_spec = [StrOption('regex', None, "Regex matching the titles of commits this rule should apply to"), + StrOption('ignore', "all", "Comman-seperate list of rules to ignore")] + + def apply(self, config, commit): + title_regex = re.compile(self.options['regex'].value, re.UNICODE) + + if title_regex.match(commit.message.title): + config.ignore = self.options['ignore'].value + + message = u"Commit title '{0}' matches the regex '{1}', ignoring rules: {2}" + message = message.format(commit.message.title, self.options['regex'].value, self.options['ignore'].value) + + LOG.debug("Ignoring commit because of rule '%s': %s", self.id, message) + + +class IgnoreByBody(ConfigurationRule): + name = "ignore-by-body" + id = "I2" + options_spec = [StrOption('regex', None, "Regex matching lines of the body of commits this rule should apply to"), + StrOption('ignore', "all", "Comman-seperate list of rules to ignore")] + + def apply(self, config, commit): + body_line_regex = re.compile(self.options['regex'].value, re.UNICODE) + + for line in commit.message.body: + if body_line_regex.match(line): + config.ignore = self.options['ignore'].value + + message = u"Commit message line '{0}' matches the regex '{1}', ignoring rules: {2}" + message = message.format(line, self.options['regex'].value, self.options['ignore'].value) + + LOG.debug("Ignoring commit because of rule '%s': %s", self.id, message) + # No need to check other lines if we found a match + return diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlint-0.8.2/gitlint/user_rules.py new/gitlint-0.11.0/gitlint/user_rules.py --- old/gitlint-0.8.2/gitlint/user_rules.py 2017-04-25 12:34:00.000000000 +0200 +++ new/gitlint-0.11.0/gitlint/user_rules.py 2019-03-13 10:29:52.000000000 +0100 @@ -41,7 +41,7 @@ modules.append(os.path.splitext(filename)[0]) # No need to continue if there are no modules specified - if len(modules) == 0: + if not modules: return [] # Append the extra rules path to python path so that we can import them @@ -93,7 +93,7 @@ rules.LineRule.__name__, rules.CommitRule.__name__)) # Rules must have an id attribute - if not hasattr(clazz, 'id') or clazz.id is None or len(clazz.id) == 0: + if not hasattr(clazz, 'id') or clazz.id is None or not clazz.id: raise UserRuleError(u"User-defined rule class '{0}' must have an 'id' attribute".format(clazz.__name__)) # Rule id's cannot start with gitlint reserved letters @@ -102,7 +102,7 @@ raise UserRuleError(msg.format(clazz.__name__, clazz.id[0])) # Rules must have a name attribute - if not hasattr(clazz, 'name') or clazz.name is None or len(clazz.name) == 0: + if not hasattr(clazz, 'name') or clazz.name is None or not clazz.name: raise UserRuleError(u"User-defined rule class '{0}' must have a 'name' attribute".format(clazz.__name__)) # if set, options_spec must be a list of RuleOption diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlint-0.8.2/gitlint/utils.py new/gitlint-0.11.0/gitlint/utils.py --- old/gitlint-0.8.2/gitlint/utils.py 2017-04-25 12:17:39.000000000 +0200 +++ new/gitlint-0.11.0/gitlint/utils.py 2019-03-13 10:29:52.000000000 +0100 @@ -1,4 +1,4 @@ -# pylint: disable=bad-option-value,unidiomatic-typecheck,undefined-variable +# pylint: disable=bad-option-value,unidiomatic-typecheck,undefined-variable,no-else-return import sys from locale import getpreferredencoding @@ -17,7 +17,10 @@ else: return unicode(obj) # pragma: no cover # noqa else: - return str(obj) + if type(obj) in [bytes]: + return obj.decode(DEFAULT_ENCODING) + else: + return str(obj) def sstr(obj): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlint-0.8.2/gitlint.egg-info/PKG-INFO new/gitlint-0.11.0/gitlint.egg-info/PKG-INFO --- old/gitlint-0.8.2/gitlint.egg-info/PKG-INFO 2017-04-25 13:26:39.000000000 +0200 +++ new/gitlint-0.11.0/gitlint.egg-info/PKG-INFO 2019-03-13 14:16:59.000000000 +0100 @@ -1,13 +1,13 @@ Metadata-Version: 1.1 Name: gitlint -Version: 0.8.2 +Version: 0.11.0 Summary: Git commit message linter written in python, checks your commit messages for style. Home-page: https://github.com/jorisroovers/gitlint Author: Joris Roovers Author-email: UNKNOWN License: MIT Description: - Great for use as a commit-msg git hook or as part of your gating script in a CI/CD pipeline (e.g. jenkins). + Great for use as a commit-msg git hook or as part of your gating script in a CI pipeline (e.g. jenkins, gitlab). Many of the gitlint validations are based on `well-known`_ community_ `standards`_, others are based on checks that we've found useful throughout the years. Gitlint has sane defaults, but you can also easily customize it to your own liking. @@ -29,12 +29,12 @@ Classifier: Development Status :: 5 - Production/Stable Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Environment :: Console diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlint-0.8.2/gitlint.egg-info/requires.txt new/gitlint-0.11.0/gitlint.egg-info/requires.txt --- old/gitlint-0.8.2/gitlint.egg-info/requires.txt 2017-04-25 13:26:39.000000000 +0200 +++ new/gitlint-0.11.0/gitlint.egg-info/requires.txt 2019-03-13 14:16:59.000000000 +0100 @@ -1,9 +1,9 @@ -Click==6.6 +Click==6.7 arrow==0.10.0 -ordereddict==1.1 -[:python_version == "2.6"] +[:python_version < "2.7"] importlib==1.0.3 +ordereddict==1.1 [:sys_platform != "win32"] -sh==1.11 +sh==1.12.14 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlint-0.8.2/setup.cfg new/gitlint-0.11.0/setup.cfg --- old/gitlint-0.8.2/setup.cfg 2017-04-25 13:26:40.000000000 +0200 +++ new/gitlint-0.11.0/setup.cfg 2019-03-13 14:16:59.000000000 +0100 @@ -4,5 +4,4 @@ [egg_info] tag_build = tag_date = 0 -tag_svn_revision = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlint-0.8.2/setup.py new/gitlint-0.11.0/setup.py --- old/gitlint-0.8.2/setup.py 2017-03-14 10:22:45.000000000 +0100 +++ new/gitlint-0.11.0/setup.py 2019-03-13 13:26:51.000000000 +0100 @@ -1,7 +1,9 @@ #!/usr/bin/env python +from __future__ import print_function from setuptools import setup, find_packages import re import os +import sys # There is an issue with building python packages in a shared vagrant directory because of how setuptools works # in python < 2.7.9. We solve this by deleting the filesystem hardlinking capability during build. @@ -9,11 +11,11 @@ try: del os.link except: - pass # Not all OSes (e.g. windows) support os.link + pass # Not all OSes (e.g. windows) support os.link description = "Git commit message linter written in python, checks your commit messages for style." long_description = """ -Great for use as a commit-msg git hook or as part of your gating script in a CI/CD pipeline (e.g. jenkins). +Great for use as a commit-msg git hook or as part of your gating script in a CI pipeline (e.g. jenkins, gitlab). Many of the gitlint validations are based on `well-known`_ community_ `standards`_, others are based on checks that we've found useful throughout the years. Gitlint has sane defaults, but you can also easily customize it to your own liking. @@ -48,12 +50,12 @@ "Development Status :: 5 - Production/Stable", "Operating System :: OS Independent", "Programming Language :: Python", - "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Environment :: Console", @@ -63,16 +65,16 @@ "License :: OSI Approved :: MIT License" ], install_requires=[ - 'Click==6.6', - 'arrow==0.10.0', - 'ordereddict==1.1', + 'Click==6.7', + 'arrow==0.10.0' ], extras_require={ - ':python_version == "2.6"': [ + ':python_version < "2.7"': [ 'importlib==1.0.3', + 'ordereddict==1.1', ], ':sys_platform != "win32"': [ - 'sh==1.11', + 'sh==1.12.14', ], }, keywords='gitlint git lint', @@ -89,3 +91,9 @@ ], }, ) + +# Print a red deprecation warning for python 2.6 users +if sys.version_info[0] == 2 and sys.version_info[1] <= 6: + msg = "\033[31mDEPRECATION: Python 2.6 or below are no longer supported by gitlint or the Python core team." + \ + "Please upgrade your Python to a later version.\033[0m" + print(msg) ++++++ relax-requirements.patch ++++++ diff -u -r gitlint-0.11.0/gitlint.egg-info/requires.txt gitlint-0.11.0.patched/gitlint.egg-info/requires.txt --- gitlint-0.11.0/gitlint.egg-info/requires.txt 2019-03-13 14:16:59.000000000 +0100 +++ gitlint-0.11.0.patched/gitlint.egg-info/requires.txt 2019-07-04 15:34:32.604844335 +0200 @@ -1,9 +1,9 @@ -Click==6.7 -arrow==0.10.0 +Click>=6.7 +arrow>=0.10.0 [:python_version < "2.7"] -importlib==1.0.3 -ordereddict==1.1 +importlib>=1.0.3 +ordereddict>=1.1 [:sys_platform != "win32"] -sh==1.12.14 +sh>=1.12.14 diff -u -r gitlint-0.11.0/setup.py gitlint-0.11.0.patched/setup.py --- gitlint-0.11.0/setup.py 2019-03-13 13:26:51.000000000 +0100 +++ gitlint-0.11.0.patched/setup.py 2019-07-04 15:33:46.932567901 +0200 @@ -65,16 +65,16 @@ "License :: OSI Approved :: MIT License" ], install_requires=[ - 'Click==6.7', - 'arrow==0.10.0' + 'Click>=6.7', + 'arrow>=0.10.0' ], extras_require={ ':python_version < "2.7"': [ - 'importlib==1.0.3', - 'ordereddict==1.1', + 'importlib>=1.0.3', + 'ordereddict>=1.1', ], ':sys_platform != "win32"': [ - 'sh==1.12.14', + 'sh>=1.12.14', ], }, keywords='gitlint git lint',
participants (1)
-
root