From 7d92bddfe9413803002a827ad0958aa80770e86e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ricks?= Date: Thu, 11 Aug 2022 16:35:36 +0200 Subject: [PATCH] Change: Extract checking a plugin for validity to a separate function Add a reusable function to check if a Python module is a valid autohooks precommit plugin. --- autohooks/cli/check.py | 35 ++++++----------- autohooks/precommit/run.py | 47 ++++++++++++++++++++++ tests/precommit/__init__.py | 16 ++++++++ tests/precommit/test_run.py | 77 +++++++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 23 deletions(-) create mode 100644 tests/precommit/__init__.py create mode 100644 tests/precommit/test_run.py diff --git a/autohooks/cli/check.py b/autohooks/cli/check.py index dc191411..c220d454 100644 --- a/autohooks/cli/check.py +++ b/autohooks/cli/check.py @@ -25,10 +25,10 @@ ) from autohooks.hooks import PreCommitHook from autohooks.precommit.run import ( + CheckPluginError, + CheckPluginWarning, autohooks_module_path, - has_precommit_function, - has_precommit_parameters, - load_plugin, + check_plugin, ) from autohooks.settings import Mode from autohooks.terminal import Terminal @@ -134,24 +134,13 @@ def check_config( else: with autohooks_module_path(): for name in plugins: - try: - plugin = load_plugin(name) - if not has_precommit_function(plugin): - term.error( - f'Plugin "{name}" has no precommit ' - "function. The function is required to run" - " the plugin as git pre commit hook." - ) - elif not has_precommit_parameters(plugin): - term.warning( - f'Plugin "{name}" uses a deprecated ' - "signature for its precommit function. It " - "is missing the **kwargs parameter." - ) + result = check_plugin(name) + if result: + if isinstance(result, CheckPluginError): + term.error(str(result)) + elif isinstance(result, CheckPluginWarning): + term.warning(str(result)) else: - term.ok(f'Plugin "{name}" active and loadable.') - except ImportError as e: - term.error( - f'"{name}" is not a valid autohooks ' - f"plugin. {e}" - ) + term.info(str(result)) + else: + term.ok(f'Plugin "{name}" active and loadable.') diff --git a/autohooks/precommit/run.py b/autohooks/precommit/run.py index 9ecfd1f1..fde3ef20 100644 --- a/autohooks/precommit/run.py +++ b/autohooks/precommit/run.py @@ -75,6 +75,53 @@ def check_hook_mode(term: Terminal, config_mode: Mode, hook_mode: Mode) -> None: ) +class CheckPluginResult: + def __init__(self, message: str) -> None: + self.message = message + + def __str__(self) -> str: + return self.message + + +class CheckPluginError(CheckPluginResult): + """ + Raised if a plugin check failed + """ + + +class CheckPluginWarning(CheckPluginResult): + """ + Used if a plugin check raises a warning + """ + + +def check_plugin(plugin_name: str) -> Optional[CheckPluginResult]: + """ + Check if a plugin (Python module) is a valid and can be used + + Returns: + A CheckPluginResult in case of an issue with the plugin + """ + try: + plugin = load_plugin(plugin_name) + if not has_precommit_function(plugin): + return CheckPluginError( + f'Plugin "{plugin_name}" has no precommit ' + "function. The function is required to run" + " the plugin as git pre commit hook." + ) + elif not has_precommit_parameters(plugin): + return CheckPluginWarning( + f'Plugin "{plugin_name}" uses a deprecated ' + "signature for its precommit function. It " + "is missing the **kwargs parameter." + ) + except ImportError as e: + return CheckPluginError( + f'"{plugin_name}" is not a valid autohooks plugin. {e}' + ) + + class ReportProgress: """ A class to report progress of a plugin diff --git a/tests/precommit/__init__.py b/tests/precommit/__init__.py new file mode 100644 index 00000000..9bb9516b --- /dev/null +++ b/tests/precommit/__init__.py @@ -0,0 +1,16 @@ +# Copyright (C) 2022 Greenbone Networks GmbH +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . diff --git a/tests/precommit/test_run.py b/tests/precommit/test_run.py new file mode 100644 index 00000000..7d86f085 --- /dev/null +++ b/tests/precommit/test_run.py @@ -0,0 +1,77 @@ +# Copyright (C) 2022 Greenbone Networks GmbH +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +import unittest + +from autohooks.precommit.run import ( + CheckPluginError, + CheckPluginWarning, + check_plugin, +) +from tests import temp_python_module, tempdir + + +class CheckPluginTestCase(unittest.TestCase): + def test_plugin_not_found(self): + with tempdir(change_into=True): + result = check_plugin("foo.bar") + + self.assertIsInstance(result, CheckPluginError) + self.assertIn( + '"foo.bar" is not a valid autohooks plugin.', result.message + ) + + def test_no_precommit_function(self): + content = """print()""" + with temp_python_module( + content, + name="foo", + ): + result = check_plugin("foo") + + self.assertIsInstance(result, CheckPluginError) + self.assertEqual( + result.message, + 'Plugin "foo" has no precommit function. The function is ' + "required to run the plugin as git pre commit hook.", + ) + + def test_no_precommit_function_arguments(self): + content = """def precommit(): + print()""" + with temp_python_module( + content, + name="foo", + ): + result = check_plugin("foo") + + self.assertIsInstance(result, CheckPluginWarning) + self.assertEqual( + 'Plugin "foo" uses a deprecated signature for its precommit ' + "function. It is missing the **kwargs parameter.", + result.message, + ) + + def test_success(self): + content = """def precommit(**kwargs): + print()""" + with temp_python_module( + content, + name="foo", + ): + self.assertIsNone(check_plugin("foo"))