Commit 9353f540 authored by Jacob Henner (Arcesium)'s avatar Jacob Henner (Arcesium) Committed by John Villalovos
Browse files

feat(api): project/group hook test triggering

Add the ability to trigger tests of project and group hooks.

Fixes #2924
parent 8d74b889
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -419,6 +419,10 @@ Update a group hook::
    hook.push_events = 0
    hook.save()

Test a group hook::

    hook.test("push_events")

Delete a group hook::

    group.hooks.delete(hook_id)
+7 −3
Original line number Diff line number Diff line
@@ -689,6 +689,10 @@ Update a project hook::
    hook.push_events = 0
    hook.save()

Test a project hook::

    hook.test("push_events")

Delete a project hook::

    project.hooks.delete(hook_id)
+5 −0
Original line number Diff line number Diff line
@@ -316,6 +316,10 @@ class GitlabDeploymentApprovalError(GitlabOperationError):
    pass


class GitlabHookTestError(GitlabOperationError):
    pass


# For an explanation of how these type-hints work see:
# https://mypy.readthedocs.io/en/stable/generics.html#declaring-decorators
#
@@ -370,6 +374,7 @@ __all__ = [
    "GitlabGetError",
    "GitlabGroupTransferError",
    "GitlabHeadError",
    "GitlabHookTestError",
    "GitlabHousekeepingError",
    "GitlabHttpError",
    "GitlabImportError",
+29 −0
Original line number Diff line number Diff line
from typing import Any, cast, Union

from gitlab import exceptions as exc
from gitlab.base import RESTManager, RESTObject
from gitlab.mixins import CRUDMixin, NoUpdateMixin, ObjectDeleteMixin, SaveMixin
from gitlab.types import RequiredOptional
@@ -31,6 +32,20 @@ class HookManager(NoUpdateMixin, RESTManager):
class ProjectHook(SaveMixin, ObjectDeleteMixin, RESTObject):
    _repr_attr = "url"

    @exc.on_http_error(exc.GitlabHookTestError)
    def test(self, trigger: str) -> None:
        """
        Test a Project Hook

        Args:
            trigger: Type of trigger event to test

        Raises:
            GitlabHookTestError: If the hook test attempt failed
        """
        path = f"{self.manager.path}/{self.encoded_id}/test/{trigger}"
        self.manager.gitlab.http_post(path)


class ProjectHookManager(CRUDMixin, RESTManager):
    _path = "/projects/{project_id}/hooks"
@@ -78,6 +93,20 @@ class ProjectHookManager(CRUDMixin, RESTManager):
class GroupHook(SaveMixin, ObjectDeleteMixin, RESTObject):
    _repr_attr = "url"

    @exc.on_http_error(exc.GitlabHookTestError)
    def test(self, trigger: str) -> None:
        """
        Test a Group Hook

        Args:
            trigger: Type of trigger event to test

        Raises:
            GitlabHookTestError: If the hook test attempt failed
        """
        path = f"{self.manager.path}/{self.encoded_id}/test/{trigger}"
        self.manager.gitlab.http_post(path)


class GroupHookManager(CRUDMixin, RESTManager):
    _path = "/groups/{group_id}/hooks"
+64 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ import re
import pytest
import responses

import gitlab
from gitlab.v4.objects import GroupHook, Hook, ProjectHook

hooks_content = [
@@ -89,6 +90,58 @@ def resp_hook_update():
        yield rsps


@pytest.fixture
def resp_hook_test():
    with responses.RequestsMock() as rsps:
        hook_pattern = re.compile(
            r"http://localhost/api/v4/((groups|projects)/1/|)hooks/1"
        )
        test_pattern = re.compile(
            r"http://localhost/api/v4/((groups|projects)/1/|)hooks/1/test/[a-z_]+"
        )
        rsps.add(
            method=responses.GET,
            url=hook_pattern,
            json=hook_content,
            content_type="application/json",
            status=200,
        )
        rsps.add(
            method=responses.POST,
            url=test_pattern,
            json={"message": "201 Created"},
            content_type="application/json",
            status=201,
        )
        yield rsps


@pytest.fixture
def resp_hook_test_error():
    with responses.RequestsMock() as rsps:
        hook_pattern = re.compile(
            r"http://localhost/api/v4/((groups|projects)/1/|)hooks/1"
        )
        test_pattern = re.compile(
            r"http://localhost/api/v4/((groups|projects)/1/|)hooks/1/test/[a-z_]+"
        )
        rsps.add(
            method=responses.GET,
            url=hook_pattern,
            json=hook_content,
            content_type="application/json",
            status=200,
        )
        rsps.add(
            method=responses.POST,
            url=test_pattern,
            json={"message": "<html>error</html>"},
            content_type="application/json",
            status=422,
        )
        yield rsps


@pytest.fixture
def resp_hook_delete():
    with responses.RequestsMock() as rsps:
@@ -174,6 +227,17 @@ def test_delete_group_hook(group, resp_hook_delete):
    group.hooks.delete(1)


def test_test_group_hook(group, resp_hook_test):
    hook = group.hooks.get(1)
    hook.test("push_events")


def test_test_error_group_hook(group, resp_hook_test_error):
    hook = group.hooks.get(1)
    with pytest.raises(gitlab.exceptions.GitlabHookTestError):
        hook.test("push_events")


def test_list_project_hooks(project, resp_hooks_list):
    hooks = project.hooks.list()
    assert hooks[0].id == 1