Skip to content

Commit b291a96

Browse files
authored
Merge pull request #1351 from mammo0/fix-reset-tag-with-extends
Fix for reset tag used with extends
2 parents 5dcfa14 + 8c35b51 commit b291a96

File tree

8 files changed

+104
-13
lines changed

8 files changed

+104
-13
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed !reset and !override tags used used with extended compose file

podman_compose.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,7 +1519,7 @@ def flat_deps(services: dict[str, Any], with_extends: bool = False) -> None:
15191519

15201520

15211521
class OverrideTag(yaml.YAMLObject):
1522-
yaml_dumper = yaml.Dumper
1522+
yaml_dumper = yaml.SafeDumper
15231523
yaml_loader = yaml.SafeLoader
15241524
yaml_tag = '!override'
15251525

@@ -1548,7 +1548,7 @@ def to_yaml(cls, dumper: Any, data: OverrideTag) -> str:
15481548

15491549

15501550
class ResetTag(yaml.YAMLObject):
1551-
yaml_dumper = yaml.Dumper
1551+
yaml_dumper = yaml.SafeDumper
15521552
yaml_loader = yaml.SafeLoader
15531553
yaml_tag = '!reset'
15541554

@@ -2214,17 +2214,34 @@ def config_hash(self, service: dict[str, Any]) -> str:
22142214
return service["_config_hash"]
22152215

22162216
# Use a stable representation of the service configuration
2217-
jsonable_service = self.original_service(service)
2217+
jsonable_service = self.original_configuration(service)
22182218
config_str = json.dumps(jsonable_service, sort_keys=True)
22192219
service["_config_hash"] = hashlib.sha256(config_str.encode('utf-8')).hexdigest()
22202220
return service["_config_hash"]
22212221

2222-
def original_service(self, service: dict[str, Any]) -> dict[str, Any]:
2222+
def original_configuration(self, configuration: dict[Any, Any]) -> dict[str, Any]:
22232223
"""
2224-
Returns the original service configuration without any overrides or resets.
2225-
This is used to compare the original service configuration with the current one.
2224+
Returns the original configuration without any overrides or resets.
2225+
This is used to get a stable representation of the configuration.
2226+
(can be converted to a JSON string)
22262227
"""
2227-
return {k: v for k, v in service.items() if isinstance(k, str) and not k.startswith("_")}
2228+
return {
2229+
# recurse if the value is also a dictionary
2230+
key: self.original_configuration(value) if isinstance(value, dict) else value
2231+
# iterate over the configuration items
2232+
for key, value in configuration.items()
2233+
# filter
2234+
if (
2235+
# only string keys
2236+
isinstance(key, str)
2237+
# which do not start with an underscore
2238+
and not key.startswith("_")
2239+
# also exclude !override
2240+
and not isinstance(value, OverrideTag)
2241+
# and !reset tags
2242+
and not isinstance(value, ResetTag)
2243+
)
2244+
}
22282245

22292246
def resolve_pod_name(self) -> str | None:
22302247
# Priorities:
@@ -2459,12 +2476,14 @@ def _parse_compose_file(self) -> None:
24592476
if not getattr(args, "no_normalize", None):
24602477
compose = normalize_final(compose, self.dirname)
24612478
self.merged_yaml = yaml.safe_dump(compose)
2462-
merged_json_b = json.dumps(compose, separators=(",", ":")).encode("utf-8")
2479+
merged_json_b = json.dumps(
2480+
self.original_configuration(compose), separators=(",", ":")
2481+
).encode("utf-8")
24632482
self.yaml_hash = hashlib.sha256(merged_json_b).hexdigest()
24642483
compose["_dirname"] = dirname
24652484
# debug mode
24662485
if len(files) > 1:
2467-
log.debug(" ** merged:\n%s", json.dumps(compose, indent=2))
2486+
log.debug(" ** merged:\n%s", json.dumps(self.original_configuration(compose), indent=2))
24682487
# ver = compose.get('version')
24692488

24702489
self._parse_x_podman_settings(compose, self.environ)

