diff --git a/newsfragments/compose_profiles_env.feature b/newsfragments/compose_profiles_env.feature new file mode 100644 index 0000000..99e6e5a --- /dev/null +++ b/newsfragments/compose_profiles_env.feature @@ -0,0 +1 @@ +Support COMPOSE_PROFILES environment variable to enable profiles. diff --git a/podman_compose.py b/podman_compose.py index c3c44cc..e627923 100755 --- a/podman_compose.py +++ b/podman_compose.py @@ -2231,6 +2231,11 @@ class PodmanCompose: env_vars = norm_as_dict(args.env) self.environ.update(env_vars) # type: ignore[arg-type] + profiles_from_env = { + p.strip() for p in self.environ.get("COMPOSE_PROFILES", "").split(",") if p.strip() + } + requested_profiles = set(args.profile).union(profiles_from_env) + compose: dict[str, Any] = {} # Iterate over files primitively to allow appending to files in-loop files_iter = iter(files) @@ -2296,7 +2301,7 @@ class PodmanCompose: # Solution is to remove 'include' key from compose obj. This doesn't break # having `include` present and correctly processed in included files del compose["include"] - resolved_services = self._resolve_profiles(compose.get("services", {}), set(args.profile)) + resolved_services = self._resolve_profiles(compose.get("services", {}), requested_profiles) compose["services"] = resolved_services if not getattr(args, "no_normalize", None): compose = normalize_final(compose, self.dirname) @@ -2318,7 +2323,7 @@ class PodmanCompose: services = {} log.warning("WARNING: No services defined") # include services with no profile defined or the selected profiles - services = self._resolve_profiles(services, set(args.profile)) + services = self._resolve_profiles(services, requested_profiles) # NOTE: maybe add "extends.service" to _deps at this stage flat_deps(services, with_extends=True) diff --git a/tests/integration/profile/test_podman_compose_up_down.py b/tests/integration/profile/test_podman_compose_up_down.py index 63e5050..b0afba2 100644 --- a/tests/integration/profile/test_podman_compose_up_down.py +++ b/tests/integration/profile/test_podman_compose_up_down.py @@ -90,3 +90,71 @@ class TestUpDown(unittest.TestCase, RunSubprocessMixin): actual_services[service] = service in actual_output self.assertEqual(expected_services, actual_services) + + @parameterized.expand( + [ + ( + ["--profile", "profile-1"], + "profile-2", + {"default-service": True, "service-1": True, "service-2": True}, + ), + ( + [], + "profile-1,profile-2", + {"default-service": True, "service-1": True, "service-2": True}, + ), + ( + [], + "profile-1, profile-2", + {"default-service": True, "service-1": True, "service-2": True}, + ), + ( + [], + "", + {"default-service": True, "service-1": False, "service-2": False}, + ), + ( + [], + ",", + {"default-service": True, "service-1": False, "service-2": False}, + ), + ], + ) + def test_up_with_compose_profiles_env( + self, profiles: List[str], compose_profiles: str, expected_services: dict + ) -> None: + """ + Tests the `up` command when the `COMPOSE_PROFILES` environment variable is set. + """ + up_cmd = [ + "coverage", + "run", + podman_compose_path(), + "-f", + profile_compose_file(), + ] + up_cmd.extend(profiles) + up_cmd.extend(["up", "-d"]) + + env = os.environ.copy() + env["COMPOSE_PROFILES"] = compose_profiles + + self.run_subprocess_assert_returncode(up_cmd, env=env) + + check_cmd = [ + "podman", + "container", + "ps", + "--format", + '"{{.Names}}"', + ] + out, _ = self.run_subprocess_assert_returncode(check_cmd) + + self.assertEqual(len(expected_services), 3) + actual_output = out.decode("utf-8") + + actual_services = {} + for service, _ in expected_services.items(): + actual_services[service] = service in actual_output + + self.assertEqual(expected_services, actual_services)