summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNejc Habjan <hab.nejc@gmail.com>2021-10-20 23:02:47 +0200
committerGitHub <noreply@github.com>2021-10-20 23:02:47 +0200
commit853d8505997b8b052d4421bb64c91dc499cecc90 (patch)
tree0596d9782a50a60e95d1677c17f9a02428993d1d
parent905781bed2afa33634b27842a42a077a160cffb8 (diff)
parent6d7c88a1fe401d271a34df80943634652195b140 (diff)
downloadgitlab-853d8505997b8b052d4421bb64c91dc499cecc90.tar.gz
Merge pull request #1610 from StingRayZA/add-label-promote
feat(api): add project label promotion
-rw-r--r--docs/gl_objects/labels.rst4
-rw-r--r--gitlab/exceptions.py4
-rw-r--r--gitlab/mixins.py47
-rw-r--r--gitlab/v4/objects/labels.py5
-rw-r--r--tests/functional/api/test_projects.py24
5 files changed, 83 insertions, 1 deletions
diff --git a/docs/gl_objects/labels.rst b/docs/gl_objects/labels.rst
index a4667aa..9a955dd 100644
--- a/docs/gl_objects/labels.rst
+++ b/docs/gl_objects/labels.rst
@@ -36,6 +36,10 @@ Update a label for a project::
label.color = '#112233'
label.save()
+Promote a project label to a group label::
+
+ label.promote()
+
Delete a label for a project::
project.labels.delete(label_id)
diff --git a/gitlab/exceptions.py b/gitlab/exceptions.py
index 6f2d4c4..66b1ee0 100644
--- a/gitlab/exceptions.py
+++ b/gitlab/exceptions.py
@@ -111,6 +111,10 @@ class GitlabProjectDeployKeyError(GitlabOperationError):
pass
+class GitlabPromoteError(GitlabOperationError):
+ pass
+
+
class GitlabCancelError(GitlabOperationError):
pass
diff --git a/gitlab/mixins.py b/gitlab/mixins.py
index 0c2cd94..62ff6dc 100644
--- a/gitlab/mixins.py
+++ b/gitlab/mixins.py
@@ -926,3 +926,50 @@ class BadgeRenderMixin(_RestManagerBase):
if TYPE_CHECKING:
assert not isinstance(result, requests.Response)
return result
+
+
+class PromoteMixin(_RestObjectBase):
+ _id_attr: Optional[str]
+ _attrs: Dict[str, Any]
+ _module: ModuleType
+ _parent_attrs: Dict[str, Any]
+ _updated_attrs: Dict[str, Any]
+ _update_uses_post: bool = False
+ manager: base.RESTManager
+
+ def _get_update_method(
+ self,
+ ) -> Callable[..., Union[Dict[str, Any], requests.Response]]:
+ """Return the HTTP method to use.
+
+ Returns:
+ object: http_put (default) or http_post
+ """
+ if self._update_uses_post:
+ http_method = self.manager.gitlab.http_post
+ else:
+ http_method = self.manager.gitlab.http_put
+ return http_method
+
+ @exc.on_http_error(exc.GitlabPromoteError)
+ def promote(self, **kwargs: Any) -> Dict[str, Any]:
+ """Promote the item.
+
+ Args:
+ **kwargs: Extra options to send to the server (e.g. sudo)
+
+ Raises:
+ GitlabAuthenticationError: If authentication is not correct
+ GitlabPromoteError: If the item could not be promoted
+ GitlabParsingError: If the json data could not be parsed
+
+ Returns:
+ dict: The updated object data (*not* a RESTObject)
+ """
+
+ path = "%s/%s/promote" % (self.manager.path, self.id)
+ http_method = self._get_update_method()
+ result = http_method(path, **kwargs)
+ if TYPE_CHECKING:
+ assert not isinstance(result, requests.Response)
+ return result
diff --git a/gitlab/v4/objects/labels.py b/gitlab/v4/objects/labels.py
index 544c3cd..99da06a 100644
--- a/gitlab/v4/objects/labels.py
+++ b/gitlab/v4/objects/labels.py
@@ -5,6 +5,7 @@ from gitlab.mixins import (
DeleteMixin,
ListMixin,
ObjectDeleteMixin,
+ PromoteMixin,
RetrieveMixin,
SaveMixin,
SubscribableMixin,
@@ -83,7 +84,9 @@ class GroupLabelManager(ListMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTMa
self.gitlab.http_delete(self.path, query_data={"name": name}, **kwargs)
-class ProjectLabel(SubscribableMixin, SaveMixin, ObjectDeleteMixin, RESTObject):
+class ProjectLabel(
+ PromoteMixin, SubscribableMixin, SaveMixin, ObjectDeleteMixin, RESTObject
+):
_id_attr = "name"
# Update without ID, but we need an ID to get from list.
diff --git a/tests/functional/api/test_projects.py b/tests/functional/api/test_projects.py
index ba8e25b..3da9d2b 100644
--- a/tests/functional/api/test_projects.py
+++ b/tests/functional/api/test_projects.py
@@ -1,3 +1,5 @@
+import uuid
+
import pytest
import gitlab
@@ -159,6 +161,28 @@ def test_project_labels(project):
assert len(project.labels.list()) == 0
+def test_project_label_promotion(gl, group):
+ """
+ Label promotion requires the project to be a child of a group (not in a user namespace)
+
+ """
+ _id = uuid.uuid4().hex
+ data = {
+ "name": f"test-project-{_id}",
+ "namespace_id": group.id,
+ }
+ project = gl.projects.create(data)
+
+ label_name = "promoteme"
+ promoted_label = project.labels.create({"name": label_name, "color": "#112233"})
+ promoted_label.promote()
+
+ assert any(label.name == label_name for label in group.labels.list())
+
+ group.labels.delete(label_name)
+ assert not any(label.name == label_name for label in group.labels.list())
+
+
def test_project_milestones(project):
milestone = project.milestones.create({"title": "milestone1"})
assert len(project.milestones.list()) == 1