Skip to content

Commit 5979750

Browse files
authored
Merge pull request #1052 from machine424/deploy-tokens-support
feat(api): add support for Gitlab Deploy Token API
2 parents 3396aa5 + 01de524 commit 5979750

File tree

7 files changed

+354
-8
lines changed

7 files changed

+354
-8
lines changed

docs/cli.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,19 @@ Get a specific user by id:
207207
208208
$ gitlab user get --id 3
209209
210+
Create a deploy token for a project:
211+
212+
.. code-block:: console
213+
214+
$ gitlab -v project-deploy-token create --project-id 2 \
215+
--name bar --username root --expires-at "2021-09-09" --scopes "read_repository"
216+
217+
List deploy tokens for a group:
218+
219+
.. code-block:: console
220+
221+
$ gitlab -v group-deploy-token list --group-id 3
222+
210223
Get a list of snippets for this project:
211224

212225
.. code-block:: console

docs/gl_objects/deploy_tokens.rst

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
#######
2+
Deploy tokens
3+
#######
4+
5+
Deploy tokens allow read-only access to your repository and registry images
6+
without having a user and a password.
7+
8+
Deploy tokens
9+
=============
10+
11+
This endpoint requires admin access.
12+
13+
Reference
14+
---------
15+
16+
* v4 API:
17+
18+
+ :class:`gitlab.v4.objects.DeployToken`
19+
+ :class:`gitlab.v4.objects.DeployTokenManager`
20+
+ :attr:`gitlab.Gitlab.deploytokens`
21+
22+
* GitLab API: https://docs.gitlab.com/ce/api/deploy_tokens.html
23+
24+
Examples
25+
--------
26+
27+
Use the ``list()`` method to list all deploy tokens across the GitLab instance.
28+
29+
::
30+
31+
# List deploy tokens
32+
deploy_tokens = gl.deploytokens.list()
33+
34+
Project deploy tokens
35+
=====================
36+
37+
This endpoint requires project maintainer access or higher.
38+
39+
Reference
40+
---------
41+
42+
* v4 API:
43+
44+
+ :class:`gitlab.v4.objects.ProjectDeployToken`
45+
+ :class:`gitlab.v4.objects.ProjectDeployTokenManager`
46+
+ :attr:`gitlab.v4.objects.Project.deploytokens`
47+
48+
* GitLab API: https://docs.gitlab.com/ce/api/deploy_tokens.html#project-deploy-tokens
49+
50+
Examples
51+
--------
52+
53+
List the deploy tokens for a project::
54+
55+
deploy_tokens = project.deploytokens.list()
56+
57+
Create a new deploy token to access registry images of a project:
58+
59+
In addition to required parameters ``name`` and ``scopes``, this method accepts
60+
the following parameters:
61+
62+
* ``expires_at`` Expiration date of the deploy token. Does not expire if no value is provided.
63+
* ``username`` Username for deploy token. Default is ``gitlab+deploy-token-{n}``
64+
65+
66+
::
67+
68+
deploy_token = project.deploytokens.create({'name': 'token1', 'scopes': ['read_registry'], 'username':'', 'expires_at':''})
69+
# show its id
70+
print(deploy_token.id)
71+
# show the token value. Make sure you save it, you won't be able to access it again.
72+
print(deploy_token.token)
73+
74+
.. warning::
75+
76+
With GitLab 12.9, even though ``username`` and ``expires_at`` are not required, they always have to be passed to the API.
77+
You can set them to empty strings, see: https://gitlab.com/gitlab-org/gitlab/-/issues/211878.
78+
Also, the ``username``'s value is ignored by the API and will be overriden with ``gitlab+deploy-token-{n}``,
79+
see: https://gitlab.com/gitlab-org/gitlab/-/issues/211963
80+
These issues were fixed in GitLab 12.10.
81+
82+
Remove a deploy token from the project::
83+
84+
deploy_token.delete()
85+
# or
86+
project.deploytokens.delete(deploy_token.id)
87+
88+
89+
Group deploy tokens
90+
===================
91+
92+
Reference
93+
---------
94+
95+
* v4 API:
96+
97+
+ :class:`gitlab.v4.objects.GroupDeployToken`
98+
+ :class:`gitlab.v4.objects.GroupDeployTokenManager`
99+
+ :attr:`gitlab.v4.objects.Group.deploytokens`
100+
101+
* GitLab API: https://docs.gitlab.com/ce/api/deploy_tokens.html#group-deploy-tokens
102+
103+
Examples
104+
--------
105+
106+
List the deploy tokens for a group::
107+
108+
deploy_tokens = group.deploytokens.list()
109+
110+
Create a new deploy token to access all repositories of all projects in a group:
111+
112+
In addition to required parameters ``name`` and ``scopes``, this method accepts
113+
the following parameters:
114+
115+
* ``expires_at`` Expiration date of the deploy token. Does not expire if no value is provided.
116+
* ``username`` Username for deploy token. Default is ``gitlab+deploy-token-{n}``
117+
118+
::
119+
120+
deploy_token = group.deploytokens.create({'name': 'token1', 'scopes': ['read_repository'], 'username':'', 'expires_at':''})
121+
# show its id
122+
print(deploy_token.id)
123+
124+
.. warning::
125+
126+
With GitLab 12.9, even though ``username`` and ``expires_at`` are not required, they always have to be passed to the API.
127+
You can set them to empty strings, see: https://gitlab.com/gitlab-org/gitlab/-/issues/211878.
128+
Also, the ``username``'s value is ignored by the API and will be overriden with ``gitlab+deploy-token-{n}``,
129+
see: https://gitlab.com/gitlab-org/gitlab/-/issues/211963
130+
These issues were fixed in GitLab 12.10.
131+
132+
Remove a deploy token from the group::
133+
134+
deploy_token.delete()
135+
# or
136+
group.deploytokens.delete(deploy_token.id)
137+

