Skip to content

Commit ce9216c

Browse files
nejchJohnVillalovos
authored andcommitted
feat(api): support head() method for get and list endpoints
1 parent b0f02fa commit ce9216c

File tree

5 files changed

+69
-3
lines changed

5 files changed

+69
-3
lines changed

gitlab/exceptions.py

+4
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ class GitlabGetError(GitlabOperationError):
8282
pass
8383

8484

85+
class GitlabHeadError(GitlabOperationError):
86+
pass
87+
88+
8589
class GitlabCreateError(GitlabOperationError):
8690
pass
8791

gitlab/mixins.py

+31-3
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,35 @@
6868
_RestObjectBase = object
6969

7070

71-
class GetMixin(_RestManagerBase):
71+
class HeadMixin(_RestManagerBase):
72+
@exc.on_http_error(exc.GitlabHeadError)
73+
def head(
74+
self, id: Optional[Union[str, int]] = None, **kwargs: Any
75+
) -> requests.structures.CaseInsensitiveDict:
76+
"""Retrieve headers from an endpoint.
77+
78+
Args:
79+
id: ID of the object to retrieve
80+
**kwargs: Extra options to send to the server (e.g. sudo)
81+
82+
Returns:
83+
A requests header object.
84+
85+
Raises:
86+
GitlabAuthenticationError: If authentication is not correct
87+
GitlabHeadError: If the server cannot perform the request
88+
"""
89+
if TYPE_CHECKING:
90+
assert self.path is not None
91+
92+
path = self.path
93+
if id is not None:
94+
path = f"{path}/{utils.EncodedId(id)}"
95+
96+
return self.gitlab.http_head(path, **kwargs)
97+
98+
99+
class GetMixin(HeadMixin, _RestManagerBase):
72100
_computed_path: Optional[str]
73101
_from_parent_attrs: Dict[str, Any]
74102
_obj_cls: Optional[Type[base.RESTObject]]
@@ -113,7 +141,7 @@ def get(
113141
return self._obj_cls(self, server_data)
114142

115143

116-
class GetWithoutIdMixin(_RestManagerBase):
144+
class GetWithoutIdMixin(HeadMixin, _RestManagerBase):
117145
_computed_path: Optional[str]
118146
_from_parent_attrs: Dict[str, Any]
119147
_obj_cls: Optional[Type[base.RESTObject]]
@@ -181,7 +209,7 @@ def refresh(self, **kwargs: Any) -> None:
181209
self._update_attrs(server_data)
182210

183211

184-
class ListMixin(_RestManagerBase):
212+
class ListMixin(HeadMixin, _RestManagerBase):
185213
_computed_path: Optional[str]
186214
_from_parent_attrs: Dict[str, Any]
187215
_list_filters: Tuple[str, ...] = ()

tests/functional/api/test_projects.py

+10
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@
66
from gitlab.v4.objects.projects import ProjectStorage
77

88

9+
def test_projects_head(gl):
10+
headers = gl.projects.head()
11+
assert headers["x-total"]
12+
13+
14+
def test_project_head(gl, project):
15+
headers = gl.projects.head(project.id)
16+
assert headers["content-type"] == "application/json"
17+
18+
919
def test_create_project(gl, user):
1020
# Moved from group tests chunk in legacy tests, TODO cleanup
1121
admin_project = gl.projects.create({"name": "admin_project"})

tests/functional/api/test_repository.py

+3
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ def test_repository_files(project):
4040
# object method
4141
assert readme.decode().decode() == "Initial content"
4242

43+
headers = project.files.head("README.rst", ref="main")
44+
assert headers["X-Gitlab-File-Path"] == "README.rst"
45+
4346
blame = project.files.blame(file_path="README.rst", ref="main")
4447
assert blame
4548

tests/unit/mixins/test_mixin_methods.py

+21
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import pytest
2+
import requests
23
import responses
34

45
from gitlab import base
@@ -47,6 +48,26 @@ class M(GetMixin, FakeManager):
4748
assert responses.assert_call_count(url, 1) is True
4849

4950

51+
@responses.activate
52+
def test_head_mixin(gl):
53+
class M(GetMixin, FakeManager):
54+
pass
55+
56+
url = "http://localhost/api/v4/tests/42"
57+
responses.add(
58+
method=responses.HEAD,
59+
url=url,
60+
headers={"X-GitLab-Header": "test"},
61+
status=200,
62+
match=[responses.matchers.query_param_matcher({})],
63+
)
64+
65+
manager = M(gl)
66+
result = manager.head(42)
67+
assert isinstance(result, requests.structures.CaseInsensitiveDict)
68+
assert result["x-gitlab-header"] == "test"
69+
70+
5071
@responses.activate
5172
def test_refresh_mixin(gl):
5273
class TestClass(RefreshMixin, FakeObject):

0 commit comments

Comments
 (0)