mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-10 21:43:23 -05:00
feat: validate emulator profiles in CI
This commit is contained in:
1 parent
5f60138dce
commit
a0ca5f208a
5 files changed
+155
-15
No files matched your search
@@ -5,6 +5,7 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- "bios/**"
|
- "bios/**"
|
||||||
- "platforms/**"
|
- "platforms/**"
|
||||||
|
- "emulators/**"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
@@ -94,6 +95,34 @@ jobs:
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
"
|
"
|
||||||
|
|
||||||
|
- name: Validate emulator profiles
|
||||||
|
run: |
|
||||||
|
python -c "
|
||||||
|
import json, yaml, sys
|
||||||
|
from jsonschema import validate, ValidationError
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
with open('schemas/emulator.schema.json') as f:
|
||||||
|
schema = json.load(f)
|
||||||
|
|
||||||
|
errors = []
|
||||||
|
for yml_file in sorted(Path('emulators').glob('*.yml')):
|
||||||
|
if yml_file.name.endswith('.old.yml'):
|
||||||
|
continue
|
||||||
|
with open(yml_file) as f:
|
||||||
|
profile = yaml.safe_load(f)
|
||||||
|
try:
|
||||||
|
validate(profile, schema)
|
||||||
|
except ValidationError as e:
|
||||||
|
path = '/'.join(str(p) for p in e.absolute_path)
|
||||||
|
errors.append(f'{yml_file.name}: {path}: {e.message}')
|
||||||
|
print(f'FAIL {yml_file.name}: {path}: {e.message}')
|
||||||
|
|
||||||
|
print(f'{len(errors)} invalid profiles')
|
||||||
|
if errors:
|
||||||
|
sys.exit(1)
|
||||||
|
"
|
||||||
|
|
||||||
run-tests:
|
run-tests:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
emulator: "FreeIntv (Touchscreen Overlay)"
|
emulator: "FreeIntv (Touchscreen Overlay)"
|
||||||
type: alias
|
type: alias
|
||||||
|
alias_of: freeintv
|
||||||
core_classification: alias
|
core_classification: alias
|
||||||
source: "https://github.com/jcarr71/FreeIntvTSOverlay"
|
source: "https://github.com/jcarr71/FreeIntvTSOverlay"
|
||||||
upstream: "https://github.com/libretro/FreeIntv"
|
upstream: "https://github.com/libretro/FreeIntv"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ type: libretro
|
|||||||
core_classification: community_fork
|
core_classification: community_fork
|
||||||
source: https://github.com/DanAlexMorton/3dsTrident
|
source: https://github.com/DanAlexMorton/3dsTrident
|
||||||
upstream: https://github.com/wheremyfoodat/Panda3DS
|
upstream: https://github.com/wheremyfoodat/Panda3DS
|
||||||
profiled_date: 2026-03-25
|
profiled_date: "2026-03-25"
|
||||||
core_version: git
|
core_version: git
|
||||||
|
|
||||||
cores:
|
cores:
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ source: https://github.com/netux79/zc210-libretro
|
|||||||
upstream: https://www.zeldaclassic.com/
|
upstream: https://www.zeldaclassic.com/
|
||||||
core_version: "2.10 Beta 5"
|
core_version: "2.10 Beta 5"
|
||||||
display_name: Zelda Classic v2.10 (ZC210)
|
display_name: Zelda Classic v2.10 (ZC210)
|
||||||
profiled_date: 2026-03-26
|
profiled_date: "2026-03-26"
|
||||||
cores:
|
cores:
|
||||||
- zc210
|
- zc210
|
||||||
systems:
|
systems:
|
||||||
|
|||||||
+123
-13
@@ -1,19 +1,72 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"title": "Emulator BIOS Profile",
|
"title": "Emulator BIOS Profile",
|
||||||
|
"description": "One YAML per emulator core or engine, documenting every external file the code loads. Field reference: https://abdess.github.io/retrobios/wiki/profiling/",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["emulator", "source", "systems", "files"],
|
"required": ["emulator", "type"],
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"comment": "An alias profile points at another profile and carries no files of its own.",
|
||||||
|
"if": {
|
||||||
|
"properties": { "type": { "const": "alias" } },
|
||||||
|
"required": ["type"]
|
||||||
|
},
|
||||||
|
"then": { "required": ["alias_of"] },
|
||||||
|
"else": { "required": ["files"] }
|
||||||
|
}
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"emulator": { "type": "string" },
|
"emulator": { "type": "string" },
|
||||||
|
"display_name": { "type": "string" },
|
||||||
"type": {
|
"type": {
|
||||||
|
"description": "Operational: resolve_platform_cores() filters on it. Not a classification.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["standalone", "libretro", "standalone + libretro"]
|
"enum": [
|
||||||
|
"libretro",
|
||||||
|
"standalone",
|
||||||
|
"standalone + libretro",
|
||||||
|
"alias",
|
||||||
|
"launcher",
|
||||||
|
"game",
|
||||||
|
"utility",
|
||||||
|
"test"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"source": { "type": "string", "format": "uri" },
|
"core_classification": {
|
||||||
"systems": {
|
"description": "Descriptive only, no effect on tooling.",
|
||||||
"type": "array",
|
"type": "string",
|
||||||
"items": { "type": "string" }
|
"enum": [
|
||||||
|
"pure_libretro",
|
||||||
|
"official_port",
|
||||||
|
"community_fork",
|
||||||
|
"frozen_snapshot",
|
||||||
|
"enhanced_fork",
|
||||||
|
"game_engine",
|
||||||
|
"embedded_hle",
|
||||||
|
"launcher",
|
||||||
|
"alias",
|
||||||
|
"other"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
"source": { "type": ["string", "object"] },
|
||||||
|
"upstream": { "type": ["string", "object", "null"] },
|
||||||
|
"source_commit": { "type": "string" },
|
||||||
|
"upstream_commit": { "type": "string" },
|
||||||
|
"profiled_date": {
|
||||||
|
"description": "Quote it: an unquoted YAML date parses to a date object.",
|
||||||
|
"type": ["string", "object"]
|
||||||
|
},
|
||||||
|
"core_version": { "type": ["string", "number", "object", "null"] },
|
||||||
|
"alias_of": { "type": "string" },
|
||||||
|
"cores": {
|
||||||
|
"description": "Upstream names the core is known by. A dict maps each name to per-variant metadata.",
|
||||||
|
"type": ["array", "object"]
|
||||||
|
},
|
||||||
|
"systems": { "type": "array", "items": { "type": "string" } },
|
||||||
|
"mode": { "type": "string", "enum": ["standalone", "libretro", "both"] },
|
||||||
|
"verification": { "type": "string", "enum": ["existence", "md5", "sha1", "crc32"] },
|
||||||
|
"exclusion_note": { "type": "string" },
|
||||||
|
"notes": { "type": ["string", "array", "object"] },
|
||||||
"files": {
|
"files": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
@@ -21,13 +74,70 @@
|
|||||||
"required": ["name"],
|
"required": ["name"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": { "type": "string" },
|
"name": { "type": "string" },
|
||||||
"region": { "type": "string" },
|
"required": { "type": "boolean" },
|
||||||
"required": { "type": "boolean", "default": false },
|
"system": { "type": "string" },
|
||||||
"md5": { "type": "string", "pattern": "^[a-fA-F0-9]{32}$" },
|
"path": { "type": ["string", "null"] },
|
||||||
"sha1": { "type": "string", "pattern": "^[a-f0-9]{40}$" },
|
"destination": { "type": "string" },
|
||||||
"size": { "type": "integer" },
|
"aliases": { "type": "array", "items": { "type": "string" } },
|
||||||
"source_ref": { "type": "string" },
|
"archive": {
|
||||||
"note": { "type": "string" }
|
"description": "ROM set the file lives in, for arcade entries.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"category": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["bios", "game_data", "bios_zip"]
|
||||||
|
},
|
||||||
|
"mode": { "type": "string", "enum": ["standalone", "libretro", "both"] },
|
||||||
|
"storage": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["embedded", "external", "user_provided", "large_file", "release"]
|
||||||
|
},
|
||||||
|
"hle_fallback": { "type": "boolean" },
|
||||||
|
"agnostic": { "type": "boolean" },
|
||||||
|
"size": { "type": ["integer", "array", "null"] },
|
||||||
|
"min_size": { "type": "integer" },
|
||||||
|
"max_size": { "type": "integer" },
|
||||||
|
"md5": {
|
||||||
|
"oneOf": [
|
||||||
|
{ "type": "null" },
|
||||||
|
{ "type": "string", "pattern": "^[a-fA-F0-9]{32}$" },
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"items": { "type": "string", "pattern": "^[a-fA-F0-9]{32}$" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sha1": {
|
||||||
|
"oneOf": [
|
||||||
|
{ "type": "string", "pattern": "^[a-fA-F0-9]{40}$" },
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"items": { "type": "string", "pattern": "^[a-fA-F0-9]{40}$" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sha256": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[a-fA-F0-9]{64}(,[a-fA-F0-9]{64})*$"
|
||||||
|
},
|
||||||
|
"crc32": { "type": "string" },
|
||||||
|
"known_hash_adler32": { "type": ["string", "integer"] },
|
||||||
|
"validation": {
|
||||||
|
"description": "Checks the code performs. A dict splits core from upstream when they diverge.",
|
||||||
|
"oneOf": [
|
||||||
|
{ "type": "array", "items": { "type": "string" } },
|
||||||
|
{ "type": "object" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"region": { "type": ["string", "array"] },
|
||||||
|
"contents": { "type": "array", "items": { "type": "object" } },
|
||||||
|
"source_ref": {
|
||||||
|
"description": "A dict splits core from upstream when the two diverge.",
|
||||||
|
"type": ["string", "array", "object"]
|
||||||
|
},
|
||||||
|
"description": { "type": "string" },
|
||||||
|
"note": { "type": "string" },
|
||||||
|
"unsourceable": { "type": "string" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user