gitlab/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ def __init__(
119119

120120
self.broadcastmessages = objects.BroadcastMessageManager(self)
121121
self.deploykeys = objects.DeployKeyManager(self)
122+
self.deploytokens = objects.DeployTokenManager(self)
122123
self.geonodes = objects.GeoNodeManager(self)
123124
self.gitlabciymls = objects.GitlabciymlManager(self)
124125
self.gitignores = objects.GitignoreManager(self)

gitlab/tests/test_gitlab.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,40 @@ def resp_application_create(url, request):
903903
self.assertEqual(application.redirect_uri, "http://localhost:8080")
904904
self.assertEqual(application.scopes, ["api", "email"])
905905

906+
def test_deploy_tokens(self):
907+
@urlmatch(
908+
scheme="http",
909+
netloc="localhost",
910+
path="/api/v4/projects/1/deploy_tokens",
911+
method="post",
912+
)
913+
def resp_deploy_token_create(url, request):
914+
headers = {"content-type": "application/json"}
915+
content = """{
916+
"id": 1,
917+
"name": "test_deploy_token",
918+
"username": "custom-user",
919+
"expires_at": "2022-01-01T00:00:00.000Z",
920+
"token": "jMRvtPNxrn3crTAGukpZ",
921+
"scopes": [ "read_repository" ]}"""
922+
content = content.encode("utf-8")
923+
return response(200, content, headers, None, 5, request)
924+
925+
with HTTMock(resp_deploy_token_create):
926+
deploy_token = self.gl.projects.get(1, lazy=True).deploytokens.create(
927+
{
928+
"name": "test_deploy_token",
929+
"expires_at": "2022-01-01T00:00:00.000Z",
930+
"username": "custom-user",
931+
"scopes": ["read_repository"],
932+
}
933+
)
934+
self.assertIsInstance(deploy_token, ProjectDeployToken)
935+
self.assertEqual(deploy_token.id, 1),
936+
self.assertEqual(deploy_token.expires_at, "2022-01-01T00:00:00.000Z"),
937+
self.assertEqual(deploy_token.username, "custom-user")
938+
self.assertEqual(deploy_token.scopes, ["read_repository"])
939+
906940
def _default_config(self):
907941
fd, temp_path = tempfile.mkstemp()
908942
os.write(fd, valid_config)

gitlab/v4/objects.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,43 @@ class DeployKeyManager(ListMixin, RESTManager):
695695
_obj_cls = DeployKey
696696

697697

698+
class DeployToken(ObjectDeleteMixin, RESTObject):
699+
pass
700+
701+
702+
class DeployTokenManager(ListMixin, RESTManager):
703+
_path = "/deploy_tokens"
704+
_obj_cls = DeployToken
705+
706+
707+
class ProjectDeployToken(ObjectDeleteMixin, RESTObject):
708+
pass
709+
710+
711+
class ProjectDeployTokenManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
712+
_path = "/projects/%(project_id)s/deploy_tokens"
713+
_from_parent_attrs = {"project_id": "id"}
714+
_obj_cls = ProjectDeployToken
715+
_create_attrs = (
716+
("name", "scopes",),
717+
("expires_at", "username",),
718+
)
719+
720+
721+
class GroupDeployToken(ObjectDeleteMixin, RESTObject):
722+
pass
723+
724+
725+
class GroupDeployTokenManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
726+
_path = "/groups/%(group_id)s/deploy_tokens"
727+
_from_parent_attrs = {"group_id": "id"}
728+
_obj_cls = GroupDeployToken
729+
_create_attrs = (
730+
("name", "scopes",),
731+
("expires_at", "username",),
732+
)
733+
734+
698735
class NotificationSettings(SaveMixin, RESTObject):
699736
_id_attr = None
700737

@@ -1323,6 +1360,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
13231360
("subgroups", "GroupSubgroupManager"),
13241361
("variables", "GroupVariableManager"),
13251362
("clusters", "GroupClusterManager"),
1363+
("deploytokens", "GroupDeployTokenManager"),
13261364
)
13271365

