Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix error message returned while querying for a missing repository file #5139

Merged
merged 1 commit into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion backend/infrahub/api/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from infrahub.core.constants import InfrahubKind
from infrahub.core.manager import NodeManager
from infrahub.database import InfrahubDatabase # noqa: TCH001
from infrahub.exceptions import CommitNotFoundError
from infrahub.exceptions import CommitNotFoundError, PropagatedFromWorkerError
from infrahub.message_bus.messages import GitFileGet, GitFileGetResponse

if TYPE_CHECKING:
Expand Down Expand Up @@ -60,4 +60,8 @@ async def get_file(
)

response = await service.message_bus.rpc(message=message, response_class=GitFileGetResponse)
if response.data.http_code is not None:
assert response.data.error_message is not None
raise PropagatedFromWorkerError(message=response.data.error_message, http_code=response.data.http_code)

return PlainTextResponse(content=response.data.content)
11 changes: 11 additions & 0 deletions backend/infrahub/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ def api_response(self) -> dict[str, Any]:
}


class PropagatedFromWorkerError(Error):
"""
Used to re-raise server side an error that happened worker side.
Note we might want to improve this so we raise the exact same error that happened worker side.
"""

def __init__(self, http_code: int, message: str) -> None:
self.HTTP_CODE = http_code
self.message = message


class RPCError(Error):
HTTP_CODE: int = 502

Expand Down
4 changes: 3 additions & 1 deletion backend/infrahub/message_bus/messages/git_file_get.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ class GitFileGet(InfrahubMessage):


class GitFileGetResponseData(InfrahubResponseData):
content: str = Field(..., description="The returned content")
content: str | None = None # is empty if error_message / http_code are not empty
error_message: str | None = None
http_code: int | None = None


class GitFileGetResponse(InfrahubResponse):
Expand Down
21 changes: 15 additions & 6 deletions backend/infrahub/message_bus/operations/git/file.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
from prefect import flow

from infrahub.exceptions import FileOutOfRepositoryError, RepositoryFileNotFoundError
from infrahub.git.repository import get_initialized_repo
from infrahub.log import get_logger
from infrahub.message_bus import messages
from infrahub.message_bus.messages.git_file_get import GitFileGetResponse, GitFileGetResponseData
from infrahub.message_bus.messages.git_file_get import (
GitFileGetResponse,
GitFileGetResponseData,
)
from infrahub.services import InfrahubServices

log = get_logger()
Expand All @@ -20,8 +24,13 @@ async def get(message: messages.GitFileGet, service: InfrahubServices) -> None:
repository_kind=message.repository_kind,
)

content = await repo.get_file(commit=message.commit, location=message.file)

if message.reply_requested:
response = GitFileGetResponse(data=GitFileGetResponseData(content=content))
await service.reply(message=response, initiator=message)
try:
content = await repo.get_file(commit=message.commit, location=message.file)
except (FileOutOfRepositoryError, RepositoryFileNotFoundError) as e:
if message.reply_requested:
response = GitFileGetResponse(data=GitFileGetResponseData(error_message=e.message, http_code=e.HTTP_CODE))
await service.reply(message=response, initiator=message)
else:
if message.reply_requested:
response = GitFileGetResponse(data=GitFileGetResponseData(content=content))
await service.reply(message=response, initiator=message)
40 changes: 40 additions & 0 deletions backend/tests/integration/git/test_git_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import yaml
from infrahub_sdk import Config, InfrahubClient
from infrahub_sdk.exceptions import NodeNotFoundError
from starlette.testclient import TestClient

from infrahub import config
from infrahub.core import registry
Expand All @@ -20,6 +21,7 @@
from infrahub.utils import get_models_dir
from tests.adapters.log import FakeTaskReportLogger
from tests.helpers.file_repo import FileRepo
from tests.helpers.test_app import TestInfrahubApp
from tests.helpers.test_client import InfrahubTestClient

# pylint: disable=unused-argument
Expand Down Expand Up @@ -293,3 +295,41 @@ async def test_import_all_yaml_files(
# FIXME not implemented yet
with pytest.raises(NodeNotFoundError):
await client.get(kind=InfrahubKind.TRANSFORMJINJA2, id=obj.id)


class TestGetMissingFile(TestInfrahubApp):
async def test_get_missing_file(self, db: InfrahubDatabase, client: InfrahubClient, git_repo_car_dealership):
# Ideally above tests would rely on `TestInfrahubApp.repo` instead of TestInfrahubClient
# and we would reuse `TestInfrahubClient.repo` fixture here.
obj = await Node.init(schema=InfrahubKind.REPOSITORY, db=db)
await obj.new(
db=db,
name=git_repo_car_dealership.name,
description="test repository",
location="git@github.com:mock/test.git",
)
await obj.save(db=db)

# Initialize the repository on the file system
repo = await InfrahubRepository.new(
id=obj.id,
name=git_repo_car_dealership.name,
location=git_repo_car_dealership.path,
task_report=FakeTaskReportLogger(),
client=client,
)

commit = repo.get_commit_value(branch_name="main")
rest_client = TestClient(app)
missing_file_name = "i_do_not_exist.txt"
with rest_client:
response = rest_client.get(
url=f"/api/file/{repo.id}/{missing_file_name}?commit={commit}",
headers={"Authorization": "Token XXXX"},
)
errors = response.json()["errors"]
assert len(errors) == 1
assert (
errors[0]["message"] == f"Unable to find the file at 'car-dealership::{commit}::{missing_file_name}'."
)
assert errors[0]["extensions"]["code"] == 404
Loading