python-gitlab 4.4.0__py3-none-any.whl → 4.6.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gitlab/_backends/protocol.py +2 -4
- gitlab/_version.py +1 -1
- gitlab/cli.py +33 -5
- gitlab/client.py +2 -3
- gitlab/mixins.py +22 -14
- gitlab/utils.py +3 -3
- gitlab/v4/cli.py +32 -11
- gitlab/v4/objects/__init__.py +1 -0
- gitlab/v4/objects/artifacts.py +7 -3
- gitlab/v4/objects/audit_events.py +1 -0
- gitlab/v4/objects/branches.py +10 -3
- gitlab/v4/objects/ci_lint.py +4 -4
- gitlab/v4/objects/commits.py +6 -6
- gitlab/v4/objects/container_registry.py +2 -2
- gitlab/v4/objects/deploy_keys.py +3 -1
- gitlab/v4/objects/deployments.py +3 -2
- gitlab/v4/objects/environments.py +1 -1
- gitlab/v4/objects/features.py +1 -0
- gitlab/v4/objects/files.py +15 -7
- gitlab/v4/objects/geo_nodes.py +4 -4
- gitlab/v4/objects/groups.py +13 -7
- gitlab/v4/objects/integrations.py +3 -1
- gitlab/v4/objects/issues.py +6 -4
- gitlab/v4/objects/iterations.py +29 -2
- gitlab/v4/objects/job_token_scope.py +48 -0
- gitlab/v4/objects/jobs.py +15 -15
- gitlab/v4/objects/merge_request_approvals.py +12 -59
- gitlab/v4/objects/merge_requests.py +14 -12
- gitlab/v4/objects/milestones.py +4 -4
- gitlab/v4/objects/namespaces.py +3 -1
- gitlab/v4/objects/packages.py +4 -4
- gitlab/v4/objects/pipelines.py +6 -5
- gitlab/v4/objects/projects.py +22 -18
- gitlab/v4/objects/repositories.py +14 -9
- gitlab/v4/objects/runners.py +2 -2
- gitlab/v4/objects/secure_files.py +2 -1
- gitlab/v4/objects/service_accounts.py +18 -0
- gitlab/v4/objects/sidekiq.py +4 -4
- gitlab/v4/objects/snippets.py +3 -3
- gitlab/v4/objects/todos.py +2 -2
- gitlab/v4/objects/topics.py +2 -2
- gitlab/v4/objects/users.py +11 -10
- gitlab/v4/objects/variables.py +1 -0
- {python_gitlab-4.4.0.dist-info → python_gitlab-4.6.0.dist-info}/METADATA +20 -3
- {python_gitlab-4.4.0.dist-info → python_gitlab-4.6.0.dist-info}/RECORD +50 -49
- {python_gitlab-4.4.0.dist-info → python_gitlab-4.6.0.dist-info}/WHEEL +1 -1
- {python_gitlab-4.4.0.dist-info → python_gitlab-4.6.0.dist-info}/AUTHORS +0 -0
- {python_gitlab-4.4.0.dist-info → python_gitlab-4.6.0.dist-info}/COPYING +0 -0
- {python_gitlab-4.4.0.dist-info → python_gitlab-4.6.0.dist-info}/entry_points.txt +0 -0
- {python_gitlab-4.4.0.dist-info → python_gitlab-4.6.0.dist-info}/top_level.txt +0 -0
gitlab/v4/objects/files.py
CHANGED
@@ -40,6 +40,7 @@ class ProjectFile(SaveMixin, ObjectDeleteMixin, RESTObject):
|
|
40
40
|
commit_message: str
|
41
41
|
file_path: str
|
42
42
|
manager: "ProjectFileManager"
|
43
|
+
content: str # since the `decode()` method uses `self.content`
|
43
44
|
|
44
45
|
def decode(self) -> bytes:
|
45
46
|
"""Returns the decoded content of the file.
|
@@ -108,7 +109,9 @@ class ProjectFileManager(GetMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTMa
|
|
108
109
|
optional=("encoding", "author_email", "author_name"),
|
109
110
|
)
|
110
111
|
|
111
|
-
@cli.register_custom_action(
|
112
|
+
@cli.register_custom_action(
|
113
|
+
cls_names="ProjectFileManager", required=("file_path", "ref")
|
114
|
+
)
|
112
115
|
# NOTE(jlvillal): Signature doesn't match UpdateMixin.update() so ignore
|
113
116
|
# type error
|
114
117
|
def get( # type: ignore
|
@@ -131,9 +134,9 @@ class ProjectFileManager(GetMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTMa
|
|
131
134
|
return cast(ProjectFile, GetMixin.get(self, file_path, ref=ref, **kwargs))
|
132
135
|
|
133
136
|
@cli.register_custom_action(
|
134
|
-
"ProjectFileManager",
|
135
|
-
("file_path", "branch", "content", "commit_message"),
|
136
|
-
("encoding", "author_email", "author_name"),
|
137
|
+
cls_names="ProjectFileManager",
|
138
|
+
required=("file_path", "branch", "content", "commit_message"),
|
139
|
+
optional=("encoding", "author_email", "author_name"),
|
137
140
|
)
|
138
141
|
@exc.on_http_error(exc.GitlabCreateError)
|
139
142
|
def create(
|
@@ -198,7 +201,8 @@ class ProjectFileManager(GetMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTMa
|
|
198
201
|
return result
|
199
202
|
|
200
203
|
@cli.register_custom_action(
|
201
|
-
"ProjectFileManager",
|
204
|
+
cls_names="ProjectFileManager",
|
205
|
+
required=("file_path", "branch", "commit_message"),
|
202
206
|
)
|
203
207
|
@exc.on_http_error(exc.GitlabDeleteError)
|
204
208
|
# NOTE(jlvillal): Signature doesn't match DeleteMixin.delete() so ignore
|
@@ -223,7 +227,9 @@ class ProjectFileManager(GetMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTMa
|
|
223
227
|
data = {"branch": branch, "commit_message": commit_message}
|
224
228
|
self.gitlab.http_delete(path, query_data=data, **kwargs)
|
225
229
|
|
226
|
-
@cli.register_custom_action(
|
230
|
+
@cli.register_custom_action(
|
231
|
+
cls_names="ProjectFileManager", required=("file_path", "ref")
|
232
|
+
)
|
227
233
|
@exc.on_http_error(exc.GitlabGetError)
|
228
234
|
def raw(
|
229
235
|
self,
|
@@ -270,7 +276,9 @@ class ProjectFileManager(GetMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTMa
|
|
270
276
|
result, streamed, action, chunk_size, iterator=iterator
|
271
277
|
)
|
272
278
|
|
273
|
-
@cli.register_custom_action(
|
279
|
+
@cli.register_custom_action(
|
280
|
+
cls_names="ProjectFileManager", required=("file_path", "ref")
|
281
|
+
)
|
274
282
|
@exc.on_http_error(exc.GitlabListError)
|
275
283
|
def blame(self, file_path: str, ref: str, **kwargs: Any) -> List[Dict[str, Any]]:
|
276
284
|
"""Return the content of a file for a commit.
|
gitlab/v4/objects/geo_nodes.py
CHANGED
@@ -19,7 +19,7 @@ __all__ = [
|
|
19
19
|
|
20
20
|
|
21
21
|
class GeoNode(SaveMixin, ObjectDeleteMixin, RESTObject):
|
22
|
-
@cli.register_custom_action("GeoNode")
|
22
|
+
@cli.register_custom_action(cls_names="GeoNode")
|
23
23
|
@exc.on_http_error(exc.GitlabRepairError)
|
24
24
|
def repair(self, **kwargs: Any) -> None:
|
25
25
|
"""Repair the OAuth authentication of the geo node.
|
@@ -37,7 +37,7 @@ class GeoNode(SaveMixin, ObjectDeleteMixin, RESTObject):
|
|
37
37
|
assert isinstance(server_data, dict)
|
38
38
|
self._update_attrs(server_data)
|
39
39
|
|
40
|
-
@cli.register_custom_action("GeoNode")
|
40
|
+
@cli.register_custom_action(cls_names="GeoNode")
|
41
41
|
@exc.on_http_error(exc.GitlabGetError)
|
42
42
|
def status(self, **kwargs: Any) -> Dict[str, Any]:
|
43
43
|
"""Get the status of the geo node.
|
@@ -69,7 +69,7 @@ class GeoNodeManager(RetrieveMixin, UpdateMixin, DeleteMixin, RESTManager):
|
|
69
69
|
def get(self, id: Union[str, int], lazy: bool = False, **kwargs: Any) -> GeoNode:
|
70
70
|
return cast(GeoNode, super().get(id=id, lazy=lazy, **kwargs))
|
71
71
|
|
72
|
-
@cli.register_custom_action("GeoNodeManager")
|
72
|
+
@cli.register_custom_action(cls_names="GeoNodeManager")
|
73
73
|
@exc.on_http_error(exc.GitlabGetError)
|
74
74
|
def status(self, **kwargs: Any) -> List[Dict[str, Any]]:
|
75
75
|
"""Get the status of all the geo nodes.
|
@@ -89,7 +89,7 @@ class GeoNodeManager(RetrieveMixin, UpdateMixin, DeleteMixin, RESTManager):
|
|
89
89
|
assert isinstance(result, list)
|
90
90
|
return result
|
91
91
|
|
92
|
-
@cli.register_custom_action("GeoNodeManager")
|
92
|
+
@cli.register_custom_action(cls_names="GeoNodeManager")
|
93
93
|
@exc.on_http_error(exc.GitlabGetError)
|
94
94
|
def current_failures(self, **kwargs: Any) -> List[Dict[str, Any]]:
|
95
95
|
"""Get the list of failures on the current geo node.
|
gitlab/v4/objects/groups.py
CHANGED
@@ -46,6 +46,7 @@ from .packages import GroupPackageManager # noqa: F401
|
|
46
46
|
from .projects import GroupProjectManager, SharedProjectManager # noqa: F401
|
47
47
|
from .push_rules import GroupPushRulesManager
|
48
48
|
from .runners import GroupRunnerManager # noqa: F401
|
49
|
+
from .service_accounts import GroupServiceAccountManager # noqa: F401
|
49
50
|
from .statistics import GroupIssuesStatisticsManager # noqa: F401
|
50
51
|
from .variables import GroupVariableManager # noqa: F401
|
51
52
|
from .wikis import GroupWikiManager # noqa: F401
|
@@ -102,8 +103,9 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
|
|
102
103
|
variables: GroupVariableManager
|
103
104
|
wikis: GroupWikiManager
|
104
105
|
saml_group_links: "GroupSAMLGroupLinkManager"
|
106
|
+
service_accounts: "GroupServiceAccountManager"
|
105
107
|
|
106
|
-
@cli.register_custom_action("Group", ("project_id",))
|
108
|
+
@cli.register_custom_action(cls_names="Group", required=("project_id",))
|
107
109
|
@exc.on_http_error(exc.GitlabTransferProjectError)
|
108
110
|
def transfer_project(self, project_id: int, **kwargs: Any) -> None:
|
109
111
|
"""Transfer a project to this group.
|
@@ -119,7 +121,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
|
|
119
121
|
path = f"/groups/{self.encoded_id}/projects/{project_id}"
|
120
122
|
self.manager.gitlab.http_post(path, **kwargs)
|
121
123
|
|
122
|
-
@cli.register_custom_action("Group", (), ("group_id",))
|
124
|
+
@cli.register_custom_action(cls_names="Group", required=(), optional=("group_id",))
|
123
125
|
@exc.on_http_error(exc.GitlabGroupTransferError)
|
124
126
|
def transfer(self, group_id: Optional[int] = None, **kwargs: Any) -> None:
|
125
127
|
"""Transfer the group to a new parent group or make it a top-level group.
|
@@ -141,7 +143,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
|
|
141
143
|
post_data["group_id"] = group_id
|
142
144
|
self.manager.gitlab.http_post(path, post_data=post_data, **kwargs)
|
143
145
|
|
144
|
-
@cli.register_custom_action("Group", ("scope", "search"))
|
146
|
+
@cli.register_custom_action(cls_names="Group", required=("scope", "search"))
|
145
147
|
@exc.on_http_error(exc.GitlabSearchError)
|
146
148
|
def search(
|
147
149
|
self, scope: str, search: str, **kwargs: Any
|
@@ -164,7 +166,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
|
|
164
166
|
path = f"/groups/{self.encoded_id}/search"
|
165
167
|
return self.manager.gitlab.http_list(path, query_data=data, **kwargs)
|
166
168
|
|
167
|
-
@cli.register_custom_action("Group")
|
169
|
+
@cli.register_custom_action(cls_names="Group")
|
168
170
|
@exc.on_http_error(exc.GitlabCreateError)
|
169
171
|
def ldap_sync(self, **kwargs: Any) -> None:
|
170
172
|
"""Sync LDAP groups.
|
@@ -179,7 +181,11 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
|
|
179
181
|
path = f"/groups/{self.encoded_id}/ldap_sync"
|
180
182
|
self.manager.gitlab.http_post(path, **kwargs)
|
181
183
|
|
182
|
-
@cli.register_custom_action(
|
184
|
+
@cli.register_custom_action(
|
185
|
+
cls_names="Group",
|
186
|
+
required=("group_id", "group_access"),
|
187
|
+
optional=("expires_at",),
|
188
|
+
)
|
183
189
|
@exc.on_http_error(exc.GitlabCreateError)
|
184
190
|
def share(
|
185
191
|
self,
|
@@ -213,7 +219,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
|
|
213
219
|
assert isinstance(server_data, dict)
|
214
220
|
self._update_attrs(server_data)
|
215
221
|
|
216
|
-
@cli.register_custom_action("Group", ("group_id",))
|
222
|
+
@cli.register_custom_action(cls_names="Group", required=("group_id",))
|
217
223
|
@exc.on_http_error(exc.GitlabDeleteError)
|
218
224
|
def unshare(self, group_id: int, **kwargs: Any) -> None:
|
219
225
|
"""Delete a shared group link within a group.
|
@@ -229,7 +235,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
|
|
229
235
|
path = f"/groups/{self.encoded_id}/share/{group_id}"
|
230
236
|
self.manager.gitlab.http_delete(path, **kwargs)
|
231
237
|
|
232
|
-
@cli.register_custom_action("Group")
|
238
|
+
@cli.register_custom_action(cls_names="Group")
|
233
239
|
@exc.on_http_error(exc.GitlabRestoreError)
|
234
240
|
def restore(self, **kwargs: Any) -> None:
|
235
241
|
"""Restore a group marked for deletion..
|
@@ -270,7 +270,9 @@ class ProjectIntegrationManager(
|
|
270
270
|
) -> ProjectIntegration:
|
271
271
|
return cast(ProjectIntegration, super().get(id=id, lazy=lazy, **kwargs))
|
272
272
|
|
273
|
-
@cli.register_custom_action(
|
273
|
+
@cli.register_custom_action(
|
274
|
+
cls_names=("ProjectIntegrationManager", "ProjectServiceManager")
|
275
|
+
)
|
274
276
|
def available(self) -> List[str]:
|
275
277
|
"""List the services known by python-gitlab.
|
276
278
|
|
gitlab/v4/objects/issues.py
CHANGED
@@ -126,7 +126,7 @@ class ProjectIssue(
|
|
126
126
|
resource_iteration_events: ProjectIssueResourceIterationEventManager
|
127
127
|
resource_weight_events: ProjectIssueResourceWeightEventManager
|
128
128
|
|
129
|
-
@cli.register_custom_action("ProjectIssue", ("to_project_id",))
|
129
|
+
@cli.register_custom_action(cls_names="ProjectIssue", required=("to_project_id",))
|
130
130
|
@exc.on_http_error(exc.GitlabUpdateError)
|
131
131
|
def move(self, to_project_id: int, **kwargs: Any) -> None:
|
132
132
|
"""Move the issue to another project.
|
@@ -146,7 +146,9 @@ class ProjectIssue(
|
|
146
146
|
assert isinstance(server_data, dict)
|
147
147
|
self._update_attrs(server_data)
|
148
148
|
|
149
|
-
@cli.register_custom_action(
|
149
|
+
@cli.register_custom_action(
|
150
|
+
cls_names="ProjectIssue", required=("move_after_id", "move_before_id")
|
151
|
+
)
|
150
152
|
@exc.on_http_error(exc.GitlabUpdateError)
|
151
153
|
def reorder(
|
152
154
|
self,
|
@@ -178,7 +180,7 @@ class ProjectIssue(
|
|
178
180
|
assert isinstance(server_data, dict)
|
179
181
|
self._update_attrs(server_data)
|
180
182
|
|
181
|
-
@cli.register_custom_action("ProjectIssue")
|
183
|
+
@cli.register_custom_action(cls_names="ProjectIssue")
|
182
184
|
@exc.on_http_error(exc.GitlabGetError)
|
183
185
|
def related_merge_requests(self, **kwargs: Any) -> Dict[str, Any]:
|
184
186
|
"""List merge requests related to the issue.
|
@@ -199,7 +201,7 @@ class ProjectIssue(
|
|
199
201
|
assert isinstance(result, dict)
|
200
202
|
return result
|
201
203
|
|
202
|
-
@cli.register_custom_action("ProjectIssue")
|
204
|
+
@cli.register_custom_action(cls_names="ProjectIssue")
|
203
205
|
@exc.on_http_error(exc.GitlabGetError)
|
204
206
|
def closed_by(self, **kwargs: Any) -> Dict[str, Any]:
|
205
207
|
"""List merge requests that will close the issue when merged.
|
gitlab/v4/objects/iterations.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
from gitlab import types
|
1
2
|
from gitlab.base import RESTManager, RESTObject
|
2
3
|
from gitlab.mixins import ListMixin
|
3
4
|
|
@@ -16,11 +17,37 @@ class GroupIterationManager(ListMixin, RESTManager):
|
|
16
17
|
_path = "/groups/{group_id}/iterations"
|
17
18
|
_obj_cls = GroupIteration
|
18
19
|
_from_parent_attrs = {"group_id": "id"}
|
19
|
-
|
20
|
+
# When using the API, the "in" keyword collides with python's "in" keyword
|
21
|
+
# raising a SyntaxError.
|
22
|
+
# For this reason, we have to use the query_parameters argument:
|
23
|
+
# group.iterations.list(query_parameters={"in": "title"})
|
24
|
+
_list_filters = (
|
25
|
+
"include_ancestors",
|
26
|
+
"include_descendants",
|
27
|
+
"in",
|
28
|
+
"search",
|
29
|
+
"state",
|
30
|
+
"updated_after",
|
31
|
+
"updated_before",
|
32
|
+
)
|
33
|
+
_types = {"in": types.ArrayAttribute}
|
20
34
|
|
21
35
|
|
22
36
|
class ProjectIterationManager(ListMixin, RESTManager):
|
23
37
|
_path = "/projects/{project_id}/iterations"
|
24
38
|
_obj_cls = GroupIteration
|
25
39
|
_from_parent_attrs = {"project_id": "id"}
|
26
|
-
|
40
|
+
# When using the API, the "in" keyword collides with python's "in" keyword
|
41
|
+
# raising a SyntaxError.
|
42
|
+
# For this reason, we have to use the query_parameters argument:
|
43
|
+
# project.iterations.list(query_parameters={"in": "title"})
|
44
|
+
_list_filters = (
|
45
|
+
"include_ancestors",
|
46
|
+
"include_descendants",
|
47
|
+
"in",
|
48
|
+
"search",
|
49
|
+
"state",
|
50
|
+
"updated_after",
|
51
|
+
"updated_before",
|
52
|
+
)
|
53
|
+
_types = {"in": types.ArrayAttribute}
|
@@ -2,12 +2,17 @@ from typing import Any, cast
|
|
2
2
|
|
3
3
|
from gitlab.base import RESTManager, RESTObject
|
4
4
|
from gitlab.mixins import (
|
5
|
+
CreateMixin,
|
6
|
+
DeleteMixin,
|
5
7
|
GetWithoutIdMixin,
|
8
|
+
ListMixin,
|
9
|
+
ObjectDeleteMixin,
|
6
10
|
RefreshMixin,
|
7
11
|
SaveMixin,
|
8
12
|
UpdateMethod,
|
9
13
|
UpdateMixin,
|
10
14
|
)
|
15
|
+
from gitlab.types import RequiredOptional
|
11
16
|
|
12
17
|
__all__ = [
|
13
18
|
"ProjectJobTokenScope",
|
@@ -18,6 +23,9 @@ __all__ = [
|
|
18
23
|
class ProjectJobTokenScope(RefreshMixin, SaveMixin, RESTObject):
|
19
24
|
_id_attr = None
|
20
25
|
|
26
|
+
allowlist: "AllowlistProjectManager"
|
27
|
+
groups_allowlist: "AllowlistGroupManager"
|
28
|
+
|
21
29
|
|
22
30
|
class ProjectJobTokenScopeManager(GetWithoutIdMixin, UpdateMixin, RESTManager):
|
23
31
|
_path = "/projects/{project_id}/job_token_scope"
|
@@ -27,3 +35,43 @@ class ProjectJobTokenScopeManager(GetWithoutIdMixin, UpdateMixin, RESTManager):
|
|
27
35
|
|
28
36
|
def get(self, **kwargs: Any) -> ProjectJobTokenScope:
|
29
37
|
return cast(ProjectJobTokenScope, super().get(**kwargs))
|
38
|
+
|
39
|
+
|
40
|
+
class AllowlistProject(ObjectDeleteMixin, RESTObject):
|
41
|
+
_id_attr = "target_project_id" # note: only true for create endpoint
|
42
|
+
|
43
|
+
def get_id(self) -> int:
|
44
|
+
"""Returns the id of the resource. This override deals with
|
45
|
+
the fact that either an `id` or a `target_project_id` attribute
|
46
|
+
is returned by the server depending on the endpoint called."""
|
47
|
+
target_project_id = cast(int, super().get_id())
|
48
|
+
if target_project_id is not None:
|
49
|
+
return target_project_id
|
50
|
+
return cast(int, self.id)
|
51
|
+
|
52
|
+
|
53
|
+
class AllowlistProjectManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
|
54
|
+
_path = "/projects/{project_id}/job_token_scope/allowlist"
|
55
|
+
_obj_cls = AllowlistProject
|
56
|
+
_from_parent_attrs = {"project_id": "project_id"}
|
57
|
+
_create_attrs = RequiredOptional(required=("target_project_id",))
|
58
|
+
|
59
|
+
|
60
|
+
class AllowlistGroup(ObjectDeleteMixin, RESTObject):
|
61
|
+
_id_attr = "target_group_id" # note: only true for create endpoint
|
62
|
+
|
63
|
+
def get_id(self) -> int:
|
64
|
+
"""Returns the id of the resource. This override deals with
|
65
|
+
the fact that either an `id` or a `target_group_id` attribute
|
66
|
+
is returned by the server depending on the endpoint called."""
|
67
|
+
target_group_id = cast(int, super().get_id())
|
68
|
+
if target_group_id is not None:
|
69
|
+
return target_group_id
|
70
|
+
return cast(int, self.id)
|
71
|
+
|
72
|
+
|
73
|
+
class AllowlistGroupManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
|
74
|
+
_path = "/projects/{project_id}/job_token_scope/groups_allowlist"
|
75
|
+
_obj_cls = AllowlistGroup
|
76
|
+
_from_parent_attrs = {"project_id": "project_id"}
|
77
|
+
_create_attrs = RequiredOptional(required=("target_group_id",))
|
gitlab/v4/objects/jobs.py
CHANGED
@@ -16,7 +16,7 @@ __all__ = [
|
|
16
16
|
|
17
17
|
|
18
18
|
class ProjectJob(RefreshMixin, RESTObject):
|
19
|
-
@cli.register_custom_action("ProjectJob")
|
19
|
+
@cli.register_custom_action(cls_names="ProjectJob")
|
20
20
|
@exc.on_http_error(exc.GitlabJobCancelError)
|
21
21
|
def cancel(self, **kwargs: Any) -> Dict[str, Any]:
|
22
22
|
"""Cancel the job.
|
@@ -34,7 +34,7 @@ class ProjectJob(RefreshMixin, RESTObject):
|
|
34
34
|
assert isinstance(result, dict)
|
35
35
|
return result
|
36
36
|
|
37
|
-
@cli.register_custom_action("ProjectJob")
|
37
|
+
@cli.register_custom_action(cls_names="ProjectJob")
|
38
38
|
@exc.on_http_error(exc.GitlabJobRetryError)
|
39
39
|
def retry(self, **kwargs: Any) -> Dict[str, Any]:
|
40
40
|
"""Retry the job.
|
@@ -52,7 +52,7 @@ class ProjectJob(RefreshMixin, RESTObject):
|
|
52
52
|
assert isinstance(result, dict)
|
53
53
|
return result
|
54
54
|
|
55
|
-
@cli.register_custom_action("ProjectJob")
|
55
|
+
@cli.register_custom_action(cls_names="ProjectJob")
|
56
56
|
@exc.on_http_error(exc.GitlabJobPlayError)
|
57
57
|
def play(self, **kwargs: Any) -> None:
|
58
58
|
"""Trigger a job explicitly.
|
@@ -65,9 +65,12 @@ class ProjectJob(RefreshMixin, RESTObject):
|
|
65
65
|
GitlabJobPlayError: If the job could not be triggered
|
66
66
|
"""
|
67
67
|
path = f"{self.manager.path}/{self.encoded_id}/play"
|
68
|
-
self.manager.gitlab.http_post(path, **kwargs)
|
68
|
+
result = self.manager.gitlab.http_post(path, **kwargs)
|
69
|
+
if TYPE_CHECKING:
|
70
|
+
assert isinstance(result, dict)
|
71
|
+
self._update_attrs(result)
|
69
72
|
|
70
|
-
@cli.register_custom_action("ProjectJob")
|
73
|
+
@cli.register_custom_action(cls_names="ProjectJob")
|
71
74
|
@exc.on_http_error(exc.GitlabJobEraseError)
|
72
75
|
def erase(self, **kwargs: Any) -> None:
|
73
76
|
"""Erase the job (remove job artifacts and trace).
|
@@ -82,7 +85,7 @@ class ProjectJob(RefreshMixin, RESTObject):
|
|
82
85
|
path = f"{self.manager.path}/{self.encoded_id}/erase"
|
83
86
|
self.manager.gitlab.http_post(path, **kwargs)
|
84
87
|
|
85
|
-
@cli.register_custom_action("ProjectJob")
|
88
|
+
@cli.register_custom_action(cls_names="ProjectJob")
|
86
89
|
@exc.on_http_error(exc.GitlabCreateError)
|
87
90
|
def keep_artifacts(self, **kwargs: Any) -> None:
|
88
91
|
"""Prevent artifacts from being deleted when expiration is set.
|
@@ -97,7 +100,7 @@ class ProjectJob(RefreshMixin, RESTObject):
|
|
97
100
|
path = f"{self.manager.path}/{self.encoded_id}/artifacts/keep"
|
98
101
|
self.manager.gitlab.http_post(path, **kwargs)
|
99
102
|
|
100
|
-
@cli.register_custom_action("ProjectJob")
|
103
|
+
@cli.register_custom_action(cls_names="ProjectJob")
|
101
104
|
@exc.on_http_error(exc.GitlabCreateError)
|
102
105
|
def delete_artifacts(self, **kwargs: Any) -> None:
|
103
106
|
"""Delete artifacts of a job.
|
@@ -112,7 +115,7 @@ class ProjectJob(RefreshMixin, RESTObject):
|
|
112
115
|
path = f"{self.manager.path}/{self.encoded_id}/artifacts"
|
113
116
|
self.manager.gitlab.http_delete(path, **kwargs)
|
114
117
|
|
115
|
-
@cli.register_custom_action("ProjectJob")
|
118
|
+
@cli.register_custom_action(cls_names="ProjectJob")
|
116
119
|
@exc.on_http_error(exc.GitlabGetError)
|
117
120
|
def artifacts(
|
118
121
|
self,
|
@@ -153,7 +156,7 @@ class ProjectJob(RefreshMixin, RESTObject):
|
|
153
156
|
result, streamed, action, chunk_size, iterator=iterator
|
154
157
|
)
|
155
158
|
|
156
|
-
@cli.register_custom_action("ProjectJob")
|
159
|
+
@cli.register_custom_action(cls_names="ProjectJob")
|
157
160
|
@exc.on_http_error(exc.GitlabGetError)
|
158
161
|
def artifact(
|
159
162
|
self,
|
@@ -196,7 +199,7 @@ class ProjectJob(RefreshMixin, RESTObject):
|
|
196
199
|
result, streamed, action, chunk_size, iterator=iterator
|
197
200
|
)
|
198
201
|
|
199
|
-
@cli.register_custom_action("ProjectJob")
|
202
|
+
@cli.register_custom_action(cls_names="ProjectJob")
|
200
203
|
@exc.on_http_error(exc.GitlabGetError)
|
201
204
|
def trace(
|
202
205
|
self,
|
@@ -206,7 +209,7 @@ class ProjectJob(RefreshMixin, RESTObject):
|
|
206
209
|
*,
|
207
210
|
iterator: bool = False,
|
208
211
|
**kwargs: Any,
|
209
|
-
) ->
|
212
|
+
) -> Optional[Union[bytes, Iterator[Any]]]:
|
210
213
|
"""Get the job trace.
|
211
214
|
|
212
215
|
Args:
|
@@ -233,12 +236,9 @@ class ProjectJob(RefreshMixin, RESTObject):
|
|
233
236
|
)
|
234
237
|
if TYPE_CHECKING:
|
235
238
|
assert isinstance(result, requests.Response)
|
236
|
-
|
239
|
+
return utils.response_content(
|
237
240
|
result, streamed, action, chunk_size, iterator=iterator
|
238
241
|
)
|
239
|
-
if TYPE_CHECKING:
|
240
|
-
assert isinstance(return_value, dict)
|
241
|
-
return return_value
|
242
242
|
|
243
243
|
|
244
244
|
class ProjectJobManager(RetrieveMixin, RESTManager):
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import Any, cast,
|
1
|
+
from typing import Any, cast, List, Optional, TYPE_CHECKING, Union
|
2
2
|
|
3
3
|
from gitlab import exceptions as exc
|
4
4
|
from gitlab.base import RESTManager, RESTObject
|
@@ -89,6 +89,8 @@ class ProjectMergeRequestApprovalManager(GetWithoutIdMixin, UpdateMixin, RESTMan
|
|
89
89
|
approver_ids: Optional[List[int]] = None,
|
90
90
|
approver_group_ids: Optional[List[int]] = None,
|
91
91
|
approval_rule_name: str = "name",
|
92
|
+
*,
|
93
|
+
approver_usernames: Optional[List[str]] = None,
|
92
94
|
**kwargs: Any,
|
93
95
|
) -> RESTObject:
|
94
96
|
"""Change MR-level allowed approvers and approver groups.
|
@@ -104,6 +106,7 @@ class ProjectMergeRequestApprovalManager(GetWithoutIdMixin, UpdateMixin, RESTMan
|
|
104
106
|
"""
|
105
107
|
approver_ids = approver_ids or []
|
106
108
|
approver_group_ids = approver_group_ids or []
|
109
|
+
approver_usernames = approver_usernames or []
|
107
110
|
|
108
111
|
data = {
|
109
112
|
"name": approval_rule_name,
|
@@ -111,6 +114,7 @@ class ProjectMergeRequestApprovalManager(GetWithoutIdMixin, UpdateMixin, RESTMan
|
|
111
114
|
"rule_type": "regular",
|
112
115
|
"user_ids": approver_ids,
|
113
116
|
"group_ids": approver_group_ids,
|
117
|
+
"usernames": approver_usernames,
|
114
118
|
}
|
115
119
|
if TYPE_CHECKING:
|
116
120
|
assert self._parent is not None
|
@@ -118,12 +122,13 @@ class ProjectMergeRequestApprovalManager(GetWithoutIdMixin, UpdateMixin, RESTMan
|
|
118
122
|
self._parent.approval_rules
|
119
123
|
)
|
120
124
|
# update any existing approval rule matching the name
|
121
|
-
existing_approval_rules = approval_rules.list()
|
125
|
+
existing_approval_rules = approval_rules.list(iterator=True)
|
122
126
|
for ar in existing_approval_rules:
|
123
127
|
if ar.name == approval_rule_name:
|
124
128
|
ar.user_ids = data["user_ids"]
|
125
129
|
ar.approvals_required = data["approvals_required"]
|
126
130
|
ar.group_ids = data["group_ids"]
|
131
|
+
ar.usernames = data["usernames"]
|
127
132
|
ar.save()
|
128
133
|
return ar
|
129
134
|
# if there was no rule matching the rule name, create a new one
|
@@ -132,53 +137,27 @@ class ProjectMergeRequestApprovalManager(GetWithoutIdMixin, UpdateMixin, RESTMan
|
|
132
137
|
|
133
138
|
class ProjectMergeRequestApprovalRule(SaveMixin, ObjectDeleteMixin, RESTObject):
|
134
139
|
_repr_attr = "name"
|
135
|
-
id: int
|
136
|
-
approval_rule_id: int
|
137
|
-
merge_request_iid: int
|
138
|
-
|
139
|
-
@exc.on_http_error(exc.GitlabUpdateError)
|
140
|
-
def save(self, **kwargs: Any) -> None:
|
141
|
-
"""Save the changes made to the object to the server.
|
142
|
-
|
143
|
-
The object is updated to match what the server returns.
|
144
|
-
|
145
|
-
Args:
|
146
|
-
**kwargs: Extra options to send to the server (e.g. sudo)
|
147
|
-
|
148
|
-
Raise:
|
149
|
-
GitlabAuthenticationError: If authentication is not correct
|
150
|
-
GitlabUpdateError: If the server cannot perform the request
|
151
|
-
"""
|
152
|
-
# There is a mismatch between the name of our id attribute and the put
|
153
|
-
# REST API name for the project_id, so we override it here.
|
154
|
-
self.approval_rule_id = self.id
|
155
|
-
self.merge_request_iid = self._parent_attrs["mr_iid"]
|
156
|
-
self.id = self._parent_attrs["project_id"]
|
157
|
-
# save will update self.id with the result from the server, so no need
|
158
|
-
# to overwrite with what it was before we overwrote it.
|
159
|
-
SaveMixin.save(self, **kwargs)
|
160
140
|
|
161
141
|
|
162
142
|
class ProjectMergeRequestApprovalRuleManager(CRUDMixin, RESTManager):
|
163
|
-
_path = "/projects/{project_id}/merge_requests/{
|
143
|
+
_path = "/projects/{project_id}/merge_requests/{merge_request_iid}/approval_rules"
|
164
144
|
_obj_cls = ProjectMergeRequestApprovalRule
|
165
|
-
_from_parent_attrs = {"project_id": "project_id", "
|
145
|
+
_from_parent_attrs = {"project_id": "project_id", "merge_request_iid": "iid"}
|
166
146
|
_update_attrs = RequiredOptional(
|
167
147
|
required=(
|
168
148
|
"id",
|
169
149
|
"merge_request_iid",
|
170
|
-
"approval_rule_id",
|
171
150
|
"name",
|
172
151
|
"approvals_required",
|
173
152
|
),
|
174
|
-
optional=("user_ids", "group_ids"),
|
153
|
+
optional=("user_ids", "group_ids", "usernames"),
|
175
154
|
)
|
176
155
|
# Important: When approval_project_rule_id is set, the name, users and
|
177
156
|
# groups of project-level rule will be copied. The approvals_required
|
178
157
|
# specified will be used.
|
179
158
|
_create_attrs = RequiredOptional(
|
180
|
-
required=("
|
181
|
-
optional=("approval_project_rule_id", "user_ids", "group_ids"),
|
159
|
+
required=("name", "approvals_required"),
|
160
|
+
optional=("approval_project_rule_id", "user_ids", "group_ids", "usernames"),
|
182
161
|
)
|
183
162
|
|
184
163
|
def get(
|
@@ -188,32 +167,6 @@ class ProjectMergeRequestApprovalRuleManager(CRUDMixin, RESTManager):
|
|
188
167
|
ProjectMergeRequestApprovalRule, super().get(id=id, lazy=lazy, **kwargs)
|
189
168
|
)
|
190
169
|
|
191
|
-
def create(
|
192
|
-
self, data: Optional[Dict[str, Any]] = None, **kwargs: Any
|
193
|
-
) -> RESTObject:
|
194
|
-
"""Create a new object.
|
195
|
-
|
196
|
-
Args:
|
197
|
-
data: Parameters to send to the server to create the
|
198
|
-
resource
|
199
|
-
**kwargs: Extra options to send to the server (e.g. sudo or
|
200
|
-
'ref_name', 'stage', 'name', 'all')
|
201
|
-
|
202
|
-
Raises:
|
203
|
-
GitlabAuthenticationError: If authentication is not correct
|
204
|
-
GitlabCreateError: If the server cannot perform the request
|
205
|
-
|
206
|
-
Returns:
|
207
|
-
A new instance of the manage object class build with
|
208
|
-
the data sent by the server
|
209
|
-
"""
|
210
|
-
if TYPE_CHECKING:
|
211
|
-
assert data is not None
|
212
|
-
new_data = data.copy()
|
213
|
-
new_data["id"] = self._from_parent_attrs["project_id"]
|
214
|
-
new_data["merge_request_iid"] = self._from_parent_attrs["mr_iid"]
|
215
|
-
return CreateMixin.create(self, new_data, **kwargs)
|
216
|
-
|
217
170
|
|
218
171
|
class ProjectMergeRequestApprovalState(RESTObject):
|
219
172
|
pass
|