13281366
@cli.register_custom_action("Group", ("to_project_id",))
@@ -4271,6 +4309,7 @@ class Project(SaveMixin, ObjectDeleteMixin, RESTObject):
42714309
("clusters", "ProjectClusterManager"),
42724310
("additionalstatistics", "ProjectAdditionalStatisticsManager"),
42734311
("issuesstatistics", "ProjectIssuesStatisticsManager"),
4312+
("deploytokens", "ProjectDeployTokenManager"),
42744313
)
42754314

42764315
@cli.register_custom_action("Project", ("submodule", "branch", "commit_sha"))

tools/cli_test_v4.sh

Lines changed: 80 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -195,14 +195,6 @@ testcase "project upload" '
195195
--filename '$(basename $0)' --filepath '$0' >/dev/null 2>&1
196196
'
197197

198-
testcase "project deletion" '
199-
GITLAB project delete --id "$PROJECT_ID"
200-
'
201-
202-
testcase "group deletion" '
203-
OUTPUT=$(try GITLAB group delete --id $GROUP_ID)
204-
'
205-
206198
testcase "application settings get" '
207199
GITLAB application-settings get >/dev/null 2>&1
208200
'
@@ -222,3 +214,83 @@ testcase "values from files" '
222214
echo $OUTPUT | grep -q "Multi line"
223215
'
224216

