diff --git a/.github/sc4pac-yaml-schema.py b/.github/sc4pac-yaml-schema.py index f043ceef..11a418d2 100644 --- a/.github/sc4pac-yaml-schema.py +++ b/.github/sc4pac-yaml-schema.py @@ -111,6 +111,34 @@ } +class DependencyChecker: + def __init__(self): + self.known_packages = set() + self.known_assets = set() + self.referenced_packages = set() + self.referenced_assets = set() + + def aggregate_identifiers(self, doc): + if 'assetId' in doc: + self.known_assets.add(doc['assetId']) + if 'group' in doc and 'name' in doc: + self.known_packages.add(doc['group'] + ":" + doc['name']) + self.referenced_packages.update(doc.get('dependencies', [])) + self.referenced_assets.update( + a['assetId'] for a in doc.get('assets', []) + if 'assetId' in a) + for v in doc.get('variants', []): + self.referenced_packages.update(v.get('dependencies', [])) + self.referenced_assets.update( + a['assetId'] for a in v.get('assets', []) + if 'assetId' in a) + + def unknowns(self): + packages = sorted(self.referenced_packages.difference(self.known_packages)) + assets = sorted(self.referenced_assets.difference(self.known_assets)) + return {'packages': packages, 'assets': assets} + + def main() -> int: args = sys.argv[1:] if not args: @@ -121,6 +149,7 @@ def main() -> int: from jsonschema import exceptions validator = Draft202012Validator(schema) validator.check_schema(schema) + dependencyChecker = DependencyChecker() validated = 0 errors = 0 for d in args: @@ -133,11 +162,33 @@ def main() -> int: validated += 1 text = f.read() for doc in yaml.safe_load_all(text): + dependencyChecker.aggregate_identifiers(doc) err = exceptions.best_match(validator.iter_errors(doc)) - if err is not None: + msgs = [] if err is None else [err.message] + + # check URLs + urls = [u for u in [doc.get('url'), doc.get('info', {}).get('website')] + if u is not None] + for u in urls: + if '/sc4evermore.com/' in u: + msgs.append(f"Domain of URL {u} should be www.sc4evermore.com") + + if msgs: errors += 1 print(f"===> {p}") - print(err.message) + for msg in msgs: + print(msg) + + if not errors: + # check that all dependencies exist + # (this check only makes sense for the self-contained main channel) + for label, unknown in dependencyChecker.unknowns().items(): + if unknown: + errors += len(unknown) + print(f"===> The following {label} are referenced, but not defined:") + for identifier in unknown: + print(identifier) + if errors > 0: print(f"Finished with {errors} errors.") return 1