feat: Add hardware metadata schema.

* Initial hardware metadata JSON schema.
* GH Action to validate all schemas for boards/shields.
This commit is contained in:
Peter Johanson 2021-03-27 20:51:04 -04:00 committed by Pete Johanson
parent 4a5454b0f9
commit 1d69bdda60
5 changed files with 368 additions and 0 deletions

View File

@ -0,0 +1,35 @@
name: Hardware Metadata Validation
on:
push:
paths:
- ".github/workflows/hardware-metadata-validation.yml"
- "schema/hardware-metadata.schema.json"
- "app/boards/**/*.zmk.yml"
- "app/scripts/west_commands/metadata.py"
pull_request:
paths:
- ".github/workflows/hardware-metadata-validation.yml"
- "schema/hardware-metadata.schema.json"
- "app/boards/**/*.zmk.yml"
- "app/scripts/west_commands/metadata.py"
jobs:
validate-metadata:
runs-on: ubuntu-latest
container:
image: zmkfirmware/zmk-dev-arm:2.5
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run: pip install -r app/scripts/requirements.txt
- name: West init
run: west init -l app
- name: Update modules (west update)
run: west update
- name: Export Zephyr CMake package (west zephyr-export)
run: west zephyr-export
- name: Validate Hardware Metadata
run: |
cd app
west metadata check

View File

@ -0,0 +1,8 @@
# Copyright (c) 2021 The ZMK Contributors
# SPDX-License-Identifier: MIT
# Convert YAML to JSON for validation
remarshal>=0.14.0
# Perform our hardware metadata validation
jsonschema>=3.2.0

View File

@ -7,3 +7,8 @@ west-commands:
- name: test
class: Test
help: run ZMK testsuite
- file: scripts/west_commands/metadata.py
commands:
- name: metadata
class: Metadata
help: Operate on ZMK metadata files

View File

@ -0,0 +1,59 @@
# Copyright (c) 2021 The ZMK Contributors
# SPDX-License-Identifier: MIT
'''Metadata command for ZMK.'''
from functools import cached_property
import glob
import json
from jsonschema import validate, ValidationError
import os
import sys
import yaml
from textwrap import dedent # just for nicer code indentation
from west.commands import WestCommand
from west import log # use this for user output
class Metadata(WestCommand):
def __init__(self):
super().__init__(
'metadata', # gets stored as self.name
'ZMK hardware metadata commands', # self.help
# self.description:
dedent('''Operate on the board/shield metadata.'''))
def do_add_parser(self, parser_adder):
parser = parser_adder.add_parser(self.name,
help=self.help,
description=self.description)
parser.add_argument('subcommand', default="check",
help='The subcommand to run. Defaults to "check".', nargs="?")
return parser # gets stored as self.parser
@cached_property
def schema(self):
return json.load(
open("../schema/hardware-metadata.schema.json", 'r'))
def validate_file(self, file):
print("Validating: " + file)
with open(file, 'r') as stream:
try:
validate(yaml.safe_load(stream), self.schema)
except yaml.YAMLError as exc:
print("Failed loading metadata yaml: " + file)
print(exc)
return False
except ValidationError as vexc:
print("Failed validation of: " + file)
print(vexc)
return False
return True
def do_run(self, args, unknown_args):
status = all([self.validate_file(f) for f in glob.glob(
"boards/**/*.zmk.yml", recursive=True)])
sys.exit(0 if status else 1)

View File

@ -0,0 +1,261 @@
{
"$id": "https://zmkfirmware.dev/zmk.metadata.json",
"title": "HardwareMetadata",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"oneOf": [
{
"$ref": "#/$defs/board"
},
{
"$ref": "#/$defs/shield"
},
{
"$ref": "#/$defs/interconnect"
}
],
"$defs": {
"id": {
"type": "string",
"pattern": "^[a-z0-9_]+$"
},
"keyboard_siblings": {
"type": "array",
"items": {
"type": "string"
}
},
"variant": {
"oneOf": [
{
"type": "string"
},
{
"type": "object",
"required": [
"id",
"features"
],
"properties": {
"id": {
"$ref": "#/$defs/id"
},
"features": {
"$ref": "#/$defs/features"
}
}
}
]
},
"features": {
"type": "array",
"items": {
"type": "string",
"enum": [
"keys",
"display",
"encoder",
"underglow",
"pointer"
]
}
},
"interconnects": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/id"
}
},
"sibling_details": {
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"$ref": "#/$defs/id"
},
"features": {
"$ref": "#/$defs/features"
},
"variants": {
"type": "array",
"items": {
"$ref": "#/$defs/variant"
}
}
}
},
"interconnect": {
"title": "Interconnect",
"type": "object",
"additionalProperties": false,
"required": [
"file_format",
"id",
"name",
"url",
"type"
],
"properties": {
"file_format": {
"type": "string",
"const": "1"
},
"id": {
"$ref": "#/$defs/id"
},
"name": {
"type": "string"
},
"version": {
"type": "string"
},
"url": {
"type": "string",
"format": "uri"
},
"description": {
"type": "string"
},
"manufacturer": {
"type": "string"
},
"type": {
"type": "string",
"const": "interconnect"
}
}
},
"board": {
"title": "Board",
"type": "object",
"additionalProperties": false,
"required": [
"file_format",
"id",
"name",
"url",
"arch",
"type",
"outputs"
],
"properties": {
"file_format": {
"type": "string",
"const": "1"
},
"id": {
"$ref": "#/$defs/id"
},
"name": {
"type": "string"
},
"version": {
"type": "string"
},
"url": {
"type": "string",
"format": "uri"
},
"description": {
"type": "string"
},
"manufacturer": {
"type": "string"
},
"arch": {
"type": "string",
"pattern": "^[a-z0-9_]+$"
},
"type": {
"type": "string",
"const": "board"
},
"siblings": {
"$ref": "#/$defs/keyboard_siblings"
},
"outputs": {
"type": "array",
"items": {
"type": "string",
"enum": [
"usb",
"ble"
]
}
},
"features": {
"$ref": "#/$defs/features"
},
"variants": {
"type": "array",
"items": {
"$ref": "#/$defs/variant"
}
},
"exposes": {
"$ref": "#/$defs/interconnects"
}
}
},
"shield": {
"title": "Shield",
"type": "object",
"additionalProperties": false,
"required": [
"file_format",
"id",
"name",
"url",
"type",
"requires"
],
"properties": {
"file_format": {
"type": "string",
"const": "1"
},
"id": {
"$ref": "#/$defs/id"
},
"name": {
"type": "string"
},
"url": {
"type": "string",
"format": "uri"
},
"description": {
"type": "string"
},
"manufacturer": {
"type": "string"
},
"version": {
"type": "string"
},
"type": {
"type": "string",
"const": "shield"
},
"features": {
"$ref": "#/$defs/features"
},
"variants": {
"type": "array",
"items": {
"$ref": "#/$defs/variant"
}
},
"siblings": {
"$ref": "#/$defs/keyboard_siblings"
},
"requires": {
"$ref": "#/$defs/interconnects"
},
"exposes": {
"$ref": "#/$defs/interconnects"
}
}
}
}
}