diff --git a/docs/gl_objects/groups.rst b/docs/gl_objects/groups.rst index 596db0a40..44fb11ddd 100644 --- a/docs/gl_objects/groups.rst +++ b/docs/gl_objects/groups.rst @@ -338,3 +338,43 @@ You can use the ``ldapgroups`` manager to list available LDAP groups:: # list the groups for a specific LDAP provider ldap_groups = gl.ldapgroups.list(search='foo', provider='ldapmain') + +Groups hooks +============ + +Reference +--------- + +* v4 API: + + + :class:`gitlab.v4.objects.GroupHook` + + :class:`gitlab.v4.objects.GroupHookManager` + + :attr:`gitlab.v4.objects.Group.hooks` + +* GitLab API: https://docs.gitlab.com/ce/api/groups.html#hooks + +Examples +-------- + +List the group hooks:: + + hooks = group.hooks.list() + +Get a group hook:: + + hook = group.hooks.get(hook_id) + +Create a group hook:: + + hook = group.hooks.create({'url': 'http://my/action/url', 'push_events': 1}) + +Update a group hook:: + + hook.push_events = 0 + hook.save() + +Delete a group hook:: + + group.hooks.delete(hook_id) + # or + hook.delete() diff --git a/gitlab/v4/objects/groups.py b/gitlab/v4/objects/groups.py index 429d95da0..ee82415e1 100644 --- a/gitlab/v4/objects/groups.py +++ b/gitlab/v4/objects/groups.py @@ -13,6 +13,7 @@ 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 @@ -52,6 +53,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject): ("descendant_groups", "GroupDescendantGroupManager"), ("exports", "GroupExportManager"), ("epics", "GroupEpicManager"), + ("hooks", "GroupHookManager"), ("imports", "GroupImportManager"), ("issues", "GroupIssueManager"), ("issues_statistics", "GroupIssuesStatisticsManager"), diff --git a/gitlab/v4/objects/hooks.py b/gitlab/v4/objects/hooks.py index 69b324e8c..428fd765c 100644 --- a/gitlab/v4/objects/hooks.py +++ b/gitlab/v4/objects/hooks.py @@ -6,6 +6,8 @@ "HookManager", "ProjectHook", "ProjectHookManager", + "GroupHook", + "GroupHookManager", ] @@ -60,3 +62,53 @@ class ProjectHookManager(CRUDMixin, RESTManager): "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/tests/functional/api/test_groups.py b/tests/functional/api/test_groups.py index 439d01ccd..312fc7ec9 100644 --- a/tests/functional/api/test_groups.py +++ b/tests/functional/api/test_groups.py @@ -209,3 +209,16 @@ def test_group_wiki(group): wiki.save() wiki.delete() assert len(group.wikis.list()) == 0 + + +@pytest.mark.skip(reason="EE feature") +def test_group_hooks(group): + hook = group.hooks.create({"url": "http://hook.url"}) + assert len(group.hooks.list()) == 1 + + hook.note_events = True + hook.save() + + hook = group.hooks.get(hook.id) + assert hook.note_events is True + hook.delete() diff --git a/tests/unit/objects/test_hooks.py b/tests/unit/objects/test_hooks.py index fe5c21c98..0f9dbe282 100644 --- a/tests/unit/objects/test_hooks.py +++ b/tests/unit/objects/test_hooks.py @@ -1,29 +1,209 @@ """ GitLab API: https://docs.gitlab.com/ce/api/system_hooks.html +GitLab API: https://docs.gitlab.com/ce/api/groups.html#hooks +GitLab API: https://docs.gitlab.com/ee/api/projects.html#hooks """ + +import re + import pytest import responses -from gitlab.v4.objects import Hook +from gitlab.v4.objects import GroupHook, Hook, ProjectHook + +hooks_content = [ + { + "id": 1, + "url": "testurl", + "push_events": True, + "tag_push_events": True, + }, + { + "id": 2, + "url": "testurl_second", + "push_events": False, + "tag_push_events": False, + }, +] + +hook_content = hooks_content[0] + + +@pytest.fixture +def resp_hooks_list(): + with responses.RequestsMock() as rsps: + rsps.add( + method=responses.GET, + url=re.compile(r"http://localhost/api/v4/((groups|projects)/1/|)hooks"), + json=hooks_content, + content_type="application/json", + status=200, + ) + yield rsps + + +@pytest.fixture +def resp_hook_get(): + with responses.RequestsMock() as rsps: + rsps.add( + method=responses.GET, + url=re.compile(r"http://localhost/api/v4/((groups|projects)/1/|)hooks/1"), + json=hook_content, + content_type="application/json", + status=200, + ) + yield rsps + + +@pytest.fixture +def resp_hook_create(): + with responses.RequestsMock() as rsps: + rsps.add( + method=responses.POST, + url=re.compile(r"http://localhost/api/v4/((groups|projects)/1/|)hooks"), + json=hook_content, + content_type="application/json", + status=200, + ) + yield rsps @pytest.fixture -def resp_get_hook(): - content = {"url": "testurl", "id": 1} +def resp_hook_update(): + with responses.RequestsMock() as rsps: + pattern = re.compile(r"http://localhost/api/v4/((groups|projects)/1/|)hooks/1") + rsps.add( + method=responses.GET, + url=pattern, + json=hook_content, + content_type="application/json", + status=200, + ) + rsps.add( + method=responses.PUT, + url=pattern, + json=hook_content, + content_type="application/json", + status=200, + ) + yield rsps + +@pytest.fixture +def resp_hook_delete(): with responses.RequestsMock() as rsps: + pattern = re.compile(r"http://localhost/api/v4/((groups|projects)/1/|)hooks/1") rsps.add( method=responses.GET, - url="http://localhost/api/v4/hooks/1", - json=content, + url=pattern, + json=hook_content, content_type="application/json", status=200, ) + rsps.add( + method=responses.DELETE, + url=pattern, + status=204, + ) yield rsps -def test_hooks(gl, resp_get_hook): +def test_list_system_hooks(gl, resp_hooks_list): + hooks = gl.hooks.list() + assert hooks[0].id == 1 + assert hooks[0].url == "testurl" + assert hooks[1].id == 2 + assert hooks[1].url == "testurl_second" + + +def test_get_system_hook(gl, resp_hook_get): data = gl.hooks.get(1) assert isinstance(data, Hook) assert data.url == "testurl" assert data.id == 1 + + +def test_create_system_hook(gl, resp_hook_create): + hook = gl.hooks.create(hook_content) + assert hook.url == "testurl" + assert hook.push_events is True + assert hook.tag_push_events is True + + +# there is no update method for system hooks + + +def test_delete_system_hook(gl, resp_hook_delete): + hook = gl.hooks.get(1) + hook.delete() + gl.hooks.delete(1) + + +def test_list_group_hooks(group, resp_hooks_list): + hooks = group.hooks.list() + assert hooks[0].id == 1 + assert hooks[0].url == "testurl" + assert hooks[1].id == 2 + assert hooks[1].url == "testurl_second" + + +def test_get_group_hook(group, resp_hook_get): + data = group.hooks.get(1) + assert isinstance(data, GroupHook) + assert data.url == "testurl" + assert data.id == 1 + + +def test_create_group_hook(group, resp_hook_create): + hook = group.hooks.create(hook_content) + assert hook.url == "testurl" + assert hook.push_events is True + assert hook.tag_push_events is True + + +def test_update_group_hook(group, resp_hook_update): + hook = group.hooks.get(1) + assert hook.id == 1 + hook.url = "testurl_more" + hook.save() + + +def test_delete_group_hook(group, resp_hook_delete): + hook = group.hooks.get(1) + hook.delete() + group.hooks.delete(1) + + +def test_list_project_hooks(project, resp_hooks_list): + hooks = project.hooks.list() + assert hooks[0].id == 1 + assert hooks[0].url == "testurl" + assert hooks[1].id == 2 + assert hooks[1].url == "testurl_second" + + +def test_get_project_hook(project, resp_hook_get): + data = project.hooks.get(1) + assert isinstance(data, ProjectHook) + assert data.url == "testurl" + assert data.id == 1 + + +def test_create_project_hook(project, resp_hook_create): + hook = project.hooks.create(hook_content) + assert hook.url == "testurl" + assert hook.push_events is True + assert hook.tag_push_events is True + + +def test_update_project_hook(project, resp_hook_update): + hook = project.hooks.get(1) + assert hook.id == 1 + hook.url = "testurl_more" + hook.save() + + +def test_delete_project_hook(project, resp_hook_delete): + hook = project.hooks.get(1) + hook.delete() + project.hooks.delete(1) diff --git a/tests/unit/objects/test_projects.py b/tests/unit/objects/test_projects.py index 73e119bd3..039d5ec75 100644 --- a/tests/unit/objects/test_projects.py +++ b/tests/unit/objects/test_projects.py @@ -177,31 +177,6 @@ def test_delete_shared_project_link(gl): pass -@pytest.mark.skip(reason="missing test") -def test_list_project_hooks(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_get_project_hook(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_create_project_hook(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_update_project_hook(gl): - pass - - -@pytest.mark.skip(reason="missing test") -def test_delete_project_hook(gl): - pass - - @pytest.mark.skip(reason="missing test") def test_create_forked_from_relationship(gl): pass pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy