summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNejc Habjan <hab.nejc@gmail.com>2021-06-27 20:26:41 +0200
committerGitHub <noreply@github.com>2021-06-27 20:26:41 +0200
commit6abf13a7e25e368da342e7d1da6cfc19915c2dfd (patch)
tree260ab3034ff8a51dcfcb5d56805d1120dcd02f71
parent33d342818599f403434e7024097449b6f21babc0 (diff)
parent953f207466c53c28a877f2a88da9160acef40643 (diff)
downloadgitlab-6abf13a7e25e368da342e7d1da6cfc19915c2dfd.tar.gz
Merge pull request #1533 from sugonyak/add-group-hooks
feat(api): add group hooks
-rw-r--r--docs/gl_objects/groups.rst40
-rw-r--r--gitlab/v4/objects/groups.py2
-rw-r--r--gitlab/v4/objects/hooks.py52
-rw-r--r--tests/functional/api/test_groups.py13
-rw-r--r--tests/unit/objects/test_hooks.py192
-rw-r--r--tests/unit/objects/test_projects.py25
6 files changed, 293 insertions, 31 deletions
diff --git a/docs/gl_objects/groups.rst b/docs/gl_objects/groups.rst
index 596db0a..44fb11d 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 429d95d..ee82415 100644
--- a/gitlab/v4/objects/groups.py
+++ b/gitlab/v4/objects/groups.py
@@ -13,6 +13,7 @@ from .custom_attributes import GroupCustomAttributeManager # noqa: F401
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 69b324e..428fd76 100644
--- a/gitlab/v4/objects/hooks.py
+++ b/gitlab/v4/objects/hooks.py
@@ -6,6 +6,8 @@ __all__ = [
"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 439d01c..312fc7e 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 fe5c21c..0f9dbe2 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 73e119b..039d5ec 100644
--- a/tests/unit/objects/test_projects.py
+++ b/tests/unit/objects/test_projects.py
@@ -178,31 +178,6 @@ def test_delete_shared_project_link(gl):
@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