This commit is contained in:
2024-12-09 18:22:38 +09:00
parent ab0cbebefc
commit c4c4547706
959 changed files with 174888 additions and 6 deletions

View File

@ -0,0 +1,79 @@
from .access_requests import *
from .appearance import *
from .applications import *
from .artifacts import *
from .audit_events import *
from .award_emojis import *
from .badges import *
from .boards import *
from .branches import *
from .broadcast_messages import *
from .bulk_imports import *
from .ci_lint import *
from .cluster_agents 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 .draft_notes 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 .group_access_tokens import *
from .groups import *
from .hooks import *
from .integrations import *
from .invitations import *
from .issues import *
from .iterations import *
from .job_token_scope 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 .merge_trains import *
from .milestones import *
from .namespaces import *
from .notes import *
from .notification_settings import *
from .package_protection_rules import *
from .packages import *
from .pages import *
from .personal_access_tokens import *
from .pipelines import *
from .project_access_tokens import *
from .projects import *
from .push_rules import *
from .registry_protection_rules import *
from .releases import *
from .repositories import *
from .resource_groups import *
from .reviewers import *
from .runners import *
from .secure_files import *
from .service_accounts import *
from .settings import *
from .sidekiq import *
from .snippets import *
from .statistics import *
from .tags import *
from .templates import *
from .todos import *
from .topics import *
from .triggers import *
from .users import *
from .variables import *
from .wikis import *
__all__ = [name for name in dir() if not name.startswith("_")]

View File

@ -0,0 +1,35 @@
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}/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}/access_requests"
_obj_cls = ProjectAccessRequest
_from_parent_attrs = {"project_id": "id"}

View File

