| |
@@ -0,0 +1,140 @@
|
| |
+ #!/usr/bin/python3
|
| |
+
|
| |
+
|
| |
+ import gi
|
| |
+ import git
|
| |
+ import os
|
| |
+ import sys
|
| |
+
|
| |
+ from gi.repository import GLib
|
| |
+ gi.require_version('Modulemd', '1.0')
|
| |
+ from gi.repository import Modulemd
|
| |
+
|
| |
+ def do_validate(filename):
|
| |
+ # Valid filenames must end in ".yaml" to be properly included by Pungi
|
| |
+ if not filename.endswith(".yaml"):
|
| |
+ print("%s does not end with .yaml. It will not be included by "
|
| |
+ "Pungi. If this file does not contain defaults, it should "
|
| |
+ "be added to the tests/exclusions.txt file." % filename,
|
| |
+ file=sys.stderr,)
|
| |
+ return False, None
|
| |
+
|
| |
+ # The files must parse correctly
|
| |
+ try:
|
| |
+ (objects, failures) = Modulemd.objects_from_file_ext(filename)
|
| |
+ except GLib.Error as e:
|
| |
+ print(e.message, file=sys.stderr)
|
| |
+ return False, None
|
| |
+
|
| |
+ if (failures):
|
| |
+ for failure in failures:
|
| |
+ print("Failed subdocument (%s): \n%s\n", failure.message,
|
| |
+ failure.doc, file=sys.stderr)
|
| |
+ return False, None
|
| |
+
|
| |
+ # There must be exactly one object per file
|
| |
+ if len(objects) != 1:
|
| |
+ print("There must be exactly one subdocument", file=sys.stderr)
|
| |
+ return False, None
|
| |
+
|
| |
+ # The files must have exactly one Modulemd.Defaults object
|
| |
+ try:
|
| |
+ (default, def_failures) = \
|
| |
+ Modulemd.Defaults.new_from_file_ext (filename)
|
| |
+ except GLib.Error as e:
|
| |
+ print(e.message, file=sys.stderr)
|
| |
+ return False, None
|
| |
+
|
| |
+ # Filenames must match their contents
|
| |
+ expected_name = os.path.basename(filename).rsplit('.', maxsplit=1)[0]
|
| |
+
|
| |
+ if expected_name != default.props.module_name:
|
| |
+ print("Module name \"%s\" doesn't match filename \"%s.yaml\"" % (
|
| |
+ default.props.module_name, expected_name),
|
| |
+ file=sys.stderr)
|
| |
+ return False, None
|
| |
+
|
| |
+ if default.props.default_stream:
|
| |
+ # Default streams must also appear in the profiles list
|
| |
+ if not default.props.default_stream in default.props.profile_defaults:
|
| |
+ print("Stream '%s' missing from profiles" % (
|
| |
+ default.props.default_stream),
|
| |
+ file=sys.stderr)
|
| |
+ return False, None
|
| |
+
|
| |
+ # Modules in Fedora must not specify "Intents"
|
| |
+ try:
|
| |
+ if (default.props.intents):
|
| |
+ print ('Module name "%s" includes the intents section, which is '
|
| |
+ 'not currently permitted in Fedora.' % (
|
| |
+ default.props.module_name),
|
| |
+ file=sys.stderr)
|
| |
+ return False, None
|
| |
+ except AttributeError:
|
| |
+ # The available version of libmodulemd does not support intents
|
| |
+ pass
|
| |
+
|
| |
+ print("%s is valid" % filename)
|
| |
+ return (True, default)
|
| |
+
|
| |
+
|
| |
+ def main():
|
| |
+ result = os.EX_OK
|
| |
+
|
| |
+ script_dir = os.path.dirname(os.path.realpath(__file__))
|
| |
+
|
| |
+ # Get the repo we're running in
|
| |
+ repo = git.Repo(script_dir,
|
| |
+ search_parent_directories=True)
|
| |
+
|
| |
+ # Get the list of files in this repository
|
| |
+ files = [x for (x, y) in repo.index.entries.keys()]
|
| |
+
|
| |
+ # Get the list of excluded files
|
| |
+ exclusions = []
|
| |
+ with open(os.path.join(script_dir, "exclusions.txt")) as f:
|
| |
+ for line in f:
|
| |
+ stripped_line = line.strip()
|
| |
+ if not stripped_line or stripped_line.startswith("#"):
|
| |
+ # Ignore comments and empty lines
|
| |
+ continue
|
| |
+ exclusions.append(line.strip())
|
| |
+
|
| |
+ # Validate all of the files
|
| |
+ prioritizer = Modulemd.Prioritizer()
|
| |
+ for file in files:
|
| |
+ excluded = False
|
| |
+ for excl in exclusions:
|
| |
+ if (file.startswith(excl)):
|
| |
+ excluded = True
|
| |
+ break
|
| |
+ if not excluded:
|
| |
+ (valid, obj) = do_validate(file)
|
| |
+ if not valid:
|
| |
+ print("%s failed to validate" % file, file=sys.stderr)
|
| |
+ result = os.EX_DATAERR
|
| |
+ else:
|
| |
+ try:
|
| |
+ prioritizer.add([obj,], 0)
|
| |
+ except GLib.Error as e:
|
| |
+ print("Could not merge %s with other defaults: %s" % (
|
| |
+ file, e.message))
|
| |
+ result = os.EX_DATAERR
|
| |
+
|
| |
+ if result == os.EX_DATAERR:
|
| |
+ return result
|
| |
+
|
| |
+ # For sanity's sake, also do a merge of all the defaults to make sure no
|
| |
+ # conflicts arise that weren't detected by the above tests. This should be
|
| |
+ # impossible.
|
| |
+ try:
|
| |
+ prioritizer.resolve()
|
| |
+ except GLib.Error as e:
|
| |
+ print("Could not merge all defaults: %s" % e.message)
|
| |
+ result = os.EX_DATAERR
|
| |
+
|
| |
+
|
| |
+ return result
|
| |
+
|
| |
+ if __name__ == "__main__":
|
| |
+ sys.exit(main())
|
| |
\ No newline at end of file
|
| |
This script should be run on all pull-requests to ensure that no invalid module defaults get merged.
This patch is a precursor to adding CI for pull-requests on this repository. It is being submitted so the validation tests can be reviewed in parallel with the CI work.
Signed-off-by: Stephen Gallagher sgallagh@redhat.com