diff --git a/gitlab/mixins.py b/gitlab/mixins.py index 7cbb7b9f9..01a5b6392 100644 --- a/gitlab/mixins.py +++ b/gitlab/mixins.py @@ -433,7 +433,9 @@ def approve(self, access_level=gitlab.DEVELOPER_ACCESS, **kwargs): class SubscribableMixin(object): - @cli.register_custom_action(("ProjectIssue", "ProjectMergeRequest", "ProjectLabel")) + @cli.register_custom_action( + ("ProjectIssue", "ProjectMergeRequest", "ProjectLabel", "GroupLabel") + ) @exc.on_http_error(exc.GitlabSubscribeError) def subscribe(self, **kwargs): """Subscribe to the object notifications. @@ -449,7 +451,9 @@ def subscribe(self, **kwargs): server_data = self.manager.gitlab.http_post(path, **kwargs) self._update_attrs(server_data) - @cli.register_custom_action(("ProjectIssue", "ProjectMergeRequest", "ProjectLabel")) + @cli.register_custom_action( + ("ProjectIssue", "ProjectMergeRequest", "ProjectLabel", "GroupLabel") + ) @exc.on_http_error(exc.GitlabUnsubscribeError) def unsubscribe(self, **kwargs): """Unsubscribe from the object notifications. diff --git a/gitlab/v4/objects.py b/gitlab/v4/objects.py index 74157f280..2642a4011 100644 --- a/gitlab/v4/objects.py +++ b/gitlab/v4/objects.py @@ -833,6 +833,64 @@ class GroupIssueManager(ListMixin, RESTManager): _types = {"labels": types.ListAttribute} +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 = (("name", "color"), ("description", "priority")) + _update_attrs = (("name",), ("new_name", "color", "description", "priority")) + + # Update without ID. + def update(self, name, new_data={}, **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["name"] = name + 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 GroupMember(SaveMixin, ObjectDeleteMixin, RESTObject): _short_print_attr = "username" @@ -1042,6 +1100,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject): ("customattributes", "GroupCustomAttributeManager"), ("epics", "GroupEpicManager"), ("issues", "GroupIssueManager"), + ("labels", "GroupLabelManager"), ("members", "GroupMemberManager"), ("mergerequests", "GroupMergeRequestManager"), ("milestones", "GroupMilestoneManager"), @@ -2934,6 +2993,17 @@ class ProjectLabelManager( _create_attrs = (("name", "color"), ("description", "priority")) _update_attrs = (("name",), ("new_name", "color", "description", "priority")) + # Update without ID. + def update(self, name, new_data={}, **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["name"] = name + super().update(id=None, new_data=new_data, **kwargs) + # Delete without ID. @exc.on_http_error(exc.GitlabDeleteError) def delete(self, name, **kwargs): diff --git a/tools/cli_test_v4.sh b/tools/cli_test_v4.sh index dea0509eb..dc6e0b278 100755 --- a/tools/cli_test_v4.sh +++ b/tools/cli_test_v4.sh @@ -25,6 +25,17 @@ testcase "project update" ' GITLAB project update --id "$PROJECT_ID" --description "My New Description" ' +testcase "group creation" ' + OUTPUT=$(try GITLAB group create --name test-group1 --path group1) || exit 1 + GROUP_ID=$(pecho "${OUTPUT}" | grep ^id: | cut -d" " -f2) + OUTPUT=$(try GITLAB group list) || exit 1 + pecho "${OUTPUT}" | grep -q test-group1 +' + +testcase "group update" ' + GITLAB group update --id "$GROUP_ID" --description "My New Description" +' + testcase "user creation" ' OUTPUT=$(GITLAB user create --email fake@email.com --username user1 \ --name "User One" --password fakepassword) @@ -89,6 +100,46 @@ testcase "merge request validation" ' --iid "$MR_ID" >/dev/null 2>&1 ' +# Test project labels +testcase "create project label" ' + OUTPUT=$(GITLAB -v project-label create --project-id $PROJECT_ID \ + --name prjlabel1 --description "prjlabel1 description" --color "#112233") +' + +testcase "list project label" ' + OUTPUT=$(GITLAB -v project-label list --project-id $PROJECT_ID) +' + +testcase "update project label" ' + OUTPUT=$(GITLAB -v project-label update --project-id $PROJECT_ID \ + --name prjlabel1 --new-name prjlabel2 --description "prjlabel2 description" --color "#332211") +' + +testcase "delete project label" ' + OUTPUT=$(GITLAB -v project-label delete --project-id $PROJECT_ID \ + --name prjlabel2) +' + +# Test group labels +testcase "create group label" ' + OUTPUT=$(GITLAB -v group-label create --group-id $GROUP_ID \ + --name grplabel1 --description "grplabel1 description" --color "#112233") +' + +testcase "list group label" ' + OUTPUT=$(GITLAB -v group-label list --group-id $GROUP_ID) +' + +testcase "update group label" ' + OUTPUT=$(GITLAB -v group-label update --group-id $GROUP_ID \ + --name grplabel1 --new-name grplabel2 --description "grplabel2 description" --color "#332211") +' + +testcase "delete group label" ' + OUTPUT=$(GITLAB -v group-label delete --group-id $GROUP_ID \ + --name grplabel2) +' + # Test project variables testcase "create project variable" ' OUTPUT=$(GITLAB -v project-variable create --project-id $PROJECT_ID \ @@ -128,6 +179,10 @@ testcase "project deletion" ' GITLAB project delete --id "$PROJECT_ID" ' +testcase "group deletion" ' + OUTPUT=$(try GITLAB group delete --id $GROUP_ID) +' + testcase "application settings get" ' GITLAB application-settings get >/dev/null 2>&1 ' @@ -146,3 +201,4 @@ testcase "values from files" ' --description @/tmp/gitlab-project-description) echo $OUTPUT | grep -q "Multi line" ' + diff --git a/tools/python_test_v4.py b/tools/python_test_v4.py index d65f39f5d..e6b6ab9fb 100644 --- a/tools/python_test_v4.py +++ b/tools/python_test_v4.py @@ -337,6 +337,18 @@ g_v.delete() assert len(group1.variables.list()) == 0 +# group labels +group1.labels.create({"name": "foo", "description": "bar", "color": "#112233"}) +g_l = group1.labels.get("foo") +assert g_l.description == "bar" +g_l.description = "baz" +g_l.save() +g_l = group1.labels.get("foo") +assert g_l.description == "baz" +assert len(group1.labels.list()) == 1 +g_l.delete() +assert len(group1.labels.list()) == 0 + # hooks hook = gl.hooks.create({"url": "http://whatever.com"}) assert len(gl.hooks.list()) == 1