217+
# Test deploy tokens
218+
CREATE_PROJECT_DEPLOY_TOKEN_OUTPUT=$(GITLAB -v project-deploy-token create --project-id $PROJECT_ID \
219+
--name foo --username root --expires-at "2021-09-09" --scopes "read_registry")
220+
CREATED_DEPLOY_TOKEN_ID=$(echo "$CREATE_PROJECT_DEPLOY_TOKEN_OUTPUT" | grep ^id: | cut -d" " -f2)
221+
testcase "create project deploy token" '
222+
echo $CREATE_PROJECT_DEPLOY_TOKEN_OUTPUT | grep -q "name: foo"
223+
'
224+
testcase "create project deploy token" '
225+
echo $CREATE_PROJECT_DEPLOY_TOKEN_OUTPUT | grep -q "expires-at: 2021-09-09T00:00:00.000Z"
226+
'
227+
testcase "create project deploy token" '
228+
echo $CREATE_PROJECT_DEPLOY_TOKEN_OUTPUT | grep "scopes: " | grep -q "read_registry"
229+
'
230+
# Uncomment once https://gitlab.com/gitlab-org/gitlab/-/issues/211963 is fixed
231+
#testcase "create project deploy token" '
232+
# echo $CREATE_PROJECT_DEPLOY_TOKEN_OUTPUT | grep -q "username: root"
233+
#'
234+
235+
# Remove once https://gitlab.com/gitlab-org/gitlab/-/issues/211963 is fixed
236+
testcase "create project deploy token" '
237+
echo $CREATE_PROJECT_DEPLOY_TOKEN_OUTPUT | grep -q "gitlab+deploy-token"
238+
'
239+
240+
LIST_DEPLOY_TOKEN_OUTPUT=$(GITLAB -v deploy-token list)
241+
testcase "list all deploy tokens" '
242+
echo $LIST_DEPLOY_TOKEN_OUTPUT | grep -q "name: foo"
243+
'
244+
testcase "list all deploy tokens" '
245+
echo $LIST_DEPLOY_TOKEN_OUTPUT | grep -q "id: $CREATED_DEPLOY_TOKEN_ID"
246+
'
247+
testcase "list all deploy tokens" '
248+
echo $LIST_DEPLOY_TOKEN_OUTPUT | grep -q "expires-at: 2021-09-09T00:00:00.000Z"
249+
'
250+
testcase "list all deploy tokens" '
251+
echo $LIST_DEPLOY_TOKEN_OUTPUT | grep "scopes: " | grep -q "read_registry"
252+
'
253+
254+
testcase "list project deploy tokens" '
255+
OUTPUT=$(GITLAB -v project-deploy-token list --project-id $PROJECT_ID)
256+
echo $OUTPUT | grep -q "id: $CREATED_DEPLOY_TOKEN_ID"
257+
'
258+
testcase "delete project deploy token" '
259+
GITLAB -v project-deploy-token delete --project-id $PROJECT_ID --id $CREATED_DEPLOY_TOKEN_ID
260+
LIST_PROJECT_DEPLOY_TOKEN_OUTPUT=$(GITLAB -v project-deploy-token list --project-id $PROJECT_ID)
261+
echo $LIST_PROJECT_DEPLOY_TOKEN_OUTPUT | grep -qv "id: $CREATED_DEPLOY_TOKEN_ID"
262+
'
263+
# Uncomment once https://gitlab.com/gitlab-org/gitlab/-/issues/212523 is fixed
264+
#testcase "delete project deploy token" '
265+
# LIST_DEPLOY_TOKEN_OUTPUT=$(GITLAB -v deploy-token list)
266+
# echo $LIST_DEPLOY_TOKEN_OUTPUT | grep -qv "id: $CREATED_DEPLOY_TOKEN_ID"
267+
#'
268+
269+
CREATE_GROUP_DEPLOY_TOKEN_OUTPUT=$(GITLAB -v group-deploy-token create --group-id $GROUP_ID \
270+
--name bar --username root --expires-at "2021-09-09" --scopes "read_repository")
271+
CREATED_DEPLOY_TOKEN_ID=$(echo "$CREATE_GROUP_DEPLOY_TOKEN_OUTPUT" | grep ^id: | cut -d" " -f2)
272+
testcase "create group deploy token" '
273+
echo $CREATE_GROUP_DEPLOY_TOKEN_OUTPUT | grep -q "name: bar"
274+
'
275+
testcase "list group deploy tokens" '
276+
OUTPUT=$(GITLAB -v group-deploy-token list --group-id $GROUP_ID)
277+
echo $OUTPUT | grep -q "id: $CREATED_DEPLOY_TOKEN_ID"
278+
'
279+
testcase "delete group deploy token" '
280+
GITLAB -v group-deploy-token delete --group-id $GROUP_ID --id $CREATED_DEPLOY_TOKEN_ID
281+
LIST_GROUP_DEPLOY_TOKEN_OUTPUT=$(GITLAB -v group-deploy-token list --group-id $GROUP_ID)
282+
echo $LIST_GROUP_DEPLOY_TOKEN_OUTPUT | grep -qv "id: $CREATED_DEPLOY_TOKEN_ID"
283+
'
284+
# Uncomment once https://gitlab.com/gitlab-org/gitlab/-/issues/212523 is fixed
285+
#testcase "delete group deploy token" '
286+
# LIST_DEPLOY_TOKEN_OUTPUT=$(GITLAB -v deploy-token list)
287+
# echo $LIST_DEPLOY_TOKEN_OUTPUT | grep -qv "id: $CREATED_DEPLOY_TOKEN_ID"
288+
#'
289+
290+
testcase "project deletion" '
291+
GITLAB project delete --id "$PROJECT_ID"
292+
'
293+
294+
testcase "group deletion" '
295+
OUTPUT=$(try GITLAB group delete --id $GROUP_ID)
296+
'

0 commit comments

Comments
 (0)