python-gitlab 4.5.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/_version.py +1 -1
- gitlab/cli.py +20 -4
- gitlab/client.py +2 -2
- gitlab/mixins.py +22 -14
- gitlab/v4/cli.py +23 -11
- gitlab/v4/objects/__init__.py +1 -0
- gitlab/v4/objects/artifacts.py +5 -2
- 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 +2 -2
- gitlab/v4/objects/environments.py +1 -1
- 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/jobs.py +11 -14
- gitlab/v4/objects/merge_request_approvals.py +8 -3
- gitlab/v4/objects/merge_requests.py +13 -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 +4 -4
- gitlab/v4/objects/projects.py +21 -18
- gitlab/v4/objects/repositories.py +13 -9
- gitlab/v4/objects/runners.py +2 -2
- gitlab/v4/objects/secure_files.py +1 -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 +10 -10
- {python_gitlab-4.5.0.dist-info → python_gitlab-4.6.0.dist-info}/METADATA +3 -3
- {python_gitlab-4.5.0.dist-info → python_gitlab-4.6.0.dist-info}/RECORD +43 -42
- {python_gitlab-4.5.0.dist-info → python_gitlab-4.6.0.dist-info}/AUTHORS +0 -0
- {python_gitlab-4.5.0.dist-info → python_gitlab-4.6.0.dist-info}/COPYING +0 -0
- {python_gitlab-4.5.0.dist-info → python_gitlab-4.6.0.dist-info}/WHEEL +0 -0
- {python_gitlab-4.5.0.dist-info → python_gitlab-4.6.0.dist-info}/entry_points.txt +0 -0
- {python_gitlab-4.5.0.dist-info → python_gitlab-4.6.0.dist-info}/top_level.txt +0 -0
gitlab/_version.py
CHANGED
gitlab/cli.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import argparse
|
2
|
+
import dataclasses
|
2
3
|
import functools
|
3
4
|
import os
|
4
5
|
import pathlib
|
@@ -29,12 +30,21 @@ from gitlab.base import RESTObject
|
|
29
30
|
camel_upperlower_regex = re.compile(r"([A-Z]+)([A-Z][a-z])")
|
30
31
|
camel_lowerupper_regex = re.compile(r"([a-z\d])([A-Z])")
|
31
32
|
|
33
|
+
|
34
|
+
@dataclasses.dataclass
|
35
|
+
class CustomAction:
|
36
|
+
required: Tuple[str, ...]
|
37
|
+
optional: Tuple[str, ...]
|
38
|
+
in_object: bool
|
39
|
+
requires_id: bool # if the `_id_attr` value should be a required argument
|
40
|
+
|
41
|
+
|
32
42
|
# custom_actions = {
|
33
43
|
# cls: {
|
34
44
|
# action: (mandatory_args, optional_args, in_obj),
|
35
45
|
# },
|
36
46
|
# }
|
37
|
-
custom_actions: Dict[str, Dict[str,
|
47
|
+
custom_actions: Dict[str, Dict[str, CustomAction]] = {}
|
38
48
|
|
39
49
|
|
40
50
|
# For an explanation of how these type-hints work see:
|
@@ -72,10 +82,12 @@ class VerticalHelpFormatter(argparse.HelpFormatter):
|
|
72
82
|
|
73
83
|
|
74
84
|
def register_custom_action(
|
85
|
+
*,
|
75
86
|
cls_names: Union[str, Tuple[str, ...]],
|
76
|
-
|
87
|
+
required: Tuple[str, ...] = (),
|
77
88
|
optional: Tuple[str, ...] = (),
|
78
89
|
custom_action: Optional[str] = None,
|
90
|
+
requires_id: bool = True, # if the `_id_attr` value should be a required argument
|
79
91
|
) -> Callable[[__F], __F]:
|
80
92
|
def wrap(f: __F) -> __F:
|
81
93
|
@functools.wraps(f)
|
@@ -98,7 +110,12 @@ def register_custom_action(
|
|
98
110
|
custom_actions[final_name] = {}
|
99
111
|
|
100
112
|
action = custom_action or f.__name__.replace("_", "-")
|
101
|
-
custom_actions[final_name][action] = (
|
113
|
+
custom_actions[final_name][action] = CustomAction(
|
114
|
+
required=required,
|
115
|
+
optional=optional,
|
116
|
+
in_object=in_obj,
|
117
|
+
requires_id=requires_id,
|
118
|
+
)
|
102
119
|
|
103
120
|
return cast(__F, wrapped_f)
|
104
121
|
|
@@ -134,7 +151,6 @@ def _get_base_parser(add_help: bool = True) -> argparse.ArgumentParser:
|
|
134
151
|
parser = argparse.ArgumentParser(
|
135
152
|
add_help=add_help,
|
136
153
|
description="GitLab API Command Line Interface",
|
137
|
-
formatter_class=VerticalHelpFormatter,
|
138
154
|
allow_abbrev=False,
|
139
155
|
)
|
140
156
|
parser.add_argument("--version", help="Display the version.", action="store_true")
|
gitlab/client.py
CHANGED
@@ -625,8 +625,8 @@ class Gitlab:
|
|
625
625
|
for item in result.history:
|
626
626
|
if item.status_code not in (301, 302):
|
627
627
|
continue
|
628
|
-
# GET methods can be redirected without issue
|
629
|
-
if item.request.method
|
628
|
+
# GET and HEAD methods can be redirected without issue
|
629
|
+
if item.request.method in ("GET", "HEAD"):
|
630
630
|
continue
|
631
631
|
target = item.headers.get("location")
|
632
632
|
raise gitlab.exceptions.RedirectError(
|
gitlab/mixins.py
CHANGED
@@ -550,7 +550,7 @@ class UserAgentDetailMixin(_RestObjectBase):
|
|
550
550
|
_updated_attrs: Dict[str, Any]
|
551
551
|
manager: base.RESTManager
|
552
552
|
|
553
|
-
@cli.register_custom_action(("Snippet", "ProjectSnippet", "ProjectIssue"))
|
553
|
+
@cli.register_custom_action(cls_names=("Snippet", "ProjectSnippet", "ProjectIssue"))
|
554
554
|
@exc.on_http_error(exc.GitlabGetError)
|
555
555
|
def user_agent_detail(self, **kwargs: Any) -> Dict[str, Any]:
|
556
556
|
"""Get the user agent detail.
|
@@ -578,7 +578,8 @@ class AccessRequestMixin(_RestObjectBase):
|
|
578
578
|
manager: base.RESTManager
|
579
579
|
|
580
580
|
@cli.register_custom_action(
|
581
|
-
("ProjectAccessRequest", "GroupAccessRequest"),
|
581
|
+
cls_names=("ProjectAccessRequest", "GroupAccessRequest"),
|
582
|
+
optional=("access_level",),
|
582
583
|
)
|
583
584
|
@exc.on_http_error(exc.GitlabUpdateError)
|
584
585
|
def approve(
|
@@ -611,7 +612,7 @@ class DownloadMixin(_RestObjectBase):
|
|
611
612
|
_updated_attrs: Dict[str, Any]
|
612
613
|
manager: base.RESTManager
|
613
614
|
|
614
|
-
@cli.register_custom_action(("GroupExport", "ProjectExport"))
|
615
|
+
@cli.register_custom_action(cls_names=("GroupExport", "ProjectExport"))
|
615
616
|
@exc.on_http_error(exc.GitlabGetError)
|
616
617
|
def download(
|
617
618
|
self,
|
@@ -721,7 +722,7 @@ class SubscribableMixin(_RestObjectBase):
|
|
721
722
|
manager: base.RESTManager
|
722
723
|
|
723
724
|
@cli.register_custom_action(
|
724
|
-
("ProjectIssue", "ProjectMergeRequest", "ProjectLabel", "GroupLabel")
|
725
|
+
cls_names=("ProjectIssue", "ProjectMergeRequest", "ProjectLabel", "GroupLabel")
|
725
726
|
)
|
726
727
|
@exc.on_http_error(exc.GitlabSubscribeError)
|
727
728
|
def subscribe(self, **kwargs: Any) -> None:
|
@@ -741,7 +742,7 @@ class SubscribableMixin(_RestObjectBase):
|
|
741
742
|
self._update_attrs(server_data)
|
742
743
|
|
743
744
|
@cli.register_custom_action(
|
744
|
-
("ProjectIssue", "ProjectMergeRequest", "ProjectLabel", "GroupLabel")
|
745
|
+
cls_names=("ProjectIssue", "ProjectMergeRequest", "ProjectLabel", "GroupLabel")
|
745
746
|
)
|
746
747
|
@exc.on_http_error(exc.GitlabUnsubscribeError)
|
747
748
|
def unsubscribe(self, **kwargs: Any) -> None:
|
@@ -769,7 +770,7 @@ class TodoMixin(_RestObjectBase):
|
|
769
770
|
_updated_attrs: Dict[str, Any]
|
770
771
|
manager: base.RESTManager
|
771
772
|
|
772
|
-
@cli.register_custom_action(("ProjectIssue", "ProjectMergeRequest"))
|
773
|
+
@cli.register_custom_action(cls_names=("ProjectIssue", "ProjectMergeRequest"))
|
773
774
|
@exc.on_http_error(exc.GitlabTodoError)
|
774
775
|
def todo(self, **kwargs: Any) -> None:
|
775
776
|
"""Create a todo associated to the object.
|
@@ -793,7 +794,7 @@ class TimeTrackingMixin(_RestObjectBase):
|
|
793
794
|
_updated_attrs: Dict[str, Any]
|
794
795
|
manager: base.RESTManager
|
795
796
|
|
796
|
-
@cli.register_custom_action(("ProjectIssue", "ProjectMergeRequest"))
|
797
|
+
@cli.register_custom_action(cls_names=("ProjectIssue", "ProjectMergeRequest"))
|
797
798
|
@exc.on_http_error(exc.GitlabTimeTrackingError)
|
798
799
|
def time_stats(self, **kwargs: Any) -> Dict[str, Any]:
|
799
800
|
"""Get time stats for the object.
|
@@ -819,7 +820,9 @@ class TimeTrackingMixin(_RestObjectBase):
|
|
819
820
|
assert not isinstance(result, requests.Response)
|
820
821
|
return result
|
821
822
|
|
822
|
-
@cli.register_custom_action(
|
823
|
+
@cli.register_custom_action(
|
824
|
+
cls_names=("ProjectIssue", "ProjectMergeRequest"), required=("duration",)
|
825
|
+
)
|
823
826
|
@exc.on_http_error(exc.GitlabTimeTrackingError)
|
824
827
|
def time_estimate(self, duration: str, **kwargs: Any) -> Dict[str, Any]:
|
825
828
|
"""Set an estimated time of work for the object.
|
@@ -839,7 +842,7 @@ class TimeTrackingMixin(_RestObjectBase):
|
|
839
842
|
assert not isinstance(result, requests.Response)
|
840
843
|
return result
|
841
844
|
|
842
|
-
@cli.register_custom_action(("ProjectIssue", "ProjectMergeRequest"))
|
845
|
+
@cli.register_custom_action(cls_names=("ProjectIssue", "ProjectMergeRequest"))
|
843
846
|
@exc.on_http_error(exc.GitlabTimeTrackingError)
|
844
847
|
def reset_time_estimate(self, **kwargs: Any) -> Dict[str, Any]:
|
845
848
|
"""Resets estimated time for the object to 0 seconds.
|
@@ -857,7 +860,9 @@ class TimeTrackingMixin(_RestObjectBase):
|
|
857
860
|
assert not isinstance(result, requests.Response)
|
858
861
|
return result
|
859
862
|
|
860
|
-
@cli.register_custom_action(
|
863
|
+
@cli.register_custom_action(
|
864
|
+
cls_names=("ProjectIssue", "ProjectMergeRequest"), required=("duration",)
|
865
|
+
)
|
861
866
|
@exc.on_http_error(exc.GitlabTimeTrackingError)
|
862
867
|
def add_spent_time(self, duration: str, **kwargs: Any) -> Dict[str, Any]:
|
863
868
|
"""Add time spent working on the object.
|
@@ -877,7 +882,7 @@ class TimeTrackingMixin(_RestObjectBase):
|
|
877
882
|
assert not isinstance(result, requests.Response)
|
878
883
|
return result
|
879
884
|
|
880
|
-
@cli.register_custom_action(("ProjectIssue", "ProjectMergeRequest"))
|
885
|
+
@cli.register_custom_action(cls_names=("ProjectIssue", "ProjectMergeRequest"))
|
881
886
|
@exc.on_http_error(exc.GitlabTimeTrackingError)
|
882
887
|
def reset_spent_time(self, **kwargs: Any) -> Dict[str, Any]:
|
883
888
|
"""Resets the time spent working on the object.
|
@@ -904,7 +909,7 @@ class ParticipantsMixin(_RestObjectBase):
|
|
904
909
|
_updated_attrs: Dict[str, Any]
|
905
910
|
manager: base.RESTManager
|
906
911
|
|
907
|
-
@cli.register_custom_action(("ProjectMergeRequest", "ProjectIssue"))
|
912
|
+
@cli.register_custom_action(cls_names=("ProjectMergeRequest", "ProjectIssue"))
|
908
913
|
@exc.on_http_error(exc.GitlabListError)
|
909
914
|
def participants(self, **kwargs: Any) -> Dict[str, Any]:
|
910
915
|
"""List the participants.
|
@@ -932,7 +937,8 @@ class ParticipantsMixin(_RestObjectBase):
|
|
932
937
|
|
933
938
|
class BadgeRenderMixin(_RestManagerBase):
|
934
939
|
@cli.register_custom_action(
|
935
|
-
("GroupBadgeManager", "ProjectBadgeManager"),
|
940
|
+
cls_names=("GroupBadgeManager", "ProjectBadgeManager"),
|
941
|
+
required=("link_url", "image_url"),
|
936
942
|
)
|
937
943
|
@exc.on_http_error(exc.GitlabRenderError)
|
938
944
|
def render(self, link_url: str, image_url: str, **kwargs: Any) -> Dict[str, Any]:
|
@@ -1025,7 +1031,9 @@ class UploadMixin(_RestObjectBase):
|
|
1025
1031
|
data = self.attributes
|
1026
1032
|
return self._upload_path.format(**data)
|
1027
1033
|
|
1028
|
-
@cli.register_custom_action(
|
1034
|
+
@cli.register_custom_action(
|
1035
|
+
cls_names=("Project", "ProjectWiki"), required=("filename", "filepath")
|
1036
|
+
)
|
1029
1037
|
@exc.on_http_error(exc.GitlabUploadError)
|
1030
1038
|
def upload(
|
1031
1039
|
self,
|
gitlab/v4/cli.py
CHANGED
@@ -82,7 +82,7 @@ class GitlabCLI:
|
|
82
82
|
|
83
83
|
def do_custom(self) -> Any:
|
84
84
|
class_instance: Union[gitlab.base.RESTManager, gitlab.base.RESTObject]
|
85
|
-
in_obj = cli.custom_actions[self.cls_name][self.resource_action]
|
85
|
+
in_obj = cli.custom_actions[self.cls_name][self.resource_action].in_object
|
86
86
|
|
87
87
|
# Get the object (lazy), then act
|
88
88
|
if in_obj:
|
@@ -207,12 +207,20 @@ def _populate_sub_parser_by_class(
|
|
207
207
|
mgr_cls = getattr(gitlab.v4.objects, mgr_cls_name)
|
208
208
|
|
209
209
|
action_parsers: Dict[str, argparse.ArgumentParser] = {}
|
210
|
-
for action_name in [
|
210
|
+
for action_name, help_text in [
|
211
|
+
("list", "List the GitLab resources"),
|
212
|
+
("get", "Get a GitLab resource"),
|
213
|
+
("create", "Create a GitLab resource"),
|
214
|
+
("update", "Update a GitLab resource"),
|
215
|
+
("delete", "Delete a GitLab resource"),
|
216
|
+
]:
|
211
217
|
if not hasattr(mgr_cls, action_name):
|
212
218
|
continue
|
213
219
|
|
214
220
|
sub_parser_action = sub_parser.add_parser(
|
215
|
-
action_name,
|
221
|
+
action_name,
|
222
|
+
conflict_handler="resolve",
|
223
|
+
help=help_text,
|
216
224
|
)
|
217
225
|
action_parsers[action_name] = sub_parser_action
|
218
226
|
sub_parser_action.add_argument("--sudo", required=False)
|
@@ -307,19 +315,19 @@ def _populate_sub_parser_by_class(
|
|
307
315
|
)
|
308
316
|
sub_parser_action.add_argument("--sudo", required=False)
|
309
317
|
|
318
|
+
custom_action = cli.custom_actions[name][action_name]
|
310
319
|
# We need to get the object somehow
|
311
320
|
if not issubclass(cls, gitlab.mixins.GetWithoutIdMixin):
|
312
|
-
if cls._id_attr is not None:
|
321
|
+
if cls._id_attr is not None and custom_action.requires_id:
|
313
322
|
id_attr = cls._id_attr.replace("_", "-")
|
314
323
|
sub_parser_action.add_argument(f"--{id_attr}", required=True)
|
315
324
|
|
316
|
-
|
317
|
-
for x in required:
|
325
|
+
for x in custom_action.required:
|
318
326
|
if x != cls._id_attr:
|
319
327
|
sub_parser_action.add_argument(
|
320
328
|
f"--{x.replace('_', '-')}", required=True
|
321
329
|
)
|
322
|
-
for x in optional:
|
330
|
+
for x in custom_action.optional:
|
323
331
|
if x != cls._id_attr:
|
324
332
|
sub_parser_action.add_argument(
|
325
333
|
f"--{x.replace('_', '-')}", required=False
|
@@ -342,13 +350,13 @@ def _populate_sub_parser_by_class(
|
|
342
350
|
)
|
343
351
|
sub_parser_action.add_argument("--sudo", required=False)
|
344
352
|
|
345
|
-
|
346
|
-
for x in required:
|
353
|
+
custom_action = cli.custom_actions[name][action_name]
|
354
|
+
for x in custom_action.required:
|
347
355
|
if x != cls._id_attr:
|
348
356
|
sub_parser_action.add_argument(
|
349
357
|
f"--{x.replace('_', '-')}", required=True
|
350
358
|
)
|
351
|
-
for x in optional:
|
359
|
+
for x in custom_action.optional:
|
352
360
|
if x != cls._id_attr:
|
353
361
|
sub_parser_action.add_argument(
|
354
362
|
f"--{x.replace('_', '-')}", required=False
|
@@ -374,8 +382,12 @@ def extend_parser(parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
|
|
374
382
|
|
375
383
|
for cls in sorted(classes, key=operator.attrgetter("__name__")):
|
376
384
|
arg_name = cli.cls_to_gitlab_resource(cls)
|
385
|
+
mgr_cls_name = f"{cls.__name__}Manager"
|
386
|
+
mgr_cls = getattr(gitlab.v4.objects, mgr_cls_name)
|
377
387
|
object_group = subparsers.add_parser(
|
378
|
-
arg_name,
|
388
|
+
arg_name,
|
389
|
+
formatter_class=cli.VerticalHelpFormatter,
|
390
|
+
help=f"API endpoint: {mgr_cls._path}",
|
379
391
|
)
|
380
392
|
|
381
393
|
object_subparsers = object_group.add_subparsers(
|
gitlab/v4/objects/__init__.py
CHANGED
gitlab/v4/objects/artifacts.py
CHANGED
@@ -44,7 +44,9 @@ class ProjectArtifactManager(RESTManager):
|
|
44
44
|
self.gitlab.http_delete(path, **kwargs)
|
45
45
|
|
46
46
|
@cli.register_custom_action(
|
47
|
-
"ProjectArtifactManager",
|
47
|
+
cls_names="ProjectArtifactManager",
|
48
|
+
required=("ref_name", "job"),
|
49
|
+
optional=("job_token",),
|
48
50
|
)
|
49
51
|
@exc.on_http_error(exc.GitlabGetError)
|
50
52
|
def download(
|
@@ -93,7 +95,8 @@ class ProjectArtifactManager(RESTManager):
|
|
93
95
|
)
|
94
96
|
|
95
97
|
@cli.register_custom_action(
|
96
|
-
"ProjectArtifactManager",
|
98
|
+
cls_names="ProjectArtifactManager",
|
99
|
+
required=("ref_name", "artifact_path", "job"),
|
97
100
|
)
|
98
101
|
@exc.on_http_error(exc.GitlabGetError)
|
99
102
|
def raw(
|
gitlab/v4/objects/ci_lint.py
CHANGED
@@ -31,8 +31,8 @@ class CiLintManager(CreateMixin, RESTManager):
|
|
31
31
|
)
|
32
32
|
|
33
33
|
@register_custom_action(
|
34
|
-
"CiLintManager",
|
35
|
-
("content",),
|
34
|
+
cls_names="CiLintManager",
|
35
|
+
required=("content",),
|
36
36
|
optional=("include_merged_yaml", "include_jobs"),
|
37
37
|
)
|
38
38
|
def validate(self, *args: Any, **kwargs: Any) -> None:
|
@@ -63,8 +63,8 @@ class ProjectCiLintManager(GetWithoutIdMixin, CreateMixin, RESTManager):
|
|
63
63
|
return cast(ProjectCiLint, super().get(**kwargs))
|
64
64
|
|
65
65
|
@register_custom_action(
|
66
|
-
"ProjectCiLintManager",
|
67
|
-
("content",),
|
66
|
+
cls_names="ProjectCiLintManager",
|
67
|
+
required=("content",),
|
68
68
|
optional=("dry_run", "include_jobs", "ref"),
|
69
69
|
)
|
70
70
|
def validate(self, *args: Any, **kwargs: Any) -> None:
|
gitlab/v4/objects/commits.py
CHANGED
@@ -28,7 +28,7 @@ class ProjectCommit(RESTObject):
|
|
28
28
|
discussions: ProjectCommitDiscussionManager
|
29
29
|
statuses: "ProjectCommitStatusManager"
|
30
30
|
|
31
|
-
@cli.register_custom_action("ProjectCommit")
|
31
|
+
@cli.register_custom_action(cls_names="ProjectCommit")
|
32
32
|
@exc.on_http_error(exc.GitlabGetError)
|
33
33
|
def diff(self, **kwargs: Any) -> Union[gitlab.GitlabList, List[Dict[str, Any]]]:
|
34
34
|
"""Generate the commit diff.
|
@@ -46,7 +46,7 @@ class ProjectCommit(RESTObject):
|
|
46
46
|
path = f"{self.manager.path}/{self.encoded_id}/diff"
|
47
47
|
return self.manager.gitlab.http_list(path, **kwargs)
|
48
48
|
|
49
|
-
@cli.register_custom_action("ProjectCommit", ("branch",))
|
49
|
+
@cli.register_custom_action(cls_names="ProjectCommit", required=("branch",))
|
50
50
|
@exc.on_http_error(exc.GitlabCherryPickError)
|
51
51
|
def cherry_pick(self, branch: str, **kwargs: Any) -> None:
|
52
52
|
"""Cherry-pick a commit into a branch.
|
@@ -63,7 +63,7 @@ class ProjectCommit(RESTObject):
|
|
63
63
|
post_data = {"branch": branch}
|
64
64
|
self.manager.gitlab.http_post(path, post_data=post_data, **kwargs)
|
65
65
|
|
66
|
-
@cli.register_custom_action("ProjectCommit", optional=("type",))
|
66
|
+
@cli.register_custom_action(cls_names="ProjectCommit", optional=("type",))
|
67
67
|
@exc.on_http_error(exc.GitlabGetError)
|
68
68
|
def refs(
|
69
69
|
self, type: str = "all", **kwargs: Any
|
@@ -85,7 +85,7 @@ class ProjectCommit(RESTObject):
|
|
85
85
|
query_data = {"type": type}
|
86
86
|
return self.manager.gitlab.http_list(path, query_data=query_data, **kwargs)
|
87
87
|
|
88
|
-
@cli.register_custom_action("ProjectCommit")
|
88
|
+
@cli.register_custom_action(cls_names="ProjectCommit")
|
89
89
|
@exc.on_http_error(exc.GitlabGetError)
|
90
90
|
def merge_requests(
|
91
91
|
self, **kwargs: Any
|
@@ -105,7 +105,7 @@ class ProjectCommit(RESTObject):
|
|
105
105
|
path = f"{self.manager.path}/{self.encoded_id}/merge_requests"
|
106
106
|
return self.manager.gitlab.http_list(path, **kwargs)
|
107
107
|
|
108
|
-
@cli.register_custom_action("ProjectCommit", ("branch",))
|
108
|
+
@cli.register_custom_action(cls_names="ProjectCommit", required=("branch",))
|
109
109
|
@exc.on_http_error(exc.GitlabRevertError)
|
110
110
|
def revert(
|
111
111
|
self, branch: str, **kwargs: Any
|
@@ -127,7 +127,7 @@ class ProjectCommit(RESTObject):
|
|
127
127
|
post_data = {"branch": branch}
|
128
128
|
return self.manager.gitlab.http_post(path, post_data=post_data, **kwargs)
|
129
129
|
|
130
|
-
@cli.register_custom_action("ProjectCommit")
|
130
|
+
@cli.register_custom_action(cls_names="ProjectCommit")
|
131
131
|
@exc.on_http_error(exc.GitlabGetError)
|
132
132
|
def signature(self, **kwargs: Any) -> Union[Dict[str, Any], requests.Response]:
|
133
133
|
"""Get the signature of the commit.
|
@@ -42,8 +42,8 @@ class ProjectRegistryTagManager(DeleteMixin, RetrieveMixin, RESTManager):
|
|
42
42
|
_path = "/projects/{project_id}/registry/repositories/{repository_id}/tags"
|
43
43
|
|
44
44
|
@cli.register_custom_action(
|
45
|
-
"ProjectRegistryTagManager",
|
46
|
-
("name_regex_delete",),
|
45
|
+
cls_names="ProjectRegistryTagManager",
|
46
|
+
required=("name_regex_delete",),
|
47
47
|
optional=("keep_n", "name_regex_keep", "older_than"),
|
48
48
|
)
|
49
49
|
@exc.on_http_error(exc.GitlabDeleteError)
|
gitlab/v4/objects/deploy_keys.py
CHANGED
@@ -36,7 +36,9 @@ class ProjectKeyManager(CRUDMixin, RESTManager):
|
|
36
36
|
_create_attrs = RequiredOptional(required=("title", "key"), optional=("can_push",))
|
37
37
|
_update_attrs = RequiredOptional(optional=("title", "can_push"))
|
38
38
|
|
39
|
-
@cli.register_custom_action(
|
39
|
+
@cli.register_custom_action(
|
40
|
+
cls_names="ProjectKeyManager", required=("key_id",), requires_id=False
|
41
|
+
)
|
40
42
|
@exc.on_http_error(exc.GitlabProjectDeployKeyError)
|
41
43
|
def enable(
|
42
44
|
self, key_id: int, **kwargs: Any
|
gitlab/v4/objects/deployments.py
CHANGED
@@ -23,8 +23,8 @@ class ProjectDeployment(SaveMixin, RESTObject):
|
|
23
23
|
mergerequests: ProjectDeploymentMergeRequestManager
|
24
24
|
|
25
25
|
@cli.register_custom_action(
|
26
|
-
"ProjectDeployment",
|
27
|
-
|
26
|
+
cls_names="ProjectDeployment",
|
27
|
+
required=("status",),
|
28
28
|
optional=("comment", "represented_as"),
|
29
29
|
)
|
30
30
|
@exc.on_http_error(exc.GitlabDeploymentApprovalError)
|
@@ -24,7 +24,7 @@ __all__ = [
|
|
24
24
|
|
25
25
|
|
26
26
|
class ProjectEnvironment(SaveMixin, ObjectDeleteMixin, RESTObject):
|
27
|
-
@cli.register_custom_action("ProjectEnvironment")
|
27
|
+
@cli.register_custom_action(cls_names="ProjectEnvironment")
|
28
28
|
@exc.on_http_error(exc.GitlabStopError)
|
29
29
|
def stop(self, **kwargs: Any) -> Union[Dict[str, Any], requests.Response]:
|
30
30
|
"""Stop the environment.
|
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
|
|