Skip to content

Commit 28ec08c

Browse files
committed
feat: Add support for COMPOSE_PROFILES environment variable
This change implements support for the COMPOSE_PROFILES environment variable, allowing users to specify active Compose profiles through their environment. The behavior is as follows: - Profiles from COMPOSE_PROFILES (comma-separated) are activated. - Both the environment variable and the --profile CLI flag can be used together, with the resulting set of active profiles being the union of both. Signed-off-by: Watson Dinh <[email protected]>
1 parent 036c0dc commit 28ec08c

File tree

3 files changed

+76
-2
lines changed

3 files changed

+76
-2
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Support COMPOSE_PROFILES environment variable to enable profiles.

podman_compose.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2231,6 +2231,11 @@ def _parse_compose_file(self) -> None:
22312231
env_vars = norm_as_dict(args.env)
22322232
self.environ.update(env_vars) # type: ignore[arg-type]
22332233

2234+
profiles_from_env = {
2235+
p.strip() for p in self.environ.get("COMPOSE_PROFILES", "").split(",") if p.strip()
2236+
}
2237+
requested_profiles = set(args.profile).union(profiles_from_env)
2238+
22342239
compose: dict[str, Any] = {}
22352240
# Iterate over files primitively to allow appending to files in-loop
22362241
files_iter = iter(files)
@@ -2296,7 +2301,7 @@ def _parse_compose_file(self) -> None:
22962301
# Solution is to remove 'include' key from compose obj. This doesn't break
22972302
# having `include` present and correctly processed in included files
22982303
del compose["include"]
2299-
resolved_services = self._resolve_profiles(compose.get("services", {}), set(args.profile))
2304+
resolved_services = self._resolve_profiles(compose.get("services", {}), requested_profiles)
23002305
compose["services"] = resolved_services
23012306
if not getattr(args, "no_normalize", None):
23022307
compose = normalize_final(compose, self.dirname)
@@ -2318,7 +2323,7 @@ def _parse_compose_file(self) -> None:
23182323
services = {}
23192324
log.warning("WARNING: No services defined")
23202325
# include services with no profile defined or the selected profiles
2321-
services = self._resolve_profiles(services, set(args.profile))
2326+
services = self._resolve_profiles(services, requested_profiles)
23222327

23232328
# NOTE: maybe add "extends.service" to _deps at this stage
23242329
flat_deps(services, with_extends=True)

tests/integration/profile/test_podman_compose_up_down.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,71 @@ def test_up(self, profiles: List[str], expected_services: dict) -> None:
9090
actual_services[service] = service in actual_output
9191

9292
self.assertEqual(expected_services, actual_services)
93+
94+
@parameterized.expand(
95+
[
96+
(
97+
["--profile", "profile-1"],
98+
"profile-2",
99+
{"default-service": True, "service-1": True, "service-2": True},
100+
),
101+
(
102+
[],
103+
"profile-1,profile-2",
104+
{"default-service": True, "service-1": True, "service-2": True},
105+
),
106+
(
107+
[],
108+
"profile-1, profile-2",
109+
{"default-service": True, "service-1": True, "service-2": True},
110+
),
111+
(
112+
[],
113+
"",
114+
{"default-service": True, "service-1": False, "service-2": False},
115+
),
116+
(
117+
[],
118+
",",
119+
{"default-service": True, "service-1": False, "service-2": False},
120+
),
121+
],
122+
)
123+
def test_up_with_compose_profiles_env(
124+
self, profiles: List[str], compose_profiles: str, expected_services: dict
125+
) -> None:
126+
"""
127+
Tests the `up` command when the `COMPOSE_PROFILES` environment variable is set.
128+
"""
129+
up_cmd = [
130+
"coverage",
131+
"run",
132+
podman_compose_path(),
133+
"-f",
134+
profile_compose_file(),
135+
]
136+
up_cmd.extend(profiles)
137+
up_cmd.extend(["up", "-d"])
138+
139+
env = os.environ.copy()
140+
env["COMPOSE_PROFILES"] = compose_profiles
141+
142+
self.run_subprocess_assert_returncode(up_cmd, env=env)
143+
144+
check_cmd = [
145+
"podman",
146+
"container",
147+
"ps",
148+
"--format",
149+
'"{{.Names}}"',
150+
]
151+
out, _ = self.run_subprocess_assert_returncode(check_cmd)
152+
153+
self.assertEqual(len(expected_services), 3)
154+
actual_output = out.decode("utf-8")
155+
156+
actual_services = {}
157+
for service, _ in expected_services.items():
158+
actual_services[service] = service in actual_output
159+
160+
self.assertEqual(expected_services, actual_services)

0 commit comments

Comments
 (0)