def JiraAssignCommentAndResolveTicket(key, JiraUserName, jiraMessage, channel, JiraPassword): jira = JIRA(basic_auth=(JiraUserName, JiraPassword), options={'server': 'https://jira.Company.com'}) issue = jira.issue(key) jira.assign_issue(issue, JiraUserName) #sleep to make sure the assign change goes through and we can find the resolve issue id time.sleep(5) transitions = jira.transitions(issue) #print [(t['id'], t['name']) for t in transitions] for t in transitions: if t['name'] == 'Resolve Issue': id = t['id'] #print id continue try: jira.transition_issue(issue, id) except: time.sleep(1) try: jira.transition_issue(issue, id) except: print 'ERROR JIRA WAS UNABLE TO FINISH RESOLVING: ' + issue.key jiraSlackSendMessage( channel, 'We were unable to resolve this issue for some reason... Get Luke to fix this!' ) jira.add_comment(issue=issue.key, body=jiraMessage, is_internal=False) #send the next ticket thread.start_new_thread(jiraPhishingMain, (channel, jira, JiraUserName, JiraPassword))
class AutoJIRA: def __init__(self, **kwargs): if 'server' in kwargs: server = kwargs['server'] else: server = os.environ['JIRA_URL'] if 'api_user' in kwargs: api_user = kwargs['api_user'] else: api_user = os.environ['JIRA_API_USER'] if 'api_token' in kwargs: api_token = kwargs['api_token'] else: api_token = os.environ['JIRA_API_TOKEN'] self.__jc = JIRA(server=server, basic_auth=(api_user, api_token)) self.__wf = WorkFlow() def __get_issues(self, **kwargs): issues = [] if 'jql' in kwargs: issues += self.__jc.search_issues(jql_str=kwargs['jql']) if 'key' in kwargs: issues.append(self.__jc.issue(kwargs['key'])) if 'file' in kwargs: with open(kwargs['file']) as fp: for key in fp.readlines(): issues.append(self.__jc.issue(key.strip())) return issues def __move(self, issue, n): if n[0] not in list( map(lambda x: int(x['id']), self.__jc.transitions(issue))): self.__move(issue, self.__wf.previous(n)) self.__jc.transition_issue(issue, n[0]) def move(self, status, **kwargs): if not self.__wf.valid(status): raise ValueError('Not a valid status') issues = self.__get_issues(**kwargs) if len(issues) == 0: raise ValueError("No issues to move") for issue in issues: print('Moving the ticket: {} to {}'.format(issue.key, status[1])) self.__move(issue, status) if 'comments' in kwargs: self.__jc.add_comment(issue, kwargs['comments']) if 'assignee' in kwargs: self.__jc.assign_issue(issue, kwargs['assignee']) print('Done')
class jira(Action): def run(self, jiraID, assignee): jira_url = self.config['jira_url'] username = self.config['jira_username'] # username = self.config['username'] # password = self.config['password'] password = self.config['jira_password'] self.jira_client = JIRA(jira_url, basic_auth=(username, password)) # tmp = '"""' + assignee + '"""' # a = tmp.split(' ') # assign = a[-1].split('"') # assign1 = assign[1] # print assign1 self.jira_client.assign_issue(jiraID, assignee) msg = "Jira " + str(jiraID) + " has been assigned to " + assignee return msg
def trigger_jira() -> None: try: jira = JIRA(options, basic_auth=(f'{user_name}', f'{password}')) except BaseException as Be: logging.exception( "******************************start*************************************" ) logging.exception(Be) logging.exception( "********************************end***********************************" ) logging.info("-----------------------------------------------------------") all_closed_issues = jira.search_issues( 'project = "HAAL Support" AND status in (resolved, closed) AND assignee is not EMPTY ORDER BY createdDate ASC', maxResults=False) logging.info("-----------------------------------------------------------") logging.info(len(all_closed_issues)) for i in range(0, len(all_closed_issues)): logging.info(all_closed_issues[i].key) train.append((str(all_closed_issues[i].key.split('-')[0]) + ' ' + str(all_closed_issues[i].fields.summary), all_closed_issues[i].fields.assignee.name)) cl = NaiveBayesClassifier(train) all_open_issues = jira.search_issues( 'project = "HAAL Support" AND status=open AND assignee = EMPTY', maxResults=False) if len(all_open_issues) > 0: for i in range(0, len(all_open_issues)): issue = str(all_open_issues[i].key.split('-')[0]) + \ ' ' + str(all_open_issues[i].fields.summary) assignee_ = cl.classify(issue) logging.info(all_open_issues[i].key, ' can be assigned to : ', assignee_) jira.assign_issue(all_open_issues[i].key, assignee_) total_time_lapse = time.time() - start_time logging.info(f"--- Total Time: {total_time_lapse} seconds ---") else: cur_date = d.datetime.now().strftime('%Y-%m-%d %H:%M:%S') logging.info( "There aren't any issues to be assigned. will try again in a 10 minute.(" + cur_date + ")")
def changejira(project,buildtime,judgement,newversion,releasejira): jira = JIRA('http://jira.ccdomain.com',basic_auth=('jira', 'jira@2017~!@')) if releasejira == "": jiralist = judgelist(project,buildtime,judgement) else: jiralist = comparelist(project,buildtime,releasejira) jirareq_list= searchjirareq(project,buildtime) #创建version: curTime = datetime.date.today() curTime = curTime.strftime("%Y-%m-%d") try: jira.create_version(newversion,project,description="Pollux %s 版本转测试" %newversion,startDate=curTime) except BaseException: print "create version %s error,maybe it's existed" %(newversion) #将所有组织测试的单转成回归测试 for a in jiralist: print "start to change bug %s to 回归测试" %(str(a)) try: issue = jira.issue(a) #修改 jira 单中的修复版本: issue_dict = { 'fixVersions':[{'name':newversion}] } issue.update(fields=issue_dict) #修改 jira 单状态: jira.transition_issue(issue,'191',comment="自动回归测试") #修改指向人 newassign = str(issue.fields.reporter.name) jira.assign_issue(issue,newassign) except BaseException: print "change fail in %s" %(str(a)) for b in jirareq_list: print "start to change req %s to 回归测试" %(str(b)) try: issue = jira.issue(b) #修改 jira 单中的修复版本: issue_dict = { 'fixVersions':[{'name':newversion}] } issue.update(fields=issue_dict) #修改 jira 单状态: jira.transition_issue(issue,'21',comment="需求自动回归测试") except BaseException: print "change fail in %s" %(str(b))
def main(credential_file, assignee, issue): """ISSUE : string - the JIRA issue identifier e.g.: RA-478 """ rest_url_file = DEFAULT_URL_FILE if not os.path.exists(rest_url_file): print("JIRA REST URL file '{}' does not exist".format(rest_url_file)) sys.exit(1) else: with open(rest_url_file, 'r') as f: url = f.readline() url = url.strip() print("read the REST URL from file '{}'".format(rest_url_file)) if credential_file is None: credential_file = DEFAULT_CREDENTIAL_FILE if not os.path.exists(credential_file): print("JIRA credential file '{}' does not exist".format(credential_file)) sys.exit(1) if issue is None: print("issue was not specified") sys.exit(1) with open(credential_file, 'r') as f: line = f.readline() line = line.strip() (username, password) = line.split(':') print("read username and password from credentials file") if assignee is None: assignee = username auth_jira = JIRA(url, basic_auth=(username, password)) if auth_jira is not None: print("Will attempt to assign issue '{}' to username '{}'".format(issue, assignee)) auth_jira.assign_issue(issue, assignee) print("Assigned issue '{}' to username '{}'".format(issue, assignee)) else: print("Could not instantiate JIRA for url '{}'".format(url))
def new_func(ctx, *args, **kwargs): obj = ctx.ensure_object(Config) cfg = obj.jira_cfg try: jira = JIRA( server=cfg['server'], basic_auth=(cfg['username'], cfg['password']), ) f(*args, **kwargs) issue = jira.issue(kwargs['branch_name']) # TODO JIRAError's except Exception as e: click.echo(e) else: username = cfg['username'] if jira.user(username) != issue.fields.assignee: jira.assign_issue(issue, username) for status in jira.transitions(issue): if status['id'] in args: # jira.transition_issue(issue, transition=status['id']) obj.out(status['name'])
class Jira: auth_jira = None project = None url = None def __init__(self): self.url = environ.get('JIRA_URL') self.auth_jira = JIRA({'server': self.url}, basic_auth=(environ.get('JIRA_LOGIN'), environ.get('JIRA_PASSWORD'))) self.project = environ.get('JIRA_PROJECT') self.jira_users = { '@lexx_v': 'Lexx', '@rainbowdash593': 'rainbowdash593', '@seniyaeclair': 'Kosheleva.yuliya.mmf', '@nezzl': 'Nezzl' } def search_issues_by_description(self, search): issues = self.auth_jira.search_issues( 'project = {project} AND description ~ {search} OR project = {project} AND summary ~ {search}' .format(project=self.project, search=search)) return list(self._generate_url_to_issue(issue) for issue in issues) def create_issue(self, summary, responsible_user, description=''): issue = self.auth_jira.create_issue( project=self.project, summary=summary, description=description, issuetype={'name': 'Баг из телеги'}) if responsible_user in self.jira_users: self.auth_jira.assign_issue(issue.key, self.jira_users[responsible_user]) return self._generate_url_to_issue(issue) def _generate_url_to_issue(self, issue): return self.url + '/browse/' + issue.key
def moveTasksToTest(version, build): fixedInBuild = 'build: {0}'.format(build) options = { 'server': SERVER } jira = JIRA(options, basic_auth=(CURRENT_USER, PASSWORD)) # a username/password tuple print('INFO -> jira: %s' % jira.client_info()) print('INFO -> current_user: %s' % CURRENT_USER) print('INFO -> target_user: %s' % TARGET_USER) assignee = 'assignee={0}'.format(CURRENT_USER) #на ком таска issues = jira.search_issues(assignee) print('\n') for issue in issues: if issue.fields.status.name in(u'READY TO MERGE'): print('INFO -> Task: %s' % issue.key.encode('utf-8','ignore')) print('INFO -> Summary: %s' % issue.fields.summary.encode('utf-8','replace')) print('INFO -> Status: %s\n' % issue.fields.status) fixedInMsg = 'fixed in ' + version + ' ' + fixedInBuild comment = jira.add_comment(issue.key, fixedInMsg) jira.transition_issue(issue, transition='Ready for test') jira.assign_issue(issue, TARGET_USER) print('DEBUG -> Success!')
if not options.componentjbide and not options.componentjbds: rootJBDS_dict = { 'project' : { 'key': 'JBDS' }, 'summary' : 'For JBDS ' + jbds_fixversion + ': ' + taskdescription, 'description' : 'For JBDS ' + jbds_fixversion + ': ' + taskdescriptionfull + '\n\n[Search for all task JIRA|' + tasksearch + ']', 'issuetype' : { 'name' : 'Task' }, 'priority' : { 'name' :'Blocker'}, 'fixVersions' : [{ "name" : jbds_fixversion }], 'components' : [{ "name" : "installer" }], 'labels' : [ "task" ], } rootJBDS = jira.create_issue(fields=rootJBDS_dict) installerLead = queryComponentLead(CLJBDS, 'installer', 0) try: jira.assign_issue(rootJBDS, installerLead) except: if (not options.jiraonly): print "[WARNING] Unexpected error! User {0} tried to assign {1} to {2}: {3}".format(options.usernameJIRA, rootJBDS, installerLead, sys.exc_info()[0]) if (options.jiraonly): print(rootJBDS.key) else: print("Task JIRA created for this milestone include:") print("") print("JBDS : " + jiraserver + '/browse/' + rootJBDS.key + " => " + installerLead) rootJBIDE_dict = { 'project' : { 'key': 'JBIDE' }, 'summary' : 'For JBIDE ' + jbide_fixversion + ': ' + taskdescription, 'description' : 'For JBIDE ' + jbide_fixversion + ': ' + taskdescriptionfull + '\n\n[Search for all task JIRA|' + tasksearch + ']\n\nSee also: ' + rootJBDS.key,
'name': 'Task' }, 'priority': { 'name': 'Blocker' }, 'fixVersions': [{ "name": jbide_fixversion }], 'components': [{ "name": "website" }] } rootnn = jira.create_issue(fields=rootnn_dict) componentLead = defaultAssignee() try: jira.assign_issue(rootnn, componentLead) except: print "[WARNING] Unexpected error! User {0} tried to assign {1} to {2}: {3}".format( options.usernameJIRA, rootnn, componentLead, sys.exc_info()[0]) print("JBoss Tools : " + jiraserver + '/browse/' + rootnn.key + " => " + componentLead + "") def nametuple(x): return {"name": x} def quote(x): return '"' + x + '"' # see JIRA_components listing in components.py
def update_tickets_from_git(last=None, current=None): """ Run during a deployment. Looks at all commits between now and the last deployment. Finds all ticket numbers and updates their status in Jira. """ from jira import JIRA, JIRAError from burlap.deploy import get_last_current_diffs from burlap.git import gittracker get_current_commit = gittracker.get_current_commit GITTRACKER = gittracker.name.upper() dryrun = common.get_dryrun() verbose = common.get_verbose() # Ensure this is only run once per role. if env.host_string != env.hosts[-1]: return if not env.jira_update_from_git: return if not env.jira_ticket_pattern: return if not env.jira_basic_auth_username or not env.jira_basic_auth_password: return # During a deployment, we should be given these, but for testing, # lookup the diffs dynamically. if not last or not current: last, current = get_last_current_diffs(GITTRACKER) if verbose: print('-'*80) print('last.keys:', last.keys()) print('-'*80) print('current.keys:', current.keys()) try: last_commit = last['GITTRACKER']['current_commit'] except KeyError: return current_commit = current['GITTRACKER']['current_commit'] # Find all tickets deployed between last deployment and now. tickets = get_tickets_between_commits(current_commit, last_commit) if verbose: print('tickets:', tickets) # Update all tickets in Jira. jira = JIRA({ 'server': env.jira_server }, basic_auth=(env.jira_basic_auth_username, env.jira_basic_auth_password)) for ticket in tickets: # Mention this Jira updated. comment = env.jira_ticket_update_message_template % dict(role=env.ROLE.lower()) print('Commenting on ticket %s: %s' % (ticket, comment)) if not dryrun: jira.add_comment(ticket, comment) # Update ticket status. recheck = False while 1: print('Looking up jira ticket %s...' % ticket) issue = jira.issue(ticket) print('Ticket %s retrieved.' % ticket) transition_to_id = dict((t['name'], t['id']) for t in jira.transitions(issue)) print('%i allowable transitions found: %s' % (len(transition_to_id), ', '.join(transition_to_id.keys()))) next_transition_name = env.jira_deploy_workflow.get(issue.fields.status.name.title()) next_transition_id = transition_to_id.get(next_transition_name) if next_transition_name: new_fields = {} # print('jira_assignee_by_status:', env.jira_assignee_by_status, issue.fields.status.name.title() new_assignee = env.jira_assignee_by_status.get( #issue.fields.status.name.title(), next_transition_name, issue.fields.assignee.name, ) if new_assignee == 'reporter': new_assignee = issue.fields.reporter.name # print('new_assignee:', new_assignee) print('Updating ticket %s to status %s and assigning it to %s.' \ % (ticket, next_transition_name, new_assignee)) if not dryrun: try: jira.transition_issue( issue, next_transition_id, ) recheck = True except AttributeError as e: print('Unable to transition ticket %s to %s: %s' \ % (ticket, next_transition_name, e), file=sys.stderr) # Note assignment should happen after transition, since the assignment may # effect remove transitions that we need. try: if new_assignee: print('Assigning ticket %s to %s.' % (ticket, new_assignee)) jira.assign_issue(issue, new_assignee) else: print('No new assignee found.') except JIRAError as e: print('Unable to reassign ticket %s to %s: %s' \ % (ticket, new_assignee, e), file=sys.stderr) else: recheck = False print('No transitions found for ticket %s currently in status "%s".' \ % (ticket, issue.fields.status.name)) if not recheck: break
class jiramenu(): user = None auth = None config = None debug = False r = Rofi() issues = [] rofi_list = [] def __init__(self, config, debug): self.config = config self.r.status("starting jiramenu") try: self.auth = JIRA(config['JIRA']['url'], basic_auth=(config['JIRA']['user'], config['JIRA']['password'])) except Exception as error: self.r.exit_with_error(str(error)) self.debug = debug def log(self, text): if not self.debug: return print(text) def show(self, user): self.user = user if user: self.log(f"show issues for: {self.user}") query = self.config['JIRA']['query'] if user: query += f" and assignee = {user}" self.log(f"Query: {query}") if not self.issues: self.issues = self.auth.search_issues(query) if not self.rofi_list: if user: self.rofi_list.append(">>ALL") else: self.rofi_list.append(">>MINE") for issue in self.issues: issuetext = '' if issue.fields.assignee: issuetext = f'[{issue.fields.assignee.name}]' if issue.fields.status.id == str(3): #id:3 = Work in Progress issuetext += '{WIP}' issuetext += f'{issue.key}:{issue.fields.summary}' self.rofi_list.append(issuetext) # print active query plus number of results on top index, key = self.r.select(f'{query}[{len(self.rofi_list)}]', self.rofi_list, rofi_args=['-i'], width=100) del key if index < 0: exit(1) if index == 0: self.issues = [] self.rofi_list = [] if user: self.show(None) else: self.show(self.config['JIRA']['user']) return self.show_details(index, user) def addComment(self, ticket_number): comment = self.r.text_entry("Content of the comment:") if comment: # replace @user with [~user] comment = re.sub(r"@(\w+)", r"[~\1]", comment) self.auth.add_comment(ticket_number, comment) def show_details(self, index, user): inputIndex = index ticket_number = re.sub(r"\[.*\]", "", self.rofi_list[index]) ticket_number = re.sub(r"\{.*\}", "", ticket_number) ticket_number = ticket_number.split(":")[0] self.log("[details]" + ticket_number) issue_description = self.issues[index - 1].fields.description output = [] output.append(">>show in browser") output.append("[[status]]") output.append(self.issues[index - 1].fields.status.name) output.append("[[description]]") output.append(issue_description) if self.auth.comments(ticket_number): output.append("[[comments]]") comment_ids = self.auth.comments(ticket_number) for comment_id in comment_ids: self.log("comment_id: " + str(comment_id)) commenttext = '[' + self.auth.comment( ticket_number, comment_id).author.name + ']' commenttext += self.auth.comment(ticket_number, comment_id).body output.append(commenttext) else: output.append("[[no comments]]") output.append(">>add comment") if self.issues[index - 1].fields.assignee: output.append("[[assignee]]" + self.issues[index - 1].fields.assignee.name) else: output.append(">>assign to me") if self.issues[index - 1].fields.status.id == str(3): # WIP output.append(">>in review") else: output.append(">>start progress") output.append('<<back') index, key = self.r.select(ticket_number, output, width=100) if index in [-1, len(output) - 1]: self.show(user) return if index == len(output) - 2: # move issue to 'In Review' self.log("[status]" + self.issues[inputIndex - 1].fields.status.name) self.log("[transitions]") self.log(self.auth.transitions(ticket_number)) if self.issues[inputIndex - 1].fields.status.id == str(3): # WIP for trans in self.auth.transitions(ticket_number): if trans['name'] == "in Review": self.log("move to 'in Review'") self.auth.transition_issue(ticket_number, trans['id']) else: for trans in self.auth.transitions(ticket_number): if trans['name'] == "Start Progress": self.log("move to 'Start Progress'") self.auth.transition_issue(ticket_number, trans['id']) self.show_details(inputIndex, user) return if index == len(output) - 4: # add comment self.log("[addComment]") self.addComment(ticket_number) self.show_details(inputIndex, user) return if index == len(output) - 3: # assign to me self.log("[assign to me]") self.auth.assign_issue(ticket_number, self.config['JIRA']['user']) self.show_details(inputIndex, user) return if index in [3, 4]: Popen(['notify-send', issue_description, '-t', '30000']) self.show_details(inputIndex, user) return # show in browser self.log("[show in browser]") uri = self.auth.issue(ticket_number).permalink() Popen(['nohup', self.config['JIRA']['browser'], uri], stdout=DEVNULL, stderr=DEVNULL)
}, 'versions': [{ "name": jbide_affectedversion }], 'components': [{ "name": component }], 'labels': ["testfailure"] } jira = JIRA(options={'server': jiraserver}, basic_auth=(options.usernameJIRA, options.passwordJIRA)) CLJBIDE = jira.project_components( jira.project('JBIDE')) # full list of components in JBIDE rootJBIDE = jira.create_issue(fields=rootJBIDE_dict) componentLead = queryComponentLead(CLJBIDE, component, 0) try: jira.assign_issue(rootJBIDE, componentLead) except: print "[WARNING] Unexpected error! User {0} tried to assign {1} to {2}: {3}".format( options.usernameJIRA, rootJBIDE, componentLead, sys.exc_info()[0]) accept = raw_input("\nAccept new JIRA " + jiraserver + '/browse/' + rootJBIDE.key + " => " + componentLead + " ? [Y/n] ") if accept.capitalize() in ["N"]: rootJBIDE.delete() # see JIRA_components listing in components.py # Sample usage: see createTestFailureJIRA.py.examples.txt
def change_jira(issue): authed_jira = JIRA('http://jira.xxx.com/', basic_auth=('qudian_sec', 'xxx')) authed_jira.assign_issue(issue, 'qudian_sec')
class Jira(object): """JIRA objects and operations.""" def __init__(self, url, username, token, project, max_results): self.jira = JIRA(url, basic_auth=(username, token)) self.project = project self.max_results = max_results def search_issues(self, keyword, **kwargs): """ Search Jira issues. Filtering by keyword is not done on JIRA query becasue it does not support filtering both summary and key by string values. """ keyword = keyword.lower() query_parameters = [] if kwargs.get('type'): query_parameters.append('type = "{}"'.format(kwargs.get('type'))) query = ' OR'.join(query_parameters) + ' order by created desc' issues = self.jira.search_issues(query, maxResults=self.max_results) matching_issues = [] for issue in issues: if keyword in issue.key.lower( ) or keyword in issue.fields.summary.lower(): matching_issues.append(issue) return matching_issues def get_issue_by_key(self, key): """Get issue by key""" try: return self.jira.issue(key) except JIRAError as e: if e.status_code == 404: raise click.UsageError( 'The specified JIRA issue: {}, does not exist.'.format( key)) raise def create_issue(self, fields): return self.jira.create_issue(fields=fields) def get_resolution_by_name(self, name): resolutions = self.jira.resolutions() for r in resolutions: if r.name == name: return r.id return None def get_transition(self, issue, name): return self.jira.find_transitionid_by_name(issue, name) def transition_issue(self, issue, transition): transition_id = self.get_transition(issue, transition) if transition_id: self.jira.transition_issue(issue, transition_id) def assign_issue(self, issue, assignee): self.jira.assign_issue(issue, assignee)
"--months", dest="no_of_months", help="Tickets to be created for every no of months given", required=True) args = parser.parse_args() print args.no_of_months authed_jira = JIRA(server='https://gayatritest.atlassian.net', basic_auth=('admin', 's8985622575')) fo = open("sample.json", "r+") issue_dict = json.loads(fo.read()) issues_to_be_created = issue_dict.get(args.no_of_months) for issue in issues_to_be_created: new_issue = authed_jira.create_issue( fields=issues_to_be_created[issue].get('issue_details')) print "Creating ", issue authed_jira.assign_issue(new_issue, issues_to_be_created[issue].get('issue_asignee')) fo.close() print "Tickets created successfully" #if args.no_of_months=="1": # for key,value in issue_dict.iteritems(): # print issue_dict.get(args.no_of_months) #Read from user monthly or yearly using argparse #for key,value in issue_dict.iteritems(): #if user gave monthly: #issue_dict.get('monthly') #for j,k in issue_dict.get('monthly'):
class Jira(object): """JIRA objects and operations.""" def __init__(self, instance, project, workflow, connection_user, max_results=50): self.workflow = workflow self.project = project self.username = instance.credentials.username self.max_results = max_results self.jira = JIRA(instance.url, basic_auth=(connection_user, instance.credentials.token)) def search_issues(self, keyword, **kwargs): """ Search Jira issues. Filtering by keyword is not done on JIRA query becasue it does not support filtering both summary and key by string values. """ keyword = keyword.lower() query_parameters = [] if kwargs.get("types"): for type in kwargs.get("types"): query_parameters.append('type = "{}"'.format(type)) query = " OR ".join(query_parameters) + " order by created desc" issues = self.jira.search_issues(query, maxResults=self.max_results) matching_issues = [] for issue in issues: if keyword in issue.key.lower( ) or keyword in issue.fields.summary.lower(): matching_issues.append(self._convert_to_issue(issue)) return matching_issues def get_issue_by_key(self, key): """Get issue by key""" try: jira_issue = self.jira.issue(key) return self._convert_to_issue(jira_issue) except JIRAError as e: if e.status_code == 404: raise click.UsageError( "The specified JIRA issue: {}, does not exist.".format( key)) raise def create_issue(self, fields): jira_issue = self.jira.create_issue(fields=fields) return self._convert_to_issue(jira_issue) def get_resolution_by_name(self, name): resolutions = self.jira.resolutions() for r in resolutions: if r.name == name: return r.id return None def get_transition(self, issue, name): return self.jira.find_transitionid_by_name(issue, name) def transition_issue(self, issue, transition): transition_id = self.get_transition(issue, transition) if transition_id: self.jira.transition_issue(issue, transition_id) def assign_issue(self, issue, assignee): self.jira.assign_issue(issue, assignee) def make_action(self, action, issue): issue.status = action.next_state # Get jira issue to perform transitions jira_issue = self.jira.issue(issue.key) for transition in action.transitions: self.transition_issue(jira_issue, transition) if action.assign_to_user: self.assign_issue(jira_issue, self.username) return issue def _convert_to_issue(self, jira_issue): """Convert to simplified issue.""" i = Issue( jira_issue.key, jira_issue.fields.summary, self._get_type(jira_issue), self._get_status(jira_issue), ) i.subtasks = self._get_subtasks(jira_issue) return i def _get_type(self, jira_issue): jira_type = jira_issue.fields.issuetype.name for type_mapping in self.workflow.types: if type_mapping.mapping == jira_type: return type_mapping.issue_type raise Exception(f"Unable to map issue type: {jira_type}") def _get_status(self, jira_issue): jira_status = jira_issue.fields.status.name for status_mapping in self.workflow.statuses: if jira_status in status_mapping.mapping: return status_mapping.status raise Exception(f"Unable to map issue status: {jira_status}") def _get_subtasks(self, jira_issue): try: return [ self._convert_to_issue(subtask) for subtask in jira_issue.fields.subtasks ] except AttributeError as e: return []
for eachline in csvopen: #print("\t%s" % eachline); fields = eachline.split(';') xpname = fields[28] #print (xpname) filename = re.search(r'.*\/(.*)\@\@', xpname) searchinput =(filename.group(1)) #print (searchinput) struct[assyst].append(searchinput) #json_out = json.dumps(struct) jira_creation =(len(struct)) #print (jira_creation) pprint.pprint(struct) for key in struct.keys(): summary = "XREF ticket -" + key issue_dict = { 'project': {'key': 'JIRA_PAD'}, 'summary': summary, 'parent' : {'key' : 'JIRA_PAD-967'}, 'issuetype': {'name': 'Sub-task'}, 'priority' : {'id' : '3'}, #'customfield_10178' : {'value' : 'BCCCNKSK'}, #'customfield_10176' : {'value' : 'INNN'}, 'customfield_10198' : {'value' : '23456789'} } new_issue = jira.create_issue(fields=issue_dict) jira.assign_issue(new_issue, 'username') print(new_issue.key)
def update_tickets_from_git(self, from_commit=None, to_commit=None): """ Find all ticket numbers and update their status in Jira. Run during a deployment. Looks at all commits between now and the last deployment. """ from jira import JIRA, JIRAError from burlap.git import gittracker, CURRENT_COMMIT r = self.local_renderer # get_current_commit = gittracker.get_current_commit # GITTRACKER = gittracker.name.upper() # Ensure this is only run once per role. if self.genv.host_string != self.genv.hosts[-1]: self.vprint('Not first server. Aborting.') return self.vprint('self.env.update_from_git:', self.env.update_from_git) self.vprint('self.genv.jirahelper_update_from_git:', self.genv.jirahelper_update_from_git) if not self.env.update_from_git: self.vprint('Update from git disabled. Aborting.') return if not self.env.ticket_pattern: self.vprint('No ticket pattern defined. Aborting.') return if not self.env.basic_auth_username or not self.env.basic_auth_password: self.vprint('Username or password not given. Aborting.') return # During a deployment, we should be given these, but for testing, # lookup the diffs dynamically. last = gittracker.last_manifest current = gittracker.current_manifest last_commit = from_commit or last.current_commit #[CURRENT_COMMIT] print('last_commit:', last_commit) current_commit = to_commit or current[CURRENT_COMMIT] print('current_commit:', current_commit) if not last_commit or not current_commit: print('Missing commit ID. Aborting.') return self.vprint('-' * 80) self.vprint('last.keys:', last.keys()) self.vprint('-' * 80) self.vprint('current.keys:', current.keys()) # try: # last_commit = last['GITTRACKER']['current_commit'] # except KeyError: # return # current_commit = current['GITTRACKER']['current_commit'] # Find all tickets deployed between last deployment and now. tickets = self.get_tickets_between_commits(current_commit, last_commit) self.vprint('tickets:', tickets) # Update all tickets in Jira. jira = JIRA({'server': self.env.server}, basic_auth=(self.env.basic_auth_username, self.env.basic_auth_password)) for ticket in tickets: # Mention this Jira updated. r.env.role = r.genv.ROLE.lower() comment = r.format(self.env.ticket_update_message_template) print('Commenting on ticket %s: %s' % (ticket, comment)) if not self.dryrun: jira.add_comment(ticket, comment) # Update ticket status. recheck = False while 1: print('Looking up jira ticket %s...' % ticket) issue = jira.issue(ticket) self.vprint('Ticket %s retrieved.' % ticket) transition_to_id = dict( (t['name'], t['id']) for t in jira.transitions(issue)) self.vprint('%i allowable transitions found:' % len(transition_to_id)) if self.verbose: pprint(transition_to_id) self.vprint('issue.fields.status.id:', issue.fields.status.id) self.vprint('issue.fields.status.name:', issue.fields.status.name) jira_status_id = issue.fields.status.name.title() self.vprint('jira_status_id:', jira_status_id) next_transition_name = self.env.deploy_workflow.get( jira_status_id) self.vprint('next_transition_name:', next_transition_name) next_transition_id = transition_to_id.get(next_transition_name) self.vprint('next_transition_id:', next_transition_id) if next_transition_name: if issue.fields.assignee: if issue.fields.assignee.raw: assignee_name = issue.fields.assignee.name else: # Get assignee name directly # https://community.atlassian.com/t5/Jira-questions/Jira-in-Python-issue-fields-reporter-name- # errors-with-TypeError/qaq-p/937924 assignee_name = issue.fields.assignee._session[ 'name'] else: assignee_name = None # Get new assignee by status new_assignee = self.env.assignee_by_status.get( #issue.fields.status.name.title(), next_transition_name, assignee_name, ) # If assigning to reporter, get reporter name. if new_assignee == 'reporter': if issue.fields.reporter.raw: new_assignee = issue.fields.reporter.name else: # Get reporter name directly # https://community.atlassian.com/t5/Jira-questions/Jira-in-Python-issue-fields-reporter-name- # errors-with-TypeError/qaq-p/937924 new_assignee = issue.fields.reporter._session[ 'name'] print( 'Updating ticket %s to status %s (%s) and assigning it to %s.' % (ticket, next_transition_name, next_transition_id, new_assignee)) if not self.dryrun: if next_transition_id: try: jira.transition_issue(issue, next_transition_id) recheck = True except AttributeError as e: print( 'Unable to transition ticket %s to %s: %s' % (ticket, next_transition_name, e), file=sys.stderr) traceback.print_exc() # Note assignment should happen after transition, since the assignment may # effect remove transitions that we need. try: if new_assignee: print('Assigning ticket %s to %s.' % (ticket, new_assignee)) jira.assign_issue(issue, new_assignee) else: print('No new assignee found.') except JIRAError as e: print('Unable to reassign ticket %s to %s: %s' % (ticket, new_assignee, e), file=sys.stderr) else: recheck = False print( 'No transitions found for ticket %s currently in status "%s".' % (ticket, issue.fields.status.name)) if not recheck: break
only_states = only_states or [] <<<<<<< HEAD if any(isinstance(new_state, ignored) for ignored in ignore_states): ======= if any([isinstance(new_state, ignored) for ignored in ignore_states]): >>>>>>> prefect clone return new_state if only_states and not any( [isinstance(new_state, included) for included in only_states] ): return new_state summary_text = str(jira_message_formatter(tracked_obj, new_state)) options["summary"] = summary_text jira = JIRA(basic_auth=(username, password), options={"server": server_URL}) created = jira.create_issue(options) if not created: raise ValueError("Creating Jira Issue for {} failed".format(tracked_obj)) if assignee: assigned = jira.assign_issue(created, assignee) if not assigned: raise ValueError("Assigning Jira issue for {} failed".format(tracked_obj)) return new_state
class jiramenu(): user = None project = None auth = None config = None debug = False r = Rofi() issues = [] rofi_list = [] def __init__(self, config, debug): self.config = config self.r.status("starting jiramenu") try: self.auth = JIRA(config['JIRA']['url'], basic_auth=(config['JIRA']['user'], config['JIRA']['password'])) except Exception as error: self.r.exit_with_error(str(error)) self.debug = debug def log(self, text): if not self.debug: return print(text) def show(self, user): self.user = user self.project = self.config['JIRA']['project'] if user: self.log(f"show issues for: {self.user}") query = self.config['JIRA']['query'] if user: query += f" and assignee = '{user}'" if self.project: query += f" and project = '{self.project}'" self.log(f"Query: {query}") if not self.issues: self.issues = self.auth.search_issues(query) self.boards = self.auth.boards() if not self.rofi_list: if user: self.rofi_list.append("> all") else: self.rofi_list.append("> mine") self.issues.sort(key=lambda x: x.fields.status.id, reverse=False) for issue in self.issues: labels = '' if len(issue.fields.labels): labels = '(' for idx, label in enumerate(issue.fields.labels): labels += label if idx != len(issue.fields.labels) -1: labels += ', ' labels += ')' issuetext = '' issueassignee = '' initials = ' ' if issue.fields.assignee: issueassignee = issue.fields.assignee.displayName initials = ''.join([x[0].upper() for x in issueassignee.split(' ')]) if issue.fields.status.id == str(3): #id:3 = Work in Progress issuetext = '{WIP}' issuekey = issue.key issuekey = "{:<9}".format(issuekey) status = "{:<24}".format(issue.fields.status.name) issueassignee = "{:<20}".format(issueassignee) issuetext += f'{issuekey} {status} {initials} {labels} {issue.fields.summary}' self.rofi_list.append(issuetext) # print active query plus number of results on top index, key = self.r.select(f'{query}[{len(self.rofi_list)}]', self.rofi_list, rofi_args=['-i'], width=100) del key if index < 0: exit(1) if index == 0: self.issues = [] self.rofi_list = [] if user: self.show(None) else: self.show(self.config['JIRA']['user']) return self.show_details(index, user) def addComment(self, ticket_number): comment = self.r.text_entry("Content of the comment:") if comment: # replace @user with [~user] comment = re.sub(r"@(\w+)", r"[~\1]", comment) self.auth.add_comment(ticket_number, comment) def show_details(self, index, user): inputIndex = index # ticket_number = re.match("IMP-([1-9]|[1-9][0-9])+", self.rofi_list[index]).group(0) issue = self.issues[index-1] ticket_number = issue.key summary = '-'.join(issue.fields.summary.split(' ')) branch_name= ticket_number + '-' + summary[:33] self.log("[details]" + ticket_number) issue_description = issue.fields.description output = [] output.append("> show in browser") output.append("") output.append(f"> copy branch ({branch_name})") output.append("") output.append("Status: " + self.issues[index - 1].fields.status.name) # output.append("Description: " + issue_description) description = [] if issue_description: description = issue_description.split('\n') for item in description: output.append(item) if self.auth.comments(ticket_number): comment_ids = self.auth.comments(ticket_number) for comment_id in comment_ids: self.log("comment_id: " + str(comment_id)) commentauthor = self.auth.comment(ticket_number, comment_id).author.displayName + ':' output.append(commentauthor) commenttext = self.auth.comment(ticket_number, comment_id).body commenttext = commenttext.split('\n') for line in commenttext: output.append(line) else: output.append("no comments") output.append("") output.append("> add comment") output.append("") if self.issues[index - 1].fields.assignee: output.append("assigned to: " + self.issues[index - 1].fields.assignee.displayName) else: output.append("> assign to me") # if self.issues[index - 1].fields.status.id == str(3): # WIP # output.append(">>in review") # else: # output.append(">>start progress") output.append("") output.append('< back') index, key = self.r.select(ticket_number, output, width=100) if index in [-1, len(output) - 1]: self.show(user) return # if index == len(output) - 2: # move issue to 'In Review' # self.log("[status]"+self.issues[inputIndex - 1].fields.status.name) # self.log("[transitions]") # self.log(self.auth.transitions(ticket_number)) # if self.issues[inputIndex - 1].fields.status.id == str(3): # WIP # for trans in self.auth.transitions(ticket_number): # if trans['name'] == "in Review": # self.log("move to 'in Review'") # self.auth.transition_issue(ticket_number, trans['id']) # # else: # for trans in self.auth.transitions(ticket_number): # if trans['name'] == "Start Progress": # self.log("move to 'Start Progress'") # self.auth.transition_issue(ticket_number, trans['id']) # self.show_details(inputIndex, user) # return if index == len(output) - 4: # add comment self.log("[addComment]") self.addComment(ticket_number) self.show_details(inputIndex, user) return if index == len(output) - 3: # assign to me self.log("[assign to me]") self.auth.assign_issue(ticket_number, self.config['JIRA']['user']) self.show_details(inputIndex, user) return if index == 2: pyperclip.copy(branch_name) return # if index in [3, 4]: # Popen(['notify-send', issue_description, '-t', '30000']) # self.show_details(inputIndex, user) # return # show in browser self.log("[show in browser]") uri = self.auth.issue(ticket_number).permalink() Popen(['nohup', self.config['JIRA']['browser'], uri], stdout=DEVNULL, stderr=DEVNULL)
}, 'priority': { 'name': 'Blocker' }, 'fixVersions': [{ "name": jbds_fixversion }], 'components': [{ "name": "installer" }], 'labels': ["task"], } rootJBDS = jira.create_issue(fields=rootJBDS_dict) componentLead = defaultAssignee() try: jira.assign_issue(rootJBDS, componentLead) except: print "[WARNING] Unexpected error! User {0} tried to assign {1} to {2}: {3}".format( options.usernameJIRA, rootJBDS, componentLead, sys.exc_info()[0]) print("Task JIRA created for this milestone include:") print("") print("JBDS : " + jiraserver + '/browse/' + rootJBDS.key + " => " + componentLead) rootJBIDE_dict = { 'project': { 'key': 'JBIDE' }, 'summary':
}, 'priority': { 'name': 'Blocker' }, 'fixVersions': [{ "name": jbds_fixversion }], 'components': [{ "name": "installer" }], 'labels': ["task"], } rootJBDS = jira.create_issue(fields=rootJBDS_dict) installerLead = queryComponentLead(CLJBDS, 'installer', 0) try: jira.assign_issue(rootJBDS, installerLead) except: if (not options.jiraonly): print "[WARNING] Unexpected error! User {0} tried to assign {1} to {2}: {3}".format( options.usernameJIRA, rootJBDS, installerLead, sys.exc_info()[0]) if (options.jiraonly): print(rootJBDS.key) else: print("Task JIRA created for this milestone include:") print("") print("JBDS : " + jiraserver + '/browse/' + rootJBDS.key + " => " + installerLead) rootJBIDE_dict = { 'project': {
class JiraSender(object): tpl = Template('\n'.join( [ '*Current State*: $state', '*Host*: $host_name', '*Service*: $service_name', '*Output*: $output', ] )) def __init__(self): self.rest_api_user = settings.JIRA_USER_NAME self.rest_api_password = settings.JIRA_USER_PASSWORD self.rest_api_url = settings.JIRA_ENDPOINT self.jira = JIRA(basic_auth=(self.rest_api_user, self.rest_api_password), options={'server': self.rest_api_url}, timeout=30) def __get_param(self, data: dict, name: str, default_value=None): val = data.get(name) if val is None: val = default_value return val def create_ticket(self, project: str, data: dict): host_name = self.__get_param(data, 'host_name') service_name = self.__get_param(data, 'service_name') status = self.__get_param(data, 'status') service_state = status.name if status is not None else 'FAIL' output = self.__get_param(data, 'output', '') assignee = self.__get_param(data, 'assignee', []) watchers = self.__get_param(data, 'watchers', []) tags = self.__get_param(data, 'tags', []) priority = self.__get_param(data, 'priority', settings.JIRA_PRIORITY) issue_type = self.__get_param(data, 'issue_type', settings.JIRA_ISSUE_TYPE) transition_resolved_id = self.__get_param(data, 'transition_resolved_id', settings.JIRA_TRANSITION_RESOLVED_ID) close_when_restore = self.__get_param(data, 'close_when_restore', settings.JIRA_CLOSE_WHEN_RESTORE) post_comments = self.__get_param(data, 'post_comments', settings.JIRA_POST_COMMENTS) triggering_status = self.__get_param(data, 'triggering_status', settings.JIRA_TRIGGERING_STATUS) try: if isinstance(watchers, str): watchers_list = re.findall(r'[^,\s]+', watchers) elif isinstance(watchers, list): watchers_list = watchers else: watchers_list = [] if isinstance(tags, str): labels = re.findall(r'[^,\s]+', tags) elif isinstance(tags, list): labels = tags else: labels = [] labels.append('nogios') subject = 'NOGIOS: {} {}'.format(host_name, service_name) search_filter = 'summary ~ "{}" AND status not in (Resolved, Closed, Done) AND project="{}"'\ .format(subject, project) existing_issues = self.jira.search_issues(search_filter) issue_dict = { 'project': project, 'summary': subject, 'description': self.tpl.substitute({ 'host_name': host_name, 'service_name': service_name, 'state': service_state, 'output': output, }), 'issuetype': {'name': issue_type}, 'priority': {'name': priority} } if existing_issues is None or len(existing_issues) == 0: if service_state == triggering_status or service_state == settings.JIRA_TRIGGERING_STATUS: new_issue = self.jira.create_issue(fields=issue_dict) try: new_issue.update(fields={"labels": labels}) except JIRAError as e: print("Error: unable to add labels to a Jira ticket:", str(e)) for watcher in watchers_list: try: self.jira.add_watcher(new_issue.id, watcher) except JIRAError as e: print("Error: unable to add watchers to a Jira ticket:", str(e)) self.__add_comments(post_comments, new_issue.key, issue_dict['description']) if re.match(r'^[\S]+\@[\S]+$', assignee) is not None: self.jira.assign_issue(new_issue, assignee) else: current_issue = existing_issues[0] if service_state == settings.JIRA_TYPE_OK and current_issue.fields.assignee is None: self.__add_comments(post_comments, current_issue.key, issue_dict['description']) if close_when_restore: self.jira.transition_issue(current_issue.key, transition=transition_resolved_id, # resolution={'id': RESOLUTION_ID} ) else: self.__add_comments(post_comments, current_issue.key, issue_dict['description']) except Exception as ex: print("ERROR: unable to create Jira ticket:", ex) def __add_comments(self, post_comments, issue_key: str, comment_text: str): if post_comments: self.jira.add_comment(issue_key, comment_text)
def jira_notifier( tracked_obj: TrackedObjectType, old_state: "prefect.engine.state.State", new_state: "prefect.engine.state.State", ignore_states: list = None, only_states: list = None, server_URL: str = None, options: dict = {}, assignee: str = "-1", ) -> "prefect.engine.state.State": """ Jira Notifier requires a Jira account and API token. The API token can be created at: https://id.atlassian.com/manage/api-tokens The Jira account username ('JIRAUSER'), API token ('JIRATOKEN') should be set as part of a 'JIRASECRETS' object in Prefect Secrets. An example 'JIRASECRETS' object looks like this: ``` JIRASECRETS = { JIRATOKEN = "XXXXXXXXX", JIRAUSER = "******", JIRASERVER = "https://???.atlassian.net", JIRAPROJECT = "TEST" } ``` The server URL can be set as part of the 'JIRASECRETS' object ('JIRASERVER') or passed to the jira notifier state handler as the "server_URL" argument. Jira Notifier works as a standalone state handler, or can be called from within a custom state handler. This function is curried meaning that it can be called multiple times to partially bind any keyword arguments (see example below). Jira Notifier creates a new ticket with the information about the task or flow it is bound to when that task or flow is in a specific state. (For example it will create a ticket to tell you that the flow you set it on is in a failed state.) You should use the options dictionary to set the project name and issue type. You can use the "assignee" argument to assign that ticket to a specific member of your team. Args: - tracked_obj (Task or Flow): Task or Flow object the handler is registered with - old_state (State): previous state of tracked object - new_state (State): new state of tracked object - options (Dictionary): Must inlucde a 'project' key and an 'issuetype' key (e.g. options = {'project': 'TEST', 'issuetype': {'name': 'task'}}). For jira service desk tickets, the issue type should use the request type id e.g. 'issuetype': {'id': '10010'}. A description can be added using the key 'description'. Custom fields can also be added e.g. 'customfield_10017': 'SDTS/flowdown' - ignore_states ([State], optional): list of `State` classes to ignore, e.g., `[Running, Scheduled]`. If `new_state` is an instance of one of the passed states, no notification will occur. - only_states ([State], optional): similar to `ignore_states`, but instead _only_ notifies you if the Task / Flow is in a state from the provided list of `State` classes - server_URL (String): The URL of your atlassian account e.g. "https://test.atlassian.net". Can also be set as a Prefect Secret. - assignee: the atlassian username of the person you want to assign the ticket to. Defaults to "automatic" if this is not set. Returns: - State: the `new_state` object that was provided Raises: - ValueError: if the jira ticket creation or assignment fails for any reason Example: ```python from prefect import task from prefect.utilities.jira_notification import jira_notifier @task(state_handlers=[jira_notifier(only_states=[Failed], options={'project': 'TEST', 'issuetype': {'name': 'Task'}}, assignee='tester')]) # uses currying def add(x, y): return x + y ``` """ jira_credentials = cast(dict, prefect.client.Secret("JIRASECRETS").get()) username = jira_credentials["JIRAUSER"] password = jira_credentials["JIRATOKEN"] if not server_URL: server_URL = jira_credentials["JIRASERVER"] ignore_states = ignore_states or [] only_states = only_states or [] if any([isinstance(new_state, ignored) for ignored in ignore_states]): return new_state if only_states and not any( [isinstance(new_state, included) for included in only_states]): return new_state summary_text = str(jira_message_formatter(tracked_obj, new_state)) options["summary"] = summary_text jira = JIRA(basic_auth=(username, password), options={"server": server_URL}) created = jira.create_issue(options) if not created: raise ValueError( "Creating Jira Issue for {} failed".format(tracked_obj)) if assignee: assigned = jira.assign_issue(created, assignee) if not assigned: raise ValueError( "Assigning Jira issue for {} failed".format(tracked_obj)) return new_state
def update_tickets_from_git(self, from_commit=None, to_commit=None): """ Find all ticket numbers and update their status in Jira. Run during a deployment. Looks at all commits between now and the last deployment. """ from jira import JIRA, JIRAError from burlap.git import gittracker, CURRENT_COMMIT r = self.local_renderer # get_current_commit = gittracker.get_current_commit # GITTRACKER = gittracker.name.upper() # Ensure this is only run once per role. if self.genv.host_string != self.genv.hosts[-1]: self.vprint('Not first server. Aborting.') return self.vprint('self.env.update_from_git:', self.env.update_from_git) self.vprint('self.genv.jirahelper_update_from_git:', self.genv.jirahelper_update_from_git) if not self.env.update_from_git: self.vprint('Update from git disabled. Aborting.') return if not self.env.ticket_pattern: self.vprint('No ticket pattern defined. Aborting.') return if not self.env.basic_auth_username or not self.env.basic_auth_password: self.vprint('Username or password not given. Aborting.') return # During a deployment, we should be given these, but for testing, # lookup the diffs dynamically. last = gittracker.last_manifest current = gittracker.current_manifest last_commit = from_commit or last.current_commit#[CURRENT_COMMIT] print('last_commit:', last_commit) current_commit = to_commit or current[CURRENT_COMMIT] print('current_commit:', current_commit) if not last_commit or not current_commit: print('Missing commit ID. Aborting.') return self.vprint('-'*80) self.vprint('last.keys:', last.keys()) self.vprint('-'*80) self.vprint('current.keys:', current.keys()) # try: # last_commit = last['GITTRACKER']['current_commit'] # except KeyError: # return # current_commit = current['GITTRACKER']['current_commit'] # Find all tickets deployed between last deployment and now. tickets = self.get_tickets_between_commits(current_commit, last_commit) self.vprint('tickets:', tickets) # Update all tickets in Jira. jira = JIRA({ 'server': self.env.server }, basic_auth=(self.env.basic_auth_username, self.env.basic_auth_password)) for ticket in tickets: # Mention this Jira updated. r.env.role = r.genv.ROLE.lower() comment = r.format(self.env.ticket_update_message_template) print('Commenting on ticket %s: %s' % (ticket, comment)) if not self.dryrun: jira.add_comment(ticket, comment) # Update ticket status. recheck = False while 1: print('Looking up jira ticket %s...' % ticket) issue = jira.issue(ticket) self.vprint('Ticket %s retrieved.' % ticket) transition_to_id = dict((t['name'], t['id']) for t in jira.transitions(issue)) self.vprint('%i allowable transitions found:' % len(transition_to_id)) if self.verbose: pprint(transition_to_id) self.vprint('issue.fields.status.id:', issue.fields.status.id) self.vprint('issue.fields.status.name:', issue.fields.status.name) jira_status_id = issue.fields.status.name.title() self.vprint('jira_status_id:', jira_status_id) next_transition_name = self.env.deploy_workflow.get(jira_status_id) self.vprint('next_transition_name:', next_transition_name) next_transition_id = transition_to_id.get(next_transition_name) self.vprint('next_transition_id:', next_transition_id) if next_transition_name: if issue.fields.assignee: if issue.fields.assignee.raw: assignee_name = issue.fields.assignee.name else: # Get assignee name directly # https://community.atlassian.com/t5/Jira-questions/Jira-in-Python-issue-fields-reporter-name- # errors-with-TypeError/qaq-p/937924 assignee_name = issue.fields.assignee._session['name'] else: assignee_name = None # Get new assignee by status new_assignee = self.env.assignee_by_status.get( #issue.fields.status.name.title(), next_transition_name, assignee_name, ) # If assigning to reporter, get reporter name. if new_assignee == 'reporter': if issue.fields.reporter.raw: new_assignee = issue.fields.reporter.name else: # Get reporter name directly # https://community.atlassian.com/t5/Jira-questions/Jira-in-Python-issue-fields-reporter-name- # errors-with-TypeError/qaq-p/937924 new_assignee = issue.fields.reporter._session['name'] print('Updating ticket %s to status %s (%s) and assigning it to %s.' % (ticket, next_transition_name, next_transition_id, new_assignee)) if not self.dryrun: if next_transition_id: try: jira.transition_issue(issue, next_transition_id) recheck = True except AttributeError as e: print('Unable to transition ticket %s to %s: %s' % (ticket, next_transition_name, e), file=sys.stderr) traceback.print_exc() # Note assignment should happen after transition, since the assignment may # effect remove transitions that we need. try: if new_assignee: print('Assigning ticket %s to %s.' % (ticket, new_assignee)) jira.assign_issue(issue, new_assignee) else: print('No new assignee found.') except JIRAError as e: print('Unable to reassign ticket %s to %s: %s' % (ticket, new_assignee, e), file=sys.stderr) else: recheck = False print('No transitions found for ticket %s currently in status "%s".' % (ticket, issue.fields.status.name)) if not recheck: break
server.login(login, password) server.sendmail(from_addr, to_addr_list, msg.as_string()) server.quit() while True: all_open_issues = jira.search_issues( 'assignee = EMPTY AND (category = IG-Ankara OR category = YY-Ankara)', maxResults=False ) if len(all_open_issues) > 0: for i in range(0, len(all_open_issues)): issue = str(all_open_issues[i].key.split('-')[0]) + \ ' ' + str(all_open_issues[i].fields.summary) assignee_ = cl.classify(issue) print(all_open_issues[i].key, ' can be assigned to : ', assignee_) jira.assign_issue(all_open_issues[i].key, assignee_) ts = d.datetime.now().strftime('%Y/%m/%d') cur.execute("INSERT INTO auto_assigned (i_key ,assignee,timestamp_) VALUES ("+f"'{all_open_issues[i].key}'"+ ","+ f"'{assignee_}'"+","+f"'{ts}'"+")") conn.commit() comment = jira.add_comment(all_open_issues[i], 'This issue is automatically assigned.', visibility={'type': 'role', 'value': 'Administrators'}) # for admins only, total_time_lapse = time.time() - start_time cur_date = d.datetime.now().strftime('%Y-%m-%d %H:%M:%S') print(f"--- Total Time: {total_time_lapse} seconds ---") try: sendemail(from_addr='*****@*****.**', to_addr_list=['*****@*****.**'], cc_addr_list='', subject=str(all_open_issues[i].key) + " is assigned to: " + str(cl.classify(issue)), body=f"Total time lapsed : {total_time_lapse} seconds ---", login="******",
class JSprint(cmd.Cmd): jira = None __current_sprint = None def __init__(self): super().__init__() username = settings.get("jira_username") password = settings.get("jira_password") or getpass.getpass() options = { "server": settings.get("jira_url"), "agile_rest_path": "agile" } self.jira = JIRA(options, auth=(username, password)) @property def prompt(self): sprint = Style.BRIGHT + self.current_sprint.name + Style.RESET_ALL return f"JSprint [{sprint}] >>> " @property def current_sprint(self): if self.__current_sprint is None: self.__current_sprint = self.get_active_sprint() return self.__current_sprint @current_sprint.setter def current_sprint(self, value): self.__current_sprint = value def get_sprints(self, state: str = "active") -> List[Sprint]: return self.jira.sprints(settings.get("jira_board_id"), state=state) def get_active_sprint(self) -> Sprint: sprints = self.get_sprints(state="active") if len(sprints): # Use fisrt active sprint as default sprint = sorted(sprints, key=attrgetter("name"))[0] else: sprint = None return sprint # ------------------ # Set current sprint # ------------------ def help_use(self): print_help(""" use [sprint_id] Set the current sprint. If no `sprint_id` is passed the current active sprint will be used. """) @do_exception def do_use(self, line): # Parse arguments args = shlex.split(line) # Select sprint if len(args) == 0: sprint = self.get_active_sprint() if sprint is None: print("No active sprint") return else: sprint_id = get_sprint_id_from_number(args[0]) sprint = self.jira.sprint(sprint_id) print( f"Using sprint {Style.BRIGHT + sprint.name + Style.RESET_ALL} ({sprint.id})" ) self.current_sprint = sprint # ------------ # Show sprints # ------------ def help_sprints(self): print_help("List all the active and future sprints") def do_sps(self, line): return self.do_sprints(line) @do_exception def do_sprints(self, line): actives = self.get_sprints(state="active") futures = self.get_sprints(state="future") sprints = futures + actives sprints = sorted(sprints, key=attrgetter("name")) for sprint in sprints: name = sprint.name id_ = Style.BRIGHT + str(sprint.id) + Style.RESET_ALL state = ("*" if sprint.state == "active" else " ") + colored_sprint_state(sprint) print(f"{state} {name} ({id_})") # ----------- # Show sprint # ----------- def help_sprint(self): print_help(""" sprint [sprint_id] Show the issues in the sprint grouped by assignee. If no `sprint_id` is given use the current selected sprint. """) def do_sp(self, line): return self.do_sprint(line) @do_exception def do_sprint(self, line): def group_by_assignee(acc, issue: Issue) -> Dict[str, Iterable[Issue]]: assignee = get_assignee_from_issue(issue) acc.setdefault(assignee, []).append(issue) return acc # Parse arguments args = shlex.split(line) # Show sprint if len(args) == 0: sprint = self.current_sprint else: sprint_id = get_sprint_id_from_number(args[0]) sprint = self.jira.sprint(sprint_id) print(f"Displaying sprint {sprint.name}") # Show issue by assignee jira_project = settings.get("jira_project") team_members = settings.get("team_members") team_labels = settings.get("team_labels") jql = f"project = '{jira_project}' AND sprint = {sprint.id}" if team_members: jql += f" AND (assignee IS NULL or assignee IN {tuple(team_members)})" if team_labels: jql += f" AND (labels IS NULL or labels IN {tuple(team_labels)})" issues = self.jira.search_issues(jql) if len(issues): permalink_padding = max(len(i.permalink()) for i in issues) status_padding = max(len(i.fields.status.name) for i in issues) issue_key_padding = max(len(i.key) for i in issues) else: permalink_padding = status_padding = issue_key_padding = 0 issues_by_user = functools.reduce(group_by_assignee, issues, {}) assignees = sorted(issues_by_user.keys()) for i, assignee in enumerate(assignees): user_issues = issues_by_user[assignee] user_issues = sorted(user_issues, key=attrgetter("id")) print(Style.BRIGHT + f"{assignee}:" + Style.RESET_ALL) for issue in user_issues: issue_key = Style.BRIGHT + issue.key.ljust( issue_key_padding) + Style.RESET_ALL url = issue.permalink().ljust(permalink_padding) status = colored_issue_status(issue, status_padding) summary = Style.BRIGHT + issue.fields.summary + Style.RESET_ALL print(f"{status} - {issue_key} ({url}) {summary}") if i != (len(assignees) - 1): print() # --------------------- # Show sprint as report # --------------------- def help_report(self): print_help(""" sprint [sprint_id] Show the issues in the sprint grouped by user for reporting. If no `sprint_id` is given use the current selected sprint. The difference with the `sprint` command is that the grouping by user is done by whom actually worked on the issue instead of just the assignee. """) def do_rp(self, line): return self.do_report(line) """ @do_exception def do_report(self, line): def group_by_developers(acc, issue: Issue) -> Dict[str, Iterable[Issue]]: developers = get_developers_from_issue(issue) for developer in developers: acc.setdefault(developer.displayName, []).append(issue) return acc def is_developer_in_team(team_members: List[str], issue: Issue) -> bool: developers = get_developers_from_issue(issue) for developer in developers: if developer.name in team_members: return True return False # Parse arguments args = shlex.split(line) # Show sprint if len(args) == 0: sprint = self.current_sprint else: sprint_id = get_sprint_id_from_number(args[0]) sprint = self.jira.sprint(sprint_id) print(f"Displaying sprint {sprint.name}") # Show issue by developers jira_project = settings.get("jira_project") team_members = settings.get("team_members") jql = f"project = '{jira_project}' AND sprint = {sprint.id}" issues = self.jira.search_issues(jql) issues = (i for i in issues if is_developer_in_team(team_members, i)) issues_by_developer = functools.reduce(group_by_developers, issues, {}) developers = sorted(set(issues_by_developer.keys())) for i, developer in enumerate(developers): developer_issues = issues_by_developer[developer] developer_issues = sorted(developer_issues, key=attrgetter("id")) print(Style.BRIGHT + f"{developer}:" + Style.RESET_ALL) for issue in developer_issues: url = issue.permalink() summary = Style.BRIGHT + issue.fields.summary + Style.RESET_ALL print(f"- {url} {summary}") if i != (len(developers) - 1): print() """ @do_exception def do_report(self, line): def group_by_assignee(acc, issue: Issue) -> Dict[str, Iterable[Issue]]: assignee = get_assignee_from_issue(issue) acc.setdefault(assignee, []).append(issue) return acc # Parse arguments args = shlex.split(line) # Show sprint if len(args) == 0: sprint = self.current_sprint else: sprint_id = get_sprint_id_from_number(args[0]) sprint = self.jira.sprint(sprint_id) print(f"Displaying sprint {sprint.name}") # Show issue by assignee jira_project = settings.get("jira_project") team_members = settings.get("team_members") team_labels = settings.get("team_labels") jql = f"project = '{jira_project}' AND sprint = {sprint.id} AND resolution = 'Unresolved'" if team_members: jql += f" AND (assignee IS NULL or assignee IN {tuple(team_members)})" if team_labels: jql += f" AND (labels IS NULL or labels IN {tuple(team_labels)})" issues = self.jira.search_issues(jql) issues_by_user = functools.reduce(group_by_assignee, issues, {}) assignees = sorted(issues_by_user.keys()) status_padding = max(len(i.fields.status.name) for i in issues) if len(issues) else 0 for i, assignee in enumerate(assignees): user_issues = issues_by_user[assignee] user_issues = sorted(user_issues, key=attrgetter("fields.customfield_14560")) print(Style.BRIGHT + f"{assignee}:" + Style.RESET_ALL) for issue in user_issues: url = issue.permalink() status = colored_issue_status(issue, status_padding) summary = Style.BRIGHT + issue.fields.summary + Style.RESET_ALL print(f"- {url} ({status}) {summary}") if i != (len(assignees) - 1): print() # -------------------- # Assign user to issue # -------------------- def help_assign(self): print_help(""" assign <issue_number> <assignee> Assign the issue to an user. """) def complete_a(self, *args): return self.complete_assign(*args) def do_a(self, *args): return self.do_assign(*args) @do_exception def complete_assign(self, text, line, begin_index, end_index): s = text.lower() matches = filter(lambda x: x.startswith(s), settings.get("team_members")) return list(matches) @do_exception def do_assign(self, line): # Parse args args = shlex.split(line) if len(args) < 2: print("Need two arguments: issue number and assignee name") return # Assign issue issue_key = get_issue_key_from_number(args[0]) assignee = args[1] self.jira.assign_issue(issue_key, assignee) # ---------------------- # Unassign user to issue # ---------------------- def help_unassign(self): print_help(""" unassign <issue_number> Remove assignee from the given issue. """) def do_u(self, line): return self.do_unassign(line) @do_exception def do_unassign(self, line): # Parse args args = shlex.split(line) if len(args) == 0: print("Needs at least an issue number") return # Unassign issue issue_key = get_issue_key_from_number(args[0]) self.jira.assign_issue(issue_key, None) # --------------------------- # Add issue to current sprint # --------------------------- def help_add(self): print_help(""" add <issue_number> Add issue to the current sprint. """) @do_exception def do_add(self, line): # Parse args args = shlex.split(line) if len(args) == 0: print("Needs at least an issue number") return # Add issue to sprint issue_keys = [get_issue_key_from_number(arg) for arg in args] sprint = self.current_sprint self.jira.add_issues_to_sprint(sprint.id, issue_keys) # ----------------------------- # Move or add issue to a sprint # ----------------------------- def help_move(self): print_help(""" move <sprint_id> <issue_number> Move an issue into a sprint. """) def do_mv(self, line): return self.do_move(line) @do_exception def do_move(self, line): # Parse args args = shlex.split(line) if len(args) < 2: print("Needs a sprint ID and at least one issue number") return # Move issues sprint_id = get_sprint_id_from_number(args[0]) issue_keys = [get_issue_key_from_number(arg) for arg in args] self.jira.add_issues_to_sprint(sprint_id, issue_keys) # --------------- # Show issue info # --------------- def help_show(self): print_help(""" show <issue_number> Show informations about the given issue number """) def do_sh(self, line): return self.do_show(line) @do_exception def do_show(self, line): # Parse args args = shlex.split(line) if len(args) < 1: print("Needs at least one issue number") return # Show issue stats issue_key = get_issue_key_from_number(args[0]) issue = self.jira.issue(issue_key, "assignee,status,summary,customfield_11360") status = colored_issue_status(issue) up_in_build = get_up_in_build_form_issue(issue) print( f"Issue : {Style.BRIGHT + issue.key + Style.RESET_ALL} ({issue.permalink()})" ) print(f"Status : {Style.BRIGHT + status + Style.RESET_ALL}") print( f"Assignee : {Style.BRIGHT + get_assignee_from_issue(issue) + Style.RESET_ALL}" ) print(f"Up in build : {Style.BRIGHT + up_in_build + Style.RESET_ALL}") print( f"Summary : {Style.BRIGHT + issue.fields.summary + Style.RESET_ALL}" ) # ----------------------- # Move issue into backlog # ----------------------- def help_backlog(self): print_help(""" backlog <issue_number> Move an issue out of the sprint and back into backlog. """) def do_bk(self, line): return self.do_backlog(line) @do_exception def do_backlog(self, line): # Parse args args = shlex.split(line) if len(args) < 1: print("Needs at least one issue number") return # Get active sprint issue_keys = [get_issue_key_from_number(arg) for arg in args] # Move issue into backlog self.jira.move_to_backlog(issue_keys) # ---------------- # Leave the REPL # ---------------- def do_quit(self, line): return True def do_q(self, args): return True def do_EOF(self, line): return True
failureDetails = failureDetails + '{code:title=' + testurl + '' + className_re + '/' + name_re + '}\n' failureDetails = failureDetails + prettyXML(s) failureDetails = failureDetails + '\n{code}\n\n' #print failureDetails rootJBIDE_dict = { 'project' : { 'key': 'JBIDE' }, 'summary' : str(len(testcaselist)) + ' Test Failure(s) in JBIDE ' + jbide_affectedversion + ' for ' + component + ' component', 'description' : failureSummary + failureDetails, 'issuetype' : { 'name' : 'Task' }, 'priority' : { 'name' :'Critical'}, 'versions' : [{ "name" : jbide_affectedversion }], 'components' : [{ "name" : component }], 'labels' : [ "testfailure" ] } jira = JIRA(options={'server':jiraserver}, basic_auth=(options.usernameJIRA, options.passwordJIRA)) CLJBIDE = jira.project_components(jira.project('JBIDE')) # full list of components in JBIDE rootJBIDE = jira.create_issue(fields=rootJBIDE_dict) componentLead = queryComponentLead(CLJBIDE, component, 0) try: jira.assign_issue(rootJBIDE, componentLead) except: print "[WARNING] Unexpected error! User {0} tried to assign {1} to {2}: {3}".format(options.usernameJIRA, rootJBIDE, componentLead, sys.exc_info()[0]) accept = raw_input("\nAccept new JIRA " + jiraserver + '/browse/' + rootJBIDE.key + " => " + componentLead + " ? [Y/n] ") if accept.capitalize() in ["N"] : rootJBIDE.delete() # see JIRA_components listing in components.py # Sample usage: see createTestFailureJIRA.py.examples.txt
def update_tickets_from_git(last=None, current=None): """ Run during a deployment. Looks at all commits between now and the last deployment. Finds all ticket numbers and updates their status in Jira. """ from jira import JIRA, JIRAError from burlap.deploy import get_last_current_diffs from burlap.git import gittracker get_current_commit = gittracker.get_current_commit GITTRACKER = gittracker.name.upper() dryrun = common.get_dryrun() verbose = common.get_verbose() # Ensure this is only run once per role. if env.host_string != env.hosts[-1]: return if not env.jira_update_from_git: return if not env.jira_ticket_pattern: return if not env.jira_basic_auth_username or not env.jira_basic_auth_password: return # During a deployment, we should be given these, but for testing, # lookup the diffs dynamically. if not last or not current: last, current = get_last_current_diffs(GITTRACKER) if verbose: print('-' * 80) print('last.keys:', last.keys()) print('-' * 80) print('current.keys:', current.keys()) try: last_commit = last['GITTRACKER']['current_commit'] except KeyError: return current_commit = current['GITTRACKER']['current_commit'] # Find all tickets deployed between last deployment and now. tickets = get_tickets_between_commits(current_commit, last_commit) if verbose: print('tickets:', tickets) # Update all tickets in Jira. jira = JIRA({'server': env.jira_server}, basic_auth=(env.jira_basic_auth_username, env.jira_basic_auth_password)) for ticket in tickets: # Mention this Jira updated. comment = env.jira_ticket_update_message_template % dict( role=env.ROLE.lower()) print('Commenting on ticket %s: %s' % (ticket, comment)) if not dryrun: jira.add_comment(ticket, comment) # Update ticket status. recheck = False while 1: print('Looking up jira ticket %s...' % ticket) issue = jira.issue(ticket) print('Ticket %s retrieved.' % ticket) transition_to_id = dict( (t['name'], t['id']) for t in jira.transitions(issue)) print('%i allowable transitions found: %s' % (len(transition_to_id), ', '.join(transition_to_id.keys()))) next_transition_name = env.jira_deploy_workflow.get( issue.fields.status.name.title()) next_transition_id = transition_to_id.get(next_transition_name) if next_transition_name: new_fields = {} # print('jira_assignee_by_status:', env.jira_assignee_by_status, issue.fields.status.name.title() new_assignee = env.jira_assignee_by_status.get( #issue.fields.status.name.title(), next_transition_name, issue.fields.assignee.name, ) if new_assignee == 'reporter': new_assignee = issue.fields.reporter.name # print('new_assignee:', new_assignee) print('Updating ticket %s to status %s and assigning it to %s.' \ % (ticket, next_transition_name, new_assignee)) if not dryrun: try: jira.transition_issue( issue, next_transition_id, ) recheck = True except AttributeError as e: print('Unable to transition ticket %s to %s: %s' \ % (ticket, next_transition_name, e), file=sys.stderr) # Note assignment should happen after transition, since the assignment may # effect remove transitions that we need. try: if new_assignee: print('Assigning ticket %s to %s.' % (ticket, new_assignee)) jira.assign_issue(issue, new_assignee) else: print('No new assignee found.') except JIRAError as e: print('Unable to reassign ticket %s to %s: %s' \ % (ticket, new_assignee, e), file=sys.stderr) else: recheck = False print('No transitions found for ticket %s currently in status "%s".' \ % (ticket, issue.fields.status.name)) if not recheck: break
import sys sys.path.append("\\\\older\\migration\\python\\lib\\3.4\\site-packages") from jira import JIRA jira = JIRA(basic_auth=('selvakuj', 'xxxxx'), server='http://gxxxx.xx:8090') for i in range(1): summary = "XREF ticket -" + str(i) issue_dict = { 'project': { 'key': 'JIRA_JAVA' }, 'summary': summary, 'parent': { 'key': 'JIRA_JAVA-29' }, 'issuetype': { 'name': 'Sub-task' }, 'priority': { 'id': '3' }, 'customfield_10198': { 'value': 'mandatory' } } new_issue = jira.create_issue(fields=issue_dict) jira.assign_issue(new_issue, 'selvakuj') print(new_issue.key)
'customfield_17680' : { 'value' : 'Low' }, # complexity of change 'customfield_17681' : { 'value' : 'Low' }, # Pre-Testing 'customfield_17682' : { 'value' : 'Low' }, # Scope of Validation 'customfield_17683' : { 'value' : 'Low' }, # Rollback Plan 'customfield_17684' : { 'value' : 'Low' }, # Customer landscape impact 'customfield_16583' : {'value':'App', 'child': {'value':'Update/Upgrade'}}, # Category(s) 'components' : [{'name': 'JAM'}], #Components 'customfield_15282' : {'value':'No Data Protection Regulation'}, # Customer Data Protection 'customfield_10802' : { 'value' : dc_total }, # Data Center 'customfield_16590' : { 'id' : time_Zone },# DC Time Zone 'customfield_10842' : { 'id' : env_type }, # Environment Type 'customfield_16794' : {'value':'None'}, # Customer Impact 'customfield_17055' : {'value':'No'}, # CCM Notify 'customfield_17056' : { 'value' : 'Not Required' }, # Maintenance Page Required? 'customfield_17057' : { 'value' : 'No' }, # Pop up enable required? 'customfield_16814' : actual_date+ 'T11:30:00.000-0700', # requested Start 'customfield_16815' : actual_date+ 'T11:30:00.000-0700', # requested End 'description' : descript, # description 'customfield_17426' : test_details, # Pre-Test Details 'customfield_17427' : justification, # Business Justification 'customfield_17058' : imp_steps, # Implementation Steps 'customfield_16800' : back_steps, # Backout Steps 'customfield_16801' : validate, # Validation Steps 'customfield_16802' : { 'name' : 'svishwanath' }, # Validator 'customfield_17059' : [{ 'value' : 'TechOwn - JAM' }], #Tech Approver 17059 'customfield_17060' : [{ 'value' : 'BusOwn - JAM' }], # Impact/Impl Approver 17060 } new_issue = jira.create_issue(fields=values) jira.assign_issue(new_issue, 'sureshkumara') print new_issue.key
class JIRA_PROJECT(object): def __init__(self, server, project, basic_auth=()): self.server = server self.project = project self.basic_auth = basic_auth self._connect_to_jira() def _connect_to_jira(self): try: print 'Tyring to connect JIRA server: {} and project: {}...'.format(self.server, self.project) self.jira = JIRA(server=self.server, basic_auth=self.basic_auth) print 'JIRA server connected successfully...' except Exception as err: print 'JIRA Connection error' print err sys.exit(1) def get_defect_from_qc(self, qc_num): # print getattr(issue.fields, 'summary') # print getattr(issue.fields, '') if self.project is not 'TDETS': print 'Project is not TDETS' sys.exit(0) defects = self.jira.search_issues('project={}'.format(self.project), maxResults=5000) for defect in defects: print 'checking', defect.key #defect = self.jira.issue(defect, fields='assignee,summary,status,customfield_13625,comment') defect = self.jira.issue(defect.key, fields='customfield_13625,summary,status,assignee') if (defect.fields.customfield_13625) and (qc_num in defect.fields.customfield_13625): print defect.key print defect.fields.customfield_13625 print defect.fields.summary print defect.fields.status print defect.fields.assignee return defect.key else: print 'no matching QC found in TDETS' return None def get_my_defects(self): # print getattr(issue.fields, 'summary') # print getattr(issue.fields, 'customfield_13625') defects = self.jira.search_issues('project={} and assignee = currentUser()'.format(self.project)) list_defects = [] for defect in defects: defect = self.jira.issue(defect.key, fields='assignee,summary,status,customfield_13625,comment') if defect.fields.comment.comments: last_comment = defect.fields.comment.comments[-1].raw['body'] else: last_comment = 'No Comment Yet' qc_id = getattr('defect.fields', 'customfield_13625', 'NO QC ID') #qc_id=defect.fields.customfield_13625 defect_summary = DEFECT_SUMMARY(id=defect.key, qc_id=qc_id, summary=defect.fields.summary, status=defect.fields.status, assignee=defect.fields.assignee, last_comment=last_comment, ) list_defects.append(defect_summary) return list_defects def get_all_issues(self): pass def create_new_issue(self): pass def update_defect(self, defect, new_comment=None, new_assignee=None): #https://answers.atlassian.com/questions/8627641/update-custom-field-using-jira-python if new_comment: #how to check new comment is posted correctly comment = self.jira.add_comment(defect, new_comment) if isinstance(comment, jira.resources.Comment): print 'Posted Comment:' print comment.raw['body'] else: print 'Failed' return False if new_assignee: #update new assignee if not self.jira.assign_issue(defect, new_assignee): return False return True def get_defect_history(self, defect): # https://answers.atlassian.com/questions/64708/is-it-possible-to-get-the-issue-history-using-the-rest-api defect = self.jira.issue(defect, expand='changelog') for history in defect.changelog.histories: for item in history.items: if item.field == 'status': print 'Date:' + history.created + ' From:' + item.fromString + ' To:' + item.toString def update_issues_from_file(self, filename): pass
nnissuesquerythisversion = 'summary ~ "New and Noteworthy" AND ((project in (JBDS) and fixVersion = "' + jbds_fixversion + '") or (project in (JBIDE) and fixVersion = "' + jbide_fixversion + '")) ORDER BY key DESC' rootnn_description = 'This [query|' + nnsearch + '] contains the search for all N&N. See subtasks below.' rootnn_dict = { 'project' : { 'key' : 'JBIDE' }, 'summary' : 'Create New and Noteworthy for ' + jbide_fixversion, 'description' : rootnn_description, 'issuetype' : { 'name' : 'Task' }, 'priority' : { 'name' :'Blocker'}, 'fixVersions' : [{ "name" : jbide_fixversion }], 'components' : [{ "name" : "website" }] } rootnn = jira.create_issue(fields=rootnn_dict) componentLead = defaultAssignee() try: jira.assign_issue(rootnn, componentLead) except: print "[WARNING] Unexpected error! User {0} tried to assign {1} to {2}: {3}".format(options.usernameJIRA, rootnn, componentLead, sys.exc_info()[0]) print("JBoss Tools : " + jiraserver + '/browse/' + rootnn.key + " => " + componentLead + "") def nametuple(x): return { "name" : x } def quote(x): return '"' + x + '"' # see JIRA_components listing in components.py from components import NN_components for name, comps in NN_components.iteritems():
jiraMessage += VTmessage #We mark the issue with a dirtyMark for everytime VT finds a malicious link if VTreport[0] == 'Possible Malware': dirtyMark += 1 jiraMessage += "\n=====VIRUS TOTAL WAS NOT ABLE TO FIND ANYTHING FOR THE URLs BELOW=====\n\n" jiraMessage = jiraBeforeMessage + jiraStartMessage + jiraMessage + jiraEndMessage if dirtyMark == 0 and URL_FOUND: #ASSIGN ISSUE TO WHOEVER RAN THE SCRIPT and RESOLVE THE TICKET #HAD TO EXCHANGE THIS - SOME TICKETS ARE BEING CLOSED B/C VT DID NOT PICK UP ON PHISH SITE #if enable_Jira_Actions if enable_Jira_Actions and (URL_BLOCKED or specialMimecastMessageFound): print 'completely clear - closing ticket' jira.assign_issue(issue, JiraUserName) #sleep to make sure the assign change goes through and we can find the resolve issue id time.sleep(5) transitions = jira.transitions(issue) #print [(t['id'], t['name']) for t in transitions] for t in transitions: if t['name'] == 'Resolve Issue': id = t['id'] #print id continue try: jira.transition_issue(issue, id) except: time.sleep(1) try: jira.transition_issue(issue, id)
class HelpDesk: def __init__(self, domain='jira.fiware.org'): self.base_url = 'https://{}'.format(domain) self.user = JIRA_USER self.password = JIRA_PASSWORD options = {'server': self.base_url, 'verify': False} self.jira = JIRA(options=options, basic_auth=(self.user, self.password)) self.emailer = Emailer(log_level=DEBUG) self.enablersBook = find_enablersbook() self.nodesBook = find_nodesbook() self.chaptersBook = find_chaptersbook() self.n_assignments = 0 self.n_channeled = 0 self.n_removed = 0 self.n_renamed = 0 def _change_channel(self): query = 'project = HELP AND issuetype in (extRequest, Monitor) ' \ 'AND component in (FIWARE-TECH-HELP, FIWARE-LAB-HELP) and updated >= -1d' inrequests = sorted(self.jira.search_issues(query, maxResults=25), key=lambda item: item.key) # issues changed to LAB channel when node has been set up # HD node = issue.fields.customfield_11104 requests = filter( lambda x: x.fields.components[0].name == 'FIWARE-TECH-HELP', inrequests) condition = lambda x: x.fields.customfield_11104 and not \ x.fields.customfield_11103 and not \ x.fields.customfield_11105 and\ x.fields.customfield_11104.value != 'Unknown' for issue in filter(condition, requests): enabler = issue.fields.customfield_11105 if enabler and enabler.value != 'Unknown': continue chapter = issue.fields.customfield_11103 if chapter and chapter.value != 'Unknown': continue issue.update(fields={'components': [{'name': 'FIWARE-LAB-HELP'}]}) logging.info('update issue= {} - change to LAB channel') # issues changed to TECH channel when enabler or chapter has been set up # HD enabler = issue.fields.customfield_11105 requests = filter( lambda x: x.fields.components[0].name == 'FIWARE-LAB-HELP', inrequests) condition = lambda x: x.fields.customfield_11105 and not \ x.fields.customfield_11104 and \ x.fields.customfield_11105.value != 'Unknown' for issue in filter(condition, requests): node = issue.fields.customfield_11104 if node and node.value != 'Unknown': continue issue.update(fields={'components': [{'name': 'FIWARE-TECH-HELP'}]}) logging.info( 'update issue= {} - change to TECH channel'.format(issue)) # HD chapter = issue.fields.customfield_11103 condition = lambda x: x.fields.customfield_11103 and not \ x.fields.customfield_11104 and \ x.fields.customfield_11103.value != 'Unknown' for issue in filter(condition, requests): node = issue.fields.customfield_11104 if node and node.value != 'Unknown': continue issue.update(fields={'components': [{'name': 'FIWARE-TECH-HELP'}]}) logging.info( 'update issue= {} - change to TECH channel'.format(issue)) def _assign_tech_channel(self): query = 'project = HELP AND issuetype in (extRequest, Monitor) ' \ 'AND component = FIWARE-TECH-HELP AND status != Closed AND assignee = EMPTY and updated >= -1d' requests = sorted(self.jira.search_issues(query, maxResults=25), key=lambda item: item.key) # HD chapter = issue.fields.customfield_11103 # HD node = issue.fields.customfield_11104 # HD enabler = issue.fields.customfield_11105 # make fields visible with value 'Unknown' condition = lambda x: not x.fields.customfield_11103 and not \ x.fields.customfield_11104 and not \ x.fields.customfield_11105 for issue in filter(condition, requests): enabler_values = self.jira.editmeta( issue)['fields']['customfield_11105']['allowedValues'] enabler = next( filter(lambda x: x['value'] == 'Unknown', enabler_values)) chapter_values = self.jira.editmeta( issue)['fields']['customfield_11103']['allowedValues'] chapter = next( filter(lambda x: x['value'] == 'Unknown', chapter_values)) node_values = self.jira.editmeta( issue)['fields']['customfield_11104']['allowedValues'] node = next(filter(lambda x: x['value'] == 'Unknown', node_values)) issue.update( fields={ 'customfield_11103': chapter, 'customfield_11104': node, 'customfield_11105': enabler }) logging.info( 'update issue: issue= {} node={}, chapter={}, enabler={}'. format(issue, node['value'], chapter['value'], enabler['value'])) # assign issues whose enabler has been set up, chapter is also filled consistently # HD enabler = issue.fields.customfield_11105 condition = lambda x: x.fields.customfield_11105 and x.fields.customfield_11105.value != 'Unknown' for issue in filter(condition, requests): enabler = issue.fields.customfield_11105.value if enabler in self.enablersBook: chapter_values = self.jira.editmeta( issue)['fields']['customfield_11103']['allowedValues'] chapter = next( filter( lambda x: x['value'] == self.enablersBook[enabler][ 'chapter'], chapter_values)) if chapter: issue.update(fields={'customfield_11103': chapter}) component = self.jira.component( self.enablersBook[enabler]['component']) assignee = component.assignee.name self.jira.assign_issue(issue, assignee=assignee) logging.info( 'assign issue= {} enabler={} chapter={} assignee={}'. format(issue, enabler, chapter['value'], assignee)) else: message = 'Dear Help Desk Caretaker Admin,' +\ "\n\nPlease, have a look at '{}' Enabler " \ "because it wasn't found in the Enablers book.".format(enabler) +\ '\n\nThanks in advance for cooperation!!' +\ '\n\nKind Regards,' +\ '\nFernando' self.emailer.send_adm_msg( 'Unknown Enabler: {}'.format(enabler), message) # assign issues for chapter leaders, enabler field is not assigned # HD enabler = issue.fields.customfield_11105 # HD chapter = issue.fields.customfield_11103 condition = lambda x: x.fields.customfield_11103 and x.fields.customfield_11103.value != 'Unknown' for issue in filter(condition, requests): enabler = issue.fields.customfield_11105 if enabler and enabler.value != 'Unknown': continue chapter = issue.fields.customfield_11103.value if chapter in self.chaptersBook: component = self.jira.component( self.chaptersBook[chapter]['coordination_key']) assignee = component.assignee.name self.jira.assign_issue(issue, assignee=assignee) logging.info('assign issue= {} chapter={} assignee={}'.format( issue, chapter, assignee)) else: message = 'Dear Help Desk Caretaker Admin,' +\ "\n\nPlease, have a look at {} Chapter " \ "because it wasn't found in the Chapters book.".format(chapter) +\ '\n\nThanks in advance for cooperation!!' +\ '\n\nKind Regards,' +\ '\nFernando' self.emailer.send_adm_msg( 'Unknown Chapter: {}'.format(chapter), message) def _assign_lab_channel(self): query = 'project = HELP AND issuetype in (extRequest, Monitor) AND component = FIWARE-LAB-HELP ' \ 'AND status != Closed and assignee = EMPTY and updated >= -1d' requests = sorted(self.jira.search_issues(query, maxResults=25), key=lambda item: item.key) # HD chapter = issue.fields.customfield_11103 # HD node = issue.fields.customfield_11104 # HD enabler = issue.fields.customfield_11105 # make issues visible condition = lambda x: not x.fields.customfield_11103 and not \ x.fields.customfield_11104 and not \ x.fields.customfield_11105 for issue in filter(condition, requests): enabler_values = self.jira.editmeta( issue)['fields']['customfield_11105']['allowedValues'] enabler = next( filter(lambda x: x['value'] == 'Unknown', enabler_values)) node_values = self.jira.editmeta( issue)['fields']['customfield_11104']['allowedValues'] node = next(filter(lambda x: x['value'] == 'Unknown', node_values)) issue.update(fields={ 'customfield_11105': enabler, 'customfield_11104': node }) logging.info('update issue= {} node={} enabler={}'.format( issue, node['value'], enabler['value'])) # assign issues whose node has been set up # HD node = issue.fields.customfield_11104 condition = lambda x: x.fields.customfield_11104 and x.fields.customfield_11104.value != 'Unknown' for issue in filter(condition, requests): node = issue.fields.customfield_11104.value if node in self.nodesBook: assignee = self.nodesBook[node]['support'] self.jira.assign_issue(issue, assignee=assignee) logging.info('assign issue= {} node={} assignee={}'.format( issue, node, assignee)) else: message = 'Dear Help Desk Caretaker Admin,' +\ "\n\nPlease, have a look at {} Node because it wasn't found in the Enablers book.".format(node) +\ '\n\nThanks in advance for cooperation!!' +\ '\n\nKind Regards,' +\ '\nFernando' self.emailer.send_adm_msg('Unknown Node: {}'.format(node), message) def channel_requests(self): query = 'project = HELP AND issuetype = extRequest AND component = EMPTY' requests = sorted(self.jira.search_issues(query, maxResults=25), key=lambda item: item.key) for request in requests: summary = request.fields.summary if re.search(r'\[SPAM\]', summary): request.update(fields={'components': [{'name': 'SPAM'}]}) continue match = re.search(r'\[[^\]]+?\]', summary) if match: channel = match.group(0)[1:-1] if channel not in channels: continue request.update( fields={'components': [{ 'name': channels[channel] }]}) self.n_channeled += 1 if not request.fields.assignee: assignee = None if channel in ('Fiware-tech-help', 'Fiware-lab-help', 'SPAM') else '-1' self.jira.assign_issue(request, assignee) self.n_assignments += 1 logging.info('updated request {}, channel= {}'.format( request, channel)) def assign_requests(self): self._change_channel() self._assign_tech_channel() self._assign_lab_channel() def naming(self): query = 'project = HELP AND issuetype in (extRequest, Monitor) ' \ 'AND status = Closed and updated >= -1d AND component != EMPTY' issues = sorted(self.jira.search_issues(query, maxResults=25), key=lambda item: item.key) # name spam logging.info('====== SPAM =======') condition = lambda x: x.fields.components[0].name == 'SPAM' for issue in filter(condition, issues): if not re.match(r'SPAM\s=>', issue.fields.summary): summary = 'SPAM => ' + re.sub(r'\[[^\]]+?\]', '', issue.fields.summary.strip()) issue.update( fields={ 'summary': summary, 'customfield_11103': None, 'customfield_11104': None, 'customfield_11105': None }) logging.info('update issue:{} {}'.format(issue, summary)) # name othen channels than TECH and LAB _channels = '|'.join( ifilterfalse(lambda x: x in ('Tech', 'Lab'), keywords.values())) logging.info('====== other channels than Tech and Lab =======') condition = lambda x: x.fields.components[0].name in noTechChannels for issue in filter(condition, issues): try: issuetype = issuetypedict[issue.fields.issuetype.name] except Exception as e: logging.warning(e) issuetype = 'Unknown' chkeyword = keywords[issue.fields.components[0].name] pattern = r'FIWARE\.{}\.{}\.'.format(issuetype, chkeyword) # formato correcto if re.match(pattern, issue.fields.summary): continue # en canal equivocado gpattern = r'FIWARE\.{}\.({})\.'.format(issuetype, _channels) if re.match(gpattern, issue.fields.summary.strip()): summary = re.sub(r'\.({})\.'.format(_channels), chkeyword, issue.fields.summary).strip() else: summary = re.sub(r'\[[^\]]+?\]', '', issue.fields.summary.strip()) summary = re.sub(r'\.FIWARE\.(Request|Question)\.\w+\.', '', summary) summary = 'FIWARE.{}.{}.{}'.format(issuetype, chkeyword, summary) issue.update( fields={ 'summary': summary, 'customfield_11103': None, 'customfield_11104': None, 'customfield_11105': None }) logging.info('update issue:{} {}'.format(issue, summary)) self.n_renamed += 1 # name Lab channel # HD chapter = issue.fields.customfield_11103 # HD node = issue.fields.customfield_11104 # HD enabler = issue.fields.customfield_11105 logging.info('===== Lab channel ========') condition = lambda x: x.fields.components[0].name == 'FIWARE-LAB-HELP' # HD node = issue.fields.customfield_11104 for issue in filter(condition, issues): try: issuetype = issuetypedict[issue.fields.issuetype.name] except Exception as e: logging.warning(e) issuetype = 'Unknown' chunks = issue.fields.summary.strip().split('.') node = issue.fields.customfield_11104 nodeValue = node.value if node else 'Unknown' _channels = '|'.join(keywords.values()) if nodeValue != 'Unknown': pattern = r'FIWARE\.{}\.Lab\.{}\.'.format(issuetype, nodeValue) if re.match(pattern, issue.fields.summary): continue pattern = r'FIWARE\.{}\.({})\.{}\.'.format( issuetype, _channels, nodeValue) if re.match(pattern, issue.fields.summary): summary = '.'.join(chunks[0:2]) + '.Lab.' + '.'.join( chunks[3:]) else: summary = re.sub(r'\[[^\]]+?\]', '', issue.fields.summary).strip() summary = re.sub(r'FIWARE\.(Request|Question)\.\w+\.', '', summary) summary = 'FIWARE.{}.Lab.{}.{}'.format( issuetype, nodeValue, summary) issue.update( fields={ 'summary': summary, 'customfield_11103': None, 'customfield_11105': None }) else: pattern = r'FIWARE\.{}\.Lab\.'.format(issuetype) if re.match(pattern, issue.fields.summary): continue pattern = r'FIWARE\.{}\.({})\.'.format(issuetype, _channels) if re.match(pattern, issue.fields.summary): summary = '.'.join(chunks[0:2]) + '.Lab.' + '.'.join( chunks[3:]) else: summary = re.sub(r'\[[^\]]+?\]', '', issue.fields.summary).strip() summary = re.sub(r'FIWARE\.(Request|Question)\.\w+\.', '', summary) summary = 'FIWARE.{}.Lab.{}.'.format(issuetype, summary) issue.update( fields={ 'summary': summary, 'customfield_11103': None, 'customfield_11104': None, 'customfield_11105': None }) logging.info('update issue: {} {}'.format(issue, summary)) self.n_renamed += 1 # name Tech channel # HD chapter = issue.fields.customfield_11103 # HD node = issue.fields.customfield_11104 # HD enabler = issue.fields.customfield_11105 logging.info('===== Tech channel =======') condition = lambda x: x.fields.components[0].name == 'FIWARE-TECH-HELP' for issue in filter(condition, issues): chapter_values = self.jira.editmeta( issue)['fields']['customfield_11103']['allowedValues'] try: issuetype = issuetypedict[issue.fields.issuetype.name] except Exception as e: logging.warning(e) issuetype = 'Unknown' chunks = issue.fields.summary.strip().split('.') chapter = issue.fields.customfield_11103 enabler = issue.fields.customfield_11105 chapter_value = chapter.value if chapter else 'Unknown' enabler_value = enabler.value if enabler else 'Unknown' if enabler_value != 'Unknown': try: enablerkeyword = self.enablersBook[enabler_value][ 'backlog_keyword'] chapterkeyword = self.enablersBook[enabler_value][ 'chapter'] except KeyError: logging.exception( 'Unknown enabler {}'.format(enabler_value)) continue chapter = next( filter(lambda x: x['value'] == chapterkeyword, chapter_values)) pattern = r'FIWARE\.{}\.Tech\.{}\.{}\.'.format( issuetype, chapterkeyword, enablerkeyword) if re.match(pattern, issue.fields.summary): continue pattern = r'FIWARE\.{}\.({})\.{}\.{}\.'.format( issuetype, _channels, chapterkeyword, enablerkeyword) if re.match(pattern, issue.fields.summary): summary = '.'.join(chunks[0:2]) + '.Tech.' + '.'.join( chunks[3:]) else: summary = re.sub(r'\[[^\]]+?\]', '', issue.fields.summary).strip() summary = re.sub(r'FIWARE\.(Request|Question)\.\w+\.', '', summary) summary = 'FIWARE.{}.Tech.{}.{}.{}'.format( issuetype, chapterkeyword, enablerkeyword, summary) issue.update( fields={ 'summary': summary, 'customfield_11103': chapter, 'customfield_11104': None }) elif enabler_value == 'Unknown' and chapter_value != 'Unknown': pattern = r'FIWARE\.{}\.Tech\.{}\.'.format( issuetype, chapter_value) if re.match(pattern, issue.fields.summary): continue pattern = r'FIWARE\.{}\.({})\.{}\.'.format( issuetype, _channels, chapter_value) if re.match(pattern, issue.fields.summary): summary = '.'.join(chunks[0:2]) + '.Tech.' + '.'.join( chunks[3:]) else: summary = re.sub(r'\[[^\]]+?\]', '', issue.fields.summary).strip() summary = re.sub(r'FIWARE\.(Request|Question)\.\w+\.', '', summary) summary = 'FIWARE.{}.Tech.{}.{}'.format( issuetype, chapter_value, summary) issue.update( fields={ 'summary': summary, 'customfield_11104': None, 'customfield_11105': None }) else: pattern = r'FIWARE\.{}\.Tech\.'.format(issuetype) if re.match(pattern, issue.fields.summary): continue pattern = r'FIWARE\.{}\.({})\.'.format(issuetype, _channels) if re.match(pattern, issue.fields.summary): summary = '.'.join(chunks[0:2]) + '.Tech.' + '.'.join( chunks[3:]) else: summary = re.sub(r'\[[^\]]+?\]', '', issue.fields.summary).strip() summary = re.sub(r'FIWARE\.(Request|Question)\.\w+\.', '', summary) summary = 'FIWARE.{}.Tech.{}.'.format(issuetype, summary) issue.update( fields={ 'summary': summary, 'customfield_11103': None, 'customfield_11104': None, 'customfield_11105': None }) logging.info('update issue: {} {}'.format(issue, summary)) self.n_renamed += 1 def remove_spam(self): query = 'project in (HELP, HELC) and component = SPAM and updated <= -7d' # query = 'project in (HELP, HELC) and component = SPAM' requests = sorted(self.jira.search_issues(query, maxResults=25), key=lambda item: item.key) for request in requests: request.delete() logging.info('DELETED SPAM {}'.format(request)) self.n_removed += 1