-
Notifications
You must be signed in to change notification settings - Fork 1.4k
feat(integrations): Add Trello setup wizard and create_card tool (#4216) #4228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| """What Trello needs before it is considered configured.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from integrations.setup_flow import IntegrationSetupSpec, SetupField | ||
| from integrations.trello.verifier import verify_trello | ||
|
|
||
| TRELLO_SETUP = IntegrationSetupSpec( | ||
| service="trello", | ||
| fields=( | ||
| SetupField( | ||
| name="api_key", | ||
| label="API Key", | ||
| prompt="Trello API Key", | ||
| env_var="TRELLO_API_KEY", | ||
| secret=True, | ||
| ), | ||
| SetupField( | ||
| name="token", | ||
| label="Token", | ||
| prompt="Trello Token", | ||
| env_var="TRELLO_TOKEN", | ||
| secret=True, | ||
| ), | ||
| SetupField( | ||
| name="board_id", | ||
| label="Board ID", | ||
| prompt="Trello Board ID (optional)", | ||
| env_var="TRELLO_BOARD_ID", | ||
| optional=True, | ||
| ), | ||
| SetupField( | ||
| name="list_id", | ||
| label="List ID", | ||
| prompt="Trello List ID", | ||
| env_var="TRELLO_LIST_ID", | ||
| optional=False, | ||
| ), | ||
| ), | ||
| verify=verify_trello, | ||
| ) | ||
|
|
||
| __all__ = ["TRELLO_SETUP"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| """Trello integration tools.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from integrations.trello.tools.create_card import create_trello_card_tool | ||
|
|
||
| __all__ = ["create_trello_card_tool"] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| """Trello create card tool for investigation workflows.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from typing import Any | ||
|
|
||
| from core.tool_framework.base import BaseTool | ||
| from core.tool_framework.utils.tool_availability import tool_unavailable | ||
| from integrations.trello.client import create_trello_card | ||
| from integrations.trello.config import build_trello_config | ||
|
|
||
|
|
||
| class CreateTrelloCardTool(BaseTool): | ||
| """Create a new card in Trello for tracking tasks or incidents.""" | ||
|
|
||
| name = "create_trello_card" | ||
| source = "trello" | ||
| description = ( | ||
| "Create a new card in Trello to track incident resolution, action items, " | ||
| "or postmortem tasks. Requires the name and description of the card." | ||
| ) | ||
| use_cases = [ | ||
| "Creating a tracking card for a newly discovered bug", | ||
| "Adding action items from an incident postmortem", | ||
| "Tracking remediation steps during an active incident", | ||
| ] | ||
| requires = ["api_key", "token", "list_id", "name", "desc"] | ||
| injected_params = ["api_key", "token"] | ||
| input_schema = { | ||
| "type": "object", | ||
| "properties": { | ||
| "api_key": {"type": "string", "description": "Trello API key"}, | ||
| "token": {"type": "string", "description": "Trello token"}, | ||
| "board_id": {"type": "string", "description": "Trello Board ID (optional)"}, | ||
| "list_id": { | ||
| "type": "string", | ||
| "description": "Trello List ID (optional if configured in environment)", | ||
| }, | ||
| "name": {"type": "string", "description": "Title of the card"}, | ||
| "desc": {"type": "string", "description": "Detailed description for the card"}, | ||
| }, | ||
| "required": ["api_key", "token", "name", "desc"], | ||
| } | ||
| outputs = { | ||
| "card_id": "The ID of the created card", | ||
| "url": "The URL of the created card", | ||
| } | ||
|
|
||
| def is_available(self, sources: dict) -> bool: | ||
| trello_config = sources.get("trello", {}) | ||
| return bool( | ||
| trello_config.get("api_key") | ||
| and trello_config.get("token") | ||
| and trello_config.get("list_id") | ||
| ) | ||
|
|
||
| def extract_params(self, sources: dict) -> dict[str, Any]: | ||
| trello = sources.get("trello", {}) | ||
| return { | ||
| "api_key": trello.get("api_key", ""), | ||
| "token": trello.get("token", ""), | ||
| "board_id": trello.get("board_id", ""), | ||
| "list_id": trello.get("list_id", ""), | ||
| "name": "", | ||
| "desc": "", | ||
| } | ||
|
|
||
| def run( | ||
| self, | ||
| api_key: str, | ||
| token: str, | ||
| name: str, | ||
| desc: str, | ||
| board_id: str = "", | ||
| list_id: str = "", | ||
| **_kwargs: Any, | ||
| ) -> dict[str, Any]: | ||
| if not api_key or not token: | ||
| return tool_unavailable("trello", "Trello integration is not configured.") | ||
| if not name: | ||
| return tool_unavailable("trello", "Card name is required.") | ||
| if not desc: | ||
| return tool_unavailable("trello", "Card description is required.") | ||
|
|
||
| config = build_trello_config( | ||
| { | ||
| "api_key": api_key, | ||
| "token": token, | ||
| "board_id": board_id, | ||
| "list_id": list_id, | ||
| } | ||
| ) | ||
|
|
||
| target_list_id = (list_id or config.list_id).strip() | ||
| if not target_list_id: | ||
| return tool_unavailable("trello", "List ID is required to create a Trello card.") | ||
|
|
||
| try: | ||
| result = create_trello_card( | ||
| config=config, | ||
| name=name, | ||
| desc=desc, | ||
| list_id=target_list_id, | ||
| ) | ||
| return { | ||
| "source": "trello", | ||
| "available": True, | ||
| "card_id": result.get("id", ""), | ||
| "url": result.get("shortUrl", ""), | ||
| } | ||
| except Exception as err: | ||
| return tool_unavailable("trello", str(err)) | ||
|
|
||
|
|
||
| create_trello_card_tool = CreateTrelloCardTool() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,47 +1,48 @@ | ||
| """Trello credential and connectivity verification.""" | ||
|
|
||
| import logging | ||
| from dataclasses import dataclass | ||
| from typing import Any | ||
|
|
||
| import httpx | ||
|
|
||
| import integrations.trello.client as client | ||
| from integrations._validation_helpers import report_validation_failure | ||
| from integrations.trello.config import TrelloConfig | ||
| from integrations.trello.config import build_trello_config | ||
| from integrations.verification import register_verifier, result | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
|
greptile-apps[bot] marked this conversation as resolved.
|
||
| @dataclass(frozen=True) | ||
| class TrelloValidationResult: | ||
| """Result of validating a Trello integration.""" | ||
|
|
||
| ok: bool | ||
| detail: str | ||
|
|
||
| @register_verifier("trello") | ||
| def verify_trello(source: str, config: dict[str, Any]) -> dict[str, str]: | ||
|
greptile-apps[bot] marked this conversation as resolved.
|
||
| """Validate Trello connectivity via the standard registry.""" | ||
| try: | ||
| trello_config = build_trello_config(config) | ||
| except Exception as err: | ||
| return result("trello", source, "missing", f"Invalid Trello configuration: {err}") | ||
|
|
||
| def validate_trello_config(config: TrelloConfig) -> TrelloValidationResult: | ||
| """Validate Trello connectivity.""" | ||
| if not config.api_key: | ||
| return TrelloValidationResult(ok=False, detail="Trello API key is required.") | ||
| if not config.token: | ||
| return TrelloValidationResult(ok=False, detail="Trello token is required.") | ||
| if not trello_config.api_key: | ||
| return result("trello", source, "missing", "Trello API key is required.") | ||
| if not trello_config.token: | ||
| return result("trello", source, "missing", "Trello token is required.") | ||
|
|
||
| try: | ||
| member = client.validate_trello_connection(config=config) | ||
| member = client.validate_trello_connection(config=trello_config) | ||
| username = member.get("username", "unknown") | ||
| return TrelloValidationResult( | ||
| ok=True, | ||
| detail=f"Trello connectivity successful. Authenticated as @{username}", | ||
| return result( | ||
| "trello", | ||
| source, | ||
| "passed", | ||
| f"Trello connectivity successful. Authenticated as @{username}", | ||
| ) | ||
| except httpx.HTTPStatusError as err: | ||
| detail = err.response.text.strip() or str(err) | ||
| return TrelloValidationResult(ok=False, detail=f"Trello validation failed: {detail}") | ||
| return result("trello", source, "failed", f"Trello validation failed: {detail}") | ||
| except Exception as err: | ||
| report_validation_failure( | ||
| err, | ||
| logger=logger, | ||
| integration="trello", | ||
| method="validate_trello_config", | ||
| method="verify_trello", | ||
| ) | ||
| return TrelloValidationResult(ok=False, detail=f"Trello validation failed: {err}") | ||
| return result("trello", source, "error", f"Trello validation failed: {err}") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Trello verification encounters a connection, timeout, response, or other generic exception, this returns the unsupported Knowledge Base Used: Integrations Framework |
||
Uh oh!
There was an error while loading. Please reload this page.