diff --git a/src/commitlint/cli.py b/src/commitlint/cli.py index d58bfcc..9fe7cc9 100644 --- a/src/commitlint/cli.py +++ b/src/commitlint/cli.py @@ -64,7 +64,14 @@ def get_args() -> argparse.Namespace: action="store_true", help="Skip the detailed error message check", ) - + # --quiet option is optional + parser.add_argument( + "-q", + "--quiet", + action="store_true", + help="Ignore stdout and stderr", + default=False, + ) # parsing args args = parser.parse_args() @@ -119,28 +126,37 @@ def _get_commit_message_from_file(filepath: str) -> str: return commit_message -def _handle_commit_message(commit_message: str, skip_detail: bool) -> None: +def _handle_commit_message( + commit_message: str, skip_detail: bool, quiet: bool = False +) -> None: """ Handles a single commit message, checks its validity, and prints the result. Args: commit_message (str): The commit message to be handled. skip_detail (bool): Whether to skip the detailed error linting. + quiet (bool): Whether to ignore stout and stderr Raises: SystemExit: If the commit message is invalid. """ success, errors = lint_commit_message(commit_message, skip_detail=skip_detail) + if success and quiet: + return + if success: sys.stdout.write(f"{VALIDATION_SUCCESSFUL}\n") - else: + return + + if not quiet: _show_errors(commit_message, errors, skip_detail=skip_detail) - sys.exit(1) + + sys.exit(1) def _handle_multiple_commit_messages( - commit_messages: List[str], skip_detail: bool + commit_messages: List[str], skip_detail: bool, quiet: bool = False ) -> None: """ Handles multiple commit messages, checks their validity, and prints the result. @@ -148,21 +164,26 @@ def _handle_multiple_commit_messages( Args: commit_messages (List[str]): List of commit messages to be handled. skip_detail (bool): Whether to skip the detailed error linting. - + quiet (bool): Whether to show the error and messages in console Raises: SystemExit: If any of the commit messages is invalid. """ has_error = False + for commit_message in commit_messages: success, errors = lint_commit_message(commit_message, skip_detail=skip_detail) - if not success: - has_error = True + if success: + continue + + has_error = True + if not quiet: _show_errors(commit_message, errors, skip_detail=skip_detail) sys.stderr.write("\n") if has_error: sys.exit(1) - else: + + if not quiet: sys.stdout.write(f"{VALIDATION_SUCCESSFUL}\n") @@ -175,20 +196,26 @@ def main() -> None: try: if args.file: commit_message = _get_commit_message_from_file(args.file) - _handle_commit_message(commit_message, skip_detail=args.skip_detail) + _handle_commit_message( + commit_message, skip_detail=args.skip_detail, quiet=args.quiet + ) elif args.hash: commit_message = get_commit_message_of_hash(args.hash) - _handle_commit_message(commit_message, skip_detail=args.skip_detail) + _handle_commit_message( + commit_message, skip_detail=args.skip_detail, quiet=args.quiet + ) elif args.from_hash: commit_messages = get_commit_messages_of_hash_range( args.from_hash, args.to_hash ) _handle_multiple_commit_messages( - commit_messages, skip_detail=args.skip_detail + commit_messages, skip_detail=args.skip_detail, quiet=args.quiet ) else: commit_message = args.commit_message.strip() - _handle_commit_message(commit_message, skip_detail=args.skip_detail) + _handle_commit_message( + commit_message, skip_detail=args.skip_detail, quiet=args.quiet + ) except CommitlintException as ex: sys.stderr.write(f"{ex}\n") sys.exit(1) diff --git a/tests/test_cli.py b/tests/test_cli.py index 0424c2e..ec19dcf 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -18,7 +18,11 @@ class TestCLIGetArgs: @patch( "argparse.ArgumentParser.parse_args", return_value=MagicMock( - commit_message="commit message", file=None, hash=None, from_hash=None + commit_message="commit message", + file=None, + hash=None, + from_hash=None, + quiet=None, ), ) def test__get_args__with_commit_message(self, *_): @@ -27,6 +31,7 @@ def test__get_args__with_commit_message(self, *_): assert args.file is None assert args.hash is None assert args.from_hash is None + assert args.quiet is None @patch( "argparse.ArgumentParser.parse_args", @@ -88,6 +93,7 @@ class TestCLIMain: hash=None, from_hash=None, skip_detail=False, + quiet=False, ), ) @patch("sys.stdout.write") @@ -107,6 +113,7 @@ def test__main__valid_commit_message( hash=None, from_hash=None, skip_detail=True, + quiet=False, ), ) @patch("sys.stdout.write") @@ -126,6 +133,7 @@ def test__main__valid_commit_message_using_skip_detail( hash=None, from_hash=None, skip_detail=False, + quiet=False, ), ) @patch("sys.stderr.write") @@ -154,6 +162,7 @@ def test__main__invalid_commit_message( hash=None, from_hash=None, skip_detail=True, + quiet=False, ), ) @patch("sys.stderr.write") @@ -177,7 +186,7 @@ def test__main__invalid_commit_message_using_skip_detail( @patch( "commitlint.cli.get_args", - return_value=MagicMock(file="path/to/file.txt", skip_detail=False), + return_value=MagicMock(file="path/to/file.txt", skip_detail=False, quiet=False), ) @patch("sys.stdout.write") @patch("builtins.open", mock_open(read_data="feat: valid commit message")) @@ -187,7 +196,7 @@ def test__main__valid_commit_message_with_file(self, mock_stdout_write, *_): @patch( "commitlint.cli.get_args", - return_value=MagicMock(file="path/to/file.txt", skip_detail=False), + return_value=MagicMock(file="path/to/file.txt", skip_detail=False, quiet=False), ) @patch("sys.stderr.write") @patch("sys.exit") @@ -209,7 +218,9 @@ def test__main__invalid_commit_message_with_file( @patch( "commitlint.cli.get_args", - return_value=MagicMock(file=None, hash="commit_hash", skip_detail=False), + return_value=MagicMock( + file=None, hash="commit_hash", skip_detail=False, quiet=False + ), ) @patch("commitlint.cli.get_commit_message_of_hash") @patch("sys.stdout.write") @@ -222,7 +233,9 @@ def test__main__valid_commit_message_with_hash( @patch( "commitlint.cli.get_args", - return_value=MagicMock(file=None, hash="commit_hash", skip_detail=False), + return_value=MagicMock( + file=None, hash="commit_hash", skip_detail=False, quiet=False + ), ) @patch("commitlint.cli.get_commit_message_of_hash") @patch("sys.stderr.write") @@ -251,6 +264,7 @@ def test__main__invalid_commit_message_with_hash( from_hash="start_commit_hash", to_hash="end_commit_hash", skip_detail=False, + quiet=False, ), ) @patch("commitlint.cli.get_commit_messages_of_hash_range") @@ -273,6 +287,7 @@ def test__main__valid_commit_message_with_hash_range( from_hash="invalid_start_hash", to_hash="end_commit_hash", skip_detail=False, + quiet=False, ), ) @patch("sys.stderr.write") @@ -308,3 +323,101 @@ def test__main__handle_exceptions( main() mock_sys_exit.assert_called_with(1) mock_stderr_write.assert_called_with("Test message\n") + + @patch( + "commitlint.cli.get_args", + return_value=MagicMock( + commit_message="Invalid commit message", + file=None, + hash=None, + from_hash=None, + skip_detail=False, + quiet=True, + ), + ) + @patch("sys.stdout.write") + @patch("sys.stderr.write") + @patch("sys.exit") + def test__main__quiet_option_with_invalid_commit_message( + self, mock_sys_exit, mock_stderr_write, mock_stdout_write, *_ + ): + main() + mock_stderr_write.assert_not_called() + mock_stdout_write.assert_not_called() + + @patch( + "commitlint.cli.get_args", + return_value=MagicMock( + commit_message="feat: valid commit message", + file=None, + hash=None, + from_hash=None, + skip_detail=False, + quiet=True, + ), + ) + @patch("sys.stdout.write") + @patch("sys.stderr.write") + @patch("sys.exit") + def test__main__quiet_option_with_valid_commit_message( + self, mock_sys_exit, mock_stderr_write, mock_stdout_write, *_ + ): + main() + mock_stderr_write.assert_not_called() + mock_stdout_write.assert_not_called() + mock_sys_exit.assert_not_called() + + @patch( + "commitlint.cli.get_args", + return_value=MagicMock( + file=None, + hash=None, + from_hash="start_commit_hash", + to_hash="end_commit_hash", + skip_detail=False, + quiet=True, + ), + ) + @patch("commitlint.cli.get_commit_messages_of_hash_range") + @patch("sys.stdout.write") + def test__valid_commit_message_with_hash_range_in_quiet( + self, mock_stdout_write, mock_get_commit_messages, *_ + ): + mock_get_commit_messages.return_value = [ + "feat: commit message 1", + "fix: commit message 2", + ] + main() + mock_stdout_write.assert_not_called() + + @patch( + "commitlint.cli.get_args", + return_value=MagicMock( + file=None, + hash=None, + from_hash="start_commit_hash", + to_hash="end_commit_hash", + skip_detail=False, + quiet=True, + ), + ) + @patch("commitlint.cli.get_commit_messages_of_hash_range") + @patch("sys.exit") + @patch("sys.stdout.write") + @patch("sys.stderr.write") + def test__invalid_commit_message_with_hash_range_in_quiet( + self, + mock_stderr_write, + mock_stdout_write, + mock_sys_exit, + mock_get_commit_messages, + *_, + ): + mock_get_commit_messages.return_value = [ + "Invalid commit message 1", + "Invalid commit message 2", + ] + main() + mock_stderr_write.assert_not_called() + mock_sys_exit.assert_called_once_with(1) + mock_stdout_write.assert_not_called()