Skip to content

Commit dae9e52

Browse files
nejchmax-wittig
authored andcommitted
feat(api): support single resource access token get API
1 parent dcca59d commit dae9e52

8 files changed

+92
-39
lines changed

docs/gl_objects/group_access_tokens.rst

+6-1
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,16 @@ List group access tokens::
2323
access_tokens = gl.groups.get(1, lazy=True).access_tokens.list()
2424
print(access_tokens[0].name)
2525

26+
Get a group access token by id::
27+
28+
token = group.access_tokens.get(123)
29+
print(token.name)
30+
2631
Create group access token::
2732

2833
access_token = gl.groups.get(1).access_tokens.create({"name": "test", "scopes": ["api"], "expires_at": "2023-06-06"})
2934

30-
Revoke a group access tokens::
35+
Revoke a group access token::
3136

3237
gl.groups.get(1).access_tokens.delete(42)
3338
# or

docs/gl_objects/personal_access_tokens.rst

+1-4
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,4 @@ Create a personal access token for a user (admin only)::
6060
.. note:: As you can see above, you can only create personal access tokens
6161
via the Users API, but you cannot revoke these objects directly.
6262
This is because the create API uses a different endpoint than the list and revoke APIs.
63-
You need to fetch the token via the list API first to revoke it.
64-
65-
As of 14.2, GitLab does not provide a GET API for single personal access tokens.
66-
You must use the list method to retrieve single tokens.
63+
You need to fetch the token via the list or get API first to revoke it.

docs/gl_objects/project_access_tokens.rst

+5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ List project access tokens::
2323
access_tokens = gl.projects.get(1, lazy=True).access_tokens.list()
2424
print(access_tokens[0].name)
2525

26+
Get a project access token by id::
27+
28+
token = project.access_tokens.get(123)
29+
print(token.name)
30+
2631
Create project access token::
2732

2833
access_token = gl.projects.get(1).access_tokens.create({"name": "test", "scopes": ["api"], "expires_at": "2023-06-06"})

gitlab/v4/objects/group_access_tokens.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
from typing import Any, cast, Union
2+
13
from gitlab.base import RESTManager, RESTObject
2-
from gitlab.mixins import CreateMixin, DeleteMixin, ListMixin, ObjectDeleteMixin
4+
from gitlab.mixins import CreateMixin, DeleteMixin, ObjectDeleteMixin, RetrieveMixin
35
from gitlab.types import ArrayAttribute, RequiredOptional
46

