Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 32 additions & 12 deletions backend/onyx/connectors/onyx_jira/connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@
_JIRA_SLIM_PAGE_SIZE = 500
_JIRA_FULL_PAGE_SIZE = 50

# Constants for Jira field names
_FIELD_REPORTER = "reporter"
_FIELD_ASSIGNEE = "assignee"
_FIELD_PRIORITY = "priority"
_FIELD_STATUS = "status"
_FIELD_RESOLUTION = "resolution"
_FIELD_LABELS = "labels"
_FIELD_KEY = "key"
_FIELD_CREATED = "created"
_FIELD_DUEDATE = "duedate"
_FIELD_ISSUETYPE = "issuetype"


def _perform_jql_search(
jira_client: JIRA,
Expand Down Expand Up @@ -107,32 +119,40 @@ def process_jira_issue(

page_url = build_jira_url(jira_client, issue.key)

metadata_dict: dict[str, str | list[str]] = {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: metadata_dict type annotation allows both str and list[str], but some fields like created and duedate could be datetime objects

people = set()
try:
creator = best_effort_get_field_from_issue(issue, "creator")
creator = best_effort_get_field_from_issue(issue, _FIELD_REPORTER)
if basic_expert_info := best_effort_basic_expert_info(creator):
people.add(basic_expert_info)
metadata_dict[_FIELD_REPORTER] = basic_expert_info.get_semantic_name()
except Exception:
# Author should exist but if not, doesn't matter
pass

try:
assignee = best_effort_get_field_from_issue(issue, "assignee")
assignee = best_effort_get_field_from_issue(issue, _FIELD_ASSIGNEE)
if basic_expert_info := best_effort_basic_expert_info(assignee):
people.add(basic_expert_info)
metadata_dict[_FIELD_ASSIGNEE] = basic_expert_info.get_semantic_name()
except Exception:
# Author should exist but if not, doesn't matter
pass

metadata_dict = {}
if priority := best_effort_get_field_from_issue(issue, "priority"):
metadata_dict["priority"] = priority.name
if status := best_effort_get_field_from_issue(issue, "status"):
metadata_dict["status"] = status.name
if resolution := best_effort_get_field_from_issue(issue, "resolution"):
metadata_dict["resolution"] = resolution.name
if labels := best_effort_get_field_from_issue(issue, "labels"):
metadata_dict["labels"] = labels
if priority := best_effort_get_field_from_issue(issue, _FIELD_PRIORITY):
metadata_dict[_FIELD_PRIORITY] = priority.name
if status := best_effort_get_field_from_issue(issue, _FIELD_STATUS):
metadata_dict[_FIELD_STATUS] = status.name
if resolution := best_effort_get_field_from_issue(issue, _FIELD_RESOLUTION):
metadata_dict[_FIELD_RESOLUTION] = resolution.name
if labels := best_effort_get_field_from_issue(issue, _FIELD_LABELS):
metadata_dict[_FIELD_LABELS] = labels
if created := best_effort_get_field_from_issue(issue, _FIELD_CREATED):
metadata_dict[_FIELD_CREATED] = created
if duedate := best_effort_get_field_from_issue(issue, _FIELD_DUEDATE):
metadata_dict[_FIELD_DUEDATE] = duedate
if issuetype := best_effort_get_field_from_issue(issue, _FIELD_ISSUETYPE):
metadata_dict[_FIELD_ISSUETYPE] = issuetype.name

return Document(
id=page_url,
Expand Down Expand Up @@ -277,7 +297,7 @@ def retrieve_all_slim_documents(
max_results=_JIRA_SLIM_PAGE_SIZE,
fields="key",
):
issue_key = best_effort_get_field_from_issue(issue, "key")
issue_key = best_effort_get_field_from_issue(issue, _FIELD_KEY)
id = build_jira_url(self.jira_client, issue_key)
slim_doc_batch.append(
SlimDocument(
Expand Down
4 changes: 2 additions & 2 deletions backend/onyx/connectors/onyx_jira/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
def best_effort_basic_expert_info(obj: Any) -> BasicExpertInfo | None:
display_name = None
email = None
if hasattr(obj, "display_name"):
display_name = obj.display_name
if hasattr(obj, "displayName"):
display_name = obj.displayName
Comment on lines +26 to +27
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Inconsistent fallback - line 29 uses get('displayName') but line 27 uses direct attribute access which could raise AttributeError

else:
display_name = obj.get("displayName")

Expand Down
72 changes: 57 additions & 15 deletions backend/tests/daily/connectors/jira/test_jira_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import pytest

from onyx.configs.constants import DocumentSource
from onyx.connectors.models import Document
from onyx.connectors.onyx_jira.connector import JiraConnector
from tests.daily.connectors.utils import load_all_docs_from_checkpoint_connector

Expand All @@ -30,19 +31,60 @@ def test_jira_connector_basic(jira_connector: JiraConnector) -> None:
start=0,
end=time.time(),
)
assert len(docs) == 1
doc = docs[0]

assert doc.id == "https://danswerai.atlassian.net/browse/AS-2"
assert doc.semantic_identifier == "AS-2: test123small"
assert doc.source == DocumentSource.JIRA
assert doc.metadata == {"priority": "Medium", "status": "Backlog"}
assert doc.secondary_owners is None
assert doc.title == "AS-2 test123small"
assert doc.from_ingestion_api is False
assert doc.additional_info is None

assert len(doc.sections) == 1
section = doc.sections[0]
assert len(docs) == 2

# Find story and epic
story: Document | None = None
epic: Document | None = None
for doc in docs:
if doc.metadata["issuetype"] == "Story":
story = doc
elif doc.metadata["issuetype"] == "Epic":
epic = doc

assert story is not None
assert epic is not None

# Check task
assert story.id == "https://danswerai.atlassian.net/browse/AS-3"
assert story.semantic_identifier == "AS-3: test123small"
assert story.source == DocumentSource.JIRA
assert story.metadata == {
"priority": "Medium",
"status": "Backlog",
"reporter": "Chris Weaver",
"assignee": "Chris Weaver",
"issuetype": "Story",
"created": "2025-04-16T16:44:06.716-0700",
}
assert story.secondary_owners is None
assert story.title == "AS-3 test123small"
assert story.from_ingestion_api is False
assert story.additional_info is None

assert len(story.sections) == 1
section = story.sections[0]
assert section.text == "example_text\n"
assert section.link == "https://danswerai.atlassian.net/browse/AS-3"

# Check epic
assert epic.id == "https://danswerai.atlassian.net/browse/AS-4"
assert epic.semantic_identifier == "AS-4: EPIC"
assert epic.source == DocumentSource.JIRA
assert epic.metadata == {
"priority": "Medium",
"status": "Backlog",
"reporter": "Founder Onyx",
"assignee": "Chris Weaver",
"issuetype": "Epic",
"created": "2025-04-16T16:55:53.068-0700",
}
assert epic.secondary_owners is None
assert epic.title == "AS-4 EPIC"
assert epic.from_ingestion_api is False
assert epic.additional_info is None

assert len(epic.sections) == 1
section = epic.sections[0]
assert section.text == "example_text\n"
assert section.link == "https://danswerai.atlassian.net/browse/AS-2"
assert section.link == "https://danswerai.atlassian.net/browse/AS-4"
Loading