@ -0,0 +1,63 @@
from typing import Any, cast, Dict, Optional, Union
from gitlab import exceptions as exc
from gitlab.base import RESTManager, RESTObject
from gitlab.mixins import GetWithoutIdMixin, SaveMixin, UpdateMixin
from gitlab.types import RequiredOptional
__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: Optional[Union[str, int]] = None,
new_data: Optional[Dict[str, Any]] = None,
**kwargs: Any,
) -> Dict[str, Any]:
"""Update an object on the server.
Args:
id: ID of the object to update (can be None if not required)
new_data: the update data for the object
**kwargs: Extra options to send to the server (e.g. sudo)
Returns:
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()
return super().update(id, data, **kwargs)
def get(self, **kwargs: Any) -> ApplicationAppearance:
return cast(ApplicationAppearance, super().get(**kwargs))

View File

@ -0,0 +1,21 @@
from gitlab.base import RESTManager, RESTObject
from gitlab.mixins import CreateMixin, DeleteMixin, ListMixin, ObjectDeleteMixin
from gitlab.types import RequiredOptional
__all__ = [
"Application",
"ApplicationManager",
]
class Application(ObjectDeleteMixin, RESTObject):
_url = "/applications"
_repr_attr = "name"
class ApplicationManager(ListMixin, CreateMixin, DeleteMixin, RESTManager):
_path = "/applications"
_obj_cls = Application
_create_attrs = RequiredOptional(
required=("name", "redirect_uri", "scopes"), optional=("confidential",)
)

View File

@ -0,0 +1,147 @@
"""
GitLab API:
https://docs.gitlab.com/ee/api/job_artifacts.html
"""
from typing import Any, Callable, Iterator, 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
__all__ = ["ProjectArtifact", "ProjectArtifactManager"]
class ProjectArtifact(RESTObject):
"""Dummy object to manage custom actions on artifacts"""
_id_attr = "ref_name"
class ProjectArtifactManager(RESTManager):
_obj_cls = ProjectArtifact
_path = "/projects/{project_id}/jobs/artifacts"
_from_parent_attrs = {"project_id": "id"}
@exc.on_http_error(exc.GitlabDeleteError)
def delete(self, **kwargs: Any) -> None:
"""Delete the project's artifacts on the server.
Args:
**kwargs: Extra options to send to the server (e.g. sudo)
Raises:
GitlabAuthenticationError: If authentication is not correct
GitlabDeleteError: If the server cannot perform the request
"""
path = self._compute_path("/projects/{project_id}/artifacts")
if TYPE_CHECKING:
assert path is not None
self.gitlab.http_delete(path, **kwargs)
@cli.register_custom_action(
cls_names="ProjectArtifactManager",
required=("ref_name", "job"),
optional=("job_token",),
)
@exc.on_http_error(exc.GitlabGetError)
def download(
self,
ref_name: str,
job: str,
streamed: bool = False,
action: Optional[Callable[[bytes], None]] = None,
chunk_size: int = 1024,
*,
iterator: bool = False,
**kwargs: Any,
) -> Optional[Union[bytes, Iterator[Any]]]:
"""Get the job artifacts archive from a specific tag or branch.
Args:
ref_name: Branch or tag name in repository. HEAD or SHA references
are not supported.
job: The name of the job.
job_token: Job token for multi-project pipeline triggers.
streamed: If True the data will be processed by chunks of
`chunk_size` and each chunk is passed to `action` for
treatment
iterator: If True directly return the underlying response
iterator
action: Callable responsible of dealing with chunk of
data
chunk_size: 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:
The artifacts if `streamed` is False, None otherwise.
"""
path = f"{self.path}/{ref_name}/download"
result = self.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, iterator=iterator
)
@cli.register_custom_action(
cls_names="ProjectArtifactManager",
required=("ref_name", "artifact_path", "job"),
)
@exc.on_http_error(exc.GitlabGetError)
def raw(
self,
ref_name: str,
artifact_path: str,
job: str,
streamed: bool = False,
action: Optional[Callable[[bytes], None]] = None,
chunk_size: int = 1024,
*,
iterator: bool = False,
**kwargs: Any,
) -> Optional[Union[bytes, Iterator[Any]]]:
"""Download a single artifact file from a specific tag or branch from
within the job's artifacts archive.
Args:
ref_name: Branch or tag name in repository. HEAD or SHA references
are not supported.
artifact_path: Path to a file inside the artifacts archive.
job: The name of the job.
streamed: If True the data will be processed by chunks of
`chunk_size` and each chunk is passed to `action` for
treatment
iterator: If True directly return the underlying response
iterator
action: Callable responsible of dealing with chunk of
data
chunk_size: 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:
The artifact if `streamed` is False, None otherwise.
"""
path = f"{self.path}/{ref_name}/raw/{artifact_path}"
result = self.gitlab.http_get(
path, streamed=streamed, raw=True, job=job, **kwargs
)
if TYPE_CHECKING:
assert isinstance(result, requests.Response)
return utils.response_content(
result, streamed, action, chunk_size, iterator=iterator
)

View File

@ -0,0 +1,73 @@
"""
GitLab API:
https://docs.gitlab.com/ee/api/audit_events.html
"""
from typing import Any, cast, Union
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")
def get(self, id: Union[str, int], lazy: bool = False, **kwargs: Any) -> AuditEvent:
return cast(AuditEvent, super().get(id=id, lazy=lazy, **kwargs))
class GroupAuditEvent(RESTObject):
_id_attr = "id"
class GroupAuditEventManager(RetrieveMixin, RESTManager):
_path = "/groups/{group_id}/audit_events"
_obj_cls = GroupAuditEvent
_from_parent_attrs = {"group_id": "id"}
_list_filters = ("created_after", "created_before")
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> GroupAuditEvent:
return cast(GroupAuditEvent, super().get(id=id, lazy=lazy, **kwargs))
class ProjectAuditEvent(RESTObject):
_id_attr = "id"
class ProjectAuditEventManager(RetrieveMixin, RESTManager):
_path = "/projects/{project_id}/audit_events"
_obj_cls = ProjectAuditEvent
_from_parent_attrs = {"project_id": "id"}
_list_filters = ("created_after", "created_before")
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectAuditEvent:
return cast(ProjectAuditEvent, super().get(id=id, lazy=lazy, **kwargs))
class ProjectAudit(ProjectAuditEvent):
pass
class ProjectAuditManager(ProjectAuditEventManager):
pass

View File

@ -0,0 +1,174 @@
from typing import Any, cast, Union
from gitlab.base import RESTManager, RESTObject
from gitlab.mixins import NoUpdateMixin, ObjectDeleteMixin
from gitlab.types import RequiredOptional
__all__ = [
"GroupEpicAwardEmoji",
"GroupEpicAwardEmojiManager",
"GroupEpicNoteAwardEmoji",
"GroupEpicNoteAwardEmojiManager",
"ProjectIssueAwardEmoji",
"ProjectIssueAwardEmojiManager",
"ProjectIssueNoteAwardEmoji",
"ProjectIssueNoteAwardEmojiManager",
"ProjectMergeRequestAwardEmoji",
"ProjectMergeRequestAwardEmojiManager",
"ProjectMergeRequestNoteAwardEmoji",
"ProjectMergeRequestNoteAwardEmojiManager",
"ProjectSnippetAwardEmoji",
"ProjectSnippetAwardEmojiManager",
"ProjectSnippetNoteAwardEmoji",
"ProjectSnippetNoteAwardEmojiManager",
]
class GroupEpicAwardEmoji(ObjectDeleteMixin, RESTObject):
pass
class GroupEpicAwardEmojiManager(NoUpdateMixin, RESTManager):
_path = "/groups/{group_id}/epics/{epic_iid}/award_emoji"
_obj_cls = GroupEpicAwardEmoji
_from_parent_attrs = {"group_id": "group_id", "epic_iid": "iid"}
_create_attrs = RequiredOptional(required=("name",))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> GroupEpicAwardEmoji:
return cast(GroupEpicAwardEmoji, super().get(id=id, lazy=lazy, **kwargs))
class GroupEpicNoteAwardEmoji(ObjectDeleteMixin, RESTObject):
pass
class GroupEpicNoteAwardEmojiManager(NoUpdateMixin, RESTManager):
_path = "/groups/{group_id}/epics/{epic_iid}/notes/{note_id}/award_emoji"
_obj_cls = GroupEpicNoteAwardEmoji
_from_parent_attrs = {
"group_id": "group_id",
"epic_iid": "epic_iid",
"note_id": "id",
}
_create_attrs = RequiredOptional(required=("name",))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> GroupEpicNoteAwardEmoji:
return cast(GroupEpicNoteAwardEmoji, super().get(id=id, lazy=lazy, **kwargs))
class ProjectIssueAwardEmoji(ObjectDeleteMixin, RESTObject):
pass
class ProjectIssueAwardEmojiManager(NoUpdateMixin, RESTManager):
_path = "/projects/{project_id}/issues/{issue_iid}/award_emoji"
_obj_cls = ProjectIssueAwardEmoji
_from_parent_attrs = {"project_id": "project_id", "issue_iid": "iid"}
_create_attrs = RequiredOptional(required=("name",))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectIssueAwardEmoji:
return cast(ProjectIssueAwardEmoji, super().get(id=id, lazy=lazy, **kwargs))
class ProjectIssueNoteAwardEmoji(ObjectDeleteMixin, RESTObject):
pass
class ProjectIssueNoteAwardEmojiManager(NoUpdateMixin, RESTManager):
_path = "/projects/{project_id}/issues/{issue_iid}/notes/{note_id}/award_emoji"
_obj_cls = ProjectIssueNoteAwardEmoji
_from_parent_attrs = {
"project_id": "project_id",
"issue_iid": "issue_iid",
"note_id": "id",
}
_create_attrs = RequiredOptional(required=("name",))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectIssueNoteAwardEmoji:
return cast(ProjectIssueNoteAwardEmoji, super().get(id=id, lazy=lazy, **kwargs))
class ProjectMergeRequestAwardEmoji(ObjectDeleteMixin, RESTObject):
pass
class ProjectMergeRequestAwardEmojiManager(NoUpdateMixin, RESTManager):
_path = "/projects/{project_id}/merge_requests/{mr_iid}/award_emoji"
_obj_cls = ProjectMergeRequestAwardEmoji
_from_parent_attrs = {"project_id": "project_id", "mr_iid": "iid"}
_create_attrs = RequiredOptional(required=("name",))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectMergeRequestAwardEmoji:
return cast(
ProjectMergeRequestAwardEmoji, super().get(id=id, lazy=lazy, **kwargs)
)
class ProjectMergeRequestNoteAwardEmoji(ObjectDeleteMixin, RESTObject):
pass
class ProjectMergeRequestNoteAwardEmojiManager(NoUpdateMixin, RESTManager):
_path = "/projects/{project_id}/merge_requests/{mr_iid}/notes/{note_id}/award_emoji"
_obj_cls = ProjectMergeRequestNoteAwardEmoji
_from_parent_attrs = {
"project_id": "project_id",
"mr_iid": "mr_iid",
"note_id": "id",
}
_create_attrs = RequiredOptional(required=("name",))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectMergeRequestNoteAwardEmoji:
return cast(
ProjectMergeRequestNoteAwardEmoji, super().get(id=id, lazy=lazy, **kwargs)
)
class ProjectSnippetAwardEmoji(ObjectDeleteMixin, RESTObject):
pass
class ProjectSnippetAwardEmojiManager(NoUpdateMixin, RESTManager):
_path = "/projects/{project_id}/snippets/{snippet_id}/award_emoji"
_obj_cls = ProjectSnippetAwardEmoji
_from_parent_attrs = {"project_id": "project_id", "snippet_id": "id"}
_create_attrs = RequiredOptional(required=("name",))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectSnippetAwardEmoji:
return cast(ProjectSnippetAwardEmoji, super().get(id=id, lazy=lazy, **kwargs))
class ProjectSnippetNoteAwardEmoji(ObjectDeleteMixin, RESTObject):
pass
class ProjectSnippetNoteAwardEmojiManager(NoUpdateMixin, RESTManager):
_path = "/projects/{project_id}/snippets/{snippet_id}/notes/{note_id}/award_emoji"
_obj_cls = ProjectSnippetNoteAwardEmoji
_from_parent_attrs = {
"project_id": "project_id",
"snippet_id": "snippet_id",
"note_id": "id",
}
_create_attrs = RequiredOptional(required=("name",))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectSnippetNoteAwardEmoji:
return cast(
ProjectSnippetNoteAwardEmoji, super().get(id=id, lazy=lazy, **kwargs)
)

View File

@ -0,0 +1,44 @@
from typing import Any, cast, Union
from gitlab.base import RESTManager, RESTObject
from gitlab.mixins import BadgeRenderMixin, CRUDMixin, ObjectDeleteMixin, SaveMixin
from gitlab.types import RequiredOptional
__all__ = [
"GroupBadge",
"GroupBadgeManager",
"ProjectBadge",
"ProjectBadgeManager",
]
class GroupBadge(SaveMixin, ObjectDeleteMixin, RESTObject):
pass
class GroupBadgeManager(BadgeRenderMixin, CRUDMixin, RESTManager):
_path = "/groups/{group_id}/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"))
def get(self, id: Union[str, int], lazy: bool = False, **kwargs: Any) -> GroupBadge:
return cast(GroupBadge, super().get(id=id, lazy=lazy, **kwargs))
class ProjectBadge(SaveMixin, ObjectDeleteMixin, RESTObject):
pass
class ProjectBadgeManager(BadgeRenderMixin, CRUDMixin, RESTManager):
_path = "/projects/{project_id}/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"))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectBadge:
return cast(ProjectBadge, super().get(id=id, lazy=lazy, **kwargs))

View File

@ -0,0 +1,84 @@
from typing import Any, cast, Union
from gitlab.base import RESTManager, RESTObject
from gitlab.mixins import CRUDMixin, ObjectDeleteMixin, SaveMixin
from gitlab.types import RequiredOptional
__all__ = [
"GroupBoardList",
"GroupBoardListManager",
"GroupBoard",
"GroupBoardManager",
"ProjectBoardList",
"ProjectBoardListManager",
"ProjectBoard",
"ProjectBoardManager",
]
class GroupBoardList(SaveMixin, ObjectDeleteMixin, RESTObject):
pass
class GroupBoardListManager(CRUDMixin, RESTManager):
_path = "/groups/{group_id}/boards/{board_id}/lists"
_obj_cls = GroupBoardList
_from_parent_attrs = {"group_id": "group_id", "board_id": "id"}
_create_attrs = RequiredOptional(
exclusive=("label_id", "assignee_id", "milestone_id")
)
_update_attrs = RequiredOptional(required=("position",))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> GroupBoardList:
return cast(GroupBoardList, super().get(id=id, lazy=lazy, **kwargs))
class GroupBoard(SaveMixin, ObjectDeleteMixin, RESTObject):
lists: GroupBoardListManager
class GroupBoardManager(CRUDMixin, RESTManager):
_path = "/groups/{group_id}/boards"
_obj_cls = GroupBoard
_from_parent_attrs = {"group_id": "id"}
_create_attrs = RequiredOptional(required=("name",))
def get(self, id: Union[str, int], lazy: bool = False, **kwargs: Any) -> GroupBoard:
return cast(GroupBoard, super().get(id=id, lazy=lazy, **kwargs))
class ProjectBoardList(SaveMixin, ObjectDeleteMixin, RESTObject):
pass
class ProjectBoardListManager(CRUDMixin, RESTManager):
_path = "/projects/{project_id}/boards/{board_id}/lists"
_obj_cls = ProjectBoardList
_from_parent_attrs = {"project_id": "project_id", "board_id": "id"}
_create_attrs = RequiredOptional(
exclusive=("label_id", "assignee_id", "milestone_id")
)
_update_attrs = RequiredOptional(required=("position",))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectBoardList:
return cast(ProjectBoardList, super().get(id=id, lazy=lazy, **kwargs))
class ProjectBoard(SaveMixin, ObjectDeleteMixin, RESTObject):
lists: ProjectBoardListManager
class ProjectBoardManager(CRUDMixin, RESTManager):
_path = "/projects/{project_id}/boards"
_obj_cls = ProjectBoard
_from_parent_attrs = {"project_id": "id"}
_create_attrs = RequiredOptional(required=("name",))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectBoard:
return cast(ProjectBoard, super().get(id=id, lazy=lazy, **kwargs))

View File

@ -0,0 +1,63 @@
from typing import Any, cast, Union
from gitlab.base import RESTManager, RESTObject
from gitlab.mixins import (
CRUDMixin,
NoUpdateMixin,
ObjectDeleteMixin,
SaveMixin,
UpdateMethod,
)
from gitlab.types import RequiredOptional
__all__ = [
"ProjectBranch",
"ProjectBranchManager",
"ProjectProtectedBranch",
"ProjectProtectedBranchManager",
]
class ProjectBranch(ObjectDeleteMixin, RESTObject):
_id_attr = "name"
class ProjectBranchManager(NoUpdateMixin, RESTManager):
_path = "/projects/{project_id}/repository/branches"
_obj_cls = ProjectBranch
_from_parent_attrs = {"project_id": "id"}
_create_attrs = RequiredOptional(required=("branch", "ref"))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectBranch:
return cast(ProjectBranch, super().get(id=id, lazy=lazy, **kwargs))
class ProjectProtectedBranch(SaveMixin, ObjectDeleteMixin, RESTObject):
_id_attr = "name"
class ProjectProtectedBranchManager(CRUDMixin, RESTManager):
_path = "/projects/{project_id}/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",
"allow_force_push",
"allowed_to_push",
"allowed_to_merge",
"allowed_to_unprotect",
"code_owner_approval_required",
),
)
_update_method = UpdateMethod.PATCH
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectProtectedBranch:
return cast(ProjectProtectedBranch, super().get(id=id, lazy=lazy, **kwargs))

View File

@ -0,0 +1,40 @@
from typing import Any, cast, Union
from gitlab.base import RESTManager, RESTObject
from gitlab.mixins import CRUDMixin, ObjectDeleteMixin, SaveMixin
from gitlab.types import ArrayAttribute, RequiredOptional
__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", "target_access_levels"),
)
_update_attrs = RequiredOptional(
optional=(
"message",
"starts_at",
"ends_at",
"color",
"font",
"target_access_levels",
)
)
_types = {"target_access_levels": ArrayAttribute}
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> BroadcastMessage:
return cast(BroadcastMessage, super().get(id=id, lazy=lazy, **kwargs))

View File

@ -0,0 +1,54 @@
from typing import Any, cast, Union
from gitlab.base import RESTManager, RESTObject
from gitlab.mixins import CreateMixin, ListMixin, RefreshMixin, RetrieveMixin
from gitlab.types import RequiredOptional
__all__ = [
"BulkImport",
"BulkImportManager",
"BulkImportAllEntity",
"BulkImportAllEntityManager",
"BulkImportEntity",
"BulkImportEntityManager",
]
class BulkImport(RefreshMixin, RESTObject):
entities: "BulkImportEntityManager"
class BulkImportManager(CreateMixin, RetrieveMixin, RESTManager):
_path = "/bulk_imports"
_obj_cls = BulkImport
_create_attrs = RequiredOptional(required=("configuration", "entities"))
_list_filters = ("sort", "status")
def get(self, id: Union[str, int], lazy: bool = False, **kwargs: Any) -> BulkImport:
return cast(BulkImport, super().get(id=id, lazy=lazy, **kwargs))
class BulkImportEntity(RefreshMixin, RESTObject):
pass
class BulkImportEntityManager(RetrieveMixin, RESTManager):
_path = "/bulk_imports/{bulk_import_id}/entities"
_obj_cls = BulkImportEntity
_from_parent_attrs = {"bulk_import_id": "id"}
_list_filters = ("sort", "status")
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> BulkImportEntity:
return cast(BulkImportEntity, super().get(id=id, lazy=lazy, **kwargs))
class BulkImportAllEntity(RESTObject):
pass
class BulkImportAllEntityManager(ListMixin, RESTManager):
_path = "/bulk_imports/entities"
_obj_cls = BulkImportAllEntity
_list_filters = ("sort", "status")

View File

@ -0,0 +1,78 @@
"""
GitLab API:
https://docs.gitlab.com/ee/api/lint.html
"""
from typing import Any, cast
from gitlab.base import RESTManager, RESTObject
from gitlab.cli import register_custom_action
from gitlab.exceptions import GitlabCiLintError
from gitlab.mixins import CreateMixin, GetWithoutIdMixin
from gitlab.types import RequiredOptional
__all__ = [
"CiLint",
"CiLintManager",
"ProjectCiLint",
"ProjectCiLintManager",
]
class CiLint(RESTObject):
_id_attr = None
class CiLintManager(CreateMixin, RESTManager):
_path = "/ci/lint"
_obj_cls = CiLint
_create_attrs = RequiredOptional(
required=("content",), optional=("include_merged_yaml", "include_jobs")
)
@register_custom_action(
cls_names="CiLintManager",
required=("content",),
optional=("include_merged_yaml", "include_jobs"),
)
def validate(self, *args: Any, **kwargs: Any) -> None:
"""Raise an error if the CI Lint results are not valid.
This is a custom python-gitlab method to wrap lint endpoints."""
result = self.create(*args, **kwargs)
if result.status != "valid":
message = ",\n".join(result.errors)
raise GitlabCiLintError(message)
class ProjectCiLint(RESTObject):
_id_attr = None
class ProjectCiLintManager(GetWithoutIdMixin, CreateMixin, RESTManager):
_path = "/projects/{project_id}/ci/lint"
_obj_cls = ProjectCiLint
_from_parent_attrs = {"project_id": "id"}
_optional_get_attrs = ("dry_run", "include_jobs", "ref")
_create_attrs = RequiredOptional(
required=("content",), optional=("dry_run", "include_jobs", "ref")
)
def get(self, **kwargs: Any) -> ProjectCiLint:
return cast(ProjectCiLint, super().get(**kwargs))
@register_custom_action(
cls_names="ProjectCiLintManager",
required=("content",),
optional=("dry_run", "include_jobs", "ref"),
)
def validate(self, *args: Any, **kwargs: Any) -> None:
"""Raise an error if the Project CI Lint results are not valid.
This is a custom python-gitlab method to wrap lint endpoints."""
result = self.create(*args, **kwargs)
if not result.valid:
message = ",\n".join(result.errors)
raise GitlabCiLintError(message)

View File

@ -0,0 +1,26 @@
from typing import Any, cast, Union
from gitlab.base import RESTManager, RESTObject
from gitlab.mixins import NoUpdateMixin, ObjectDeleteMixin, SaveMixin
from gitlab.types import RequiredOptional
__all__ = [
"ProjectClusterAgent",
"ProjectClusterAgentManager",
]
class ProjectClusterAgent(SaveMixin, ObjectDeleteMixin, RESTObject):
_repr_attr = "name"
class ProjectClusterAgentManager(NoUpdateMixin, RESTManager):
_path = "/projects/{project_id}/cluster_agents"
_obj_cls = ProjectClusterAgent
_from_parent_attrs = {"project_id": "id"}
_create_attrs = RequiredOptional(required=("name",))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectClusterAgent:
return cast(ProjectClusterAgent, super().get(id=id, lazy=lazy, **kwargs))

View File

@ -0,0 +1,115 @@
from typing import Any, cast, Dict, Optional, Union
from gitlab import exceptions as exc
from gitlab.base import RESTManager, RESTObject
from gitlab.mixins import CreateMixin, CRUDMixin, ObjectDeleteMixin, SaveMixin
from gitlab.types import RequiredOptional
__all__ = [
"GroupCluster",
"GroupClusterManager",
"ProjectCluster",
"ProjectClusterManager",
]
class GroupCluster(SaveMixin, ObjectDeleteMixin, RESTObject):
pass
class GroupClusterManager(CRUDMixin, RESTManager):
_path = "/groups/{group_id}/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: Optional[Dict[str, Any]] = None, **kwargs: Any
) -> GroupCluster:
"""Create a new object.
Args:
data: 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:
A new instance of the manage object class build with
the data sent by the server
"""
path = f"{self.path}/user"
return cast(GroupCluster, CreateMixin.create(self, data, path=path, **kwargs))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> GroupCluster:
return cast(GroupCluster, super().get(id=id, lazy=lazy, **kwargs))
class ProjectCluster(SaveMixin, ObjectDeleteMixin, RESTObject):
pass
class ProjectClusterManager(CRUDMixin, RESTManager):
_path = "/projects/{project_id}/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: Optional[Dict[str, Any]] = None, **kwargs: Any
) -> ProjectCluster:
"""Create a new object.
Args:
data: 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:
A new instance of the manage object class build with
the data sent by the server
"""
path = f"{self.path}/user"
return cast(ProjectCluster, CreateMixin.create(self, data, path=path, **kwargs))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectCluster:
return cast(ProjectCluster, super().get(id=id, lazy=lazy, **kwargs))

View File

@ -0,0 +1,253 @@
from typing import Any, cast, Dict, List, Optional, TYPE_CHECKING, Union
import requests
import gitlab
from gitlab import cli
from gitlab import exceptions as exc
from gitlab.base import RESTManager, RESTObject
from gitlab.mixins import CreateMixin, ListMixin, RefreshMixin, RetrieveMixin
from gitlab.types import RequiredOptional
from .discussions import ProjectCommitDiscussionManager # noqa: F401
__all__ = [
"ProjectCommit",
"ProjectCommitManager",
"ProjectCommitComment",
"ProjectCommitCommentManager",
"ProjectCommitStatus",
"ProjectCommitStatusManager",
]
class ProjectCommit(RESTObject):
_repr_attr = "title"
comments: "ProjectCommitCommentManager"
discussions: ProjectCommitDiscussionManager
statuses: "ProjectCommitStatusManager"
@cli.register_custom_action(cls_names="ProjectCommit")
@exc.on_http_error(exc.GitlabGetError)
def diff(self, **kwargs: Any) -> Union[gitlab.GitlabList, List[Dict[str, Any]]]:
"""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:
The changes done in this commit
"""
path = f"{self.manager.path}/{self.encoded_id}/diff"
return self.manager.gitlab.http_list(path, **kwargs)
@cli.register_custom_action(cls_names="ProjectCommit", required=("branch",))
@exc.on_http_error(exc.GitlabCherryPickError)
def cherry_pick(self, branch: str, **kwargs: Any) -> None:
"""Cherry-pick a commit into a branch.
Args:
branch: 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 = f"{self.manager.path}/{self.encoded_id}/cherry_pick"
post_data = {"branch": branch}
self.manager.gitlab.http_post(path, post_data=post_data, **kwargs)
@cli.register_custom_action(cls_names="ProjectCommit", optional=("type",))
@exc.on_http_error(exc.GitlabGetError)
def refs(
self, type: str = "all", **kwargs: Any
) -> Union[gitlab.GitlabList, List[Dict[str, Any]]]:
"""List the references the commit is pushed to.
Args:
type: 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:
The references the commit is pushed to.
"""
path = f"{self.manager.path}/{self.encoded_id}/refs"
query_data = {"type": type}
return self.manager.gitlab.http_list(path, query_data=query_data, **kwargs)
@cli.register_custom_action(cls_names="ProjectCommit")
@exc.on_http_error(exc.GitlabGetError)
def merge_requests(
self, **kwargs: Any
) -> Union[gitlab.GitlabList, List[Dict[str, Any]]]:
"""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:
The merge requests related to the commit.
"""
path = f"{self.manager.path}/{self.encoded_id}/merge_requests"
return self.manager.gitlab.http_list(path, **kwargs)
@cli.register_custom_action(cls_names="ProjectCommit", required=("branch",))
@exc.on_http_error(exc.GitlabRevertError)
def revert(
self, branch: str, **kwargs: Any
) -> Union[Dict[str, Any], requests.Response]:
"""Revert a commit on a given branch.
Args:
branch: 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:
The new commit data (*not* a RESTObject)
"""
path = f"{self.manager.path}/{self.encoded_id}/revert"
post_data = {"branch": branch}
return self.manager.gitlab.http_post(path, post_data=post_data, **kwargs)
@cli.register_custom_action(cls_names="ProjectCommit")
@exc.on_http_error(exc.GitlabGetError)
def sequence(self, **kwargs: Any) -> Union[Dict[str, Any], requests.Response]:
"""Get the sequence number 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 sequence number could not be retrieved
Returns:
The commit's sequence number
"""
path = f"{self.manager.path}/{self.encoded_id}/sequence"
return self.manager.gitlab.http_get(path, **kwargs)
@cli.register_custom_action(cls_names="ProjectCommit")
@exc.on_http_error(exc.GitlabGetError)
def signature(self, **kwargs: Any) -> Union[Dict[str, Any], requests.Response]:
"""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:
The commit's signature data
"""
path = f"{self.manager.path}/{self.encoded_id}/signature"
return self.manager.gitlab.http_get(path, **kwargs)
class ProjectCommitManager(RetrieveMixin, CreateMixin, RESTManager):
_path = "/projects/{project_id}/repository/commits"
_obj_cls = ProjectCommit
_from_parent_attrs = {"project_id": "id"}
_create_attrs = RequiredOptional(
required=("branch", "commit_message", "actions"),
optional=("author_email", "author_name"),
)
_list_filters = (
"all",
"ref_name",
"since",
"until",
"path",
"with_stats",
"first_parent",
"order",
"trailers",
)
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectCommit:
return cast(ProjectCommit, super().get(id=id, lazy=lazy, **kwargs))
class ProjectCommitComment(RESTObject):
_id_attr = None
_repr_attr = "note"
class ProjectCommitCommentManager(ListMixin, CreateMixin, RESTManager):
_path = "/projects/{project_id}/repository/commits/{commit_id}/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}/repository/commits/{commit_id}/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: Optional[Dict[str, Any]] = None, **kwargs: Any
) -> ProjectCommitStatus:
"""Create a new object.
Args:
data: 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:
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}/statuses/{commit_id}"
path: Optional[str]
if data is not None and "project_id" in data and "commit_id" in data:
path = base_path.format(**data)
else:
path = self._compute_path(base_path)
if TYPE_CHECKING:
assert path is not None
return cast(
ProjectCommitStatus, CreateMixin.create(self, data, path=path, **kwargs)
)

View File

@ -0,0 +1,96 @@
from typing import Any, cast, TYPE_CHECKING, Union
from gitlab import cli
from gitlab import exceptions as exc
from gitlab.base import RESTManager, RESTObject
from gitlab.mixins import (
DeleteMixin,
GetMixin,
ListMixin,
ObjectDeleteMixin,
RetrieveMixin,
)
__all__ = [
"GroupRegistryRepositoryManager",
"ProjectRegistryRepository",
"ProjectRegistryRepositoryManager",
"ProjectRegistryTag",
"ProjectRegistryTagManager",
"RegistryRepository",
"RegistryRepositoryManager",
]
class ProjectRegistryRepository(ObjectDeleteMixin, RESTObject):
tags: "ProjectRegistryTagManager"
class ProjectRegistryRepositoryManager(DeleteMixin, ListMixin, RESTManager):
_path = "/projects/{project_id}/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}/registry/repositories/{repository_id}/tags"
@cli.register_custom_action(
cls_names="ProjectRegistryTagManager",
required=("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: str, **kwargs: Any) -> None:
"""Delete Tag in bulk
Args:
name_regex_delete: The regex of the name to delete. To delete all
tags specify .*.
keep_n: The amount of latest tags of given name to keep.
name_regex_keep: The regex of the name to keep. This value
overrides any matches from name_regex.
older_than: 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})
if TYPE_CHECKING:
assert self.path is not None
self.gitlab.http_delete(self.path, query_data=data, **kwargs)
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectRegistryTag:
return cast(ProjectRegistryTag, super().get(id=id, lazy=lazy, **kwargs))
class GroupRegistryRepositoryManager(ListMixin, RESTManager):
_path = "/groups/{group_id}/registry/repositories"
_obj_cls = ProjectRegistryRepository
_from_parent_attrs = {"group_id": "id"}
class RegistryRepository(RESTObject):
_repr_attr = "path"
class RegistryRepositoryManager(GetMixin, RESTManager):
_path = "/registry/repositories"
_obj_cls = RegistryRepository
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> RegistryRepository:
return cast(RegistryRepository, super().get(id=id, lazy=lazy, **kwargs))

