Skip to content

Commit e06c51b

Browse files
authored
Merge pull request #1327 from python-gitlab/feat/project-access-token-api
feat(projects): add project access token api
2 parents bb227d3 + 5d94846 commit e06c51b

File tree

4 files changed

+167
-0
lines changed

4 files changed

+167
-0
lines changed
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#####################
2+
Project Access Tokens
3+
#####################
4+
5+
Get a list of project access tokens
6+
7+
References
8+
----------
9+
10+
* v4 API:
11+
12+
+ :class:`gitlab.v4.objects.ProjectAccessToken`
13+
+ :class:`gitlab.v4.objects.ProjectAccessTokenManager`
14+
+ :attr:`gitlab.Gitlab.project_access_tokens`
15+
16+
* GitLab API: https://docs.gitlab.com/ee/api/resource_access_tokens.html
17+
18+
Examples
19+
--------
20+
21+
List project access tokens::
22+
23+
access_tokens = gl.projects.get(1, lazy=True).access_tokens.list()
24+
print(access_tokens[0].name)
25+
26+
Create project access token::
27+
28+
access_token = gl.projects.get(1).access_tokens.create({"name": "test", "scopes": ["api"]})
29+
30+
Revoke a project access tokens::
31+
32+
gl.projects.get(1).access_tokens.delete(42)
33+
# or
34+
access_token.delete()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
"""
2+
GitLab API: https://docs.gitlab.com/ee/api/resource_access_tokens.html
3+
"""
4+
5+
import pytest
6+
import responses
7+
8+
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+
]
23+
24+
with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps:
25+
rsps.add(
26+
method=responses.GET,
27+
url="http://localhost/api/v4/projects/1/access_tokens",
28+
json=content,
29+
content_type="application/json",
30+
status=200,
31+
)
32+
yield rsps
33+
34+
35+
@pytest.fixture
36+
def resp_create_project_access_token():
37+
content = {
38+
"user_id": 141,
39+
"scopes": ["api"],
40+
"name": "token",
41+
"expires_at": "2021-01-31",
42+
"id": 42,
43+
"active": True,
44+
"created_at": "2021-01-20T22:11:48.151Z",
45+
"revoked": False,
46+
}
47+
48+
with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps:
49+
rsps.add(
50+
method=responses.POST,
51+
url="http://localhost/api/v4/projects/1/access_tokens",
52+
json=content,
53+
content_type="application/json",
54+
status=200,
55+
)
56+
yield rsps
57+
58+
59+
@pytest.fixture
60+
def resp_revoke_project_access_token():
61+
content = [
62+
{
63+
"user_id": 141,
64+
"scopes": ["api"],
65+
"name": "token",
66+
"expires_at": "2021-01-31",
67+
"id": 42,
68+
"active": True,
69+
"created_at": "2021-01-20T22:11:48.151Z",
70+
"revoked": False,
71+
}
72+
]
73+
74+
with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps:
75+
rsps.add(
76+
method=responses.DELETE,
77+
url="http://localhost/api/v4/projects/1/access_tokens/42",
78+
json=content,
79+
content_type="application/json",
80+
status=204,
81+
)
82+
rsps.add(
83+
method=responses.GET,
84+
url="http://localhost/api/v4/projects/1/access_tokens",
85+
json=content,
86+
content_type="application/json",
87+
status=200,
88+
)
89+
yield rsps
90+
91+
92+
def test_list_project_access_tokens(gl, resp_list_project_access_token):
93+
access_tokens = gl.projects.get(1, lazy=True).access_tokens.list()
94+
assert len(access_tokens) == 1
95+
assert access_tokens[0].revoked is False
96+
assert access_tokens[0].name == "token"
97+
98+
99+
def test_create_project_access_token(gl, resp_create_project_access_token):
100+
access_tokens = gl.projects.get(1, lazy=True).access_tokens.create(
101+
{"name": "test", "scopes": ["api"]}
102+
)
103+
assert access_tokens.revoked is False
104+
assert access_tokens.user_id == 141
105+
assert access_tokens.expires_at == "2021-01-31"
106+
107+
108+
def test_revoke_project_access_token(
109+
gl, resp_list_project_access_token, resp_revoke_project_access_token
110+
):
111+
gl.projects.get(1, lazy=True).access_tokens.delete(42)
112+
access_token = gl.projects.get(1, lazy=True).access_tokens.list()[0]
113+
access_token.delete()
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from gitlab.base import * # noqa
2+
from gitlab.mixins import * # noqa
3+
4+
5+
__all__ = [
6+
"ProjectAccessToken",
7+
"ProjectAccessTokenManager",
8+
]
9+
10+
11+
class ProjectAccessToken(ObjectDeleteMixin, RESTObject):
12+
pass
13+
14+
15+
class ProjectAccessTokenManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
16+
_path = "/projects/%(project_id)s/access_tokens"
17+
_obj_cls = ProjectAccessToken
18+
_from_parent_attrs = {"project_id": "id"}

gitlab/v4/objects/projects.py

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from gitlab.base import * # noqa
44
from gitlab.mixins import * # noqa
55

6+
from .project_access_tokens import ProjectAccessTokenManager
67
from .access_requests import ProjectAccessRequestManager
78
from .badges import ProjectBadgeManager
89
from .boards import ProjectBoardManager
@@ -94,6 +95,7 @@ class GroupProjectManager(ListMixin, RESTManager):
9495
class Project(RefreshMixin, SaveMixin, ObjectDeleteMixin, RESTObject):
9596
_short_print_attr = "path"
9697
_managers = (
98+
("access_tokens", "ProjectAccessTokenManager"),
9799
("accessrequests", "ProjectAccessRequestManager"),
98100
("approvals", "ProjectApprovalManager"),
99101
("approvalrules", "ProjectApprovalRuleManager"),

0 commit comments

Comments
 (0)