refactor: streamline GitHub issue trigger implementation

- Removed the deprecated IssuesTrigger class and replaced it with a more focused IssueOpenedTrigger class to handle specific events when a new issue is opened.
- Updated the GitHub trigger YAML configuration to reflect changes in the subscription schema and parameters.
- Enhanced the validation logic for issue parameters, including title patterns, labels, assignees, authors, milestones, and body content.
- Improved the overall structure and clarity of the trigger implementation, ensuring better maintainability and functionality.

These changes contribute to a more efficient and organized handling of GitHub issue events, enhancing the plugin's responsiveness to user interactions.
This commit is contained in:
Harry
2025-09-29 18:31:39 +08:00
parent d75f734b7d
commit 46b1ef471a
9 changed files with 827 additions and 671 deletions
@@ -30,9 +30,10 @@ from dify_plugin.interfaces.trigger import TriggerProvider, TriggerSubscriptionC
class GithubProvider(TriggerProvider):
"""Handle GitHub webhook event dispatch."""
_TRIGGER_EVENTS: ClassVar[dict[str, list[str]]] = {
"issues": ["issues"],
"issue_comment": ["issues"],
__TRIGGER_EVENTS_MAPPING: ClassVar[Mapping[str, Mapping[str, list[str]]]] = {
"issues": {
"opened": ["issue_opened"],
}
}
def _dispatch_event(self, subscription: Subscription, request: Request) -> TriggerDispatch:
@@ -44,14 +45,19 @@ class GithubProvider(TriggerProvider):
if not event_type:
raise TriggerDispatchError("Missing GitHub event type header")
# Validate payload and raise meaningful errors when parsing fails.
self._parse_payload(request)
triggers = self._TRIGGER_EVENTS.get(event_type, [])
payload = self._validate_payload(request)
triggers = self._dispatch_event_triggers(event_type, payload)
response = Response(response='{"status": "ok"}', status=200, mimetype="application/json")
return TriggerDispatch(triggers=triggers, response=response)
def _parse_payload(self, request: Request) -> Mapping[str, Any]:
def _dispatch_event_triggers(self, event_type: str, payload: Mapping[str, Any]) -> list[str]:
event_type = event_type.lower()
if event_type == "issues":
action = payload.get("action")
return self.__TRIGGER_EVENTS_MAPPING["issues"].get(action, [])
return []
def _validate_payload(self, request: Request) -> Mapping[str, Any]:
try:
content_type = request.headers.get("Content-Type", "")
if "application/x-www-form-urlencoded" in content_type:
@@ -1,33 +1,47 @@
subscription_schema:
- name: "webhook_secret"
type: "secret-input"
required: false
label:
zh_Hans: "Webhook Secret"
en_US: "Webhook Secret"
ja_JP: "Webhookシークレット"
help:
en_US: "Optional webhook secret for validating GitHub webhook requests"
ja_JP: "GitHub Webhookリクエストの検証用のオプションのWebhookシークレット"
zh_Hans: "可选的用于验证 GitHub webhook 请求的 webhook 密钥"
- name: "webhook_secret"
type: "secret-input"
required: false
label:
zh_Hans: "Webhook Secret"
en_US: "Webhook Secret"
ja_JP: "Webhookシークレット"
help:
en_US: "Optional webhook secret for validating GitHub webhook requests"
ja_JP: "GitHub Webhookリクエストの検証用のオプションのWebhookシークレット"
zh_Hans: "可选的用于验证 GitHub webhook 请求的 webhook 密钥"
subscription_constructor: # OPTIONAL
subscription_constructor:
parameters:
- name: "repository"
- name: "repository"
label:
en_US: "Repository"
zh_Hans: "仓库"
ja_JP: "リポジトリ"
type: "dynamic-select"
required: true
placeholder:
en_US: "owner/repo"
zh_Hans: "owner/repo"
ja_JP: "owner/repo"
help:
en_US: "GitHub repository in format owner/repo (e.g., microsoft/vscode)"
zh_Hans: "GitHub 仓库,格式为 owner/repo(例如:microsoft/vscode"
ja_JP: "GitHubリポジトリは owner/repo 形式で入力してください(例: microsoft/vscode"
- name: "triggers"
label:
en_US: "Triggers"
zh_Hans: "触发器"
ja_JP: "トリガー"
type: "checkbox"
required: true
options:
- value: "issues"
label:
en_US: "Repository"
zh_Hans: "仓库"
ja_JP: "リポジトリ"
type: "dynamic-select"
required: true
placeholder:
en_US: "owner/repo"
zh_Hans: "owner/repo"
ja_JP: "owner/repo"
help:
en_US: "GitHub repository in format owner/repo (e.g., microsoft/vscode)"
zh_Hans: "GitHub 仓库,格式为 owner/repo(例如:microsoft/vscode"
ja_JP: "GitHubリポジトリは owner/repo 形式で入力してください(例: microsoft/vscode"
en_US: "Issues"
zh_Hans: "议题"
ja_JP: "イシュー"
credentials_schema:
access_tokens:
help:
@@ -47,52 +61,51 @@ subscription_constructor: # OPTIONAL
url: https://github.com/settings/tokens?type=beta
oauth_schema:
client_schema:
- name: "client_id"
type: "secret-input"
required: true
url: https://github.com/settings/applications/new
placeholder:
en_US: "Please input your Client ID"
zh_Hans: "请输入你的 Client ID"
ja_JP: "クライアントIDを入力してください"
help:
en_US: "Client ID is used to authenticate requests to the GitHub API."
zh_Hans: "Client ID 用于认证请求到 GitHub API。"
ja_JP: "クライアントIDはGitHub APIへのリクエスト認証に使用されます。"
label:
zh_Hans: "Client ID"
en_US: "Client ID"
ja_JP: "クライアントID"
- name: "client_secret"
type: "secret-input"
required: true
url: https://github.com/settings/applications/new
placeholder:
en_US: "Please input your Client Secret"
zh_Hans: "请输入你的 Client Secret"
ja_JP: "クライアントシークレットを入力してください"
help:
en_US: "Client Secret is used to authenticate requests to the GitHub API."
zh_Hans: "Client Secret 用于认证请求到 GitHub API。"
ja_JP: "クライアントシークレットはGitHub APIへのリクエスト認証に使用されます。"
label:
zh_Hans: "Client Secret"
en_US: "Client Secret"
ja_JP: "クライアントシークレット"
- name: "client_id"
type: "secret-input"
required: true
url: https://github.com/settings/applications/new
placeholder:
en_US: "Please input your Client ID"
zh_Hans: "请输入你的 Client ID"
ja_JP: "クライアントIDを入力してください"
help:
en_US: "Client ID is used to authenticate requests to the GitHub API."
zh_Hans: "Client ID 用于认证请求到 GitHub API。"
ja_JP: "クライアントIDはGitHub APIへのリクエスト認証に使用されます。"
label:
zh_Hans: "Client ID"
en_US: "Client ID"
ja_JP: "クライアントID"
- name: "client_secret"
type: "secret-input"
required: true
url: https://github.com/settings/applications/new
placeholder:
en_US: "Please input your Client Secret"
zh_Hans: "请输入你的 Client Secret"
ja_JP: "クライアントシークレットを入力してください"
help:
en_US: "Client Secret is used to authenticate requests to the GitHub API."
zh_Hans: "Client Secret 用于认证请求到 GitHub API。"
ja_JP: "クライアントシークレットはGitHub APIへのリクエスト認証に使用されます。"
label:
zh_Hans: "Client Secret"
en_US: "Client Secret"
ja_JP: "クライアントシークレット"
credentials_schema:
- name: "access_tokens"
type: "secret-input"
label:
zh_Hans: "Access Token"
en_US: "Access Token"
ja_JP: "アクセストークン"
- name: "access_tokens"
type: "secret-input"
label:
zh_Hans: "Access Token"
en_US: "Access Token"
ja_JP: "アクセストークン"
extra:
python:
source: provider/github.py
triggers:
# Core Events (Consolidated)
- triggers/issues.yaml # Handles: opened, closed, reopened, edited, assigned, unassigned, labeled, unlabeled, etc.
- triggers/issues/issue_opened.yaml
identity:
author: langgenius
@@ -1,52 +0,0 @@
from collections.abc import Mapping
from typing import Any
from werkzeug import Request
from dify_plugin.entities.trigger import Event
from dify_plugin.errors.trigger import TriggerIgnoreEventError
from dify_plugin.interfaces.trigger import TriggerEvent
class IssuesTrigger(TriggerEvent):
"""
GitHub Issue Event Trigger
This unified trigger handles all GitHub issue events and extracts relevant
information from the webhook payload to provide as variables to the workflow.
"""
def _trigger(self, request: Request, parameters: Mapping[str, Any]) -> Event:
"""
Handle GitHub issue event trigger with comprehensive filtering
Parameters:
- event: Select which issue actions to trigger on (opened, closed, reopened, edited, assigned, labeled, etc.)
- labels: Only trigger if issue has these labels (comma-separated)
- exclude_labels: Don't trigger if issue has these labels (comma-separated)
- assignee: Only trigger if assigned to these users (comma-separated)
- authors: Only trigger for issues from these authors (comma-separated)
- exclude_authors: Don't trigger for issues from these authors (comma-separated)
- milestone: Only trigger for issues with these milestones (comma-separated)
- title_pattern: Only trigger if title matches this pattern (supports wildcards, comma-separated)
- body_contains: Only trigger if body contains these keywords (comma-separated)
"""
# Get the event payload
payload = request.get_json()
if not payload:
raise ValueError("No payload received")
# Get the action type
action = payload.get("action", "")
# Apply event filter
event = parameters.get("event", [])
if event and action not in event:
raise TriggerIgnoreEventError(f"Action '{action}' not in filter list: {event}")
return Event(
variables={
"action": action,
# TODO: add more variables depends on the trigger configuration
}
)
@@ -1,484 +0,0 @@
identity:
name: issues
author: langgenius
label:
en_US: Issues
zh_Hans: 议题
ja_JP: イシュー
description:
human:
en_US: Triggers on issue events (opened, closed, reopened, edited, assigned, labeled, etc.)
zh_Hans: 在议题事件时触发(打开、关闭、重新打开、编辑、分配、标记等)
ja_JP: イシューイベント(作成、クローズ、再オープン、編集、担当者割り当て、ラベル付与など)でトリガーされます
llm:
en_US: This trigger activates on various GitHub issue events, providing comprehensive information about the issue, repository, and involved users.
zh_Hans: 此触发器在各种 GitHub 议题事件时激活,提供有关议题、仓库和相关用户的综合信息。
ja_JP: このトリガーは様々なGitHubイシューイベントで発動し、イシュー、リポジトリ、関係ユーザーの包括的な情報を提供します。
parameters:
- name: event
label:
en_US: Event
zh_Hans: 事件
ja_JP: イベント
type: checkbox
required: false
options:
- value: opened
label:
en_US: Opened
zh_Hans: 新建议题
ja_JP: 作成
- value: closed
label:
en_US: Closed
zh_Hans: 议题关闭
ja_JP: クローズ
- value: reopened
label:
en_US: Reopened
zh_Hans: 关闭后再次开启
ja_JP: 再オープン
- value: edited
label:
en_US: Edited
zh_Hans: 议题内容被修改
ja_JP: 編集
- value: assigned
label:
en_US: Assigned
zh_Hans: 指定负责人
ja_JP: 担当者割り当て
- value: unassigned
label:
en_US: Unassigned
zh_Hans: 移除负责人
ja_JP: 担当者解除
- value: labeled
label:
en_US: Labeled
zh_Hans: 议题被打标签
ja_JP: ラベル付与
- value: unlabeled
label:
en_US: Unlabeled
zh_Hans: 议题标签被移除
ja_JP: ラベル削除
- value: milestoned
label:
en_US: Milestoned
zh_Hans: 设置目标里程碑
ja_JP: マイルストーン追加
- value: demilestoned
label:
en_US: Demilestoned
zh_Hans: 取消目标里程碑
ja_JP: マイルストーン削除
- value: pinned
label:
en_US: Pinned
zh_Hans: 议题被置顶
ja_JP: ピン留め
- value: unpinned
label:
en_US: Unpinned
zh_Hans: 议题取消置顶
ja_JP: ピン留め解除
- value: locked
label:
en_US: Locked
zh_Hans: 议题被锁定,无法评论
ja_JP: ロック
- value: unlocked
label:
en_US: Unlocked
zh_Hans: 议题解锁,允许评论
ja_JP: ロック解除
- value: transferred
label:
en_US: Transferred
zh_Hans: 议题转移到其他仓库
ja_JP: 転送
multiple: true
help:
en_US: "Select which issue actions to trigger on (leave empty for all)"
zh_Hans: "选择触发的议题操作(留空表示所有)"
ja_JP: "どのイシューアクションでトリガーするか選択してください(空欄ですべて)"
- name: labels
label:
en_US: Required Labels
zh_Hans: 必需标签
ja_JP: 必須ラベル
type: string
required: false
placeholder:
en_US: "e.g., bug, enhancement, urgent (comma-separated)"
zh_Hans: "例如:bug, enhancement, urgent(逗号分隔)"
ja_JP: "例: bug, enhancement, urgent(カンマ区切り)"
help:
en_US: "Only trigger if issue has these labels"
zh_Hans: "仅当议题有这些标签时触发"
ja_JP: "イシューがこれらのラベルを持つ場合のみトリガー"
- name: exclude_labels
label:
en_US: Exclude Labels
zh_Hans: 排除标签
ja_JP: 除外ラベル
type: string
required: false
placeholder:
en_US: "e.g., wontfix, duplicate (comma-separated)"
zh_Hans: "例如:wontfix, duplicate(逗号分隔)"
ja_JP: "例: wontfix, duplicate(カンマ区切り)"
help:
en_US: "Don't trigger if issue has these labels"
zh_Hans: "如果议题有这些标签则不触发"
ja_JP: "イシューがこれらのラベルを持つ場合はトリガーしない"
- name: assignee
label:
en_US: Assignee Filter
zh_Hans: 受理人过滤
ja_JP: 担当者フィルター
type: string
required: false
placeholder:
en_US: "e.g., username1, username2 (comma-separated)"
zh_Hans: "例如:username1, username2(逗号分隔)"
ja_JP: "例: username1, username2(カンマ区切り)"
help:
en_US: "Only trigger if assigned to these users"
zh_Hans: "仅当分配给这些用户时触发"
ja_JP: "これらのユーザーに割り当てられた場合のみトリガー"
- name: authors
label:
en_US: Authors
zh_Hans: 作者
ja_JP: 作成者
type: string
required: false
placeholder:
en_US: "e.g., user1, user2 (comma-separated)"
zh_Hans: "例如:user1, user2(逗号分隔)"
ja_JP: "例: user1, user2(カンマ区切り)"
help:
en_US: "Only trigger for issues from these authors"
zh_Hans: "仅对这些作者的议题触发"
ja_JP: "これらの作成者のイシューのみトリガー"
- name: exclude_authors
label:
en_US: Exclude Authors
zh_Hans: 排除作者
ja_JP: 除外作成者
type: string
required: false
placeholder:
en_US: "e.g., bot1, bot2 (comma-separated)"
zh_Hans: "例如:bot1, bot2(逗号分隔)"
ja_JP: "例: bot1, bot2(カンマ区切り)"
help:
en_US: "Don't trigger for issues from these authors"
zh_Hans: "不对这些作者的议题触发"
ja_JP: "これらの作成者のイシューはトリガーしない"
- name: milestone
label:
en_US: Milestone
zh_Hans: 里程碑
ja_JP: マイルストーン
type: string
required: false
placeholder:
en_US: "e.g., v1.0, v2.0 (comma-separated) (default: all)"
zh_Hans: "例如:v1.0, v2.0(逗号分隔)(默认所有)"
ja_JP: "例: v1.0, v2.0(カンマ区切り)(デフォルト: 全て)"
help:
en_US: "Only trigger for issues with these milestones"
zh_Hans: "仅对具有这些里程碑的议题触发"
ja_JP: "これらのマイルストーンのイシューのみトリガー"
- name: title_pattern
label:
en_US: Title Pattern
zh_Hans: 标题模式
ja_JP: タイトルパターン
type: string
required: false
placeholder:
en_US: "e.g., [BUG]*, [FEATURE]* (supports wildcards)"
zh_Hans: "例如:[BUG]*, [FEATURE]*(支持通配符)"
ja_JP: "例: [BUG]*, [FEATURE]*(ワイルドカード対応)"
help:
en_US: "Only trigger if title matches this pattern"
zh_Hans: "仅当标题匹配此模式时触发"
ja_JP: "タイトルがこのパターンに一致する場合のみトリガー"
- name: body_contains
label:
en_US: Body Contains
zh_Hans: 正文包含
ja_JP: 本文に含む
type: string
required: false
placeholder:
en_US: "e.g., regression, critical (comma-separated keywords)"
zh_Hans: "例如:regression, critical(逗号分隔的关键词)"
ja_JP: "例: regression, critical(カンマ区切りキーワード)"
help:
en_US: "Only trigger if body contains these keywords"
zh_Hans: "仅当正文包含这些关键词时触发"
ja_JP: "本文にこれらのキーワードが含まれる場合のみトリガー"
output_schema:
type: object
properties:
action:
type: string
description: The action that was performed on the issue (opened, edited, deleted, pinned, unpinned, closed, reopened, assigned, unassigned, labeled, unlabeled, locked, unlocked, transferred, milestoned, demilestoned)
issue:
type: object
description: The issue itself
properties:
id:
type: integer
description: Unique identifier of the issue
number:
type: integer
description: Number uniquely identifying the issue within its repository
title:
type: string
description: Title of the issue
body:
type: string
description: Contents of the issue
state:
type: string
description: State of the issue (open or closed)
state_reason:
type: string
description: The reason for the current state (completed, reopened, not_planned)
created_at:
type: string
description: When the issue was created (ISO 8601 format)
updated_at:
type: string
description: When the issue was last updated (ISO 8601 format)
closed_at:
type: string
description: When the issue was closed (ISO 8601 format), null if open
user:
type: object
description: The user who created the issue
properties:
login:
type: string
description: GitHub username
id:
type: integer
description: User ID
avatar_url:
type: string
description: Avatar URL
type:
type: string
description: User type (User, Bot, Organization)
assignees:
type: array
description: Users assigned to this issue
items:
type: object
properties:
login:
type: string
description: GitHub username
id:
type: integer
description: User ID
labels:
type: array
description: Labels associated with the issue
items:
type: object
properties:
id:
type: integer
description: Label ID
name:
type: string
description: The name of the label
color:
type: string
description: 6-character hex code, without the leading #
description:
type: string
description: Description of the label
milestone:
type: object
description: Milestone associated with the issue
properties:
id:
type: integer
description: Milestone ID
number:
type: integer
description: Milestone number
title:
type: string
description: The title of the milestone
description:
type: string
description: Description of the milestone
state:
type: string
description: State of the milestone (open or closed)
due_on:
type: string
description: When the milestone is due (ISO 8601 format)
created_at:
type: string
description: When the milestone was created
updated_at:
type: string
description: When the milestone was last updated
closed_at:
type: string
description: When the milestone was closed
locked:
type: boolean
description: Whether the issue is locked
comments:
type: integer
description: Number of comments on the issue
html_url:
type: string
description: URL to the issue on GitHub
url:
type: string
description: API URL for the issue
repository:
type: object
description: The repository where the issue was created
properties:
id:
type: integer
description: Repository ID
name:
type: string
description: The name of the repository
full_name:
type: string
description: The full name of the repository (owner/name)
private:
type: boolean
description: Whether the repository is private
owner:
type: object
description: Repository owner
properties:
login:
type: string
description: Owner username
id:
type: integer
description: Owner ID
type:
type: string
description: Owner type (User or Organization)
html_url:
type: string
description: URL to the repository on GitHub
description:
type: string
description: Repository description
fork:
type: boolean
description: Whether the repository is a fork
created_at:
type: string
description: When the repository was created
updated_at:
type: string
description: When the repository was last updated
pushed_at:
type: string
description: When the repository was last pushed to
language:
type: string
description: Primary language of the repository
default_branch:
type: string
description: Default branch of the repository
sender:
type: object
description: The user who triggered the event
properties:
login:
type: string
description: GitHub username
id:
type: integer
description: User ID
avatar_url:
type: string
description: Avatar URL
type:
type: string
description: User type (User, Bot, Organization)
assignee:
type: object
description: The assignee added or removed (only for assigned/unassigned events)
properties:
login:
type: string
description: GitHub username
id:
type: integer
description: User ID
label:
type: object
description: The label added or removed (only for labeled/unlabeled events)
properties:
id:
type: integer
description: Label ID
name:
type: string
description: The name of the label
color:
type: string
description: 6-character hex code, without the leading #
description:
type: string
description: Description of the label
changes:
type: object
description: Changes made in an edit (only for edited events)
properties:
title:
type: object
properties:
from:
type: string
description: Previous title
body:
type: object
properties:
from:
type: string
description: Previous body content
installation:
type: object
description: GitHub App installation (when triggered by a GitHub App)
properties:
id:
type: integer
description: Installation ID
extra:
python:
source: triggers/issues.py
@@ -0,0 +1,129 @@
from collections.abc import Mapping
import re
from typing import Any
from dify_plugin.errors.trigger import TriggerIgnoreEventError
from werkzeug import Request
from dify_plugin.entities.trigger import Event
from dify_plugin.interfaces.trigger import TriggerEvent
class IssueOpenedTrigger(TriggerEvent):
"""
GitHub Issue Opened Event Trigger
This trigger handles GitHub issue opened events and extracts relevant
information from the webhook payload to provide as variables to the workflow.
"""
def _check_title_pattern(self, issue: dict, pattern: str) -> None:
"""Check if issue title matches the pattern"""
if not pattern:
return
title = issue.get("title", "")
if not re.match(pattern, title):
raise TriggerIgnoreEventError()
def _check_labels(self, issue: dict, labels_param: str) -> None:
"""Check if issue has required labels"""
if not labels_param:
return
required_labels = [label.strip() for label in labels_param.split(",") if label.strip()]
if not required_labels:
return
issue_labels = [label.get("name") for label in issue.get("labels", [])]
if not any(label in issue_labels for label in required_labels):
raise TriggerIgnoreEventError()
def _check_assignee(self, issue: dict, assignee_param: str) -> None:
"""Check if issue is assigned to allowed users"""
if not assignee_param:
return
allowed_assignees = [assignee.strip() for assignee in assignee_param.split(",") if assignee.strip()]
if not allowed_assignees:
return
issue_assignees = []
# Collect assignee usernames
single_assignee = issue.get("assignee")
if single_assignee and single_assignee.get("login"):
issue_assignees.append(single_assignee["login"])
for assignee in issue.get("assignees", []):
login = assignee.get("login")
if login:
issue_assignees.append(login)
if not any(assignee in issue_assignees for assignee in allowed_assignees):
raise TriggerIgnoreEventError()
def _check_authors(self, issue: dict, authors_param: str) -> None:
"""Check if issue author is in allowed list"""
if not authors_param:
return
allowed_authors = [author.strip() for author in authors_param.split(",") if author.strip()]
if not allowed_authors:
return
issue_author = issue.get("user", {}).get("login")
if issue_author not in allowed_authors:
raise TriggerIgnoreEventError()
def _check_milestone(self, issue: dict, milestone_param: str) -> None:
"""Check if issue milestone matches allowed milestones"""
if not milestone_param:
return
allowed_milestones = [milestone.strip() for milestone in milestone_param.split(",") if milestone.strip()]
if not allowed_milestones:
return
milestone = issue.get("milestone")
if not milestone:
raise TriggerIgnoreEventError()
milestone_title = milestone.get("title")
if not milestone_title or milestone_title not in allowed_milestones:
raise TriggerIgnoreEventError()
def _check_body_contains(self, issue: dict, body_contains_param: str) -> None:
"""Check if issue body contains required keywords"""
if not body_contains_param:
return
keywords = [keyword.strip().lower() for keyword in body_contains_param.split(",") if keyword.strip()]
if not keywords:
return
issue_body = (issue.get("body") or "").lower()
if not any(keyword in issue_body for keyword in keywords):
raise TriggerIgnoreEventError()
def _trigger(self, request: Request, parameters: Mapping[str, Any]) -> Event:
"""
Handle GitHub issue opened event trigger
"""
payload = request.get_json()
if not payload:
raise ValueError("No payload received")
issue = payload.get("issue")
if not issue:
raise ValueError("No issue data in payload")
# Apply all filters
self._check_title_pattern(issue, parameters.get("title_pattern"))
self._check_labels(issue, parameters.get("labels"))
self._check_assignee(issue, parameters.get("assignee"))
self._check_authors(issue, parameters.get("authors"))
self._check_milestone(issue, parameters.get("milestone"))
self._check_body_contains(issue, parameters.get("body_contains"))
return Event(variables={**payload})
@@ -0,0 +1,604 @@
identity:
name: issue_opened
author: langgenius
label:
en_US: Issue Opened
zh_Hans: Issue 打开
pt_BR: Issue Aberta
description:
human:
en_US: Triggers when a new issue is opened
zh_Hans: 当新 issue 打开时触发
pt_BR: Dispara quando uma nova issue é aberta
llm:
en_US: This trigger activates when a new issue is opened on a GitHub repository, providing information about the issue, repository, and user who opened it.
zh_Hans: 当在 GitHub 仓库中打开新 issue 时,此触发器会被激活,提供有关 issue、仓库和打开它的用户的信息。
pt_BR: Este gatilho é ativado quando uma nova issue é aberta em um repositório do GitHub, fornecendo informações sobre a issue, repositório e usuário que a abriu.
parameters:
- name: labels
label:
en_US: Required Labels
zh_Hans: 必需标签
ja_JP: 必須ラベル
type: string
required: false
description:
en_US: "Only trigger if issue has these labels (e.g., bug, enhancement, urgent, comma-separated)"
zh_Hans: "仅当议题有这些标签时触发(例如:bug, enhancement, urgent,逗号分隔)"
ja_JP: "イシューがこれらのラベルを持つ場合のみトリガー(例: bug, enhancement, urgent,カンマ区切り)"
- name: assignee
label:
en_US: Assignee Filter
zh_Hans: 受理人过滤
ja_JP: 担当者フィルター
type: string
required: false
description:
en_US: "Only trigger if assigned to these users (e.g., username1, username2, comma-separated)"
zh_Hans: "仅当分配给这些用户时触发(例如:username1, username2,逗号分隔)"
ja_JP: "これらのユーザーに割り当てられた場合のみトリガー(例: username1, username2,カンマ区切り)"
- name: authors
label:
en_US: Authors
zh_Hans: 作者
ja_JP: 作成者
type: string
required: false
description:
en_US: "Only trigger for issues from these authors (e.g., user1, user2, comma-separated)"
zh_Hans: "仅对这些作者的议题触发(例如:user1, user2,逗号分隔)"
ja_JP: "これらの作成者のイシューのみトリガー(例: user1, user2,カンマ区切り)"
- name: milestone
label:
en_US: Milestone
zh_Hans: 里程碑
ja_JP: マイルストーン
type: string
required: false
description:
en_US: "Only trigger for issues with these milestones (e.g., v1.0, v2.0, comma-separated, default: all)"
zh_Hans: "仅对具有这些里程碑的议题触发(例如:v1.0, v2.0,逗号分隔,默认所有)"
ja_JP: "これらのマイルストーンのイシューのみトリガー(例: v1.0, v2.0,カンマ区切り,デフォルト: 全て)"
- name: title_pattern
label:
en_US: Title Pattern
zh_Hans: 标题模式
ja_JP: タイトルパターン
type: string
required: false
description:
en_US: "Only trigger if title matches this pattern (e.g., [BUG]*, [FEATURE]*, supports wildcards)"
zh_Hans: "仅当标题匹配此模式时触发(例如:[BUG]*, [FEATURE]*,支持通配符)"
ja_JP: "タイトルがこのパターンに一致する場合のみトリガー(例: [BUG]*, [FEATURE]*,ワイルドカード対応)"
- name: body_contains
label:
en_US: Body Contains
zh_Hans: 正文包含
ja_JP: 本文に含む
type: string
required: false
description:
en_US: "Only trigger if body contains these keywords (e.g., regression, critical, comma-separated)"
zh_Hans: "仅当正文包含这些关键词时触发(例如:regression, critical,逗号分隔)"
ja_JP: "本文にこれらのキーワードが含まれる場合のみトリガー(例: regression, critical,カンマ区切り)"
output_schema:
type: object
properties:
issue:
type: object
description: The issue itself
properties:
id:
type: integer
format: int64
description: Unique identifier of the issue
node_id:
type: string
description: Node ID of the issue
number:
type: integer
description: Issue number
title:
type: string
description: Title of the issue
body:
type:
- string
description: Contents of the issue
state:
type: string
enum:
- open
- closed
description: State of the issue
state_reason:
type:
- string
locked:
type: boolean
description: Whether the issue is locked
active_lock_reason:
type:
- string
enum:
- resolved
- off-topic
- too heated
- spam
- null
comments:
type: integer
description: Number of comments
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
closed_at:
type:
- string
format: date-time
author_association:
type: string
enum:
- COLLABORATOR
- CONTRIBUTOR
- FIRST_TIMER
- FIRST_TIME_CONTRIBUTOR
- MANNEQUIN
- MEMBER
- NONE
- OWNER
description: How the author is associated with the repository
user:
type:
- object
description: User who created the issue
properties:
id:
type: integer
format: int64
login:
type: string
node_id:
type: string
avatar_url:
type: string
format: uri
html_url:
type: string
format: uri
type:
type: string
enum:
- Bot
- User
- Organization
site_admin:
type: boolean
name:
type: string
email:
type:
- string
required:
- id
- login
assignee:
type:
- object
description: User assigned to the issue
properties:
id:
type: integer
login:
type: string
avatar_url:
type: string
format: uri
html_url:
type: string
format: uri
type:
type: string
enum:
- Bot
- User
- Organization
required:
- id
- login
assignees:
type: array
description: Users assigned to the issue
items:
type:
- object
properties:
id:
type: integer
login:
type: string
avatar_url:
type: string
format: uri
html_url:
type: string
format: uri
type:
type: string
enum:
- Bot
- User
- Organization
required:
- id
- login
labels:
type: array
description: Labels on the issue
items:
type: object
properties:
id:
type: integer
node_id:
type: string
name:
type: string
description: The name of the label
color:
type: string
description: 6-character hex code, without the leading #
default:
type: boolean
description:
type:
- string
url:
type: string
format: uri
required:
- id
- name
- color
milestone:
type:
- object
description: A collection of related issues and pull requests
properties:
id:
type: integer
node_id:
type: string
number:
type: integer
description: The number of the milestone
title:
type: string
description: The title of the milestone
description:
type:
- string
state:
type: string
enum:
- open
- closed
description: The state of the milestone
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
due_on:
type:
- string
format: date-time
closed_at:
type:
- string
format: date-time
open_issues:
type: integer
closed_issues:
type: integer
html_url:
type: string
format: uri
required:
- id
- number
- title
- state
html_url:
type: string
format: uri
description: URL to view the issue on GitHub
url:
type: string
format: uri
description: API URL for the issue
repository_url:
type: string
format: uri
labels_url:
type: string
format: uri-template
comments_url:
type: string
format: uri
events_url:
type: string
format: uri
timeline_url:
type: string
format: uri
reactions:
type: object
properties:
url:
type: string
format: uri
total_count:
type: integer
"+1":
type: integer
"-1":
type: integer
laugh:
type: integer
confused:
type: integer
heart:
type: integer
hooray:
type: integer
eyes:
type: integer
rocket:
type: integer
required:
- total_count
required:
- id
- node_id
- number
- title
- state
- created_at
- updated_at
- user
- html_url
- url
- repository_url
- labels_url
- comments_url
- events_url
- comments
- locked
- author_association
- reactions
repository:
type: object
description: The repository where the issue was opened
properties:
id:
type: integer
format: int64
description: Unique identifier of the repository
node_id:
type: string
name:
type: string
description: The name of the repository
full_name:
type: string
description: Full name including owner
private:
type: boolean
description: Whether the repository is private
owner:
type:
- object
properties:
id:
type: integer
login:
type: string
node_id:
type: string
avatar_url:
type: string
format: uri
html_url:
type: string
format: uri
type:
type: string
enum:
- Bot
- User
- Organization
site_admin:
type: boolean
required:
- id
- login
html_url:
type: string
format: uri
description:
type:
- string
fork:
type: boolean
url:
type: string
format: uri
created_at:
oneOf:
- type: integer
- type: string
format: date-time
updated_at:
type: string
format: date-time
pushed_at:
oneOf:
- type: integer
- type: string
format: date-time
homepage:
type:
- string
size:
type: integer
stargazers_count:
type: integer
watchers_count:
type: integer
language:
type:
- string
forks_count:
type: integer
open_issues_count:
type: integer
default_branch:
type: string
description: The default branch of the repository
topics:
type: array
items:
type: string
visibility:
type: string
enum:
- public
- private
- internal
required:
- id
- node_id
- name
- full_name
- private
- owner
- html_url
- url
- created_at
- updated_at
- fork
- default_branch
- visibility
sender:
type: object
description: The user who triggered the event
properties:
id:
type: integer
login:
type: string
node_id:
type: string
avatar_url:
type: string
format: uri
html_url:
type: string
format: uri
type:
type: string
enum:
- Bot
- User
- Organization
site_admin:
type: boolean
required:
- id
- login
- type
organization:
type: object
description: The organization that owns the repository (if applicable)
properties:
id:
type: integer
login:
type: string
node_id:
type: string
url:
type: string
format: uri
avatar_url:
type: string
format: uri
description:
type:
- string
required:
- id
- login
- node_id
- url
installation:
type: object
description: The GitHub App installation (if applicable)
properties:
id:
type: integer
node_id:
type: string
required:
- id
- node_id
required:
- issue
- repository
- sender
extra:
python:
source: triggers/issues/issue_opened.py