Skip to content
Open
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
12 changes: 11 additions & 1 deletion gitlab/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import os
import re
from http import HTTPStatus
from typing import Any, BinaryIO, cast, TYPE_CHECKING
from urllib import parse

Expand Down Expand Up @@ -756,7 +757,7 @@ def http_request(
):
continue

error_message = result.content
error_message: str | bytes = result.content
try:
error_json = result.json()
for k in ("message", "error"):
Expand All @@ -765,6 +766,15 @@ def http_request(
except (KeyError, ValueError, TypeError):
pass

if not error_message:
# Bodyless responses, such as HEAD errors, do not carry a
# GitLab error message. Use the HTTP reason phrase instead.
try:
default_reason = HTTPStatus(result.status_code).phrase
except ValueError:
default_reason = ""
error_message = result.reason or default_reason

if result.status_code == 401:
raise gitlab.exceptions.GitlabAuthenticationError(
response_code=result.status_code,
Expand Down
21 changes: 21 additions & 0 deletions tests/unit/objects/test_repositories.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import responses
from requests.structures import CaseInsensitiveDict

from gitlab.exceptions import GitlabHeadError
from gitlab.v4.objects import ProjectFile

file_path = "app/models/key.rb"
Expand Down Expand Up @@ -62,6 +63,26 @@ def test_head_repository_file(project, resp_head_repository_file):
assert headers["X-Gitlab-File-Path"] == file_path


@responses.activate
def test_head_repository_file_error_without_body(project):
missing_file_path = "nonexistent.yaml"
encoded_path = quote(missing_file_path, safe="")
responses.add(
method=responses.HEAD,
url=f"http://localhost/api/v4/projects/1/repository/files/{encoded_path}",
status=404,
)

with pytest.raises(GitlabHeadError) as exc_info:
project.files.head(missing_file_path, ref=ref)

error = exc_info.value
assert error.response_code == 404
assert error.response_body == b""
assert error.error_message == "Not Found"
assert str(error) == "404: Not Found"


@pytest.fixture
def resp_get_repository_file():
file_response = {
Expand Down
59 changes: 59 additions & 0 deletions tests/unit/test_gitlab_http_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,65 @@ def test_head_request(gl):
assert result["X-Total"] == "1"


@responses.activate
def test_head_request_error_without_body_uses_reason(gl):
url = "http://localhost/api/v4/not_there"
responses.add(
method=responses.HEAD,
url=url,
status=404,
match=helpers.MATCH_EMPTY_QUERY_PARAMS,
)

with pytest.raises(GitlabHttpError) as exc_info:
gl.http_head("/not_there")

error = exc_info.value
assert error.response_code == 404
assert error.response_body == b""
assert error.error_message == "Not Found"
assert str(error) == "404: Not Found"


@responses.activate
def test_head_request_error_with_unknown_status_preserves_error(gl):
url = "http://localhost/api/v4/not_there"
responses.add(
method=responses.HEAD,
url=url,
status=599,
match=helpers.MATCH_EMPTY_QUERY_PARAMS,
)

with pytest.raises(GitlabHttpError) as exc_info:
gl.http_head("/not_there")

error = exc_info.value
assert error.response_code == 599
assert error.response_body == b""
assert str(error).startswith("599:")


@responses.activate
def test_http_request_error_message_takes_precedence_over_reason(gl):
url = "http://localhost/api/v4/not_there"
responses.add(
method=responses.GET,
url=url,
json={"message": "File Not Found"},
status=404,
match=helpers.MATCH_EMPTY_QUERY_PARAMS,
)

with pytest.raises(GitlabHttpError) as exc_info:
gl.http_get("/not_there")

error = exc_info.value
assert error.response_body == b'{"message": "File Not Found"}'
assert error.error_message == "File Not Found"
assert str(error) == "404: File Not Found"


@responses.activate
def test_list_request(gl):
url = "http://localhost/api/v4/projects"
Expand Down
Loading