mirror of
https://github.com/langgenius/dify-plugin-sdks.git
synced 2026-07-25 21:46:57 -04:00
feat(trigger): enhance trigger execution and response handling
- Introduced new response entities for trigger operations: TriggerInvokeResponse, TriggerDispatchResponse, TriggerSubscriptionResponse, TriggerUnsubscribeResponse, and TriggerRefreshResponse. - Updated PluginExecutor methods to utilize the new response structures, improving clarity and consistency in trigger handling. - Enhanced HTTP request parsing and response conversion utilities for better integration with various content types. - Refactored GitHub provider to align with the updated trigger dispatch and subscription handling mechanisms.
This commit is contained in:
@@ -9,10 +9,10 @@ from typing import Any
|
||||
import requests
|
||||
from werkzeug import Request, Response
|
||||
|
||||
from dify_plugin.interfaces.trigger import TriggerProvider
|
||||
from dify_plugin.entities.trigger import TriggerEventDispatch, Subscription, Unsubscription
|
||||
from dify_plugin.entities.trigger import Subscription, TriggerDispatch, Unsubscription
|
||||
from dify_plugin.errors.tool import ToolProviderCredentialValidationError, ToolProviderOAuthError
|
||||
from dify_plugin.errors.trigger import SubscriptionError, WebhookValidationError, TriggerDispatchError
|
||||
from dify_plugin.errors.trigger import SubscriptionError, TriggerDispatchError, WebhookValidationError
|
||||
from dify_plugin.interfaces.trigger import TriggerProvider
|
||||
|
||||
|
||||
class GithubProvider(TriggerProvider):
|
||||
@@ -67,12 +67,12 @@ class GithubProvider(TriggerProvider):
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e)) from e
|
||||
|
||||
def _dispatch_event(self, subscription: Subscription, request: Request) -> TriggerEventDispatch:
|
||||
def _dispatch_event(self, subscription: Subscription, request: Request) -> TriggerDispatch:
|
||||
"""
|
||||
Dispatch GitHub webhook events - focusing on issue comment events
|
||||
"""
|
||||
# Verify webhook signature if secret is provided
|
||||
webhook_secret = subscription.configuration.get("webhook_secret")
|
||||
webhook_secret = subscription.properties.get("webhook_secret")
|
||||
if webhook_secret:
|
||||
signature = request.headers.get("X-Hub-Signature-256")
|
||||
if not signature:
|
||||
@@ -102,25 +102,30 @@ class GithubProvider(TriggerProvider):
|
||||
# Create trigger event dispatch with GitHub event type
|
||||
# Map GitHub events to our trigger events
|
||||
if event_type == "issue_comment":
|
||||
return TriggerEventDispatch(event="issue_comment", response=response)
|
||||
return TriggerDispatch(events=["issue_comment"], response=response)
|
||||
elif event_type == "issues":
|
||||
return TriggerEventDispatch(event="issues", response=response)
|
||||
# Issues event can trigger multiple workflows based on action
|
||||
action = payload.get("action")
|
||||
if action == "opened":
|
||||
# Dispatch both generic issues event and specific opened event
|
||||
return TriggerDispatch(events=["issues", "issues.opened"], response=response)
|
||||
elif action == "closed":
|
||||
return TriggerDispatch(events=["issues", "issues.closed"], response=response)
|
||||
else:
|
||||
return TriggerDispatch(events=["issues"], response=response)
|
||||
else:
|
||||
# For other events, pass them through with prefix
|
||||
return TriggerEventDispatch(event=f"github.{event_type}", response=response)
|
||||
return TriggerDispatch(events=[f"github.{event_type}"], response=response)
|
||||
|
||||
def _subscribe(self, credentials: Mapping[str, Any], subscription_params: Mapping[str, Any]) -> Subscription:
|
||||
def _subscribe(self, endpoint: str, credentials: Mapping[str, Any], parameters: Mapping[str, Any]) -> Subscription:
|
||||
"""
|
||||
Create a GitHub webhook subscription for issue comment events
|
||||
"""
|
||||
# Extract parameters
|
||||
endpoint = subscription_params.get("endpoint")
|
||||
webhook_secret = subscription_params.get("webhook_secret")
|
||||
repository = subscription_params.get("repository") # format: "owner/repo"
|
||||
events = subscription_params.get("events", ["issue_comment", "issues"])
|
||||
webhook_secret = parameters.get("webhook_secret")
|
||||
repository = parameters.get("repository") # format: "owner/repo"
|
||||
events = parameters.get("events", ["issue_comment", "issues"])
|
||||
|
||||
if not endpoint:
|
||||
raise ValueError("endpoint is required for webhook subscription")
|
||||
if not repository:
|
||||
raise ValueError("repository is required (format: owner/repo)")
|
||||
|
||||
@@ -154,9 +159,9 @@ class GithubProvider(TriggerProvider):
|
||||
webhook = response.json()
|
||||
# Return subscription with webhook details
|
||||
return Subscription(
|
||||
expire_at=int(time.time()) + 30 * 24 * 60 * 60, # 30 days expiration
|
||||
expires_at=int(time.time()) + 30 * 24 * 60 * 60, # 30 days expiration
|
||||
endpoint=endpoint,
|
||||
configuration={
|
||||
properties={
|
||||
"external_id": str(webhook["id"]),
|
||||
"webhook_url": webhook["url"],
|
||||
"repository": repository,
|
||||
@@ -175,17 +180,17 @@ class GithubProvider(TriggerProvider):
|
||||
except requests.RequestException as e:
|
||||
raise SubscriptionError(f"Network error while creating webhook: {e}", error_code="NETWORK_ERROR")
|
||||
|
||||
def _unsubscribe(self, subscription: Subscription, credentials: Mapping[str, Any]) -> Unsubscription:
|
||||
def _unsubscribe(self, endpoint: str, subscription: Subscription, credentials: Mapping[str, Any]) -> Unsubscription:
|
||||
"""
|
||||
Remove a GitHub webhook subscription
|
||||
"""
|
||||
# Extract webhook details from data
|
||||
external_id = subscription.configuration.get("external_id")
|
||||
repository = subscription.configuration.get("repository")
|
||||
# Extract webhook details from properties
|
||||
external_id = subscription.properties.get("external_id")
|
||||
repository = subscription.properties.get("repository")
|
||||
|
||||
if not external_id or not repository:
|
||||
return Unsubscription(
|
||||
success=False, message="Missing webhook ID or repository information", error_code="MISSING_DATA"
|
||||
success=False, message="Missing webhook ID or repository information", error_code="MISSING_PROPERTIES"
|
||||
)
|
||||
|
||||
# Parse repository
|
||||
@@ -193,7 +198,7 @@ class GithubProvider(TriggerProvider):
|
||||
owner, repo = repository.split("/")
|
||||
except ValueError:
|
||||
return Unsubscription(
|
||||
success=False, message="Invalid repository format in data", error_code="INVALID_REPOSITORY"
|
||||
success=False, message="Invalid repository format in properties", error_code="INVALID_REPOSITORY"
|
||||
)
|
||||
|
||||
# Delete webhook using GitHub API
|
||||
@@ -227,7 +232,7 @@ class GithubProvider(TriggerProvider):
|
||||
success=False, message=f"Network error while deleting webhook: {e}", error_code="NETWORK_ERROR"
|
||||
)
|
||||
|
||||
def _refresh(self, subscription: Subscription, credentials: Mapping[str, Any]) -> Subscription:
|
||||
def _refresh(self, endpoint: str, subscription: Subscription, credentials: Mapping[str, Any]) -> Subscription:
|
||||
"""
|
||||
Refresh a GitHub webhook subscription (extend expiration)
|
||||
GitHub webhooks don't expire, so we just extend our internal expiration
|
||||
@@ -235,7 +240,7 @@ class GithubProvider(TriggerProvider):
|
||||
# Simply return the subscription with extended expiration
|
||||
# GitHub webhooks don't have built-in expiration
|
||||
return Subscription(
|
||||
expire_at=int(time.time()) + 30 * 24 * 60 * 60, # Extend by 30 days
|
||||
endpoint=subscription.endpoint, # Keep the same endpoint
|
||||
configuration=subscription.configuration, # Keep the same data
|
||||
expires_at=int(time.time()) + 30 * 24 * 60 * 60, # Extend by 30 days
|
||||
endpoint=endpoint, # Keep the same endpoint
|
||||
properties=subscription.properties, # Keep the same properties
|
||||
)
|
||||
|
||||
@@ -3,8 +3,8 @@ from typing import Any
|
||||
|
||||
from werkzeug import Request
|
||||
|
||||
from dify_plugin.entities.trigger import Event
|
||||
from dify_plugin.interfaces.trigger import TriggerEvent
|
||||
from dify_plugin.entities.trigger import TriggerEvent as TriggerEventResponse
|
||||
|
||||
|
||||
class IssueCommentTrigger(TriggerEvent):
|
||||
@@ -15,10 +15,10 @@ class IssueCommentTrigger(TriggerEvent):
|
||||
from the webhook payload to provide as variables to the workflow.
|
||||
"""
|
||||
|
||||
def _trigger(self, request: Request, values: Mapping[str, Any], parameters: Mapping[str, Any]) -> TriggerEventResponse:
|
||||
def _trigger(self, request: Request, parameters: Mapping[str, Any]) -> Event:
|
||||
"""
|
||||
Handle GitHub issue comment event trigger
|
||||
|
||||
|
||||
Parameters:
|
||||
- action_filter: Filter by action type (created, edited, deleted, or any)
|
||||
- issue_filter: Filter by specific issue number (optional)
|
||||
@@ -30,19 +30,19 @@ class IssueCommentTrigger(TriggerEvent):
|
||||
|
||||
# Extract action type
|
||||
action = payload.get("action", "")
|
||||
|
||||
|
||||
# Apply action filter if specified
|
||||
action_filter = parameters.get("action_filter", "any")
|
||||
if action_filter != "any" and action != action_filter:
|
||||
# Skip this event if it doesn't match the filter
|
||||
return TriggerEventResponse(variables={})
|
||||
|
||||
|
||||
# Extract issue comment information
|
||||
comment = payload.get("comment", {})
|
||||
issue = payload.get("issue", {})
|
||||
repository = payload.get("repository", {})
|
||||
sender = payload.get("sender", {})
|
||||
|
||||
|
||||
# Apply issue number filter if specified
|
||||
issue_filter = parameters.get("issue_filter")
|
||||
if issue_filter is not None:
|
||||
@@ -50,20 +50,20 @@ class IssueCommentTrigger(TriggerEvent):
|
||||
if issue_number != int(issue_filter):
|
||||
# Skip this event if it doesn't match the issue filter
|
||||
return TriggerEventResponse(variables={})
|
||||
|
||||
|
||||
# Check if this is a pull request
|
||||
is_pull_request = "pull_request" in issue
|
||||
|
||||
|
||||
# Extract labels
|
||||
labels = [
|
||||
{
|
||||
"name": label.get("name", ""),
|
||||
"color": label.get("color", ""),
|
||||
"description": label.get("description", "")
|
||||
"description": label.get("description", ""),
|
||||
}
|
||||
for label in issue.get("labels", [])
|
||||
]
|
||||
|
||||
|
||||
# Build variables for the workflow
|
||||
variables = {
|
||||
"action": action,
|
||||
@@ -76,8 +76,8 @@ class IssueCommentTrigger(TriggerEvent):
|
||||
"author": {
|
||||
"login": comment.get("user", {}).get("login", ""),
|
||||
"avatar_url": comment.get("user", {}).get("avatar_url", ""),
|
||||
"html_url": comment.get("user", {}).get("html_url", "")
|
||||
}
|
||||
"html_url": comment.get("user", {}).get("html_url", ""),
|
||||
},
|
||||
},
|
||||
"issue": {
|
||||
"number": issue.get("number"),
|
||||
@@ -94,10 +94,10 @@ class IssueCommentTrigger(TriggerEvent):
|
||||
{
|
||||
"login": assignee.get("login", ""),
|
||||
"avatar_url": assignee.get("avatar_url", ""),
|
||||
"html_url": assignee.get("html_url", "")
|
||||
"html_url": assignee.get("html_url", ""),
|
||||
}
|
||||
for assignee in issue.get("assignees", [])
|
||||
]
|
||||
],
|
||||
},
|
||||
"repository": {
|
||||
"name": repository.get("name", ""),
|
||||
@@ -108,15 +108,15 @@ class IssueCommentTrigger(TriggerEvent):
|
||||
"owner": {
|
||||
"login": repository.get("owner", {}).get("login", ""),
|
||||
"avatar_url": repository.get("owner", {}).get("avatar_url", ""),
|
||||
"html_url": repository.get("owner", {}).get("html_url", "")
|
||||
}
|
||||
"html_url": repository.get("owner", {}).get("html_url", ""),
|
||||
},
|
||||
},
|
||||
"sender": {
|
||||
"login": sender.get("login", ""),
|
||||
"avatar_url": sender.get("avatar_url", ""),
|
||||
"html_url": sender.get("html_url", ""),
|
||||
"type": sender.get("type", "")
|
||||
}
|
||||
"type": sender.get("type", ""),
|
||||
},
|
||||
}
|
||||
|
||||
return TriggerEventResponse(variables=variables)
|
||||
return TriggerEventResponse(variables=variables)
|
||||
|
||||
Reference in New Issue
Block a user