diff --git a/atlassian/confluence/__init__.py b/atlassian/confluence/__init__.py
index 5ac9fb324..e26099383 100644
--- a/atlassian/confluence/__init__.py
+++ b/atlassian/confluence/__init__.py
@@ -25,9 +25,12 @@ def __init__(self, url, *args, **kwargs):
if is_cloud is None:
hostname = urlparse(url).hostname or ""
is_cloud = (
- hostname == "atlassian.net" or hostname.endswith(".atlassian.net")
- or hostname == "jira.com" or hostname.endswith(".jira.com")
- or hostname == "api.atlassian.com" or hostname.endswith(".api.atlassian.com")
+ hostname == "atlassian.net"
+ or hostname.endswith(".atlassian.net")
+ or hostname == "jira.com"
+ or hostname.endswith(".jira.com")
+ or hostname == "api.atlassian.com"
+ or hostname.endswith(".api.atlassian.com")
)
if is_cloud:
impl = ConfluenceCloud(url, *args, **kwargs)
diff --git a/atlassian/confluence/cloud/base.py b/atlassian/confluence/cloud/base.py
index ec2a081b0..f90f43f5f 100644
--- a/atlassian/confluence/cloud/base.py
+++ b/atlassian/confluence/cloud/base.py
@@ -23,5 +23,3 @@ def __init__(self, url, *args, **kwargs):
:return: nothing
"""
super(ConfluenceCloudBase, self).__init__(url, *args, **kwargs)
-
-
diff --git a/atlassian/confluence/server/__init__.py b/atlassian/confluence/server/__init__.py
index 50ccc9978..65199e083 100644
--- a/atlassian/confluence/server/__init__.py
+++ b/atlassian/confluence/server/__init__.py
@@ -297,7 +297,9 @@ def get_all_draft_pages_from_space(self, space_key, **kwargs):
def get_all_draft_blog_posts_from_space(self, space_key, **kwargs):
"""Get all draft blog posts from space."""
- return self._get_paged("content", params={"spaceKey": space_key, "type": "blogpost", "status": "draft", **kwargs})
+ return self._get_paged(
+ "content", params={"spaceKey": space_key, "type": "blogpost", "status": "draft", **kwargs}
+ )
# Trash Management
def get_trash_content(self, space_key, **kwargs):
@@ -310,7 +312,9 @@ def get_all_pages_from_space_trash(self, space_key, **kwargs):
def get_all_blog_posts_from_space_trash(self, space_key, **kwargs):
"""Get all blog posts from space trash."""
- return self._get_paged("content", params={"spaceKey": space_key, "type": "blogpost", "status": "trashed", **kwargs})
+ return self._get_paged(
+ "content", params={"spaceKey": space_key, "type": "blogpost", "status": "trashed", **kwargs}
+ )
# Export
def export_content(self, content_id, **kwargs):
diff --git a/atlassian/confluence/server/base.py b/atlassian/confluence/server/base.py
index f7451db93..0bfd53963 100644
--- a/atlassian/confluence/server/base.py
+++ b/atlassian/confluence/server/base.py
@@ -23,5 +23,3 @@ def __init__(self, url, *args, **kwargs):
:return: nothing
"""
super(ConfluenceServerBase, self).__init__(url, *args, **kwargs)
-
-
diff --git a/atlassian/jira.py b/atlassian/jira.py
index 454c57da7..6dad5c309 100644
--- a/atlassian/jira.py
+++ b/atlassian/jira.py
@@ -1457,6 +1457,40 @@ def get_issue_changelog(self, issue_key: str, start: Optional[int] = None, limit
url = f"{base_url}/{issue_key}?expand=changelog"
return self._get_response_content(url, fields=[("changelog", params)])
+ def get_changelogs_bulk(
+ self,
+ issue_ids_or_keys: List[str],
+ fields_by: Optional[str] = None,
+ next_page_token: Optional[str] = None,
+ max_results: Optional[int] = None,
+ ) -> T_resp_json:
+ """
+ Returns changelogs for multiple issues in bulk.
+ Only Jira Cloud platform.
+
+ Reference: https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-changelog-bulkfetch-post
+
+ :param issue_ids_or_keys: List of issue IDs or keys to fetch changelogs for. Required.
+ :param fields_by: OPTIONAL: Whether to filter changelog entries by field ID or field name.
+ Valid values: "id", "name".
+ :param next_page_token: OPTIONAL: Token for the next page of results (pagination).
+ :param max_results: OPTIONAL: Maximum number of results to return.
+ :return: Paginated list of changelogs for the given issues.
+ """
+ if not self.cloud:
+ raise ValueError("``get_changelogs_bulk`` method is only available for Jira Cloud platform")
+ url = self.resource_url("changelog/bulkfetch", api_version=3)
+ data: dict = {"issueIdsOrKeys": issue_ids_or_keys}
+ if fields_by is not None:
+ if fields_by not in ("id", "name"):
+ raise ValueError("``fields_by`` must be either 'id' or 'name'")
+ data["fieldsByKeys"] = fields_by == "name"
+ if next_page_token is not None:
+ data["nextPageToken"] = next_page_token
+ if max_results is not None:
+ data["maxResults"] = int(max_results)
+ return self.post(url, data=data)
+
def issue_add_json_worklog(self, key: str, worklog: Union[dict, str]):
"""
diff --git a/atlassian/utils.py b/atlassian/utils.py
index 631d0111d..24a479993 100644
--- a/atlassian/utils.py
+++ b/atlassian/utils.py
@@ -213,12 +213,14 @@ def block_code_macro_confluence(code, lang=None):
"""
if not lang:
lang = ""
- return ("""\
+ return (
+ """\
| Project Key | Project Name | Leader | {project_name} | {lead_name} | {lead_email} | - """.format(**data) + """.format( + **data + ) html += "
|---|