Skip to content

Commit 3b092f3

Browse files
authored
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
1 parent 0921d23 commit 3b092f3

File tree

3 files changed

+188
-9
lines changed

3 files changed

+188
-9
lines changed

โ€Žautogpt_platform/backend/backend/blocks/linear/_api.pyโ€Ž

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,68 @@ async def try_search_issues(self, term: str) -> list[Issue]:
265265
return [Issue(**issue) for issue in issues["searchIssues"]["nodes"]]
266266
except LinearAPIException as e:
267267
raise e
268+
269+
async def try_get_issues(
270+
self, project: str, status: str, is_assigned: bool, include_comments: bool
271+
) -> list[Issue]:
272+
try:
273+
query = """
274+
query IssuesByProjectStatusAndAssignee(
275+
$projectName: String!
276+
$statusName: String!
277+
$isAssigned: Boolean!
278+
$includeComments: Boolean! = false
279+
) {
280+
issues(
281+
filter: {
282+
project: { name: { eq: $projectName } }
283+
state: { name: { eq: $statusName } }
284+
assignee: { null: $isAssigned }
285+
}
286+
) {
287+
nodes {
288+
id
289+
title
290+
identifier
291+
description
292+
createdAt
293+
priority
294+
assignee {
295+
id
296+
name
297+
}
298+
project {
299+
id
300+
name
301+
}
302+
state {
303+
id
304+
name
305+
}
306+
comments @include(if: $includeComments) {
307+
nodes {
308+
id
309+
body
310+
createdAt
311+
user {
312+
id
313+
name
314+
}
315+
}
316+
}
317+
}
318+
}
319+
}
320+
"""
321+
322+
variables: dict[str, Any] = {
323+
"projectName": project,
324+
"statusName": status,
325+
"isAssigned": not is_assigned,
326+
"includeComments": include_comments,
327+
}
328+
329+
issues = await self.query(query, variables)
330+
return [Issue(**issue) for issue in issues["issues"]["nodes"]]
331+
except LinearAPIException as e:
332+
raise e

โ€Žautogpt_platform/backend/backend/blocks/linear/issues.pyโ€Ž

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,106 @@ async def run(
203203
yield "error", str(e)
204204
except Exception as e:
205205
yield "error", f"Unexpected error: {str(e)}"
206+
207+
208+
class LinearGetProjectIssuesBlock(Block):
209+
"""Block for getting issues from a Linear project filtered by status and assignee"""
210+
211+
class Input(BlockSchemaInput):
212+
credentials: CredentialsMetaInput = linear.credentials_field(
213+
description="Linear credentials with read permissions",
214+
required_scopes={LinearScope.READ},
215+
)
216+
project: str = SchemaField(description="Name of the project to get issues from")
217+
status: str = SchemaField(
218+
description="Status/state name to filter issues by (e.g., 'In Progress', 'Done')"
219+
)
220+
is_assigned: bool = SchemaField(
221+
description="Filter by assignee status - True to get assigned issues, False to get unassigned issues",
222+
default=False,
223+
)
224+
include_comments: bool = SchemaField(
225+
description="Whether to include comments in the response",
226+
default=False,
227+
)
228+
229+
class Output(BlockSchemaOutput):
230+
issues: list[Issue] = SchemaField(
231+
description="List of issues matching the criteria"
232+
)
233+
234+
def __init__(self):
235+
super().__init__(
236+
id="c7d3f1e8-45a9-4b2c-9f81-3e6a8d7c5b1a",
237+
description="Gets issues from a Linear project filtered by status and assignee",
238+
input_schema=self.Input,
239+
output_schema=self.Output,
240+
categories={BlockCategory.PRODUCTIVITY, BlockCategory.ISSUE_TRACKING},
241+
test_input={
242+
"project": "Test Project",
243+
"status": "In Progress",
244+
"is_assigned": False,
245+
"include_comments": False,
246+
"credentials": TEST_CREDENTIALS_INPUT_OAUTH,
247+
},
248+
test_credentials=TEST_CREDENTIALS_OAUTH,
249+
test_output=[
250+
(
251+
"issues",
252+
[
253+
Issue(
254+
id="abc123",
255+
identifier="TST-123",
256+
title="Test issue",
257+
description="Test description",
258+
priority=1,
259+
)
260+
],
261+
),
262+
],
263+
test_mock={
264+
"get_project_issues": lambda *args, **kwargs: [
265+
Issue(
266+
id="abc123",
267+
identifier="TST-123",
268+
title="Test issue",
269+
description="Test description",
270+
priority=1,
271+
)
272+
]
273+
},
274+
)
275+
276+
@staticmethod
277+
async def get_project_issues(
278+
credentials: OAuth2Credentials | APIKeyCredentials,
279+
project: str,
280+
status: str,
281+
is_assigned: bool,
282+
include_comments: bool,
283+
) -> list[Issue]:
284+
client = LinearClient(credentials=credentials)
285+
response: list[Issue] = await client.try_get_issues(
286+
project=project,
287+
status=status,
288+
is_assigned=is_assigned,
289+
include_comments=include_comments,
290+
)
291+
return response
292+
293+
async def run(
294+
self,
295+
input_data: Input,
296+
*,
297+
credentials: OAuth2Credentials | APIKeyCredentials,
298+
**kwargs,
299+
) -> BlockOutput:
300+
"""Execute getting project issues"""
301+
issues = await self.get_project_issues(
302+
credentials=credentials,
303+
project=input_data.project,
304+
status=input_data.status,
305+
is_assigned=input_data.is_assigned,
306+
include_comments=input_data.include_comments,
307+
)
308+
yield "issues", issues

โ€Žautogpt_platform/backend/backend/blocks/linear/models.pyโ€Ž

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
from backend.sdk import BaseModel
22

33

4+
class User(BaseModel):
5+
id: str
6+
name: str
7+
8+
49
class Comment(BaseModel):
510
id: str
611
body: str
12+
createdAt: str | None = None
13+
user: User | None = None
714

815

916
class CreateCommentInput(BaseModel):
@@ -20,22 +27,26 @@ class CreateCommentResponseWrapper(BaseModel):
2027
commentCreate: CreateCommentResponse
2128

2229

30+
class Project(BaseModel):
31+
id: str
32+
name: str
33+
description: str | None = None
34+
priority: int | None = None
35+
progress: float | None = None
36+
content: str | None = None
37+
38+
2339
class Issue(BaseModel):
2440
id: str
2541
identifier: str
2642
title: str
2743
description: str | None
2844
priority: int
45+
project: Project | None = None
46+
createdAt: str | None = None
47+
comments: list[Comment] | None = None
48+
assignee: User | None = None
2949

3050

3151
class CreateIssueResponse(BaseModel):
3252
issue: Issue
33-
34-
35-
class Project(BaseModel):
36-
id: str
37-
name: str
38-
description: str
39-
priority: int
40-
progress: float
41-
content: str | None

0 commit comments

Comments
ย (0)