class JiraIntegration(object): def signIn(self, jiraurl, username, password): try: self.__authed_jira = JIRA(server=jiraurl, basic_auth=(username, password), logging=True, max_retries=3) return True except Exception: return False def signOut(self): try: self.__authed_jira.kill_session() return True except Exception: return False def getOpenIssues(self): issues = self.__authed_jira.search_issues("""assignee = currentUser() and sprint in openSprints () order by priority desc""", maxResults=5) return issues def getTitlesForMany(self, issue_id_list): issues = self.__authed_jira.search_issues(' key in (%s)' % issue_id_list.join(',')) return issues def getTitleFor(self, issue_id): issues = self.__authed_jira.search_issues(' key in (%s)' % issue_id) return issues
def update_description(username, password, issue, new_description): try: Jira = JIRA(JIRA_URL, basic_auth=(username, password), max_retries=0) existing_issue = Jira.issue(issue) existing_issue.update(description=new_description) Jira.kill_session() except JIRAError as e: raise JIRAError()
def create_ticket( username, password, project, title, description, reporter, assignee=None, watchers=None, ): ''' Creates a JIRA Ticket Returns the string URL of the JIRA Ticket ''' try: Jira = JIRA(JIRA_URL, basic_auth=(username, password), max_retries=0) issue_dict = { 'project': { 'id': int(project) }, 'summary': title, 'description': description, 'issuetype': { 'name': 'Task' }, 'reporter': { 'name': reporter }, 'assignee': { 'name': assignee }, } new_issue = Jira.create_issue(fields=issue_dict) if watchers is not None: for watcher in watchers: jira.add_watcher(new_issue.id, watcher) Jira.kill_session() return str(new_issue) except JIRAError as e: raise JIRAError()
class JiraClient(): jira_con = None board_details = None def __init__(self): self._get_jira_board_details() secrets = _get_secrets_from_netrc() if not secrets: err_msg = 'Unable to locate or load suitable `.netrc` file for JIRA integration' logger.error(err_msg) raise ValueError(err_msg) try: username, account, apikey = secrets.authenticators( self.jira_hostname) except TypeError: err_msg = 'JIRA Connection. Unable to find details for machine "{}" `.netrc` file.'.format( self.jira_hostname) logger.error(err_msg) raise ValueError(err_msg) self.jira_con = JIRA(options={'server': account}, basic_auth=(username, apikey)) _check_jira_con(self.jira_con, username) logger.debug('JIRA Connection. Details = {}'.format( self.jira_con.myself())) def _get_jira_board_details(self): # TODO read these in from a config file self.jira_hostname = 'mapaction.atlassian.net' self.project_key = 'PIPET' # The target column should be were the column where new issues are created self.target_column = '10110' self.common_task_fields = { 'project': self.project_key, 'issuetype': { 'id': '10235' } } def __del__(self): try: self.jira_con.kill_session() except (TypeError, AttributeError): pass def task_handler(self, fail_threshold, msg, task_referal=None): logger.debug( 'JiraClient.task_handler called with status="{}", and msg="{}"'. format(fail_threshold, msg)) assured_referal = self.ensure_task_referal_type( task_referal, msg, fail_threshold) if not assured_referal: logger.debug( 'JiraClient.task_handler; `None` value passed for task_referal parameter. Nothing to handle.' ) return unique_summary = assured_referal.get_task_unique_summary() task_desc = assured_referal.get_task_description() op_id = assured_referal.get_operation_id() j_issue = self.search_issue_by_unique_summary(unique_summary, op_id) if j_issue: # Update existing card and maybe move it back into "Doing" column self.update_jira_issue(j_issue, task_desc, fail_threshold) else: if fail_threshold > logging.INFO: # Create a new task self.create_new_jira_issue(unique_summary, task_desc, op_id) def ensure_task_referal_type(self, task_referal, msg, fail_threshold): """ Check whether or not the `task_referal` is an instance of TaskReferralBase object. If it is the object is then it is returned unchanged. If not then an generic TaskReferralBase will be created and returned. The value of `str(task_referal)` will be used. @param task_referal: An object that may or may not be a TaskReferralBase object. @returns: If the `task_referal` param is an instance of TaskReferralBase object, then `task_referal` is returned. If `task_referal` param is NOT an instance of TaskReferralBase AND fail_threshold is logging.ERROR then a new TaskReferralBase object is created (using `msg` and `str(task_referal)` for context). Else `None` is returned. """ if isinstance(task_referal, TaskReferralBase): logger.debug( 'JiraClient.ensure_task_referal_type found a TaskReferralBase object' ) return task_referal if task_referal and (fail_threshold > logging.WARNING): logger.debug( 'JiraClient.ensure_task_referal_type created a new TaskReferralBase object' ) return TaskReferralBase(None, msg=msg, other=str(task_referal)) logger.debug( 'JiraClient.ensure_task_referal_type passed "{}" but returned `None`' .format(str(task_referal))) return None def search_issue_by_unique_summary(self, search_summary, op_id): # Default if `op_id` is None jql_op_id = 'operational_id is EMPTY' if op_id: jql_op_id = 'operational_id ~ "{}"'.format(op_id) jql_str = 'project={} AND {} AND summary ~ "{}"'.format( self.project_key, jql_op_id, search_summary) found_issues = self.jira_con.search_issues(jql_str, maxResults=2) if found_issues: if len(found_issues) > 1: raise ValueError( 'More than one JIRA Issue found with the summary "{}". This suggests that additional' ' issues have been raised manualy on the board "{}". Please ensure that there is exactly' ' one issues with this summary, by deleting those which have not been created by the' ' user "{}"'.format( search_summary, self.project_key, self.jira_con.myself()['emailAddress'])) else: return found_issues[0] else: return None def create_new_jira_issue(self, unique_summary, task_desc, op_id): flds = self.common_task_fields.copy() flds['summary'] = unique_summary flds['description'] = task_desc # This is the JIRA API's field ID for operational_id. To work this out execute: # ``` # a = j.jira_con.createmeta(projectKeys=['PIPET'], issuetypeIds=[10235], expand='projects.issuetypes.fields') # print(a) # ``` # Then search the output for your custom field name. Doubtless there is a programmatic way to do this. flds['customfield_10234'] = op_id new_task = self.jira_con.create_issue(fields=flds) # new_task.update(fields={'operational_id':op_id}) # new_task.update(operational_id=op_id) print(new_task) # print('desc', new_task.fields.description) # print('opid', new_task.fields.operational_id) # for f in new_task.fields: # print('field itr', f) def update_jira_issue(self, j_issue, task_desc, fail_threshold): now_utc = pytz.utc.localize(datetime.now()) time_stamp = now_utc.strftime('%Y-%m-%d %H:%M:%S %Z%z') # prev_desc = if task_desc != j_issue.fields.description: j_issue.update(description=task_desc) if fail_threshold > logging.INFO: self.jira_con.add_comment( j_issue.id, 'This Issue was still current when MapChef was run at {}'. format(time_stamp))