diff --git a/src/compwa_policy/utilities/executor.py b/src/compwa_policy/utilities/executor.py index fd809ce9..6337d41f 100644 --- a/src/compwa_policy/utilities/executor.py +++ b/src/compwa_policy/utilities/executor.py @@ -105,14 +105,19 @@ def __exit__( exc_type: type[BaseException] | None, exc_value: BaseException | None, tb: TracebackType | None, - ) -> None: + ) -> bool: + if exc_type is not None and not issubclass(exc_type, PrecommitError): + return False + if isinstance(exc_value, PrecommitError): + self.__error_messages.append(str("\n".join(exc_value.args))) error_msg = self.merge_messages() if error_msg: if self.__raise_exception: - raise PrecommitError(error_msg) from exc_value + raise PrecommitError(error_msg) print(error_msg) # noqa: T201 if os.getenv("COMPWA_POLICY_DEBUG") is not None: self.print_execution_times() + return True def merge_messages(self) -> str: stripped_messages = (s.strip() for s in self.__error_messages) diff --git a/src/compwa_policy/utilities/precommit/__init__.py b/src/compwa_policy/utilities/precommit/__init__.py index 3c3ea51a..e4e4e651 100644 --- a/src/compwa_policy/utilities/precommit/__init__.py +++ b/src/compwa_policy/utilities/precommit/__init__.py @@ -60,7 +60,8 @@ def load(cls: type[T], source: IO | Path | str = CONFIG_PATH.precommit) -> T: def dumps(self) -> str: with io.StringIO() as stream: - return self.parser.dump(self.document, stream) + self.parser.dump(self.document, stream) + return stream.getvalue() def find_repo(self, search_pattern: str) -> Repo | None: """Find pre-commit repo definition in pre-commit config.""" @@ -88,10 +89,12 @@ def __exit__( exc_type: type[BaseException] | None, exc_value: BaseException | None, tb: TracebackType | None, - ) -> None: + ) -> bool: + if exc_type is not None and not issubclass(exc_type, PrecommitError): + return False if not self.__changelog: - return - if self.parser is None: + return True + if self.parser is not None: self.dump(self.source) msg = "The following modifications were made" if isinstance(self.source, Path): diff --git a/src/compwa_policy/utilities/pyproject/__init__.py b/src/compwa_policy/utilities/pyproject/__init__.py index 86dff787..1ad203b1 100644 --- a/src/compwa_policy/utilities/pyproject/__init__.py +++ b/src/compwa_policy/utilities/pyproject/__init__.py @@ -159,10 +159,12 @@ def __exit__( exc_type: type[BaseException] | None, exc_value: BaseException | None, tb: TracebackType | None, - ) -> None: + ) -> bool: + if exc_type is not None and not issubclass(exc_type, PrecommitError): + return False if not self._changelog: - return - if self._source is None: + return True + if self._source is not None: self.dump(self._source) msg = "The following modifications were made" if isinstance(self._source, (Path, str)): diff --git a/tests/check_dev_files/editorconfig/.pre-commit-config-bad.yaml b/tests/check_dev_files/editorconfig/.pre-commit-config-bad.yaml new file mode 100644 index 00000000..d1e01790 --- /dev/null +++ b/tests/check_dev_files/editorconfig/.pre-commit-config-bad.yaml @@ -0,0 +1,5 @@ +repos: + - repo: https://github.com/editorconfig-checker/editorconfig-checker.python + rev: 2.7.3 + hooks: + - id: editorconfig-checker diff --git a/tests/check_dev_files/editorconfig/.pre-commit-config-good-no-python.yaml b/tests/check_dev_files/editorconfig/.pre-commit-config-good-no-python.yaml new file mode 100644 index 00000000..5de1a635 --- /dev/null +++ b/tests/check_dev_files/editorconfig/.pre-commit-config-good-no-python.yaml @@ -0,0 +1,7 @@ +repos: + - repo: https://github.com/editorconfig-checker/editorconfig-checker.python + rev: 2.7.3 + hooks: + - id: editorconfig-checker + name: editorconfig + alias: ec diff --git a/tests/check_dev_files/editorconfig/.pre-commit-config-good.yaml b/tests/check_dev_files/editorconfig/.pre-commit-config-good.yaml new file mode 100644 index 00000000..0f28f1e4 --- /dev/null +++ b/tests/check_dev_files/editorconfig/.pre-commit-config-good.yaml @@ -0,0 +1,11 @@ +repos: + - repo: https://github.com/editorconfig-checker/editorconfig-checker.python + rev: 2.7.3 + hooks: + - id: editorconfig-checker + name: editorconfig + alias: ec + exclude: >- + (?x)^( + .*\.py + )$ diff --git a/tests/check_dev_files/editorconfig/__init__.py b/tests/check_dev_files/editorconfig/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/check_dev_files/editorconfig/test_editorconfig.py b/tests/check_dev_files/editorconfig/test_editorconfig.py new file mode 100644 index 00000000..2a3690f7 --- /dev/null +++ b/tests/check_dev_files/editorconfig/test_editorconfig.py @@ -0,0 +1,30 @@ +import io +from pathlib import Path + +import pytest + +from compwa_policy.check_dev_files.editorconfig import _update_precommit_config +from compwa_policy.errors import PrecommitError +from compwa_policy.utilities.precommit import ModifiablePrecommit + + +@pytest.mark.parametrize("no_python", [True, False]) +def test_update_precommit_config(no_python: bool): + this_dir = Path(__file__).parent + with open(this_dir / ".pre-commit-config-bad.yaml") as file: + src = file.read() + + stream = io.StringIO(src) + with pytest.raises( + PrecommitError, match=r"Updated editorconfig-checker hook" + ), ModifiablePrecommit.load(stream) as precommit: + _update_precommit_config(precommit, no_python) + + result = precommit.dumps() + if no_python: + expected_file = this_dir / ".pre-commit-config-good-no-python.yaml" + else: + expected_file = this_dir / ".pre-commit-config-good.yaml" + with open(expected_file) as file: + expected = file.read() + assert result == expected diff --git a/tests/utilities/precommit/test_class.py b/tests/utilities/precommit/test_class.py new file mode 100644 index 00000000..2af4f35e --- /dev/null +++ b/tests/utilities/precommit/test_class.py @@ -0,0 +1,55 @@ +import io +from pathlib import Path + +import pytest + +from compwa_policy.errors import PrecommitError +from compwa_policy.utilities.precommit import ModifiablePrecommit, Precommit + + +@pytest.fixture +def this_dir() -> Path: + return Path(__file__).parent + + +@pytest.fixture +def example_config(this_dir: Path) -> str: + with open(this_dir / ".pre-commit-config.yaml") as file: + return file.read() + + +class TestModifiablePrecommit: + def test_no_context_manager(self, example_config: str): + with pytest.raises( + expected_exception=RuntimeError, + match=r"^Modifications can only be made within a context$", + ): + precommit = ModifiablePrecommit.load(example_config) + precommit.document["fail_fast"] = True + precommit.append_to_changelog("Fake modification") + + def test_context_manager_path(self, this_dir: Path, example_config: str): + with pytest.raises( + PrecommitError, + match=r"Fake modification$", + ), ModifiablePrecommit.load(this_dir / ".pre-commit-config.yaml") as precommit: + precommit.append_to_changelog("Fake modification") + yaml = precommit.dumps() + assert yaml == example_config + + def test_context_manager_string_stream(self, example_config: str): + stream = io.StringIO(example_config) + with pytest.raises( + PrecommitError, match=r"Fake modification$" + ), ModifiablePrecommit.load(stream) as precommit: + precommit.append_to_changelog("Fake modification") + stream.seek(0) + yaml = stream.read() + assert yaml == example_config + + +class TestPrecommit: + def test_dumps(self, this_dir: Path, example_config: str): + precommit = Precommit.load(this_dir / ".pre-commit-config.yaml") + yaml = precommit.dumps() + assert yaml == example_config