diff --git a/newsfragments/env-var-interpolation-for-keys.feature b/newsfragments/env-var-interpolation-for-keys.feature new file mode 100644 index 0000000..d1b39c8 --- /dev/null +++ b/newsfragments/env-var-interpolation-for-keys.feature @@ -0,0 +1 @@ +Add support for environment variable interpolation for YAML keys. diff --git a/podman_compose.py b/podman_compose.py index f710a28..61c0a55 100755 --- a/podman_compose.py +++ b/podman_compose.py @@ -290,7 +290,7 @@ def rec_subs(value: dict | str | Iterable, subs_dict: dict[str, Any]) -> dict | svc_envs = rec_subs(svc_envs, subs_dict) subs_dict.update(svc_envs) - value = {k: rec_subs(v, subs_dict) for k, v in value.items()} + value = {rec_subs(k, subs_dict): rec_subs(v, subs_dict) for k, v in value.items()} elif isinstance(value, str): def convert(m: re.Match) -> str: diff --git a/tests/integration/interpolation/.env b/tests/integration/interpolation/.env index 272b573..2728dd9 100644 --- a/tests/integration/interpolation/.env +++ b/tests/integration/interpolation/.env @@ -1 +1,2 @@ DOT_ENV_VARIABLE=This value is from the .env file +TEST_LABELS=TEST diff --git a/tests/integration/interpolation/docker-compose.yml b/tests/integration/interpolation/docker-compose.yml index da0b5cf..97de648 100644 --- a/tests/integration/interpolation/docker-compose.yml +++ b/tests/integration/interpolation/docker-compose.yml @@ -11,4 +11,10 @@ services: EXAMPLE_DOT_ENV: $DOT_ENV_VARIABLE EXAMPLE_LITERAL: This is a $$literal EXAMPLE_EMPTY: $NOT_A_VARIABLE + labels_test: + image: busybox + labels: + - "$TEST_LABELS=test_labels" + - test.${TEST_LABELS}=${TEST_LABELS} + - "${TEST_LABELS}.test2=test2(`${TEST_LABELS}`)" diff --git a/tests/integration/interpolation/test_podman_compose_interpolation.py b/tests/integration/interpolation/test_podman_compose_interpolation.py index 14c8a54..b9ae0c9 100644 --- a/tests/integration/interpolation/test_podman_compose_interpolation.py +++ b/tests/integration/interpolation/test_podman_compose_interpolation.py @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 +import json import os import unittest @@ -36,6 +37,18 @@ class TestComposeInterpolation(unittest.TestCase, RunSubprocessMixin): self.assertIn("EXAMPLE_DOT_ENV='This value is from the .env file'", str(output)) self.assertIn("EXAMPLE_EMPTY=''", str(output)) self.assertIn("EXAMPLE_LITERAL='This is a $literal'", str(output)) + + output, _ = self.run_subprocess_assert_returncode([ + "podman", + "inspect", + "interpolation_labels_test_1", + ]) + inspect_output = json.loads(output) + labels_dict = inspect_output[0].get("Config", {}).get("Labels", {}) + self.assertIn(('TEST', 'test_labels'), labels_dict.items()) + self.assertIn(('TEST.test2', 'test2(`TEST`)'), labels_dict.items()) + self.assertIn(('test.TEST', 'TEST'), labels_dict.items()) + finally: self.run_subprocess_assert_returncode([ podman_compose_path(), diff --git a/tests/unit/test_rec_subs.py b/tests/unit/test_rec_subs.py index 82a358d..cd7342c 100644 --- a/tests/unit/test_rec_subs.py +++ b/tests/unit/test_rec_subs.py @@ -71,3 +71,34 @@ class TestRecSubs(unittest.TestCase): sub_dict = {"v1": "high priority", "empty": ""} result = rec_subs(input, sub_dict) self.assertEqual(result, expected, msg=desc) + + def test_env_var_substitution_in_dictionary_keys(self) -> None: + sub_dict = {"NAME": "TEST1", "NAME2": "TEST2"} + input = { + 'services': { + 'test': { + 'image': 'busybox', + 'labels': { + '$NAME and ${NAME2}': '${NAME2} and $NAME', + 'test1.${NAME}': 'test1', + '$NAME': '${NAME2}', + '${NAME}.test2': 'Host(`${NAME2}`)', + }, + } + } + } + result = rec_subs(input, sub_dict) + expected = { + 'services': { + 'test': { + 'image': 'busybox', + 'labels': { + 'TEST1 and TEST2': 'TEST2 and TEST1', + 'test1.TEST1': 'test1', + 'TEST1': 'TEST2', + 'TEST1.test2': 'Host(`TEST2`)', + }, + } + } + } + self.assertEqual(result, expected)