Skip to content

feat(api): add project label promotion #1610

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/gl_objects/labels.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions gitlab/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ class GitlabProjectDeployKeyError(GitlabOperationError):
pass


class GitlabPromoteError(GitlabOperationError):
pass


class GitlabCancelError(GitlabOperationError):
pass

Expand Down
47 changes: 47 additions & 0 deletions gitlab/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -926,3 +926,50 @@ def render(self, link_url: str, image_url: str, **kwargs: Any) -> Dict[str, Any]
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
5 changes: 4 additions & 1 deletion gitlab/v4/objects/labels.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
DeleteMixin,
ListMixin,
ObjectDeleteMixin,
PromoteMixin,
RetrieveMixin,
SaveMixin,
SubscribableMixin,
Expand Down Expand Up @@ -83,7 +84,9 @@ def delete(self, name, **kwargs):
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.
Expand Down
24 changes: 24 additions & 0 deletions tests/functional/api/test_projects.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import uuid

import pytest

import gitlab
Expand Down Expand Up @@ -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
Expand Down