tests/integration/merge/reset_and_override_tags/reset_tag_attribute_w_extends/__init__.py

Whitespace-only changes.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
webapp:
2+
image: nopush/podman-compose-test
3+
ports:
4+
- "8000:8000"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
version: "3"
2+
services:
3+
web:
4+
extends:
5+
file: common-services.yml
6+
service: webapp
7+
ports: !reset []
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
3+
import json
4+
import os
5+
import unittest
6+
from io import BytesIO
7+
8+
from tests.integration.test_utils import RunSubprocessMixin
9+
from tests.integration.test_utils import podman_compose_path
10+
from tests.integration.test_utils import test_path
11+
12+
13+
def compose_yaml_path() -> str:
14+
return os.path.join(
15+
os.path.join(
16+
test_path(), "merge", "reset_and_override_tags", "reset_tag_attribute_w_extends"
17+
),
18+
"docker-compose.yml",
19+
)
20+
21+
22+
class TestComposeResetTagAttributeWithExtends(unittest.TestCase, RunSubprocessMixin):
23+
def test_reset_w_extends(self) -> None: # when file is Dockerfile for building the image
24+
try:
25+
self.run_subprocess_assert_returncode(
26+
[
27+
podman_compose_path(),
28+
"-f",
29+
compose_yaml_path(),
30+
"up",
31+
],
32+
)
33+
output, _ = self.run_subprocess_assert_returncode([
34+
podman_compose_path(),
35+
"-f",
36+
compose_yaml_path(),
37+
"ps",
38+
])
39+
self.assertIn("reset_tag_attribute_w_extends_web_1", str(output))
40+
41+
output, _ = self.run_subprocess_assert_returncode([
42+
"podman",
43+
"inspect",
44+
"reset_tag_attribute_w_extends_web_1",
45+
])
46+
inspect = json.load(BytesIO(output))
47+
48+
self.assertEqual(len(inspect), 1)
49+
self.assertIn("NetworkSettings", inspect[0])
50+
self.assertIn("Ports", inspect[0]["NetworkSettings"])
51+
self.assertEqual(len(inspect[0]["NetworkSettings"]["Ports"]), 0)
52+
finally:
53+
self.run_subprocess_assert_returncode([
54+
podman_compose_path(),
55+
"-f",
56+
compose_yaml_path(),
57+
"down",
58+
])

tests/unit/test_can_merge_build.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def test_parse_compose_file_when_multiple_composes(self, input, override, expect
9292

9393
actual_compose = {}
9494
if podman_compose.services:
95-
actual_compose = podman_compose.original_service(
95+
actual_compose = podman_compose.original_configuration(
9696
podman_compose.services["test-service"]
9797
)
9898
self.assertEqual(actual_compose, expected)
@@ -160,7 +160,9 @@ def test_parse_compose_file_when_multiple_composes_keys_command_entrypoint(
160160

161161
actual = {}
162162
if podman_compose.services:
163-
actual = podman_compose.original_service(podman_compose.services["test-service"])
163+
actual = podman_compose.original_configuration(
164+
podman_compose.services["test-service"]
165+
)
164166
self.assertEqual(actual, expected)
165167

166168

tests/unit/test_normalize_final_build.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def test_parse_compose_file_when_single_compose(self, input, expected):
123123

124124
actual_compose = {}
125125
if podman_compose.services:
126-
actual_compose = podman_compose.original_service(
126+
actual_compose = podman_compose.original_configuration(
127127
podman_compose.services["test-service"]
128128
)
129129
self.assertEqual(actual_compose, expected)
@@ -239,7 +239,7 @@ def test_parse_when_multiple_composes(self, input, override, expected):
239239

240240
actual_compose = {}
241241
if podman_compose.services:
242-
actual_compose = podman_compose.original_service(
242+
actual_compose = podman_compose.original_configuration(
243243
podman_compose.services["test-service"]
244244
)
245245
self.assertEqual(actual_compose, expected)

0 commit comments

Comments
 (0)