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

Lines changed: 4 additions & 0 deletions
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

Lines changed: 31 additions & 3 deletions
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

Lines changed: 10 additions & 0 deletions
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

Lines changed: 3 additions & 0 deletions
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

Lines changed: 21 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy