def notify_webmasters(key: str, site_name: str, unit: str, webmasters: str, Jahia_url: str) -> None: # time to buid the mails jinja_env = Environment(loader=FileSystemLoader("{}/templates/".format( os.path.dirname(os.path.dirname(__file__)))), autoescape=select_autoescape('html', 'xml'), trim_blocks=True, lstrip_blocks=True) jinja_template = jinja_env.get_template( "20180516_WM_freeze_jahia_notification.html") # Send the mail for webmaster in webmasters.split("|"): msgSubject = "[WWP] [{0}] Le site '{0}' va être migré sur WordPress / The '{0}' site will be migrated to WordPress".format( site_name) msgBody = jinja_template.render(site_name=site_name, unit=unit, webmasters=", ".join( webmasters.split("|")), Jahia_url=Jahia_url) send_message(webmaster, msgSubject, msgBody) jira = JIRA(settings.JIRA_URL, basic_auth=(settings.JIRA_USERNAME, settings.JIRA_PASSWORD)) comment = "{}: Notified '{}' that the site should be frozen".format( site_name, webmasters) jira.add_comment(key, comment)
def update_jira(site_name: str, unit_name: str, webmasters: str) -> None: # cleanup unit_name = unit_name.upper() jira = JIRA(settings.JIRA_URL, basic_auth=(settings.JIRA_USERNAME, settings.JIRA_PASSWORD)) sites = jira.search_issues( "project=WPFEEDBACK AND summary~'{}'".format(site_name), maxResults=1) assert len(sites) == 1 site = sites[0] if site.fields.customfield_10404 != unit_name: comment = "{}: Updating unit name from '{}' to '{}'".format( site_name, site.fields.customfield_10404, unit_name) print(comment) jira.add_comment(site, comment) site.update(fields={'customfield_10404': unit_name}) if site.fields.customfield_10403 != webmasters: comment = "{}: Updating webmasters from '{}' to '{}'".format( site_name, site.fields.customfield_10403, webmasters) print(comment) jira.add_comment(site, comment) site.update(fields={'customfield_10403': webmasters})
def notify_webmasters(key: str, site_name: str, unit: str, webmasters: str, Jahia_url: str) -> None: # time to buid the mails jinja_env = Environment(loader=FileSystemLoader("{}/templates/".format( os.path.dirname(os.path.dirname(__file__)))), autoescape=select_autoescape('html', 'xml'), trim_blocks=True, lstrip_blocks=True) jinja_template = jinja_env.get_template( "20180925_WM_realnce_notification.html") # Send the mail for webmaster in webmasters.split("|"): msgSubject = "[WWP] [{0}] Migration de vos sites de Jahia à Wordpress / Migration of your website from Jahia to Worpress".format( site_name) msgBody = jinja_template.render(site_name=site_name, unit=unit, webmasters=", ".join( webmasters.split("|")), Jahia_url=Jahia_url) send_message(webmaster, msgSubject, msgBody) jira = JIRA(settings.JIRA_URL, basic_auth=(settings.JIRA_USERNAME, settings.JIRA_PASSWORD)) comment = "{}: Notified '{}' that we still wait for feedback".format( site_name, webmasters) jira.add_comment(key, comment)
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))
def main(): parser = argparse.ArgumentParser() parser.add_argument('change', help='Change number') parser.add_argument('username', help='Change author\'s username') args = parser.parse_args() change = args.change username = args.username try: email = get_email_by_username(username) description = get_change_description(change) issue_keys = re.findall(ISSUE_KEY_RE, description) jira = JIRA( JIRA_URL, basic_auth=(JIRA_USER, JIRA_PASSWORD)) for issue_key in issue_keys: if not email: jira_user = username logging.warning('Cannot find email of user %s' % username) else: jira_user = '******'.format(email) comment = '{} mentioned this issue in Perforce. Change: *{}*, description: _{}_'.format( jira_user, change, description) jira.add_comment(issue_key, comment) logging.info('Comment added to issue %s with description: %s' % (issue_key, description)) except Exception as err: logging.error('Cannot process change %s by %s' % (change, username)) logging.error(err) pass
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')
def notify_webmasters(key: str, site_name: str, webmasters: str, wordpress_url: str, QA18_url: str, url_ventilation: str, QA_source: str) -> None: # time to buid the mails jinja_env = Environment(loader=FileSystemLoader("{}/templates/".format( os.path.dirname(os.path.dirname(__file__)))), autoescape=select_autoescape('html', 'xml'), trim_blocks=True, lstrip_blocks=True) jinja_template = jinja_env.get_template( "20190529_WM18_assoc_notification_choice.html") # Send the mail for webmaster in webmasters.split("|"): msgSubject = "[{0}] changement identité visuelle / New visual identity".format( site_name) msgBody = jinja_template.render(site_name=site_name, webmasters=", ".join( webmasters.split("|")), WordPress_url=wordpress_url, QA18_url=QA18_url, url_ventilee=url_ventilation, QA_source=QA_source) send_message(webmaster, msgSubject, msgBody) jira = JIRA(settings.JIRA_URL, basic_auth=(settings.JIRA_USERNAME, settings.JIRA_PASSWORD)) comment = "{}: Notified '{}' assoc to make choice copy ou empty ".format( site_name, webmasters) jira.add_comment(key, comment)
def create_jira_issue(summary, description, comment="", project_key="PROP", task_type="Task"): # Method to create JIRA issue try: authed_jira = JIRA(server=conf.JIRA_URL, basic_auth=(conf.JIRA_USER, conf.JIRA_PASSWORD)) issue_dict = { 'project': { 'key': project_key }, 'description': description, 'issuetype': { 'name': task_type }, 'summary': summary, } if not conf.PRODUCTION: issue_dict["project"] = {'key': 'DEVPROP'} issue_dict["summary"] = '[DEV] ' + summary new_issue = authed_jira.create_issue(fields=issue_dict) # add comments if comment != "": authed_jira.add_comment(new_issue, comment) except Exception as e: logger.error("Error al Crear Issue en JIRA : %s." % e)
def notify_webmasters(key: str, site_name: str, webmasters: str, wordpress_url: str, QA18_url: str, url_ventilation: str, QA_source: str) -> None: # time to buid the mails jinja_env = Environment(loader=FileSystemLoader("{}/templates/".format( os.path.dirname(os.path.dirname(__file__)))), autoescape=select_autoescape('html', 'xml'), trim_blocks=True, lstrip_blocks=True) jinja_template = jinja_env.get_template( "20190611_notify_WM_vide_QA_2018.html") # Send the mail for webmaster in webmasters.split("|"): msgSubject = "[{0}] Votre site vide dans l’environnement d’adaptation est prêt – Your empty site in the prepration environement is ready.".format( site_name) msgBody = jinja_template.render(site_name=site_name, webmasters=", ".join( webmasters.split("|")), WordPress_url=wordpress_url, QA18_url=QA18_url, url_ventilee=url_ventilation, QA_source=QA_source) send_message(webmaster, msgSubject, msgBody) jira = JIRA(settings.JIRA_URL, basic_auth=(settings.JIRA_USERNAME, settings.JIRA_PASSWORD)) comment = "{}: Notified '{}' that a empty site has been created".format( site_name, webmasters) jira.add_comment(key, comment)
def notify_webmasters(key: str, site_name: str, webmasters: str, wordpress_url: str, QA18_url: str, url_ventilation: str, QA_source: str) -> None: # time to buid the mails jinja_env = Environment(loader=FileSystemLoader("{}/templates/".format( os.path.dirname(os.path.dirname(__file__)))), autoescape=select_autoescape('html', 'xml'), trim_blocks=True, lstrip_blocks=True) jinja_template = jinja_env.get_template( "20180516_WM18_deployment_notification.html") # Send the mail for webmaster in webmasters.split("|"): msgSubject = "[WWP] [{0}] Le site '{0}' a été (re)déployé / The '{0}' site has been (re)deployed".format( site_name) msgBody = jinja_template.render(site_name=site_name, webmasters=", ".join( webmasters.split("|")), WordPress_url=wordpress_url, QA18_url=QA18_url, url_ventilee=url_ventilation, QA_source=QA_source) send_message(webmaster, msgSubject, msgBody) jira = JIRA(settings.JIRA_URL, basic_auth=(settings.JIRA_USERNAME, settings.JIRA_PASSWORD)) comment = "{}: Notified '{}' that the site 2018 has been (re)deployed".format( site_name, webmasters) jira.add_comment(key, comment)
def notify_webmasters(key: str, site_name: str, webmasters: str, wordpress_url: str, QA18_url: str, url_ventilation: str, url_racine_instance: str, URL_racine_instance: str, fin_url1: str, fin_url2: str) -> None: # time to buid the mails jinja_env = Environment(loader=FileSystemLoader("{}/templates/".format( os.path.dirname(os.path.dirname(__file__)))), autoescape=select_autoescape('html', 'xml'), trim_blocks=True, lstrip_blocks=True) jinja_template = jinja_env.get_template( "20180516_WM18_finished_migration_notification.html") # Send the mail for webmaster in webmasters.split("|"): msgSubject = "[{0}] Votre site est en ligne avec la nouvelle charte - Your website is online with the new charter".format( site_name) msgBody = jinja_template.render( site_name=site_name, webmasters=", ".join(webmasters.split("|")), WordPress_url=wordpress_url, QA18_url=QA18_url, url_ventilee=url_ventilation, url_racine_instance=url_racine_instance, URL_racine_instance=URL_racine_instance, fin_url1=fin_url1, fin_url2=fin_url2) send_message(webmaster, msgSubject, msgBody) jira = JIRA(settings.JIRA_URL, basic_auth=(settings.JIRA_USERNAME, settings.JIRA_PASSWORD)) comment = "{}: Notified '{}' that the site 2018 is ready".format( site_name, webmasters) jira.add_comment(key, comment)
def jira_comment(issue_key, comment): j = JIRA( settings.jira_url, basic_auth=(settings.username, settings.password), ) issue = j.issue(issue_key) j.add_comment(issue, comment)
def makeissue(repository, fragment, html_url, lineinfo): print Fore.RED + fragment print(Style.RESET_ALL) body = """ The Cyber Defense Center found cleartext credentials in this repository. %s %s %s """ % (fragment, html_url, lineinfo) if qprompt.ask_yesno("Is this a valid result?", dft="n"): print "Creating Github Issue...." g = Github(base_url="https://github.$ENTERPRISE.com/api/v3", login_or_token="") repo = g.get_repo(repository) createissue = repo.create_issue( title="Security: Cleartext Credentials Found", body=body) jiracomment = "Created issue #%s for %s repository" % ( createissue.number, repository) print jiracomment jira = JIRA('https://jira.$ENTERPRISE.com', basic_auth=(jirausername, jirapassword)) issue = jira.issue("ATTACKPT-62") jira.add_comment(issue, jiracomment) qprompt.pause() qprompt.clear() qprompt.clear()
def notify_webmasters(key: str, site_name: str, webmasters: str, wordpress_url: str, QA18_url: str, url_ventilation: str) -> None: # time to buid the mails jinja_env = Environment(loader=FileSystemLoader("{}/templates/".format( os.path.dirname(os.path.dirname(__file__)))), autoescape=select_autoescape('html', 'xml'), trim_blocks=True, lstrip_blocks=True) jinja_template = jinja_env.get_template( "20180516_WM18_finished_migration_notification.html") # Send the mail for webmaster in webmasters.split("|"): msgSubject = "[WWP] [{0}] site '{0}' avec nouvelle charte graphique / '{0}' site with new visual identity".format( site_name) msgBody = jinja_template.render(site_name=site_name, webmasters=", ".join( webmasters.split("|")), WordPress_url=wordpress_url, QA18_url=QA18_url, url_ventilee=url_ventilation) send_message(webmaster, msgSubject, msgBody) jira = JIRA(settings.JIRA_URL, basic_auth=(settings.JIRA_USERNAME, settings.JIRA_PASSWORD)) comment = "{}: Notified '{}' that the site 2018 is ready".format( site_name, webmasters) jira.add_comment(key, comment)
def add_comment(find, note, force_push=False): prod = Product.objects.get(engagement=Engagement.objects.get(test=find.test)) jpkey = JIRA_PKey.objects.get(product=prod) jira_conf = jpkey.conf if jpkey.push_notes or force_push == True: jira = JIRA(server=jira_conf.url, basic_auth=(jira_conf.username, jira_conf.password)) j_issue = JIRA_Issue.objects.get(finding=find) jira.add_comment(j_issue.jira_id, '(%s): %s' % (note.author.get_full_name(), note.entry))
def add_comment(find, note): prod = Product.objects.get(engagement=Engagement.objects.get(test=find.test)) jpkey = JIRA_PKey.objects.get(product=prod) jira_conf = jpkey.conf if jpkey.push_notes: jira = JIRA(server=jira_conf.url, basic_auth=(jira_conf.username, jira_conf.password)) j_issue = JIRA_Issue.objects.get(finding=find) jira.add_comment(j_issue.jira_id, '(%s): %s' % (note.author.get_full_name(), note.entry))
def updateIssues(issuelist, NEXTorDOTX, description): numExistingIssues = len(issuelist) if not issuelist == None else 0 if numExistingIssues > 0 : if debug: print "[DEBUG] Move " + str(numExistingIssues) + " " + description jira = JIRA(options={'server':jiraserver}, basic_auth=(jirauser, jirapwd)) cnt = 0 for s in issuelist : key = components.getText(components.findChildNodeByName(s, 'key').childNodes) issue = jira.issue(key) cnt += 1 doThisJIRA = True whichLabelSkipped = "" for label in issue.fields.labels: for skipLabel in skipLabels: if label == skipLabel.strip(): whichLabelSkipped = label doThisJIRA = False linkURL = components.getText(components.findChildNodeByName(s, 'link').childNodes) summary = components.getText(components.findChildNodeByName(s, 'summary').childNodes).strip() operation = " + [" + str(cnt) + "/" + str(len(issuelist)) + "] Update " + linkURL + " : " + summary if debug: operation = operation + " :: " + str(issue.fields.labels) if doThisJIRA == False: operation = " - [" + str(cnt) + "/" + str(len(issuelist)) + "] -Skip- " + linkURL + " (" + whichLabelSkipped + ") : " + summary print operation else: if options.autoApplyChanges or options.dryrun: print operation yesno = "" else: yesno = raw_input(operation + " ? [y/N] ") if options.autoApplyChanges or yesno.capitalize() in ["Y"]: # move issue to next fixversion if components.findChildNodeByName(s, 'project').attributes["key"].value == "JBIDE": # JBIDE or JBDS fixversion = version_jbt fixversion_NEXT = version_jbt_NEXT if NEXTorDOTX else version_jbt_DOTX else: fixversion = version_ds fixversion_NEXT = version_ds_NEXT if NEXTorDOTX else version_ds_DOTX fixVersions = [] # NOTE: if there is more than one fixversion, the others will not be changed for version in issue.fields.fixVersions: if version.name != fixversion: fixVersions.append({'name': version.name}) fixVersions.append({'name': fixversion_NEXT}) issue.update(fields={'fixVersions': fixVersions}) # only for NEXT, not for .x if NEXTorDOTX: # move issue to new sprint jira.add_issues_to_sprint(sprintId_NEXT, [key]) jira.add_comment(key, "[checkUnresolvedIssues.py] Slip to fixversion = " + fixversion_NEXT + " and sprint " + sprintId_NEXT) else: jira.add_comment(key, "[checkUnresolvedIssues.py] Slip to fixversion = " + fixversion_NEXT)
def updateIssues(issuelist, NEXTorDOTX, description): numExistingIssues = len(issuelist) if not issuelist == None else 0 if numExistingIssues > 0 : if debug: print "[DEBUG] Move " + str(numExistingIssues) + " " + description jira = JIRA(options={'server':jiraserver}, basic_auth=(jirauser, jirapwd)) cnt = 0 for s in issuelist : key = components.getText(components.findChildNodeByName(s, 'key').childNodes) issue = jira.issue(key) cnt += 1 doThisJIRA = True whichLabelSkipped = "" for label in issue.fields.labels: for skipLabel in skipLabels: if label == skipLabel.strip(): whichLabelSkipped = label doThisJIRA = False linkURL = components.getText(components.findChildNodeByName(s, 'link').childNodes) summary = components.getText(components.findChildNodeByName(s, 'summary').childNodes).strip() operation = " + [" + str(cnt) + "/" + str(len(issuelist)) + "] Update " + linkURL + " : " + summary if debug: operation = operation + " :: " + str(issue.fields.labels) if doThisJIRA == False: operation = " - [" + str(cnt) + "/" + str(len(issuelist)) + "] -Skip- " + linkURL + " (" + whichLabelSkipped + ") : " + summary print operation else: if options.autoApplyChanges or options.dryrun: print operation yesno = "" else: yesno = raw_input(operation + " ? [y/N] ") if options.autoApplyChanges or yesno.capitalize() in ["Y"]: # move issue to next fixversion if components.findChildNodeByName(s, 'project').attributes["key"].value == "JBIDE": # JBIDE or JBDS fixversion = version_jbt fixversion_NEXT = version_jbt_NEXT if NEXTorDOTX else version_jbt_DOTX else: fixversion = version_ds fixversion_NEXT = version_ds_NEXT if NEXTorDOTX else version_ds_DOTX fixVersions = [] # NOTE: if there is more than one fixversion, the others will not be changed for version in issue.fields.fixVersions: if version.name != fixversion: fixVersions.append({'name': version.name}) fixVersions.append({'name': fixversion_NEXT}) issue.update(fields={'fixVersions': fixVersions}) # only for NEXT, not for .x if NEXTorDOTX: # move issue to new sprint jira.add_issues_to_sprint(sprintId_NEXT, [key]) jira.add_comment(key, "[checkUnresolvedIssues.py] Slip to fixversion = *" + fixversion_NEXT + "* and sprint = *" + sprint_NEXT + "*") else: jira.add_comment(key, "[checkUnresolvedIssues.py] Slip to fixversion = *" + fixversion_NEXT + "*")
def add_issue_comment(opts, issue_key, comment): url = opts.get('jira_url') if not url: raise CommonException('Invalid URL specified') auth = (opts.get('jira_username'), opts.get('jira_password')) j = JIRA(url, auth=auth) try: j.add_comment(issue_key, comment) except JIRAError as ex: raise CommonException('Failed to add comment: {}'.format(ex))
def transition_site(key: str, new_status: str, site_name: str, site) -> None: jira = JIRA(settings.JIRA_URL, basic_auth=(settings.JIRA_USERNAME, settings.JIRA_PASSWORD)) transitions = jira.transitions(key) for t in transitions: if t['name'] == new_status: comment = "{}: Applied transition '{}'".format(site_name, new_status) print(comment) jira.transition_issue(issue=site, transition=t['id']) jira.add_comment(key, comment) break
def tasks_comment(task_key): text = request.form['text'] email = session['current_user_email'] jira_api_token = database_manager.get_jira_api_token(email) if not jira_api_token: return redirect('/jira/register') options = {'server': 'https://synetech.atlassian.net'} jira_client = JIRA(options, basic_auth=(email, jira_api_token)) jira_client.add_comment(task_key, text) return redirect("/tasks")
def add_jira_comment(username, password, issue, comment): ''' Given a comment, add it to the provided JIRA Issue ''' Jira = JIRA(JIRA_URL, basic_auth=(username, password), max_retries=0) try: jira_issue = Jira.issue(issue) except JIRAError as e: raise JIRAError(text="JIRA Error {}: {}".format( e.response.status_code, e.response.reason)) Jira.add_comment(jira_issue, comment)
def update_jira_ticket(jira_ticket_nr, jira_report_comment, jira_report_attachment_path): jira = JIRA(basic_auth=('USER', 'PASS'), options={ 'server': 'https://JIRA-IP', 'verify': False }) issue = jira.issue(jira_ticket_nr) jira.add_comment(issue, jira_report_comment) with open(jira_report_attachment_path, "rb") as report_to_upload: jira.add_attachment(issue=issue, attachment=report_to_upload)
def set_jira_rtbf(jira_rtbf_issue, jira_usr, jira_pwd, result): from jira import JIRA from jira.resources import Issue jira = JIRA(basic_auth=(jira_usr, jira_pwd), options={'server':'https://jira.smc.com'}) issue = jira.issue(jira_rtbf_issue) jira.add_comment(jira_rtbf_issue, result) issue.update(assignee={'name': (issue.fields.reporter.name)}) issues_lst=[] issues_lst.append(issue.key) #spint_id 3844 is for 'COMPLETED GDPR Requests' jira.add_issues_to_sprint(3844,issues_lst) print('success')
class JiraQuery(object): """Class to query and update a jira project compared to a Github repository """ def __init__(self, jira, key=None, user=None, password=None): """Class to query and update a jira project compared to a Github repository Parameters ---------- jira: str Name of a repository to track and update the issues. The name of the repository should be in the form of 'url/project/name' key: str Authentification token for the current user user: str Username for the current user password: str password for the current user """ # link to the current rero site, repo_name = jira.split('/projects/') self.repo = repo_name # authenticate with github if key: self.jira = JIRA(site, oauth=key) elif user is not None: self.jira = JIRA(site, basic_auth=(user, password)) else: self.jira = JIRA(site) @property def issue(self): return self._issue @issue.setter def issue(self, issue_id): try: self._issue = self.jira.issue(issue_id) except JIRAError: self._issue = None def add_comment(self, comment): """Add a comment to an issue. Parameters ---------- comment: str Comment to be added to an issue """ self.jira.add_comment(self.issue, comment)
def main(credential_file, comment, comment_file, 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 comment is None and comment_file is None: print("--comment and --comment_file were not specified") sys.exit(1) if comment is '': print("You must provide some test for the comment") sys.exit(1) if comment_file is not None: with open(comment_file, 'r') as cf: comment = cf.read() 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") auth_jira = JIRA(url, basic_auth=(username, password)) if auth_jira is not None: print("Will attempt to add comment '{}' to issue '{}'".format(comment, issue)) auth_jira.add_comment(issue, comment) print("Added comment '{}' to issue '{}'".format(comment, issue)) else: print("Could not instantiate JIRA for url '{}'".format(url))
class JIRA_Wapper(): def __init__(self, user, password, server_url='http://jira.calix.local', **kwargs): self.jira = JIRA(basic_auth=(user, password), server=server_url, **kwargs) def _list_projects(self): return sorted([pro.key for pro in self.jira.projects()]) def _get_a_issue(self, issue_id): return self.jira.issue(issue_id) def search_issues_by_jql(self, jql, **kwargs): return self.jira.search_issues(jql, **kwargs) def get_assignee(self, issue_id): return self._get_a_issue( issue_id).raw['fields']['assignee']['displayName'] def get_issue_link(self, issue_id): return self._get_a_issue( issue_id).raw['fields']['votes']['self'].replace( 'rest/api/2/issue', 'browse').replace('/votes', '') def get_issue_title(self, issue_id): return self._get_a_issue(issue_id).raw['fields']['summary'] def get_reporter(self, issue_id): return self._get_a_issue( issue_id).raw['fields']['reporter']['displayName'] def get_issue_type(self, issue_id): return self._get_a_issue(issue_id).raw['fields']['issuetype']['name'] def get_priority(self, issue_id): return self._get_a_issue(issue_id).raw['fields']['priority']['name'] def add_comment(self, issue_id, comment): self.jira.add_comment(issue_id, comment) def update_issue(self, issue_id, **kwargs): self._get_a_issue(issue_id).update(**kwargs) def delete_issue(self, issue): issue.delete() def add_watcher(self, issue_id, watcher): self.jira.add_watcher(issue_id, watcher)
def update_jira_story(story_id, transition_id, comment=None, **kwargs): try: jira = JIRA("https://thezebra.atlassian.net", basic_auth=(os.environ['username'], os.environ['password'])) issue = jira.issue(story_id) allowed_transitions = {t['id'] for t in jira.transitions(issue)} if str(transition_id) not in allowed_transitions: app.logger.warn("Story %s cannot transition to %s" % (story_id, transition_id)) else: jira.transition_issue(issue, transition_id) if comment: jira.add_comment(issue, comment) except Exception as ex: app.logger.error(ex)
def add_jira_comment(jira_id, comment): if not settings.CASELINK_JIRA['ENABLE']: return False user = settings.CASELINK_JIRA['USER'] password = settings.CASELINK_JIRA['PASSWORD'] server = settings.CASELINK_JIRA['SERVER'] basic_auth = (user, password) options = { 'server': server, 'verify': False, } jira = JIRA(options, basic_auth=basic_auth) jira.add_comment(jira.issue(id=jira_id), comment) return True
def add_jira_comment(jira_id, comment): if not settings.CASELINK_JIRA['ENABLE']: return False user = settings.CASELINK_JIRA['USER'] password = settings.CASELINK_JIRA['PASSWORD'] server = settings.CASELINK_JIRA['SERVER'] basic_auth = (user, password) options = { 'server': server, 'verify': False, } jira = JIRA(options, basic_auth=basic_auth) jira.add_comment(jira.issue(id=jira_id), comment) return True
def close_issue(opts, issue_key, reason): url = opts.get('jira_url') if not url: raise CommonException('Invalid URL specified') auth = (opts.get('jira_username'), opts.get('jira_password')) j = JIRA(url, auth=auth) try: j.add_comment(issue_key, reason) issue = j.issue(issue_key) trans = j.transitions(issue) for t in trans: if t['name'] in ['Done', 'Close']: j.transition_issue(issue, t['id']) except JIRAError as ex: raise CommonException(f'Failed to transition: {ex}')
def transition_site(site_name: str, new_status: str) -> None: jira = JIRA(settings.JIRA_URL, basic_auth=(settings.JIRA_USERNAME, settings.JIRA_PASSWORD)) sites = jira.search_issues( "project=WPFEEDBACK AND summary~'{}'".format(site_name), maxResults=1) assert len(sites) == 1 site = sites[0] transitions = jira.transitions(site) for t in transitions: if t['name'] == new_status: comment = "{}: Applied transition '{}'".format( site_name, new_status) print(comment) jira.transition_issue(issue=site, transition=t['id']) jira.add_comment(site, comment)
class Jira(object): """This class will be used to connect to JIRA""" def __init__(self, jira_id): dbobj = DBHandler() host = dbobj.getValue("jira_uri") user = dbobj.getValue("jira_user") password = dbobj.getValue("jira_password") self.jira_obj = JIRA(server=host, basic_auth=(user, password)) self.jira_id = jira_id def comment(self, message=None, jira_id=None): try: if message is not None: jira_id = self.jira_id if jira_id is None else jira_id self.jira_obj.add_comment(jira_id, message) except Exception, e: logger.error(e)
def test_jira_api(args): logger.info(str(args)) if not isinstance(g.identity, AnonymousIdentity): raw_ua = request.headers.get('User-Agent') or '' ua = user_agents.parse(raw_ua) args['os'] = ua.os.family args['browser'] = ua.browser.family args['device'] = ua.device.family args['ua'] = raw_ua from jira import JIRA HOST = current_app.config['JIRA_HOST'] BASIC_AUTH_USER = current_app.config['BASIC_AUTH_USER'] BASIC_AUTH_PASSWORD = current_app.config['BASIC_AUTH_PASSWORD'] PROJECT = current_app.config['PROJECT'] EPIC = current_app.config['EPIC'] # 权限 jira = JIRA(HOST, basic_auth=(BASIC_AUTH_USER, BASIC_AUTH_PASSWORD)) # 新建issue new_issue = jira.create_issue(project=PROJECT, summary=args['summary'], description=args.get('description', ''), issuetype={'name': args['type']}) # 添加issue到epic jira.add_issues_to_epic(EPIC, [str(new_issue.key)]) # 添加额外信息到comment display_list = ['summary', 'description', 'type', 'file'] comment_body = ''.join( ['%s:%s \n' % (k, args[k]) for k in args if k not in display_list]) jira.add_comment(new_issue.key, comment_body) if comment_body else "" # 添加附件 data = request.files.getlist("file") current_app.logger.info(type(data)) if data: for file_data in data: current_app.logger.info(file_data.filename) binary = file_data.stream.read() if binary: jira.add_attachment(issue=new_issue, attachment=binary, filename=str(uuid.uuid1()) + '.' + file_data.filename.split(".")[-1])
class Jira: def __init__(self): options = { 'server': jira_url, 'verify': False, 'check_update': False } self.jira = JIRA(options, basic_auth=(jira_user, jira_passwd)) def main(self, comment, group_name): message = comment['message'].split('\n')[0] commit_sha1 = comment['id'] author = comment['author_name'] commited_date = comment['committed_date'].split('+')[0] date = datetime.datetime.strptime(commited_date, "%Y-%m-%dT%H:%M:%S.%f") projects = self.jira.projects() project_keys = sorted([project.key for project in projects]) for keys in project_keys: if message.startswith(keys): issue_id = message.split(' ')[0] try: comment_msg = ' '.join(message.split(' ')[1:]) except IndexError: comment_msg = issue_id compare_url = "%s/%s/%s/commit/%s" % (git_server_url, group_name, project_name, refs) msg = '%s\n\nProject Repo: %s\nUser: %s\nCommit Time: %s\nCommit SHA1: [%s | %s]\n\n' %\ (comment_msg, project_name, author, date, commit_sha1, compare_url) comment = self.jira.add_comment(issue_id, msg)
import pika parameters = pika.URLParameters('amqp://*****:*****@localhost:5672/%2F') connection = pika.BlockingConnection(parameters) channel = connection.channel() channel.basic_publish('seemq_exchange', 'seemq_routing_key', 'JIRA ID 123 - 001 : message body value', ############ Integration pika.BasicProperties(content_type='text/plain', delivery_mode=1)) connection.close() # Add a comment to the issue. jira.add_comment(issue, 'Message Queue activity mentioned here') # Update the labels field like this issue.update(labels=['AAA', 'BBB']) # Resolve the issue and assign it to 'pm_user' in one step #jira.transition_issue(issue, '5', fields: {'assignee':{'name': 'pm_user'}, 'resolution':{'id': '3'}}) # For more involved access to JIRA issues, use JIRA native REST API like so # curl request to http://jira-server/rest/api/latest/issue/ABC-123
def post_jira_comment(server, username, password, ticketId, commentText): jira = JIRA(server=server, basic_auth=(username, password), options={'verify':False}) jira.add_comment(ticketId, commentText)
def reopened_task(branch): jira = JIRA(options, basic_auth=(JIRA_USERNAME, PASSWORD)) issue = jira.issue(branch) jira.transition_issue(issue, u'Reopened') jira.add_comment(branch, 'Autotest fail')
# Get all projects viewable by anonymous users. projects = jira.projects() # Sort available project keys, then return the second, third, and fourth keys. keys = sorted([project.key for project in projects])[2:5] # Get an issue. issue = jira.issue('JRA-1330') # Find all comments made by Atlassians on this issue. atl_comments = [comment for comment in issue.fields.comment.comments if re.search(r'@atlassian.com$', comment.author.emailAddress)] # Add a comment to the issue. jira.add_comment(issue, 'Comment text') # Change the issue's summary and description. issue.update( summary="I'm different!", description='Changed the summary to be different.') # Change the issue without sending updates issue.update(notify=False, description='Quiet summary update.') # You can update the entire labels field like this issue.update(labels=['AAA', 'BBB']) # Or modify the List of existing labels. The new label is unicode with no # spaces issue.fields.labels.append(u'new_text') issue.update(fields={"labels": issue.fields.labels})
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
def report_issue(self, build): try: jira = JIRA(server='https://issues.voltdb.com/', basic_auth=(JIRA_USER, JIRA_PASS)) except: logging.exception('Could not connect to Jira') return build_report_url = self.jhost + '/job/' + job + '/' + str(build) + '/api/python' build_report = eval(self.read_url(build_report_url)) build_url = build_report.get('url') build_result = build_report.get('result') if build_result == 'SUCCESS': # only generate Jira issue if the test fails print 'No new issue created. Build ' + str(build) + 'resulted in: ' + build_result return summary_url = self.jhost + '/job/' + job + '/' + str(build) + '/artifact/tests/sqlgrammar/summary.out' summary_report = self.read_url(summary_url) pframe_split = summary_report.split('Problematic frame:') pframe_split = pframe_split[1].split('C') pframe_split = pframe_split[1].split(']') pframe_split = pframe_split[1].split('#') pframe = pframe_split[0].strip() summary = job + ':' + str(build) + ' - ' + pframe # search_issues gets a parsing error on (), so escape it. existing = jira.search_issues('summary ~ \'%s\'' % summary.replace('()','\\\\(\\\\)',10)) if len(existing) > 0: print 'No new Jira issue created. Build ' + str(build) + ' has already been reported.' return 'Already reported' old_issue = '' existing = jira.search_issues('summary ~ \'%s\'' % pframe_split[0].strip().replace('()','\\\\(\\\\)',10)) for issue in existing: if str(issue.fields.status) != 'Closed' and u'grammar-gen' in issue.fields.labels: old_issue = issue build_artifacts = build_report.get('artifacts')[0] pid_fileName = build_artifacts['fileName'] pid_url = build_url + 'artifact/' + pid_fileName query_split = summary_report.split('(or it was never started??), after SQL statement:') crash_query = query_split[1] hash_split = summary_report.split('#', 1) hash_split = hash_split[1].split('# See problematic frame for where to report the bug.') sigsegv_message = hash_split[0] + '# See problematic frame for where to report the bug.\n#' description = job + ' build ' + str(build) + ' : ' + str(build_result) + '\n' \ + 'Jenkins build: ' + build_url + ' \n \n' \ + 'DDL: ' + 'https://github.com/VoltDB/voltdb/blob/master/tests/sqlgrammar/DDL.sql' + ' \n \n' \ + 'hs_err_pid: ' + pid_url + ' \n \n' \ + 'SIGSEGV Message: \n' + '#' + sigsegv_message + ' \n \n' \ + 'Query that Caused the Crash: ' + crash_query description = description.replace('#', '\#') labels = ['grammar-gen'] component = 'Core' components = jira.project_components(JIRA_PROJECT) jira_component = {} for c in components: if c.name == component: jira_component = { 'name': c.name, 'id': c.id } break current_version_raw = str(self.read_url('https://raw.githubusercontent.com/VoltDB/voltdb/master/version.txt')) current_version_float = float(current_version_raw) current_version = 'V' + current_version_raw current_version = current_version.strip() next_version = current_version_float + .1 next_version = str(next_version) next_version = 'V' + next_version next_version = next_version[:4] jira_versions = jira.project_versions(JIRA_PROJECT) this_version = {} new_version = {} for v in jira_versions: if str(v.name) == current_version: this_version = { 'name': v.name, 'id': v.id } if str(v.name) == next_version: new_version = { 'name': v.name, 'id': v.id } issue_dict = { 'project': JIRA_PROJECT, 'summary': summary, 'description': description, 'issuetype': {'name': 'Bug'}, 'priority': {'name': 'Blocker'}, 'labels': labels, 'customfield_10430': {'value': 'CORE team'}, 'components': [jira_component] } if new_version: issue_dict['versions'] = [new_version] issue_dict['fixVersions'] = [new_version] elif this_version: issue_dict['versions'] = [this_version] issue_dict['fixVersions'] = [this_version] if old_issue: new_comment = jira.add_comment(old_issue, description) print 'JIRA-action: New comment on issue: ' + str(old_issue) + ' created for failure on build ' + str(build) else: new_issue = jira.create_issue(fields=issue_dict) print 'JIRA-action: New issue ' + new_issue.key + ' created for failure on build ' + str(build)
def update_or_create_jira_issue(study_id, user_token, is_curator): try: params = app.config.get('JIRA_PARAMS') user_name = params['username'] password = params['password'] updated_studies = [] try: jira = JIRA(options=options, basic_auth=(user_name, password)) except: return False, 'Could not connect to JIRA server, incorrect username or password?', updated_studies # Get the MetaboLights project mtbls_project = jira.project(project) studies = [study_id] if not study_id and is_curator: studies = get_all_studies(user_token) for study in studies: study_id = study[0] user_name = study[1] release_date = study[2] update_date = study[3] study_status = study[4] curator = study[5] issue = [] summary = None # Get an issue based on a study accession search pattern search_param = "project='" + mtbls_project.key + "' AND summary ~ '" + study_id + " \\\-\\\ 20*'" issues = jira.search_issues(search_param) # project = MetaboLights AND summary ~ 'MTBLS121 ' new_summary = study_id + ' - ' + release_date.replace('-', '') + ' - ' + \ study_status + ' (' + user_name + ')' try: if issues: issue = issues[0] else: if study_status == 'Submitted': logger.info("Could not find Jira issue for " + search_param) print("Creating new Jira issue for " + search_param) issue = jira.create_issue(project=mtbls_project.key, summary='MTBLS study - To be updated', description='Created by API', issuetype={'name': 'Story'}) else: continue # Only create new cases if the study is in status Submitted except Exception: # We could not find or create a Jira issue continue summary = issue.fields.summary # Follow pattern 'MTBLS123 - YYYYMMDD - Status' try: assignee = issue.fields.assignee.name except: assignee = "" valid_curator = False jira_curator = "" if curator: if curator.lower() == 'mark': jira_curator = 'mwilliam' valid_curator = True elif curator.lower() == 'keeva': jira_curator = 'keeva' valid_curator = True else: jira_curator = "" # Release date or status has changed, or the assignee (curator) has changed if summary.startswith('MTBLS') and (summary != new_summary or assignee != jira_curator): # Add "Curation" Epic issues_to_add = [issue.key] jira.add_issues_to_epic(curation_epic, issues_to_add) # Add the Curation Epic labels = maintain_jira_labels(issue, study_status, user_name) # Add a comment to the issue. comment_text = 'Status ' + study_status + '. Database update date ' + update_date jira.add_comment(issue, comment_text) # Change the issue's summary, comments and description. issue.update(summary=new_summary, fields={"labels": labels}, notify=False) if valid_curator: # ToDo, what if the curation log is not up to date? issue.update(assignee={'name': jira_curator}) updated_studies.append(study_id) logger.info('Updated Jira case for study ' + study_id) print('Updated Jira case for study ' + study_id) except Exception: return False, 'Update failed', updated_studies return True, 'Ticket(s) updated successfully', updated_studies
# -*- coding: utf-8 -*- from jira import JIRA jira_server = 'http://10.10.10.10:8080' jira_username = '******' jira_password = '******' myjira = JIRA(jira_server,basic_auth=(jira_username,jira_password)) myissue = myjira.issue('WWTES-69') print (myissue) myjira.add_comment(myissue, 'commented by python') # missue = myissue.fields.customfield_13412.displayName # summary = myissue.fields.customfield_13412; # print(missue, summary)
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
class JiraCI: resolution_state = {"fixed": "1", "wont fixed": "2", "duplicate": "3", "incomplete": "4", "cannot reproduce": "5", "not a bug": "6", "done": "7"} def __init__(self, jira_url, login, password): if version_info[1] <= 6: options = jira_url else: options = {"server": jira_url} self.jira = JIRA(options, basic_auth=(login, password)) @staticmethod def debug_jira(text): stdout.write("[DEBUG JIRA]: {0}\n".format(text)) def check_issue_exist(self, issue_id): try: self.jira.issue(issue_id) except JIRAError as e: print "[-] : {0} - {1}".format(issue_id, e.text) return False else: return True def check_issue_state(self, issue_id, issue_state): jira_issue = self.jira.issue(issue_id) if jira_issue.fields.status.name.lower() == issue_state.lower(): return True else: return False def add_comment(self, issue_id, comment, formatting=False): jira_issue = self.jira.issue(issue_id) if formatting: comment = "{code}" + comment + "{code}" if not self.check_comment_exist(issue_id, comment): self.jira.add_comment(jira_issue, comment) self.debug_jira("Comment (for {0}) : {1} added".format(issue_id, comment.rstrip())) else: self.debug_jira("Comment (for {0}) : {1} already exist".format(issue_id, comment.rstrip())) def assign_issue(self, issue_id, assigned_user): jira_issue = self.jira.issue(issue_id) jira_issue.update(assignee={"name": assigned_user}) def add_link(self, issue_id, title, url): url_object = {"url": url, "title": title} if not self.check_link_exist(issue_id, title, url): self.jira.add_remote_link(issue_id, url_object) self.debug_jira("Link (for {0}) : {1} added".format(issue_id, url)) else: self.debug_jira("Link (for {0}) : {1} already exist".format(issue_id, url)) def resolve_issue_to_reporter(self, issue_id): reporter = self.get_reporter_issue(issue_id) self.jira.transition_issue(issue_id, "5", resolution={"id": self.resolution_state["fixed"]}) self.assign_issue(issue_id, reporter) def get_reporter_issue(self, issue_id): jira_issue = self.jira.issue(issue_id) return jira_issue.fields.reporter.name def check_comment_exist(self, issue_id, new_comment): comments = [c.body for c in self.jira.comments(issue_id)] if new_comment in comments: return True return False def check_link_exist(self, issue_id, title, url): links = [l.raw["object"] for l in self.jira.remote_links(issue_id)] for link in links: if link["title"] == title and link["url"] == url: return True return False def resolve_from_git(self, issue_id, short_commit_message, title_url, package_url): if self.check_issue_exist(issue_id): if not self.check_issue_state(issue_id, "resolved"): self.resolve_issue_to_reporter(issue_id) self.debug_jira("Issue {0} already resolve".format(issue_id)) else: self.debug_jira("Issue {0} resolved".format(issue_id)) self.add_link(issue_id, title_url, package_url) self.add_comment(issue_id, short_commit_message, formatting=True) def refer_from_git(self, issue_id, commit_message): if self.check_issue_exist(issue_id): self.add_comment(issue_id, commit_message, formatting=True)
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
class Jira(object): """ jira operation class """ def __init__(self, **args): """ Init JIRA connection """ self.server = settings.CASELINK_JIRA['SERVER'] self.username = settings.CASELINK_JIRA['USER'] self.password = settings.CASELINK_JIRA['PASSWORD'] self.verify = False # TODO: move to settings self._jira = JIRA(options={ 'server': self.server, 'verify': self.verify, }, basic_auth=(self.username, self.password)) def search_issues(self, project_name, jql_str, fields=None): """ Search issue under the project and return result """ jql_str = "project = " + project_name + " and " + jql_str return self.jira_.search_issues(jql_str, maxResults=-1, fields=fields) def add_comment(self, issue, comment): """ Add comments in the issue """ if isinstance(issue, (str, unicode)): issue = self._jira.issue(issue) return self._jira.add_comment(issue, comment) def transition_issue(self, issue, status): """ Transition issue status to another """ self.jira_.transition_issue(issue, status) def get_watchers(self, issue): """ Get a watchers Resource from the server for an issue """ watcher_data = self.jira_.watchers(issue) return [str(w.key) for w in watcher_data.watchers] def add_watcher(self, issue, watchers): """ Append an issue's watchers list """ new_watchers = [] if isinstance(watchers, str): new_watchers.append(watchers) elif isinstance(watchers, list): new_watchers = watchers for watcher in new_watchers: self.jira_.add_watcher(issue, watcher) def remove_watcher(self, issue, watchers): """ Remove watchers from an issue's watchers list """ del_watchers = [] if isinstance(watchers, str): del_watchers.append(watchers) elif isinstance(watchers, list): del_watchers = watchers for watcher in del_watchers: self.jira_.remove_watcher(issue, watcher) def create_issue(self, issue_dict): """ Create Issue and apply some default properties """ dict_ = { 'project': { 'key': 'LIBVIRTAT', }, 'summary': None, 'description': None, 'priority': { 'name': 'Major', }, 'assignee': { 'name': None }, } parent_issue = issue_dict.pop('parent_issue', None) or settings.CASELINK_JIRA['DEFAULT_PARENT_ISSUE'] assignee = issue_dict.pop('assignee', None) or settings.CASELINK_JIRA['DEFAULT_ASSIGNEE'] dict_.update({ 'assignee': { 'name': assignee } }) if parent_issue: dict_.update({ 'parent': { 'id': parent_issue }, 'issuetype': { 'name': 'Sub-task' } }) else: dict_.update({ 'issuetype': { 'name': 'Task' } }) dict_.update(issue_dict) return self._jira.create_issue(dict_) # Helper functions def update_issue(self, issue, changes=None): trans = settings.CASELINK_JIRA['REOPEN_TRANSITION'] try: if isinstance(issue, (str, unicode)): issue = self._jira.issue(issue) return self._jira.transition_issue(issue, trans) except Exception: pass if changes: self.add_comment(issue, 'Polarion Workitem Changed: {code}%s{code}' % changes) def create_automation_request(self, wi_id, wi_title, wi_url, changes, assignee, parent_issue=None): description = AUTOMATION_REQUEST_DESCRIPTION.format( polarion_wi_id=wi_id, polarion_wi_title=wi_title, polarion_wi_url=wi_url, ) summary = AUTOMATION_REQUEST_SUMMARY.format( polarion_wi_id=wi_id, polarion_wi_title=wi_title ) assignee = assignee parent_issue = parent_issue return self.create_issue({ 'summary': summary, 'description': description, 'assignee': assignee, 'parent_issue': parent_issue }) def create_update_request(self, wi_id, wi_title, wi_url, changes, assignee, parent_issue=None): description = UPDATE_REQUEST_DESCRIPTION.format( polarion_wi_id=wi_id, polarion_wi_title=wi_title, polarion_wi_url=wi_url, polarion_wi_changes=changes ) summary = UPDATE_REQUEST_SUMMARY.format( polarion_wi_id=wi_id, polarion_wi_title=wi_title ) assignee = assignee parent_issue = parent_issue return self.create_issue({ 'summary': summary, 'description': description, 'assignee': assignee, 'parent_issue': parent_issue }) def get_issue_feedback(self, issue_key): issue = self._jira.issue(issue_key) status = str(issue.fields.status) resolution = str(issue.fields.resolution) comments = issue.fields.comment.comments if status == 'Done': for comment in reversed(comments): match = re.match(UPDATED_PATTERN_REGEX, comment.body, re.M) if match: return { "status": status, "resolution": resolution, "cases": filter(lambda x: x, map(lambda x: x.strip(), match.groupdict()['cases'].splitlines())), "prs": filter(lambda x: x, map(lambda x: x.strip(), match.groupdict()['prs'].splitlines())), } return { "status": status, "resolution": resolution, "cases": None, "prs": None, }