launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #27914
[Merge] ~jugmac00/launchpad:add-minimal-launchpad.yml-parser into launchpad:master
Jürgen Gmach has proposed merging ~jugmac00/launchpad:add-minimal-launchpad.yml-parser into launchpad:master.
Commit message:
Add minimal `.launchpad.yaml` parser
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~jugmac00/launchpad/+git/launchpad/+merge/413818
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~jugmac00/launchpad:add-minimal-launchpad.yml-parser into launchpad:master.
diff --git a/lib/lp/code/model/lpcraft.py b/lib/lp/code/model/lpcraft.py
new file mode 100644
index 0000000..38bc880
--- /dev/null
+++ b/lib/lp/code/model/lpcraft.py
@@ -0,0 +1,50 @@
+"""This modules provides a parser for lpcraft's configuration file.
+
+As currently Launchpad is only compatible with Python 3.5, it was not possible
+to reuse lpcraft's parser.
+
+The implementation was copied from `lpcraft/config.py`.
+
+XXX jugmac00 2022-01-07: use lpcraft for parsing the configuration file once
+we are on Python 3.8
+"""
+
+__all__ = ["load_configuration"]
+
+import yaml
+
+
+def _expand_job_values(values):
+ expanded_values = []
+ if "matrix" in values:
+ base_values = values.copy()
+ del base_values["matrix"]
+ for variant in values["matrix"]:
+ variant_values = base_values.copy()
+ variant_values.update(variant)
+ expanded_values.append(variant_values)
+ else:
+ expanded_values.append(values)
+ return expanded_values
+
+
+def load_configuration(configuration_file):
+ """loads a `.launchpad.yaml` file into a `Configuration` object"""
+ # load yaml
+ with open(configuration_file) as stream:
+ content = yaml.safe_load(stream)
+ # expand matrix
+ expanded_values = content.copy()
+ if expanded_values.get("jobs"):
+ expanded_values["jobs"] = {
+ job_name: _expand_job_values(job_values)
+ for job_name, job_values in content["jobs"].items()
+ }
+ # create "data class"
+ return Configuration(expanded_values)
+
+
+class Configuration:
+ """configuration object representation of a `.launchpad.yaml` file"""
+ def __init__(self, d):
+ self.__dict__.update(d)
diff --git a/lib/lp/code/model/tests/test_lpcraft.py b/lib/lp/code/model/tests/test_lpcraft.py
new file mode 100644
index 0000000..ef91016
--- /dev/null
+++ b/lib/lp/code/model/tests/test_lpcraft.py
@@ -0,0 +1,84 @@
+import tempfile
+from textwrap import dedent
+from unittest import TestCase
+
+from lp.code.model.lpcraft import load_configuration
+
+
+class TestLoadConfiguration(TestCase):
+ def create_configuration_file(self, s):
+ _, path = tempfile.mkstemp()
+ with open(path, "w") as f:
+ f.write(s)
+ return path
+
+ def test_load_configuration_with_pipeline(self):
+ c = dedent("""\
+ pipeline:
+ - test
+ """)
+
+ configuration = load_configuration(self.create_configuration_file(c))
+
+ self.assertEqual(
+ ["test"], configuration.pipeline
+ )
+
+ def test_load_configuration_with_pipeline_and_jobs(self):
+ c = dedent("""\
+ pipeline:
+ - test
+ jobs:
+ test:
+ series:
+ focal
+ lint:
+ series:
+ focal
+ publish:
+ series:
+ focal
+ """)
+
+ configuration = load_configuration(self.create_configuration_file(c))
+
+ self.assertEqual(
+ ["test"], configuration.pipeline,
+ )
+
+ self.assertEqual(
+ {
+ "test": [{'series': 'focal'}],
+ "lint": [{'series': 'focal'}],
+ "publish": [{'series': 'focal'}],
+ }, configuration.jobs,
+ )
+
+ def test_expand_matrix(self):
+ c = dedent("""\
+ pipeline:
+ - test
+ jobs:
+ test:
+ matrix:
+ - series: bionic
+ architectures: amd64
+ - series: focal
+ architectures: [amd64, s390x]
+ """)
+
+ configuration = load_configuration(self.create_configuration_file(c))
+
+ self.assertEqual(
+ ["test"], configuration.pipeline,
+ )
+
+ self.assertEqual(
+ {
+ 'test': [
+ {'series': 'bionic', 'architectures': 'amd64'},
+ {'series': 'focal', 'architectures': ['amd64', 's390x']}
+ ]
+ },
+ configuration.jobs,
+ )