Merge pull request #1258 from mokibit/add-env-var-interpolation-to-keys

Implement environment variable interpolation to YAML dictionary keys
This commit is contained in:
Povilas Kanapickas
2025-07-01 00:15:05 +03:00
committed by GitHub
6 changed files with 53 additions and 1 deletions

View File

@ -0,0 +1 @@
Add support for environment variable interpolation for YAML keys.

View File

@ -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:

View File

@ -1 +1,2 @@
DOT_ENV_VARIABLE=This value is from the .env file
TEST_LABELS=TEST

View File

@ -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}`)"

View File

@ -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(),

View File

@ -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)