diff --git a/Schema.json b/Schema.json new file mode 100644 index 0000000..6ed9d6d --- /dev/null +++ b/Schema.json @@ -0,0 +1,112 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "title": "PortainerAppTemplate", + "properties": { + "version": { + "type": "string", + "minLength": 1, + "description": "The version of the Portainer App Template." + }, + "templates": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "integer", + "minimum": 1, + "maximum": 2, + "description": "The type of the application (1 for container, 2 for swarm stack)." + }, + "title": { + "type": "string", + "minLength": 1, + "description": "The title of the application." + }, + "description": { + "type": "string", + "minLength": 1, + "description": "A brief description of the application." + }, + "categories": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "description": "An array of categories the application belongs to." + }, + "platform": { + "type": "string", + "minLength": 1, + "description": "The target platform of the application (e.g., 'linux', 'windows')." + }, + "logo": { + "type": "string", + "format": "uri", + "description": "A URI to the logo of the application." + }, + "image": { + "type": "string", + "minLength": 1, + "description": "The name of the Docker image used for the application." + }, + "restart_policy": { + "type": "string", + "enum": ["always", "unless-stopped", "on-failure", "no"], + "description": "The restart policy for the application." + }, + "ports": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[0-9]+:[0-9]+(/tcp|/udp)?$", + "description": "A port mapping in the format 'hostPort:containerPort/protocol'." + }, + "description": "An array of port mappings for the application." + }, + "volumes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "bind": { + "type": "string", + "minLength": 1, + "description": "The host path for the volume binding." + }, + "container": { + "type": "string", + "minLength": 1, + "description": "The container path for the volume binding." + } + }, + "required": ["bind", "container"] + }, + "description": "An array of volume mappings for the application." + }, + "environment": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "The name of the environment variable." + }, + "label": { + "type": "string" + } + } + } + } + }, + "required": ["type", "title", "description", "categories", "platform", "logo", "image"] + } + } + }, + "required": ["version", "templates"] +} + diff --git a/lib/validate.py b/lib/validate.py new file mode 100644 index 0000000..5f6cda3 --- /dev/null +++ b/lib/validate.py @@ -0,0 +1,35 @@ +import json +import os +import sys +from jsonschema import validate, ValidationError + +def load_json_file(file_path): + with open(file_path, 'r') as file: + return json.load(file) + +def main(): + try: + script_dir = os.path.dirname(os.path.abspath(__file__)) + + schema_file = os.path.join(script_dir, '..', 'Schema.json') + templates_file = os.path.join(script_dir, '..', 'templates.json') + + schema = load_json_file(schema_file) + templates = load_json_file(templates_file) + + validate(instance=templates, schema=schema) + + print('✅ templates.json is valid against the schema') + + except ValidationError as ve: + print('Validation error:', ve.message) + sys.exit(1) + except FileNotFoundError as fnfe: + print(f'File not found error: {fnfe}') + sys.exit(1) + except json.JSONDecodeError as jde: + print(f'JSON decoding error: {jde}') + sys.exit(1) + +if __name__ == '__main__': + main()