From 83e63302e8da7a2c038a6752f2b99c651b395ed4 Mon Sep 17 00:00:00 2001 From: Ian Woodard <17186604+IanWoodard@users.noreply.github.com> Date: Fri, 3 Jan 2025 10:59:18 -0800 Subject: [PATCH] ref(commands): Improving error message for service not found DEVINFRA-572 (#197) * ref(commands): Improving error message for service not found * Fixing f-string usage --- devservices/utils/services.py | 9 ++++- tests/utils/test_services.py | 67 +++++++++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/devservices/utils/services.py b/devservices/utils/services.py index 1b26820..f8bb72a 100644 --- a/devservices/utils/services.py +++ b/devservices/utils/services.py @@ -65,4 +65,11 @@ def find_matching_service(service_name: str | None = None) -> Service: for service in services: if service.name.lower() == service_name.lower(): return service - raise ServiceNotFoundError(f'Service "{service_name}" not found') + unique_service_names = sorted(set(service.name for service in services)) + error_message = f"Service '{service_name}' not found." + if len(unique_service_names) > 0: + service_bullet_points = "\n".join( + [f"- {service_name}" for service_name in unique_service_names] + ) + error_message += "\nSupported services:\n" + service_bullet_points + raise ServiceNotFoundError(error_message) diff --git a/tests/utils/test_services.py b/tests/utils/test_services.py index eff3339..e17f6a3 100644 --- a/tests/utils/test_services.py +++ b/tests/utils/test_services.py @@ -6,9 +6,11 @@ import pytest +from devservices.configs.service_config import ServiceConfig from devservices.exceptions import ServiceNotFoundError from devservices.utils.services import find_matching_service from devservices.utils.services import get_local_services +from devservices.utils.services import Service from testing.utils import create_mock_git_repo @@ -85,7 +87,13 @@ def test_get_local_services_skips_non_devservices_repos(tmp_path: Path) -> None: assert local_services[0].repo_path == str(mock_basic_repo_path) -def test_find_matching_service_not_found(tmp_path: Path) -> None: +@mock.patch( + "devservices.utils.services.get_local_services", + return_value=[], +) +def test_find_matching_service_not_found_no_local_services( + mock_get_local_services: mock.Mock, tmp_path: Path +) -> None: mock_code_root = tmp_path / "code" os.makedirs(mock_code_root) with ( @@ -98,5 +106,60 @@ def test_find_matching_service_not_found(tmp_path: Path) -> None: return_value=str(mock_code_root), ), ): - with pytest.raises(ServiceNotFoundError): + with pytest.raises(ServiceNotFoundError) as e: find_matching_service(str(tmp_path / "non-existent-repo")) + + assert str(e.value) == f"Service '{tmp_path / 'non-existent-repo'}' not found." + + mock_get_local_services.assert_called_once_with(str(mock_code_root)) + + +@mock.patch( + "devservices.utils.services.get_local_services", + return_value=[ + Service( + name="example-service-1", + repo_path="/path/to/example-service-1", + config=ServiceConfig( + version=0.1, + service_name="example-service-1", + dependencies={}, + modes={"default": []}, + ), + ), + Service( + name="example-service-2", + repo_path="/path/to/example-service-2", + config=ServiceConfig( + version=0.1, + service_name="example-service-2", + dependencies={}, + modes={"default": []}, + ), + ), + ], +) +def test_find_matching_service_not_found_with_local_services( + mock_get_local_services: mock.Mock, tmp_path: Path +) -> None: + mock_code_root = tmp_path / "code" + os.makedirs(mock_code_root) + with ( + mock.patch( + "devservices.utils.dependencies.DEVSERVICES_DEPENDENCIES_CACHE_DIR", + str(tmp_path / "dependency-dir"), + ), + mock.patch( + "devservices.utils.services.get_coderoot", + return_value=str(mock_code_root), + ), + ): + with pytest.raises(ServiceNotFoundError) as e: + find_matching_service(str(tmp_path / "non-existent-repo")) + + assert ( + str(e.value) + == f"Service '{tmp_path / 'non-existent-repo'}' not found.\nSupported services:\n- example-service-1\n- example-service-2" + ) + + mock_get_local_services.assert_called_once_with(str(mock_code_root))