View File

@ -0,0 +1,58 @@
from typing import Any, cast, Union
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}/custom_attributes"
_obj_cls = GroupCustomAttribute
_from_parent_attrs = {"group_id": "id"}
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> GroupCustomAttribute:
return cast(GroupCustomAttribute, super().get(id=id, lazy=lazy, **kwargs))
class ProjectCustomAttribute(ObjectDeleteMixin, RESTObject):
_id_attr = "key"
class ProjectCustomAttributeManager(RetrieveMixin, SetMixin, DeleteMixin, RESTManager):
_path = "/projects/{project_id}/custom_attributes"
_obj_cls = ProjectCustomAttribute
_from_parent_attrs = {"project_id": "id"}
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectCustomAttribute:
return cast(ProjectCustomAttribute, super().get(id=id, lazy=lazy, **kwargs))
class UserCustomAttribute(ObjectDeleteMixin, RESTObject):
_id_attr = "key"
class UserCustomAttributeManager(RetrieveMixin, SetMixin, DeleteMixin, RESTManager):
_path = "/users/{user_id}/custom_attributes"
_obj_cls = UserCustomAttribute
_from_parent_attrs = {"user_id": "id"}
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> UserCustomAttribute:
return cast(UserCustomAttribute, super().get(id=id, lazy=lazy, **kwargs))

