예제 #1
0
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))
예제 #2
0
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')
예제 #3
0
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
예제 #4
0
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 + ")")
예제 #5
0
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))
예제 #7
0
 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'])
예제 #8
0
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
예제 #9
0
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
예제 #12
0
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
                
예제 #13
0
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)
예제 #14
0
            },
            '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
예제 #15
0
def change_jira(issue):
    authed_jira = JIRA('http://jira.xxx.com/',
                       basic_auth=('qudian_sec', 'xxx'))
    authed_jira.assign_issue(issue, 'qudian_sec')
예제 #16
0
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)
예제 #17
0
                    "--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'):
예제 #18
0
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 []
예제 #19
0
    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)
       
        
예제 #20
0
    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
예제 #22
0
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)
예제 #23
0
        },
        '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': {
예제 #25
0
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)
예제 #26
0
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
예제 #27
0
    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
예제 #28
0
    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="******",
예제 #29
0
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
예제 #31
0
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
예제 #32
0
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)
예제 #33
0
            '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():
예제 #36
0
                            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)
예제 #37
0
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