From 7ccaf6241d5bb2332cd7cd624cbf9018824d91cd Mon Sep 17 00:00:00 2001 From: LuisFigueroaG Date: Wed, 28 Oct 2026 17:28:11 -0300 Subject: [PATCH] [Confluence] ConfluenceCloud: fix get_content_ancestors Cloud.get_content_ancestors requests /wiki/rest/api/content/{id}/ancestors, but the v1 content API has no such endpoint, so the call always fails with a 404. Ancestors are only available on the content itself through expand=ancestors. Request /wiki/rest/api/content/{id}?expand=ancestors instead and return the ancestors list, like the Server get_page_ancestors does. Extra params passed by the caller are kept. --- atlassian/confluence/cloud/__init__.py | 12 ++++++++++-- tests/confluence/test_confluence_cloud.py | 24 ++++++++++++++++++++--- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/atlassian/confluence/cloud/__init__.py b/atlassian/confluence/cloud/__init__.py index 5a72a9fc3..aa8c78922 100644 --- a/atlassian/confluence/cloud/__init__.py +++ b/atlassian/confluence/cloud/__init__.py @@ -228,8 +228,16 @@ def get_descendant_pages(self, content_id, **kwargs): return self.get(f"rest/api/content/{content_id}/descendant/page", **kwargs) def get_content_ancestors(self, content_id, **kwargs): - """Get ancestor content.""" - return self.get(f"rest/api/content/{content_id}/ancestors", **kwargs) + """Get ancestor content. + + The v1 content API has no ancestors endpoint, so the ancestors are read + from the content itself with ``expand=ancestors``. + + :return: list of ancestors, from the top-level page down to the parent + """ + params = {**(kwargs.pop("params", None) or {}), "expand": "ancestors"} + content = self.get(f"rest/api/content/{content_id}", params=params, **kwargs) + return (content or {}).get("ancestors", []) def get_page_by_title(self, space_key, title, **kwargs): """Get page by title and space key.""" diff --git a/tests/confluence/test_confluence_cloud.py b/tests/confluence/test_confluence_cloud.py index 4fed088f0..ce600496e 100644 --- a/tests/confluence/test_confluence_cloud.py +++ b/tests/confluence/test_confluence_cloud.py @@ -564,10 +564,28 @@ def test_get_content_descendants(self, mock_get, confluence_cloud): @patch.object(ConfluenceCloud, "get") def test_get_content_ancestors(self, mock_get, confluence_cloud): """Test get_content_ancestors method.""" - mock_get.return_value = {"results": [{"id": "111", "title": "Ancestor Page"}]} + mock_get.return_value = {"id": "123", "ancestors": [{"id": "111", "title": "Ancestor Page"}]} result = confluence_cloud.get_content_ancestors("123") - mock_get.assert_called_once_with("rest/api/content/123/ancestors", **{}) - assert result == {"results": [{"id": "111", "title": "Ancestor Page"}]} + mock_get.assert_called_once_with("rest/api/content/123", params={"expand": "ancestors"}) + assert result == [{"id": "111", "title": "Ancestor Page"}] + + @patch.object(ConfluenceCloud, "get") + def test_get_content_ancestors_keeps_extra_params(self, mock_get, confluence_cloud): + mock_get.return_value = {"id": "123", "ancestors": []} + + assert confluence_cloud.get_content_ancestors("123", params={"status": "draft"}) == [] + mock_get.assert_called_once_with("rest/api/content/123", params={"status": "draft", "expand": "ancestors"}) + + def test_get_content_ancestors_requests_wiki_content_endpoint(self, confluence_cloud): + response = Response() + response.status_code = 200 + response._content = b'{"id": "123", "ancestors": [{"id": "111"}, {"id": "112"}]}' + + with patch.object(confluence_cloud._session, "request", return_value=response) as mock_request: + assert confluence_cloud.get_content_ancestors("123") == [{"id": "111"}, {"id": "112"}] + + url = mock_request.call_args.kwargs["url"] + assert url == "https://test.atlassian.net/wiki/rest/api/content/123?expand=ancestors" # Space Management Tests @patch.object(ConfluenceCloud, "get")