summaryrefslogtreecommitdiff
path: root/gitlab/mixins.py
diff options
context:
space:
mode:
authorNejc Habjan <hab.nejc@gmail.com>2021-12-01 01:04:53 +0100
committerGitHub <noreply@github.com>2021-12-01 01:04:53 +0100
commit8d76826fa64460e504acc5924f859f8dbc246b42 (patch)
tree083fefada982c795e2415092794db429abb0c184 /gitlab/mixins.py
parent5a1678f43184bd459132102cc13cf8426fe0449d (diff)
parent86ab04e54ea4175f10053decfad5086cda7aa024 (diff)
downloadgitlab-master.tar.gz
Merge pull request #1723 from python-gitlab/jlvillal/dead_mastermaster
Close-out `master` branch
Diffstat (limited to 'gitlab/mixins.py')
-rw-r--r--gitlab/mixins.py928
1 files changed, 0 insertions, 928 deletions
diff --git a/gitlab/mixins.py b/gitlab/mixins.py
deleted file mode 100644
index 0c2cd94..0000000
--- a/gitlab/mixins.py
+++ /dev/null
@@ -1,928 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2013-2017 Gauvain Pocentek <gauvain@pocentek.net>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-from types import ModuleType
-from typing import (
- Any,
- Callable,
- Dict,
- List,
- Optional,
- Tuple,
- Type,
- TYPE_CHECKING,
- Union,
-)
-
-import requests
-
-import gitlab
-from gitlab import base, cli
-from gitlab import exceptions as exc
-from gitlab import types as g_types
-from gitlab import utils
-
-__all__ = [
- "GetMixin",
- "GetWithoutIdMixin",
- "RefreshMixin",
- "ListMixin",
- "RetrieveMixin",
- "CreateMixin",
- "UpdateMixin",
- "SetMixin",
- "DeleteMixin",
- "CRUDMixin",
- "NoUpdateMixin",
- "SaveMixin",
- "ObjectDeleteMixin",
- "UserAgentDetailMixin",
- "AccessRequestMixin",
- "DownloadMixin",
- "SubscribableMixin",
- "TodoMixin",
- "TimeTrackingMixin",
- "ParticipantsMixin",
- "BadgeRenderMixin",
-]
-
-if TYPE_CHECKING:
- # When running mypy we use these as the base classes
- _RestManagerBase = base.RESTManager
- _RestObjectBase = base.RESTObject
-else:
- _RestManagerBase = object
- _RestObjectBase = object
-
-
-class GetMixin(_RestManagerBase):
- _computed_path: Optional[str]
- _from_parent_attrs: Dict[str, Any]
- _obj_cls: Optional[Type[base.RESTObject]]
- _optional_get_attrs: Tuple[str, ...] = ()
- _parent: Optional[base.RESTObject]
- _parent_attrs: Dict[str, Any]
- _path: Optional[str]
- gitlab: gitlab.Gitlab
-
- @exc.on_http_error(exc.GitlabGetError)
- def get(
- self, id: Union[str, int], lazy: bool = False, **kwargs: Any
- ) -> base.RESTObject:
- """Retrieve a single object.
-
- Args:
- id (int or str): ID of the object to retrieve
- lazy (bool): If True, don't request the server, but create a
- shallow object giving access to the managers. This is
- useful if you want to avoid useless calls to the API.
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Returns:
- object: The generated RESTObject.
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabGetError: If the server cannot perform the request
- """
- if not isinstance(id, int):
- id = utils.clean_str_id(id)
- path = "%s/%s" % (self.path, id)
- if TYPE_CHECKING:
- assert self._obj_cls is not None
- if lazy is True:
- if TYPE_CHECKING:
- assert self._obj_cls._id_attr is not None
- return self._obj_cls(self, {self._obj_cls._id_attr: id})
- server_data = self.gitlab.http_get(path, **kwargs)
- if TYPE_CHECKING:
- assert not isinstance(server_data, requests.Response)
- return self._obj_cls(self, server_data)
-
-
-class GetWithoutIdMixin(_RestManagerBase):
- _computed_path: Optional[str]
- _from_parent_attrs: Dict[str, Any]
- _obj_cls: Optional[Type[base.RESTObject]]
- _optional_get_attrs: Tuple[str, ...] = ()
- _parent: Optional[base.RESTObject]
- _parent_attrs: Dict[str, Any]
- _path: Optional[str]
- gitlab: gitlab.Gitlab
-
- @exc.on_http_error(exc.GitlabGetError)
- def get(
- self, id: Optional[Union[int, str]] = None, **kwargs: Any
- ) -> Optional[base.RESTObject]:
- """Retrieve a single object.
-
- Args:
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Returns:
- object: The generated RESTObject
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabGetError: If the server cannot perform the request
- """
- if TYPE_CHECKING:
- assert self.path is not None
- server_data = self.gitlab.http_get(self.path, **kwargs)
- if server_data is None:
- return None
- if TYPE_CHECKING:
- assert not isinstance(server_data, requests.Response)
- assert self._obj_cls is not None
- return self._obj_cls(self, server_data)
-
-
-class RefreshMixin(_RestObjectBase):
- _id_attr: Optional[str]
- _attrs: Dict[str, Any]
- _module: ModuleType
- _parent_attrs: Dict[str, Any]
- _updated_attrs: Dict[str, Any]
- manager: base.RESTManager
-
- @exc.on_http_error(exc.GitlabGetError)
- def refresh(self, **kwargs: Any) -> None:
- """Refresh a single object from server.
-
- Args:
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Returns None (updates the object)
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabGetError: If the server cannot perform the request
- """
- if self._id_attr:
- path = "%s/%s" % (self.manager.path, self.id)
- else:
- if TYPE_CHECKING:
- assert self.manager.path is not None
- path = self.manager.path
- server_data = self.manager.gitlab.http_get(path, **kwargs)
- if TYPE_CHECKING:
- assert not isinstance(server_data, requests.Response)
- self._update_attrs(server_data)
-
-
-class ListMixin(_RestManagerBase):
- _computed_path: Optional[str]
- _from_parent_attrs: Dict[str, Any]
- _list_filters: Tuple[str, ...] = ()
- _obj_cls: Optional[Type[base.RESTObject]]
- _parent: Optional[base.RESTObject]
- _parent_attrs: Dict[str, Any]
- _path: Optional[str]
- gitlab: gitlab.Gitlab
-
- @exc.on_http_error(exc.GitlabListError)
- def list(self, **kwargs: Any) -> Union[base.RESTObjectList, List[base.RESTObject]]:
- """Retrieve a list of objects.
-
- Args:
- all (bool): If True, return all the items, without pagination
- per_page (int): Number of items to retrieve per request
- page (int): ID of the page to return (starts with page 1)
- as_list (bool): If set to False and no pagination option is
- defined, return a generator instead of a list
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Returns:
- list: The list of objects, or a generator if `as_list` is False
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabListError: If the server cannot perform the request
- """
-
- # Duplicate data to avoid messing with what the user sent us
- data = kwargs.copy()
- if self.gitlab.per_page:
- data.setdefault("per_page", self.gitlab.per_page)
-
- # global keyset pagination
- if self.gitlab.pagination:
- data.setdefault("pagination", self.gitlab.pagination)
-
- if self.gitlab.order_by:
- data.setdefault("order_by", self.gitlab.order_by)
-
- # We get the attributes that need some special transformation
- if self._types:
- for attr_name, type_cls in self._types.items():
- if attr_name in data.keys():
- type_obj = type_cls(data[attr_name])
- data[attr_name] = type_obj.get_for_api()
-
- # Allow to overwrite the path, handy for custom listings
- path = data.pop("path", self.path)
-
- if TYPE_CHECKING:
- assert self._obj_cls is not None
- obj = self.gitlab.http_list(path, **data)
- if isinstance(obj, list):
- return [self._obj_cls(self, item) for item in obj]
- else:
- return base.RESTObjectList(self, self._obj_cls, obj)
-
-
-class RetrieveMixin(ListMixin, GetMixin):
- _computed_path: Optional[str]
- _from_parent_attrs: Dict[str, Any]
- _obj_cls: Optional[Type[base.RESTObject]]
- _parent: Optional[base.RESTObject]
- _parent_attrs: Dict[str, Any]
- _path: Optional[str]
- gitlab: gitlab.Gitlab
-
- pass
-
-
-class CreateMixin(_RestManagerBase):
- _computed_path: Optional[str]
- _from_parent_attrs: Dict[str, Any]
- _obj_cls: Optional[Type[base.RESTObject]]
- _parent: Optional[base.RESTObject]
- _parent_attrs: Dict[str, Any]
- _path: Optional[str]
- gitlab: gitlab.Gitlab
-
- def _check_missing_create_attrs(self, data: Dict[str, Any]) -> None:
- missing = []
- for attr in self._create_attrs.required:
- if attr not in data:
- missing.append(attr)
- continue
- if missing:
- raise AttributeError("Missing attributes: %s" % ", ".join(missing))
-
- @exc.on_http_error(exc.GitlabCreateError)
- def create(
- self, data: Optional[Dict[str, Any]] = None, **kwargs: Any
- ) -> base.RESTObject:
- """Create a new object.
-
- Args:
- data (dict): parameters to send to the server to create the
- resource
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Returns:
- RESTObject: a new instance of the managed object class built with
- the data sent by the server
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabCreateError: If the server cannot perform the request
- """
- if data is None:
- data = {}
-
- self._check_missing_create_attrs(data)
- files = {}
-
- # We get the attributes that need some special transformation
- if self._types:
- # Duplicate data to avoid messing with what the user sent us
- data = data.copy()
- for attr_name, type_cls in self._types.items():
- if attr_name in data.keys():
- type_obj = type_cls(data[attr_name])
-
- # if the type if FileAttribute we need to pass the data as
- # file
- if isinstance(type_obj, g_types.FileAttribute):
- k = type_obj.get_file_name(attr_name)
- files[attr_name] = (k, data.pop(attr_name))
- else:
- data[attr_name] = type_obj.get_for_api()
-
- # Handle specific URL for creation
- path = kwargs.pop("path", self.path)
- server_data = self.gitlab.http_post(path, post_data=data, files=files, **kwargs)
- if TYPE_CHECKING:
- assert not isinstance(server_data, requests.Response)
- assert self._obj_cls is not None
- return self._obj_cls(self, server_data)
-
-
-class UpdateMixin(_RestManagerBase):
- _computed_path: Optional[str]
- _from_parent_attrs: Dict[str, Any]
- _obj_cls: Optional[Type[base.RESTObject]]
- _parent: Optional[base.RESTObject]
- _parent_attrs: Dict[str, Any]
- _path: Optional[str]
- _update_uses_post: bool = False
- gitlab: gitlab.Gitlab
-
- def _check_missing_update_attrs(self, data: Dict[str, Any]) -> None:
- if TYPE_CHECKING:
- assert self._obj_cls is not None
- # Remove the id field from the required list as it was previously moved
- # to the http path.
- required = tuple(
- [k for k in self._update_attrs.required if k != self._obj_cls._id_attr]
- )
- missing = []
- for attr in required:
- if attr not in data:
- missing.append(attr)
- continue
- if missing:
- raise AttributeError("Missing attributes: %s" % ", ".join(missing))
-
- def _get_update_method(
- self,
- ) -> Callable[..., Union[Dict[str, Any], requests.Response]]:
- """Return the HTTP method to use.
-
- Returns:
- object: http_put (default) or http_post
- """
- if self._update_uses_post:
- http_method = self.gitlab.http_post
- else:
- http_method = self.gitlab.http_put
- return http_method
-
- @exc.on_http_error(exc.GitlabUpdateError)
- def update(
- self,
- id: Optional[Union[str, int]] = None,
- new_data: Optional[Dict[str, Any]] = None,
- **kwargs: Any
- ) -> Dict[str, Any]:
- """Update an object on the server.
-
- Args:
- id: ID of the object to update (can be None if not required)
- new_data: the update data for the object
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Returns:
- dict: The new object data (*not* a RESTObject)
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabUpdateError: If the server cannot perform the request
- """
- new_data = new_data or {}
-
- if id is None:
- path = self.path
- else:
- path = "%s/%s" % (self.path, id)
-
- self._check_missing_update_attrs(new_data)
- files = {}
-
- # We get the attributes that need some special transformation
- if self._types:
- # Duplicate data to avoid messing with what the user sent us
- new_data = new_data.copy()
- for attr_name, type_cls in self._types.items():
- if attr_name in new_data.keys():
- type_obj = type_cls(new_data[attr_name])
-
- # if the type if FileAttribute we need to pass the data as
- # file
- if isinstance(type_obj, g_types.FileAttribute):
- k = type_obj.get_file_name(attr_name)
- files[attr_name] = (k, new_data.pop(attr_name))
- else:
- new_data[attr_name] = type_obj.get_for_api()
-
- http_method = self._get_update_method()
- result = http_method(path, post_data=new_data, files=files, **kwargs)
- if TYPE_CHECKING:
- assert not isinstance(result, requests.Response)
- return result
-
-
-class SetMixin(_RestManagerBase):
- _computed_path: Optional[str]
- _from_parent_attrs: Dict[str, Any]
- _obj_cls: Optional[Type[base.RESTObject]]
- _parent: Optional[base.RESTObject]
- _parent_attrs: Dict[str, Any]
- _path: Optional[str]
- gitlab: gitlab.Gitlab
-
- @exc.on_http_error(exc.GitlabSetError)
- def set(self, key: str, value: str, **kwargs: Any) -> base.RESTObject:
- """Create or update the object.
-
- Args:
- key (str): The key of the object to create/update
- value (str): The value to set for the object
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabSetError: If an error occurred
-
- Returns:
- obj: The created/updated attribute
- """
- path = "%s/%s" % (self.path, utils.clean_str_id(key))
- data = {"value": value}
- server_data = self.gitlab.http_put(path, post_data=data, **kwargs)
- if TYPE_CHECKING:
- assert not isinstance(server_data, requests.Response)
- assert self._obj_cls is not None
- return self._obj_cls(self, server_data)
-
-
-class DeleteMixin(_RestManagerBase):
- _computed_path: Optional[str]
- _from_parent_attrs: Dict[str, Any]
- _obj_cls: Optional[Type[base.RESTObject]]
- _parent: Optional[base.RESTObject]
- _parent_attrs: Dict[str, Any]
- _path: Optional[str]
- gitlab: gitlab.Gitlab
-
- @exc.on_http_error(exc.GitlabDeleteError)
- def delete(self, id: Union[str, int], **kwargs: Any) -> None:
- """Delete an object on the server.
-
- Args:
- id: ID of the object to delete
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabDeleteError: If the server cannot perform the request
- """
- if id is None:
- path = self.path
- else:
- if not isinstance(id, int):
- id = utils.clean_str_id(id)
- path = "%s/%s" % (self.path, id)
- self.gitlab.http_delete(path, **kwargs)
-
-
-class CRUDMixin(GetMixin, ListMixin, CreateMixin, UpdateMixin, DeleteMixin):
- _computed_path: Optional[str]
- _from_parent_attrs: Dict[str, Any]
- _obj_cls: Optional[Type[base.RESTObject]]
- _parent: Optional[base.RESTObject]
- _parent_attrs: Dict[str, Any]
- _path: Optional[str]
- gitlab: gitlab.Gitlab
-
- pass
-
-
-class NoUpdateMixin(GetMixin, ListMixin, CreateMixin, DeleteMixin):
- _computed_path: Optional[str]
- _from_parent_attrs: Dict[str, Any]
- _obj_cls: Optional[Type[base.RESTObject]]
- _parent: Optional[base.RESTObject]
- _parent_attrs: Dict[str, Any]
- _path: Optional[str]
- gitlab: gitlab.Gitlab
-
- pass
-
-
-class SaveMixin(_RestObjectBase):
- """Mixin for RESTObject's that can be updated."""
-
- _id_attr: Optional[str]
- _attrs: Dict[str, Any]
- _module: ModuleType
- _parent_attrs: Dict[str, Any]
- _updated_attrs: Dict[str, Any]
- manager: base.RESTManager
-
- def _get_updated_data(self) -> Dict[str, Any]:
- updated_data = {}
- for attr in self.manager._update_attrs.required:
- # Get everything required, no matter if it's been updated
- updated_data[attr] = getattr(self, attr)
- # Add the updated attributes
- updated_data.update(self._updated_attrs)
-
- return updated_data
-
- def save(self, **kwargs: Any) -> None:
- """Save the changes made to the object to the server.
-
- The object is updated to match what the server returns.
-
- Args:
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Raise:
- GitlabAuthenticationError: If authentication is not correct
- GitlabUpdateError: If the server cannot perform the request
- """
- updated_data = self._get_updated_data()
- # Nothing to update. Server fails if sent an empty dict.
- if not updated_data:
- return
-
- # call the manager
- obj_id = self.get_id()
- if TYPE_CHECKING:
- assert isinstance(self.manager, UpdateMixin)
- server_data = self.manager.update(obj_id, updated_data, **kwargs)
- if server_data is not None:
- self._update_attrs(server_data)
-
-
-class ObjectDeleteMixin(_RestObjectBase):
- """Mixin for RESTObject's that can be deleted."""
-
- _id_attr: Optional[str]
- _attrs: Dict[str, Any]
- _module: ModuleType
- _parent_attrs: Dict[str, Any]
- _updated_attrs: Dict[str, Any]
- manager: base.RESTManager
-
- def delete(self, **kwargs: Any) -> None:
- """Delete the object from the server.
-
- Args:
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabDeleteError: If the server cannot perform the request
- """
- if TYPE_CHECKING:
- assert isinstance(self.manager, DeleteMixin)
- self.manager.delete(self.get_id(), **kwargs)
-
-
-class UserAgentDetailMixin(_RestObjectBase):
- _id_attr: Optional[str]
- _attrs: Dict[str, Any]
- _module: ModuleType
- _parent_attrs: Dict[str, Any]
- _updated_attrs: Dict[str, Any]
- manager: base.RESTManager
-
- @cli.register_custom_action(("Snippet", "ProjectSnippet", "ProjectIssue"))
- @exc.on_http_error(exc.GitlabGetError)
- def user_agent_detail(self, **kwargs: Any) -> Dict[str, Any]:
- """Get the user agent detail.
-
- Args:
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabGetError: If the server cannot perform the request
- """
- path = "%s/%s/user_agent_detail" % (self.manager.path, self.get_id())
- result = self.manager.gitlab.http_get(path, **kwargs)
- if TYPE_CHECKING:
- assert not isinstance(result, requests.Response)
- return result
-
-
-class AccessRequestMixin(_RestObjectBase):
- _id_attr: Optional[str]
- _attrs: Dict[str, Any]
- _module: ModuleType
- _parent_attrs: Dict[str, Any]
- _updated_attrs: Dict[str, Any]
- manager: base.RESTManager
-
- @cli.register_custom_action(
- ("ProjectAccessRequest", "GroupAccessRequest"), tuple(), ("access_level",)
- )
- @exc.on_http_error(exc.GitlabUpdateError)
- def approve(
- self, access_level: int = gitlab.DEVELOPER_ACCESS, **kwargs: Any
- ) -> None:
- """Approve an access request.
-
- Args:
- access_level (int): The access level for the user
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabUpdateError: If the server fails to perform the request
- """
-
- path = "%s/%s/approve" % (self.manager.path, self.id)
- data = {"access_level": access_level}
- server_data = self.manager.gitlab.http_put(path, post_data=data, **kwargs)
- if TYPE_CHECKING:
- assert not isinstance(server_data, requests.Response)
- self._update_attrs(server_data)
-
-
-class DownloadMixin(_RestObjectBase):
- _id_attr: Optional[str]
- _attrs: Dict[str, Any]
- _module: ModuleType
- _parent_attrs: Dict[str, Any]
- _updated_attrs: Dict[str, Any]
- manager: base.RESTManager
-
- @cli.register_custom_action(("GroupExport", "ProjectExport"))
- @exc.on_http_error(exc.GitlabGetError)
- def download(
- self,
- streamed: bool = False,
- action: Optional[Callable] = None,
- chunk_size: int = 1024,
- **kwargs: Any
- ) -> Optional[bytes]:
- """Download the archive of a resource export.
-
- Args:
- streamed (bool): If True the data will be processed by chunks of
- `chunk_size` and each chunk is passed to `action` for
- treatment
- action (callable): Callable responsible of dealing with chunk of
- data
- chunk_size (int): Size of each chunk
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabGetError: If the server failed to perform the request
-
- Returns:
- str: The blob content if streamed is False, None otherwise
- """
- path = "%s/download" % (self.manager.path)
- result = self.manager.gitlab.http_get(
- path, streamed=streamed, raw=True, **kwargs
- )
- if TYPE_CHECKING:
- assert isinstance(result, requests.Response)
- return utils.response_content(result, streamed, action, chunk_size)
-
-
-class SubscribableMixin(_RestObjectBase):
- _id_attr: Optional[str]
- _attrs: Dict[str, Any]
- _module: ModuleType
- _parent_attrs: Dict[str, Any]
- _updated_attrs: Dict[str, Any]
- manager: base.RESTManager
-
- @cli.register_custom_action(
- ("ProjectIssue", "ProjectMergeRequest", "ProjectLabel", "GroupLabel")
- )
- @exc.on_http_error(exc.GitlabSubscribeError)
- def subscribe(self, **kwargs: Any) -> None:
- """Subscribe to the object notifications.
-
- Args:
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabSubscribeError: If the subscription cannot be done
- """
- path = "%s/%s/subscribe" % (self.manager.path, self.get_id())
- server_data = self.manager.gitlab.http_post(path, **kwargs)
- if TYPE_CHECKING:
- assert not isinstance(server_data, requests.Response)
- self._update_attrs(server_data)
-
- @cli.register_custom_action(
- ("ProjectIssue", "ProjectMergeRequest", "ProjectLabel", "GroupLabel")
- )
- @exc.on_http_error(exc.GitlabUnsubscribeError)
- def unsubscribe(self, **kwargs: Any) -> None:
- """Unsubscribe from the object notifications.
-
- Args:
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabUnsubscribeError: If the unsubscription cannot be done
- """
- path = "%s/%s/unsubscribe" % (self.manager.path, self.get_id())
- server_data = self.manager.gitlab.http_post(path, **kwargs)
- if TYPE_CHECKING:
- assert not isinstance(server_data, requests.Response)
- self._update_attrs(server_data)
-
-
-class TodoMixin(_RestObjectBase):
- _id_attr: Optional[str]
- _attrs: Dict[str, Any]
- _module: ModuleType
- _parent_attrs: Dict[str, Any]
- _updated_attrs: Dict[str, Any]
- manager: base.RESTManager
-
- @cli.register_custom_action(("ProjectIssue", "ProjectMergeRequest"))
- @exc.on_http_error(exc.GitlabTodoError)
- def todo(self, **kwargs: Any) -> None:
- """Create a todo associated to the object.
-
- Args:
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabTodoError: If the todo cannot be set
- """
- path = "%s/%s/todo" % (self.manager.path, self.get_id())
- self.manager.gitlab.http_post(path, **kwargs)
-
-
-class TimeTrackingMixin(_RestObjectBase):
- _id_attr: Optional[str]
- _attrs: Dict[str, Any]
- _module: ModuleType
- _parent_attrs: Dict[str, Any]
- _updated_attrs: Dict[str, Any]
- manager: base.RESTManager
-
- @cli.register_custom_action(("ProjectIssue", "ProjectMergeRequest"))
- @exc.on_http_error(exc.GitlabTimeTrackingError)
- def time_stats(self, **kwargs: Any) -> Dict[str, Any]:
- """Get time stats for the object.
-
- Args:
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabTimeTrackingError: If the time tracking update cannot be done
- """
- # Use the existing time_stats attribute if it exist, otherwise make an
- # API call
- if "time_stats" in self.attributes:
- return self.attributes["time_stats"]
-
- path = "%s/%s/time_stats" % (self.manager.path, self.get_id())
- result = self.manager.gitlab.http_get(path, **kwargs)
- if TYPE_CHECKING:
- assert not isinstance(result, requests.Response)
- return result
-
- @cli.register_custom_action(("ProjectIssue", "ProjectMergeRequest"), ("duration",))
- @exc.on_http_error(exc.GitlabTimeTrackingError)
- def time_estimate(self, duration: str, **kwargs: Any) -> Dict[str, Any]:
- """Set an estimated time of work for the object.
-
- Args:
- duration (str): Duration in human format (e.g. 3h30)
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabTimeTrackingError: If the time tracking update cannot be done
- """
- path = "%s/%s/time_estimate" % (self.manager.path, self.get_id())
- data = {"duration": duration}
- result = self.manager.gitlab.http_post(path, post_data=data, **kwargs)
- if TYPE_CHECKING:
- assert not isinstance(result, requests.Response)
- return result
-
- @cli.register_custom_action(("ProjectIssue", "ProjectMergeRequest"))
- @exc.on_http_error(exc.GitlabTimeTrackingError)
- def reset_time_estimate(self, **kwargs: Any) -> Dict[str, Any]:
- """Resets estimated time for the object to 0 seconds.
-
- Args:
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabTimeTrackingError: If the time tracking update cannot be done
- """
- path = "%s/%s/reset_time_estimate" % (self.manager.path, self.get_id())
- result = self.manager.gitlab.http_post(path, **kwargs)
- if TYPE_CHECKING:
- assert not isinstance(result, requests.Response)
- return result
-
- @cli.register_custom_action(("ProjectIssue", "ProjectMergeRequest"), ("duration",))
- @exc.on_http_error(exc.GitlabTimeTrackingError)
- def add_spent_time(self, duration: str, **kwargs: Any) -> Dict[str, Any]:
- """Add time spent working on the object.
-
- Args:
- duration (str): Duration in human format (e.g. 3h30)
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabTimeTrackingError: If the time tracking update cannot be done
- """
- path = "%s/%s/add_spent_time" % (self.manager.path, self.get_id())
- data = {"duration": duration}
- result = self.manager.gitlab.http_post(path, post_data=data, **kwargs)
- if TYPE_CHECKING:
- assert not isinstance(result, requests.Response)
- return result
-
- @cli.register_custom_action(("ProjectIssue", "ProjectMergeRequest"))
- @exc.on_http_error(exc.GitlabTimeTrackingError)
- def reset_spent_time(self, **kwargs: Any) -> Dict[str, Any]:
- """Resets the time spent working on the object.
-
- Args:
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabTimeTrackingError: If the time tracking update cannot be done
- """
- path = "%s/%s/reset_spent_time" % (self.manager.path, self.get_id())
- result = self.manager.gitlab.http_post(path, **kwargs)
- if TYPE_CHECKING:
- assert not isinstance(result, requests.Response)
- return result
-
-
-class ParticipantsMixin(_RestObjectBase):
- _id_attr: Optional[str]
- _attrs: Dict[str, Any]
- _module: ModuleType
- _parent_attrs: Dict[str, Any]
- _updated_attrs: Dict[str, Any]
- manager: base.RESTManager
-
- @cli.register_custom_action(("ProjectMergeRequest", "ProjectIssue"))
- @exc.on_http_error(exc.GitlabListError)
- def participants(self, **kwargs: Any) -> Dict[str, Any]:
- """List the participants.
-
- Args:
- all (bool): If True, return all the items, without pagination
- per_page (int): Number of items to retrieve per request
- page (int): ID of the page to return (starts with page 1)
- as_list (bool): If set to False and no pagination option is
- defined, return a generator instead of a list
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabListError: If the list could not be retrieved
-
- Returns:
- RESTObjectList: The list of participants
- """
-
- path = "%s/%s/participants" % (self.manager.path, self.get_id())
- result = self.manager.gitlab.http_get(path, **kwargs)
- if TYPE_CHECKING:
- assert not isinstance(result, requests.Response)
- return result
-
-
-class BadgeRenderMixin(_RestManagerBase):
- @cli.register_custom_action(
- ("GroupBadgeManager", "ProjectBadgeManager"), ("link_url", "image_url")
- )
- @exc.on_http_error(exc.GitlabRenderError)
- def render(self, link_url: str, image_url: str, **kwargs: Any) -> Dict[str, Any]:
- """Preview link_url and image_url after interpolation.
-
- Args:
- link_url (str): URL of the badge link
- image_url (str): URL of the badge image
- **kwargs: Extra options to send to the server (e.g. sudo)
-
- Raises:
- GitlabAuthenticationError: If authentication is not correct
- GitlabRenderError: If the rendering failed
-
- Returns:
- dict: The rendering properties
- """
- path = "%s/render" % self.path
- data = {"link_url": link_url, "image_url": image_url}
- result = self.gitlab.http_get(path, data, **kwargs)
- if TYPE_CHECKING:
- assert not isinstance(result, requests.Response)
- return result