Jira toolkit: deduplicate cloud data in Atlassian's available-resources response (#456)

This commit is contained in:
Renato Byrro 2025-06-24 12:39:16 -03:00 committed by GitHub
parent 67bc53c8ce
commit 352079151e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 89 additions and 11 deletions

View file

@ -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

View file

@ -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 = [

View 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