diff --git a/action.yml b/action.yml index 429cffe..f821137 100644 --- a/action.yml +++ b/action.yml @@ -14,7 +14,7 @@ runs: using: "composite" steps: - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v6 with: python-version: '3.11' diff --git a/validate.py b/validate.py index 31568cc..7013a63 100644 --- a/validate.py +++ b/validate.py @@ -1,18 +1,22 @@ #!/usr/bin/env python3 -import os -import json -import yaml import argparse +import json +import os import sys -from typing import List, Dict, Any +from typing import Any, Dict, List + +import yaml # We use packaging.version for robust version comparison try: from packaging import version except ImportError: - print("::warning:: 'packaging' library not found. Version comparison might be less robust.") + print( + "::warning:: 'packaging' library not found. Version comparison might be less robust." + ) version = None + def error(message: str, file: str = None, line: int = None, col: int = None): """Prints error in GitHub Actions format.""" location = "" @@ -29,6 +33,7 @@ def error(message: str, file: str = None, line: int = None, col: int = None): print(f"::error::{message}") print(f"ERROR: {message}", file=sys.stderr) + def validate_addons_json(repo_path: str) -> Dict[str, Any]: json_path = os.path.join(repo_path, "addons.json") if not os.path.exists(json_path): @@ -36,10 +41,15 @@ def validate_addons_json(repo_path: str) -> Dict[str, Any]: return None try: - with open(json_path, 'r', encoding='utf-8') as f: + with open(json_path, "r", encoding="utf-8") as f: data = json.load(f) except json.JSONDecodeError as e: - error(f"Invalid JSON in addons.json: {e.msg}", file=json_path, line=e.lineno, col=e.colno) + error( + f"Invalid JSON in addons.json: {e.msg}", + file=json_path, + line=e.lineno, + col=e.colno, + ) return None if "addons" not in data or not isinstance(data["addons"], list): @@ -48,7 +58,10 @@ def validate_addons_json(repo_path: str) -> Dict[str, Any]: return data -def validate_addon_directory(repo_path: str, addon_id: str, core_version: str = None) -> bool: + +def validate_addon_directory( + repo_path: str, addon_id: str, core_version: str = None +) -> bool: addon_path = os.path.join(repo_path, addon_id) if not os.path.isdir(addon_path): error(f"Directory not found for addon '{addon_id}'", file=addon_path) @@ -62,10 +75,12 @@ def validate_addon_directory(repo_path: str, addon_id: str, core_version: str = manifest = None try: - with open(manifest_path, 'r', encoding='utf-8') as f: + with open(manifest_path, "r", encoding="utf-8") as f: manifest = json.load(f) except json.JSONDecodeError as e: - error(f"Invalid JSON in manifest.json for '{addon_id}': {e}", file=manifest_path) + error( + f"Invalid JSON in manifest.json for '{addon_id}': {e}", file=manifest_path + ) return False # Required Fields Check @@ -78,8 +93,11 @@ def validate_addon_directory(repo_path: str, addon_id: str, core_version: str = # Domain Validation (Simple) domain = manifest.get("domain") if not domain.isidentifier(): - error(f"Invalid domain '{domain}'. Must be a valid identifier (alphanumeric, underscore).", file=manifest_path) - return False + error( + f"Invalid domain '{domain}'. Must be a valid identifier (alphanumeric, underscore).", + file=manifest_path, + ) + return False # Check Implementations implementations = manifest.get("implementations") @@ -88,36 +106,53 @@ def validate_addon_directory(repo_path: str, addon_id: str, core_version: str = # For this refactor, let's enforce 'implementations' OR 'integration.py' implicit # But user asked for Polyglot. Let's warn if missing. if os.path.exists(os.path.join(addon_path, "integration.py")): - # Implicit python support - pass + # Implicit python support + pass else: - error(f"manifest.json in '{addon_id}' missing 'implementations' map, and no implicit 'integration.py' found.", file=manifest_path) - return False + error( + f"manifest.json in '{addon_id}' missing 'implementations' map, and no implicit 'integration.py' found.", + file=manifest_path, + ) + return False if implementations: for lang, filename in implementations.items(): file_path = os.path.join(addon_path, filename) if not os.path.exists(file_path): - error(f"Implementation file '{filename}' for '{lang}' not found in '{addon_id}'", file=file_path) - return False + error( + f"Implementation file '{filename}' for '{lang}' not found in '{addon_id}'", + file=file_path, + ) + return False # Check Core Version Compatibility min_ver = manifest.get("min_core_version") if min_ver and core_version and version: try: if version.parse(min_ver) > version.parse(core_version): - error(f"Addon '{addon_id}' requires Core >= {min_ver}, but current Core is {core_version}", file=manifest_path) + error( + f"Addon '{addon_id}' requires Core >= {min_ver}, but current Core is {core_version}", + file=manifest_path, + ) return False except Exception as e: - error(f"Version comparison failed for '{addon_id}' (min: {min_ver}, core: {core_version}): {e}", file=manifest_path) - return False + error( + f"Version comparison failed for '{addon_id}' (min: {min_ver}, core: {core_version}): {e}", + file=manifest_path, + ) + return False return True + def main(): parser = argparse.ArgumentParser(description="Validate Addon Repository") parser.add_argument("repo_path", help="Path to the repository root") - parser.add_argument("--core-version", help="Current version of faneX-ID Core to check compatibility against", default=None) + parser.add_argument( + "--core-version", + help="Current version of faneX-ID Core to check compatibility against", + default=None, + ) args = parser.parse_args() repo_path = os.path.abspath(args.repo_path) @@ -139,9 +174,12 @@ def main(): # Minimal check on addons.json entry format could persist, but directory check is more important addon_id = addon.get("id") if not addon_id: - error(f"Addon entry at index {i} missing 'id'", file=os.path.join(repo_path, "addons.json")) - success = False - continue + error( + f"Addon entry at index {i} missing 'id'", + file=os.path.join(repo_path, "addons.json"), + ) + success = False + continue print(f"Validating addon: {addon_id}...") @@ -155,5 +193,6 @@ def main(): print("Validation SUCCESSFUL.") sys.exit(0) + if __name__ == "__main__": main()