"""Jira API client for handling all communication with Jira Cloud REST API."""importloggingimportrequestsfrom.exceptionsimportJiraApiError,AuthenticationError,IssueNotFoundError
[docs]classJiraApiClient:"""Handles all communication with the Jira Cloud REST API."""
[docs]def__init__(self,domain,email,api_token):"""Initialize the Jira API client. Args: domain: Jira domain (e.g., 'company.atlassian.net') email: User email for authentication api_token: API token for authentication """self.domain=domainself.email=emailself.api_token=api_tokenself.base_url=f"https://{domain}"self.api_base=f"{self.base_url}/rest/api/3"self.session=requests.Session()self.session.auth=(email,api_token)self.session.headers.update({"Accept":"application/json","Content-Type":"application/json"})self.logger=logging.getLogger(__name__)
[docs]deffetch_issue(self,issue_key):"""Fetch issue data from Jira API. Args: issue_key: The Jira issue key (e.g., 'PROJ-123') Returns: dict: Raw JSON response from Jira API Raises: AuthenticationError: If authentication fails IssueNotFoundError: If issue is not found JiraApiError: For other API errors """url=f"{self.api_base}/issue/{issue_key}"params={"fields":"*all","expand":"renderedFields"}self.logger.info(f"Fetching issue {issue_key}...")try:response=self.session.get(url,params=params)response.raise_for_status()returnresponse.json()exceptrequests.exceptions.HTTPErrorase:ifresponse.status_code==401:raiseAuthenticationError("Authentication failed. Please check your API token and email.",status_code=401,response=response,)elifresponse.status_code==404:raiseIssueNotFoundError(f"Issue {issue_key} not found or not accessible.",status_code=404,response=response,)else:raiseJiraApiError(f"HTTP error occurred: {e}",status_code=response.status_code,response=response,)exceptrequests.exceptions.RequestExceptionase:raiseJiraApiError(f"Error fetching issue: {e}")
[docs]defget_attachment_content_url(self,attachment):"""Get the download URL for an attachment. Args: attachment: Attachment metadata from Jira API Returns: str: The content URL for downloading the attachment """returnattachment.get("content","")
[docs]defdownload_attachment_stream(self,content_url):"""Stream download an attachment. Args: content_url: The URL to download the attachment from Returns: requests.Response: Streaming response object Raises: JiraApiError: If download fails """try:response=self.session.get(content_url,stream=True)response.raise_for_status()returnresponseexceptrequests.exceptions.RequestExceptionase:raiseJiraApiError(f"Error downloading attachment: {e}")