Jira toolkit: deduplicate cloud data in Atlassian's available-resources response (#456)
This commit is contained in:
parent
67bc53c8ce
commit
352079151e
3 changed files with 89 additions and 11 deletions
|
|
@ -56,26 +56,29 @@ class JiraClient:
|
|||
headers={"Authorization": f"Bearer {self.auth_token}"},
|
||||
)
|
||||
|
||||
data = response.json()
|
||||
available_resources = deduplicate_available_resources(response.json())
|
||||
|
||||
if len(data) == 0:
|
||||
if len(available_resources) == 0:
|
||||
raise JiraToolExecutionError(
|
||||
message="No cloud ID returned by Atlassian, cannot make API calls"
|
||||
)
|
||||
if len(data) > 1:
|
||||
if len(available_resources) > 1:
|
||||
cloud_ids_found = json.dumps([
|
||||
{
|
||||
"id": item["id"],
|
||||
"name": item["name"],
|
||||
"url": item["url"],
|
||||
"id": resource["id"],
|
||||
"name": resource["name"],
|
||||
"url": resource["url"],
|
||||
}
|
||||
for item in data
|
||||
for resource in available_resources
|
||||
])
|
||||
raise JiraToolExecutionError(
|
||||
message=f"Multiple cloud IDs returned by Atlassian: {cloud_ids_found}. "
|
||||
"Cannot resolve which one to use."
|
||||
message=(
|
||||
"Multiple cloud IDs returned by Atlassian, cannot resolve which one "
|
||||
"to use. Please revoke your authorization access and authorize a single "
|
||||
f"Atlassian Cloud. Available cloud IDs: {cloud_ids_found}. "
|
||||
)
|
||||
)
|
||||
return cast(dict[str, Any], data[0])
|
||||
return cast(dict[str, Any], available_resources[0])
|
||||
|
||||
def _build_error_messages(self, response: httpx.Response) -> tuple[str, str | None]:
|
||||
try:
|
||||
|
|
@ -224,3 +227,15 @@ class JiraClient:
|
|||
self._raise_for_status(response)
|
||||
|
||||
return self._format_response_dict(response)
|
||||
|
||||
|
||||
def deduplicate_available_resources(available_resources: list[dict]) -> list[dict]:
|
||||
account_ids_seen = set()
|
||||
deduplicated = []
|
||||
|
||||
for item in available_resources:
|
||||
if item["id"] not in account_ids_seen:
|
||||
deduplicated.append(item)
|
||||
account_ids_seen.add(item["id"])
|
||||
|
||||
return deduplicated
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|||
|
||||
[project]
|
||||
name = "arcade_jira"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
description = "Arcade.dev LLM tools for interacting with Atlassian Jira"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
|
|
|
|||
63
toolkits/jira/tests/test_client.py
Normal file
63
toolkits/jira/tests/test_client.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import json
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from arcade_jira.client import JiraClient
|
||||
from arcade_jira.exceptions import JiraToolExecutionError
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_cloud_data_from_available_resources_single_cloud(
|
||||
mock_httpx_client, fake_auth_token
|
||||
):
|
||||
cloud = {"id": "123", "name": "Test Cloud", "url": "https://test.atlassian.net"}
|
||||
|
||||
client = JiraClient(auth_token=fake_auth_token)
|
||||
|
||||
mock_httpx_client.get.return_value = httpx.Response(
|
||||
status_code=200,
|
||||
json=[cloud],
|
||||
)
|
||||
|
||||
response = await client._get_cloud_data_from_available_resources()
|
||||
assert response == cloud
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_cloud_data_from_available_resources_multiple_clouds(
|
||||
mock_httpx_client, fake_auth_token
|
||||
):
|
||||
cloud1 = {"id": "123", "name": "Test Cloud", "url": "https://test.atlassian.net"}
|
||||
cloud2 = {"id": "456", "name": "Test Cloud 2", "url": "https://test2.atlassian.net"}
|
||||
|
||||
client = JiraClient(auth_token=fake_auth_token)
|
||||
|
||||
mock_httpx_client.get.return_value = httpx.Response(
|
||||
status_code=200,
|
||||
json=[cloud1, cloud2],
|
||||
)
|
||||
|
||||
with pytest.raises(JiraToolExecutionError) as error:
|
||||
await client._get_cloud_data_from_available_resources()
|
||||
|
||||
assert "Multiple cloud IDs returned by Atlassian" in error.value.message
|
||||
assert json.dumps(cloud1) in error.value.message
|
||||
assert json.dumps(cloud2) in error.value.message
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_cloud_data_from_available_resources_duplicate_cloud(
|
||||
mock_httpx_client, fake_auth_token
|
||||
):
|
||||
cloud = {"id": "123", "name": "Test Cloud", "url": "https://test.atlassian.net"}
|
||||
|
||||
client = JiraClient(auth_token=fake_auth_token)
|
||||
|
||||
mock_httpx_client.get.return_value = httpx.Response(
|
||||
status_code=200,
|
||||
json=[cloud, cloud],
|
||||
)
|
||||
|
||||
response = await client._get_cloud_data_from_available_resources()
|
||||
assert response == cloud
|
||||
Loading…
Reference in a new issue