Files
mcphub/plugins/gitea/handlers/webhooks.py
airano-ir 2c9d4ed3d2 feat(F.16): Gitea plugin review, test & public release — v3.6.0
- Added update_webhook and delete_label tools (58 total Gitea tools)
- 97 unit tests (test_gitea_plugin.py)
- Gitea now public for all users (DEFAULT_PUBLIC_PLUGINS)
- Fixed merge_pull_request optional field handling

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 07:45:17 +02:00

333 lines
13 KiB
Python

"""Webhook Handler - manages Gitea webhooks for repositories"""
import json
from typing import Any
from plugins.gitea.client import GiteaClient
def get_tool_specifications() -> list[dict[str, Any]]:
"""Return tool specifications for ToolGenerator"""
return [
# === WEBHOOKS ===
{
"name": "list_webhooks",
"method_name": "list_webhooks",
"description": "List all webhooks configured for a repository.",
"schema": {
"type": "object",
"properties": {
"owner": {"type": "string", "description": "Repository owner", "minLength": 1},
"repo": {"type": "string", "description": "Repository name", "minLength": 1},
},
"required": ["owner", "repo"],
},
"scope": "read",
},
{
"name": "create_webhook",
"method_name": "create_webhook",
"description": "Create a new webhook for a repository to receive event notifications.",
"schema": {
"type": "object",
"properties": {
"owner": {"type": "string", "description": "Repository owner", "minLength": 1},
"repo": {"type": "string", "description": "Repository name", "minLength": 1},
"url": {
"type": "string",
"description": "Webhook URL to send events to",
"format": "uri",
},
"events": {
"type": "array",
"items": {
"type": "string",
"enum": [
"create",
"delete",
"fork",
"push",
"issues",
"issue_assign",
"issue_label",
"issue_milestone",
"issue_comment",
"pull_request",
"pull_request_assign",
"pull_request_label",
"pull_request_milestone",
"pull_request_comment",
"pull_request_review_approved",
"pull_request_review_rejected",
"pull_request_review_comment",
"pull_request_sync",
"wiki",
"repository",
"release",
],
},
"description": "List of events to trigger webhook",
"minItems": 1,
},
"content_type": {
"type": "string",
"description": "Content type for webhook payload",
"enum": ["json", "form"],
"default": "json",
},
"secret": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"description": "Secret for webhook signature verification",
},
"active": {
"type": "boolean",
"description": "Activate webhook immediately",
"default": True,
},
"type": {
"type": "string",
"description": "Webhook type",
"enum": [
"gitea",
"gogs",
"slack",
"discord",
"dingtalk",
"telegram",
"msteams",
"feishu",
"wechatwork",
"packagist",
],
"default": "gitea",
},
},
"required": ["owner", "repo", "url", "events"],
},
"scope": "admin",
},
{
"name": "delete_webhook",
"method_name": "delete_webhook",
"description": "Delete a webhook from a repository.",
"schema": {
"type": "object",
"properties": {
"owner": {"type": "string", "description": "Repository owner", "minLength": 1},
"repo": {"type": "string", "description": "Repository name", "minLength": 1},
"webhook_id": {
"type": "integer",
"description": "Webhook ID to delete",
"minimum": 1,
},
},
"required": ["owner", "repo", "webhook_id"],
},
"scope": "admin",
},
{
"name": "test_webhook",
"method_name": "test_webhook",
"description": "Send a test payload to a webhook to verify it's working.",
"schema": {
"type": "object",
"properties": {
"owner": {"type": "string", "description": "Repository owner", "minLength": 1},
"repo": {"type": "string", "description": "Repository name", "minLength": 1},
"webhook_id": {
"type": "integer",
"description": "Webhook ID to test",
"minimum": 1,
},
},
"required": ["owner", "repo", "webhook_id"],
},
"scope": "admin",
},
{
"name": "get_webhook",
"method_name": "get_webhook",
"description": "Get details of a specific webhook.",
"schema": {
"type": "object",
"properties": {
"owner": {"type": "string", "description": "Repository owner", "minLength": 1},
"repo": {"type": "string", "description": "Repository name", "minLength": 1},
"webhook_id": {"type": "integer", "description": "Webhook ID", "minimum": 1},
},
"required": ["owner", "repo", "webhook_id"],
},
"scope": "read",
},
{
"name": "update_webhook",
"method_name": "update_webhook",
"description": "Update an existing webhook's configuration, events, or active status.",
"schema": {
"type": "object",
"properties": {
"owner": {"type": "string", "description": "Repository owner", "minLength": 1},
"repo": {"type": "string", "description": "Repository name", "minLength": 1},
"webhook_id": {
"type": "integer",
"description": "Webhook ID to update",
"minimum": 1,
},
"url": {
"anyOf": [{"type": "string", "format": "uri"}, {"type": "null"}],
"description": "New webhook URL",
},
"events": {
"anyOf": [
{
"type": "array",
"items": {
"type": "string",
"enum": [
"create",
"delete",
"fork",
"push",
"issues",
"issue_assign",
"issue_label",
"issue_milestone",
"issue_comment",
"pull_request",
"pull_request_assign",
"pull_request_label",
"pull_request_milestone",
"pull_request_comment",
"pull_request_review_approved",
"pull_request_review_rejected",
"pull_request_review_comment",
"pull_request_sync",
"wiki",
"repository",
"release",
],
},
},
{"type": "null"},
],
"description": "Updated list of events to trigger webhook",
},
"content_type": {
"anyOf": [
{"type": "string", "enum": ["json", "form"]},
{"type": "null"},
],
"description": "Content type for webhook payload",
},
"secret": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"description": "Secret for webhook signature verification",
},
"active": {
"anyOf": [{"type": "boolean"}, {"type": "null"}],
"description": "Activate or deactivate webhook",
},
},
"required": ["owner", "repo", "webhook_id"],
},
"scope": "admin",
},
]
async def list_webhooks(client: GiteaClient, owner: str, repo: str) -> str:
"""List repository webhooks"""
webhooks = await client.list_webhooks(owner, repo)
result = {"success": True, "count": len(webhooks), "webhooks": webhooks}
return json.dumps(result, indent=2)
async def create_webhook(
client: GiteaClient,
owner: str,
repo: str,
url: str,
events: list[str],
content_type: str = "json",
secret: str | None = None,
active: bool = True,
type: str = "gitea",
) -> str:
"""Create a webhook"""
# Build webhook configuration
config = {"url": url, "content_type": content_type}
if secret:
config["secret"] = secret
data = {"type": type, "config": config, "events": events, "active": active}
webhook = await client.create_webhook(owner, repo, data)
result = {
"success": True,
"message": f"Webhook created successfully for {owner}/{repo}",
"webhook": webhook,
}
return json.dumps(result, indent=2)
async def delete_webhook(client: GiteaClient, owner: str, repo: str, webhook_id: int) -> str:
"""Delete a webhook"""
await client.delete_webhook(owner, repo, webhook_id)
result = {"success": True, "message": f"Webhook {webhook_id} deleted successfully"}
return json.dumps(result, indent=2)
async def test_webhook(client: GiteaClient, owner: str, repo: str, webhook_id: int) -> str:
"""Test a webhook"""
test_result = await client.test_webhook(owner, repo, webhook_id)
result = {
"success": True,
"message": f"Test payload sent to webhook {webhook_id}",
"result": test_result,
}
return json.dumps(result, indent=2)
async def get_webhook(client: GiteaClient, owner: str, repo: str, webhook_id: int) -> str:
"""Get webhook details"""
webhook = await client.get_webhook(owner, repo, webhook_id)
result = {"success": True, "webhook": webhook}
return json.dumps(result, indent=2)
async def update_webhook(
client: GiteaClient,
owner: str,
repo: str,
webhook_id: int,
url: str | None = None,
events: list[str] | None = None,
content_type: str | None = None,
secret: str | None = None,
active: bool | None = None,
) -> str:
"""Update a webhook"""
data: dict = {}
if events is not None:
data["events"] = events
if active is not None:
data["active"] = active
config: dict = {}
if url is not None:
config["url"] = url
if content_type is not None:
config["content_type"] = content_type
if secret is not None:
config["secret"] = secret
if config:
data["config"] = config
webhook = await client.update_webhook(owner, repo, webhook_id, data)
result = {
"success": True,
"message": f"Webhook {webhook_id} updated successfully",
"webhook": webhook,
}
return json.dumps(result, indent=2)