def cli(config, c, ignore, verbose, silent): """ Git lint tool, checks your git commit messages for styling issues """ try: # Config precedence: # First, load default config or config from configfile lint_config = get_lint_config(config) # Then process any commandline configuration flags try: lint_config.apply_config_options(c) except LintConfigError as e: click.echo("Config Error: {}".format(e.message)) exit(CONFIG_ERROR_CODE) # Finally, overwrite with any convenience commandline flags lint_config.apply_on_csv_string(ignore, lint_config.disable_rule) if silent: lint_config.verbosity = 0 elif verbose > 0: lint_config.verbosity = verbose except LintConfigError as e: click.echo("Config Error: {0}".format(e.message)) exit(CONFIG_ERROR_CODE) # return 10000 on config error if sys.stdin.isatty(): gitcontext = GitContext.from_environment() else: gitcontext = GitContext() gitcontext.set_commit_msg(sys.stdin.read()) linter = GitLinter(lint_config) violations = linter.lint(gitcontext) linter.print_violations(violations) exit(len(violations))
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) else: gitcontext = GitContext.from_commit_msg(sys.stdin.read()) except GitContextError as e: click.echo(str(e)) ctx.exit(GIT_CONTEXT_ERROR_CODE) config_builder = ctx.obj[1] last_commit = gitcontext.commits[-1] # Apply an additional config that is specified in the last commit message config_builder.set_config_from_commit(last_commit) lint_config = config_builder.build(lint_config) # Let's get linting! linter = GitLinter(lint_config) violations = linter.lint(last_commit) linter.print_violations(violations) exit_code = min(MAX_VIOLATION_ERROR_CODE, len(violations)) ctx.exit(exit_code)
def lint(ctx): """ Lints a git repository [default command] """ lint_config = ctx.obj.config refspec = ctx.obj.refspec msg_filename = ctx.obj.msg_filename gitcontext = build_git_context(lint_config, msg_filename, refspec) # Set gitcontext in the click context, so we can use it in command that are ran after this # in particular, this is used by run-hook ctx.obj.gitcontext = gitcontext 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: LOG.debug(u'No commits in range "%s"', refspec) ctx.exit(0) LOG.debug(u'Linting %d commit(s)', number_of_commits) general_config_builder = ctx.obj.config_builder last_commit = gitcontext.commits[-1] # Let's get linting! first_violation = True exit_code = 0 for commit in gitcontext.commits: # 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) # 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) if violations: # Display the commit hash & new lines intelligently if number_of_commits > 1 and commit.sha: linter.display.e("{0}Commit {1}:".format( "\n" if not first_violation or commit is last_commit else "", commit.sha[:10])) linter.print_violations(violations) first_violation = False # cap actual max exit code because bash doesn't like exit codes larger than 255: # http://tldp.org/LDP/abs/html/exitcodes.html exit_code = min(MAX_VIOLATION_ERROR_CODE, exit_code) LOG.debug("Exit Code = %s", exit_code) ctx.exit(exit_code)
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) 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])) ctx.exit(0) general_config_builder = ctx.obj[1] last_commit = gitcontext.commits[-1] # Let's get linting! 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) config_builder = general_config_builder.clone() config_builder.set_config_from_commit(commit) lint_config = config_builder.build(lint_config) linter = GitLinter(lint_config) # Actually do the linting violations = linter.lint(commit) # exit code equals the total number of violations in all commits exit_code += len(violations) if violations: # Display the commit hash & new lines intelligently if number_of_commits > 1 and commit.sha: linter.display.e(u"{0}Commit {1}:".format( "\n" if not first_violation or commit is last_commit else "", commit.sha[:10] )) linter.print_violations(violations) first_violation = False # cap actual max exit code because bash doesn't like exit codes larger than 255: # http://tldp.org/LDP/abs/html/exitcodes.html exit_code = min(MAX_VIOLATION_ERROR_CODE, exit_code) LOG.debug("Exit Code = %s", exit_code) ctx.exit(exit_code)
def test_print_violations(self): violations = [RuleViolation("RULE_ID_1", "Error Message 1", "Violating Content 1", 1), RuleViolation("RULE_ID_2", "Error Message 2", "Violating Content 2", 2)] linter = GitLinter(LintConfig()) # test output with increasing verbosity with patch('gitlint.display.stderr', new=StringIO()) as stderr: linter.config.verbosity = 0 linter.print_violations(violations) self.assertEqual("", stderr.getvalue()) with patch('gitlint.display.stderr', new=StringIO()) as stderr: linter.config.verbosity = 1 linter.print_violations(violations) expected = "1: RULE_ID_1\n2: RULE_ID_2\n" self.assertEqual(expected, stderr.getvalue()) with patch('gitlint.display.stderr', new=StringIO()) as stderr: linter.config.verbosity = 2 linter.print_violations(violations) expected = "1: RULE_ID_1 Error Message 1\n2: RULE_ID_2 Error Message 2\n" self.assertEqual(expected, stderr.getvalue()) with patch('gitlint.display.stderr', new=StringIO()) as stderr: linter.config.verbosity = 3 linter.print_violations(violations) expected = "1: RULE_ID_1 Error Message 1: \"Violating Content 1\"\n" + \ "2: RULE_ID_2 Error Message 2: \"Violating Content 2\"\n" self.assertEqual(expected, stderr.getvalue())
def test_print_violations(self): violations = [ RuleViolation("RULE_ID_1", u"Error Messåge 1", "Violating Content 1", None), RuleViolation("RULE_ID_2", "Error Message 2", u"Violåting Content 2", 2) ] linter = GitLinter(LintConfig()) # test output with increasing verbosity with patch('gitlint.display.stderr', new=StringIO()) as stderr: linter.config.verbosity = 0 linter.print_violations(violations) self.assertEqual("", stderr.getvalue()) with patch('gitlint.display.stderr', new=StringIO()) as stderr: linter.config.verbosity = 1 linter.print_violations(violations) expected = u"-: RULE_ID_1\n2: RULE_ID_2\n" self.assertEqual(expected, stderr.getvalue()) with patch('gitlint.display.stderr', new=StringIO()) as stderr: linter.config.verbosity = 2 linter.print_violations(violations) expected = u"-: RULE_ID_1 Error Messåge 1\n2: RULE_ID_2 Error Message 2\n" self.assertEqual(expected, stderr.getvalue()) with patch('gitlint.display.stderr', new=StringIO()) as stderr: linter.config.verbosity = 3 linter.print_violations(violations) expected = u"-: RULE_ID_1 Error Messåge 1: \"Violating Content 1\"\n" + \ u"2: RULE_ID_2 Error Message 2: \"Violåting Content 2\"\n" self.assertEqual(expected, stderr.getvalue())
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) 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])) ctx.exit(0) config_builder = ctx.obj[1] last_commit = gitcontext.commits[-1] # Apply an additional config that is specified in the last commit message config_builder.set_config_from_commit(last_commit) lint_config = config_builder.build(lint_config) # Let's get linting! linter = GitLinter(lint_config) first_violation = True for commit in gitcontext.commits: violations = linter.lint(commit) if violations: # Display the commit hash & new lines intelligently if number_of_commits > 1 and commit.sha: click.echo(u"{0}Commit {1}:".format( "\n" if not first_violation or commit is last_commit else "", commit.sha[:10])) linter.print_violations(violations) first_violation = False exit_code = min(MAX_VIOLATION_ERROR_CODE, len(violations)) ctx.exit(exit_code)
def lint(ctx): """ Lints a git repository [default command] """ lint_config = ctx.obj try: if sys.stdin.isatty(): gitcontext = GitContext.from_local_repository(lint_config.target) else: gitcontext = GitContext.from_commit_msg(sys.stdin.read()) except GitContextError as e: click.echo(str(e)) ctx.exit(GIT_CONTEXT_ERROR_CODE) last_commit = gitcontext.commits[-1] # Apply an additional config that is specified in the last commit message lint_config.apply_config_from_commit(last_commit) # Let's get linting! linter = GitLinter(lint_config) violations = linter.lint(last_commit, gitcontext) linter.print_violations(violations) exit_code = min(MAX_VIOLATION_ERROR_CODE, len(violations)) ctx.exit(exit_code)
def lint(ctx): """ Lints a git repository [default command] """ lint_config = ctx.obj try: if sys.stdin.isatty(): gitcontext = GitContext.from_local_repository(lint_config.target) else: gitcontext = GitContext.from_commit_msg(sys.stdin.read()) except GitContextError as e: click.echo(str(e)) ctx.exit(GIT_CONTEXT_ERROR_CODE) last_commit = gitcontext.commits[-1] # Apply an additional config that is specified in the last commit message lint_config.apply_config_from_commit(last_commit) # Let's get linting! linter = GitLinter(lint_config) violations = linter.lint(last_commit) linter.print_violations(violations) exit_code = min(MAX_VIOLATION_ERROR_CODE, len(violations)) ctx.exit(exit_code)
def lint(ctx): """ Lints a git repository [default command] """ lint_config = ctx.obj[0] 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: LOG.debug(u'No commits in range "%s"', ctx.obj[2]) ctx.exit(0) general_config_builder = ctx.obj[1] last_commit = gitcontext.commits[-1] # Let's get linting! first_violation = True exit_code = 0 for commit in gitcontext.commits: # 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) # 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) if violations: # Display the commit hash & new lines intelligently if number_of_commits > 1 and commit.sha: linter.display.e(u"{0}Commit {1}:".format( "\n" if not first_violation or commit is last_commit else "", commit.sha[:10])) linter.print_violations(violations) first_violation = False # cap actual max exit code because bash doesn't like exit codes larger than 255: # http://tldp.org/LDP/abs/html/exitcodes.html exit_code = min(MAX_VIOLATION_ERROR_CODE, exit_code) LOG.debug("Exit Code = %s", exit_code) ctx.exit(exit_code)