diff --git a/newsfragments/fix-short-syntax-env-variables.bugfix b/newsfragments/fix-short-syntax-env-variables.bugfix new file mode 100644 index 0000000..becafec --- /dev/null +++ b/newsfragments/fix-short-syntax-env-variables.bugfix @@ -0,0 +1 @@ +Implemented short syntax for environment variables set in `.env` for compose.yml "environment:" section. diff --git a/podman_compose.py b/podman_compose.py index dda6792..89395fb 100755 --- a/podman_compose.py +++ b/podman_compose.py @@ -1159,7 +1159,14 @@ async def container_to_args( podman_args.extend(["-e", e]) env = norm_as_list(cnt.get("environment", {})) for e in env: - podman_args.extend(["-e", e]) + # new environment variable is set + if "=" in e: + podman_args.extend(["-e", e]) + else: + # environment variable already exists in environment so pass its value + if e in compose.environ.keys(): + podman_args.extend(["-e", f"{e}={compose.environ[e]}"]) + tmpfs_ls = cnt.get("tmpfs", []) if isinstance(tmpfs_ls, str): tmpfs_ls = [tmpfs_ls] diff --git a/tests/integration/env_file_tests/project/.env b/tests/integration/env_file_tests/project/.env index cc2c0ce..629bc2d 100644 --- a/tests/integration/env_file_tests/project/.env +++ b/tests/integration/env_file_tests/project/.env @@ -1,2 +1,3 @@ ZZVAR1='This value is loaded but should be overwritten' ZZVAR2='This value is loaded from .env in project/ directory' +ZZVAR3=TEST diff --git a/tests/integration/env_file_tests/project/container-compose.short_syntax.yaml b/tests/integration/env_file_tests/project/container-compose.short_syntax.yaml new file mode 100644 index 0000000..2e0c3eb --- /dev/null +++ b/tests/integration/env_file_tests/project/container-compose.short_syntax.yaml @@ -0,0 +1,10 @@ +services: + app: + image: nopush/podman-compose-test + command: ["/bin/busybox", "sh", "-c", "env | grep ZZVAR3"] + # 'env_file:' section is not used, so .env file is searched in the same directory as compose.yml + # file + environment: + # this is short syntax: podman-compose takes only this variable value from '.env' file and + # sends it to container environment + - ZZVAR3 diff --git a/tests/integration/env_file_tests/test_podman_compose_env_file.py b/tests/integration/env_file_tests/test_podman_compose_env_file.py index 73607f3..329aa33 100644 --- a/tests/integration/env_file_tests/test_podman_compose_env_file.py +++ b/tests/integration/env_file_tests/test_podman_compose_env_file.py @@ -233,7 +233,7 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin): [ 'ZZVAR1=This value is loaded but should be overwritten\r', 'ZZVAR2=This value is loaded from .env in project/ directory\r', - 'ZZVAR3=\r', + 'ZZVAR3=TEST\r', '', ], ) @@ -244,3 +244,36 @@ class TestComposeEnvFile(unittest.TestCase, RunSubprocessMixin): path_compose_file, "down", ]) + + def test_env_var_value_accessed_in_compose_file_short_syntax(self) -> None: + # Test that compose file can access the environment variable set in .env file using + # short syntax, that is: only the name of environment variable is used in "environment:" in + # compose.yml file and its value is picked up directly from .env file + # long syntax of environment variables interpolation is tested in + # tests/integration/interpolation + + base_path = compose_base_path() + compose_file_path = os.path.join(base_path, "project/container-compose.short_syntax.yaml") + try: + self.run_subprocess_assert_returncode([ + podman_compose_path(), + "-f", + compose_file_path, + "up", + "-d", + ]) + output, _ = self.run_subprocess_assert_returncode([ + podman_compose_path(), + "-f", + compose_file_path, + "logs", + ]) + # ZZVAR3 was set in .env file + self.assertEqual(output, b"ZZVAR3=TEST\n") + finally: + self.run_subprocess_assert_returncode([ + podman_compose_path(), + "-f", + compose_file_path, + "down", + ]) diff --git a/tests/unit/test_container_to_args.py b/tests/unit/test_container_to_args.py index bf21ad8..aba4a51 100644 --- a/tests/unit/test_container_to_args.py +++ b/tests/unit/test_container_to_args.py @@ -262,6 +262,42 @@ class TestContainerToArgs(unittest.IsolatedAsyncioTestCase): ], ) + @parameterized.expand([ + # short syntax: only take this specific environment variable value from .env file + ("use_env_var_from_default_env_file_short_syntax", ["ZZVAR1"], "ZZVAR1=TEST1"), + # long syntax: environment variable value from .env file is taken through variable + # interpolation + # only the value required in 'environment:' compose file is sent to containers + # environment + ("use_env_var_from_default_env_file_long_syntax", ["ZZVAR1=TEST1"], "ZZVAR1=TEST1"), + # "environment:" section in compose file overrides environment variable value from .env file + ( + "use_env_var_from_default_env_file_override_value", + ["ZZVAR1=NEW_TEST1"], + "ZZVAR1=NEW_TEST1", + ), + ]) + async def test_env_file(self, test_name: str, cnt_env: list, expected_var: str) -> None: + c = create_compose_mock() + # environment variables were set in .env file + c.environ = {"ZZVAR1": "TEST1", "ZZVAR2": "TEST2"} + + cnt = get_minimal_container() + cnt["environment"] = cnt_env + + args = await container_to_args(c, cnt) + self.assertEqual( + args, + [ + "--name=project_name_service_name1", + "-d", + "-e", + f"{expected_var}", + "--network=bridge:alias=service_name", + "busybox", + ], + ) + async def test_env_file_str(self) -> None: c = create_compose_mock()