mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-01-09 07:08:09 -05:00
feat(platform): Add Get Linear Issues Block (#11415)
Added the ability to get all issues for a given project. ### Changes 🏗️ - added api query - added new models - added new block that gets all issues for a given project ### Checklist 📋 #### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: <!-- Put your test plan here: --> - [x] I have ensured the new block works in dev - [x] I have ensured the other linear blocks still work
This commit is contained in:
@@ -265,3 +265,68 @@ class LinearClient:
|
||||
return [Issue(**issue) for issue in issues["searchIssues"]["nodes"]]
|
||||
except LinearAPIException as e:
|
||||
raise e
|
||||
|
||||
async def try_get_issues(
|
||||
self, project: str, status: str, is_assigned: bool, include_comments: bool
|
||||
) -> list[Issue]:
|
||||
try:
|
||||
query = """
|
||||
query IssuesByProjectStatusAndAssignee(
|
||||
$projectName: String!
|
||||
$statusName: String!
|
||||
$isAssigned: Boolean!
|
||||
$includeComments: Boolean! = false
|
||||
) {
|
||||
issues(
|
||||
filter: {
|
||||
project: { name: { eq: $projectName } }
|
||||
state: { name: { eq: $statusName } }
|
||||
assignee: { null: $isAssigned }
|
||||
}
|
||||
) {
|
||||
nodes {
|
||||
id
|
||||
title
|
||||
identifier
|
||||
description
|
||||
createdAt
|
||||
priority
|
||||
assignee {
|
||||
id
|
||||
name
|
||||
}
|
||||
project {
|
||||
id
|
||||
name
|
||||
}
|
||||
state {
|
||||
id
|
||||
name
|
||||
}
|
||||
comments @include(if: $includeComments) {
|
||||
nodes {
|
||||
id
|
||||
body
|
||||
createdAt
|
||||
user {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
variables: dict[str, Any] = {
|
||||
"projectName": project,
|
||||
"statusName": status,
|
||||
"isAssigned": not is_assigned,
|
||||
"includeComments": include_comments,
|
||||
}
|
||||
|
||||
issues = await self.query(query, variables)
|
||||
return [Issue(**issue) for issue in issues["issues"]["nodes"]]
|
||||
except LinearAPIException as e:
|
||||
raise e
|
||||
|
||||
@@ -203,3 +203,106 @@ class LinearSearchIssuesBlock(Block):
|
||||
yield "error", str(e)
|
||||
except Exception as e:
|
||||
yield "error", f"Unexpected error: {str(e)}"
|
||||
|
||||
|
||||
class LinearGetProjectIssuesBlock(Block):
|
||||
"""Block for getting issues from a Linear project filtered by status and assignee"""
|
||||
|
||||
class Input(BlockSchemaInput):
|
||||
credentials: CredentialsMetaInput = linear.credentials_field(
|
||||
description="Linear credentials with read permissions",
|
||||
required_scopes={LinearScope.READ},
|
||||
)
|
||||
project: str = SchemaField(description="Name of the project to get issues from")
|
||||
status: str = SchemaField(
|
||||
description="Status/state name to filter issues by (e.g., 'In Progress', 'Done')"
|
||||
)
|
||||
is_assigned: bool = SchemaField(
|
||||
description="Filter by assignee status - True to get assigned issues, False to get unassigned issues",
|
||||
default=False,
|
||||
)
|
||||
include_comments: bool = SchemaField(
|
||||
description="Whether to include comments in the response",
|
||||
default=False,
|
||||
)
|
||||
|
||||
class Output(BlockSchemaOutput):
|
||||
issues: list[Issue] = SchemaField(
|
||||
description="List of issues matching the criteria"
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
id="c7d3f1e8-45a9-4b2c-9f81-3e6a8d7c5b1a",
|
||||
description="Gets issues from a Linear project filtered by status and assignee",
|
||||
input_schema=self.Input,
|
||||
output_schema=self.Output,
|
||||
categories={BlockCategory.PRODUCTIVITY, BlockCategory.ISSUE_TRACKING},
|
||||
test_input={
|
||||
"project": "Test Project",
|
||||
"status": "In Progress",
|
||||
"is_assigned": False,
|
||||
"include_comments": False,
|
||||
"credentials": TEST_CREDENTIALS_INPUT_OAUTH,
|
||||
},
|
||||
test_credentials=TEST_CREDENTIALS_OAUTH,
|
||||
test_output=[
|
||||
(
|
||||
"issues",
|
||||
[
|
||||
Issue(
|
||||
id="abc123",
|
||||
identifier="TST-123",
|
||||
title="Test issue",
|
||||
description="Test description",
|
||||
priority=1,
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
test_mock={
|
||||
"get_project_issues": lambda *args, **kwargs: [
|
||||
Issue(
|
||||
id="abc123",
|
||||
identifier="TST-123",
|
||||
title="Test issue",
|
||||
description="Test description",
|
||||
priority=1,
|
||||
)
|
||||
]
|
||||
},
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
async def get_project_issues(
|
||||
credentials: OAuth2Credentials | APIKeyCredentials,
|
||||
project: str,
|
||||
status: str,
|
||||
is_assigned: bool,
|
||||
include_comments: bool,
|
||||
) -> list[Issue]:
|
||||
client = LinearClient(credentials=credentials)
|
||||
response: list[Issue] = await client.try_get_issues(
|
||||
project=project,
|
||||
status=status,
|
||||
is_assigned=is_assigned,
|
||||
include_comments=include_comments,
|
||||
)
|
||||
return response
|
||||
|
||||
async def run(
|
||||
self,
|
||||
input_data: Input,
|
||||
*,
|
||||
credentials: OAuth2Credentials | APIKeyCredentials,
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
"""Execute getting project issues"""
|
||||
issues = await self.get_project_issues(
|
||||
credentials=credentials,
|
||||
project=input_data.project,
|
||||
status=input_data.status,
|
||||
is_assigned=input_data.is_assigned,
|
||||
include_comments=input_data.include_comments,
|
||||
)
|
||||
yield "issues", issues
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
from backend.sdk import BaseModel
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
|
||||
|
||||
class Comment(BaseModel):
|
||||
id: str
|
||||
body: str
|
||||
createdAt: str | None = None
|
||||
user: User | None = None
|
||||
|
||||
|
||||
class CreateCommentInput(BaseModel):
|
||||
@@ -20,22 +27,26 @@ class CreateCommentResponseWrapper(BaseModel):
|
||||
commentCreate: CreateCommentResponse
|
||||
|
||||
|
||||
class Project(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
description: str | None = None
|
||||
priority: int | None = None
|
||||
progress: float | None = None
|
||||
content: str | None = None
|
||||
|
||||
|
||||
class Issue(BaseModel):
|
||||
id: str
|
||||
identifier: str
|
||||
title: str
|
||||
description: str | None
|
||||
priority: int
|
||||
project: Project | None = None
|
||||
createdAt: str | None = None
|
||||
comments: list[Comment] | None = None
|
||||
assignee: User | None = None
|
||||
|
||||
|
||||
class CreateIssueResponse(BaseModel):
|
||||
issue: Issue
|
||||
|
||||
|
||||
class Project(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
description: str
|
||||
priority: int
|
||||
progress: float
|
||||
content: str | None
|
||||
|
||||
Reference in New Issue
Block a user