← Back to team overview

launchpad-reviewers team mailing list archive

[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,
+        )