Skip to content

Commit

Permalink
Don't read stdin when --ignore-stdin flag is specified
Browse files Browse the repository at this point in the history
Previously, gitlint would still read from stdin and log whatever was passed,
even when the `--ignore-stin` flag was specified. This is problematic for
situations where stdin is blocking and the user is trying to have gitlint ignore
stdin all-together.

This should provide a workaround for #91
  • Loading branch information
jorisroovers committed Jul 8, 2019
1 parent c5dc226 commit ec72ae9
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 21 deletions.
3 changes: 3 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ The block below shows a sample ```.gitlint``` file. Details about rule config op
# By default gitlint will ignore squash commits. Set to 'false' to disable.
# ignore-squash-commits=true

# Ignore any data send to gitlint via stdin
# ignore-stdin=true

# Enable debug mode (prints more output). Disabled by default.
# debug=true

Expand Down
42 changes: 23 additions & 19 deletions gitlint/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,27 @@ def get_stdin_data():
return False


def build_git_context(lint_config, msg_filename, refspec):
""" Builds a git context based on passed parameters and order of precedence """
# Order of precedence:
# 1. Any data specified via --msg-filename
if msg_filename:
LOG.debug("Attempting to read from --msg-filename.")
return GitContext.from_commit_msg(ustr(msg_filename.read()))

# 2. Any data sent to stdin (unless stdin is being ignored)
if not lint_config.ignore_stdin:
stdin_input = get_stdin_data()
if stdin_input:
LOG.debug("Stdin data: %r", stdin_input)
LOG.debug("Stdin detected and not ignored. Will be used as input.")
return GitContext.from_commit_msg(stdin_input)

# 3. Fallback to reading from local repository
LOG.debug("No --msg-filename flag, no or empty data passed to stdin. Attempting to read from the local repo.")
return GitContext.from_local_repository(lint_config.target, refspec)


@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', type=click.Path(exists=True, resolve_path=True, file_okay=False, readable=True),
Expand Down Expand Up @@ -170,7 +191,6 @@ def cli( # pylint: disable=too-many-arguments
# 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, contrib, ignore_stdin, verbose, silent, debug)

LOG.debug(u"Configuration\n%s", ustr(config))

ctx.obj = (config, config_builder, commits, msg_filename)
Expand All @@ -189,26 +209,10 @@ def cli( # pylint: disable=too-many-arguments
def lint(ctx):
""" Lints a git repository [default command] """
lint_config = ctx.obj[0]
refspec = ctx.obj[2]
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 stdin_input:
LOG.debug("Stdin data: %r", stdin_input)

if msg_filename:
LOG.debug("Attempting to read from --msg-filename.")
gitcontext = GitContext.from_commit_msg(ustr(msg_filename.read()))
elif stdin_input and not lint_config.ignore_stdin:
LOG.debug("Stdin detected and not ignored. Will be used as input.")
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])
gitcontext = build_git_context(lint_config, msg_filename, refspec)

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
Expand Down
2 changes: 2 additions & 0 deletions gitlint/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ def __eq__(self, other):
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.ignore_stdin == other.ignore_stdin and \
self.debug == other.debug and \
self.ignore == other.ignore and \
self._config_path == other._config_path # noqa
Expand All @@ -295,6 +296,7 @@ def __str__(self):
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"ignore-stdin: {0}\n".format(self.ignore_stdin)
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)
Expand Down
3 changes: 3 additions & 0 deletions gitlint/files/gitlint
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
# By default gitlint will ignore squash commits. Set to 'false' to disable.
# ignore-squash-commits=true

# Ignore any data send to gitlint via stdin
# ignore-stdin=true

# Enable debug mode (prints more output). Disabled by default.
# debug=true

Expand Down
1 change: 1 addition & 0 deletions gitlint/tests/expected/debug_configuration_output1
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ ignore: title-trailing-whitespace,B2
ignore-merge-commits: False
ignore-fixup-commits: True
ignore-squash-commits: True
ignore-stdin: False
verbosity: 1
debug: True
target: {target}
Expand Down
7 changes: 5 additions & 2 deletions gitlint/tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ def test_input_stream(self, _):

@patch('gitlint.cli.get_stdin_data', return_value="Should be ignored\n")
@patch('gitlint.git.sh')
def test_lint_ignore_stdin(self, sh, _):
def test_lint_ignore_stdin(self, sh, stdin_data):
""" Test for ignoring stdin when --ignore-stdin flag is enabled"""
sh.git.side_effect = self.GIT_CONFIG_SIDE_EFFECTS + [
"6f29bf81a8322a04071bb794666e48c443a90360",
Expand All @@ -214,6 +214,9 @@ def test_lint_ignore_stdin(self, sh, _):
self.assertEqual(stderr.getvalue(), u'3: B5 Body message is too short (11<20): "commït-body"\n')
self.assertEqual(result.exit_code, 1)

# Assert that we didn't even try to get the stdin data
self.assertEqual(stdin_data.call_count, 0)

@patch('gitlint.cli.get_stdin_data', return_value=False)
def test_msg_filename(self, _):
expected_output = u"3: B6 Body message is missing\n"
Expand Down Expand Up @@ -472,8 +475,8 @@ def test_install_hook(self, _, install_hook):
result = self.cli.invoke(cli.cli, ["install-hook"])
expected_path = os.path.join(u"/hür", u"dur", hooks.COMMIT_MSG_HOOK_DST_PATH)
expected = u"Successfully installed gitlint commit-msg hook in {0}\n".format(expected_path)
self.assertEqual(result.exit_code, 0)
self.assertEqual(result.output, expected)
self.assertEqual(result.exit_code, 0)
expected_config = config.LintConfig()
expected_config.target = os.path.realpath(os.getcwd())
install_hook.assert_called_once_with(expected_config)
Expand Down
1 change: 1 addition & 0 deletions qa/expected/debug_output1
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ignore: title-trailing-punctuation,B2
ignore-merge-commits: True
ignore-fixup-commits: True
ignore-squash-commits: True
ignore-stdin: False
verbosity: 2
debug: True
target: {target}
Expand Down

0 comments on commit ec72ae9

Please sign in to comment.