57
__all__ = [
@@ -12,11 +14,16 @@ class GroupAccessToken(ObjectDeleteMixin, RESTObject):
1214
pass
1315

1416

15-
class GroupAccessTokenManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
17+
class GroupAccessTokenManager(CreateMixin, DeleteMixin, RetrieveMixin, RESTManager):
1618
_path = "/groups/{group_id}/access_tokens"
1719
_obj_cls = GroupAccessToken
1820
_from_parent_attrs = {"group_id": "id"}
1921
_create_attrs = RequiredOptional(
2022
required=("name", "scopes"), optional=("access_level", "expires_at")
2123
)
2224
_types = {"scopes": ArrayAttribute}
25+
26+
def get(
27+
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
28+
) -> GroupAccessToken:
29+
return cast(GroupAccessToken, super().get(id=id, lazy=lazy, **kwargs))

gitlab/v4/objects/project_access_tokens.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
from typing import Any, cast, Union
2+
13
from gitlab.base import RESTManager, RESTObject
2-
from gitlab.mixins import CreateMixin, DeleteMixin, ListMixin, ObjectDeleteMixin
4+
from gitlab.mixins import CreateMixin, DeleteMixin, ObjectDeleteMixin, RetrieveMixin
35
from gitlab.types import ArrayAttribute, RequiredOptional
46

57
__all__ = [
@@ -12,11 +14,16 @@ class ProjectAccessToken(ObjectDeleteMixin, RESTObject):
1214
pass
1315

1416

15-
class ProjectAccessTokenManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
17+
class ProjectAccessTokenManager(CreateMixin, DeleteMixin, RetrieveMixin, RESTManager):
1618
_path = "/projects/{project_id}/access_tokens"
1719
_obj_cls = ProjectAccessToken
1820
_from_parent_attrs = {"project_id": "id"}
1921
_create_attrs = RequiredOptional(
2022
required=("name", "scopes"), optional=("access_level", "expires_at")
2123
)
2224
_types = {"scopes": ArrayAttribute}
25+
26+
def get(
27+
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
28+
) -> ProjectAccessToken:
29+
return cast(ProjectAccessToken, super().get(id=id, lazy=lazy, **kwargs))

tests/unit/objects/conftest.py

+14
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,20 @@ def created_content():
2121
return {"message": "201 Created"}
2222

2323

24+
@pytest.fixture
25+
def token_content():
26+
return {
27+
"user_id": 141,
28+
"scopes": ["api"],
29+
"name": "token",
30+
"expires_at": "2021-01-31",
31+
"id": 42,
32+
"active": True,
33+
"created_at": "2021-01-20T22:11:48.151Z",
34+
"revoked": False,
35+
}
36+
37+
2438
@pytest.fixture
2539
def resp_export(accepted_content, binary_content):
2640
"""Common fixture for group and project exports."""

tests/unit/objects/test_group_access_tokens.py

+24-15
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,29 @@
55
import pytest
66
import responses
77

8+
from gitlab.v4.objects import GroupAccessToken
89

9-
@pytest.fixture
10-
def resp_list_group_access_token():
11-
content = [
12-
{
13-
"user_id": 141,
14-
"scopes": ["api"],
15-
"name": "token",
16-
"expires_at": "2021-01-31",
17-
"id": 42,
18-
"active": True,
19-
"created_at": "2021-01-20T22:11:48.151Z",
20-
"revoked": False,
21-
}
22-
]
2310

11+
@pytest.fixture
12+
def resp_list_group_access_token(token_content):
2413
with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps:
2514
rsps.add(
2615
method=responses.GET,
2716
url="http://localhost/api/v4/groups/1/access_tokens",
28-
json=content,
17+
json=[token_content],
18+
content_type="application/json",
19+
status=200,
20+
)
21+
yield rsps
22+
23+
24+
@pytest.fixture
25+
def resp_get_group_access_token(token_content):
26+
with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps:
27+
rsps.add(
28+
method=responses.GET,
29+
url="http://localhost/api/v4/groups/1/access_tokens/1",
30+
json=token_content,
2931
content_type="application/json",
3032
status=200,
3133
)
@@ -94,6 +96,13 @@ def test_list_group_access_tokens(gl, resp_list_group_access_token):
9496
assert access_tokens[0].name == "token"
9597

9698

99+
def test_get_group_access_token(group, resp_get_group_access_token):
100+
access_token = group.access_tokens.get(1)
101+
assert isinstance(access_token, GroupAccessToken)
102+
assert access_token.revoked is False
103+
assert access_token.name == "token"
104+
105+
97106
def test_create_group_access_token(gl, resp_create_group_access_token):
98107
access_tokens = gl.groups.get(1, lazy=True).access_tokens.create(
99108
{"name": "test", "scopes": ["api"]}

tests/unit/objects/test_project_access_tokens.py

+24-15
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,29 @@
55
import pytest
66
import responses
77

8+
from gitlab.v4.objects import ProjectAccessToken
89

9-
@pytest.fixture
10-
def resp_list_project_access_token():
11-
content = [
12-
{
13-
"user_id": 141,
14-
"scopes": ["api"],
15-
"name": "token",
16-
"expires_at": "2021-01-31",
17-
"id": 42,
18-
"active": True,
19-
"created_at": "2021-01-20T22:11:48.151Z",
20-
"revoked": False,
21-
}
22-
]
2310

11+
@pytest.fixture
12+
def resp_list_project_access_token(token_content):
2413
with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps:
2514
rsps.add(
2615
method=responses.GET,
2716
url="http://localhost/api/v4/projects/1/access_tokens",
28-
json=content,
17+
json=[token_content],
18+
content_type="application/json",
19+
status=200,
20+
)
21+
yield rsps
22+
23+
24+
@pytest.fixture
25+
def resp_get_project_access_token(token_content):
26+
with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps:
27+
rsps.add(
28+
method=responses.GET,
29+
url="http://localhost/api/v4/projects/1/access_tokens/1",
30+
json=token_content,
2931
content_type="application/json",
3032
status=200,
3133
)
@@ -94,6 +96,13 @@ def test_list_project_access_tokens(gl, resp_list_project_access_token):
9496
assert access_tokens[0].name == "token"
9597

9698

99+
def test_get_project_access_token(project, resp_get_project_access_token):
100+
access_token = project.access_tokens.get(1)
101+
assert isinstance(access_token, ProjectAccessToken)
102+
assert access_token.revoked is False
103+
assert access_token.name == "token"
104+
105+
97106
def test_create_project_access_token(gl, resp_create_project_access_token):
98107
access_tokens = gl.projects.get(1, lazy=True).access_tokens.create(
99108
{"name": "test", "scopes": ["api"]}

0 commit comments

Comments
 (0)