diff options
Diffstat (limited to 'gitlab/v4')
63 files changed, 0 insertions, 7992 deletions
diff --git a/gitlab/v4/__init__.py b/gitlab/v4/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/gitlab/v4/__init__.py +++ /dev/null diff --git a/gitlab/v4/cli.py b/gitlab/v4/cli.py deleted file mode 100644 index 6986552..0000000 --- a/gitlab/v4/cli.py +++ /dev/null @@ -1,500 +0,0 @@ -#!/usr/bin/env python -# -*- 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/>. - -import argparse -import operator -import sys -from typing import Any, Dict, List, Optional, Type, TYPE_CHECKING, Union - -import gitlab -import gitlab.base -import gitlab.v4.objects -from gitlab import cli - - -class GitlabCLI(object): - def __init__( - self, gl: gitlab.Gitlab, what: str, action: str, args: Dict[str, str] - ) -> None: - self.cls: Type[gitlab.base.RESTObject] = cli.what_to_cls( - what, namespace=gitlab.v4.objects - ) - self.cls_name = self.cls.__name__ - self.what = what.replace("-", "_") - self.action = action.lower() - self.gl = gl - self.args = args - self.mgr_cls: Union[ - Type[gitlab.mixins.CreateMixin], - Type[gitlab.mixins.DeleteMixin], - Type[gitlab.mixins.GetMixin], - Type[gitlab.mixins.GetWithoutIdMixin], - Type[gitlab.mixins.ListMixin], - Type[gitlab.mixins.UpdateMixin], - ] = getattr(gitlab.v4.objects, self.cls.__name__ + "Manager") - # We could do something smart, like splitting the manager name to find - # parents, build the chain of managers to get to the final object. - # Instead we do something ugly and efficient: interpolate variables in - # the class _path attribute, and replace the value with the result. - if TYPE_CHECKING: - assert self.mgr_cls._path is not None - self.mgr_cls._path = self.mgr_cls._path % self.args - self.mgr = self.mgr_cls(gl) - - if self.mgr_cls._types: - for attr_name, type_cls in self.mgr_cls._types.items(): - if attr_name in self.args.keys(): - obj = type_cls() - obj.set_from_cli(self.args[attr_name]) - self.args[attr_name] = obj.get() - - def __call__(self) -> Any: - # Check for a method that matches object + action - method = "do_%s_%s" % (self.what, self.action) - if hasattr(self, method): - return getattr(self, method)() - - # Fallback to standard actions (get, list, create, ...) - method = "do_%s" % self.action - if hasattr(self, method): - return getattr(self, method)() - - # Finally try to find custom methods - return self.do_custom() - - def do_custom(self) -> Any: - in_obj = cli.custom_actions[self.cls_name][self.action][2] - - # Get the object (lazy), then act - if in_obj: - data = {} - if self.mgr._from_parent_attrs: - for k in self.mgr._from_parent_attrs: - data[k] = self.args[k] - if not issubclass(self.cls, gitlab.mixins.GetWithoutIdMixin): - if TYPE_CHECKING: - assert isinstance(self.cls._id_attr, str) - data[self.cls._id_attr] = self.args.pop(self.cls._id_attr) - obj = self.cls(self.mgr, data) - method_name = self.action.replace("-", "_") - return getattr(obj, method_name)(**self.args) - else: - return getattr(self.mgr, self.action)(**self.args) - - def do_project_export_download(self) -> None: - try: - project = self.gl.projects.get(int(self.args["project_id"]), lazy=True) - export_status = project.exports.get() - if TYPE_CHECKING: - assert export_status is not None - data = export_status.download() - sys.stdout.buffer.write(data) - - except Exception as e: - cli.die("Impossible to download the export", e) - - def do_create(self) -> gitlab.base.RESTObject: - if TYPE_CHECKING: - assert isinstance(self.mgr, gitlab.mixins.CreateMixin) - try: - result = self.mgr.create(self.args) - except Exception as e: - cli.die("Impossible to create object", e) - return result - - def do_list( - self, - ) -> Union[gitlab.base.RESTObjectList, List[gitlab.base.RESTObject]]: - if TYPE_CHECKING: - assert isinstance(self.mgr, gitlab.mixins.ListMixin) - try: - result = self.mgr.list(**self.args) - except Exception as e: - cli.die("Impossible to list objects", e) - return result - - def do_get(self) -> Optional[gitlab.base.RESTObject]: - if isinstance(self.mgr, gitlab.mixins.GetWithoutIdMixin): - try: - result = self.mgr.get(id=None, **self.args) - except Exception as e: - cli.die("Impossible to get object", e) - return result - - if TYPE_CHECKING: - assert isinstance(self.mgr, gitlab.mixins.GetMixin) - assert isinstance(self.cls._id_attr, str) - - id = self.args.pop(self.cls._id_attr) - try: - result = self.mgr.get(id, lazy=False, **self.args) - except Exception as e: - cli.die("Impossible to get object", e) - return result - - def do_delete(self) -> None: - if TYPE_CHECKING: - assert isinstance(self.mgr, gitlab.mixins.DeleteMixin) - assert isinstance(self.cls._id_attr, str) - id = self.args.pop(self.cls._id_attr) - try: - self.mgr.delete(id, **self.args) - except Exception as e: - cli.die("Impossible to destroy object", e) - - def do_update(self) -> Dict[str, Any]: - if TYPE_CHECKING: - assert isinstance(self.mgr, gitlab.mixins.UpdateMixin) - if issubclass(self.mgr_cls, gitlab.mixins.GetWithoutIdMixin): - id = None - else: - if TYPE_CHECKING: - assert isinstance(self.cls._id_attr, str) - id = self.args.pop(self.cls._id_attr) - - try: - result = self.mgr.update(id, self.args) - except Exception as e: - cli.die("Impossible to update object", e) - return result - - -def _populate_sub_parser_by_class( - cls: Type[gitlab.base.RESTObject], sub_parser: argparse._SubParsersAction -) -> None: - mgr_cls_name = cls.__name__ + "Manager" - mgr_cls = getattr(gitlab.v4.objects, mgr_cls_name) - - for action_name in ["list", "get", "create", "update", "delete"]: - if not hasattr(mgr_cls, action_name): - continue - - sub_parser_action = sub_parser.add_parser(action_name) - sub_parser_action.add_argument("--sudo", required=False) - if mgr_cls._from_parent_attrs: - for x in mgr_cls._from_parent_attrs: - sub_parser_action.add_argument( - "--%s" % x.replace("_", "-"), required=True - ) - - if action_name == "list": - for x in mgr_cls._list_filters: - sub_parser_action.add_argument( - "--%s" % x.replace("_", "-"), required=False - ) - - sub_parser_action.add_argument("--page", required=False) - sub_parser_action.add_argument("--per-page", required=False) - sub_parser_action.add_argument("--all", required=False, action="store_true") - - if action_name == "delete": - if cls._id_attr is not None: - id_attr = cls._id_attr.replace("_", "-") - sub_parser_action.add_argument("--%s" % id_attr, required=True) - - if action_name == "get": - if not issubclass(cls, gitlab.mixins.GetWithoutIdMixin): - if cls._id_attr is not None: - id_attr = cls._id_attr.replace("_", "-") - sub_parser_action.add_argument("--%s" % id_attr, required=True) - - for x in mgr_cls._optional_get_attrs: - sub_parser_action.add_argument( - "--%s" % x.replace("_", "-"), required=False - ) - - if action_name == "create": - for x in mgr_cls._create_attrs.required: - sub_parser_action.add_argument( - "--%s" % x.replace("_", "-"), required=True - ) - for x in mgr_cls._create_attrs.optional: - sub_parser_action.add_argument( - "--%s" % x.replace("_", "-"), required=False - ) - - if action_name == "update": - if cls._id_attr is not None: - id_attr = cls._id_attr.replace("_", "-") - sub_parser_action.add_argument("--%s" % id_attr, required=True) - - for x in mgr_cls._update_attrs.required: - if x != cls._id_attr: - sub_parser_action.add_argument( - "--%s" % x.replace("_", "-"), required=True - ) - - for x in mgr_cls._update_attrs.optional: - if x != cls._id_attr: - sub_parser_action.add_argument( - "--%s" % x.replace("_", "-"), required=False - ) - - if cls.__name__ in cli.custom_actions: - name = cls.__name__ - for action_name in cli.custom_actions[name]: - sub_parser_action = sub_parser.add_parser(action_name) - # Get the attributes for URL/path construction - if mgr_cls._from_parent_attrs: - for x in mgr_cls._from_parent_attrs: - sub_parser_action.add_argument( - "--%s" % x.replace("_", "-"), required=True - ) - sub_parser_action.add_argument("--sudo", required=False) - - # We need to get the object somehow - if not issubclass(cls, gitlab.mixins.GetWithoutIdMixin): - if cls._id_attr is not None: - id_attr = cls._id_attr.replace("_", "-") - sub_parser_action.add_argument("--%s" % id_attr, required=True) - - required, optional, dummy = cli.custom_actions[name][action_name] - [ - sub_parser_action.add_argument( - "--%s" % x.replace("_", "-"), required=True - ) - for x in required - if x != cls._id_attr - ] - [ - sub_parser_action.add_argument( - "--%s" % x.replace("_", "-"), required=False - ) - for x in optional - if x != cls._id_attr - ] - - if mgr_cls.__name__ in cli.custom_actions: - name = mgr_cls.__name__ - for action_name in cli.custom_actions[name]: - sub_parser_action = sub_parser.add_parser(action_name) - if mgr_cls._from_parent_attrs: - for x in mgr_cls._from_parent_attrs: - sub_parser_action.add_argument( - "--%s" % x.replace("_", "-"), required=True - ) - sub_parser_action.add_argument("--sudo", required=False) - - required, optional, dummy = cli.custom_actions[name][action_name] - [ - sub_parser_action.add_argument( - "--%s" % x.replace("_", "-"), required=True - ) - for x in required - if x != cls._id_attr - ] - [ - sub_parser_action.add_argument( - "--%s" % x.replace("_", "-"), required=False - ) - for x in optional - if x != cls._id_attr - ] - - -def extend_parser(parser: argparse.ArgumentParser) -> argparse.ArgumentParser: - subparsers = parser.add_subparsers( - title="object", dest="what", help="Object to manipulate." - ) - subparsers.required = True - - # populate argparse for all Gitlab Object - classes = [] - for cls in gitlab.v4.objects.__dict__.values(): - if not isinstance(cls, type): - continue - if issubclass(cls, gitlab.base.RESTManager): - if cls._obj_cls is not None: - classes.append(cls._obj_cls) - classes.sort(key=operator.attrgetter("__name__")) - - for cls in classes: - arg_name = cli.cls_to_what(cls) - object_group = subparsers.add_parser(arg_name) - - object_subparsers = object_group.add_subparsers( - title="action", dest="whaction", help="Action to execute." - ) - _populate_sub_parser_by_class(cls, object_subparsers) - object_subparsers.required = True - - return parser - - -def get_dict( - obj: Union[str, gitlab.base.RESTObject], fields: List[str] -) -> Union[str, Dict[str, Any]]: - if isinstance(obj, str): - return obj - - if fields: - return {k: v for k, v in obj.attributes.items() if k in fields} - return obj.attributes - - -class JSONPrinter(object): - def display(self, d: Union[str, Dict[str, Any]], **kwargs: Any) -> None: - import json # noqa - - print(json.dumps(d)) - - def display_list( - self, - data: List[Union[str, gitlab.base.RESTObject]], - fields: List[str], - **kwargs: Any - ) -> None: - import json # noqa - - print(json.dumps([get_dict(obj, fields) for obj in data])) - - -class YAMLPrinter(object): - def display(self, d: Union[str, Dict[str, Any]], **kwargs: Any) -> None: - try: - import yaml # noqa - - print(yaml.safe_dump(d, default_flow_style=False)) - except ImportError: - exit( - "PyYaml is not installed.\n" - "Install it with `pip install PyYaml` " - "to use the yaml output feature" - ) - - def display_list( - self, - data: List[Union[str, gitlab.base.RESTObject]], - fields: List[str], - **kwargs: Any - ) -> None: - try: - import yaml # noqa - - print( - yaml.safe_dump( - [get_dict(obj, fields) for obj in data], default_flow_style=False - ) - ) - except ImportError: - exit( - "PyYaml is not installed.\n" - "Install it with `pip install PyYaml` " - "to use the yaml output feature" - ) - - -class LegacyPrinter(object): - def display(self, d: Union[str, Dict[str, Any]], **kwargs: Any) -> None: - verbose = kwargs.get("verbose", False) - padding = kwargs.get("padding", 0) - obj: Optional[Union[Dict[str, Any], gitlab.base.RESTObject]] = kwargs.get("obj") - if TYPE_CHECKING: - assert obj is not None - - def display_dict(d: Dict[str, Any], padding: int) -> None: - for k in sorted(d.keys()): - v = d[k] - if isinstance(v, dict): - print("%s%s:" % (" " * padding, k.replace("_", "-"))) - new_padding = padding + 2 - self.display(v, verbose=True, padding=new_padding, obj=v) - continue - print("%s%s: %s" % (" " * padding, k.replace("_", "-"), v)) - - if verbose: - if isinstance(obj, dict): - display_dict(obj, padding) - return - - # not a dict, we assume it's a RESTObject - if obj._id_attr: - id = getattr(obj, obj._id_attr, None) - print("%s: %s" % (obj._id_attr, id)) - attrs = obj.attributes - if obj._id_attr: - attrs.pop(obj._id_attr) - display_dict(attrs, padding) - - else: - if TYPE_CHECKING: - assert isinstance(obj, gitlab.base.RESTObject) - if obj._id_attr: - id = getattr(obj, obj._id_attr) - print("%s: %s" % (obj._id_attr.replace("_", "-"), id)) - if obj._short_print_attr: - value = getattr(obj, obj._short_print_attr) or "None" - value = value.replace("\r", "").replace("\n", " ") - # If the attribute is a note (ProjectCommitComment) then we do - # some modifications to fit everything on one line - line = "%s: %s" % (obj._short_print_attr, value) - # ellipsize long lines (comments) - if len(line) > 79: - line = line[:76] + "..." - print(line) - - def display_list( - self, - data: List[Union[str, gitlab.base.RESTObject]], - fields: List[str], - **kwargs: Any - ) -> None: - verbose = kwargs.get("verbose", False) - for obj in data: - if isinstance(obj, gitlab.base.RESTObject): - self.display(get_dict(obj, fields), verbose=verbose, obj=obj) - else: - print(obj) - print("") - - -PRINTERS: Dict[ - str, Union[Type[JSONPrinter], Type[LegacyPrinter], Type[YAMLPrinter]] -] = { - "json": JSONPrinter, - "legacy": LegacyPrinter, - "yaml": YAMLPrinter, -} - - -def run( - gl: gitlab.Gitlab, - what: str, - action: str, - args: Dict[str, Any], - verbose: bool, - output: str, - fields: List[str], -) -> None: - g_cli = GitlabCLI(gl=gl, what=what, action=action, args=args) - data = g_cli() - - printer: Union[JSONPrinter, LegacyPrinter, YAMLPrinter] = PRINTERS[output]() - - if isinstance(data, dict): - printer.display(data, verbose=True, obj=data) - elif isinstance(data, list): - printer.display_list(data, fields, verbose=verbose) - elif isinstance(data, gitlab.base.RESTObject): - printer.display(get_dict(data, fields), verbose=verbose, obj=data) - elif isinstance(data, str): - print(data) - elif isinstance(data, bytes): - sys.stdout.buffer.write(data) - elif hasattr(data, "decode"): - print(data.decode()) diff --git a/gitlab/v4/objects/__init__.py b/gitlab/v4/objects/__init__.py deleted file mode 100644 index c2ff4fb..0000000 --- a/gitlab/v4/objects/__init__.py +++ /dev/null @@ -1,77 +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 .access_requests import * -from .appearance import * -from .applications import * -from .audit_events import * -from .award_emojis import * -from .badges import * -from .boards import * -from .branches import * -from .broadcast_messages import * -from .clusters import * -from .commits import * -from .container_registry import * -from .custom_attributes import * -from .deploy_keys import * -from .deploy_tokens import * -from .deployments import * -from .discussions import * -from .environments import * -from .epics import * -from .events import * -from .export_import import * -from .features import * -from .files import * -from .geo_nodes import * -from .groups import * -from .hooks import * -from .issues import * -from .jobs import * -from .keys import * -from .labels import * -from .ldap import * -from .members import * -from .merge_request_approvals import * -from .merge_requests import * -from .milestones import * -from .namespaces import * -from .notes import * -from .notification_settings import * -from .packages import * -from .pages import * -from .personal_access_tokens import * -from .pipelines import * -from .projects import * -from .push_rules import * -from .releases import * -from .runners import * -from .services import * -from .settings import * -from .sidekiq import * -from .snippets import * -from .statistics import * -from .tags import * -from .templates import * -from .todos import * -from .triggers import * -from .users import * -from .variables import * -from .wikis import * - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/gitlab/v4/objects/access_requests.py b/gitlab/v4/objects/access_requests.py deleted file mode 100644 index 4e3328a..0000000 --- a/gitlab/v4/objects/access_requests.py +++ /dev/null @@ -1,35 +0,0 @@ -from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import ( - AccessRequestMixin, - CreateMixin, - DeleteMixin, - ListMixin, - ObjectDeleteMixin, -) - -__all__ = [ - "GroupAccessRequest", - "GroupAccessRequestManager", - "ProjectAccessRequest", - "ProjectAccessRequestManager", -] - - -class GroupAccessRequest(AccessRequestMixin, ObjectDeleteMixin, RESTObject): - pass - - -class GroupAccessRequestManager(ListMixin, CreateMixin, DeleteMixin, RESTManager): - _path = "/groups/%(group_id)s/access_requests" - _obj_cls = GroupAccessRequest - _from_parent_attrs = {"group_id": "id"} - - -class ProjectAccessRequest(AccessRequestMixin, ObjectDeleteMixin, RESTObject): - pass - - -class ProjectAccessRequestManager(ListMixin, CreateMixin, DeleteMixin, RESTManager): - _path = "/projects/%(project_id)s/access_requests" - _obj_cls = ProjectAccessRequest - _from_parent_attrs = {"project_id": "id"} diff --git a/gitlab/v4/objects/appearance.py b/gitlab/v4/objects/appearance.py deleted file mode 100644 index a34398e..0000000 --- a/gitlab/v4/objects/appearance.py +++ /dev/null @@ -1,52 +0,0 @@ -from gitlab import exceptions as exc -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import GetWithoutIdMixin, SaveMixin, UpdateMixin - -__all__ = [ - "ApplicationAppearance", - "ApplicationAppearanceManager", -] - - -class ApplicationAppearance(SaveMixin, RESTObject): - _id_attr = None - - -class ApplicationAppearanceManager(GetWithoutIdMixin, UpdateMixin, RESTManager): - _path = "/application/appearance" - _obj_cls = ApplicationAppearance - _update_attrs = RequiredOptional( - optional=( - "title", - "description", - "logo", - "header_logo", - "favicon", - "new_project_guidelines", - "header_message", - "footer_message", - "message_background_color", - "message_font_color", - "email_header_and_footer_enabled", - ), - ) - - @exc.on_http_error(exc.GitlabUpdateError) - def update(self, id=None, new_data=None, **kwargs): - """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 {} - data = new_data.copy() - super(ApplicationAppearanceManager, self).update(id, data, **kwargs) diff --git a/gitlab/v4/objects/applications.py b/gitlab/v4/objects/applications.py deleted file mode 100644 index c91dee1..0000000 --- a/gitlab/v4/objects/applications.py +++ /dev/null @@ -1,20 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CreateMixin, DeleteMixin, ListMixin, ObjectDeleteMixin - -__all__ = [ - "Application", - "ApplicationManager", -] - - -class Application(ObjectDeleteMixin, RESTObject): - _url = "/applications" - _short_print_attr = "name" - - -class ApplicationManager(ListMixin, CreateMixin, DeleteMixin, RESTManager): - _path = "/applications" - _obj_cls = Application - _create_attrs = RequiredOptional( - required=("name", "redirect_uri", "scopes"), optional=("confidential",) - ) diff --git a/gitlab/v4/objects/audit_events.py b/gitlab/v4/objects/audit_events.py deleted file mode 100644 index 20ea116..0000000 --- a/gitlab/v4/objects/audit_events.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -GitLab API: -https://docs.gitlab.com/ee/api/audit_events.html -""" -from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import RetrieveMixin - -__all__ = [ - "AuditEvent", - "AuditEventManager", - "GroupAuditEvent", - "GroupAuditEventManager", - "ProjectAuditEvent", - "ProjectAuditEventManager", - "ProjectAudit", - "ProjectAuditManager", -] - - -class AuditEvent(RESTObject): - _id_attr = "id" - - -class AuditEventManager(RetrieveMixin, RESTManager): - _path = "/audit_events" - _obj_cls = AuditEvent - _list_filters = ("created_after", "created_before", "entity_type", "entity_id") - - -class GroupAuditEvent(RESTObject): - _id_attr = "id" - - -class GroupAuditEventManager(RetrieveMixin, RESTManager): - _path = "/groups/%(group_id)s/audit_events" - _obj_cls = GroupAuditEvent - _from_parent_attrs = {"group_id": "id"} - _list_filters = ("created_after", "created_before") - - -class ProjectAuditEvent(RESTObject): - _id_attr = "id" - - -class ProjectAuditEventManager(RetrieveMixin, RESTManager): - _path = "/projects/%(project_id)s/audit_events" - _obj_cls = ProjectAuditEvent - _from_parent_attrs = {"project_id": "id"} - _list_filters = ("created_after", "created_before") - - -class ProjectAudit(ProjectAuditEvent): - pass - - -class ProjectAuditManager(ProjectAuditEventManager): - pass diff --git a/gitlab/v4/objects/award_emojis.py b/gitlab/v4/objects/award_emojis.py deleted file mode 100644 index 1a7aecd..0000000 --- a/gitlab/v4/objects/award_emojis.py +++ /dev/null @@ -1,103 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import NoUpdateMixin, ObjectDeleteMixin - -__all__ = [ - "ProjectIssueAwardEmoji", - "ProjectIssueAwardEmojiManager", - "ProjectIssueNoteAwardEmoji", - "ProjectIssueNoteAwardEmojiManager", - "ProjectMergeRequestAwardEmoji", - "ProjectMergeRequestAwardEmojiManager", - "ProjectMergeRequestNoteAwardEmoji", - "ProjectMergeRequestNoteAwardEmojiManager", - "ProjectSnippetAwardEmoji", - "ProjectSnippetAwardEmojiManager", - "ProjectSnippetNoteAwardEmoji", - "ProjectSnippetNoteAwardEmojiManager", -] - - -class ProjectIssueAwardEmoji(ObjectDeleteMixin, RESTObject): - pass - - -class ProjectIssueAwardEmojiManager(NoUpdateMixin, RESTManager): - _path = "/projects/%(project_id)s/issues/%(issue_iid)s/award_emoji" - _obj_cls = ProjectIssueAwardEmoji - _from_parent_attrs = {"project_id": "project_id", "issue_iid": "iid"} - _create_attrs = RequiredOptional(required=("name",)) - - -class ProjectIssueNoteAwardEmoji(ObjectDeleteMixin, RESTObject): - pass - - -class ProjectIssueNoteAwardEmojiManager(NoUpdateMixin, RESTManager): - _path = ( - "/projects/%(project_id)s/issues/%(issue_iid)s" "/notes/%(note_id)s/award_emoji" - ) - _obj_cls = ProjectIssueNoteAwardEmoji - _from_parent_attrs = { - "project_id": "project_id", - "issue_iid": "issue_iid", - "note_id": "id", - } - _create_attrs = RequiredOptional(required=("name",)) - - -class ProjectMergeRequestAwardEmoji(ObjectDeleteMixin, RESTObject): - pass - - -class ProjectMergeRequestAwardEmojiManager(NoUpdateMixin, RESTManager): - _path = "/projects/%(project_id)s/merge_requests/%(mr_iid)s/award_emoji" - _obj_cls = ProjectMergeRequestAwardEmoji - _from_parent_attrs = {"project_id": "project_id", "mr_iid": "iid"} - _create_attrs = RequiredOptional(required=("name",)) - - -class ProjectMergeRequestNoteAwardEmoji(ObjectDeleteMixin, RESTObject): - pass - - -class ProjectMergeRequestNoteAwardEmojiManager(NoUpdateMixin, RESTManager): - _path = ( - "/projects/%(project_id)s/merge_requests/%(mr_iid)s" - "/notes/%(note_id)s/award_emoji" - ) - _obj_cls = ProjectMergeRequestNoteAwardEmoji - _from_parent_attrs = { - "project_id": "project_id", - "mr_iid": "mr_iid", - "note_id": "id", - } - _create_attrs = RequiredOptional(required=("name",)) - - -class ProjectSnippetAwardEmoji(ObjectDeleteMixin, RESTObject): - pass - - -class ProjectSnippetAwardEmojiManager(NoUpdateMixin, RESTManager): - _path = "/projects/%(project_id)s/snippets/%(snippet_id)s/award_emoji" - _obj_cls = ProjectSnippetAwardEmoji - _from_parent_attrs = {"project_id": "project_id", "snippet_id": "id"} - _create_attrs = RequiredOptional(required=("name",)) - - -class ProjectSnippetNoteAwardEmoji(ObjectDeleteMixin, RESTObject): - pass - - -class ProjectSnippetNoteAwardEmojiManager(NoUpdateMixin, RESTManager): - _path = ( - "/projects/%(project_id)s/snippets/%(snippet_id)s" - "/notes/%(note_id)s/award_emoji" - ) - _obj_cls = ProjectSnippetNoteAwardEmoji - _from_parent_attrs = { - "project_id": "project_id", - "snippet_id": "snippet_id", - "note_id": "id", - } - _create_attrs = RequiredOptional(required=("name",)) diff --git a/gitlab/v4/objects/badges.py b/gitlab/v4/objects/badges.py deleted file mode 100644 index 198f6ea..0000000 --- a/gitlab/v4/objects/badges.py +++ /dev/null @@ -1,33 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import BadgeRenderMixin, CRUDMixin, ObjectDeleteMixin, SaveMixin - -__all__ = [ - "GroupBadge", - "GroupBadgeManager", - "ProjectBadge", - "ProjectBadgeManager", -] - - -class GroupBadge(SaveMixin, ObjectDeleteMixin, RESTObject): - pass - - -class GroupBadgeManager(BadgeRenderMixin, CRUDMixin, RESTManager): - _path = "/groups/%(group_id)s/badges" - _obj_cls = GroupBadge - _from_parent_attrs = {"group_id": "id"} - _create_attrs = RequiredOptional(required=("link_url", "image_url")) - _update_attrs = RequiredOptional(optional=("link_url", "image_url")) - - -class ProjectBadge(SaveMixin, ObjectDeleteMixin, RESTObject): - pass - - -class ProjectBadgeManager(BadgeRenderMixin, CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/badges" - _obj_cls = ProjectBadge - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional(required=("link_url", "image_url")) - _update_attrs = RequiredOptional(optional=("link_url", "image_url")) diff --git a/gitlab/v4/objects/boards.py b/gitlab/v4/objects/boards.py deleted file mode 100644 index 8b2959d..0000000 --- a/gitlab/v4/objects/boards.py +++ /dev/null @@ -1,59 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CRUDMixin, ObjectDeleteMixin, SaveMixin - -__all__ = [ - "GroupBoardList", - "GroupBoardListManager", - "GroupBoard", - "GroupBoardManager", - "ProjectBoardList", - "ProjectBoardListManager", - "ProjectBoard", - "ProjectBoardManager", -] - - -class GroupBoardList(SaveMixin, ObjectDeleteMixin, RESTObject): - pass - - -class GroupBoardListManager(CRUDMixin, RESTManager): - _path = "/groups/%(group_id)s/boards/%(board_id)s/lists" - _obj_cls = GroupBoardList - _from_parent_attrs = {"group_id": "group_id", "board_id": "id"} - _create_attrs = RequiredOptional(required=("label_id",)) - _update_attrs = RequiredOptional(required=("position",)) - - -class GroupBoard(SaveMixin, ObjectDeleteMixin, RESTObject): - lists: GroupBoardListManager - - -class GroupBoardManager(CRUDMixin, RESTManager): - _path = "/groups/%(group_id)s/boards" - _obj_cls = GroupBoard - _from_parent_attrs = {"group_id": "id"} - _create_attrs = RequiredOptional(required=("name",)) - - -class ProjectBoardList(SaveMixin, ObjectDeleteMixin, RESTObject): - pass - - -class ProjectBoardListManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/boards/%(board_id)s/lists" - _obj_cls = ProjectBoardList - _from_parent_attrs = {"project_id": "project_id", "board_id": "id"} - _create_attrs = RequiredOptional(required=("label_id",)) - _update_attrs = RequiredOptional(required=("position",)) - - -class ProjectBoard(SaveMixin, ObjectDeleteMixin, RESTObject): - lists: ProjectBoardListManager - - -class ProjectBoardManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/boards" - _obj_cls = ProjectBoard - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional(required=("name",)) diff --git a/gitlab/v4/objects/branches.py b/gitlab/v4/objects/branches.py deleted file mode 100644 index 5bd8442..0000000 --- a/gitlab/v4/objects/branches.py +++ /dev/null @@ -1,42 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import NoUpdateMixin, ObjectDeleteMixin - -__all__ = [ - "ProjectBranch", - "ProjectBranchManager", - "ProjectProtectedBranch", - "ProjectProtectedBranchManager", -] - - -class ProjectBranch(ObjectDeleteMixin, RESTObject): - _id_attr = "name" - - -class ProjectBranchManager(NoUpdateMixin, RESTManager): - _path = "/projects/%(project_id)s/repository/branches" - _obj_cls = ProjectBranch - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional(required=("branch", "ref")) - - -class ProjectProtectedBranch(ObjectDeleteMixin, RESTObject): - _id_attr = "name" - - -class ProjectProtectedBranchManager(NoUpdateMixin, RESTManager): - _path = "/projects/%(project_id)s/protected_branches" - _obj_cls = ProjectProtectedBranch - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("name",), - optional=( - "push_access_level", - "merge_access_level", - "unprotect_access_level", - "allowed_to_push", - "allowed_to_merge", - "allowed_to_unprotect", - "code_owner_approval_required", - ), - ) diff --git a/gitlab/v4/objects/broadcast_messages.py b/gitlab/v4/objects/broadcast_messages.py deleted file mode 100644 index 7784997..0000000 --- a/gitlab/v4/objects/broadcast_messages.py +++ /dev/null @@ -1,23 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CRUDMixin, ObjectDeleteMixin, SaveMixin - -__all__ = [ - "BroadcastMessage", - "BroadcastMessageManager", -] - - -class BroadcastMessage(SaveMixin, ObjectDeleteMixin, RESTObject): - pass - - -class BroadcastMessageManager(CRUDMixin, RESTManager): - _path = "/broadcast_messages" - _obj_cls = BroadcastMessage - - _create_attrs = RequiredOptional( - required=("message",), optional=("starts_at", "ends_at", "color", "font") - ) - _update_attrs = RequiredOptional( - optional=("message", "starts_at", "ends_at", "color", "font") - ) diff --git a/gitlab/v4/objects/clusters.py b/gitlab/v4/objects/clusters.py deleted file mode 100644 index 10ff202..0000000 --- a/gitlab/v4/objects/clusters.py +++ /dev/null @@ -1,98 +0,0 @@ -from gitlab import exceptions as exc -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CreateMixin, CRUDMixin, ObjectDeleteMixin, SaveMixin - -__all__ = [ - "GroupCluster", - "GroupClusterManager", - "ProjectCluster", - "ProjectClusterManager", -] - - -class GroupCluster(SaveMixin, ObjectDeleteMixin, RESTObject): - pass - - -class GroupClusterManager(CRUDMixin, RESTManager): - _path = "/groups/%(group_id)s/clusters" - _obj_cls = GroupCluster - _from_parent_attrs = {"group_id": "id"} - _create_attrs = RequiredOptional( - required=("name", "platform_kubernetes_attributes"), - optional=("domain", "enabled", "managed", "environment_scope"), - ) - _update_attrs = RequiredOptional( - optional=( - "name", - "domain", - "management_project_id", - "platform_kubernetes_attributes", - "environment_scope", - ), - ) - - @exc.on_http_error(exc.GitlabStopError) - def create(self, data, **kwargs): - """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 or - 'ref_name', 'stage', 'name', 'all') - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCreateError: If the server cannot perform the request - - Returns: - RESTObject: A new instance of the manage object class build with - the data sent by the server - """ - path = "%s/user" % (self.path) - return CreateMixin.create(self, data, path=path, **kwargs) - - -class ProjectCluster(SaveMixin, ObjectDeleteMixin, RESTObject): - pass - - -class ProjectClusterManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/clusters" - _obj_cls = ProjectCluster - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("name", "platform_kubernetes_attributes"), - optional=("domain", "enabled", "managed", "environment_scope"), - ) - _update_attrs = RequiredOptional( - optional=( - "name", - "domain", - "management_project_id", - "platform_kubernetes_attributes", - "environment_scope", - ), - ) - - @exc.on_http_error(exc.GitlabStopError) - def create(self, data, **kwargs): - """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 or - 'ref_name', 'stage', 'name', 'all') - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCreateError: If the server cannot perform the request - - Returns: - RESTObject: A new instance of the manage object class build with - the data sent by the server - """ - path = "%s/user" % (self.path) - return CreateMixin.create(self, data, path=path, **kwargs) diff --git a/gitlab/v4/objects/commits.py b/gitlab/v4/objects/commits.py deleted file mode 100644 index 05b55b0..0000000 --- a/gitlab/v4/objects/commits.py +++ /dev/null @@ -1,200 +0,0 @@ -from gitlab import cli -from gitlab import exceptions as exc -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CreateMixin, ListMixin, RefreshMixin, RetrieveMixin - -from .discussions import ProjectCommitDiscussionManager # noqa: F401 - -__all__ = [ - "ProjectCommit", - "ProjectCommitManager", - "ProjectCommitComment", - "ProjectCommitCommentManager", - "ProjectCommitStatus", - "ProjectCommitStatusManager", -] - - -class ProjectCommit(RESTObject): - _short_print_attr = "title" - - comments: "ProjectCommitCommentManager" - discussions: ProjectCommitDiscussionManager - statuses: "ProjectCommitStatusManager" - - @cli.register_custom_action("ProjectCommit") - @exc.on_http_error(exc.GitlabGetError) - def diff(self, **kwargs): - """Generate the commit diff. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabGetError: If the diff could not be retrieved - - Returns: - list: The changes done in this commit - """ - path = "%s/%s/diff" % (self.manager.path, self.get_id()) - return self.manager.gitlab.http_get(path, **kwargs) - - @cli.register_custom_action("ProjectCommit", ("branch",)) - @exc.on_http_error(exc.GitlabCherryPickError) - def cherry_pick(self, branch, **kwargs): - """Cherry-pick a commit into a branch. - - Args: - branch (str): Name of target branch - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCherryPickError: If the cherry-pick could not be performed - """ - path = "%s/%s/cherry_pick" % (self.manager.path, self.get_id()) - post_data = {"branch": branch} - self.manager.gitlab.http_post(path, post_data=post_data, **kwargs) - - @cli.register_custom_action("ProjectCommit", optional=("type",)) - @exc.on_http_error(exc.GitlabGetError) - def refs(self, type="all", **kwargs): - """List the references the commit is pushed to. - - Args: - type (str): The scope of references ('branch', 'tag' or 'all') - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabGetError: If the references could not be retrieved - - Returns: - list: The references the commit is pushed to. - """ - path = "%s/%s/refs" % (self.manager.path, self.get_id()) - data = {"type": type} - return self.manager.gitlab.http_get(path, query_data=data, **kwargs) - - @cli.register_custom_action("ProjectCommit") - @exc.on_http_error(exc.GitlabGetError) - def merge_requests(self, **kwargs): - """List the merge requests related to the commit. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabGetError: If the references could not be retrieved - - Returns: - list: The merge requests related to the commit. - """ - path = "%s/%s/merge_requests" % (self.manager.path, self.get_id()) - return self.manager.gitlab.http_get(path, **kwargs) - - @cli.register_custom_action("ProjectCommit", ("branch",)) - @exc.on_http_error(exc.GitlabRevertError) - def revert(self, branch, **kwargs): - """Revert a commit on a given branch. - - Args: - branch (str): Name of target branch - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabRevertError: If the revert could not be performed - - Returns: - dict: The new commit data (*not* a RESTObject) - """ - path = "%s/%s/revert" % (self.manager.path, self.get_id()) - post_data = {"branch": branch} - return self.manager.gitlab.http_post(path, post_data=post_data, **kwargs) - - @cli.register_custom_action("ProjectCommit") - @exc.on_http_error(exc.GitlabGetError) - def signature(self, **kwargs): - """Get the signature of the commit. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabGetError: If the signature could not be retrieved - - Returns: - dict: The commit's signature data - """ - path = "%s/%s/signature" % (self.manager.path, self.get_id()) - return self.manager.gitlab.http_get(path, **kwargs) - - -class ProjectCommitManager(RetrieveMixin, CreateMixin, RESTManager): - _path = "/projects/%(project_id)s/repository/commits" - _obj_cls = ProjectCommit - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("branch", "commit_message", "actions"), - optional=("author_email", "author_name"), - ) - - -class ProjectCommitComment(RESTObject): - _id_attr = None - _short_print_attr = "note" - - -class ProjectCommitCommentManager(ListMixin, CreateMixin, RESTManager): - _path = "/projects/%(project_id)s/repository/commits/%(commit_id)s" "/comments" - _obj_cls = ProjectCommitComment - _from_parent_attrs = {"project_id": "project_id", "commit_id": "id"} - _create_attrs = RequiredOptional( - required=("note",), optional=("path", "line", "line_type") - ) - - -class ProjectCommitStatus(RefreshMixin, RESTObject): - pass - - -class ProjectCommitStatusManager(ListMixin, CreateMixin, RESTManager): - _path = "/projects/%(project_id)s/repository/commits/%(commit_id)s" "/statuses" - _obj_cls = ProjectCommitStatus - _from_parent_attrs = {"project_id": "project_id", "commit_id": "id"} - _create_attrs = RequiredOptional( - required=("state",), - optional=("description", "name", "context", "ref", "target_url", "coverage"), - ) - - @exc.on_http_error(exc.GitlabCreateError) - def create(self, data, **kwargs): - """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 or - 'ref_name', 'stage', 'name', 'all') - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCreateError: If the server cannot perform the request - - Returns: - RESTObject: A new instance of the manage object class build with - the data sent by the server - """ - # project_id and commit_id are in the data dict when using the CLI, but - # they are missing when using only the API - # See #511 - base_path = "/projects/%(project_id)s/statuses/%(commit_id)s" - if "project_id" in data and "commit_id" in data: - path = base_path % data - else: - path = self._compute_path(base_path) - return CreateMixin.create(self, data, path=path, **kwargs) diff --git a/gitlab/v4/objects/container_registry.py b/gitlab/v4/objects/container_registry.py deleted file mode 100644 index ce03d35..0000000 --- a/gitlab/v4/objects/container_registry.py +++ /dev/null @@ -1,58 +0,0 @@ -from gitlab import cli -from gitlab import exceptions as exc -from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import DeleteMixin, ListMixin, ObjectDeleteMixin, RetrieveMixin - -__all__ = [ - "ProjectRegistryRepository", - "ProjectRegistryRepositoryManager", - "ProjectRegistryTag", - "ProjectRegistryTagManager", -] - - -class ProjectRegistryRepository(ObjectDeleteMixin, RESTObject): - tags: "ProjectRegistryTagManager" - - -class ProjectRegistryRepositoryManager(DeleteMixin, ListMixin, RESTManager): - _path = "/projects/%(project_id)s/registry/repositories" - _obj_cls = ProjectRegistryRepository - _from_parent_attrs = {"project_id": "id"} - - -class ProjectRegistryTag(ObjectDeleteMixin, RESTObject): - _id_attr = "name" - - -class ProjectRegistryTagManager(DeleteMixin, RetrieveMixin, RESTManager): - _obj_cls = ProjectRegistryTag - _from_parent_attrs = {"project_id": "project_id", "repository_id": "id"} - _path = "/projects/%(project_id)s/registry/repositories/%(repository_id)s/tags" - - @cli.register_custom_action( - "ProjectRegistryTagManager", - ("name_regex_delete",), - optional=("keep_n", "name_regex_keep", "older_than"), - ) - @exc.on_http_error(exc.GitlabDeleteError) - def delete_in_bulk(self, name_regex_delete, **kwargs): - """Delete Tag in bulk - - Args: - name_regex_delete (string): The regex of the name to delete. To delete all - tags specify .*. - keep_n (integer): The amount of latest tags of given name to keep. - name_regex_keep (string): The regex of the name to keep. This value - overrides any matches from name_regex. - older_than (string): Tags to delete that are older than the given time, - written in human readable form 1h, 1d, 1month. - **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 - """ - valid_attrs = ["keep_n", "name_regex_keep", "older_than"] - data = {"name_regex_delete": name_regex_delete} - data.update({k: v for k, v in kwargs.items() if k in valid_attrs}) - self.gitlab.http_delete(self.path, query_data=data, **kwargs) diff --git a/gitlab/v4/objects/custom_attributes.py b/gitlab/v4/objects/custom_attributes.py deleted file mode 100644 index 48296ca..0000000 --- a/gitlab/v4/objects/custom_attributes.py +++ /dev/null @@ -1,41 +0,0 @@ -from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import DeleteMixin, ObjectDeleteMixin, RetrieveMixin, SetMixin - -__all__ = [ - "GroupCustomAttribute", - "GroupCustomAttributeManager", - "ProjectCustomAttribute", - "ProjectCustomAttributeManager", - "UserCustomAttribute", - "UserCustomAttributeManager", -] - - -class GroupCustomAttribute(ObjectDeleteMixin, RESTObject): - _id_attr = "key" - - -class GroupCustomAttributeManager(RetrieveMixin, SetMixin, DeleteMixin, RESTManager): - _path = "/groups/%(group_id)s/custom_attributes" - _obj_cls = GroupCustomAttribute - _from_parent_attrs = {"group_id": "id"} - - -class ProjectCustomAttribute(ObjectDeleteMixin, RESTObject): - _id_attr = "key" - - -class ProjectCustomAttributeManager(RetrieveMixin, SetMixin, DeleteMixin, RESTManager): - _path = "/projects/%(project_id)s/custom_attributes" - _obj_cls = ProjectCustomAttribute - _from_parent_attrs = {"project_id": "id"} - - -class UserCustomAttribute(ObjectDeleteMixin, RESTObject): - _id_attr = "key" - - -class UserCustomAttributeManager(RetrieveMixin, SetMixin, DeleteMixin, RESTManager): - _path = "/users/%(user_id)s/custom_attributes" - _obj_cls = UserCustomAttribute - _from_parent_attrs = {"user_id": "id"} diff --git a/gitlab/v4/objects/deploy_keys.py b/gitlab/v4/objects/deploy_keys.py deleted file mode 100644 index cf0507d..0000000 --- a/gitlab/v4/objects/deploy_keys.py +++ /dev/null @@ -1,48 +0,0 @@ -from gitlab import cli -from gitlab import exceptions as exc -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CRUDMixin, ListMixin, ObjectDeleteMixin, SaveMixin - -__all__ = [ - "DeployKey", - "DeployKeyManager", - "ProjectKey", - "ProjectKeyManager", -] - - -class DeployKey(RESTObject): - pass - - -class DeployKeyManager(ListMixin, RESTManager): - _path = "/deploy_keys" - _obj_cls = DeployKey - - -class ProjectKey(SaveMixin, ObjectDeleteMixin, RESTObject): - pass - - -class ProjectKeyManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/deploy_keys" - _obj_cls = ProjectKey - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional(required=("title", "key"), optional=("can_push",)) - _update_attrs = RequiredOptional(optional=("title", "can_push")) - - @cli.register_custom_action("ProjectKeyManager", ("key_id",)) - @exc.on_http_error(exc.GitlabProjectDeployKeyError) - def enable(self, key_id, **kwargs): - """Enable a deploy key for a project. - - Args: - key_id (int): The ID of the key to enable - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabProjectDeployKeyError: If the key could not be enabled - """ - path = "%s/%s/enable" % (self.path, key_id) - self.gitlab.http_post(path, **kwargs) diff --git a/gitlab/v4/objects/deploy_tokens.py b/gitlab/v4/objects/deploy_tokens.py deleted file mode 100644 index c6ba0d6..0000000 --- a/gitlab/v4/objects/deploy_tokens.py +++ /dev/null @@ -1,63 +0,0 @@ -from gitlab import types -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CreateMixin, DeleteMixin, ListMixin, ObjectDeleteMixin - -__all__ = [ - "DeployToken", - "DeployTokenManager", - "GroupDeployToken", - "GroupDeployTokenManager", - "ProjectDeployToken", - "ProjectDeployTokenManager", -] - - -class DeployToken(ObjectDeleteMixin, RESTObject): - pass - - -class DeployTokenManager(ListMixin, RESTManager): - _path = "/deploy_tokens" - _obj_cls = DeployToken - - -class GroupDeployToken(ObjectDeleteMixin, RESTObject): - pass - - -class GroupDeployTokenManager(ListMixin, CreateMixin, DeleteMixin, RESTManager): - _path = "/groups/%(group_id)s/deploy_tokens" - _from_parent_attrs = {"group_id": "id"} - _obj_cls = GroupDeployToken - _create_attrs = RequiredOptional( - required=( - "name", - "scopes", - ), - optional=( - "expires_at", - "username", - ), - ) - _types = {"scopes": types.ListAttribute} - - -class ProjectDeployToken(ObjectDeleteMixin, RESTObject): - pass - - -class ProjectDeployTokenManager(ListMixin, CreateMixin, DeleteMixin, RESTManager): - _path = "/projects/%(project_id)s/deploy_tokens" - _from_parent_attrs = {"project_id": "id"} - _obj_cls = ProjectDeployToken - _create_attrs = RequiredOptional( - required=( - "name", - "scopes", - ), - optional=( - "expires_at", - "username", - ), - ) - _types = {"scopes": types.ListAttribute} diff --git a/gitlab/v4/objects/deployments.py b/gitlab/v4/objects/deployments.py deleted file mode 100644 index 11c60d1..0000000 --- a/gitlab/v4/objects/deployments.py +++ /dev/null @@ -1,30 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CreateMixin, RetrieveMixin, SaveMixin, UpdateMixin - -from .merge_requests import ProjectDeploymentMergeRequestManager # noqa: F401 - -__all__ = [ - "ProjectDeployment", - "ProjectDeploymentManager", -] - - -class ProjectDeployment(SaveMixin, RESTObject): - mergerequests: ProjectDeploymentMergeRequestManager - - -class ProjectDeploymentManager(RetrieveMixin, CreateMixin, UpdateMixin, RESTManager): - _path = "/projects/%(project_id)s/deployments" - _obj_cls = ProjectDeployment - _from_parent_attrs = {"project_id": "id"} - _list_filters = ( - "order_by", - "sort", - "updated_after", - "updated_before", - "environment", - "status", - ) - _create_attrs = RequiredOptional( - required=("sha", "ref", "tag", "status", "environment") - ) diff --git a/gitlab/v4/objects/discussions.py b/gitlab/v4/objects/discussions.py deleted file mode 100644 index ae7a4d5..0000000 --- a/gitlab/v4/objects/discussions.py +++ /dev/null @@ -1,69 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CreateMixin, RetrieveMixin, SaveMixin, UpdateMixin - -from .notes import ( # noqa: F401 - ProjectCommitDiscussionNoteManager, - ProjectIssueDiscussionNoteManager, - ProjectMergeRequestDiscussionNoteManager, - ProjectSnippetDiscussionNoteManager, -) - -__all__ = [ - "ProjectCommitDiscussion", - "ProjectCommitDiscussionManager", - "ProjectIssueDiscussion", - "ProjectIssueDiscussionManager", - "ProjectMergeRequestDiscussion", - "ProjectMergeRequestDiscussionManager", - "ProjectSnippetDiscussion", - "ProjectSnippetDiscussionManager", -] - - -class ProjectCommitDiscussion(RESTObject): - notes: ProjectCommitDiscussionNoteManager - - -class ProjectCommitDiscussionManager(RetrieveMixin, CreateMixin, RESTManager): - _path = "/projects/%(project_id)s/repository/commits/%(commit_id)s/" "discussions" - _obj_cls = ProjectCommitDiscussion - _from_parent_attrs = {"project_id": "project_id", "commit_id": "id"} - _create_attrs = RequiredOptional(required=("body",), optional=("created_at",)) - - -class ProjectIssueDiscussion(RESTObject): - notes: ProjectIssueDiscussionNoteManager - - -class ProjectIssueDiscussionManager(RetrieveMixin, CreateMixin, RESTManager): - _path = "/projects/%(project_id)s/issues/%(issue_iid)s/discussions" - _obj_cls = ProjectIssueDiscussion - _from_parent_attrs = {"project_id": "project_id", "issue_iid": "iid"} - _create_attrs = RequiredOptional(required=("body",), optional=("created_at",)) - - -class ProjectMergeRequestDiscussion(SaveMixin, RESTObject): - notes: ProjectMergeRequestDiscussionNoteManager - - -class ProjectMergeRequestDiscussionManager( - RetrieveMixin, CreateMixin, UpdateMixin, RESTManager -): - _path = "/projects/%(project_id)s/merge_requests/%(mr_iid)s/discussions" - _obj_cls = ProjectMergeRequestDiscussion - _from_parent_attrs = {"project_id": "project_id", "mr_iid": "iid"} - _create_attrs = RequiredOptional( - required=("body",), optional=("created_at", "position") - ) - _update_attrs = RequiredOptional(required=("resolved",)) - - -class ProjectSnippetDiscussion(RESTObject): - notes: ProjectSnippetDiscussionNoteManager - - -class ProjectSnippetDiscussionManager(RetrieveMixin, CreateMixin, RESTManager): - _path = "/projects/%(project_id)s/snippets/%(snippet_id)s/discussions" - _obj_cls = ProjectSnippetDiscussion - _from_parent_attrs = {"project_id": "project_id", "snippet_id": "id"} - _create_attrs = RequiredOptional(required=("body",), optional=("created_at",)) diff --git a/gitlab/v4/objects/environments.py b/gitlab/v4/objects/environments.py deleted file mode 100644 index e318da8..0000000 --- a/gitlab/v4/objects/environments.py +++ /dev/null @@ -1,43 +0,0 @@ -from gitlab import cli -from gitlab import exceptions as exc -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import ( - CreateMixin, - DeleteMixin, - ObjectDeleteMixin, - RetrieveMixin, - SaveMixin, - UpdateMixin, -) - -__all__ = [ - "ProjectEnvironment", - "ProjectEnvironmentManager", -] - - -class ProjectEnvironment(SaveMixin, ObjectDeleteMixin, RESTObject): - @cli.register_custom_action("ProjectEnvironment") - @exc.on_http_error(exc.GitlabStopError) - def stop(self, **kwargs): - """Stop the environment. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabStopError: If the operation failed - """ - path = "%s/%s/stop" % (self.manager.path, self.get_id()) - self.manager.gitlab.http_post(path, **kwargs) - - -class ProjectEnvironmentManager( - RetrieveMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTManager -): - _path = "/projects/%(project_id)s/environments" - _obj_cls = ProjectEnvironment - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional(required=("name",), optional=("external_url",)) - _update_attrs = RequiredOptional(optional=("name", "external_url")) diff --git a/gitlab/v4/objects/epics.py b/gitlab/v4/objects/epics.py deleted file mode 100644 index 90dc6ad..0000000 --- a/gitlab/v4/objects/epics.py +++ /dev/null @@ -1,104 +0,0 @@ -from gitlab import exceptions as exc -from gitlab import types -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import ( - CreateMixin, - CRUDMixin, - DeleteMixin, - ListMixin, - ObjectDeleteMixin, - SaveMixin, - UpdateMixin, -) - -from .events import GroupEpicResourceLabelEventManager # noqa: F401 - -__all__ = [ - "GroupEpic", - "GroupEpicManager", - "GroupEpicIssue", - "GroupEpicIssueManager", -] - - -class GroupEpic(ObjectDeleteMixin, SaveMixin, RESTObject): - _id_attr = "iid" - - issues: "GroupEpicIssueManager" - resourcelabelevents: GroupEpicResourceLabelEventManager - - -class GroupEpicManager(CRUDMixin, RESTManager): - _path = "/groups/%(group_id)s/epics" - _obj_cls = GroupEpic - _from_parent_attrs = {"group_id": "id"} - _list_filters = ("author_id", "labels", "order_by", "sort", "search") - _create_attrs = RequiredOptional( - required=("title",), - optional=("labels", "description", "start_date", "end_date"), - ) - _update_attrs = RequiredOptional( - optional=("title", "labels", "description", "start_date", "end_date"), - ) - _types = {"labels": types.ListAttribute} - - -class GroupEpicIssue(ObjectDeleteMixin, SaveMixin, RESTObject): - _id_attr = "epic_issue_id" - - def save(self, **kwargs): - """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() - self.manager.update(obj_id, updated_data, **kwargs) - - -class GroupEpicIssueManager( - ListMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTManager -): - _path = "/groups/%(group_id)s/epics/%(epic_iid)s/issues" - _obj_cls = GroupEpicIssue - _from_parent_attrs = {"group_id": "group_id", "epic_iid": "iid"} - _create_attrs = RequiredOptional(required=("issue_id",)) - _update_attrs = RequiredOptional(optional=("move_before_id", "move_after_id")) - - @exc.on_http_error(exc.GitlabCreateError) - def create(self, data, **kwargs): - """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) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCreateError: If the server cannot perform the request - - Returns: - RESTObject: A new instance of the manage object class build with - the data sent by the server - """ - CreateMixin._check_missing_create_attrs(self, data) - path = "%s/%s" % (self.path, data.pop("issue_id")) - server_data = self.gitlab.http_post(path, **kwargs) - # The epic_issue_id attribute doesn't exist when creating the resource, - # but is used everywhere elese. Let's create it to be consistent client - # side - server_data["epic_issue_id"] = server_data["id"] - return self._obj_cls(self, server_data) diff --git a/gitlab/v4/objects/events.py b/gitlab/v4/objects/events.py deleted file mode 100644 index 8772e8d..0000000 --- a/gitlab/v4/objects/events.py +++ /dev/null @@ -1,130 +0,0 @@ -from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import ListMixin, RetrieveMixin - -__all__ = [ - "Event", - "EventManager", - "GroupEpicResourceLabelEvent", - "GroupEpicResourceLabelEventManager", - "ProjectEvent", - "ProjectEventManager", - "ProjectIssueResourceLabelEvent", - "ProjectIssueResourceLabelEventManager", - "ProjectIssueResourceMilestoneEvent", - "ProjectIssueResourceMilestoneEventManager", - "ProjectIssueResourceStateEvent", - "ProjectIssueResourceStateEventManager", - "ProjectMergeRequestResourceLabelEvent", - "ProjectMergeRequestResourceLabelEventManager", - "ProjectMergeRequestResourceMilestoneEvent", - "ProjectMergeRequestResourceMilestoneEventManager", - "ProjectMergeRequestResourceStateEvent", - "ProjectMergeRequestResourceStateEventManager", - "UserEvent", - "UserEventManager", -] - - -class Event(RESTObject): - _id_attr = None - _short_print_attr = "target_title" - - -class EventManager(ListMixin, RESTManager): - _path = "/events" - _obj_cls = Event - _list_filters = ("action", "target_type", "before", "after", "sort") - - -class GroupEpicResourceLabelEvent(RESTObject): - pass - - -class GroupEpicResourceLabelEventManager(RetrieveMixin, RESTManager): - _path = "/groups/%(group_id)s/epics/%(epic_id)s/resource_label_events" - _obj_cls = GroupEpicResourceLabelEvent - _from_parent_attrs = {"group_id": "group_id", "epic_id": "id"} - - -class ProjectEvent(Event): - pass - - -class ProjectEventManager(EventManager): - _path = "/projects/%(project_id)s/events" - _obj_cls = ProjectEvent - _from_parent_attrs = {"project_id": "id"} - - -class ProjectIssueResourceLabelEvent(RESTObject): - pass - - -class ProjectIssueResourceLabelEventManager(RetrieveMixin, RESTManager): - _path = "/projects/%(project_id)s/issues/%(issue_iid)s" "/resource_label_events" - _obj_cls = ProjectIssueResourceLabelEvent - _from_parent_attrs = {"project_id": "project_id", "issue_iid": "iid"} - - -class ProjectIssueResourceMilestoneEvent(RESTObject): - pass - - -class ProjectIssueResourceMilestoneEventManager(RetrieveMixin, RESTManager): - _path = "/projects/%(project_id)s/issues/%(issue_iid)s/resource_milestone_events" - _obj_cls = ProjectIssueResourceMilestoneEvent - _from_parent_attrs = {"project_id": "project_id", "issue_iid": "iid"} - - -class ProjectIssueResourceStateEvent(RESTObject): - pass - - -class ProjectIssueResourceStateEventManager(RetrieveMixin, RESTManager): - _path = "/projects/%(project_id)s/issues/%(issue_iid)s/resource_state_events" - _obj_cls = ProjectIssueResourceStateEvent - _from_parent_attrs = {"project_id": "project_id", "issue_iid": "iid"} - - -class ProjectMergeRequestResourceLabelEvent(RESTObject): - pass - - -class ProjectMergeRequestResourceLabelEventManager(RetrieveMixin, RESTManager): - _path = ( - "/projects/%(project_id)s/merge_requests/%(mr_iid)s" "/resource_label_events" - ) - _obj_cls = ProjectMergeRequestResourceLabelEvent - _from_parent_attrs = {"project_id": "project_id", "mr_iid": "iid"} - - -class ProjectMergeRequestResourceMilestoneEvent(RESTObject): - pass - - -class ProjectMergeRequestResourceMilestoneEventManager(RetrieveMixin, RESTManager): - _path = ( - "/projects/%(project_id)s/merge_requests/%(mr_iid)s/resource_milestone_events" - ) - _obj_cls = ProjectMergeRequestResourceMilestoneEvent - _from_parent_attrs = {"project_id": "project_id", "mr_iid": "iid"} - - -class ProjectMergeRequestResourceStateEvent(RESTObject): - pass - - -class ProjectMergeRequestResourceStateEventManager(RetrieveMixin, RESTManager): - _path = "/projects/%(project_id)s/merge_requests/%(mr_iid)s/resource_state_events" - _obj_cls = ProjectMergeRequestResourceStateEvent - _from_parent_attrs = {"project_id": "project_id", "mr_iid": "iid"} - - -class UserEvent(Event): - pass - - -class UserEventManager(EventManager): - _path = "/users/%(user_id)s/events" - _obj_cls = UserEvent - _from_parent_attrs = {"user_id": "id"} diff --git a/gitlab/v4/objects/export_import.py b/gitlab/v4/objects/export_import.py deleted file mode 100644 index ec4532a..0000000 --- a/gitlab/v4/objects/export_import.py +++ /dev/null @@ -1,54 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CreateMixin, DownloadMixin, GetWithoutIdMixin, RefreshMixin - -__all__ = [ - "GroupExport", - "GroupExportManager", - "GroupImport", - "GroupImportManager", - "ProjectExport", - "ProjectExportManager", - "ProjectImport", - "ProjectImportManager", -] - - -class GroupExport(DownloadMixin, RESTObject): - _id_attr = None - - -class GroupExportManager(GetWithoutIdMixin, CreateMixin, RESTManager): - _path = "/groups/%(group_id)s/export" - _obj_cls = GroupExport - _from_parent_attrs = {"group_id": "id"} - - -class GroupImport(RESTObject): - _id_attr = None - - -class GroupImportManager(GetWithoutIdMixin, RESTManager): - _path = "/groups/%(group_id)s/import" - _obj_cls = GroupImport - _from_parent_attrs = {"group_id": "id"} - - -class ProjectExport(DownloadMixin, RefreshMixin, RESTObject): - _id_attr = None - - -class ProjectExportManager(GetWithoutIdMixin, CreateMixin, RESTManager): - _path = "/projects/%(project_id)s/export" - _obj_cls = ProjectExport - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional(optional=("description",)) - - -class ProjectImport(RefreshMixin, RESTObject): - _id_attr = None - - -class ProjectImportManager(GetWithoutIdMixin, RESTManager): - _path = "/projects/%(project_id)s/import" - _obj_cls = ProjectImport - _from_parent_attrs = {"project_id": "id"} diff --git a/gitlab/v4/objects/features.py b/gitlab/v4/objects/features.py deleted file mode 100644 index f4117c8..0000000 --- a/gitlab/v4/objects/features.py +++ /dev/null @@ -1,59 +0,0 @@ -from gitlab import exceptions as exc -from gitlab import utils -from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import DeleteMixin, ListMixin, ObjectDeleteMixin - -__all__ = [ - "Feature", - "FeatureManager", -] - - -class Feature(ObjectDeleteMixin, RESTObject): - _id_attr = "name" - - -class FeatureManager(ListMixin, DeleteMixin, RESTManager): - _path = "/features/" - _obj_cls = Feature - - @exc.on_http_error(exc.GitlabSetError) - def set( - self, - name, - value, - feature_group=None, - user=None, - group=None, - project=None, - **kwargs - ): - """Create or update the object. - - Args: - name (str): The value to set for the object - value (bool/int): The value to set for the object - feature_group (str): A feature group name - user (str): A GitLab username - group (str): A GitLab group - project (str): A GitLab project in form group/project - **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, name.replace("/", "%2F")) - data = { - "value": value, - "feature_group": feature_group, - "user": user, - "group": group, - "project": project, - } - data = utils.remove_none_from_dict(data) - server_data = self.gitlab.http_post(path, post_data=data, **kwargs) - return self._obj_cls(self, server_data) diff --git a/gitlab/v4/objects/files.py b/gitlab/v4/objects/files.py deleted file mode 100644 index ff45478..0000000 --- a/gitlab/v4/objects/files.py +++ /dev/null @@ -1,228 +0,0 @@ -import base64 - -from gitlab import cli -from gitlab import exceptions as exc -from gitlab import utils -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import ( - CreateMixin, - DeleteMixin, - GetMixin, - ObjectDeleteMixin, - SaveMixin, - UpdateMixin, -) - -__all__ = [ - "ProjectFile", - "ProjectFileManager", -] - - -class ProjectFile(SaveMixin, ObjectDeleteMixin, RESTObject): - _id_attr = "file_path" - _short_print_attr = "file_path" - - def decode(self) -> bytes: - """Returns the decoded content of the file. - - Returns: - (bytes): the decoded content. - """ - return base64.b64decode(self.content) - - def save(self, branch, commit_message, **kwargs): - """Save the changes made to the file to the server. - - The object is updated to match what the server returns. - - Args: - branch (str): Branch in which the file will be updated - commit_message (str): Message to send with the commit - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabUpdateError: If the server cannot perform the request - """ - self.branch = branch - self.commit_message = commit_message - self.file_path = self.file_path.replace("/", "%2F") - super(ProjectFile, self).save(**kwargs) - - def delete(self, branch, commit_message, **kwargs): - """Delete the file from the server. - - Args: - branch (str): Branch from which the file will be removed - commit_message (str): Commit message for the deletion - **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 - """ - file_path = self.get_id().replace("/", "%2F") - self.manager.delete(file_path, branch, commit_message, **kwargs) - - -class ProjectFileManager(GetMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTManager): - _path = "/projects/%(project_id)s/repository/files" - _obj_cls = ProjectFile - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("file_path", "branch", "content", "commit_message"), - optional=("encoding", "author_email", "author_name"), - ) - _update_attrs = RequiredOptional( - required=("file_path", "branch", "content", "commit_message"), - optional=("encoding", "author_email", "author_name"), - ) - - @cli.register_custom_action("ProjectFileManager", ("file_path", "ref")) - def get(self, file_path, ref, **kwargs): - """Retrieve a single file. - - Args: - file_path (str): Path of the file to retrieve - ref (str): Name of the branch, tag or commit - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabGetError: If the file could not be retrieved - - Returns: - object: The generated RESTObject - """ - return GetMixin.get(self, file_path, ref=ref, **kwargs) - - @cli.register_custom_action( - "ProjectFileManager", - ("file_path", "branch", "content", "commit_message"), - ("encoding", "author_email", "author_name"), - ) - @exc.on_http_error(exc.GitlabCreateError) - def create(self, data, **kwargs): - """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 - """ - - self._check_missing_create_attrs(data) - new_data = data.copy() - file_path = new_data.pop("file_path").replace("/", "%2F") - path = "%s/%s" % (self.path, file_path) - server_data = self.gitlab.http_post(path, post_data=new_data, **kwargs) - return self._obj_cls(self, server_data) - - @exc.on_http_error(exc.GitlabUpdateError) - def update(self, file_path, new_data=None, **kwargs): - """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 {} - data = new_data.copy() - file_path = file_path.replace("/", "%2F") - data["file_path"] = file_path - path = "%s/%s" % (self.path, file_path) - self._check_missing_update_attrs(data) - return self.gitlab.http_put(path, post_data=data, **kwargs) - - @cli.register_custom_action( - "ProjectFileManager", ("file_path", "branch", "commit_message") - ) - @exc.on_http_error(exc.GitlabDeleteError) - def delete(self, file_path, branch, commit_message, **kwargs): - """Delete a file on the server. - - Args: - file_path (str): Path of the file to remove - branch (str): Branch from which the file will be removed - commit_message (str): Commit message for the deletion - **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 - """ - path = "%s/%s" % (self.path, file_path.replace("/", "%2F")) - data = {"branch": branch, "commit_message": commit_message} - self.gitlab.http_delete(path, query_data=data, **kwargs) - - @cli.register_custom_action("ProjectFileManager", ("file_path", "ref")) - @exc.on_http_error(exc.GitlabGetError) - def raw( - self, file_path, ref, streamed=False, action=None, chunk_size=1024, **kwargs - ): - """Return the content of a file for a commit. - - Args: - ref (str): ID of the commit - filepath (str): Path of the file to return - 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 file could not be retrieved - - Returns: - str: The file content - """ - file_path = file_path.replace("/", "%2F").replace(".", "%2E") - path = "%s/%s/raw" % (self.path, file_path) - query_data = {"ref": ref} - result = self.gitlab.http_get( - path, query_data=query_data, streamed=streamed, raw=True, **kwargs - ) - return utils.response_content(result, streamed, action, chunk_size) - - @cli.register_custom_action("ProjectFileManager", ("file_path", "ref")) - @exc.on_http_error(exc.GitlabListError) - def blame(self, file_path, ref, **kwargs): - """Return the content of a file for a commit. - - Args: - file_path (str): Path of the file to retrieve - ref (str): Name of the branch, tag or commit - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabListError: If the server failed to perform the request - - Returns: - list(blame): a list of commits/lines matching the file - """ - file_path = file_path.replace("/", "%2F").replace(".", "%2E") - path = "%s/%s/blame" % (self.path, file_path) - query_data = {"ref": ref} - return self.gitlab.http_list(path, query_data, **kwargs) diff --git a/gitlab/v4/objects/geo_nodes.py b/gitlab/v4/objects/geo_nodes.py deleted file mode 100644 index 16fc783..0000000 --- a/gitlab/v4/objects/geo_nodes.py +++ /dev/null @@ -1,93 +0,0 @@ -from gitlab import cli -from gitlab import exceptions as exc -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import ( - DeleteMixin, - ObjectDeleteMixin, - RetrieveMixin, - SaveMixin, - UpdateMixin, -) - -__all__ = [ - "GeoNode", - "GeoNodeManager", -] - - -class GeoNode(SaveMixin, ObjectDeleteMixin, RESTObject): - @cli.register_custom_action("GeoNode") - @exc.on_http_error(exc.GitlabRepairError) - def repair(self, **kwargs): - """Repair the OAuth authentication of the geo node. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabRepairError: If the server failed to perform the request - """ - path = "/geo_nodes/%s/repair" % self.get_id() - server_data = self.manager.gitlab.http_post(path, **kwargs) - self._update_attrs(server_data) - - @cli.register_custom_action("GeoNode") - @exc.on_http_error(exc.GitlabGetError) - def status(self, **kwargs): - """Get the status of the geo node. - - Args: - **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: - dict: The status of the geo node - """ - path = "/geo_nodes/%s/status" % self.get_id() - return self.manager.gitlab.http_get(path, **kwargs) - - -class GeoNodeManager(RetrieveMixin, UpdateMixin, DeleteMixin, RESTManager): - _path = "/geo_nodes" - _obj_cls = GeoNode - _update_attrs = RequiredOptional( - optional=("enabled", "url", "files_max_capacity", "repos_max_capacity"), - ) - - @cli.register_custom_action("GeoNodeManager") - @exc.on_http_error(exc.GitlabGetError) - def status(self, **kwargs): - """Get the status of all the geo nodes. - - Args: - **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: - list: The status of all the geo nodes - """ - return self.gitlab.http_list("/geo_nodes/status", **kwargs) - - @cli.register_custom_action("GeoNodeManager") - @exc.on_http_error(exc.GitlabGetError) - def current_failures(self, **kwargs): - """Get the list of failures on the current geo node. - - Args: - **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: - list: The list of failures - """ - return self.gitlab.http_list("/geo_nodes/current/failures", **kwargs) diff --git a/gitlab/v4/objects/groups.py b/gitlab/v4/objects/groups.py deleted file mode 100644 index b675a39..0000000 --- a/gitlab/v4/objects/groups.py +++ /dev/null @@ -1,334 +0,0 @@ -from gitlab import cli -from gitlab import exceptions as exc -from gitlab import types -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CRUDMixin, ListMixin, ObjectDeleteMixin, SaveMixin - -from .access_requests import GroupAccessRequestManager # noqa: F401 -from .audit_events import GroupAuditEventManager # noqa: F401 -from .badges import GroupBadgeManager # noqa: F401 -from .boards import GroupBoardManager # noqa: F401 -from .clusters import GroupClusterManager # noqa: F401 -from .custom_attributes import GroupCustomAttributeManager # noqa: F401 -from .deploy_tokens import GroupDeployTokenManager # noqa: F401 -from .epics import GroupEpicManager # noqa: F401 -from .export_import import GroupExportManager, GroupImportManager # noqa: F401 -from .hooks import GroupHookManager # noqa: F401 -from .issues import GroupIssueManager # noqa: F401 -from .labels import GroupLabelManager # noqa: F401 -from .members import ( # noqa: F401 - GroupBillableMemberManager, - GroupMemberAllManager, - GroupMemberManager, -) -from .merge_requests import GroupMergeRequestManager # noqa: F401 -from .milestones import GroupMilestoneManager # noqa: F401 -from .notification_settings import GroupNotificationSettingsManager # noqa: F401 -from .packages import GroupPackageManager # noqa: F401 -from .projects import GroupProjectManager # noqa: F401 -from .runners import GroupRunnerManager # noqa: F401 -from .statistics import GroupIssuesStatisticsManager # noqa: F401 -from .variables import GroupVariableManager # noqa: F401 -from .wikis import GroupWikiManager # noqa: F401 - -__all__ = [ - "Group", - "GroupManager", - "GroupDescendantGroup", - "GroupDescendantGroupManager", - "GroupSubgroup", - "GroupSubgroupManager", -] - - -class Group(SaveMixin, ObjectDeleteMixin, RESTObject): - _short_print_attr = "name" - - accessrequests: GroupAccessRequestManager - audit_events: GroupAuditEventManager - badges: GroupBadgeManager - billable_members: GroupBillableMemberManager - boards: GroupBoardManager - clusters: GroupClusterManager - customattributes: GroupCustomAttributeManager - deploytokens: GroupDeployTokenManager - descendant_groups: "GroupDescendantGroupManager" - epics: GroupEpicManager - exports: GroupExportManager - hooks: GroupHookManager - imports: GroupImportManager - issues: GroupIssueManager - issues_statistics: GroupIssuesStatisticsManager - labels: GroupLabelManager - members: GroupMemberManager - members_all: GroupMemberAllManager - mergerequests: GroupMergeRequestManager - milestones: GroupMilestoneManager - notificationsettings: GroupNotificationSettingsManager - packages: GroupPackageManager - projects: GroupProjectManager - runners: GroupRunnerManager - subgroups: "GroupSubgroupManager" - variables: GroupVariableManager - wikis: GroupWikiManager - - @cli.register_custom_action("Group", ("project_id",)) - @exc.on_http_error(exc.GitlabTransferProjectError) - def transfer_project(self, project_id, **kwargs): - """Transfer a project to this group. - - Args: - to_project_id (int): ID of the project to transfer - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabTransferProjectError: If the project could not be transferred - """ - path = "/groups/%s/projects/%s" % (self.id, project_id) - self.manager.gitlab.http_post(path, **kwargs) - - @cli.register_custom_action("Group", ("scope", "search")) - @exc.on_http_error(exc.GitlabSearchError) - def search(self, scope, search, **kwargs): - """Search the group resources matching the provided string.' - - Args: - scope (str): Scope of the search - search (str): Search string - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabSearchError: If the server failed to perform the request - - Returns: - GitlabList: A list of dicts describing the resources found. - """ - data = {"scope": scope, "search": search} - path = "/groups/%s/search" % self.get_id() - return self.manager.gitlab.http_list(path, query_data=data, **kwargs) - - @cli.register_custom_action("Group", ("cn", "group_access", "provider")) - @exc.on_http_error(exc.GitlabCreateError) - def add_ldap_group_link(self, cn, group_access, provider, **kwargs): - """Add an LDAP group link. - - Args: - cn (str): CN of the LDAP group - group_access (int): Minimum access level for members of the LDAP - group - provider (str): LDAP provider for the LDAP group - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCreateError: If the server cannot perform the request - """ - path = "/groups/%s/ldap_group_links" % self.get_id() - data = {"cn": cn, "group_access": group_access, "provider": provider} - self.manager.gitlab.http_post(path, post_data=data, **kwargs) - - @cli.register_custom_action("Group", ("cn",), ("provider",)) - @exc.on_http_error(exc.GitlabDeleteError) - def delete_ldap_group_link(self, cn, provider=None, **kwargs): - """Delete an LDAP group link. - - Args: - cn (str): CN of the LDAP group - provider (str): LDAP provider for the LDAP group - **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 - """ - path = "/groups/%s/ldap_group_links" % self.get_id() - if provider is not None: - path += "/%s" % provider - path += "/%s" % cn - self.manager.gitlab.http_delete(path) - - @cli.register_custom_action("Group") - @exc.on_http_error(exc.GitlabCreateError) - def ldap_sync(self, **kwargs): - """Sync LDAP groups. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCreateError: If the server cannot perform the request - """ - path = "/groups/%s/ldap_sync" % self.get_id() - self.manager.gitlab.http_post(path, **kwargs) - - @cli.register_custom_action("Group", ("group_id", "group_access"), ("expires_at",)) - @exc.on_http_error(exc.GitlabCreateError) - def share(self, group_id, group_access, expires_at=None, **kwargs): - """Share the group with a group. - - Args: - group_id (int): ID of the group. - group_access (int): Access level for the group. - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCreateError: If the server failed to perform the request - """ - path = "/groups/%s/share" % self.get_id() - data = { - "group_id": group_id, - "group_access": group_access, - "expires_at": expires_at, - } - self.manager.gitlab.http_post(path, post_data=data, **kwargs) - - @cli.register_custom_action("Group", ("group_id",)) - @exc.on_http_error(exc.GitlabDeleteError) - def unshare(self, group_id, **kwargs): - """Delete a shared group link within a group. - - Args: - group_id (int): ID of the group. - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabDeleteError: If the server failed to perform the request - """ - path = "/groups/%s/share/%s" % (self.get_id(), group_id) - self.manager.gitlab.http_delete(path, **kwargs) - - -class GroupManager(CRUDMixin, RESTManager): - _path = "/groups" - _obj_cls = Group - _list_filters = ( - "skip_groups", - "all_available", - "search", - "order_by", - "sort", - "statistics", - "owned", - "with_custom_attributes", - "min_access_level", - "top_level_only", - ) - _create_attrs = RequiredOptional( - required=("name", "path"), - optional=( - "description", - "membership_lock", - "visibility", - "share_with_group_lock", - "require_two_factor_authentication", - "two_factor_grace_period", - "project_creation_level", - "auto_devops_enabled", - "subgroup_creation_level", - "emails_disabled", - "avatar", - "mentions_disabled", - "lfs_enabled", - "request_access_enabled", - "parent_id", - "default_branch_protection", - "shared_runners_minutes_limit", - "extra_shared_runners_minutes_limit", - ), - ) - _update_attrs = RequiredOptional( - optional=( - "name", - "path", - "description", - "membership_lock", - "share_with_group_lock", - "visibility", - "require_two_factor_authentication", - "two_factor_grace_period", - "project_creation_level", - "auto_devops_enabled", - "subgroup_creation_level", - "emails_disabled", - "avatar", - "mentions_disabled", - "lfs_enabled", - "request_access_enabled", - "default_branch_protection", - "file_template_project_id", - "shared_runners_minutes_limit", - "extra_shared_runners_minutes_limit", - "prevent_forking_outside_group", - "shared_runners_setting", - ), - ) - _types = {"avatar": types.ImageAttribute, "skip_groups": types.ListAttribute} - - @exc.on_http_error(exc.GitlabImportError) - def import_group(self, file, path, name, parent_id=None, **kwargs): - """Import a group from an archive file. - - Args: - file: Data or file object containing the group - path (str): The path for the new group to be imported. - name (str): The name for the new group. - parent_id (str): ID of a parent group that the group will - be imported into. - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabImportError: If the server failed to perform the request - - Returns: - dict: A representation of the import status. - """ - files = {"file": ("file.tar.gz", file, "application/octet-stream")} - data = {"path": path, "name": name} - if parent_id is not None: - data["parent_id"] = parent_id - - return self.gitlab.http_post( - "/groups/import", post_data=data, files=files, **kwargs - ) - - -class GroupSubgroup(RESTObject): - pass - - -class GroupSubgroupManager(ListMixin, RESTManager): - _path = "/groups/%(group_id)s/subgroups" - _obj_cls = GroupSubgroup - _from_parent_attrs = {"group_id": "id"} - _list_filters = ( - "skip_groups", - "all_available", - "search", - "order_by", - "sort", - "statistics", - "owned", - "with_custom_attributes", - "min_access_level", - ) - _types = {"skip_groups": types.ListAttribute} - - -class GroupDescendantGroup(RESTObject): - pass - - -class GroupDescendantGroupManager(GroupSubgroupManager): - """ - This manager inherits from GroupSubgroupManager as descendant groups - share all attributes with subgroups, except the path and object class. - """ - - _path = "/groups/%(group_id)s/descendant_groups" - _obj_cls = GroupDescendantGroup diff --git a/gitlab/v4/objects/hooks.py b/gitlab/v4/objects/hooks.py deleted file mode 100644 index 428fd76..0000000 --- a/gitlab/v4/objects/hooks.py +++ /dev/null @@ -1,114 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CRUDMixin, NoUpdateMixin, ObjectDeleteMixin, SaveMixin - -__all__ = [ - "Hook", - "HookManager", - "ProjectHook", - "ProjectHookManager", - "GroupHook", - "GroupHookManager", -] - - -class Hook(ObjectDeleteMixin, RESTObject): - _url = "/hooks" - _short_print_attr = "url" - - -class HookManager(NoUpdateMixin, RESTManager): - _path = "/hooks" - _obj_cls = Hook - _create_attrs = RequiredOptional(required=("url",)) - - -class ProjectHook(SaveMixin, ObjectDeleteMixin, RESTObject): - _short_print_attr = "url" - - -class ProjectHookManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/hooks" - _obj_cls = ProjectHook - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("url",), - optional=( - "push_events", - "issues_events", - "confidential_issues_events", - "merge_requests_events", - "tag_push_events", - "note_events", - "job_events", - "pipeline_events", - "wiki_page_events", - "enable_ssl_verification", - "token", - ), - ) - _update_attrs = RequiredOptional( - required=("url",), - optional=( - "push_events", - "issues_events", - "confidential_issues_events", - "merge_requests_events", - "tag_push_events", - "note_events", - "job_events", - "pipeline_events", - "wiki_events", - "enable_ssl_verification", - "token", - ), - ) - - -class GroupHook(SaveMixin, ObjectDeleteMixin, RESTObject): - _short_print_attr = "url" - - -class GroupHookManager(CRUDMixin, RESTManager): - _path = "/groups/%(group_id)s/hooks" - _obj_cls = GroupHook - _from_parent_attrs = {"group_id": "id"} - _create_attrs = RequiredOptional( - required=("url",), - optional=( - "push_events", - "issues_events", - "confidential_issues_events", - "merge_requests_events", - "tag_push_events", - "note_events", - "confidential_note_events", - "job_events", - "pipeline_events", - "wiki_page_events", - "deployment_events", - "releases_events", - "subgroup_events", - "enable_ssl_verification", - "token", - ), - ) - _update_attrs = RequiredOptional( - required=("url",), - optional=( - "push_events", - "issues_events", - "confidential_issues_events", - "merge_requests_events", - "tag_push_events", - "note_events", - "confidential_note_events", - "job_events", - "pipeline_events", - "wiki_page_events", - "deployment_events", - "releases_events", - "subgroup_events", - "enable_ssl_verification", - "token", - ), - ) diff --git a/gitlab/v4/objects/issues.py b/gitlab/v4/objects/issues.py deleted file mode 100644 index 9272908..0000000 --- a/gitlab/v4/objects/issues.py +++ /dev/null @@ -1,256 +0,0 @@ -from gitlab import cli -from gitlab import exceptions as exc -from gitlab import types -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import ( - CreateMixin, - CRUDMixin, - DeleteMixin, - ListMixin, - ObjectDeleteMixin, - ParticipantsMixin, - RetrieveMixin, - SaveMixin, - SubscribableMixin, - TimeTrackingMixin, - TodoMixin, - UserAgentDetailMixin, -) - -from .award_emojis import ProjectIssueAwardEmojiManager # noqa: F401 -from .discussions import ProjectIssueDiscussionManager # noqa: F401 -from .events import ( # noqa: F401 - ProjectIssueResourceLabelEventManager, - ProjectIssueResourceMilestoneEventManager, - ProjectIssueResourceStateEventManager, -) -from .notes import ProjectIssueNoteManager # noqa: F401 - -__all__ = [ - "Issue", - "IssueManager", - "GroupIssue", - "GroupIssueManager", - "ProjectIssue", - "ProjectIssueManager", - "ProjectIssueLink", - "ProjectIssueLinkManager", -] - - -class Issue(RESTObject): - _url = "/issues" - _short_print_attr = "title" - - -class IssueManager(RetrieveMixin, RESTManager): - _path = "/issues" - _obj_cls = Issue - _list_filters = ( - "state", - "labels", - "milestone", - "scope", - "author_id", - "assignee_id", - "my_reaction_emoji", - "iids", - "order_by", - "sort", - "search", - "created_after", - "created_before", - "updated_after", - "updated_before", - ) - _types = {"iids": types.ListAttribute, "labels": types.ListAttribute} - - -class GroupIssue(RESTObject): - pass - - -class GroupIssueManager(ListMixin, RESTManager): - _path = "/groups/%(group_id)s/issues" - _obj_cls = GroupIssue - _from_parent_attrs = {"group_id": "id"} - _list_filters = ( - "state", - "labels", - "milestone", - "order_by", - "sort", - "iids", - "author_id", - "assignee_id", - "my_reaction_emoji", - "search", - "created_after", - "created_before", - "updated_after", - "updated_before", - ) - _types = {"iids": types.ListAttribute, "labels": types.ListAttribute} - - -class ProjectIssue( - UserAgentDetailMixin, - SubscribableMixin, - TodoMixin, - TimeTrackingMixin, - ParticipantsMixin, - SaveMixin, - ObjectDeleteMixin, - RESTObject, -): - _short_print_attr = "title" - _id_attr = "iid" - - awardemojis: ProjectIssueAwardEmojiManager - discussions: ProjectIssueDiscussionManager - links: "ProjectIssueLinkManager" - notes: ProjectIssueNoteManager - resourcelabelevents: ProjectIssueResourceLabelEventManager - resourcemilestoneevents: ProjectIssueResourceMilestoneEventManager - resourcestateevents: ProjectIssueResourceStateEventManager - - @cli.register_custom_action("ProjectIssue", ("to_project_id",)) - @exc.on_http_error(exc.GitlabUpdateError) - def move(self, to_project_id, **kwargs): - """Move the issue to another project. - - Args: - to_project_id(int): ID of the target project - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabUpdateError: If the issue could not be moved - """ - path = "%s/%s/move" % (self.manager.path, self.get_id()) - data = {"to_project_id": to_project_id} - server_data = self.manager.gitlab.http_post(path, post_data=data, **kwargs) - self._update_attrs(server_data) - - @cli.register_custom_action("ProjectIssue") - @exc.on_http_error(exc.GitlabGetError) - def related_merge_requests(self, **kwargs): - """List merge requests related to the issue. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabGetErrot: If the merge requests could not be retrieved - - Returns: - list: The list of merge requests. - """ - path = "%s/%s/related_merge_requests" % (self.manager.path, self.get_id()) - return self.manager.gitlab.http_get(path, **kwargs) - - @cli.register_custom_action("ProjectIssue") - @exc.on_http_error(exc.GitlabGetError) - def closed_by(self, **kwargs): - """List merge requests that will close the issue when merged. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabGetErrot: If the merge requests could not be retrieved - - Returns: - list: The list of merge requests. - """ - path = "%s/%s/closed_by" % (self.manager.path, self.get_id()) - return self.manager.gitlab.http_get(path, **kwargs) - - -class ProjectIssueManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/issues" - _obj_cls = ProjectIssue - _from_parent_attrs = {"project_id": "id"} - _list_filters = ( - "iids", - "state", - "labels", - "milestone", - "scope", - "author_id", - "assignee_id", - "my_reaction_emoji", - "order_by", - "sort", - "search", - "created_after", - "created_before", - "updated_after", - "updated_before", - ) - _create_attrs = RequiredOptional( - required=("title",), - optional=( - "description", - "confidential", - "assignee_ids", - "assignee_id", - "milestone_id", - "labels", - "created_at", - "due_date", - "merge_request_to_resolve_discussions_of", - "discussion_to_resolve", - ), - ) - _update_attrs = RequiredOptional( - optional=( - "title", - "description", - "confidential", - "assignee_ids", - "assignee_id", - "milestone_id", - "labels", - "state_event", - "updated_at", - "due_date", - "discussion_locked", - ), - ) - _types = {"iids": types.ListAttribute, "labels": types.ListAttribute} - - -class ProjectIssueLink(ObjectDeleteMixin, RESTObject): - _id_attr = "issue_link_id" - - -class ProjectIssueLinkManager(ListMixin, CreateMixin, DeleteMixin, RESTManager): - _path = "/projects/%(project_id)s/issues/%(issue_iid)s/links" - _obj_cls = ProjectIssueLink - _from_parent_attrs = {"project_id": "project_id", "issue_iid": "iid"} - _create_attrs = RequiredOptional(required=("target_project_id", "target_issue_iid")) - - @exc.on_http_error(exc.GitlabCreateError) - def create(self, data, **kwargs): - """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, RESTObject: The source and target issues - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCreateError: If the server cannot perform the request - """ - self._check_missing_create_attrs(data) - server_data = self.gitlab.http_post(self.path, post_data=data, **kwargs) - source_issue = ProjectIssue(self._parent.manager, server_data["source_issue"]) - target_issue = ProjectIssue(self._parent.manager, server_data["target_issue"]) - return source_issue, target_issue diff --git a/gitlab/v4/objects/jobs.py b/gitlab/v4/objects/jobs.py deleted file mode 100644 index 2e7693d..0000000 --- a/gitlab/v4/objects/jobs.py +++ /dev/null @@ -1,190 +0,0 @@ -from gitlab import cli -from gitlab import exceptions as exc -from gitlab import utils -from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import RefreshMixin, RetrieveMixin - -__all__ = [ - "ProjectJob", - "ProjectJobManager", -] - - -class ProjectJob(RefreshMixin, RESTObject): - @cli.register_custom_action("ProjectJob") - @exc.on_http_error(exc.GitlabJobCancelError) - def cancel(self, **kwargs): - """Cancel the job. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabJobCancelError: If the job could not be canceled - """ - path = "%s/%s/cancel" % (self.manager.path, self.get_id()) - return self.manager.gitlab.http_post(path) - - @cli.register_custom_action("ProjectJob") - @exc.on_http_error(exc.GitlabJobRetryError) - def retry(self, **kwargs): - """Retry the job. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabJobRetryError: If the job could not be retried - """ - path = "%s/%s/retry" % (self.manager.path, self.get_id()) - return self.manager.gitlab.http_post(path) - - @cli.register_custom_action("ProjectJob") - @exc.on_http_error(exc.GitlabJobPlayError) - def play(self, **kwargs): - """Trigger a job explicitly. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabJobPlayError: If the job could not be triggered - """ - path = "%s/%s/play" % (self.manager.path, self.get_id()) - self.manager.gitlab.http_post(path) - - @cli.register_custom_action("ProjectJob") - @exc.on_http_error(exc.GitlabJobEraseError) - def erase(self, **kwargs): - """Erase the job (remove job artifacts and trace). - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabJobEraseError: If the job could not be erased - """ - path = "%s/%s/erase" % (self.manager.path, self.get_id()) - self.manager.gitlab.http_post(path) - - @cli.register_custom_action("ProjectJob") - @exc.on_http_error(exc.GitlabCreateError) - def keep_artifacts(self, **kwargs): - """Prevent artifacts from being deleted when expiration is set. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCreateError: If the request could not be performed - """ - path = "%s/%s/artifacts/keep" % (self.manager.path, self.get_id()) - self.manager.gitlab.http_post(path) - - @cli.register_custom_action("ProjectJob") - @exc.on_http_error(exc.GitlabCreateError) - def delete_artifacts(self, **kwargs): - """Delete artifacts of a job. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabDeleteError: If the request could not be performed - """ - path = "%s/%s/artifacts" % (self.manager.path, self.get_id()) - self.manager.gitlab.http_delete(path) - - @cli.register_custom_action("ProjectJob") - @exc.on_http_error(exc.GitlabGetError) - def artifacts(self, streamed=False, action=None, chunk_size=1024, **kwargs): - """Get the job artifacts. - - 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 artifacts could not be retrieved - - Returns: - str: The artifacts if `streamed` is False, None otherwise. - """ - path = "%s/%s/artifacts" % (self.manager.path, self.get_id()) - result = self.manager.gitlab.http_get( - path, streamed=streamed, raw=True, **kwargs - ) - return utils.response_content(result, streamed, action, chunk_size) - - @cli.register_custom_action("ProjectJob") - @exc.on_http_error(exc.GitlabGetError) - def artifact(self, path, streamed=False, action=None, chunk_size=1024, **kwargs): - """Get a single artifact file from within the job's artifacts archive. - - Args: - path (str): Path of the artifact - 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 artifacts could not be retrieved - - Returns: - str: The artifacts if `streamed` is False, None otherwise. - """ - path = "%s/%s/artifacts/%s" % (self.manager.path, self.get_id(), path) - result = self.manager.gitlab.http_get( - path, streamed=streamed, raw=True, **kwargs - ) - return utils.response_content(result, streamed, action, chunk_size) - - @cli.register_custom_action("ProjectJob") - @exc.on_http_error(exc.GitlabGetError) - def trace(self, streamed=False, action=None, chunk_size=1024, **kwargs): - """Get the job trace. - - 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 artifacts could not be retrieved - - Returns: - str: The trace - """ - path = "%s/%s/trace" % (self.manager.path, self.get_id()) - result = self.manager.gitlab.http_get( - path, streamed=streamed, raw=True, **kwargs - ) - return utils.response_content(result, streamed, action, chunk_size) - - -class ProjectJobManager(RetrieveMixin, RESTManager): - _path = "/projects/%(project_id)s/jobs" - _obj_cls = ProjectJob - _from_parent_attrs = {"project_id": "id"} diff --git a/gitlab/v4/objects/keys.py b/gitlab/v4/objects/keys.py deleted file mode 100644 index 7f8fa0e..0000000 --- a/gitlab/v4/objects/keys.py +++ /dev/null @@ -1,26 +0,0 @@ -from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import GetMixin - -__all__ = [ - "Key", - "KeyManager", -] - - -class Key(RESTObject): - pass - - -class KeyManager(GetMixin, RESTManager): - _path = "/keys" - _obj_cls = Key - - def get(self, id=None, **kwargs): - if id is not None: - return super(KeyManager, self).get(id, **kwargs) - - if "fingerprint" not in kwargs: - raise AttributeError("Missing attribute: id or fingerprint") - - server_data = self.gitlab.http_get(self.path, **kwargs) - return self._obj_cls(self, server_data) diff --git a/gitlab/v4/objects/labels.py b/gitlab/v4/objects/labels.py deleted file mode 100644 index 544c3cd..0000000 --- a/gitlab/v4/objects/labels.py +++ /dev/null @@ -1,149 +0,0 @@ -from gitlab import exceptions as exc -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import ( - CreateMixin, - DeleteMixin, - ListMixin, - ObjectDeleteMixin, - RetrieveMixin, - SaveMixin, - SubscribableMixin, - UpdateMixin, -) - -__all__ = [ - "GroupLabel", - "GroupLabelManager", - "ProjectLabel", - "ProjectLabelManager", -] - - -class GroupLabel(SubscribableMixin, SaveMixin, ObjectDeleteMixin, RESTObject): - _id_attr = "name" - - # Update without ID, but we need an ID to get from list. - @exc.on_http_error(exc.GitlabUpdateError) - def save(self, **kwargs): - """Saves 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) - - Raises: - GitlabAuthenticationError: If authentication is not correct. - GitlabUpdateError: If the server cannot perform the request. - """ - updated_data = self._get_updated_data() - - # call the manager - server_data = self.manager.update(None, updated_data, **kwargs) - self._update_attrs(server_data) - - -class GroupLabelManager(ListMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTManager): - _path = "/groups/%(group_id)s/labels" - _obj_cls = GroupLabel - _from_parent_attrs = {"group_id": "id"} - _create_attrs = RequiredOptional( - required=("name", "color"), optional=("description", "priority") - ) - _update_attrs = RequiredOptional( - required=("name",), optional=("new_name", "color", "description", "priority") - ) - - # Update without ID. - def update(self, name, new_data=None, **kwargs): - """Update a Label on the server. - - Args: - name: The name of the label - **kwargs: Extra options to send to the server (e.g. sudo) - """ - new_data = new_data or {} - if name: - new_data["name"] = name - return super().update(id=None, new_data=new_data, **kwargs) - - # Delete without ID. - @exc.on_http_error(exc.GitlabDeleteError) - def delete(self, name, **kwargs): - """Delete a Label on the server. - - Args: - name: The name of the label - **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 - """ - self.gitlab.http_delete(self.path, query_data={"name": name}, **kwargs) - - -class ProjectLabel(SubscribableMixin, SaveMixin, ObjectDeleteMixin, RESTObject): - _id_attr = "name" - - # Update without ID, but we need an ID to get from list. - @exc.on_http_error(exc.GitlabUpdateError) - def save(self, **kwargs): - """Saves 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) - - Raises: - GitlabAuthenticationError: If authentication is not correct. - GitlabUpdateError: If the server cannot perform the request. - """ - updated_data = self._get_updated_data() - - # call the manager - server_data = self.manager.update(None, updated_data, **kwargs) - self._update_attrs(server_data) - - -class ProjectLabelManager( - RetrieveMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTManager -): - _path = "/projects/%(project_id)s/labels" - _obj_cls = ProjectLabel - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("name", "color"), optional=("description", "priority") - ) - _update_attrs = RequiredOptional( - required=("name",), optional=("new_name", "color", "description", "priority") - ) - - # Update without ID. - def update(self, name, new_data=None, **kwargs): - """Update a Label on the server. - - Args: - name: The name of the label - **kwargs: Extra options to send to the server (e.g. sudo) - """ - new_data = new_data or {} - if name: - new_data["name"] = name - return super().update(id=None, new_data=new_data, **kwargs) - - # Delete without ID. - @exc.on_http_error(exc.GitlabDeleteError) - def delete(self, name, **kwargs): - """Delete a Label on the server. - - Args: - name: The name of the label - **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 - """ - self.gitlab.http_delete(self.path, query_data={"name": name}, **kwargs) diff --git a/gitlab/v4/objects/ldap.py b/gitlab/v4/objects/ldap.py deleted file mode 100644 index e0202a1..0000000 --- a/gitlab/v4/objects/ldap.py +++ /dev/null @@ -1,51 +0,0 @@ -from gitlab import exceptions as exc -from gitlab.base import RESTManager, RESTObject, RESTObjectList - -__all__ = [ - "LDAPGroup", - "LDAPGroupManager", -] - - -class LDAPGroup(RESTObject): - _id_attr = None - - -class LDAPGroupManager(RESTManager): - _path = "/ldap/groups" - _obj_cls = LDAPGroup - _list_filters = ("search", "provider") - - @exc.on_http_error(exc.GitlabListError) - def list(self, **kwargs): - """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 - """ - data = kwargs.copy() - if self.gitlab.per_page: - data.setdefault("per_page", self.gitlab.per_page) - - if "provider" in data: - path = "/ldap/%s/groups" % data["provider"] - else: - path = self._path - - obj = self.gitlab.http_list(path, **data) - if isinstance(obj, list): - return [self._obj_cls(self, item) for item in obj] - else: - return RESTObjectList(self, self._obj_cls, obj) diff --git a/gitlab/v4/objects/members.py b/gitlab/v4/objects/members.py deleted file mode 100644 index 0c92185..0000000 --- a/gitlab/v4/objects/members.py +++ /dev/null @@ -1,92 +0,0 @@ -from gitlab import types -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import ( - CRUDMixin, - DeleteMixin, - ListMixin, - ObjectDeleteMixin, - RetrieveMixin, - SaveMixin, -) - -__all__ = [ - "GroupBillableMember", - "GroupBillableMemberManager", - "GroupBillableMemberMembership", - "GroupBillableMemberMembershipManager", - "GroupMember", - "GroupMemberManager", - "GroupMemberAllManager", - "ProjectMember", - "ProjectMemberManager", - "ProjectMemberAllManager", -] - - -class GroupMember(SaveMixin, ObjectDeleteMixin, RESTObject): - _short_print_attr = "username" - - -class GroupMemberManager(CRUDMixin, RESTManager): - _path = "/groups/%(group_id)s/members" - _obj_cls = GroupMember - _from_parent_attrs = {"group_id": "id"} - _create_attrs = RequiredOptional( - required=("access_level", "user_id"), optional=("expires_at",) - ) - _update_attrs = RequiredOptional( - required=("access_level",), optional=("expires_at",) - ) - _types = {"user_ids": types.ListAttribute} - - -class GroupBillableMember(ObjectDeleteMixin, RESTObject): - _short_print_attr = "username" - - memberships: "GroupBillableMemberMembershipManager" - - -class GroupBillableMemberManager(ListMixin, DeleteMixin, RESTManager): - _path = "/groups/%(group_id)s/billable_members" - _obj_cls = GroupBillableMember - _from_parent_attrs = {"group_id": "id"} - _list_filters = ("search", "sort") - - -class GroupBillableMemberMembership(RESTObject): - _id_attr = "user_id" - - -class GroupBillableMemberMembershipManager(ListMixin, RESTManager): - _path = "/groups/%(group_id)s/billable_members/%(user_id)s/memberships" - _obj_cls = GroupBillableMemberMembership - _from_parent_attrs = {"group_id": "group_id", "user_id": "id"} - - -class GroupMemberAllManager(RetrieveMixin, RESTManager): - _path = "/groups/%(group_id)s/members/all" - _obj_cls = GroupMember - _from_parent_attrs = {"group_id": "id"} - - -class ProjectMember(SaveMixin, ObjectDeleteMixin, RESTObject): - _short_print_attr = "username" - - -class ProjectMemberManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/members" - _obj_cls = ProjectMember - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("access_level", "user_id"), optional=("expires_at",) - ) - _update_attrs = RequiredOptional( - required=("access_level",), optional=("expires_at",) - ) - _types = {"user_ids": types.ListAttribute} - - -class ProjectMemberAllManager(RetrieveMixin, RESTManager): - _path = "/projects/%(project_id)s/members/all" - _obj_cls = ProjectMember - _from_parent_attrs = {"project_id": "id"} diff --git a/gitlab/v4/objects/merge_request_approvals.py b/gitlab/v4/objects/merge_request_approvals.py deleted file mode 100644 index 4a41ca4..0000000 --- a/gitlab/v4/objects/merge_request_approvals.py +++ /dev/null @@ -1,206 +0,0 @@ -from gitlab import exceptions as exc -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import ( - CreateMixin, - DeleteMixin, - GetWithoutIdMixin, - ListMixin, - ObjectDeleteMixin, - SaveMixin, - UpdateMixin, -) - -__all__ = [ - "ProjectApproval", - "ProjectApprovalManager", - "ProjectApprovalRule", - "ProjectApprovalRuleManager", - "ProjectMergeRequestApproval", - "ProjectMergeRequestApprovalManager", - "ProjectMergeRequestApprovalRule", - "ProjectMergeRequestApprovalRuleManager", -] - - -class ProjectApproval(SaveMixin, RESTObject): - _id_attr = None - - -class ProjectApprovalManager(GetWithoutIdMixin, UpdateMixin, RESTManager): - _path = "/projects/%(project_id)s/approvals" - _obj_cls = ProjectApproval - _from_parent_attrs = {"project_id": "id"} - _update_attrs = RequiredOptional( - optional=( - "approvals_before_merge", - "reset_approvals_on_push", - "disable_overriding_approvers_per_merge_request", - "merge_requests_author_approval", - "merge_requests_disable_committers_approval", - ), - ) - _update_uses_post = True - - @exc.on_http_error(exc.GitlabUpdateError) - def set_approvers(self, approver_ids=None, approver_group_ids=None, **kwargs): - """Change project-level allowed approvers and approver groups. - - Args: - approver_ids (list): User IDs that can approve MRs - approver_group_ids (list): Group IDs whose members can approve MRs - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabUpdateError: If the server failed to perform the request - """ - approver_ids = approver_ids or [] - approver_group_ids = approver_group_ids or [] - - path = "/projects/%s/approvers" % self._parent.get_id() - data = {"approver_ids": approver_ids, "approver_group_ids": approver_group_ids} - self.gitlab.http_put(path, post_data=data, **kwargs) - - -class ProjectApprovalRule(SaveMixin, ObjectDeleteMixin, RESTObject): - _id_attr = "id" - - -class ProjectApprovalRuleManager( - ListMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTManager -): - _path = "/projects/%(project_id)s/approval_rules" - _obj_cls = ProjectApprovalRule - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("name", "approvals_required"), - optional=("user_ids", "group_ids", "protected_branch_ids"), - ) - - -class ProjectMergeRequestApproval(SaveMixin, RESTObject): - _id_attr = None - - -class ProjectMergeRequestApprovalManager(GetWithoutIdMixin, UpdateMixin, RESTManager): - _path = "/projects/%(project_id)s/merge_requests/%(mr_iid)s/approvals" - _obj_cls = ProjectMergeRequestApproval - _from_parent_attrs = {"project_id": "project_id", "mr_iid": "iid"} - _update_attrs = RequiredOptional(required=("approvals_required",)) - _update_uses_post = True - - @exc.on_http_error(exc.GitlabUpdateError) - def set_approvers( - self, - approvals_required, - approver_ids=None, - approver_group_ids=None, - approval_rule_name="name", - **kwargs - ): - """Change MR-level allowed approvers and approver groups. - - Args: - approvals_required (integer): The number of required approvals for this rule - approver_ids (list of integers): User IDs that can approve MRs - approver_group_ids (list): Group IDs whose members can approve MRs - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabUpdateError: If the server failed to perform the request - """ - approver_ids = approver_ids or [] - approver_group_ids = approver_group_ids or [] - - data = { - "name": approval_rule_name, - "approvals_required": approvals_required, - "rule_type": "regular", - "user_ids": approver_ids, - "group_ids": approver_group_ids, - } - approval_rules = self._parent.approval_rules - """ update any existing approval rule matching the name""" - existing_approval_rules = approval_rules.list() - for ar in existing_approval_rules: - if ar.name == approval_rule_name: - ar.user_ids = data["user_ids"] - ar.approvals_required = data["approvals_required"] - ar.group_ids = data["group_ids"] - ar.save() - return ar - """ if there was no rule matching the rule name, create a new one""" - return approval_rules.create(data=data) - - -class ProjectMergeRequestApprovalRule(SaveMixin, RESTObject): - _id_attr = "approval_rule_id" - _short_print_attr = "approval_rule" - - @exc.on_http_error(exc.GitlabUpdateError) - def save(self, **kwargs): - """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 - """ - # There is a mismatch between the name of our id attribute and the put REST API name for the - # project_id, so we override it here. - self.approval_rule_id = self.id - self.merge_request_iid = self._parent_attrs["mr_iid"] - self.id = self._parent_attrs["project_id"] - # save will update self.id with the result from the server, so no need to overwrite with - # what it was before we overwrote it.""" - SaveMixin.save(self, **kwargs) - - -class ProjectMergeRequestApprovalRuleManager( - ListMixin, UpdateMixin, CreateMixin, RESTManager -): - _path = "/projects/%(project_id)s/merge_requests/%(mr_iid)s/approval_rules" - _obj_cls = ProjectMergeRequestApprovalRule - _from_parent_attrs = {"project_id": "project_id", "mr_iid": "iid"} - _list_filters = ("name", "rule_type") - _update_attrs = RequiredOptional( - required=( - "id", - "merge_request_iid", - "approval_rule_id", - "name", - "approvals_required", - ), - optional=("user_ids", "group_ids"), - ) - # Important: When approval_project_rule_id is set, the name, users and groups of - # project-level rule will be copied. The approvals_required specified will be used. """ - _create_attrs = RequiredOptional( - required=("id", "merge_request_iid", "name", "approvals_required"), - optional=("approval_project_rule_id", "user_ids", "group_ids"), - ) - - def create(self, data, **kwargs): - """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 or - 'ref_name', 'stage', 'name', 'all') - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCreateError: If the server cannot perform the request - - Returns: - RESTObject: A new instance of the manage object class build with - the data sent by the server - """ - new_data = data.copy() - new_data["id"] = self._from_parent_attrs["project_id"] - new_data["merge_request_iid"] = self._from_parent_attrs["mr_iid"] - return CreateMixin.create(self, new_data, **kwargs) diff --git a/gitlab/v4/objects/merge_requests.py b/gitlab/v4/objects/merge_requests.py deleted file mode 100644 index 4def98c..0000000 --- a/gitlab/v4/objects/merge_requests.py +++ /dev/null @@ -1,439 +0,0 @@ -from gitlab import cli -from gitlab import exceptions as exc -from gitlab import types -from gitlab.base import RequiredOptional, RESTManager, RESTObject, RESTObjectList -from gitlab.mixins import ( - CRUDMixin, - ListMixin, - ObjectDeleteMixin, - ParticipantsMixin, - RetrieveMixin, - SaveMixin, - SubscribableMixin, - TimeTrackingMixin, - TodoMixin, -) - -from .award_emojis import ProjectMergeRequestAwardEmojiManager # noqa: F401 -from .commits import ProjectCommit, ProjectCommitManager -from .discussions import ProjectMergeRequestDiscussionManager # noqa: F401 -from .events import ( # noqa: F401 - ProjectMergeRequestResourceLabelEventManager, - ProjectMergeRequestResourceMilestoneEventManager, - ProjectMergeRequestResourceStateEventManager, -) -from .issues import ProjectIssue, ProjectIssueManager -from .merge_request_approvals import ( # noqa: F401 - ProjectMergeRequestApprovalManager, - ProjectMergeRequestApprovalRuleManager, -) -from .notes import ProjectMergeRequestNoteManager # noqa: F401 -from .pipelines import ProjectMergeRequestPipelineManager # noqa: F401 - -__all__ = [ - "MergeRequest", - "MergeRequestManager", - "GroupMergeRequest", - "GroupMergeRequestManager", - "ProjectMergeRequest", - "ProjectMergeRequestManager", - "ProjectDeploymentMergeRequest", - "ProjectDeploymentMergeRequestManager", - "ProjectMergeRequestDiff", - "ProjectMergeRequestDiffManager", -] - - -class MergeRequest(RESTObject): - pass - - -class MergeRequestManager(ListMixin, RESTManager): - _path = "/merge_requests" - _obj_cls = MergeRequest - _list_filters = ( - "state", - "order_by", - "sort", - "milestone", - "view", - "labels", - "with_labels_details", - "with_merge_status_recheck", - "created_after", - "created_before", - "updated_after", - "updated_before", - "scope", - "author_id", - "author_username", - "assignee_id", - "approver_ids", - "approved_by_ids", - "reviewer_id", - "reviewer_username", - "my_reaction_emoji", - "source_branch", - "target_branch", - "search", - "in", - "wip", - "not", - "environment", - "deployed_before", - "deployed_after", - ) - _types = { - "approver_ids": types.ListAttribute, - "approved_by_ids": types.ListAttribute, - "in": types.ListAttribute, - "labels": types.ListAttribute, - } - - -class GroupMergeRequest(RESTObject): - pass - - -class GroupMergeRequestManager(ListMixin, RESTManager): - _path = "/groups/%(group_id)s/merge_requests" - _obj_cls = GroupMergeRequest - _from_parent_attrs = {"group_id": "id"} - _list_filters = ( - "state", - "order_by", - "sort", - "milestone", - "view", - "labels", - "created_after", - "created_before", - "updated_after", - "updated_before", - "scope", - "author_id", - "assignee_id", - "approver_ids", - "approved_by_ids", - "my_reaction_emoji", - "source_branch", - "target_branch", - "search", - "wip", - ) - _types = { - "approver_ids": types.ListAttribute, - "approved_by_ids": types.ListAttribute, - "labels": types.ListAttribute, - } - - -class ProjectMergeRequest( - SubscribableMixin, - TodoMixin, - TimeTrackingMixin, - ParticipantsMixin, - SaveMixin, - ObjectDeleteMixin, - RESTObject, -): - _id_attr = "iid" - - approval_rules: ProjectMergeRequestApprovalRuleManager - approvals: ProjectMergeRequestApprovalManager - awardemojis: ProjectMergeRequestAwardEmojiManager - diffs: "ProjectMergeRequestDiffManager" - discussions: ProjectMergeRequestDiscussionManager - notes: ProjectMergeRequestNoteManager - pipelines: ProjectMergeRequestPipelineManager - resourcelabelevents: ProjectMergeRequestResourceLabelEventManager - resourcemilestoneevents: ProjectMergeRequestResourceMilestoneEventManager - resourcestateevents: ProjectMergeRequestResourceStateEventManager - - @cli.register_custom_action("ProjectMergeRequest") - @exc.on_http_error(exc.GitlabMROnBuildSuccessError) - def cancel_merge_when_pipeline_succeeds(self, **kwargs): - """Cancel merge when the pipeline succeeds. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabMROnBuildSuccessError: If the server could not handle the - request - """ - - path = "%s/%s/cancel_merge_when_pipeline_succeeds" % ( - self.manager.path, - self.get_id(), - ) - server_data = self.manager.gitlab.http_put(path, **kwargs) - self._update_attrs(server_data) - - @cli.register_custom_action("ProjectMergeRequest") - @exc.on_http_error(exc.GitlabListError) - def closes_issues(self, **kwargs): - """List issues that will close on merge." - - 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: List of issues - """ - path = "%s/%s/closes_issues" % (self.manager.path, self.get_id()) - data_list = self.manager.gitlab.http_list(path, as_list=False, **kwargs) - manager = ProjectIssueManager(self.manager.gitlab, parent=self.manager._parent) - return RESTObjectList(manager, ProjectIssue, data_list) - - @cli.register_custom_action("ProjectMergeRequest") - @exc.on_http_error(exc.GitlabListError) - def commits(self, **kwargs): - """List the merge request commits. - - 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 commits - """ - - path = "%s/%s/commits" % (self.manager.path, self.get_id()) - data_list = self.manager.gitlab.http_list(path, as_list=False, **kwargs) - manager = ProjectCommitManager(self.manager.gitlab, parent=self.manager._parent) - return RESTObjectList(manager, ProjectCommit, data_list) - - @cli.register_custom_action("ProjectMergeRequest") - @exc.on_http_error(exc.GitlabListError) - def changes(self, **kwargs): - """List the merge request changes. - - Args: - **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: List of changes - """ - path = "%s/%s/changes" % (self.manager.path, self.get_id()) - return self.manager.gitlab.http_get(path, **kwargs) - - @cli.register_custom_action("ProjectMergeRequest", tuple(), ("sha",)) - @exc.on_http_error(exc.GitlabMRApprovalError) - def approve(self, sha=None, **kwargs): - """Approve the merge request. - - Args: - sha (str): Head SHA of MR - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabMRApprovalError: If the approval failed - """ - path = "%s/%s/approve" % (self.manager.path, self.get_id()) - data = {} - if sha: - data["sha"] = sha - - server_data = self.manager.gitlab.http_post(path, post_data=data, **kwargs) - self._update_attrs(server_data) - - @cli.register_custom_action("ProjectMergeRequest") - @exc.on_http_error(exc.GitlabMRApprovalError) - def unapprove(self, **kwargs): - """Unapprove the merge request. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabMRApprovalError: If the unapproval failed - """ - path = "%s/%s/unapprove" % (self.manager.path, self.get_id()) - data = {} - - server_data = self.manager.gitlab.http_post(path, post_data=data, **kwargs) - self._update_attrs(server_data) - - @cli.register_custom_action("ProjectMergeRequest") - @exc.on_http_error(exc.GitlabMRRebaseError) - def rebase(self, **kwargs): - """Attempt to rebase the source branch onto the target branch - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabMRRebaseError: If rebasing failed - """ - path = "%s/%s/rebase" % (self.manager.path, self.get_id()) - data = {} - return self.manager.gitlab.http_put(path, post_data=data, **kwargs) - - @cli.register_custom_action("ProjectMergeRequest") - @exc.on_http_error(exc.GitlabGetError) - def merge_ref(self, **kwargs): - """Attempt to merge changes between source and target branches into - `refs/merge-requests/:iid/merge`. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabGetError: If cannot be merged - """ - path = "%s/%s/merge_ref" % (self.manager.path, self.get_id()) - return self.manager.gitlab.http_get(path, **kwargs) - - @cli.register_custom_action( - "ProjectMergeRequest", - tuple(), - ( - "merge_commit_message", - "should_remove_source_branch", - "merge_when_pipeline_succeeds", - ), - ) - @exc.on_http_error(exc.GitlabMRClosedError) - def merge( - self, - merge_commit_message=None, - should_remove_source_branch=False, - merge_when_pipeline_succeeds=False, - **kwargs - ): - """Accept the merge request. - - Args: - merge_commit_message (bool): Commit message - should_remove_source_branch (bool): If True, removes the source - branch - merge_when_pipeline_succeeds (bool): Wait for the build to succeed, - then merge - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabMRClosedError: If the merge failed - """ - path = "%s/%s/merge" % (self.manager.path, self.get_id()) - data = {} - if merge_commit_message: - data["merge_commit_message"] = merge_commit_message - if should_remove_source_branch is not None: - data["should_remove_source_branch"] = should_remove_source_branch - if merge_when_pipeline_succeeds: - data["merge_when_pipeline_succeeds"] = True - - server_data = self.manager.gitlab.http_put(path, post_data=data, **kwargs) - self._update_attrs(server_data) - - -class ProjectMergeRequestManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/merge_requests" - _obj_cls = ProjectMergeRequest - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("source_branch", "target_branch", "title"), - optional=( - "assignee_id", - "description", - "target_project_id", - "labels", - "milestone_id", - "remove_source_branch", - "allow_maintainer_to_push", - "squash", - "reviewer_ids", - ), - ) - _update_attrs = RequiredOptional( - optional=( - "target_branch", - "assignee_id", - "title", - "description", - "state_event", - "labels", - "milestone_id", - "remove_source_branch", - "discussion_locked", - "allow_maintainer_to_push", - "squash", - "reviewer_ids", - ), - ) - _list_filters = ( - "state", - "order_by", - "sort", - "milestone", - "view", - "labels", - "created_after", - "created_before", - "updated_after", - "updated_before", - "scope", - "iids", - "author_id", - "assignee_id", - "approver_ids", - "approved_by_ids", - "my_reaction_emoji", - "source_branch", - "target_branch", - "search", - "wip", - ) - _types = { - "approver_ids": types.ListAttribute, - "approved_by_ids": types.ListAttribute, - "iids": types.ListAttribute, - "labels": types.ListAttribute, - } - - -class ProjectDeploymentMergeRequest(MergeRequest): - pass - - -class ProjectDeploymentMergeRequestManager(MergeRequestManager): - _path = "/projects/%(project_id)s/deployments/%(deployment_id)s/merge_requests" - _obj_cls = ProjectDeploymentMergeRequest - _from_parent_attrs = {"deployment_id": "id", "project_id": "project_id"} - - -class ProjectMergeRequestDiff(RESTObject): - pass - - -class ProjectMergeRequestDiffManager(RetrieveMixin, RESTManager): - _path = "/projects/%(project_id)s/merge_requests/%(mr_iid)s/versions" - _obj_cls = ProjectMergeRequestDiff - _from_parent_attrs = {"project_id": "project_id", "mr_iid": "iid"} diff --git a/gitlab/v4/objects/milestones.py b/gitlab/v4/objects/milestones.py deleted file mode 100644 index 0a53e1b..0000000 --- a/gitlab/v4/objects/milestones.py +++ /dev/null @@ -1,164 +0,0 @@ -from gitlab import cli -from gitlab import exceptions as exc -from gitlab import types -from gitlab.base import RequiredOptional, RESTManager, RESTObject, RESTObjectList -from gitlab.mixins import CRUDMixin, ObjectDeleteMixin, SaveMixin - -from .issues import GroupIssue, GroupIssueManager, ProjectIssue, ProjectIssueManager -from .merge_requests import ( - GroupMergeRequest, - ProjectMergeRequest, - ProjectMergeRequestManager, -) - -__all__ = [ - "GroupMilestone", - "GroupMilestoneManager", - "ProjectMilestone", - "ProjectMilestoneManager", -] - - -class GroupMilestone(SaveMixin, ObjectDeleteMixin, RESTObject): - _short_print_attr = "title" - - @cli.register_custom_action("GroupMilestone") - @exc.on_http_error(exc.GitlabListError) - def issues(self, **kwargs): - """List issues related to this milestone. - - 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 issues - """ - - path = "%s/%s/issues" % (self.manager.path, self.get_id()) - data_list = self.manager.gitlab.http_list(path, as_list=False, **kwargs) - manager = GroupIssueManager(self.manager.gitlab, parent=self.manager._parent) - # FIXME(gpocentek): the computed manager path is not correct - return RESTObjectList(manager, GroupIssue, data_list) - - @cli.register_custom_action("GroupMilestone") - @exc.on_http_error(exc.GitlabListError) - def merge_requests(self, **kwargs): - """List the merge requests related to this milestone. - - 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 merge requests - """ - path = "%s/%s/merge_requests" % (self.manager.path, self.get_id()) - data_list = self.manager.gitlab.http_list(path, as_list=False, **kwargs) - manager = GroupIssueManager(self.manager.gitlab, parent=self.manager._parent) - # FIXME(gpocentek): the computed manager path is not correct - return RESTObjectList(manager, GroupMergeRequest, data_list) - - -class GroupMilestoneManager(CRUDMixin, RESTManager): - _path = "/groups/%(group_id)s/milestones" - _obj_cls = GroupMilestone - _from_parent_attrs = {"group_id": "id"} - _create_attrs = RequiredOptional( - required=("title",), optional=("description", "due_date", "start_date") - ) - _update_attrs = RequiredOptional( - optional=("title", "description", "due_date", "start_date", "state_event"), - ) - _list_filters = ("iids", "state", "search") - _types = {"iids": types.ListAttribute} - - -class ProjectMilestone(SaveMixin, ObjectDeleteMixin, RESTObject): - _short_print_attr = "title" - - @cli.register_custom_action("ProjectMilestone") - @exc.on_http_error(exc.GitlabListError) - def issues(self, **kwargs): - """List issues related to this milestone. - - 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 issues - """ - - path = "%s/%s/issues" % (self.manager.path, self.get_id()) - data_list = self.manager.gitlab.http_list(path, as_list=False, **kwargs) - manager = ProjectIssueManager(self.manager.gitlab, parent=self.manager._parent) - # FIXME(gpocentek): the computed manager path is not correct - return RESTObjectList(manager, ProjectIssue, data_list) - - @cli.register_custom_action("ProjectMilestone") - @exc.on_http_error(exc.GitlabListError) - def merge_requests(self, **kwargs): - """List the merge requests related to this milestone. - - 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 merge requests - """ - path = "%s/%s/merge_requests" % (self.manager.path, self.get_id()) - data_list = self.manager.gitlab.http_list(path, as_list=False, **kwargs) - manager = ProjectMergeRequestManager( - self.manager.gitlab, parent=self.manager._parent - ) - # FIXME(gpocentek): the computed manager path is not correct - return RESTObjectList(manager, ProjectMergeRequest, data_list) - - -class ProjectMilestoneManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/milestones" - _obj_cls = ProjectMilestone - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("title",), - optional=("description", "due_date", "start_date", "state_event"), - ) - _update_attrs = RequiredOptional( - optional=("title", "description", "due_date", "start_date", "state_event"), - ) - _list_filters = ("iids", "state", "search") - _types = {"iids": types.ListAttribute} diff --git a/gitlab/v4/objects/namespaces.py b/gitlab/v4/objects/namespaces.py deleted file mode 100644 index deee281..0000000 --- a/gitlab/v4/objects/namespaces.py +++ /dev/null @@ -1,17 +0,0 @@ -from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import RetrieveMixin - -__all__ = [ - "Namespace", - "NamespaceManager", -] - - -class Namespace(RESTObject): - pass - - -class NamespaceManager(RetrieveMixin, RESTManager): - _path = "/namespaces" - _obj_cls = Namespace - _list_filters = ("search",) diff --git a/gitlab/v4/objects/notes.py b/gitlab/v4/objects/notes.py deleted file mode 100644 index cbd237e..0000000 --- a/gitlab/v4/objects/notes.py +++ /dev/null @@ -1,169 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import ( - CreateMixin, - CRUDMixin, - DeleteMixin, - GetMixin, - ObjectDeleteMixin, - RetrieveMixin, - SaveMixin, - UpdateMixin, -) - -from .award_emojis import ( # noqa: F401 - ProjectIssueNoteAwardEmojiManager, - ProjectMergeRequestNoteAwardEmojiManager, - ProjectSnippetNoteAwardEmojiManager, -) - -__all__ = [ - "ProjectNote", - "ProjectNoteManager", - "ProjectCommitDiscussionNote", - "ProjectCommitDiscussionNoteManager", - "ProjectIssueNote", - "ProjectIssueNoteManager", - "ProjectIssueDiscussionNote", - "ProjectIssueDiscussionNoteManager", - "ProjectMergeRequestNote", - "ProjectMergeRequestNoteManager", - "ProjectMergeRequestDiscussionNote", - "ProjectMergeRequestDiscussionNoteManager", - "ProjectSnippetNote", - "ProjectSnippetNoteManager", - "ProjectSnippetDiscussionNote", - "ProjectSnippetDiscussionNoteManager", -] - - -class ProjectNote(RESTObject): - pass - - -class ProjectNoteManager(RetrieveMixin, RESTManager): - _path = "/projects/%(project_id)s/notes" - _obj_cls = ProjectNote - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional(required=("body",)) - - -class ProjectCommitDiscussionNote(SaveMixin, ObjectDeleteMixin, RESTObject): - pass - - -class ProjectCommitDiscussionNoteManager( - GetMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTManager -): - _path = ( - "/projects/%(project_id)s/repository/commits/%(commit_id)s/" - "discussions/%(discussion_id)s/notes" - ) - _obj_cls = ProjectCommitDiscussionNote - _from_parent_attrs = { - "project_id": "project_id", - "commit_id": "commit_id", - "discussion_id": "id", - } - _create_attrs = RequiredOptional( - required=("body",), optional=("created_at", "position") - ) - _update_attrs = RequiredOptional(required=("body",)) - - -class ProjectIssueNote(SaveMixin, ObjectDeleteMixin, RESTObject): - awardemojis: ProjectIssueNoteAwardEmojiManager - - -class ProjectIssueNoteManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/issues/%(issue_iid)s/notes" - _obj_cls = ProjectIssueNote - _from_parent_attrs = {"project_id": "project_id", "issue_iid": "iid"} - _create_attrs = RequiredOptional(required=("body",), optional=("created_at",)) - _update_attrs = RequiredOptional(required=("body",)) - - -class ProjectIssueDiscussionNote(SaveMixin, ObjectDeleteMixin, RESTObject): - pass - - -class ProjectIssueDiscussionNoteManager( - GetMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTManager -): - _path = ( - "/projects/%(project_id)s/issues/%(issue_iid)s/" - "discussions/%(discussion_id)s/notes" - ) - _obj_cls = ProjectIssueDiscussionNote - _from_parent_attrs = { - "project_id": "project_id", - "issue_iid": "issue_iid", - "discussion_id": "id", - } - _create_attrs = RequiredOptional(required=("body",), optional=("created_at",)) - _update_attrs = RequiredOptional(required=("body",)) - - -class ProjectMergeRequestNote(SaveMixin, ObjectDeleteMixin, RESTObject): - awardemojis: ProjectMergeRequestNoteAwardEmojiManager - - -class ProjectMergeRequestNoteManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/merge_requests/%(mr_iid)s/notes" - _obj_cls = ProjectMergeRequestNote - _from_parent_attrs = {"project_id": "project_id", "mr_iid": "iid"} - _create_attrs = RequiredOptional(required=("body",)) - _update_attrs = RequiredOptional(required=("body",)) - - -class ProjectMergeRequestDiscussionNote(SaveMixin, ObjectDeleteMixin, RESTObject): - pass - - -class ProjectMergeRequestDiscussionNoteManager( - GetMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTManager -): - _path = ( - "/projects/%(project_id)s/merge_requests/%(mr_iid)s/" - "discussions/%(discussion_id)s/notes" - ) - _obj_cls = ProjectMergeRequestDiscussionNote - _from_parent_attrs = { - "project_id": "project_id", - "mr_iid": "mr_iid", - "discussion_id": "id", - } - _create_attrs = RequiredOptional(required=("body",), optional=("created_at",)) - _update_attrs = RequiredOptional(required=("body",)) - - -class ProjectSnippetNote(SaveMixin, ObjectDeleteMixin, RESTObject): - awardemojis: ProjectMergeRequestNoteAwardEmojiManager - - -class ProjectSnippetNoteManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/snippets/%(snippet_id)s/notes" - _obj_cls = ProjectSnippetNote - _from_parent_attrs = {"project_id": "project_id", "snippet_id": "id"} - _create_attrs = RequiredOptional(required=("body",)) - _update_attrs = RequiredOptional(required=("body",)) - - -class ProjectSnippetDiscussionNote(SaveMixin, ObjectDeleteMixin, RESTObject): - pass - - -class ProjectSnippetDiscussionNoteManager( - GetMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTManager -): - _path = ( - "/projects/%(project_id)s/snippets/%(snippet_id)s/" - "discussions/%(discussion_id)s/notes" - ) - _obj_cls = ProjectSnippetDiscussionNote - _from_parent_attrs = { - "project_id": "project_id", - "snippet_id": "snippet_id", - "discussion_id": "id", - } - _create_attrs = RequiredOptional(required=("body",), optional=("created_at",)) - _update_attrs = RequiredOptional(required=("body",)) diff --git a/gitlab/v4/objects/notification_settings.py b/gitlab/v4/objects/notification_settings.py deleted file mode 100644 index 3682ed0..0000000 --- a/gitlab/v4/objects/notification_settings.py +++ /dev/null @@ -1,57 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import GetWithoutIdMixin, SaveMixin, UpdateMixin - -__all__ = [ - "NotificationSettings", - "NotificationSettingsManager", - "GroupNotificationSettings", - "GroupNotificationSettingsManager", - "ProjectNotificationSettings", - "ProjectNotificationSettingsManager", -] - - -class NotificationSettings(SaveMixin, RESTObject): - _id_attr = None - - -class NotificationSettingsManager(GetWithoutIdMixin, UpdateMixin, RESTManager): - _path = "/notification_settings" - _obj_cls = NotificationSettings - - _update_attrs = RequiredOptional( - optional=( - "level", - "notification_email", - "new_note", - "new_issue", - "reopen_issue", - "close_issue", - "reassign_issue", - "new_merge_request", - "reopen_merge_request", - "close_merge_request", - "reassign_merge_request", - "merge_merge_request", - ), - ) - - -class GroupNotificationSettings(NotificationSettings): - pass - - -class GroupNotificationSettingsManager(NotificationSettingsManager): - _path = "/groups/%(group_id)s/notification_settings" - _obj_cls = GroupNotificationSettings - _from_parent_attrs = {"group_id": "id"} - - -class ProjectNotificationSettings(NotificationSettings): - pass - - -class ProjectNotificationSettingsManager(NotificationSettingsManager): - _path = "/projects/%(project_id)s/notification_settings" - _obj_cls = ProjectNotificationSettings - _from_parent_attrs = {"project_id": "id"} diff --git a/gitlab/v4/objects/packages.py b/gitlab/v4/objects/packages.py deleted file mode 100644 index e76a5c6..0000000 --- a/gitlab/v4/objects/packages.py +++ /dev/null @@ -1,168 +0,0 @@ -from pathlib import Path -from typing import Any, Callable, Optional, TYPE_CHECKING, Union - -import requests - -from gitlab import cli -from gitlab import exceptions as exc -from gitlab import utils -from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import DeleteMixin, GetMixin, ListMixin, ObjectDeleteMixin - -__all__ = [ - "GenericPackage", - "GenericPackageManager", - "GroupPackage", - "GroupPackageManager", - "ProjectPackage", - "ProjectPackageManager", - "ProjectPackageFile", - "ProjectPackageFileManager", -] - - -class GenericPackage(RESTObject): - _id_attr = "package_name" - - -class GenericPackageManager(RESTManager): - _path = "/projects/%(project_id)s/packages/generic" - _obj_cls = GenericPackage - _from_parent_attrs = {"project_id": "id"} - - @cli.register_custom_action( - "GenericPackageManager", - ("package_name", "package_version", "file_name", "path"), - ) - @exc.on_http_error(exc.GitlabUploadError) - def upload( - self, - package_name: str, - package_version: str, - file_name: str, - path: Union[str, Path], - **kwargs, - ) -> GenericPackage: - """Upload a file as a generic package. - - Args: - package_name (str): The package name. Must follow generic package - name regex rules - package_version (str): The package version. Must follow semantic - version regex rules - file_name (str): The name of the file as uploaded in the registry - path (str): The path to a local file to upload - - Raises: - GitlabConnectionError: If the server cannot be reached - GitlabUploadError: If the file upload fails - GitlabUploadError: If ``filepath`` cannot be read - - Returns: - GenericPackage: An object storing the metadata of the uploaded package. - """ - - try: - with open(path, "rb") as f: - file_data = f.read() - except OSError: - raise exc.GitlabUploadError(f"Failed to read package file {path}") - - url = f"{self._computed_path}/{package_name}/{package_version}/{file_name}" - server_data = self.gitlab.http_put(url, post_data=file_data, raw=True, **kwargs) - - return self._obj_cls( - self, - attrs={ - "package_name": package_name, - "package_version": package_version, - "file_name": file_name, - "path": path, - "message": server_data["message"], - }, - ) - - @cli.register_custom_action( - "GenericPackageManager", - ("package_name", "package_version", "file_name"), - ) - @exc.on_http_error(exc.GitlabGetError) - def download( - self, - package_name: str, - package_version: str, - file_name: str, - streamed: bool = False, - action: Optional[Callable] = None, - chunk_size: int = 1024, - **kwargs: Any, - ) -> Optional[bytes]: - """Download a generic package. - - Args: - package_name (str): The package name. - package_version (str): The package version. - file_name (str): The name of the file in the registry - 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 package content if streamed is False, None otherwise - """ - path = f"{self._computed_path}/{package_name}/{package_version}/{file_name}" - result = self.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 GroupPackage(RESTObject): - pass - - -class GroupPackageManager(ListMixin, RESTManager): - _path = "/groups/%(group_id)s/packages" - _obj_cls = GroupPackage - _from_parent_attrs = {"group_id": "id"} - _list_filters = ( - "exclude_subgroups", - "order_by", - "sort", - "package_type", - "package_name", - ) - - -class ProjectPackage(ObjectDeleteMixin, RESTObject): - package_files: "ProjectPackageFileManager" - - -class ProjectPackageManager(ListMixin, GetMixin, DeleteMixin, RESTManager): - _path = "/projects/%(project_id)s/packages" - _obj_cls = ProjectPackage - _from_parent_attrs = {"project_id": "id"} - _list_filters = ( - "order_by", - "sort", - "package_type", - "package_name", - ) - - -class ProjectPackageFile(RESTObject): - pass - - -class ProjectPackageFileManager(ListMixin, RESTManager): - _path = "/projects/%(project_id)s/packages/%(package_id)s/package_files" - _obj_cls = ProjectPackageFile - _from_parent_attrs = {"project_id": "project_id", "package_id": "id"} diff --git a/gitlab/v4/objects/pages.py b/gitlab/v4/objects/pages.py deleted file mode 100644 index 709d9f0..0000000 --- a/gitlab/v4/objects/pages.py +++ /dev/null @@ -1,32 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CRUDMixin, ListMixin, ObjectDeleteMixin, SaveMixin - -__all__ = [ - "PagesDomain", - "PagesDomainManager", - "ProjectPagesDomain", - "ProjectPagesDomainManager", -] - - -class PagesDomain(RESTObject): - _id_attr = "domain" - - -class PagesDomainManager(ListMixin, RESTManager): - _path = "/pages/domains" - _obj_cls = PagesDomain - - -class ProjectPagesDomain(SaveMixin, ObjectDeleteMixin, RESTObject): - _id_attr = "domain" - - -class ProjectPagesDomainManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/pages/domains" - _obj_cls = ProjectPagesDomain - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("domain",), optional=("certificate", "key") - ) - _update_attrs = RequiredOptional(optional=("certificate", "key")) diff --git a/gitlab/v4/objects/personal_access_tokens.py b/gitlab/v4/objects/personal_access_tokens.py deleted file mode 100644 index 6cdb305..0000000 --- a/gitlab/v4/objects/personal_access_tokens.py +++ /dev/null @@ -1,32 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CreateMixin, DeleteMixin, ListMixin, ObjectDeleteMixin - -__all__ = [ - "PersonalAccessToken", - "PersonalAccessTokenManager", - "UserPersonalAccessToken", - "UserPersonalAccessTokenManager", -] - - -class PersonalAccessToken(ObjectDeleteMixin, RESTObject): - pass - - -class PersonalAccessTokenManager(DeleteMixin, ListMixin, RESTManager): - _path = "/personal_access_tokens" - _obj_cls = PersonalAccessToken - _list_filters = ("user_id",) - - -class UserPersonalAccessToken(RESTObject): - pass - - -class UserPersonalAccessTokenManager(CreateMixin, RESTManager): - _path = "/users/%(user_id)s/personal_access_tokens" - _obj_cls = UserPersonalAccessToken - _from_parent_attrs = {"user_id": "id"} - _create_attrs = RequiredOptional( - required=("name", "scopes"), optional=("expires_at",) - ) diff --git a/gitlab/v4/objects/pipelines.py b/gitlab/v4/objects/pipelines.py deleted file mode 100644 index 2d212a6..0000000 --- a/gitlab/v4/objects/pipelines.py +++ /dev/null @@ -1,227 +0,0 @@ -from gitlab import cli -from gitlab import exceptions as exc -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import ( - CreateMixin, - CRUDMixin, - DeleteMixin, - GetWithoutIdMixin, - ListMixin, - ObjectDeleteMixin, - RefreshMixin, - RetrieveMixin, - SaveMixin, - UpdateMixin, -) - -__all__ = [ - "ProjectMergeRequestPipeline", - "ProjectMergeRequestPipelineManager", - "ProjectPipeline", - "ProjectPipelineManager", - "ProjectPipelineJob", - "ProjectPipelineJobManager", - "ProjectPipelineBridge", - "ProjectPipelineBridgeManager", - "ProjectPipelineVariable", - "ProjectPipelineVariableManager", - "ProjectPipelineScheduleVariable", - "ProjectPipelineScheduleVariableManager", - "ProjectPipelineSchedule", - "ProjectPipelineScheduleManager", - "ProjectPipelineTestReport", - "ProjectPipelineTestReportManager", -] - - -class ProjectMergeRequestPipeline(RESTObject): - pass - - -class ProjectMergeRequestPipelineManager(CreateMixin, ListMixin, RESTManager): - _path = "/projects/%(project_id)s/merge_requests/%(mr_iid)s/pipelines" - _obj_cls = ProjectMergeRequestPipeline - _from_parent_attrs = {"project_id": "project_id", "mr_iid": "iid"} - - -class ProjectPipeline(RefreshMixin, ObjectDeleteMixin, RESTObject): - bridges: "ProjectPipelineBridgeManager" - jobs: "ProjectPipelineJobManager" - test_report: "ProjectPipelineTestReportManager" - variables: "ProjectPipelineVariableManager" - - @cli.register_custom_action("ProjectPipeline") - @exc.on_http_error(exc.GitlabPipelineCancelError) - def cancel(self, **kwargs): - """Cancel the job. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabPipelineCancelError: If the request failed - """ - path = "%s/%s/cancel" % (self.manager.path, self.get_id()) - return self.manager.gitlab.http_post(path) - - @cli.register_custom_action("ProjectPipeline") - @exc.on_http_error(exc.GitlabPipelineRetryError) - def retry(self, **kwargs): - """Retry the job. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabPipelineRetryError: If the request failed - """ - path = "%s/%s/retry" % (self.manager.path, self.get_id()) - return self.manager.gitlab.http_post(path) - - -class ProjectPipelineManager(RetrieveMixin, CreateMixin, DeleteMixin, RESTManager): - _path = "/projects/%(project_id)s/pipelines" - _obj_cls = ProjectPipeline - _from_parent_attrs = {"project_id": "id"} - _list_filters = ( - "scope", - "status", - "ref", - "sha", - "yaml_errors", - "name", - "username", - "order_by", - "sort", - ) - _create_attrs = RequiredOptional(required=("ref",)) - - def create(self, data, **kwargs): - """Creates 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) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCreateError: If the server cannot perform the request - - Returns: - RESTObject: A new instance of the managed object class build with - the data sent by the server - """ - path = self.path[:-1] # drop the 's' - return CreateMixin.create(self, data, path=path, **kwargs) - - -class ProjectPipelineJob(RESTObject): - pass - - -class ProjectPipelineJobManager(ListMixin, RESTManager): - _path = "/projects/%(project_id)s/pipelines/%(pipeline_id)s/jobs" - _obj_cls = ProjectPipelineJob - _from_parent_attrs = {"project_id": "project_id", "pipeline_id": "id"} - _list_filters = ("scope", "include_retried") - - -class ProjectPipelineBridge(RESTObject): - pass - - -class ProjectPipelineBridgeManager(ListMixin, RESTManager): - _path = "/projects/%(project_id)s/pipelines/%(pipeline_id)s/bridges" - _obj_cls = ProjectPipelineBridge - _from_parent_attrs = {"project_id": "project_id", "pipeline_id": "id"} - _list_filters = ("scope",) - - -class ProjectPipelineVariable(RESTObject): - _id_attr = "key" - - -class ProjectPipelineVariableManager(ListMixin, RESTManager): - _path = "/projects/%(project_id)s/pipelines/%(pipeline_id)s/variables" - _obj_cls = ProjectPipelineVariable - _from_parent_attrs = {"project_id": "project_id", "pipeline_id": "id"} - - -class ProjectPipelineScheduleVariable(SaveMixin, ObjectDeleteMixin, RESTObject): - _id_attr = "key" - - -class ProjectPipelineScheduleVariableManager( - CreateMixin, UpdateMixin, DeleteMixin, RESTManager -): - _path = ( - "/projects/%(project_id)s/pipeline_schedules/" - "%(pipeline_schedule_id)s/variables" - ) - _obj_cls = ProjectPipelineScheduleVariable - _from_parent_attrs = {"project_id": "project_id", "pipeline_schedule_id": "id"} - _create_attrs = RequiredOptional(required=("key", "value")) - _update_attrs = RequiredOptional(required=("key", "value")) - - -class ProjectPipelineSchedule(SaveMixin, ObjectDeleteMixin, RESTObject): - variables: ProjectPipelineScheduleVariableManager - - @cli.register_custom_action("ProjectPipelineSchedule") - @exc.on_http_error(exc.GitlabOwnershipError) - def take_ownership(self, **kwargs): - """Update the owner of a pipeline schedule. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabOwnershipError: If the request failed - """ - path = "%s/%s/take_ownership" % (self.manager.path, self.get_id()) - server_data = self.manager.gitlab.http_post(path, **kwargs) - self._update_attrs(server_data) - - @cli.register_custom_action("ProjectPipelineSchedule") - @exc.on_http_error(exc.GitlabPipelinePlayError) - def play(self, **kwargs): - """Trigger a new scheduled pipeline, which runs immediately. - The next scheduled run of this pipeline is not affected. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabPipelinePlayError: If the request failed - """ - path = "%s/%s/play" % (self.manager.path, self.get_id()) - server_data = self.manager.gitlab.http_post(path, **kwargs) - self._update_attrs(server_data) - return server_data - - -class ProjectPipelineScheduleManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/pipeline_schedules" - _obj_cls = ProjectPipelineSchedule - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("description", "ref", "cron"), optional=("cron_timezone", "active") - ) - _update_attrs = RequiredOptional( - optional=("description", "ref", "cron", "cron_timezone", "active"), - ) - - -class ProjectPipelineTestReport(RESTObject): - _id_attr = None - - -class ProjectPipelineTestReportManager(GetWithoutIdMixin, RESTManager): - _path = "/projects/%(project_id)s/pipelines/%(pipeline_id)s/test_report" - _obj_cls = ProjectPipelineTestReport - _from_parent_attrs = {"project_id": "project_id", "pipeline_id": "id"} diff --git a/gitlab/v4/objects/project_access_tokens.py b/gitlab/v4/objects/project_access_tokens.py deleted file mode 100644 index f59ea85..0000000 --- a/gitlab/v4/objects/project_access_tokens.py +++ /dev/null @@ -1,17 +0,0 @@ -from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import CreateMixin, DeleteMixin, ListMixin, ObjectDeleteMixin - -__all__ = [ - "ProjectAccessToken", - "ProjectAccessTokenManager", -] - - -class ProjectAccessToken(ObjectDeleteMixin, RESTObject): - pass - - -class ProjectAccessTokenManager(ListMixin, CreateMixin, DeleteMixin, RESTManager): - _path = "/projects/%(project_id)s/access_tokens" - _obj_cls = ProjectAccessToken - _from_parent_attrs = {"project_id": "id"} diff --git a/gitlab/v4/objects/projects.py b/gitlab/v4/objects/projects.py deleted file mode 100644 index 551079a..0000000 --- a/gitlab/v4/objects/projects.py +++ /dev/null @@ -1,1047 +0,0 @@ -from typing import Any, Callable, cast, Dict, List, Optional, TYPE_CHECKING, Union - -import requests - -from gitlab import cli, client -from gitlab import exceptions as exc -from gitlab import types, utils -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import ( - CreateMixin, - CRUDMixin, - ListMixin, - ObjectDeleteMixin, - RefreshMixin, - SaveMixin, - UpdateMixin, -) - -from .access_requests import ProjectAccessRequestManager # noqa: F401 -from .audit_events import ProjectAuditEventManager # noqa: F401 -from .badges import ProjectBadgeManager # noqa: F401 -from .boards import ProjectBoardManager # noqa: F401 -from .branches import ProjectBranchManager, ProjectProtectedBranchManager # noqa: F401 -from .clusters import ProjectClusterManager # noqa: F401 -from .commits import ProjectCommitManager # noqa: F401 -from .container_registry import ProjectRegistryRepositoryManager # noqa: F401 -from .custom_attributes import ProjectCustomAttributeManager # noqa: F401 -from .deploy_keys import ProjectKeyManager # noqa: F401 -from .deploy_tokens import ProjectDeployTokenManager # noqa: F401 -from .deployments import ProjectDeploymentManager # noqa: F401 -from .environments import ProjectEnvironmentManager # noqa: F401 -from .events import ProjectEventManager # noqa: F401 -from .export_import import ProjectExportManager, ProjectImportManager # noqa: F401 -from .files import ProjectFileManager # noqa: F401 -from .hooks import ProjectHookManager # noqa: F401 -from .issues import ProjectIssueManager # noqa: F401 -from .jobs import ProjectJobManager # noqa: F401 -from .labels import ProjectLabelManager # noqa: F401 -from .members import ProjectMemberAllManager, ProjectMemberManager # noqa: F401 -from .merge_request_approvals import ( # noqa: F401 - ProjectApprovalManager, - ProjectApprovalRuleManager, -) -from .merge_requests import ProjectMergeRequestManager # noqa: F401 -from .milestones import ProjectMilestoneManager # noqa: F401 -from .notes import ProjectNoteManager # noqa: F401 -from .notification_settings import ProjectNotificationSettingsManager # noqa: F401 -from .packages import GenericPackageManager, ProjectPackageManager # noqa: F401 -from .pages import ProjectPagesDomainManager # noqa: F401 -from .pipelines import ( # noqa: F401 - ProjectPipeline, - ProjectPipelineManager, - ProjectPipelineScheduleManager, -) -from .project_access_tokens import ProjectAccessTokenManager # noqa: F401 -from .push_rules import ProjectPushRulesManager # noqa: F401 -from .releases import ProjectReleaseManager # noqa: F401 -from .repositories import RepositoryMixin -from .runners import ProjectRunnerManager # noqa: F401 -from .services import ProjectServiceManager # noqa: F401 -from .snippets import ProjectSnippetManager # noqa: F401 -from .statistics import ( # noqa: F401 - ProjectAdditionalStatisticsManager, - ProjectIssuesStatisticsManager, -) -from .tags import ProjectProtectedTagManager, ProjectTagManager # noqa: F401 -from .triggers import ProjectTriggerManager # noqa: F401 -from .users import ProjectUserManager # noqa: F401 -from .variables import ProjectVariableManager # noqa: F401 -from .wikis import ProjectWikiManager # noqa: F401 - -__all__ = [ - "GroupProject", - "GroupProjectManager", - "Project", - "ProjectManager", - "ProjectFork", - "ProjectForkManager", - "ProjectRemoteMirror", - "ProjectRemoteMirrorManager", -] - - -class GroupProject(RESTObject): - pass - - -class GroupProjectManager(ListMixin, RESTManager): - _path = "/groups/%(group_id)s/projects" - _obj_cls = GroupProject - _from_parent_attrs = {"group_id": "id"} - _list_filters = ( - "archived", - "visibility", - "order_by", - "sort", - "search", - "simple", - "owned", - "starred", - "with_custom_attributes", - "include_subgroups", - "with_issues_enabled", - "with_merge_requests_enabled", - "with_shared", - "min_access_level", - "with_security_reports", - ) - - -class Project(RefreshMixin, SaveMixin, ObjectDeleteMixin, RepositoryMixin, RESTObject): - _short_print_attr = "path" - - access_tokens: ProjectAccessTokenManager - accessrequests: ProjectAccessRequestManager - additionalstatistics: ProjectAdditionalStatisticsManager - approvalrules: ProjectApprovalRuleManager - approvals: ProjectApprovalManager - audit_events: ProjectAuditEventManager - badges: ProjectBadgeManager - boards: ProjectBoardManager - branches: ProjectBranchManager - clusters: ProjectClusterManager - commits: ProjectCommitManager - customattributes: ProjectCustomAttributeManager - deployments: ProjectDeploymentManager - deploytokens: ProjectDeployTokenManager - environments: ProjectEnvironmentManager - events: ProjectEventManager - exports: ProjectExportManager - files: ProjectFileManager - forks: "ProjectForkManager" - generic_packages: GenericPackageManager - hooks: ProjectHookManager - imports: ProjectImportManager - issues: ProjectIssueManager - issues_statistics: ProjectIssuesStatisticsManager - jobs: ProjectJobManager - keys: ProjectKeyManager - labels: ProjectLabelManager - members: ProjectMemberManager - members_all: ProjectMemberAllManager - mergerequests: ProjectMergeRequestManager - milestones: ProjectMilestoneManager - notes: ProjectNoteManager - notificationsettings: ProjectNotificationSettingsManager - packages: ProjectPackageManager - pagesdomains: ProjectPagesDomainManager - pipelines: ProjectPipelineManager - pipelineschedules: ProjectPipelineScheduleManager - protectedbranches: ProjectProtectedBranchManager - protectedtags: ProjectProtectedTagManager - pushrules: ProjectPushRulesManager - releases: ProjectReleaseManager - remote_mirrors: "ProjectRemoteMirrorManager" - repositories: ProjectRegistryRepositoryManager - runners: ProjectRunnerManager - services: ProjectServiceManager - snippets: ProjectSnippetManager - tags: ProjectTagManager - triggers: ProjectTriggerManager - users: ProjectUserManager - variables: ProjectVariableManager - wikis: ProjectWikiManager - - @cli.register_custom_action("Project", ("forked_from_id",)) - @exc.on_http_error(exc.GitlabCreateError) - def create_fork_relation(self, forked_from_id: int, **kwargs: Any) -> None: - """Create a forked from/to relation between existing projects. - - Args: - forked_from_id (int): The ID of the project that was forked from - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCreateError: If the relation could not be created - """ - path = "/projects/%s/fork/%s" % (self.get_id(), forked_from_id) - self.manager.gitlab.http_post(path, **kwargs) - - @cli.register_custom_action("Project") - @exc.on_http_error(exc.GitlabDeleteError) - def delete_fork_relation(self, **kwargs: Any) -> None: - """Delete a forked relation between existing projects. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabDeleteError: If the server failed to perform the request - """ - path = "/projects/%s/fork" % self.get_id() - self.manager.gitlab.http_delete(path, **kwargs) - - @cli.register_custom_action("Project") - @exc.on_http_error(exc.GitlabGetError) - def languages(self, **kwargs: Any) -> Union[Dict[str, Any], requests.Response]: - """Get languages used in the project with percentage value. - - Args: - **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 - """ - path = "/projects/%s/languages" % self.get_id() - return self.manager.gitlab.http_get(path, **kwargs) - - @cli.register_custom_action("Project") - @exc.on_http_error(exc.GitlabCreateError) - def star(self, **kwargs: Any) -> None: - """Star a project. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCreateError: If the server failed to perform the request - """ - path = "/projects/%s/star" % self.get_id() - server_data = self.manager.gitlab.http_post(path, **kwargs) - if TYPE_CHECKING: - assert isinstance(server_data, dict) - self._update_attrs(server_data) - - @cli.register_custom_action("Project") - @exc.on_http_error(exc.GitlabDeleteError) - def unstar(self, **kwargs: Any) -> None: - """Unstar a project. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabDeleteError: If the server failed to perform the request - """ - path = "/projects/%s/unstar" % self.get_id() - server_data = self.manager.gitlab.http_post(path, **kwargs) - if TYPE_CHECKING: - assert isinstance(server_data, dict) - self._update_attrs(server_data) - - @cli.register_custom_action("Project") - @exc.on_http_error(exc.GitlabCreateError) - def archive(self, **kwargs: Any) -> None: - """Archive a project. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCreateError: If the server failed to perform the request - """ - path = "/projects/%s/archive" % self.get_id() - server_data = self.manager.gitlab.http_post(path, **kwargs) - if TYPE_CHECKING: - assert isinstance(server_data, dict) - self._update_attrs(server_data) - - @cli.register_custom_action("Project") - @exc.on_http_error(exc.GitlabDeleteError) - def unarchive(self, **kwargs: Any) -> None: - """Unarchive a project. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabDeleteError: If the server failed to perform the request - """ - path = "/projects/%s/unarchive" % self.get_id() - server_data = self.manager.gitlab.http_post(path, **kwargs) - if TYPE_CHECKING: - assert isinstance(server_data, dict) - self._update_attrs(server_data) - - @cli.register_custom_action( - "Project", ("group_id", "group_access"), ("expires_at",) - ) - @exc.on_http_error(exc.GitlabCreateError) - def share( - self, - group_id: int, - group_access: int, - expires_at: Optional[str] = None, - **kwargs: Any - ) -> None: - """Share the project with a group. - - Args: - group_id (int): ID of the group. - group_access (int): Access level for the group. - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCreateError: If the server failed to perform the request - """ - path = "/projects/%s/share" % self.get_id() - data = { - "group_id": group_id, - "group_access": group_access, - "expires_at": expires_at, - } - self.manager.gitlab.http_post(path, post_data=data, **kwargs) - - @cli.register_custom_action("Project", ("group_id",)) - @exc.on_http_error(exc.GitlabDeleteError) - def unshare(self, group_id: int, **kwargs: Any) -> None: - """Delete a shared project link within a group. - - Args: - group_id (int): ID of the group. - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabDeleteError: If the server failed to perform the request - """ - path = "/projects/%s/share/%s" % (self.get_id(), group_id) - self.manager.gitlab.http_delete(path, **kwargs) - - # variables not supported in CLI - @cli.register_custom_action("Project", ("ref", "token")) - @exc.on_http_error(exc.GitlabCreateError) - def trigger_pipeline( - self, - ref: str, - token: str, - variables: Optional[Dict[str, Any]] = None, - **kwargs: Any - ) -> ProjectPipeline: - """Trigger a CI build. - - See https://gitlab.com/help/ci/triggers/README.md#trigger-a-build - - Args: - ref (str): Commit to build; can be a branch name or a tag - token (str): The trigger token - variables (dict): Variables passed to the build script - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCreateError: If the server failed to perform the request - """ - variables = variables or {} - path = "/projects/%s/trigger/pipeline" % self.get_id() - post_data = {"ref": ref, "token": token, "variables": variables} - attrs = self.manager.gitlab.http_post(path, post_data=post_data, **kwargs) - if TYPE_CHECKING: - assert isinstance(attrs, dict) - return ProjectPipeline(self.pipelines, attrs) - - @cli.register_custom_action("Project") - @exc.on_http_error(exc.GitlabHousekeepingError) - def housekeeping(self, **kwargs: Any) -> None: - """Start the housekeeping task. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabHousekeepingError: If the server failed to perform the - request - """ - path = "/projects/%s/housekeeping" % self.get_id() - self.manager.gitlab.http_post(path, **kwargs) - - # see #56 - add file attachment features - @cli.register_custom_action("Project", ("filename", "filepath")) - @exc.on_http_error(exc.GitlabUploadError) - def upload( - self, - filename: str, - filedata: Optional[bytes] = None, - filepath: Optional[str] = None, - **kwargs: Any - ) -> Dict[str, Any]: - """Upload the specified file into the project. - - .. note:: - - Either ``filedata`` or ``filepath`` *MUST* be specified. - - Args: - filename (str): The name of the file being uploaded - filedata (bytes): The raw data of the file being uploaded - filepath (str): The path to a local file to upload (optional) - - Raises: - GitlabConnectionError: If the server cannot be reached - GitlabUploadError: If the file upload fails - GitlabUploadError: If ``filedata`` and ``filepath`` are not - specified - GitlabUploadError: If both ``filedata`` and ``filepath`` are - specified - - Returns: - dict: A ``dict`` with the keys: - * ``alt`` - The alternate text for the upload - * ``url`` - The direct url to the uploaded file - * ``markdown`` - Markdown for the uploaded file - """ - if filepath is None and filedata is None: - raise exc.GitlabUploadError("No file contents or path specified") - - if filedata is not None and filepath is not None: - raise exc.GitlabUploadError("File contents and file path specified") - - if filepath is not None: - with open(filepath, "rb") as f: - filedata = f.read() - - url = "/projects/%(id)s/uploads" % {"id": self.id} - file_info = {"file": (filename, filedata)} - data = self.manager.gitlab.http_post(url, files=file_info) - - if TYPE_CHECKING: - assert isinstance(data, dict) - return {"alt": data["alt"], "url": data["url"], "markdown": data["markdown"]} - - @cli.register_custom_action("Project", optional=("wiki",)) - @exc.on_http_error(exc.GitlabGetError) - def snapshot( - self, - wiki: bool = False, - streamed: bool = False, - action: Optional[Callable] = None, - chunk_size: int = 1024, - **kwargs: Any - ) -> Optional[bytes]: - """Return a snapshot of the repository. - - Args: - wiki (bool): If True return the wiki repository - 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 content could not be retrieved - - Returns: - str: The uncompressed tar archive of the repository - """ - path = "/projects/%s/snapshot" % self.get_id() - 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) - - @cli.register_custom_action("Project", ("scope", "search")) - @exc.on_http_error(exc.GitlabSearchError) - def search( - self, scope: str, search: str, **kwargs: Any - ) -> Union[client.GitlabList, List[Dict[str, Any]]]: - """Search the project resources matching the provided string.' - - Args: - scope (str): Scope of the search - search (str): Search string - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabSearchError: If the server failed to perform the request - - Returns: - GitlabList: A list of dicts describing the resources found. - """ - data = {"scope": scope, "search": search} - path = "/projects/%s/search" % self.get_id() - return self.manager.gitlab.http_list(path, query_data=data, **kwargs) - - @cli.register_custom_action("Project") - @exc.on_http_error(exc.GitlabCreateError) - def mirror_pull(self, **kwargs: Any) -> None: - """Start the pull mirroring process for the project. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCreateError: If the server failed to perform the request - """ - path = "/projects/%s/mirror/pull" % self.get_id() - self.manager.gitlab.http_post(path, **kwargs) - - @cli.register_custom_action("Project", ("to_namespace",)) - @exc.on_http_error(exc.GitlabTransferProjectError) - def transfer_project(self, to_namespace: str, **kwargs: Any) -> None: - """Transfer a project to the given namespace ID - - Args: - to_namespace (str): ID or path of the namespace to transfer the - project to - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabTransferProjectError: If the project could not be transferred - """ - path = "/projects/%s/transfer" % (self.id,) - self.manager.gitlab.http_put( - path, post_data={"namespace": to_namespace}, **kwargs - ) - - @cli.register_custom_action("Project", ("ref_name", "job"), ("job_token",)) - @exc.on_http_error(exc.GitlabGetError) - def artifacts( - self, - ref_name: str, - job: str, - streamed: bool = False, - action: Optional[Callable] = None, - chunk_size: int = 1024, - **kwargs: Any - ) -> Optional[bytes]: - """Get the job artifacts archive from a specific tag or branch. - - Args: - ref_name (str): Branch or tag name in repository. HEAD or SHA references - are not supported. - artifact_path (str): Path to a file inside the artifacts archive. - job (str): The name of the job. - job_token (str): Job token for multi-project pipeline triggers. - 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 artifacts could not be retrieved - - Returns: - str: The artifacts if `streamed` is False, None otherwise. - """ - path = "/projects/%s/jobs/artifacts/%s/download" % (self.get_id(), ref_name) - result = self.manager.gitlab.http_get( - path, job=job, streamed=streamed, raw=True, **kwargs - ) - if TYPE_CHECKING: - assert isinstance(result, requests.Response) - return utils.response_content(result, streamed, action, chunk_size) - - @cli.register_custom_action("Project", ("ref_name", "artifact_path", "job")) - @exc.on_http_error(exc.GitlabGetError) - def artifact( - self, - ref_name: str, - artifact_path: str, - job: str, - streamed: bool = False, - action: Optional[Callable] = None, - chunk_size: int = 1024, - **kwargs: Any - ) -> Optional[bytes]: - """Download a single artifact file from a specific tag or branch from within the job’s artifacts archive. - - Args: - ref_name (str): Branch or tag name in repository. HEAD or SHA references are not supported. - artifact_path (str): Path to a file inside the artifacts archive. - job (str): The name of the job. - 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 artifacts could not be retrieved - - Returns: - str: The artifacts if `streamed` is False, None otherwise. - """ - - path = "/projects/%s/jobs/artifacts/%s/raw/%s?job=%s" % ( - self.get_id(), - ref_name, - artifact_path, - job, - ) - 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 ProjectManager(CRUDMixin, RESTManager): - _path = "/projects" - _obj_cls = Project - # Please keep these _create_attrs in same order as they are at: - # https://docs.gitlab.com/ee/api/projects.html#create-project - _create_attrs = RequiredOptional( - optional=( - "name", - "path", - "allow_merge_on_skipped_pipeline", - "analytics_access_level", - "approvals_before_merge", - "auto_cancel_pending_pipelines", - "auto_devops_deploy_strategy", - "auto_devops_enabled", - "autoclose_referenced_issues", - "avatar", - "build_coverage_regex", - "build_git_strategy", - "build_timeout", - "builds_access_level", - "ci_config_path", - "container_expiration_policy_attributes", - "container_registry_enabled", - "default_branch", - "description", - "emails_disabled", - "external_authorization_classification_label", - "forking_access_level", - "group_with_project_templates_id", - "import_url", - "initialize_with_readme", - "issues_access_level", - "issues_enabled", - "jobs_enabled", - "lfs_enabled", - "merge_method", - "merge_requests_access_level", - "merge_requests_enabled", - "mirror_trigger_builds", - "mirror", - "namespace_id", - "operations_access_level", - "only_allow_merge_if_all_discussions_are_resolved", - "only_allow_merge_if_pipeline_succeeds", - "packages_enabled", - "pages_access_level", - "requirements_access_level", - "printing_merge_request_link_enabled", - "public_builds", - "remove_source_branch_after_merge", - "repository_access_level", - "repository_storage", - "request_access_enabled", - "resolve_outdated_diff_discussions", - "shared_runners_enabled", - "show_default_award_emojis", - "snippets_access_level", - "snippets_enabled", - "tag_list", - "template_name", - "template_project_id", - "use_custom_template", - "visibility", - "wiki_access_level", - "wiki_enabled", - ), - ) - # Please keep these _update_attrs in same order as they are at: - # https://docs.gitlab.com/ee/api/projects.html#edit-project - _update_attrs = RequiredOptional( - optional=( - "allow_merge_on_skipped_pipeline", - "analytics_access_level", - "approvals_before_merge", - "auto_cancel_pending_pipelines", - "auto_devops_deploy_strategy", - "auto_devops_enabled", - "autoclose_referenced_issues", - "avatar", - "build_coverage_regex", - "build_git_strategy", - "build_timeout", - "builds_access_level", - "ci_config_path", - "ci_default_git_depth", - "ci_forward_deployment_enabled", - "container_expiration_policy_attributes", - "container_registry_enabled", - "default_branch", - "description", - "emails_disabled", - "external_authorization_classification_label", - "forking_access_level", - "import_url", - "issues_access_level", - "issues_enabled", - "jobs_enabled", - "lfs_enabled", - "merge_method", - "merge_requests_access_level", - "merge_requests_enabled", - "mirror_overwrites_diverged_branches", - "mirror_trigger_builds", - "mirror_user_id", - "mirror", - "name", - "operations_access_level", - "only_allow_merge_if_all_discussions_are_resolved", - "only_allow_merge_if_pipeline_succeeds", - "only_mirror_protected_branches", - "packages_enabled", - "pages_access_level", - "requirements_access_level", - "restrict_user_defined_variables", - "path", - "public_builds", - "remove_source_branch_after_merge", - "repository_access_level", - "repository_storage", - "request_access_enabled", - "resolve_outdated_diff_discussions", - "service_desk_enabled", - "shared_runners_enabled", - "show_default_award_emojis", - "snippets_access_level", - "snippets_enabled", - "suggestion_commit_message", - "tag_list", - "visibility", - "wiki_access_level", - "wiki_enabled", - "issues_template", - "merge_requests_template", - ), - ) - _list_filters = ( - "archived", - "id_after", - "id_before", - "last_activity_after", - "last_activity_before", - "membership", - "min_access_level", - "order_by", - "owned", - "repository_checksum_failed", - "repository_storage", - "search_namespaces", - "search", - "simple", - "sort", - "starred", - "statistics", - "topic", - "visibility", - "wiki_checksum_failed", - "with_custom_attributes", - "with_issues_enabled", - "with_merge_requests_enabled", - "with_programming_language", - ) - _types = {"avatar": types.ImageAttribute, "topic": types.ListAttribute} - - def get(self, id: Union[str, int], lazy: bool = False, **kwargs: Any) -> Project: - return cast(Project, super().get(id=id, lazy=lazy, **kwargs)) - - def import_project( - self, - file: str, - path: str, - name: Optional[str] = None, - namespace: Optional[str] = None, - overwrite: bool = False, - override_params: Optional[Dict[str, Any]] = None, - **kwargs: Any - ) -> Union[Dict[str, Any], requests.Response]: - """Import a project from an archive file. - - Args: - file: Data or file object containing the project - path (str): Name and path for the new project - namespace (str): The ID or path of the namespace that the project - will be imported to - overwrite (bool): If True overwrite an existing project with the - same path - override_params (dict): Set the specific settings for the project - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabListError: If the server failed to perform the request - - Returns: - dict: A representation of the import status. - """ - files = {"file": ("file.tar.gz", file, "application/octet-stream")} - data = {"path": path, "overwrite": str(overwrite)} - if override_params: - for k, v in override_params.items(): - data["override_params[%s]" % k] = v - if name is not None: - data["name"] = name - if namespace: - data["namespace"] = namespace - return self.gitlab.http_post( - "/projects/import", post_data=data, files=files, **kwargs - ) - - def import_bitbucket_server( - self, - bitbucket_server_url: str, - bitbucket_server_username: str, - personal_access_token: str, - bitbucket_server_project: str, - bitbucket_server_repo: str, - new_name: Optional[str] = None, - target_namespace: Optional[str] = None, - **kwargs: Any - ) -> Union[Dict[str, Any], requests.Response]: - """Import a project from BitBucket Server to Gitlab (schedule the import) - - This method will return when an import operation has been safely queued, - or an error has occurred. After triggering an import, check the - ``import_status`` of the newly created project to detect when the import - operation has completed. - - .. note:: - This request may take longer than most other API requests. - So this method will specify a 60 second default timeout if none is specified. - A timeout can be specified via kwargs to override this functionality. - - Args: - bitbucket_server_url (str): Bitbucket Server URL - bitbucket_server_username (str): Bitbucket Server Username - personal_access_token (str): Bitbucket Server personal access - token/password - bitbucket_server_project (str): Bitbucket Project Key - bitbucket_server_repo (str): Bitbucket Repository Name - new_name (str): New repository name (Optional) - target_namespace (str): Namespace to import repository into. - Supports subgroups like /namespace/subgroup (Optional) - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabListError: If the server failed to perform the request - - Returns: - dict: A representation of the import status. - - Example: - - .. code-block:: python - - gl = gitlab.Gitlab_from_config() - print("Triggering import") - result = gl.projects.import_bitbucket_server( - bitbucket_server_url="https://some.server.url", - bitbucket_server_username="some_bitbucket_user", - personal_access_token="my_password_or_access_token", - bitbucket_server_project="my_project", - bitbucket_server_repo="my_repo", - new_name="gl_project_name", - target_namespace="gl_project_path" - ) - project = gl.projects.get(ret['id']) - print("Waiting for import to complete") - while project.import_status == u'started': - time.sleep(1.0) - project = gl.projects.get(project.id) - print("BitBucket import complete") - - """ - data = { - "bitbucket_server_url": bitbucket_server_url, - "bitbucket_server_username": bitbucket_server_username, - "personal_access_token": personal_access_token, - "bitbucket_server_project": bitbucket_server_project, - "bitbucket_server_repo": bitbucket_server_repo, - } - if new_name: - data["new_name"] = new_name - if target_namespace: - data["target_namespace"] = target_namespace - if ( - "timeout" not in kwargs - or self.gitlab.timeout is None - or self.gitlab.timeout < 60.0 - ): - # Ensure that this HTTP request has a longer-than-usual default timeout - # The base gitlab object tends to have a default that is <10 seconds, - # and this is too short for this API command, typically. - # On the order of 24 seconds has been measured on a typical gitlab instance. - kwargs["timeout"] = 60.0 - result = self.gitlab.http_post( - "/import/bitbucket_server", post_data=data, **kwargs - ) - return result - - def import_github( - self, - personal_access_token: str, - repo_id: int, - target_namespace: str, - new_name: Optional[str] = None, - **kwargs: Any - ) -> Union[Dict[str, Any], requests.Response]: - """Import a project from Github to Gitlab (schedule the import) - - This method will return when an import operation has been safely queued, - or an error has occurred. After triggering an import, check the - ``import_status`` of the newly created project to detect when the import - operation has completed. - - .. note:: - This request may take longer than most other API requests. - So this method will specify a 60 second default timeout if none is specified. - A timeout can be specified via kwargs to override this functionality. - - Args: - personal_access_token (str): GitHub personal access token - repo_id (int): Github repository ID - target_namespace (str): Namespace to import repo into - new_name (str): New repo name (Optional) - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabListError: If the server failed to perform the request - - Returns: - dict: A representation of the import status. - - Example: - - .. code-block:: python - - gl = gitlab.Gitlab_from_config() - print("Triggering import") - result = gl.projects.import_github(ACCESS_TOKEN, - 123456, - "my-group/my-subgroup") - project = gl.projects.get(ret['id']) - print("Waiting for import to complete") - while project.import_status == u'started': - time.sleep(1.0) - project = gl.projects.get(project.id) - print("Github import complete") - - """ - data = { - "personal_access_token": personal_access_token, - "repo_id": repo_id, - "target_namespace": target_namespace, - } - if new_name: - data["new_name"] = new_name - if ( - "timeout" not in kwargs - or self.gitlab.timeout is None - or self.gitlab.timeout < 60.0 - ): - # Ensure that this HTTP request has a longer-than-usual default timeout - # The base gitlab object tends to have a default that is <10 seconds, - # and this is too short for this API command, typically. - # On the order of 24 seconds has been measured on a typical gitlab instance. - kwargs["timeout"] = 60.0 - result = self.gitlab.http_post("/import/github", post_data=data, **kwargs) - return result - - -class ProjectFork(RESTObject): - pass - - -class ProjectForkManager(CreateMixin, ListMixin, RESTManager): - _path = "/projects/%(project_id)s/forks" - _obj_cls = ProjectFork - _from_parent_attrs = {"project_id": "id"} - _list_filters = ( - "archived", - "visibility", - "order_by", - "sort", - "search", - "simple", - "owned", - "membership", - "starred", - "statistics", - "with_custom_attributes", - "with_issues_enabled", - "with_merge_requests_enabled", - ) - _create_attrs = RequiredOptional(optional=("namespace",)) - - def create( - self, data: Optional[Dict[str, Any]] = None, **kwargs: Any - ) -> ProjectFork: - """Creates 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) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabCreateError: If the server cannot perform the request - - Returns: - RESTObject: A new instance of the managed object class build with - the data sent by the server - """ - if TYPE_CHECKING: - assert self.path is not None - path = self.path[:-1] # drop the 's' - return cast(ProjectFork, CreateMixin.create(self, data, path=path, **kwargs)) - - -class ProjectRemoteMirror(SaveMixin, RESTObject): - pass - - -class ProjectRemoteMirrorManager(ListMixin, CreateMixin, UpdateMixin, RESTManager): - _path = "/projects/%(project_id)s/remote_mirrors" - _obj_cls = ProjectRemoteMirror - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("url",), optional=("enabled", "only_protected_branches") - ) - _update_attrs = RequiredOptional(optional=("enabled", "only_protected_branches")) diff --git a/gitlab/v4/objects/push_rules.py b/gitlab/v4/objects/push_rules.py deleted file mode 100644 index ee20f96..0000000 --- a/gitlab/v4/objects/push_rules.py +++ /dev/null @@ -1,50 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import ( - CreateMixin, - DeleteMixin, - GetWithoutIdMixin, - ObjectDeleteMixin, - SaveMixin, - UpdateMixin, -) - -__all__ = [ - "ProjectPushRules", - "ProjectPushRulesManager", -] - - -class ProjectPushRules(SaveMixin, ObjectDeleteMixin, RESTObject): - _id_attr = None - - -class ProjectPushRulesManager( - GetWithoutIdMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTManager -): - _path = "/projects/%(project_id)s/push_rule" - _obj_cls = ProjectPushRules - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - optional=( - "deny_delete_tag", - "member_check", - "prevent_secrets", - "commit_message_regex", - "branch_name_regex", - "author_email_regex", - "file_name_regex", - "max_file_size", - ), - ) - _update_attrs = RequiredOptional( - optional=( - "deny_delete_tag", - "member_check", - "prevent_secrets", - "commit_message_regex", - "branch_name_regex", - "author_email_regex", - "file_name_regex", - "max_file_size", - ), - ) diff --git a/gitlab/v4/objects/releases.py b/gitlab/v4/objects/releases.py deleted file mode 100644 index 2af3248..0000000 --- a/gitlab/v4/objects/releases.py +++ /dev/null @@ -1,41 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CRUDMixin, ObjectDeleteMixin, SaveMixin - -__all__ = [ - "ProjectRelease", - "ProjectReleaseManager", - "ProjectReleaseLink", - "ProjectReleaseLinkManager", -] - - -class ProjectRelease(SaveMixin, RESTObject): - _id_attr = "tag_name" - - links: "ProjectReleaseLinkManager" - - -class ProjectReleaseManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/releases" - _obj_cls = ProjectRelease - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("tag_name", "description"), optional=("name", "ref", "assets") - ) - _update_attrs = RequiredOptional( - optional=("name", "description", "milestones", "released_at") - ) - - -class ProjectReleaseLink(ObjectDeleteMixin, SaveMixin, RESTObject): - pass - - -class ProjectReleaseLinkManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/releases/%(tag_name)s/assets/links" - _obj_cls = ProjectReleaseLink - _from_parent_attrs = {"project_id": "project_id", "tag_name": "tag_name"} - _create_attrs = RequiredOptional( - required=("name", "url"), optional=("filepath", "link_type") - ) - _update_attrs = RequiredOptional(optional=("name", "url", "filepath", "link_type")) diff --git a/gitlab/v4/objects/repositories.py b/gitlab/v4/objects/repositories.py deleted file mode 100644 index de5f0d2..0000000 --- a/gitlab/v4/objects/repositories.py +++ /dev/null @@ -1,207 +0,0 @@ -""" -GitLab API: https://docs.gitlab.com/ee/api/repositories.html - -Currently this module only contains repository-related methods for projects. -""" - -from gitlab import cli -from gitlab import exceptions as exc -from gitlab import utils - - -class RepositoryMixin: - @cli.register_custom_action("Project", ("submodule", "branch", "commit_sha")) - @exc.on_http_error(exc.GitlabUpdateError) - def update_submodule(self, submodule, branch, commit_sha, **kwargs): - """Update a project submodule - - Args: - submodule (str): Full path to the submodule - branch (str): Name of the branch to commit into - commit_sha (str): Full commit SHA to update the submodule to - commit_message (str): Commit message. If no message is provided, a default one will be set (optional) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabPutError: If the submodule could not be updated - """ - - submodule = submodule.replace("/", "%2F") # .replace('.', '%2E') - path = "/projects/%s/repository/submodules/%s" % (self.get_id(), submodule) - data = {"branch": branch, "commit_sha": commit_sha} - if "commit_message" in kwargs: - data["commit_message"] = kwargs["commit_message"] - return self.manager.gitlab.http_put(path, post_data=data) - - @cli.register_custom_action("Project", tuple(), ("path", "ref", "recursive")) - @exc.on_http_error(exc.GitlabGetError) - def repository_tree(self, path="", ref="", recursive=False, **kwargs): - """Return a list of files in the repository. - - Args: - path (str): Path of the top folder (/ by default) - ref (str): Reference to a commit or branch - recursive (bool): Whether to get the tree recursively - 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 - GitlabGetError: If the server failed to perform the request - - Returns: - list: The representation of the tree - """ - gl_path = "/projects/%s/repository/tree" % self.get_id() - query_data = {"recursive": recursive} - if path: - query_data["path"] = path - if ref: - query_data["ref"] = ref - return self.manager.gitlab.http_list(gl_path, query_data=query_data, **kwargs) - - @cli.register_custom_action("Project", ("sha",)) - @exc.on_http_error(exc.GitlabGetError) - def repository_blob(self, sha, **kwargs): - """Return a file by blob SHA. - - Args: - sha(str): ID of the blob - **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: - dict: The blob content and metadata - """ - - path = "/projects/%s/repository/blobs/%s" % (self.get_id(), sha) - return self.manager.gitlab.http_get(path, **kwargs) - - @cli.register_custom_action("Project", ("sha",)) - @exc.on_http_error(exc.GitlabGetError) - def repository_raw_blob( - self, sha, streamed=False, action=None, chunk_size=1024, **kwargs - ): - """Return the raw file contents for a blob. - - Args: - sha(str): ID of the blob - 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 = "/projects/%s/repository/blobs/%s/raw" % (self.get_id(), sha) - result = self.manager.gitlab.http_get( - path, streamed=streamed, raw=True, **kwargs - ) - return utils.response_content(result, streamed, action, chunk_size) - - @cli.register_custom_action("Project", ("from_", "to")) - @exc.on_http_error(exc.GitlabGetError) - def repository_compare(self, from_, to, **kwargs): - """Return a diff between two branches/commits. - - Args: - from_(str): Source branch/SHA - to(str): Destination branch/SHA - **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 diff - """ - path = "/projects/%s/repository/compare" % self.get_id() - query_data = {"from": from_, "to": to} - return self.manager.gitlab.http_get(path, query_data=query_data, **kwargs) - - @cli.register_custom_action("Project") - @exc.on_http_error(exc.GitlabGetError) - def repository_contributors(self, **kwargs): - """Return a list of contributors for the project. - - 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 - GitlabGetError: If the server failed to perform the request - - Returns: - list: The contributors - """ - path = "/projects/%s/repository/contributors" % self.get_id() - return self.manager.gitlab.http_list(path, **kwargs) - - @cli.register_custom_action("Project", tuple(), ("sha",)) - @exc.on_http_error(exc.GitlabListError) - def repository_archive( - self, sha=None, streamed=False, action=None, chunk_size=1024, **kwargs - ): - """Return a tarball of the repository. - - Args: - sha (str): ID of the commit (default branch by default) - 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 - GitlabListError: If the server failed to perform the request - - Returns: - bytes: The binary data of the archive - """ - path = "/projects/%s/repository/archive" % self.get_id() - query_data = {} - if sha: - query_data["sha"] = sha - result = self.manager.gitlab.http_get( - path, query_data=query_data, raw=True, streamed=streamed, **kwargs - ) - return utils.response_content(result, streamed, action, chunk_size) - - @cli.register_custom_action("Project") - @exc.on_http_error(exc.GitlabDeleteError) - def delete_merged_branches(self, **kwargs): - """Delete merged branches. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabDeleteError: If the server failed to perform the request - """ - path = "/projects/%s/repository/merged_branches" % self.get_id() - self.manager.gitlab.http_delete(path, **kwargs) diff --git a/gitlab/v4/objects/runners.py b/gitlab/v4/objects/runners.py deleted file mode 100644 index a32dc84..0000000 --- a/gitlab/v4/objects/runners.py +++ /dev/null @@ -1,140 +0,0 @@ -from gitlab import cli -from gitlab import exceptions as exc -from gitlab import types -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import ( - CRUDMixin, - ListMixin, - NoUpdateMixin, - ObjectDeleteMixin, - SaveMixin, -) - -__all__ = [ - "RunnerJob", - "RunnerJobManager", - "Runner", - "RunnerManager", - "GroupRunner", - "GroupRunnerManager", - "ProjectRunner", - "ProjectRunnerManager", -] - - -class RunnerJob(RESTObject): - pass - - -class RunnerJobManager(ListMixin, RESTManager): - _path = "/runners/%(runner_id)s/jobs" - _obj_cls = RunnerJob - _from_parent_attrs = {"runner_id": "id"} - _list_filters = ("status",) - - -class Runner(SaveMixin, ObjectDeleteMixin, RESTObject): - jobs: RunnerJobManager - - -class RunnerManager(CRUDMixin, RESTManager): - _path = "/runners" - _obj_cls = Runner - _create_attrs = RequiredOptional( - required=("token",), - optional=( - "description", - "info", - "active", - "locked", - "run_untagged", - "tag_list", - "access_level", - "maximum_timeout", - ), - ) - _update_attrs = RequiredOptional( - optional=( - "description", - "active", - "tag_list", - "run_untagged", - "locked", - "access_level", - "maximum_timeout", - ), - ) - _list_filters = ("scope", "tag_list") - _types = {"tag_list": types.ListAttribute} - - @cli.register_custom_action("RunnerManager", tuple(), ("scope",)) - @exc.on_http_error(exc.GitlabListError) - def all(self, scope=None, **kwargs): - """List all the runners. - - Args: - scope (str): The scope of runners to show, one of: specific, - shared, active, paused, online - 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 server failed to perform the request - - Returns: - list(Runner): a list of runners matching the scope. - """ - path = "/runners/all" - query_data = {} - if scope is not None: - query_data["scope"] = scope - obj = self.gitlab.http_list(path, query_data, **kwargs) - return [self._obj_cls(self, item) for item in obj] - - @cli.register_custom_action("RunnerManager", ("token",)) - @exc.on_http_error(exc.GitlabVerifyError) - def verify(self, token, **kwargs): - """Validates authentication credentials for a registered Runner. - - Args: - token (str): The runner's authentication token - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabVerifyError: If the server failed to verify the token - """ - path = "/runners/verify" - post_data = {"token": token} - self.gitlab.http_post(path, post_data=post_data, **kwargs) - - -class GroupRunner(ObjectDeleteMixin, RESTObject): - pass - - -class GroupRunnerManager(NoUpdateMixin, RESTManager): - _path = "/groups/%(group_id)s/runners" - _obj_cls = GroupRunner - _from_parent_attrs = {"group_id": "id"} - _create_attrs = RequiredOptional(required=("runner_id",)) - _list_filters = ("scope", "tag_list") - _types = {"tag_list": types.ListAttribute} - - -class ProjectRunner(ObjectDeleteMixin, RESTObject): - pass - - -class ProjectRunnerManager(NoUpdateMixin, RESTManager): - _path = "/projects/%(project_id)s/runners" - _obj_cls = ProjectRunner - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional(required=("runner_id",)) - _list_filters = ("scope", "tag_list") - _types = {"tag_list": types.ListAttribute} diff --git a/gitlab/v4/objects/services.py b/gitlab/v4/objects/services.py deleted file mode 100644 index 6aedc39..0000000 --- a/gitlab/v4/objects/services.py +++ /dev/null @@ -1,303 +0,0 @@ -from gitlab import cli -from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import ( - DeleteMixin, - GetMixin, - ListMixin, - ObjectDeleteMixin, - SaveMixin, - UpdateMixin, -) - -__all__ = [ - "ProjectService", - "ProjectServiceManager", -] - - -class ProjectService(SaveMixin, ObjectDeleteMixin, RESTObject): - pass - - -class ProjectServiceManager(GetMixin, UpdateMixin, DeleteMixin, ListMixin, RESTManager): - _path = "/projects/%(project_id)s/services" - _from_parent_attrs = {"project_id": "id"} - _obj_cls = ProjectService - - _service_attrs = { - "asana": (("api_key",), ("restrict_to_branch", "push_events")), - "assembla": (("token",), ("subdomain", "push_events")), - "bamboo": ( - ("bamboo_url", "build_key", "username", "password"), - ("push_events",), - ), - "bugzilla": ( - ("new_issue_url", "issues_url", "project_url"), - ("description", "title", "push_events"), - ), - "buildkite": ( - ("token", "project_url"), - ("enable_ssl_verification", "push_events"), - ), - "campfire": (("token",), ("subdomain", "room", "push_events")), - "circuit": ( - ("webhook",), - ( - "notify_only_broken_pipelines", - "branches_to_be_notified", - "push_events", - "issues_events", - "confidential_issues_events", - "merge_requests_events", - "tag_push_events", - "note_events", - "confidential_note_events", - "pipeline_events", - "wiki_page_events", - ), - ), - "custom-issue-tracker": ( - ("new_issue_url", "issues_url", "project_url"), - ("description", "title", "push_events"), - ), - "drone-ci": ( - ("token", "drone_url"), - ( - "enable_ssl_verification", - "push_events", - "merge_requests_events", - "tag_push_events", - ), - ), - "emails-on-push": ( - ("recipients",), - ( - "disable_diffs", - "send_from_committer_email", - "push_events", - "tag_push_events", - "branches_to_be_notified", - ), - ), - "pipelines-email": ( - ("recipients",), - ( - "add_pusher", - "notify_only_broken_builds", - "branches_to_be_notified", - "notify_only_default_branch", - "pipeline_events", - ), - ), - "external-wiki": (("external_wiki_url",), tuple()), - "flowdock": (("token",), ("push_events",)), - "github": (("token", "repository_url"), ("static_context",)), - "hangouts-chat": ( - ("webhook",), - ( - "notify_only_broken_pipelines", - "notify_only_default_branch", - "branches_to_be_notified", - "push_events", - "issues_events", - "confidential_issues_events", - "merge_requests_events", - "tag_push_events", - "note_events", - "confidential_note_events", - "pipeline_events", - "wiki_page_events", - ), - ), - "hipchat": ( - ("token",), - ( - "color", - "notify", - "room", - "api_version", - "server", - "push_events", - "issues_events", - "confidential_issues_events", - "merge_requests_events", - "tag_push_events", - "note_events", - "confidential_note_events", - "pipeline_events", - ), - ), - "irker": ( - ("recipients",), - ( - "default_irc_uri", - "server_port", - "server_host", - "colorize_messages", - "push_events", - ), - ), - "jira": ( - ( - "url", - "username", - "password", - ), - ( - "api_url", - "active", - "jira_issue_transition_id", - "commit_events", - "merge_requests_events", - "comment_on_event_enabled", - ), - ), - "slack-slash-commands": (("token",), tuple()), - "mattermost-slash-commands": (("token",), ("username",)), - "packagist": ( - ("username", "token"), - ("server", "push_events", "merge_requests_events", "tag_push_events"), - ), - "mattermost": ( - ("webhook",), - ( - "username", - "channel", - "notify_only_broken_pipelines", - "notify_only_default_branch", - "branches_to_be_notified", - "push_events", - "issues_events", - "confidential_issues_events", - "merge_requests_events", - "tag_push_events", - "note_events", - "confidential_note_events", - "pipeline_events", - "wiki_page_events", - "push_channel", - "issue_channel", - "confidential_issue_channel" "merge_request_channel", - "note_channel", - "confidential_note_channel", - "tag_push_channel", - "pipeline_channel", - "wiki_page_channel", - ), - ), - "pivotaltracker": (("token",), ("restrict_to_branch", "push_events")), - "prometheus": (("api_url",), tuple()), - "pushover": ( - ("api_key", "user_key", "priority"), - ("device", "sound", "push_events"), - ), - "redmine": ( - ("new_issue_url", "project_url", "issues_url"), - ("description", "push_events"), - ), - "slack": ( - ("webhook",), - ( - "username", - "channel", - "notify_only_broken_pipelines", - "notify_only_default_branch", - "branches_to_be_notified", - "commit_events", - "confidential_issue_channel", - "confidential_issues_events", - "confidential_note_channel", - "confidential_note_events", - "deployment_channel", - "deployment_events", - "issue_channel", - "issues_events", - "job_events", - "merge_request_channel", - "merge_requests_events", - "note_channel", - "note_events", - "pipeline_channel", - "pipeline_events", - "push_channel", - "push_events", - "tag_push_channel", - "tag_push_events", - "wiki_page_channel", - "wiki_page_events", - ), - ), - "microsoft-teams": ( - ("webhook",), - ( - "notify_only_broken_pipelines", - "notify_only_default_branch", - "branches_to_be_notified", - "push_events", - "issues_events", - "confidential_issues_events", - "merge_requests_events", - "tag_push_events", - "note_events", - "confidential_note_events", - "pipeline_events", - "wiki_page_events", - ), - ), - "teamcity": ( - ("teamcity_url", "build_type", "username", "password"), - ("push_events",), - ), - "jenkins": (("jenkins_url", "project_name"), ("username", "password")), - "mock-ci": (("mock_service_url",), tuple()), - "youtrack": (("issues_url", "project_url"), ("description", "push_events")), - } - - def get(self, id, **kwargs): - """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 - """ - obj = super(ProjectServiceManager, self).get(id, **kwargs) - obj.id = id - return obj - - def update(self, id=None, new_data=None, **kwargs): - """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 {} - super(ProjectServiceManager, self).update(id, new_data, **kwargs) - self.id = id - - @cli.register_custom_action("ProjectServiceManager") - def available(self, **kwargs): - """List the services known by python-gitlab. - - Returns: - list (str): The list of service code names. - """ - return list(self._service_attrs.keys()) diff --git a/gitlab/v4/objects/settings.py b/gitlab/v4/objects/settings.py deleted file mode 100644 index 1c8be25..0000000 --- a/gitlab/v4/objects/settings.py +++ /dev/null @@ -1,109 +0,0 @@ -from gitlab import exceptions as exc -from gitlab import types -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import GetWithoutIdMixin, SaveMixin, UpdateMixin - -__all__ = [ - "ApplicationSettings", - "ApplicationSettingsManager", -] - - -class ApplicationSettings(SaveMixin, RESTObject): - _id_attr = None - - -class ApplicationSettingsManager(GetWithoutIdMixin, UpdateMixin, RESTManager): - _path = "/application/settings" - _obj_cls = ApplicationSettings - _update_attrs = RequiredOptional( - optional=( - "id", - "default_projects_limit", - "signup_enabled", - "password_authentication_enabled_for_web", - "gravatar_enabled", - "sign_in_text", - "created_at", - "updated_at", - "home_page_url", - "default_branch_protection", - "restricted_visibility_levels", - "max_attachment_size", - "session_expire_delay", - "default_project_visibility", - "default_snippet_visibility", - "default_group_visibility", - "outbound_local_requests_whitelist", - "disabled_oauth_sign_in_sources", - "domain_whitelist", - "domain_blacklist_enabled", - "domain_blacklist", - "domain_allowlist", - "domain_denylist_enabled", - "domain_denylist", - "external_authorization_service_enabled", - "external_authorization_service_url", - "external_authorization_service_default_label", - "external_authorization_service_timeout", - "import_sources", - "user_oauth_applications", - "after_sign_out_path", - "container_registry_token_expire_delay", - "repository_storages", - "plantuml_enabled", - "plantuml_url", - "terminal_max_session_time", - "polling_interval_multiplier", - "rsa_key_restriction", - "dsa_key_restriction", - "ecdsa_key_restriction", - "ed25519_key_restriction", - "first_day_of_week", - "enforce_terms", - "terms", - "performance_bar_allowed_group_id", - "instance_statistics_visibility_private", - "user_show_add_ssh_key_message", - "file_template_project_id", - "local_markdown_version", - "asset_proxy_enabled", - "asset_proxy_url", - "asset_proxy_whitelist", - "asset_proxy_allowlist", - "geo_node_allowed_ips", - "allow_local_requests_from_hooks_and_services", - "allow_local_requests_from_web_hooks_and_services", - "allow_local_requests_from_system_hooks", - ), - ) - _types = { - "asset_proxy_allowlist": types.ListAttribute, - "disabled_oauth_sign_in_sources": types.ListAttribute, - "domain_allowlist": types.ListAttribute, - "domain_denylist": types.ListAttribute, - "import_sources": types.ListAttribute, - "restricted_visibility_levels": types.ListAttribute, - } - - @exc.on_http_error(exc.GitlabUpdateError) - def update(self, id=None, new_data=None, **kwargs): - """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 {} - data = new_data.copy() - if "domain_whitelist" in data and data["domain_whitelist"] is None: - data.pop("domain_whitelist") - super(ApplicationSettingsManager, self).update(id, data, **kwargs) diff --git a/gitlab/v4/objects/sidekiq.py b/gitlab/v4/objects/sidekiq.py deleted file mode 100644 index dc1094a..0000000 --- a/gitlab/v4/objects/sidekiq.py +++ /dev/null @@ -1,83 +0,0 @@ -from gitlab import cli -from gitlab import exceptions as exc -from gitlab.base import RESTManager - -__all__ = [ - "SidekiqManager", -] - - -class SidekiqManager(RESTManager): - """Manager for the Sidekiq methods. - - This manager doesn't actually manage objects but provides helper function - for the sidekiq metrics API. - """ - - @cli.register_custom_action("SidekiqManager") - @exc.on_http_error(exc.GitlabGetError) - def queue_metrics(self, **kwargs): - """Return the registered queues information. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabGetError: If the information couldn't be retrieved - - Returns: - dict: Information about the Sidekiq queues - """ - return self.gitlab.http_get("/sidekiq/queue_metrics", **kwargs) - - @cli.register_custom_action("SidekiqManager") - @exc.on_http_error(exc.GitlabGetError) - def process_metrics(self, **kwargs): - """Return the registered sidekiq workers. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabGetError: If the information couldn't be retrieved - - Returns: - dict: Information about the register Sidekiq worker - """ - return self.gitlab.http_get("/sidekiq/process_metrics", **kwargs) - - @cli.register_custom_action("SidekiqManager") - @exc.on_http_error(exc.GitlabGetError) - def job_stats(self, **kwargs): - """Return statistics about the jobs performed. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabGetError: If the information couldn't be retrieved - - Returns: - dict: Statistics about the Sidekiq jobs performed - """ - return self.gitlab.http_get("/sidekiq/job_stats", **kwargs) - - @cli.register_custom_action("SidekiqManager") - @exc.on_http_error(exc.GitlabGetError) - def compound_metrics(self, **kwargs): - """Return all available metrics and statistics. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabGetError: If the information couldn't be retrieved - - Returns: - dict: All available Sidekiq metrics and statistics - """ - return self.gitlab.http_get("/sidekiq/compound_metrics", **kwargs) diff --git a/gitlab/v4/objects/snippets.py b/gitlab/v4/objects/snippets.py deleted file mode 100644 index 164b30c..0000000 --- a/gitlab/v4/objects/snippets.py +++ /dev/null @@ -1,123 +0,0 @@ -from gitlab import cli -from gitlab import exceptions as exc -from gitlab import utils -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CRUDMixin, ObjectDeleteMixin, SaveMixin, UserAgentDetailMixin - -from .award_emojis import ProjectSnippetAwardEmojiManager # noqa: F401 -from .discussions import ProjectSnippetDiscussionManager # noqa: F401 -from .notes import ProjectSnippetNoteManager # noqa: F401 - -__all__ = [ - "Snippet", - "SnippetManager", - "ProjectSnippet", - "ProjectSnippetManager", -] - - -class Snippet(UserAgentDetailMixin, SaveMixin, ObjectDeleteMixin, RESTObject): - _short_print_attr = "title" - - @cli.register_custom_action("Snippet") - @exc.on_http_error(exc.GitlabGetError) - def content(self, streamed=False, action=None, chunk_size=1024, **kwargs): - """Return the content of a snippet. - - 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 content could not be retrieved - - Returns: - str: The snippet content - """ - path = "/snippets/%s/raw" % self.get_id() - result = self.manager.gitlab.http_get( - path, streamed=streamed, raw=True, **kwargs - ) - return utils.response_content(result, streamed, action, chunk_size) - - -class SnippetManager(CRUDMixin, RESTManager): - _path = "/snippets" - _obj_cls = Snippet - _create_attrs = RequiredOptional( - required=("title", "file_name", "content"), optional=("lifetime", "visibility") - ) - _update_attrs = RequiredOptional( - optional=("title", "file_name", "content", "visibility") - ) - - @cli.register_custom_action("SnippetManager") - def public(self, **kwargs): - """List all the public snippets. - - Args: - all (bool): If True the returned object will be a list - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabListError: If the list could not be retrieved - - Returns: - RESTObjectList: A generator for the snippets list - """ - return self.list(path="/snippets/public", **kwargs) - - -class ProjectSnippet(UserAgentDetailMixin, SaveMixin, ObjectDeleteMixin, RESTObject): - _url = "/projects/%(project_id)s/snippets" - _short_print_attr = "title" - - awardemojis: ProjectSnippetAwardEmojiManager - discussions: ProjectSnippetDiscussionManager - notes: ProjectSnippetNoteManager - - @cli.register_custom_action("ProjectSnippet") - @exc.on_http_error(exc.GitlabGetError) - def content(self, streamed=False, action=None, chunk_size=1024, **kwargs): - """Return the content of a snippet. - - 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 content could not be retrieved - - Returns: - str: The snippet content - """ - path = "%s/%s/raw" % (self.manager.path, self.get_id()) - result = self.manager.gitlab.http_get( - path, streamed=streamed, raw=True, **kwargs - ) - return utils.response_content(result, streamed, action, chunk_size) - - -class ProjectSnippetManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/snippets" - _obj_cls = ProjectSnippet - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("title", "file_name", "content", "visibility"), - optional=("description",), - ) - _update_attrs = RequiredOptional( - optional=("title", "file_name", "content", "visibility", "description"), - ) diff --git a/gitlab/v4/objects/statistics.py b/gitlab/v4/objects/statistics.py deleted file mode 100644 index 5d7c19e..0000000 --- a/gitlab/v4/objects/statistics.py +++ /dev/null @@ -1,52 +0,0 @@ -from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import GetWithoutIdMixin, RefreshMixin - -__all__ = [ - "GroupIssuesStatistics", - "GroupIssuesStatisticsManager", - "ProjectAdditionalStatistics", - "ProjectAdditionalStatisticsManager", - "IssuesStatistics", - "IssuesStatisticsManager", - "ProjectIssuesStatistics", - "ProjectIssuesStatisticsManager", -] - - -class ProjectAdditionalStatistics(RefreshMixin, RESTObject): - _id_attr = None - - -class ProjectAdditionalStatisticsManager(GetWithoutIdMixin, RESTManager): - _path = "/projects/%(project_id)s/statistics" - _obj_cls = ProjectAdditionalStatistics - _from_parent_attrs = {"project_id": "id"} - - -class IssuesStatistics(RefreshMixin, RESTObject): - _id_attr = None - - -class IssuesStatisticsManager(GetWithoutIdMixin, RESTManager): - _path = "/issues_statistics" - _obj_cls = IssuesStatistics - - -class GroupIssuesStatistics(RefreshMixin, RESTObject): - _id_attr = None - - -class GroupIssuesStatisticsManager(GetWithoutIdMixin, RESTManager): - _path = "/groups/%(group_id)s/issues_statistics" - _obj_cls = GroupIssuesStatistics - _from_parent_attrs = {"group_id": "id"} - - -class ProjectIssuesStatistics(RefreshMixin, RESTObject): - _id_attr = None - - -class ProjectIssuesStatisticsManager(GetWithoutIdMixin, RESTManager): - _path = "/projects/%(project_id)s/issues_statistics" - _obj_cls = ProjectIssuesStatistics - _from_parent_attrs = {"project_id": "id"} diff --git a/gitlab/v4/objects/tags.py b/gitlab/v4/objects/tags.py deleted file mode 100644 index 44fc23c..0000000 --- a/gitlab/v4/objects/tags.py +++ /dev/null @@ -1,37 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import NoUpdateMixin, ObjectDeleteMixin - -__all__ = [ - "ProjectTag", - "ProjectTagManager", - "ProjectProtectedTag", - "ProjectProtectedTagManager", -] - - -class ProjectTag(ObjectDeleteMixin, RESTObject): - _id_attr = "name" - _short_print_attr = "name" - - -class ProjectTagManager(NoUpdateMixin, RESTManager): - _path = "/projects/%(project_id)s/repository/tags" - _obj_cls = ProjectTag - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("tag_name", "ref"), optional=("message",) - ) - - -class ProjectProtectedTag(ObjectDeleteMixin, RESTObject): - _id_attr = "name" - _short_print_attr = "name" - - -class ProjectProtectedTagManager(NoUpdateMixin, RESTManager): - _path = "/projects/%(project_id)s/protected_tags" - _obj_cls = ProjectProtectedTag - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("name",), optional=("create_access_level",) - ) diff --git a/gitlab/v4/objects/templates.py b/gitlab/v4/objects/templates.py deleted file mode 100644 index 04de463..0000000 --- a/gitlab/v4/objects/templates.py +++ /dev/null @@ -1,51 +0,0 @@ -from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import RetrieveMixin - -__all__ = [ - "Dockerfile", - "DockerfileManager", - "Gitignore", - "GitignoreManager", - "Gitlabciyml", - "GitlabciymlManager", - "License", - "LicenseManager", -] - - -class Dockerfile(RESTObject): - _id_attr = "name" - - -class DockerfileManager(RetrieveMixin, RESTManager): - _path = "/templates/dockerfiles" - _obj_cls = Dockerfile - - -class Gitignore(RESTObject): - _id_attr = "name" - - -class GitignoreManager(RetrieveMixin, RESTManager): - _path = "/templates/gitignores" - _obj_cls = Gitignore - - -class Gitlabciyml(RESTObject): - _id_attr = "name" - - -class GitlabciymlManager(RetrieveMixin, RESTManager): - _path = "/templates/gitlab_ci_ymls" - _obj_cls = Gitlabciyml - - -class License(RESTObject): - _id_attr = "key" - - -class LicenseManager(RetrieveMixin, RESTManager): - _path = "/templates/licenses" - _obj_cls = License - _list_filters = ("popular",) - _optional_get_attrs = ("project", "fullname") diff --git a/gitlab/v4/objects/todos.py b/gitlab/v4/objects/todos.py deleted file mode 100644 index de82437..0000000 --- a/gitlab/v4/objects/todos.py +++ /dev/null @@ -1,50 +0,0 @@ -from gitlab import cli -from gitlab import exceptions as exc -from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import DeleteMixin, ListMixin, ObjectDeleteMixin - -__all__ = [ - "Todo", - "TodoManager", -] - - -class Todo(ObjectDeleteMixin, RESTObject): - @cli.register_custom_action("Todo") - @exc.on_http_error(exc.GitlabTodoError) - def mark_as_done(self, **kwargs): - """Mark the todo as done. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabTodoError: If the server failed to perform the request - """ - path = "%s/%s/mark_as_done" % (self.manager.path, self.id) - server_data = self.manager.gitlab.http_post(path, **kwargs) - self._update_attrs(server_data) - - -class TodoManager(ListMixin, DeleteMixin, RESTManager): - _path = "/todos" - _obj_cls = Todo - _list_filters = ("action", "author_id", "project_id", "state", "type") - - @cli.register_custom_action("TodoManager") - @exc.on_http_error(exc.GitlabTodoError) - def mark_all_as_done(self, **kwargs): - """Mark all the todos as done. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabTodoError: If the server failed to perform the request - - Returns: - int: The number of todos marked done - """ - self.gitlab.http_post("/todos/mark_as_done", **kwargs) diff --git a/gitlab/v4/objects/triggers.py b/gitlab/v4/objects/triggers.py deleted file mode 100644 index f203d93..0000000 --- a/gitlab/v4/objects/triggers.py +++ /dev/null @@ -1,19 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CRUDMixin, ObjectDeleteMixin, SaveMixin - -__all__ = [ - "ProjectTrigger", - "ProjectTriggerManager", -] - - -class ProjectTrigger(SaveMixin, ObjectDeleteMixin, RESTObject): - pass - - -class ProjectTriggerManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/triggers" - _obj_cls = ProjectTrigger - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional(required=("description",)) - _update_attrs = RequiredOptional(required=("description",)) diff --git a/gitlab/v4/objects/users.py b/gitlab/v4/objects/users.py deleted file mode 100644 index e4bbcf1..0000000 --- a/gitlab/v4/objects/users.py +++ /dev/null @@ -1,514 +0,0 @@ -from typing import Any, cast, Dict, List, Union - -import requests - -from gitlab import cli -from gitlab import exceptions as exc -from gitlab import types -from gitlab.base import RequiredOptional, RESTManager, RESTObject, RESTObjectList -from gitlab.mixins import ( - CreateMixin, - CRUDMixin, - DeleteMixin, - GetWithoutIdMixin, - ListMixin, - NoUpdateMixin, - ObjectDeleteMixin, - RetrieveMixin, - SaveMixin, - UpdateMixin, -) - -from .custom_attributes import UserCustomAttributeManager # noqa: F401 -from .events import UserEventManager # noqa: F401 -from .personal_access_tokens import UserPersonalAccessTokenManager # noqa: F401 - -__all__ = [ - "CurrentUserEmail", - "CurrentUserEmailManager", - "CurrentUserGPGKey", - "CurrentUserGPGKeyManager", - "CurrentUserKey", - "CurrentUserKeyManager", - "CurrentUserStatus", - "CurrentUserStatusManager", - "CurrentUser", - "CurrentUserManager", - "User", - "UserManager", - "ProjectUser", - "ProjectUserManager", - "UserEmail", - "UserEmailManager", - "UserActivities", - "UserStatus", - "UserStatusManager", - "UserActivitiesManager", - "UserGPGKey", - "UserGPGKeyManager", - "UserKey", - "UserKeyManager", - "UserIdentityProviderManager", - "UserImpersonationToken", - "UserImpersonationTokenManager", - "UserMembership", - "UserMembershipManager", - "UserProject", - "UserProjectManager", -] - - -class CurrentUserEmail(ObjectDeleteMixin, RESTObject): - _short_print_attr = "email" - - -class CurrentUserEmailManager(RetrieveMixin, CreateMixin, DeleteMixin, RESTManager): - _path = "/user/emails" - _obj_cls = CurrentUserEmail - _create_attrs = RequiredOptional(required=("email",)) - - -class CurrentUserGPGKey(ObjectDeleteMixin, RESTObject): - pass - - -class CurrentUserGPGKeyManager(RetrieveMixin, CreateMixin, DeleteMixin, RESTManager): - _path = "/user/gpg_keys" - _obj_cls = CurrentUserGPGKey - _create_attrs = RequiredOptional(required=("key",)) - - -class CurrentUserKey(ObjectDeleteMixin, RESTObject): - _short_print_attr = "title" - - -class CurrentUserKeyManager(RetrieveMixin, CreateMixin, DeleteMixin, RESTManager): - _path = "/user/keys" - _obj_cls = CurrentUserKey - _create_attrs = RequiredOptional(required=("title", "key")) - - -class CurrentUserStatus(SaveMixin, RESTObject): - _id_attr = None - _short_print_attr = "message" - - -class CurrentUserStatusManager(GetWithoutIdMixin, UpdateMixin, RESTManager): - _path = "/user/status" - _obj_cls = CurrentUserStatus - _update_attrs = RequiredOptional(optional=("emoji", "message")) - - -class CurrentUser(RESTObject): - _id_attr = None - _short_print_attr = "username" - - emails: CurrentUserEmailManager - gpgkeys: CurrentUserGPGKeyManager - keys: CurrentUserKeyManager - status: CurrentUserStatusManager - - -class CurrentUserManager(GetWithoutIdMixin, RESTManager): - _path = "/user" - _obj_cls = CurrentUser - - -class User(SaveMixin, ObjectDeleteMixin, RESTObject): - _short_print_attr = "username" - - customattributes: UserCustomAttributeManager - emails: "UserEmailManager" - events: UserEventManager - followers_users: "UserFollowersManager" - following_users: "UserFollowingManager" - gpgkeys: "UserGPGKeyManager" - identityproviders: "UserIdentityProviderManager" - impersonationtokens: "UserImpersonationTokenManager" - keys: "UserKeyManager" - memberships: "UserMembershipManager" - personal_access_tokens: UserPersonalAccessTokenManager - projects: "UserProjectManager" - status: "UserStatusManager" - - @cli.register_custom_action("User") - @exc.on_http_error(exc.GitlabBlockError) - def block(self, **kwargs: Any) -> Union[Dict[str, Any], requests.Response]: - """Block the user. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabBlockError: If the user could not be blocked - - Returns: - bool: Whether the user status has been changed - """ - path = "/users/%s/block" % self.id - server_data = self.manager.gitlab.http_post(path, **kwargs) - if server_data is True: - self._attrs["state"] = "blocked" - return server_data - - @cli.register_custom_action("User") - @exc.on_http_error(exc.GitlabFollowError) - def follow(self, **kwargs: Any) -> Union[Dict[str, Any], requests.Response]: - """Follow the user. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabFollowError: If the user could not be followed - - Returns: - dict: The new object data (*not* a RESTObject) - """ - path = "/users/%s/follow" % self.id - return self.manager.gitlab.http_post(path, **kwargs) - - @cli.register_custom_action("User") - @exc.on_http_error(exc.GitlabUnfollowError) - def unfollow(self, **kwargs: Any) -> Union[Dict[str, Any], requests.Response]: - """Unfollow the user. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabUnfollowError: If the user could not be followed - - Returns: - dict: The new object data (*not* a RESTObject) - """ - path = "/users/%s/unfollow" % self.id - return self.manager.gitlab.http_post(path, **kwargs) - - @cli.register_custom_action("User") - @exc.on_http_error(exc.GitlabUnblockError) - def unblock(self, **kwargs: Any) -> Union[Dict[str, Any], requests.Response]: - """Unblock the user. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabUnblockError: If the user could not be unblocked - - Returns: - bool: Whether the user status has been changed - """ - path = "/users/%s/unblock" % self.id - server_data = self.manager.gitlab.http_post(path, **kwargs) - if server_data is True: - self._attrs["state"] = "active" - return server_data - - @cli.register_custom_action("User") - @exc.on_http_error(exc.GitlabDeactivateError) - def deactivate(self, **kwargs: Any) -> Union[Dict[str, Any], requests.Response]: - """Deactivate the user. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabDeactivateError: If the user could not be deactivated - - Returns: - bool: Whether the user status has been changed - """ - path = "/users/%s/deactivate" % self.id - server_data = self.manager.gitlab.http_post(path, **kwargs) - if server_data: - self._attrs["state"] = "deactivated" - return server_data - - @cli.register_custom_action("User") - @exc.on_http_error(exc.GitlabActivateError) - def activate(self, **kwargs: Any) -> Union[Dict[str, Any], requests.Response]: - """Activate the user. - - Args: - **kwargs: Extra options to send to the server (e.g. sudo) - - Raises: - GitlabAuthenticationError: If authentication is not correct - GitlabActivateError: If the user could not be activated - - Returns: - bool: Whether the user status has been changed - """ - path = "/users/%s/activate" % self.id - server_data = self.manager.gitlab.http_post(path, **kwargs) - if server_data: - self._attrs["state"] = "active" - return server_data - - -class UserManager(CRUDMixin, RESTManager): - _path = "/users" - _obj_cls = User - - _list_filters = ( - "active", - "blocked", - "username", - "extern_uid", - "provider", - "external", - "search", - "custom_attributes", - "status", - "two_factor", - ) - _create_attrs = RequiredOptional( - optional=( - "email", - "username", - "name", - "password", - "reset_password", - "skype", - "linkedin", - "twitter", - "projects_limit", - "extern_uid", - "provider", - "bio", - "admin", - "can_create_group", - "website_url", - "skip_confirmation", - "external", - "organization", - "location", - "avatar", - "public_email", - "private_profile", - "color_scheme_id", - "theme_id", - ), - ) - _update_attrs = RequiredOptional( - required=("email", "username", "name"), - optional=( - "password", - "skype", - "linkedin", - "twitter", - "projects_limit", - "extern_uid", - "provider", - "bio", - "admin", - "can_create_group", - "website_url", - "skip_reconfirmation", - "external", - "organization", - "location", - "avatar", - "public_email", - "private_profile", - "color_scheme_id", - "theme_id", - ), - ) - _types = {"confirm": types.LowercaseStringAttribute, "avatar": types.ImageAttribute} - - def get(self, id: Union[str, int], lazy: bool = False, **kwargs: Any) -> User: - return cast(User, super().get(id=id, lazy=lazy, **kwargs)) - - -class ProjectUser(RESTObject): - pass - - -class ProjectUserManager(ListMixin, RESTManager): - _path = "/projects/%(project_id)s/users" - _obj_cls = ProjectUser - _from_parent_attrs = {"project_id": "id"} - _list_filters = ("search", "skip_users") - _types = {"skip_users": types.ListAttribute} - - -class UserEmail(ObjectDeleteMixin, RESTObject): - _short_print_attr = "email" - - -class UserEmailManager(RetrieveMixin, CreateMixin, DeleteMixin, RESTManager): - _path = "/users/%(user_id)s/emails" - _obj_cls = UserEmail - _from_parent_attrs = {"user_id": "id"} - _create_attrs = RequiredOptional(required=("email",)) - - -class UserActivities(RESTObject): - _id_attr = "username" - - -class UserStatus(RESTObject): - _id_attr = None - _short_print_attr = "message" - - -class UserStatusManager(GetWithoutIdMixin, RESTManager): - _path = "/users/%(user_id)s/status" - _obj_cls = UserStatus - _from_parent_attrs = {"user_id": "id"} - - -class UserActivitiesManager(ListMixin, RESTManager): - _path = "/user/activities" - _obj_cls = UserActivities - - -class UserGPGKey(ObjectDeleteMixin, RESTObject): - pass - - -class UserGPGKeyManager(RetrieveMixin, CreateMixin, DeleteMixin, RESTManager): - _path = "/users/%(user_id)s/gpg_keys" - _obj_cls = UserGPGKey - _from_parent_attrs = {"user_id": "id"} - _create_attrs = RequiredOptional(required=("key",)) - - -class UserKey(ObjectDeleteMixin, RESTObject): - pass - - -class UserKeyManager(ListMixin, CreateMixin, DeleteMixin, RESTManager): - _path = "/users/%(user_id)s/keys" - _obj_cls = UserKey - _from_parent_attrs = {"user_id": "id"} - _create_attrs = RequiredOptional(required=("title", "key")) - - -class UserIdentityProviderManager(DeleteMixin, RESTManager): - """Manager for user identities. - - This manager does not actually manage objects but enables - functionality for deletion of user identities by provider. - """ - - _path = "/users/%(user_id)s/identities" - _from_parent_attrs = {"user_id": "id"} - - -class UserImpersonationToken(ObjectDeleteMixin, RESTObject): - pass - - -class UserImpersonationTokenManager(NoUpdateMixin, RESTManager): - _path = "/users/%(user_id)s/impersonation_tokens" - _obj_cls = UserImpersonationToken - _from_parent_attrs = {"user_id": "id"} - _create_attrs = RequiredOptional( - required=("name", "scopes"), optional=("expires_at",) - ) - _list_filters = ("state",) - - -class UserMembership(RESTObject): - _id_attr = "source_id" - - -class UserMembershipManager(RetrieveMixin, RESTManager): - _path = "/users/%(user_id)s/memberships" - _obj_cls = UserMembership - _from_parent_attrs = {"user_id": "id"} - _list_filters = ("type",) - - -# Having this outside projects avoids circular imports due to ProjectUser -class UserProject(RESTObject): - pass - - -class UserProjectManager(ListMixin, CreateMixin, RESTManager): - _path = "/projects/user/%(user_id)s" - _obj_cls = UserProject - _from_parent_attrs = {"user_id": "id"} - _create_attrs = RequiredOptional( - required=("name",), - optional=( - "default_branch", - "issues_enabled", - "wall_enabled", - "merge_requests_enabled", - "wiki_enabled", - "snippets_enabled", - "public", - "visibility", - "description", - "builds_enabled", - "public_builds", - "import_url", - "only_allow_merge_if_build_succeeds", - ), - ) - _list_filters = ( - "archived", - "visibility", - "order_by", - "sort", - "search", - "simple", - "owned", - "membership", - "starred", - "statistics", - "with_issues_enabled", - "with_merge_requests_enabled", - "with_custom_attributes", - "with_programming_language", - "wiki_checksum_failed", - "repository_checksum_failed", - "min_access_level", - "id_after", - "id_before", - ) - - def list(self, **kwargs: Any) -> Union[RESTObjectList, List[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 - """ - if self._parent: - path = "/users/%s/projects" % self._parent.id - else: - path = "/users/%s/projects" % kwargs["user_id"] - return ListMixin.list(self, path=path, **kwargs) - - -class UserFollowersManager(ListMixin, RESTManager): - _path = "/users/%(user_id)s/followers" - _obj_cls = User - _from_parent_attrs = {"user_id": "id"} - - -class UserFollowingManager(ListMixin, RESTManager): - _path = "/users/%(user_id)s/following" - _obj_cls = User - _from_parent_attrs = {"user_id": "id"} diff --git a/gitlab/v4/objects/variables.py b/gitlab/v4/objects/variables.py deleted file mode 100644 index 2e5e483..0000000 --- a/gitlab/v4/objects/variables.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -GitLab API: -https://docs.gitlab.com/ee/api/instance_level_ci_variables.html -https://docs.gitlab.com/ee/api/project_level_variables.html -https://docs.gitlab.com/ee/api/group_level_variables.html -""" -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CRUDMixin, ObjectDeleteMixin, SaveMixin - -__all__ = [ - "Variable", - "VariableManager", - "GroupVariable", - "GroupVariableManager", - "ProjectVariable", - "ProjectVariableManager", -] - - -class Variable(SaveMixin, ObjectDeleteMixin, RESTObject): - _id_attr = "key" - - -class VariableManager(CRUDMixin, RESTManager): - _path = "/admin/ci/variables" - _obj_cls = Variable - _create_attrs = RequiredOptional( - required=("key", "value"), optional=("protected", "variable_type", "masked") - ) - _update_attrs = RequiredOptional( - required=("key", "value"), optional=("protected", "variable_type", "masked") - ) - - -class GroupVariable(SaveMixin, ObjectDeleteMixin, RESTObject): - _id_attr = "key" - - -class GroupVariableManager(CRUDMixin, RESTManager): - _path = "/groups/%(group_id)s/variables" - _obj_cls = GroupVariable - _from_parent_attrs = {"group_id": "id"} - _create_attrs = RequiredOptional( - required=("key", "value"), optional=("protected", "variable_type", "masked") - ) - _update_attrs = RequiredOptional( - required=("key", "value"), optional=("protected", "variable_type", "masked") - ) - - -class ProjectVariable(SaveMixin, ObjectDeleteMixin, RESTObject): - _id_attr = "key" - - -class ProjectVariableManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/variables" - _obj_cls = ProjectVariable - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("key", "value"), - optional=("protected", "variable_type", "masked", "environment_scope"), - ) - _update_attrs = RequiredOptional( - required=("key", "value"), - optional=("protected", "variable_type", "masked", "environment_scope"), - ) diff --git a/gitlab/v4/objects/wikis.py b/gitlab/v4/objects/wikis.py deleted file mode 100644 index a86b442..0000000 --- a/gitlab/v4/objects/wikis.py +++ /dev/null @@ -1,41 +0,0 @@ -from gitlab.base import RequiredOptional, RESTManager, RESTObject -from gitlab.mixins import CRUDMixin, ObjectDeleteMixin, SaveMixin - -__all__ = [ - "ProjectWiki", - "ProjectWikiManager", - "GroupWiki", - "GroupWikiManager", -] - - -class ProjectWiki(SaveMixin, ObjectDeleteMixin, RESTObject): - _id_attr = "slug" - _short_print_attr = "slug" - - -class ProjectWikiManager(CRUDMixin, RESTManager): - _path = "/projects/%(project_id)s/wikis" - _obj_cls = ProjectWiki - _from_parent_attrs = {"project_id": "id"} - _create_attrs = RequiredOptional( - required=("title", "content"), optional=("format",) - ) - _update_attrs = RequiredOptional(optional=("title", "content", "format")) - _list_filters = ("with_content",) - - -class GroupWiki(SaveMixin, ObjectDeleteMixin, RESTObject): - _id_attr = "slug" - _short_print_attr = "slug" - - -class GroupWikiManager(CRUDMixin, RESTManager): - _path = "/groups/%(group_id)s/wikis" - _obj_cls = GroupWiki - _from_parent_attrs = {"group_id": "id"} - _create_attrs = RequiredOptional( - required=("title", "content"), optional=("format",) - ) - _update_attrs = RequiredOptional(optional=("title", "content", "format")) - _list_filters = ("with_content",) |