diff --git a/README.rst b/README.rst index 5f2237a46..25a851766 100644 --- a/README.rst +++ b/README.rst @@ -78,6 +78,23 @@ And here's another example of how to get issues from Jira using JQL Query: data = jira.jql(JQL) print(data) +The traditional jql method is deprecated for Jira Cloud users, as Atlassian has transitioned to a nextPageToken-based pagination approach instead of startAt. Use enhanced_jql for improved performance and future compatibility. + +.. code-block:: python + + from atlassian import Jira + + jira = Jira( + url='https://your-jira-instance.atlassian.net', + username='your-email@example.com', + password='your-api-token', + cloud=True # Ensure this is set to True for Jira Cloud + ) + JQL = 'project = DEMO AND status IN ("To Do", "In Progress") ORDER BY issuekey' + # Fetch issues using the new enhanced_jql method + data = jira.enhanced_jql(JQL) + print(data) + Also, you can use the Bitbucket module e.g. for getting project list .. code-block:: python diff --git a/atlassian/jira.py b/atlassian/jira.py index d49846139..6c9180605 100644 --- a/atlassian/jira.py +++ b/atlassian/jira.py @@ -3397,6 +3397,19 @@ def jql( :param validate_query: OPTIONAL: Whether to validate the JQL query :return: """ + if self.cloud: + if start==0: + return self.enhanced_jql( + jql=jql, + fields=fields, + limit=limit, + expand=expand, + ) + else: + raise ValueError( + "The `jql` method is deprecated in Jira Cloud. Use `enhanced_jql` method instead." + ) + params = {} if start is not None: params["startAt"] = int(start) @@ -3415,6 +3428,64 @@ def jql( url = self.resource_url("search") return self.get(url, params=params) + def enhanced_jql( + self, + jql, + fields="*all", + nextPageToken=None, + limit=None, + expand=None, + ): + """ + Get issues from jql search result with all related fields + :param jql: + :param fields: list of fields, for example: ['priority', 'summary', 'customfield_10007'] + :param nextPageToken (Optional[str]): Token for paginated results. Default: None. + :param limit: OPTIONAL: The limit of the number of issues to return, this may be restricted by + fixed system limits. Default by built-in method: 50 + :param expand: OPTIONAL: expand the search result + :return: + """ + + if not self.cloud: + raise ValueError("``enhanced_jql`` method is only available for Jira Cloud platform") + + params = {} + if nextPageToken is not None: + params["nextPageToken"] = str(nextPageToken) + if limit is not None: + params["maxResults"] = int(limit) + if fields is not None: + if isinstance(fields, (list, tuple, set)): + fields = ",".join(fields) + params["fields"] = fields + if jql is not None: + params["jql"] = jql + if expand is not None: + params["expand"] = expand + + url = self.resource_url("search/jql") + return self.get(url, params=params) + + def approximate_issue_count( + self, + jql, + ): + """ + Get an approximate count of issues matching a JQL search string. + + :param jql: The JQL search string. + :return: The issue count. + """ + + if not self.cloud: + raise ValueError("``approximate_issue_count`` method is only available for Jira Cloud platform") + + data = {"jql": jql} + + url = self.resource_url("search/approximate-count") + return self.post(url, data) + def jql_get_list_of_tickets( self, jql, @@ -3435,6 +3506,19 @@ def jql_get_list_of_tickets( :param validate_query: Whether to validate the JQL query :return: """ + if self.cloud: + if start==0: + return self.enhanced_jql_get_list_of_tickets( + jql=jql, + fields=fields, + limit=limit, + expand=expand, + ) + else: + raise ValueError( + "The `jql_get_list_of_tickets` method is deprecated in Jira Cloud. Use `enhanced_jql_get_list_of_tickets` method instead." + ) + params = {} if limit is not None: params["maxResults"] = int(limit) @@ -3456,7 +3540,7 @@ def jql_get_list_of_tickets( response = self.get(url, params=params) if not response: break - + issues = response["issues"] results.extend(issues) total = int(response["total"]) @@ -3465,7 +3549,61 @@ def jql_get_list_of_tickets( if limit is not None or total <= len(response["issues"]) + start: break start += len(issues) + return results + def enhanced_jql_get_list_of_tickets( + self, + jql, + fields="*all", + limit=None, + expand=None, + ): + """ + Get issues from JQL search result with all related fields using nextPageToken pagination. + + Applicable only for Jira Cloud. + + :param jql: The JQL search string. + :param fields: List of fields, for example: ['priority', 'summary', 'customfield_10007'] + :param limit: OPTIONAL: The limit of the number of issues to return, this may be restricted by + fixed system limits. Default by built-in method: 50 + :param expand: OPTIONAL: Expand the search result. + :return: List of issues. + """ + + if not self.cloud: + raise ValueError("``enhanced_jql_get_list_of_tickets`` is only available for Jira Cloud.") + + params = {} + if limit is not None: + params["maxResults"] = int(limit) + if fields is not None: + if isinstance(fields, (list, tuple, set)): + fields = ",".join(fields) + params["fields"] = fields + if jql is not None: + params["jql"] = jql + if expand is not None: + params["expand"] = expand + + url = self.resource_url("search/jql") + results = [] + nextPageToken = None + + while True: + if nextPageToken is not None: + params["nextPageToken"] = nextPageToken + + response = self.get(url, params=params) + if not response: + break + + issues = response["issues"] + results.extend(issues) + + nextPageToken = response.get("nextPageToken") + if not nextPageToken or (limit is not None and len(results) >= limit): + break return results def csv(self, jql, limit=1000, all_fields=True, start=None, delimiter=None): diff --git a/examples/jira/jira_search_issues_cloud.py b/examples/jira/jira_search_issues_cloud.py new file mode 100644 index 000000000..53c2de29c --- /dev/null +++ b/examples/jira/jira_search_issues_cloud.py @@ -0,0 +1,35 @@ +# coding=utf-8 +""" +Example: Using enhanced JQL search methods in Jira Cloud. + +This script demonstrates: +1. Fetching issues using `enhanced_jql` (nextPageToken-based pagination). +2. Getting an approximate issue count with `approximate_issue_count`. +3. Fetching issues using `enhanced_jql_get_list_of_tickets` (legacy startAt pagination for Data Center users). + +⚠️ Note: `enhanced_jql` is recommended for Jira Cloud users as it aligns with Atlassian's new search API. +""" + +from atlassian import Jira + +# Initialize Jira Cloud instance +jira_cloud = Jira( + cloud=True, + url="https://your-jira-instance.atlassian.net", + username="your-email@example.com", + password="your-api-token", +) + +print("========== Fetching Issues Using enhanced_jql ==========") +issues = jira_cloud.enhanced_jql("updated >= -1d ORDER BY updated DESC", limit=20, fields="*nav") +print(issues) + +print("========== Getting Approximate Issue Count ==========") +issue_count = jira_cloud.approximate_issue_count("updated >= -1d ORDER BY updated DESC") +print(issue_count) + +print("========== Fetching Issues Using enhanced_jql_get_list_of_tickets ==========") +issues_list = jira_cloud.enhanced_jql_get_list_of_tickets("updated >= -1d ORDER BY updated DESC", limit=300, fields="*nav") +print(issues_list) + +print("========== Done ==========")