diff --git a/hooks/conan-center.py b/hooks/conan-center.py index b0b7b52f..ed3df651 100644 --- a/hooks/conan-center.py +++ b/hooks/conan-center.py @@ -7,13 +7,15 @@ import sys from logging import WARNING, ERROR, INFO, DEBUG, NOTSET +from conans import tools, ConanFile + import yaml -from conans import tools try: from conans import Settings except ImportError: from conans.model.settings import Settings + kb_errors = {"KB-H001": "DEPRECATED GLOBAL CPPSTD", "KB-H002": "REFERENCE LOWERCASE", "KB-H003": "RECIPE METADATA", @@ -46,6 +48,7 @@ "KB-H031": "CONANDATA.YML REDUCE", "KB-H032": "SYSTEM REQUIREMENTS", "KB-H034": "TEST PACKAGE - NO IMPORTS()", + "KB-H035": "CUSTOM ATTRIBUTES", "KB-H037": "NO AUTHOR", "KB-H040": "NO TARGET NAME", "KB-H041": "NO FINAL ENDLINE", @@ -421,6 +424,19 @@ def test(out): if "def imports" in test_package_conanfile: out.error("The method `imports` is not allowed in test_package/conanfile.py") + @run_test("KB-H035", output) + def test(out): + mock = ConanFile(conanfile.output, None) + valid_attrs = [attr for attr in dir(mock) if not callable(attr)] + ['conan_data', 'python_requires'] + current_attrs = [attr for attr in dir(conanfile) if not callable(attr)] + invalid_attrs = re.findall(r"(__.*)\s?=", conanfile_content, re.MULTILINE) + for attr in current_attrs: + if not attr.startswith("_") and attr not in valid_attrs: + invalid_attrs.append(attr) + if invalid_attrs: + out.error("Custom attributes must be declared as protected. " \ + "The follow attributes are invalid: '{}'".format("', '".join(invalid_attrs))) + @run_test("KB-H037", output) def test(out): author = getattr(conanfile, "author", None) diff --git a/tests/test_hooks/conan-center/test_conan-center.py b/tests/test_hooks/conan-center/test_conan-center.py index 8f8e7cc2..fc48d136 100644 --- a/tests/test_hooks/conan-center/test_conan-center.py +++ b/tests/test_hooks/conan-center/test_conan-center.py @@ -118,6 +118,7 @@ def test_conanfile(self): self.assertIn("ERROR: [CONAN CENTER INDEX URL (KB-H027)] The attribute 'url' should " \ "point to: https://github.com/conan-io/conan-center-index", output) self.assertIn("[CMAKE MINIMUM VERSION (KB-H028)] OK", output) + self.assertIn("[CUSTOM ATTRIBUTES (KB-H035)] OK", output) self.assertIn("[SYSTEM REQUIREMENTS (KB-H032)] OK", output) self.assertIn("[SINGLE REQUIRES (KB-H055)] OK", output) @@ -141,6 +142,7 @@ def test_conanfile_header_only(self): "recipe", output) self.assertIn("[META LINES (KB-H025)] OK", output) self.assertIn("[CMAKE MINIMUM VERSION (KB-H028)] OK", output) + self.assertIn("[CUSTOM ATTRIBUTES (KB-H035)] OK", output) self.assertIn("[SYSTEM REQUIREMENTS (KB-H032)] OK", output) def test_conanfile_header_only_with_settings(self): @@ -162,6 +164,7 @@ def test_conanfile_header_only_with_settings(self): "recipe", output) self.assertIn("[META LINES (KB-H025)] OK", output) self.assertIn("[CMAKE MINIMUM VERSION (KB-H028)] OK", output) + self.assertIn("[CUSTOM ATTRIBUTES (KB-H035)] OK", output) self.assertIn("[SYSTEM REQUIREMENTS (KB-H032)] OK", output) def test_conanfile_settings_clear_with_settings(self): @@ -604,6 +607,42 @@ def system_requirements(self): self.assertIn("[SYSTEM REQUIREMENTS (KB-H032)] 'libusb' is part of the allowlist.", output) self.assertNotIn("ERROR: [SYSTEM REQUIREMENTS (KB-H032)]", output) + def test_invalid_recipe_attributes(self): + conanfile = textwrap.dedent("""\ + from conans import ConanFile + + class AConan(ConanFile): + url = "fake_url.com" + license = "fake_license" + description = "whatever" + homepage = "homepage.com" + topics = ("fake_topic", "another_fake_topic") + exports_sources = "header.h" + options = {"foo": [True, False], "bar": [True, False]} + default_options = {"foo": False, "bar": True} + _source_subfolder = "source_subfolder" + _build_subfolder = "build_subfolder" + __my_private = "secret" + __attribute__ = "foobar" + __qux= "baz" + foobar = "package" + package_subfolder = "package" + + def package(self): + self.copy("*", dst="include") + + def _foobar(self): + pass + + def __private(self): + pass + """) + tools.save('conanfile.py', content=conanfile) + output = self.conan(['create', '.', 'name/version@user/test']) + self.assertIn("ERROR: [CUSTOM ATTRIBUTES (KB-H035)] Custom attributes must be declared as " + "protected. The follow attributes are invalid: '__my_private ', " + "'__attribute__ ', '__qux', 'foobar', 'package_subfolder'", output) + def test_imports_not_allowed(self): conanfile_tp = textwrap.dedent("""\ from conans import ConanFile, tools