From 7d31f425cc93738cef91bcd96c1c87acecf84137 Mon Sep 17 00:00:00 2001 From: Yu-Ting Hsiung Date: Thu, 12 Jun 2025 22:17:06 +0800 Subject: [PATCH] fix(ExitCode): add from_str in ExitCode and replace parse_no_raise with it Warn if a given decimal string is not in range --- commitizen/cli.py | 25 ++++++++++++------------- commitizen/exceptions.py | 12 ++++++++++-- tests/test_exceptions.py | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 15 deletions(-) create mode 100644 tests/test_exceptions.py diff --git a/commitizen/cli.py b/commitizen/cli.py index 6f7556df4..703a407b8 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -583,20 +583,19 @@ def parse_no_raise(comma_separated_no_raise: str) -> list[int]: Receives digits and strings and outputs the parsed integer which represents the exit code found in exceptions. """ - no_raise_items: list[str] = comma_separated_no_raise.split(",") - no_raise_codes: list[int] = [] - for item in no_raise_items: - if item.isdecimal(): - no_raise_codes.append(int(item)) - continue + + def exit_code_from_str_or_skip(s: str) -> ExitCode | None: try: - exit_code = ExitCode[item.strip()] - except KeyError: - out.warn(f"WARN: no_raise key `{item}` does not exist. Skipping.") - continue - else: - no_raise_codes.append(exit_code.value) - return no_raise_codes + return ExitCode.from_str(s) + except (KeyError, ValueError): + out.warn(f"WARN: no_raise value `{s}` is not a valid exit code. Skipping.") + return None + + return [ + code.value + for s in comma_separated_no_raise.split(",") + if (code := exit_code_from_str_or_skip(s)) is not None + ] if TYPE_CHECKING: diff --git a/commitizen/exceptions.py b/commitizen/exceptions.py index 8c0956be5..cbb9b6d83 100644 --- a/commitizen/exceptions.py +++ b/commitizen/exceptions.py @@ -1,10 +1,12 @@ -import enum +from __future__ import annotations + +from enum import IntEnum from typing import Any from commitizen import out -class ExitCode(enum.IntEnum): +class ExitCode(IntEnum): EXPECTED_EXIT = 0 NO_COMMITIZEN_FOUND = 1 NOT_A_GIT_PROJECT = 2 @@ -39,6 +41,12 @@ class ExitCode(enum.IntEnum): CONFIG_FILE_IS_EMPTY = 31 COMMIT_MESSAGE_LENGTH_LIMIT_EXCEEDED = 32 + @classmethod + def from_str(cls, value: str) -> ExitCode: + if value.isdecimal(): + return cls(int(value)) + return cls[value.strip()] + class CommitizenException(Exception): def __init__(self, *args: str, **kwargs: Any) -> None: diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py new file mode 100644 index 000000000..1a66c79d0 --- /dev/null +++ b/tests/test_exceptions.py @@ -0,0 +1,38 @@ +import pytest + +from commitizen.exceptions import ExitCode + + +def test_from_str_with_decimal(): + """Test from_str with decimal values.""" + assert ExitCode.from_str("0") == ExitCode.EXPECTED_EXIT + assert ExitCode.from_str("1") == ExitCode.NO_COMMITIZEN_FOUND + assert ExitCode.from_str("32") == ExitCode.COMMIT_MESSAGE_LENGTH_LIMIT_EXCEEDED + + +def test_from_str_with_enum_name(): + """Test from_str with enum names.""" + assert ExitCode.from_str("EXPECTED_EXIT") == ExitCode.EXPECTED_EXIT + assert ExitCode.from_str("NO_COMMITIZEN_FOUND") == ExitCode.NO_COMMITIZEN_FOUND + assert ( + ExitCode.from_str("COMMIT_MESSAGE_LENGTH_LIMIT_EXCEEDED") + == ExitCode.COMMIT_MESSAGE_LENGTH_LIMIT_EXCEEDED + ) + + +def test_from_str_with_whitespace(): + """Test from_str with whitespace in enum names.""" + assert ExitCode.from_str(" EXPECTED_EXIT ") == ExitCode.EXPECTED_EXIT + assert ExitCode.from_str("\tNO_COMMITIZEN_FOUND\t") == ExitCode.NO_COMMITIZEN_FOUND + + +def test_from_str_with_invalid_values(): + """Test from_str with invalid values.""" + with pytest.raises(KeyError): + ExitCode.from_str("invalid_name") + with pytest.raises(ValueError): + ExitCode.from_str("999") # Out of range decimal + with pytest.raises(KeyError): + ExitCode.from_str("") + with pytest.raises(KeyError): + ExitCode.from_str(" ")