mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-11 03:12:55 +00:00
Keep a Linear sync going when one issue or document cannot be read
An issue deleted after it was listed, or comments the token cannot read, now lose that detail with a warning instead of failing the whole sync; an unreadable document is skipped.
This commit is contained in:
1 parent
06de211e61
commit
f2349edb4c
2 files changed
+60
-8
No files matched your search
@@ -19,7 +19,7 @@ import re
|
||||
from typing import Any, Optional
|
||||
|
||||
from docsgpt.connectors import linear
|
||||
from docsgpt.connectors.mcp import run_connection_session
|
||||
from docsgpt.connectors.mcp import MCPToolError, run_connection_session
|
||||
from docsgpt.parser.remote.base import BaseRemote
|
||||
from docsgpt.parser.schema.base import Document
|
||||
|
||||
@@ -90,9 +90,19 @@ class LinearLoader(BaseRemote):
|
||||
issues.setdefault(key, issue)
|
||||
documents = []
|
||||
for key, issue in issues.items():
|
||||
# One issue Linear will not read (deleted since it was listed, or
|
||||
# out of the token's reach) loses that detail, not the whole sync.
|
||||
if linear.is_truncated(issue.get("description")) or issue.get("descriptionTruncated"):
|
||||
issue = await self._full_issue(session, key, issue)
|
||||
comments = await self._comments(session, key) if selection["include_comments"] else []
|
||||
try:
|
||||
issue = await self._full_issue(session, key, issue)
|
||||
except MCPToolError as exc:
|
||||
logger.warning("Linear sync keeps %s as listed: %s", key, exc)
|
||||
comments = []
|
||||
if selection["include_comments"]:
|
||||
try:
|
||||
comments = await self._comments(session, key)
|
||||
except MCPToolError as exc:
|
||||
logger.warning("Linear sync leaves out the comments of %s: %s", key, exc)
|
||||
documents.append(self._issue_document(issue, comments, selection))
|
||||
if selection["include_documents"]:
|
||||
documents.extend(await self._project_documents(session, selection["projects"]))
|
||||
@@ -179,11 +189,16 @@ class LinearLoader(BaseRemote):
|
||||
):
|
||||
content = record.get("content")
|
||||
if (not content or linear.is_truncated(content)) and get_schema is not None and record.get("id"):
|
||||
full = linear.unwrap(
|
||||
await session.call("get_document", {linear.argument(get_schema, "id", "documentId"):
|
||||
str(record["id"])}),
|
||||
"document",
|
||||
)
|
||||
try:
|
||||
full = linear.unwrap(
|
||||
await session.call("get_document", {linear.argument(get_schema, "id", "documentId"):
|
||||
str(record["id"])}),
|
||||
"document",
|
||||
)
|
||||
except MCPToolError as exc:
|
||||
# A document that cannot be read is skipped, not the sync.
|
||||
logger.warning("Linear sync skips document %s: %s", record.get("id"), exc)
|
||||
continue
|
||||
record = {**record, **{k: v for k, v in full.items() if v not in (None, "")}}
|
||||
document = self._linear_document(record, project)
|
||||
path = document.extra_info["file_path"]
|
||||
|
||||
@@ -288,3 +288,40 @@ class TestLoadData:
|
||||
def test_needs_a_connection(self):
|
||||
with pytest.raises(ValueError):
|
||||
LinearLoader().load_data({"teams": ["t1"]})
|
||||
|
||||
|
||||
class TestOneBadItemDoesNotStopTheSync:
|
||||
"""An issue deleted since it was listed, or comments the token cannot
|
||||
read, lose that detail; the rest of the sync still lands."""
|
||||
|
||||
@staticmethod
|
||||
def _refuse(args):
|
||||
from docsgpt.connectors.mcp import MCPToolError
|
||||
|
||||
raise MCPToolError("Entity not found")
|
||||
|
||||
def test_an_issue_that_cannot_be_read_in_full_keeps_what_was_listed(self):
|
||||
clipped = {**ISSUE, "description": "The spinner (truncated, use get_issue to read the full description)"}
|
||||
session = FakeLinear({
|
||||
"list_issues": lambda args: {"issues": [clipped, {**ISSUE, "id": "ENG-2", "title": "Other"}]},
|
||||
"get_issue": self._refuse,
|
||||
})
|
||||
docs = _collect(session, teams=["team-1"], include_comments=False)
|
||||
assert [d.text.splitlines()[0] for d in docs] == ["# ENG-1310: Fix the loader", "# ENG-2: Other"]
|
||||
|
||||
def test_comments_that_cannot_be_read_are_left_out(self):
|
||||
session = FakeLinear({"list_issues": lambda args: [ISSUE], "list_comments": self._refuse})
|
||||
[doc] = _collect(session, teams=["team-1"])
|
||||
assert "## Comments" not in doc.text
|
||||
|
||||
def test_a_document_that_cannot_be_read_is_skipped(self):
|
||||
session = FakeLinear({
|
||||
"list_issues": lambda args: {"issues": []},
|
||||
"list_documents": lambda args: {"documents": [
|
||||
{"id": "d1", "title": "Gone"},
|
||||
{"id": "d2", "title": "Plan", "content": "We ship on Monday."},
|
||||
]},
|
||||
"get_document": self._refuse,
|
||||
})
|
||||
docs = _collect(session, projects=[{"id": "project-1", "name": "Acme"}], include_documents=True)
|
||||
assert [d.text.splitlines()[0] for d in docs] == ["# Plan"]
|
||||
Reference in new issue
Block a user