- 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>
333 lines
13 KiB
Python
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)
|