mirror of
https://github.com/containers/podman-compose.git
synced 2025-08-13 15:37:14 +02:00
Hide stack trace shown on YAML parse error by default
Fixes https://github.com/containers/podman-compose/issues/1139 Signed-off-by: Yusuke Matsubara <whym@whym.org>
This commit is contained in:
committed by
Povilas Kanapickas
parent
b06224389e
commit
764efd360c
1
newsfragments/hide-stack-trace-yaml-parse-error.change
Normal file
1
newsfragments/hide-stack-trace-yaml-parse-error.change
Normal file
@ -0,0 +1 @@
|
|||||||
|
Hide the stack trace on a YAML parse error.
|
@ -1904,6 +1904,15 @@ def rec_merge(target: dict[str, Any], *sources: dict[str, Any]) -> dict[str, Any
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def load_yaml_or_die(file_path: str, stream: Any) -> dict[str, Any]:
|
||||||
|
try:
|
||||||
|
return yaml.safe_load(stream)
|
||||||
|
except yaml.scanner.ScannerError as e:
|
||||||
|
log.fatal("Compose file contains an error:\n%s", e)
|
||||||
|
log.info("Compose file %s contains an error:", file_path, exc_info=e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def resolve_extends(
|
def resolve_extends(
|
||||||
services: dict[str, Any], service_names: list[str], environ: dict[str, Any]
|
services: dict[str, Any], service_names: list[str], environ: dict[str, Any]
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -1920,7 +1929,7 @@ def resolve_extends(
|
|||||||
if filename.startswith("./"):
|
if filename.startswith("./"):
|
||||||
filename = filename[2:]
|
filename = filename[2:]
|
||||||
with open(filename, "r", encoding="utf-8") as f:
|
with open(filename, "r", encoding="utf-8") as f:
|
||||||
content = yaml.safe_load(f) or {}
|
content = load_yaml_or_die(filename, f) or {}
|
||||||
if "services" in content:
|
if "services" in content:
|
||||||
content = content["services"]
|
content = content["services"]
|
||||||
subdirectory = os.path.dirname(filename)
|
subdirectory = os.path.dirname(filename)
|
||||||
@ -2229,10 +2238,10 @@ class PodmanCompose:
|
|||||||
break
|
break
|
||||||
|
|
||||||
if filename.strip().split('/')[-1] == '-':
|
if filename.strip().split('/')[-1] == '-':
|
||||||
content = yaml.safe_load(sys.stdin)
|
content = load_yaml_or_die(filename, sys.stdin)
|
||||||
else:
|
else:
|
||||||
with open(filename, "r", encoding="utf-8") as f:
|
with open(filename, "r", encoding="utf-8") as f:
|
||||||
content = yaml.safe_load(f)
|
content = load_yaml_or_die(filename, f)
|
||||||
# log(filename, json.dumps(content, indent = 2))
|
# log(filename, json.dumps(content, indent = 2))
|
||||||
if not isinstance(content, dict):
|
if not isinstance(content, dict):
|
||||||
sys.stderr.write(
|
sys.stderr.write(
|
||||||
|
4
tests/integration/parse-error/docker-compose-error.yml
Normal file
4
tests/integration/parse-error/docker-compose-error.yml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
version: "3"
|
||||||
|
services:foo
|
||||||
|
web1:
|
||||||
|
image: busybox
|
4
tests/integration/parse-error/docker-compose.yml
Normal file
4
tests/integration/parse-error/docker-compose.yml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
web1:
|
||||||
|
image: busybox
|
@ -0,0 +1,66 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from tests.integration.test_utils import RunSubprocessMixin
|
||||||
|
from tests.integration.test_utils import podman_compose_path
|
||||||
|
from tests.integration.test_utils import test_path
|
||||||
|
|
||||||
|
|
||||||
|
def bad_compose_yaml_path() -> str:
|
||||||
|
base_path = os.path.join(test_path(), "parse-error")
|
||||||
|
return os.path.join(base_path, "docker-compose-error.yml")
|
||||||
|
|
||||||
|
|
||||||
|
def good_compose_yaml_path() -> str:
|
||||||
|
base_path = os.path.join(test_path(), "parse-error")
|
||||||
|
return os.path.join(base_path, "docker-compose.yml")
|
||||||
|
|
||||||
|
|
||||||
|
class TestComposeBuildParseError(unittest.TestCase, RunSubprocessMixin):
|
||||||
|
def test_no_error(self) -> None:
|
||||||
|
try:
|
||||||
|
_, err = self.run_subprocess_assert_returncode(
|
||||||
|
[podman_compose_path(), "-f", good_compose_yaml_path(), "config"], 0
|
||||||
|
)
|
||||||
|
self.assertEqual(b"", err)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
self.run_subprocess([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
bad_compose_yaml_path(),
|
||||||
|
"down",
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_simple_parse_error(self) -> None:
|
||||||
|
try:
|
||||||
|
_, err = self.run_subprocess_assert_returncode(
|
||||||
|
[podman_compose_path(), "-f", bad_compose_yaml_path(), "config"], 1
|
||||||
|
)
|
||||||
|
self.assertIn(b"could not find expected ':'", err)
|
||||||
|
self.assertNotIn(b"\nTraceback (most recent call last):\n", err)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
self.run_subprocess([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
bad_compose_yaml_path(),
|
||||||
|
"down",
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_verbose_parse_error_contains_stack_trace(self) -> None:
|
||||||
|
try:
|
||||||
|
_, err = self.run_subprocess_assert_returncode(
|
||||||
|
[podman_compose_path(), "--verbose", "-f", bad_compose_yaml_path(), "config"], 1
|
||||||
|
)
|
||||||
|
self.assertIn(b"\nTraceback (most recent call last):\n", err)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
self.run_subprocess([
|
||||||
|
podman_compose_path(),
|
||||||
|
"-f",
|
||||||
|
bad_compose_yaml_path(),
|
||||||
|
"down",
|
||||||
|
])
|
Reference in New Issue
Block a user