View File

@ -0,0 +1,66 @@
from typing import Any, cast, Dict, Union
import requests
from gitlab import cli
from gitlab import exceptions as exc
from gitlab.base import RESTManager, RESTObject
from gitlab.mixins import CRUDMixin, ListMixin, ObjectDeleteMixin, SaveMixin
from gitlab.types import RequiredOptional
__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}/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(
cls_names="ProjectKeyManager",
required=("key_id",),
requires_id=False,
help="Enable a deploy key for the project",
)
@exc.on_http_error(exc.GitlabProjectDeployKeyError)
def enable(
self, key_id: int, **kwargs: Any
) -> Union[Dict[str, Any], requests.Response]:
"""Enable a deploy key for a project.
Args:
key_id: 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
Returns:
A dict of the result.
"""
path = f"{self.path}/{key_id}/enable"
return self.gitlab.http_post(path, **kwargs)
def get(self, id: Union[str, int], lazy: bool = False, **kwargs: Any) -> ProjectKey:
return cast(ProjectKey, super().get(id=id, lazy=lazy, **kwargs))

View File

@ -0,0 +1,84 @@
from typing import Any, cast, Union
from gitlab import types
from gitlab.base import RESTManager, RESTObject
from gitlab.mixins import (
CreateMixin,
DeleteMixin,
ListMixin,
ObjectDeleteMixin,
RetrieveMixin,
)
from gitlab.types import RequiredOptional
__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(RetrieveMixin, CreateMixin, DeleteMixin, RESTManager):
_path = "/groups/{group_id}/deploy_tokens"
_from_parent_attrs = {"group_id": "id"}
_obj_cls = GroupDeployToken
_create_attrs = RequiredOptional(
required=(
"name",
"scopes",
),
optional=(
"expires_at",
"username",
),
)
_list_filters = ("scopes",)
_types = {"scopes": types.ArrayAttribute}
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> GroupDeployToken:
return cast(GroupDeployToken, super().get(id=id, lazy=lazy, **kwargs))
class ProjectDeployToken(ObjectDeleteMixin, RESTObject):
pass
class ProjectDeployTokenManager(RetrieveMixin, CreateMixin, DeleteMixin, RESTManager):
_path = "/projects/{project_id}/deploy_tokens"
_from_parent_attrs = {"project_id": "id"}
_obj_cls = ProjectDeployToken
_create_attrs = RequiredOptional(
required=(
"name",
"scopes",
),
optional=(
"expires_at",
"username",
),
)
_list_filters = ("scopes",)
_types = {"scopes": types.ArrayAttribute}
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectDeployToken:
return cast(ProjectDeployToken, super().get(id=id, lazy=lazy, **kwargs))

