← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~artivis/lpcraft:feature/yaml-alias into lpcraft:main

 

jeremie has proposed merging ~artivis/lpcraft:feature/yaml-alias into lpcraft:main.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~artivis/lpcraft/+git/lpcraft/+merge/435370

Changes pydantic configuration for extra fields from 'forbid' to 'ignore'. This allows defining extra fields which can be used to e.g. define yaml anchors. Aliases are resolved to anchors by pyyaml before being ignored (filtered out) by pydantic.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~artivis/lpcraft:feature/yaml-alias into lpcraft:main.
diff --git a/lpcraft/config.py b/lpcraft/config.py
index d228270..eaaf73c 100644
--- a/lpcraft/config.py
+++ b/lpcraft/config.py
@@ -31,7 +31,7 @@ class _Identifier(pydantic.ConstrainedStr):
 
 class ModelConfigDefaults(
     pydantic.BaseModel,
-    extra=pydantic.Extra.forbid,
+    extra=pydantic.Extra.ignore,
     alias_generator=lambda s: s.replace("_", "-"),
     underscore_attrs_are_private=True,
 ):
diff --git a/lpcraft/tests/test_config.py b/lpcraft/tests/test_config.py
index 6c69eab..8695520 100644
--- a/lpcraft/tests/test_config.py
+++ b/lpcraft/tests/test_config.py
@@ -825,3 +825,87 @@ class TestConfig(TestCase):
             Config.load,
             path,
         )
+
+    def test_yaml_anchor_alias_single_value(self):
+        # A yaml alias is resolved to an anchor holding a single value.
+        path = self.create_config(
+            dedent(
+                """
+                pipeline:
+                    - test
+
+                jobs:
+                    test-a:
+                        series: &myseries focal
+                        architectures: [amd64]
+
+                    test-b:
+                        series: *myseries
+                        architectures: [amd64]
+                """
+            )
+        )
+        config = Config.load(path)
+        self.assertEqual(
+            config.jobs["test-a"][0].series, config.jobs["test-b"][0].series
+        )
+        self.assertEqual("focal", config.jobs["test-b"][0].series)
+
+    def test_yaml_anchor_alias_single_value_at_root(self):
+        # A yaml alias is resolved to an anchor holding a single value.
+        path = self.create_config(
+            dedent(
+                """
+                .series: &myseries focal
+
+                pipeline:
+                    - test
+
+                jobs:
+                    test:
+                        series: *myseries
+                        architectures: [amd64]
+                """
+            )
+        )
+        config = Config.load(path)
+        self.assertEqual("focal", config.jobs["test"][0].series)
+
+    def test_yaml_anchor_alias_job(self):
+        # A yaml alias is resolved to an anchor holding a whole job.
+        # The root-level extra filed is filtered out by pydantic.
+        path = self.create_config(
+            dedent(
+                """
+                .test: &mytest
+                    series: focal
+                    architectures: [amd64]
+
+                pipeline:
+                    - test
+
+                jobs:
+                    test: *mytest
+                """
+            )
+        )
+        config = Config.load(path)
+
+        self.assertThat(
+            config,
+            MatchesStructure(
+                pipeline=Equals([["test"]]),
+                jobs=MatchesDict(
+                    {
+                        "test": MatchesListwise(
+                            [
+                                MatchesStructure.byEquality(
+                                    series="focal",
+                                    architectures=["amd64"],
+                                )
+                            ]
+                        )
+                    }
+                ),
+            ),
+        )

Follow ups