Browse Source

CI: Validate JSON Schema of Services files

Matt Gajownik 3 years ago
parent
commit
de11632a9c
2 changed files with 124 additions and 0 deletions
  1. 40 0
      .github/workflows/services-json.yml
  2. 84 0
      CI/check-jsonschema.py

+ 40 - 0
.github/workflows/services-json.yml

@@ -0,0 +1,40 @@
+name: Services Validator
+
+on:
+  push:
+    paths:
+      - "plugins/rtmp-services/data/services.json"
+      - "plugins/rtmp-services/data/package.json"
+  pull_request:
+    paths:
+      - "plugins/rtmp-services/data/services.json"
+      - "plugins/rtmp-services/data/package.json"
+
+jobs:
+  schema:
+    name: Schema
+    runs-on: [ubuntu-latest]
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+
+      - name: Install & Configure Python
+        run: |
+          sudo apt install python3.9-dev
+          python3.9 -m pip install jsonschema json_source_map
+
+      - name: Validate Service JSON Schema
+        run: |
+          JSON_FILES=(
+            plugins/rtmp-services/data/services.json
+            plugins/rtmp-services/data/package.json
+          )
+          python3.9 CI/check-jsonschema.py "${JSON_FILES[@]}"
+
+      - name: Annotate Errors
+        if: failure()
+        uses: yuzutech/[email protected]
+        with:
+          repo-token: "${{ secrets.GITHUB_TOKEN }}"
+          title: "Service JSON Errors"
+          input: "./validation_errors.json"

+ 84 - 0
CI/check-jsonschema.py

@@ -0,0 +1,84 @@
+import json
+from jsonschema import Draft7Validator
+from json_source_map import calculate
+from json_source_map.errors import InvalidInputError
+import os
+import sys
+
+
+errors = []
+
+
+def main():
+    if len(sys.argv) < 2:
+        print("JSON path required.")
+        return 1
+
+    for filename in sys.argv[1:]:
+        prep(filename)
+
+    try:
+        with open('validation_errors.json', 'w') as outfile:
+            json.dump(errors, outfile)
+    except OSError as e:
+        print(f'Failed to write validation output to file: {e}')
+        return 1
+
+    if errors:
+        return 1
+
+    return 0
+
+
+def prep(filename):
+    try:
+        with open(filename) as json_file:
+            json_string = json_file.read()
+            json_data = json.loads(json_string)
+    except OSError as e:
+        print(f'Failed to load file "{filename}": {e}')
+        return
+
+    schema_filename = json_data.get('$schema')
+    if not schema_filename:
+        print('File has no schema:', filename)
+        return
+
+    file_path = os.path.split(filename)[0]
+    schema_file = os.path.join(file_path, schema_filename)
+
+    try:
+        with open(schema_file) as json_file:
+            schema = json.load(json_file)
+    except OSError as e:
+        print(f'Failed to load schema file "{schema_file}": {e}')
+        return
+
+    validate(filename, json_data, json_string, schema)
+
+
+def validate(filename, json_data, json_string, schema):
+    try:
+        servicesPaths = calculate(json_string)
+    except InvalidInputError as e:
+        print("Error with file:", e)
+        return
+
+    cls = Draft7Validator(schema)
+
+    for e in sorted(cls.iter_errors(json_data), key=str):
+        print(f'{e}\nIn "{filename}"\n\n')
+        errorPath = '/'.join(str(v) for v in e.absolute_path)
+        errorEntry = servicesPaths['/' + errorPath]
+        errors.append({
+            "file": filename,
+            "start_line": errorEntry.value_start.line + 1,
+            "end_line": errorEntry.value_end.line + 1,
+            "title": "Validation Error",
+            "message": e.message,
+            "annotation_level": "failure"
+        })
+
+
+if __name__ == '__main__':
+    sys.exit(main())