View File

@ -0,0 +1,89 @@
"""
GitLab API:
https://docs.gitlab.com/ee/api/deployments.html
"""
from typing import Any, cast, Dict, Optional, TYPE_CHECKING, Union
from gitlab import cli
from gitlab import exceptions as exc
from gitlab.base import RESTManager, RESTObject
from gitlab.mixins import CreateMixin, RetrieveMixin, SaveMixin, UpdateMixin
from gitlab.types import RequiredOptional
from .merge_requests import ProjectDeploymentMergeRequestManager # noqa: F401
__all__ = [
"ProjectDeployment",
"ProjectDeploymentManager",
]
class ProjectDeployment(SaveMixin, RESTObject):
mergerequests: ProjectDeploymentMergeRequestManager
@cli.register_custom_action(
cls_names="ProjectDeployment",
required=("status",),
optional=("comment", "represented_as"),
)
@exc.on_http_error(exc.GitlabDeploymentApprovalError)
def approval(
self,
status: str,
comment: Optional[str] = None,
represented_as: Optional[str] = None,
**kwargs: Any,
) -> Dict[str, Any]:
"""Approve or reject a blocked deployment.
Args:
status: Either "approved" or "rejected"
comment: A comment to go with the approval
represented_as: The name of the User/Group/Role to use for the
approval, when the user belongs to multiple
approval rules.
**kwargs: Extra options to send to the server (e.g. sudo)
Raises:
GitlabAuthenticationError: If authentication is not correct
GitlabMRApprovalError: If the approval failed
Returns:
A dict containing the result.
https://docs.gitlab.com/ee/api/deployments.html#approve-or-reject-a-blocked-deployment
"""
path = f"{self.manager.path}/{self.encoded_id}/approval"
data = {"status": status}
if comment is not None:
data["comment"] = comment
if represented_as is not None:
data["represented_as"] = represented_as
server_data = self.manager.gitlab.http_post(path, post_data=data, **kwargs)
if TYPE_CHECKING:
assert isinstance(server_data, dict)
return server_data
class ProjectDeploymentManager(RetrieveMixin, CreateMixin, UpdateMixin, RESTManager):
_path = "/projects/{project_id}/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")
)
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectDeployment:
return cast(ProjectDeployment, super().get(id=id, lazy=lazy, **kwargs))

