diff --git a/c2cciutils/__init__.py b/c2cciutils/__init__.py index 88ff2d195..00ff6fd32 100644 --- a/c2cciutils/__init__.py +++ b/c2cciutils/__init__.py @@ -11,12 +11,12 @@ import sys from typing import Any, Dict, List, Match, Optional, Pattern, Tuple, TypedDict, cast +import jsonschema_gentypes.validate import magic import requests import ruamel.yaml import c2cciutils.configuration -import jsonschema_gentypes.validate def get_repository() -> str: @@ -192,6 +192,15 @@ def get_config() -> c2cciutils.configuration.Configuration: "print_environment_variables": True, "print_github_event": True, "black_config": {"propertires": {"line-length": 110}}, + "prospector_config": { + "propertires": { + "strictness": "veryhigh", + "max-line-length": 110, + "doc-warnings": True, + "mypy": {"run": True}, + "bandit": {"run": True}, + } + }, "editorconfig": { "properties": editorconfig_full_properties, }, diff --git a/c2cciutils/checks.py b/c2cciutils/checks.py index 79435a241..a106923a6 100644 --- a/c2cciutils/checks.py +++ b/c2cciutils/checks.py @@ -17,6 +17,7 @@ import ruamel.yaml import yaml from editorconfig import EditorConfigError, get_properties +from ruamel.yaml.comments import CommentedMap import c2cciutils.prettier import c2cciutils.security @@ -141,6 +142,78 @@ def black_config( return True +def _check_properties(check: str, file: str, path: str, properties: CommentedMap, reference: Dict[str, Any])-> bool: + if path: + path += "." + + success = True + + for key, value in reference.items(): + if key not in properties: + c2cciutils.error( + check, + f"The property '{path}{key}' should be defined", + file, + properties.lc.line + 1, + properties.lc.col + 1, + ) + success = False + if isinstance(value, dict): + if not isinstance(properties[key], dict): + c2cciutils.error( + check, + f"The property '{path}{key}' should be a dictionary", + file, + properties.lc.line + 1, + properties.lc.col + 1, + ) + success = False + else: + success |= _check_properties(check, file, path + key, properties[key], value) + else: + if properties[key] != value: + c2cciutils.error( + check, + f"The property '{path}{key}' should have the value, '{value}', " + f"but is '{properties[key]}'", + file, + properties.lc.line + 1, + properties.lc.col + 1, + ) + success = False + return success + + +def prospector_config( + config: c2cciutils.configuration.ChecksBlackConfigurationConfig, + full_config: c2cciutils.configuration.Configuration, + args: Namespace, +) -> bool: + """ + Check the prospector configuration. + + config is like: + properties: # dictionary of properties to check + + Arguments: + config: The check section config + full_config: All the CI config + args: The parsed command arguments + """ + del full_config, args + success = True + + # If there is no python file the check is disabled + for filename in ( + subprocess.check_output(["git", "ls-files", ".prospector.yaml"]).decode().strip().split("\n") + ): + with open(filename, encoding="utf-8") as dependabot_file: + properties: CommentedMap = ruamel.yaml.round_trip_load(dependabot_file) # type: ignore + success |= _check_properties("prospector_config", filename, "", properties, config.get("properties", {})) + + return success + + def editorconfig( config: c2cciutils.configuration.ChecksEditorconfigConfig, full_config: c2cciutils.configuration.Configuration, diff --git a/c2cciutils/configuration.py b/c2cciutils/configuration.py index ab2708ad9..c56e82778 100644 --- a/c2cciutils/configuration.py +++ b/c2cciutils/configuration.py @@ -3,8 +3,7 @@ """ -from typing import Dict, Literal, TypedDict, Any, Union, List - +from typing import Any, Dict, List, Literal, TypedDict, Union # Audit # @@ -129,6 +128,7 @@ { "black": "ChecksBlack", "black_config": "ChecksBlackConfiguration", + "prospector_config": "ChecksProspectorConfiguration", "codespell": "ChecksCodespell", "dependabot_config": "ChecksDependabotConfiguration", "editorconfig": "ChecksEditorconfig", @@ -185,7 +185,7 @@ ChecksBlackConfigurationConfig = TypedDict( "ChecksBlackConfigurationConfig", { - # The properties key = value thet should be present + # The properties key = value that should be present "properties": Dict[str, Union[Union[int, float], str]], }, total=False, @@ -206,7 +206,7 @@ ChecksCodespellConfig = TypedDict( "ChecksCodespellConfig", { - # List of argument that will be added to the codspell command + # List of argument that will be added to the codespell command "arguments": List[str], # List of regular expression that should be ignored "ignore_re": List[str], @@ -316,10 +316,31 @@ # Checks print config # -# The print the autogenerated configguration +# The print the auto-generated configuration ChecksPrintConfig = bool +# Checks Prospector configuration +# +# The Black configuration check configuration +# +# oneOf +ChecksProspectorConfiguration = Union["ChecksProspectorConfigurationConfig", Literal[False]] + + +# Checks prospector configuration config +# +# The Prospector configuration check configuration +ChecksProspectorConfigurationConfig = TypedDict( + "ChecksProspectorConfigurationConfig", + { + # The properties key = value that should be present + "properties": Dict[str, Any], + }, + total=False, +) + + # checks required workflows # # The required workflow check configuration @@ -378,7 +399,7 @@ "backport_labels": bool, # Check the versions of the protected branches "branches": bool, - # Versions that are not in the `SECURITY.md` but should still be consided + # Versions that are not in the `SECURITY.md` but should still be considered "extra_versions": List[str], # Check the versions in the rebuild workflows # diff --git a/c2cciutils/schema.json b/c2cciutils/schema.json index 8bbdaefe7..37287814f 100644 --- a/c2cciutils/schema.json +++ b/c2cciutils/schema.json @@ -137,7 +137,7 @@ "type": "object", "properties": { "properties": { - "description": "The properties key = value thet should be present", + "description": "The properties key = value that should be present", "type": "object", "additionalProperties": { "type": ["number", "string"] } } @@ -146,6 +146,24 @@ { "const": false } ] }, + "checks_prospector_config": { + "title": "Checks Prospector configuration", + "description": "The Black configuration check configuration", + "oneOf": [ + { + "title": "Checks prospector configuration config", + "description": "The Prospector configuration check configuration", + "type": "object", + "properties": { + "properties": { + "description": "The properties key = value that should be present", + "type": "object" + } + } + }, + { "const": false } + ] + }, "checks_codespell": { "title": "Checks codespell", "description": "The codespell check configuration", @@ -156,7 +174,7 @@ "type": "object", "properties": { "arguments": { - "description": "List of argument that will be added to the codspell command", + "description": "List of argument that will be added to the codespell command", "type": "array", "items": { "type": "string" } }, @@ -276,7 +294,7 @@ }, "checks_print_config": { "title": "Checks print config", - "description": "The print the autogenerated configguration", + "description": "The print the auto-generated configuration", "type": "boolean" }, "checks_required_workflows": { @@ -357,7 +375,7 @@ "type": "boolean" }, "extra_versions": { - "description": "Versions that are not in the `SECURITY.md` but should still be consided", + "description": "Versions that are not in the `SECURITY.md` but should still be considered", "type": "array", "items": { "type": "string" } }, @@ -670,6 +688,7 @@ "properties": { "black": { "$ref": "#/definitions/checks_black" }, "black_config": { "$ref": "#/definitions/checks_black_config" }, + "prospector_config": { "$ref": "#/definitions/checks_prospector_config" }, "codespell": { "$ref": "#/definitions/checks_codespell" }, "dependabot_config": { "$ref": "#/definitions/checks_dependabot_config" }, "editorconfig": { "$ref": "#/definitions/checks_editorconfig" },