View File

@ -0,0 +1,94 @@
from typing import Any, cast, Union
from gitlab.base import RESTManager, RESTObject
from gitlab.mixins import CreateMixin, RetrieveMixin, SaveMixin, UpdateMixin
from gitlab.types import RequiredOptional
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}/repository/commits/{commit_id}/discussions"
_obj_cls = ProjectCommitDiscussion
_from_parent_attrs = {"project_id": "project_id", "commit_id": "id"}
_create_attrs = RequiredOptional(required=("body",), optional=("created_at",))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectCommitDiscussion:
return cast(ProjectCommitDiscussion, super().get(id=id, lazy=lazy, **kwargs))
class ProjectIssueDiscussion(RESTObject):
notes: ProjectIssueDiscussionNoteManager
class ProjectIssueDiscussionManager(RetrieveMixin, CreateMixin, RESTManager):
_path = "/projects/{project_id}/issues/{issue_iid}/discussions"
_obj_cls = ProjectIssueDiscussion
_from_parent_attrs = {"project_id": "project_id", "issue_iid": "iid"}
_create_attrs = RequiredOptional(required=("body",), optional=("created_at",))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectIssueDiscussion:
return cast(ProjectIssueDiscussion, super().get(id=id, lazy=lazy, **kwargs))
class ProjectMergeRequestDiscussion(SaveMixin, RESTObject):
notes: ProjectMergeRequestDiscussionNoteManager
class ProjectMergeRequestDiscussionManager(
RetrieveMixin, CreateMixin, UpdateMixin, RESTManager
):
_path = "/projects/{project_id}/merge_requests/{mr_iid}/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",))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectMergeRequestDiscussion:
return cast(
ProjectMergeRequestDiscussion, super().get(id=id, lazy=lazy, **kwargs)
)
class ProjectSnippetDiscussion(RESTObject):
notes: ProjectSnippetDiscussionNoteManager
class ProjectSnippetDiscussionManager(RetrieveMixin, CreateMixin, RESTManager):
_path = "/projects/{project_id}/snippets/{snippet_id}/discussions"
_obj_cls = ProjectSnippetDiscussion
_from_parent_attrs = {"project_id": "project_id", "snippet_id": "id"}
_create_attrs = RequiredOptional(required=("body",), optional=("created_at",))
def get(
self, id: Union[str, int], lazy: bool = False, **kwargs: Any
) -> ProjectSnippetDiscussion:
return cast(ProjectSnippetDiscussion, super().get(id=id, lazy=lazy, **kwargs))

Some files were not shown because too many files have changed in this diff Show More