def createcomponent():
    print "start to create component in jira"
    fname = "demo3.xls"
    bk = xlrd.open_workbook(fname)

    #获取用户名密码
    try:
        login = bk.sheet_by_name("login")
    except:
        print "no sheet in %s named login , can't login jira without it" % fname

    rowl = login.row_values(1)
    jira = JIRA('http://172.16.3.139:80/', basic_auth=('admin', 'admin'))
    project = 'PSR'
    #获取模块信息
    try:
        sh = bk.sheet_by_name("info")
    except:
        print "no sheet in %s named info" % fname

    nrows = sh.nrows
    ncols = sh.ncols
    print "nrows %d, ncols %d" % (nrows, ncols)

    #创建模块
    for i in range(1, nrows):
        rowd = sh.row_values(i)
        try:
            new_component = jira.create_component(
                rowd[0],
                project,
                description=rowd[1],
                leadUserName=rowd[2],
                assigneeType='COMPONENT_LEAD',
                isAssigneeTypeValid=True)
            print new_component
        except BaseException, e:
            print "create error in %d" % (i + 1)
            e = str(e).split(":")[-1].strip()
            cmd = "cat %s |tail -1" % (e)
            faillog = commands.getoutput(cmd)
            print faillog
Exemple #2
0
    if month in [1, 3, 5, 7, 8, 10, 12]:
        days = 31
    if month == 2:
        days = 29
    prefix = ""
    if month < 10:
        prefix = "0"
    monthStr = "{0}{1}".format(prefix, month)
    version = "{0}.{1}".format(year,monthStr)
    endDate = "{0}{1}-{2}-{3}".format("20", year, monthStr, days)
    createVersions and jira.create_version(version, projectKey, releaseDate=endDate)


# Creacion de componentes
for component in componentsToCreate(projectKey, componentsList):
    createComponents and jira.create_component(component, projectKey)
    print("------------>> " + component)

# Eliminacion de componentes
for myComponent in gettingComponentes(projectKey):
    deleteComponents and jira.delete_component(myComponent.id)

# Obtener descripcion aleatoria
def getIssueDescription():
    return " ".join([random.choice(i) for i in l])

# Obtener array de componentes
def getComponents():
    numberOfComponents = random.sample([1, 1, 2], 1)[0]
    myComponents = random.sample(["db", "redis", "tutorial", "result", "vote", "worker"], numberOfComponents)
    arrayComponents = []
Exemple #3
0
class JiraTool():
    def __init__(self, server, username, password, maxResults = 500):
        self.server = server
        self.basic_auth = (username, password)
        # issues查询的最大值
        self.maxResults = maxResults

    def login(self):
        self.jira = JIRA(server=self.server, basic_auth=self.basic_auth)
        if self.jira == None:
            print('连接失败')
            sys.exit(-1)

    def get_projects(self):
        """
        获得jira 的所有项目
        :return:
        """
        return [(p.key, p.name, p.id) for p in self.jira.projects()]

    def get_components(self, project):
        """
        获得某项目的所有模块
        :param project:
        :return:
        """
        return [(c.name, c.id) for c in self.jira.project_components(self.jira.project(project))]

    def create_component(self, project, compoment, description, leadUserName=None, assigneeType=None,
                         isAssigneeTypeValid=False):
        """
        # 创建项目模块
        :param project: 模块所属项目
        :param compoment:模块名称
        :param description:模块描述
        :param leadUserName:
        :param assigneeType:
        :param isAssigneeTypeValid:
        :return:
        """
        components = self.jira.project_components(self.jira.project(project))
        if compoment not in [c.name for c in components]:
            self.jira.create_component(compoment, project, description=description, leadUserName=leadUserName,
                                       assigneeType=assigneeType, isAssigneeTypeValid=isAssigneeTypeValid)

    def create_issue(self, project, compoment, summary, description, assignee, issuetype, priority='Medium'):
        """
        创建提交bug
        :param project: 项目
        :param issuetype: 问题类型,Task
        :param summary: 主题
        :param compoment: 模块
        :param description: 描述
        :param assignee: 经办人
        :param priority: 优先级
        :return:
        """
        issue_dict = {
            'project': {'key': project},
            'issuetype': {'id': issuetype},
            'summary': summary,
            'components': [{'name': compoment}],
            'description': description,
            'assignee': {'name': assignee},
            'priority': {'name': priority},
        }
        return self.jira.create_issue(issue_dict)

    def delete_issue(self, issue):
        """
        删除bug
        :param issue:
        :return:
        """
        issue.delete()

    def update_issue_content(self, issue, issue_dict):
        """
        更新bug内容
        :param issue:
        :param issue_dict:
            issue_dict = {
                'project': {'key': project},
                'issuetype': {'id': issuetype},
                'summary': summary,
                'components': [{'name': compoment}],
                'description': description,
                'assignee': {'name': assignee},
                'priority': {'name': priority},
            }
        :return:
        """
        issue.update(fields=issue_dict)
    def update_issue_issuetype(self, issue, issuetype):
        """
        更新bug 状态
        :param issue:
        :param issuetype: 可以为id值如11,可以为值如'恢复开启问题'
        :return:
        """
        transitions = self.jira.transitions(issue)
        # print([(t['id'], t['name']) for t in transitions])
        self.jira.transition_issue(issue, issuetype)

    def search_issues(self, jql):
        """
        查询bug
        :param jql: 查询语句,
                    如"project=项目key AND component = 模块 AND status=closed AND summary ~标题 AND description ~描述"
        :return:
        """
        try:
            # maxResults参数是设置返回数据的最大值,默认是50。
            issues = self.jira.search_issues(jql, maxResults=self.maxResults)
        except Exception as e:
            print(e)
            sys.exit(-1)
        return issues
    def search_issue_content(self, issue, content_type):
        """
        获取bug 的相关信息
        :param issue:
        :param content_type:项目project; 模块名称components; 标题summary; 缺陷类型issuetype; 具体描述内容description;
                            经办人assignee; 报告人reporter; 解决结果resolution; bug状态status; 优先级priority;
                            创建时间created; 更新时间updated; 评论comments
        :return:
        """
        # 评论
        if content_type == 'comments':
            return [c.body for c in self.jira.comments(issue)]
        if hasattr(issue.fields, content_type):
            result = getattr(issue.fields, content_type)
            if isinstance(result, list):
                return [c.name for c in result if hasattr(c, 'name')]
            return result

    def collect_bug_report(self, project, root_path):
        """
        搜集bug报告上模块信息
        :param project:
        :param root_path:
        :return:
        """
        import os

        statistics_path = root_path + '/BugReport/statistics/'
        reports_path = root_path + '/BugReport/reports/' + project + '/'
        if not os.path.exists(statistics_path):
            os.makedirs(statistics_path)
        if not os.path.exists(reports_path):
            os.makedirs(reports_path)

        text = 'id, Key, Type, Status, Resolution, Priority, components, AffectsVersions, FixedVersions, Reporter, ' \
               'Creator, Assignee, CreatedDate, ResolutionDate, UpdatedDate, Summary\n'
        search_str = 'project = ' + project.upper() + ' AND issuetype = Bug AND status in (Resolved, Closed) AND ' \
                                                      'resolution in (Fixed, Resolved) ORDER BY key ASC'

        start = 0
        max_results_each_search = 1000
        while True:
            try:
                # maxResults参数是设置返回数据的最大值,默认是50。
                issues = self.jira.search_issues(search_str, startAt=start, maxResults=max_results_each_search)
            except Exception as e:
                print(e)
                sys.exit(-1)

            for issue in issues:
                text += issue.id + ','
                text += issue.key + ','
                text += issue.fields.issuetype.name + ','
                text += issue.fields.status.name + ','
                text += issue.fields.resolution.name + ','
                priority_name = 'Unassigned' if issue.fields.priority is None else issue.fields.priority.name
                text += priority_name + ','
                components = issue.fields.components
                if len(components) > 0:
                    for component in components:
                        text += component.name + '|'
                text += ','
                if hasattr(issue.fields, 'versions'):
                    for version in issue.fields.versions:
                        text += version.name + '|'
                text += ','
                for version in issue.fields.fixVersions:
                    text += version.name + '|'
                text += ','
                reporterName = 'Unassigned' if issue.fields.reporter is None else issue.fields.reporter.displayName
                creatorName = 'Unassigned' if issue.fields.creator is None else issue.fields.creator.displayName
                assigneeName = 'Unassigned' if issue.fields.assignee is None else issue.fields.assignee.displayName
                text += reporterName + ','
                text += creatorName + ','
                text += assigneeName + ','
                text += issue.fields.created + ','
                text += issue.fields.resolutiondate + ','
                text += issue.fields.updated + ','
                text += issue.fields.summary + ','
                # 输出报告内容
                with open(reports_path + issue.key + '.txt', 'w', encoding='utf-8') as fw:
                    description = 'Summary:\n' + issue.fields.summary + '\nDescription:\n'
                    description += '' if issue.fields.description is None else issue.fields.description
                    fw.write(description)
                    fw.close()
                text += '\n'

            start += max_results_each_search
            print(start)
            if start > issues.total:
                break
        # 输出项目统计信息
        with open(statistics_path + project + '.csv', 'w', encoding='utf-8') as fw:
            fw.write(text)
            fw.close()

        print('The collection for bug reports of Project ' + project + ' has finished!')
Exemple #4
0
###Get 'raw' lists (Jira classes are not so handy)
listSrc = []
listDst = []

for i in projSrc:
    if cMatch.match(str(i)):
        listSrc.append(str(i))

for i in projDst:
    if cMatch.match(str(i)):
        listDst.append(str(i))

###Get absent strings
toAdd = []

for item in listSrc:
    if item not in listDst:
        toAdd.append(item)

####Add absent strings to project components.
if toAdd != []:
    for item in toAdd:
        print("Adding absent component:", item)
        jira.create_component(name=item,
                              project=args.dest,
                              description='Business Component',
                              assigneeType='UNASSIGNED')
else:
    print("Nothing to add.")
Exemple #5
0
class Strategy:
    def __init__(self, account_name, user_name, user_password):
        self._account = account_name
        self._user = user_name
        self._password = user_password
        self._server = 'https://{}.atlassian.net'.format(self._account)
        self._jira_connection = JIRA(server=self._server,
                                     basic_auth=(self._user, self._password))
        self._makelog = makelog.Makelog('output', 'errorlog')

    def execute(self, key):
        if key == 1:
            self._doreporting()
        elif key == 2:
            self._domailing()
        elif key == 3:
            self._dogenerating()
        else:
            return False

    def _doreporting(self):
        data_peruser = {}
        data_percomponent = {}

        # getting all users
        users_all = self._jira_connection.search_users('%',
                                                       maxResults=False,
                                                       includeInactive=True)
        for user in users_all:
            data_peruser[user.name] = {
                'time_total': 0,
                'time_perissue': {},
                'actual_name': user.displayName,
                'components': set()
            }

        # getting all components
        components_all = set()
        projects_all = self._jira_connection.projects()
        for project in projects_all:
            try:
                comps = self._jira_connection.project_components(project)
                components_all.update(comps)
            except:
                outstr = "Unexpected error with getting components from project: {}\n".format(
                    project.key)
                self._makelog.putto_console(outstr)
                self._makelog.putto_errorlog(outstr, traceback.format_exc())

        for comp in components_all:
            try:
                component_data = self._jira_connection.component(comp.id)
                data_percomponent[component_data.id] = {
                    'name':
                    component_data.name,
                    'projectkey':
                    component_data.project,
                    'time_total':
                    0,
                    'time_perissue': {},
                    'lead':
                    '' if not hasattr(component_data, 'lead') else
                    component_data.lead.name
                }
                if hasattr(component_data, 'lead'):
                    data_peruser[component_data.lead.name]['components'].add(
                        component_data.id)
            except:
                outstr = "Unexpected error with getting data of component id: {}\n".format(
                    comp.id)
                self._makelog.putto_console(outstr)
                self._makelog.putto_errorlog(outstr, traceback.format_exc())

        # counting hours logic
        issues_all = self._jira_connection.search_issues('', maxResults=False)
        for iss in issues_all:
            try:
                iss_works = self._jira_connection.worklogs(iss)
                for work in iss_works:
                    # per user
                    data_peruser[work.author.
                                 name]['time_total'] += work.timeSpentSeconds
                    if iss.key not in data_peruser[
                            work.author.name]['time_perissue']:
                        data_peruser[work.author.name]['time_perissue'][
                            iss.key] = 0
                    data_peruser[work.author.name]['time_perissue'][
                        iss.key] += work.timeSpentSeconds

                    # per valid component (with lead)
                    for comp in iss.fields.components:
                        if data_percomponent[
                                comp.id]['lead'] == work.author.name:
                            data_percomponent[
                                comp.id]['time_total'] += work.timeSpentSeconds
                            if iss.key not in data_percomponent[
                                    comp.id]['time_perissue']:
                                data_percomponent[comp.id]['time_perissue'][
                                    iss.key] = 0
                            data_percomponent[comp.id]['time_perissue'][
                                iss.key] += work.timeSpentSeconds
            except:
                outstr = "Unexpected error counting hours with issue: {}\n".format(
                    iss.key)
                self._makelog.putto_console(outstr)
                self._makelog.putto_errorlog(outstr, traceback.format_exc())

        # outputting data
        outstr = ""
        outstr += "\t\t\tReport on the spent hours:\n"
        outstr += "\n\t\tPer programmer:\n\n"
        for user_name, user_dat in data_peruser.iteritems():
            outstr += "-> Name: {} ({})\n".format(user_dat['actual_name'],
                                                  user_name)
            outstr += "   Total time: {} hour(s)\n".format(
                str(user_dat['time_total'] / 3600))
            outstr += "   Time per issue:\n"
            for iss_key, time_val in user_dat['time_perissue'].iteritems():
                outstr += "\t{} is: {} hour(s)\n".format(
                    iss_key, str(time_val / 3600))

            outstr += "\n"

        outstr += "\n\t\tPer component (with lead only):\n\n"
        for comp_id, comp_dat in data_percomponent.iteritems():
            outstr += "-> Name: {} ({})\n".format(comp_dat['name'],
                                                  comp_dat['projectkey'])
            outstr += "   Lead: {}\n".format(comp_dat['lead'])
            outstr += "   Total time: {} hour(s)\n".format(
                str(comp_dat['time_total'] / 3600))
            outstr += "   Time per issue:\n"
            for iss_key, time_val in comp_dat['time_perissue'].iteritems():
                outstr += "\t{} is: {} hour(s)\n".format(
                    iss_key, str(time_val / 3600))

            outstr += "\n"

        outstr += "\n-----> END REPORT <-----\n\n"
        self._makelog.putto_console(outstr, iscln=True)
        self._makelog.putto_file(outstr)

    def _domailing(self):
        issues_tonotify = []
        issues_all = self._jira_connection.search_issues('', maxResults=False)
        for iss in issues_all:
            try:
                iss_data = self._jira_connection.issue(iss)
                if (iss_data.fields.timeestimate is None) or (len(
                        iss_data.fields.components) == 0):
                    issues_tonotify.append({
                        'name':
                        iss_data.fields.assignee.name,
                        'dispname':
                        iss_data.fields.assignee.displayName,
                        'email':
                        iss_data.fields.assignee.emailAddress,
                        'isskey':
                        iss.key
                    })
            except:
                outstr = "Unexpected error with getting issue: {}\n".format(
                    iss.key)
                self._makelog.putto_console(outstr)
                self._makelog.putto_errorlog(outstr, traceback.format_exc())

        for data in issues_tonotify:
            try:
                url = "{}/rest/api/2/issue/{}/notify".format(
                    self._server, data['isskey'])
                notify_data = {
                    "subject":
                    "You have some incomplete fields in issue {}".format(
                        data['isskey']),
                    "textBody":
                    "Your got this notification because have one or couple incomplete fields in {} issue. Note, that 'estimates' \
                                            and 'component' fields are mandatory. Please, check this fields and fill its in if need."
                    .format(data['isskey']),
                    "to": {
                        "users": [{
                            "name": data['name']
                        }]
                    },
                }

                requests.post(url,
                              auth=(self._user, self._password),
                              json=notify_data)
                outstr = "Successfully sending notification to:\n-> {} {} about incomplete fields in {} issue\n".format(
                    data['dispname'], data['email'], data['isskey'])
                self._makelog.putto_console(outstr)
                self._makelog.putto_file(outstr)
            except:
                outstr = "Unexpected error with sending notification to:\n-> {} {} about: {}\n".format(
                    data['dispname'], data['email'], data['isskey'])
                self._makelog.putto_console(outstr)
                self._makelog.putto_errorlog(outstr, traceback.format_exc())

        if len(issues_tonotify) == 0:
            self._makelog.putto_console(
                "All tested issues were filed in correct")

    def _dogenerating(self):
        names_base = namebase.Namebase()
        maxlen_projname = 10
        content_count = {
            'project': 1,
            'user': 1,
            'component': 2,
            'issue': 10,
            'worklog': 20
        }

        # making projects
        for i in xrange(content_count['project']):
            newname = names_base.getname_project()
            parts = newname.split()[::2]
            newkey = string.join(
                (parts[0][:(maxlen_projname - len(parts[1]))], parts[1]), '')
            try:
                self._jira_connection.create_project(newkey, name=newname)
                outstr = "Project {} was successfully created\n".format(newkey)
                self._makelog.putto_console(outstr)
                self._makelog.putto_file(outstr)
            except:
                outstr = "Some problem with project {} creation\n".format(
                    newkey)
                self._makelog.putto_console(outstr)
                self._makelog.putto_errorlog(outstr, traceback.format_exc())

        # making users
        for i in xrange(content_count['user']):
            newname = names_base.getname_user()
            try:
                self._jira_connection.add_user(newname, "{}@mail.net".format(newname),\
                                                fullname="Name {}{}".format(string.upper(newname[:1]), newname[1:]))
                outstr = "User {} was successfully created\n".format(newname)
                self._makelog.putto_console(outstr)
                self._makelog.putto_file(outstr)
            except:
                outstr = "Some problem with user {} creation\n".format(newname)
                self._makelog.putto_console(outstr)
                self._makelog.putto_errorlog(outstr, traceback.format_exc())

        # getting all valid project keys
        projects_keys = []
        projects_all = self._jira_connection.projects()
        for project in projects_all:
            projects_keys.append(project.key)

        # getting all valid user names
        users_keys = []
        users_all = self._jira_connection.search_users('%',
                                                       maxResults=False,
                                                       includeInactive=True)
        for user in users_all:
            users_keys.append(user.name)

        # making components
        for i in xrange(content_count['component']):
            newname = names_base.getname_component()
            try:
                self._jira_connection.create_component(
                    newname,
                    random.choice(projects_keys),
                    leadUserName=random.choice(users_keys))
                outstr = "Component {} was successfully created\n".format(
                    newname)
                self._makelog.putto_console(outstr)
                self._makelog.putto_file(outstr)
            except:
                outstr = "Some problem with component {} creation\n".format(
                    newname)
                self._makelog.putto_console(outstr)
                self._makelog.putto_errorlog(outstr, traceback.format_exc())

        # making issues
        for i in xrange(content_count['issue']):
            newname = names_base.getname_issue()
            fields = {
                "project": {
                    "key": random.choice(projects_keys)
                },
                "summary":
                "Here should be some random text summary for issue {}".format(
                    newname),
                "description":
                "Here should be some random text description for issue {}".
                format(newname),
                "issuetype": {
                    "name":
                    random.choice(
                        ("Bug", "Improvement", "Task", "Epic", "New Feature"))
                },
                "assignee": {
                    "name": random.choice(users_keys)
                },
                "timetracking": {
                    "originalEstimate":
                    "{}w {}d {}h".format(random.randint(1, 3),
                                         random.randint(1, 4),
                                         random.randint(1, 7)),
                    "remainingEstimate":
                    "{}d {}h".format(random.randint(1, 4),
                                     random.randint(1, 7))
                }
            }
            try:
                self._jira_connection.create_issue(fields=fields)
                outstr = "Issue {} was successfully created\n".format(newname)
                self._makelog.putto_console(outstr)
                self._makelog.putto_file(outstr)
            except:
                outstr = "Some problem with issue {} creation\n".format(
                    newname)
                self._makelog.putto_console(outstr)
                self._makelog.putto_errorlog(outstr, traceback.format_exc())

        # making worklogs
        issues_all = self._jira_connection.search_issues('', maxResults=False)
        for i in xrange(content_count['worklog']):
            iss = random.choice(issues_all)
            try:
                self._jira_connection.add_worklog(iss, timeSpent="{}h".format(random.randint(1, 3)), user=random.choice(users_keys),\
                                                    comment="Here should be some random text about work on this issue")
                outstr = "Worklog for issue {} was successfully created\n".format(
                    iss.key)
                self._makelog.putto_console(outstr)
                self._makelog.putto_file(outstr)
            except:
                outstr = "Some problem with worklog creation for issue {}\n".format(
                    iss.key)
                self._makelog.putto_console(outstr)
                self._makelog.putto_errorlog(outstr, traceback.format_exc())
class JiraTool(object):
    def __init__(self, server, username, password, maxResults=50):
        self.server = server
        self.basic_auth = (username, password)
        # issues查询的最大值
        self.maxResults = maxResults

    def login(self):
        self.jira = JIRA(server=self.server, basic_auth=self.basic_auth)
        if self.jira == None:
            print('连接失败')
            sys.exit(-1)

    def get_projects(self):
        """
        获得jira 的所有项目
        :return:
        """
        return [(p.key, p.name, p.id) for p in self.jira.projects()]

    # def get_components(self, project):
    #     """
    #     获得某项目的所有模块
    #     :param project:
    #     :return:
    #     """
    #     return [(c.name, c.id) for c in self.jira.project_components(self.jira.project(project))]

    def create_component(self,
                         project,
                         compoment,
                         description,
                         leadUserName=None,
                         assigneeType=None,
                         isAssigneeTypeValid=False):
        """
        # 创建项目模块
        :param project: 模块所属项目
        :param compoment:模块名称
        :param description:模块描述
        :param leadUserName:
        :param assigneeType:
        :param isAssigneeTypeValid:
        :return:
        """
        components = self.jira.project_components(self.jira.project(project))
        if compoment not in [c.name for c in components]:
            self.jira.create_component(compoment,
                                       project,
                                       description=description,
                                       leadUserName=leadUserName,
                                       assigneeType=assigneeType,
                                       isAssigneeTypeValid=isAssigneeTypeValid)

    def create_issue(self,
                     project,
                     compoment,
                     summary,
                     description,
                     assignee,
                     issuetype,
                     priority='Medium'):
        """
        创建提交issue
        :param project: 项目
        :param issuetype: 问题类型,Task
        :param summary: 主题
        :param compoment: 模块
        :param description: 描述
        :param assignee: 经办人
        :param priority: 优先级
        :return:
        """
        issue_dict = {
            'project': {
                'key': project
            },
            'issuetype': {
                'id': issuetype
            },
            'summary': summary,
            'components': [{
                'name': compoment
            }],
            'description': description,
            'assignee': {
                'name': assignee
            },
            'priority': {
                'name': priority
            },
        }
        return self.jira.create_issue(issue_dict)

    def delete_issue(self, issue):
        """
        删除issue
        :param issue:
        :return:
        """
        issue.delete()

    def update_issue_content(self, issue, issue_dict):
        """
        更新issue内容
        :param issue:
        :param issue_dict:
            issue_dict = {
                'project': {'key': project},
                'issuetype': {'id': issuetype},
                'summary': summary,
                'components': [{'name': compoment}],
                'description': description,
                'assignee': {'name': assignee},
                'priority': {'name': priority},
            }
        :return:
        """
        issue.update(fields=issue_dict)

    def update_issue_issuetype(self, issue, issuetype):
        """
        更新bug 状态
        :param issue:
        :param issuetype: 可以为id值如11,可以为值如'恢复开启问题'
        :return:
        """
        transitions = self.jira.transitions(issue)
        # print([(t['id'], t['name']) for t in transitions])
        self.jira.transition_issue(issue, issuetype)

    def search_all_issue(self, jql):
        block_size = 100
        block_num = 0
        issues = []
        while True:
            start_idx = block_num * block_size
            part_issues = self.jira.search_issues(jql, start_idx, block_size)
            if len(part_issues) == 0:
                break
            block_num += 1
            issues.extend(part_issues)
        return issues

    # def search_issues(self, jql):
    #     """
    #     查询bug
    #     :param jql: 查询语句,如"project=项目key AND component = 模块 AND status=closed AND summary ~标题 AND description ~描述"
    #     :return:
    #     """
    #     try:
    #         # maxResults参数是设置返回数据的最大值,默认是50。
    #         issues = self.jira.search_issues(jql, maxResults=self.maxResults)
    #     except Exception as e:
    #         print(e)
    #         sys.exit(-1)
    #     return issues

    def search_issue_content(self, issue, content_type):
        """
        获取issue 的相关信息
        :param issue:
        :param content_type:项目project; 模块名称components; 标题summary; 缺陷类型issuetype; 具体描述内容description; 经办人assignee; 报告人reporter; 解决结果resolution; bug状态status; 优先级priority; 创建时间created; 更新时间updated; 评论comments
        :return:
        """
        # 评论
        if content_type == 'comments':
            return [c.body for c in self.jira.comments(issue)]
        if hasattr(issue.fields, content_type):
            result = getattr(issue.fields, content_type)
            if isinstance(result, list):
                return [c.name for c in result if hasattr(c, 'name')]
            return result

    def get_issue_types(self):
        """
        获取所有issues类型
        :return:
        """
        issue_type_name = []
        issue_types = self.jira.issue_types()
        for issue_type in issue_types:
            issue_type_name.append(issue_type.name)
        return issue_type_name

    def get_components(self, issue):
        """
        获取组件字段
        :param issue: 每个issue
        :return:
        """
        for i in issue.fields.components:
            components = i.name
            return components

    def get_epic_link(self, issue):
        """
        获取epic_link字段
        :param issue: 每个issue
        :return:
        """
        for i in issue.fields.customfield_10900:
            epic_link = i.name
            return epic_link

    def make_cse_env_num(self, cse_num):
        try:
            res = cse_num.split('-')
            num = int(res[1]) + 1
            cse_env_nu = 'CSE-' + str(num)
        except Exception as e:
            cse_env_nu = ''
        return cse_env_nu

    def get_result(self, issue):
        """
        获取处理结果的字段  如 产品问题、环境问题
        :param issue:
        :return:
        """
        if issue.fields.customfield_11100:
            result = issue.fields.customfield_11100.value
        else:
            result = ''
        return result

    def get_resolve_time(self, issue):
        try:
            resolve_time = issue.fields.resolutiondate[0:19]
        except Exception as e:
            print(e)
            resolve_time = ''
        print(resolve_time)
        return resolve_time
Exemple #7
0
class ViraAPI():
    '''
    This class gets imported by __init__.py
    '''
    def __init__(self):
        '''
        Initialize vira
        '''

        # Load user-defined config files
        file_servers = vim.eval('g:vira_config_file_servers')
        file_projects = vim.eval('g:vira_config_file_projects')
        try:
            self.vira_servers = load_config(file_servers)
            self.vira_projects = load_config(file_projects)
        except:
            print(f'Could not load {file_servers} or {file_projects}')

        self.userconfig_filter_default = {
            'assignee': '',
            'component': '',
            'fixVersion': '',
            'issuetype': '',
            'priority': '',
            'project': '',
            'reporter': '',
            'status': '',
            "'Epic Link'": '',
            'statusCategory': ['To Do', 'In Progress'],
            'text': ''
        }
        self.reset_filters()

        self.userconfig_newissue = {
            'assignee': '',
            'component': '',
            'fixVersion': '',
            'issuetype': 'Bug',
            'priority': '',
            'epics': '',
            'status': '',
        }

        self.users = set()
        self.versions = set()
        self.servers = set()
        self.users_type = ''
        self.async_count = 0

        self.versions_hide(True)

    def _async(self, func):
        try:
            func()
        except:
            pass

    def _async_vim(self):
        #  TODO: VIRA-247 [210223] - Clean-up vim variables in python _async
        try:
            if len(vim.eval('s:versions')) == 0:
                vim.command('let s:projects = s:projects[1:]')
                if len(vim.eval('s:projects')) == 0:
                    #  TODO: VIRA-247 [210223] - Check for new projects and versions and start PRIORITY ranking for updates
                    vim.command('let s:vira_async_timer = g:vira_async_timer')
                    self.get_projects()
                self.get_versions()
            else:
                #  self.version_percent(str(vim.eval('s:projects[0]')), str(vim.eval('s:versions[0]')))
                vim.command('let s:versions = s:versions[1:]')

            if self.async_count == 0 and vim.eval(
                    's:vira_async_timer') == 10000:
                self.users = self.get_users()
                self.async_count = 1000
            self.async_count -= 1
        except:
            pass

    def create_issue(self, input_stripped):
        '''
        Create new issue in jira
        '''

        section = {
            'summary':
            parse_prompt_text(input_stripped, '*Summary*', 'Description'),
            'description':
            parse_prompt_text(input_stripped, 'Description', '*Project*'),
            'project':
            parse_prompt_text(input_stripped, '*Project*', '*IssueType*'),
            'issuetype':
            parse_prompt_text(input_stripped, '*IssueType*', 'Status'),
            'status':
            parse_prompt_text(input_stripped, 'Status', 'Priority'),
            'priority':
            parse_prompt_text(input_stripped, 'Priority', 'Component'),
            'components':
            parse_prompt_text(input_stripped, 'Component', 'Version'),
            'fixVersions':
            parse_prompt_text(input_stripped, 'Version', 'Assignee'),
            'assignee':
            parse_prompt_text(input_stripped, 'Assignee'),
        }

        # Check if required fields was entered by user
        if section['summary'] == '' or section['project'] == '' or section[
                'issuetype'] == '':
            return

        issue_kwargs = {
            'project': section['project'],
            'summary': section['summary'],
            'description': section['description'],
            'issuetype': {
                'name': section['issuetype']
            },
            'priority': {
                'name': section['priority']
            },
            'components': [{
                'name': section['components']
            }],
            'fixVersions': [{
                'name': section['fixVersions']
            }],
            'assignee': {
                'name': section['assignee']
            },
        }

        # Jira API doesn't accept empty fields for certain keys
        for key in issue_kwargs.copy().keys():
            if section[key] == '':
                issue_kwargs.pop(key)

        # Create issue and transition
        issue_key = self.jira.create_issue(**issue_kwargs)
        if section['status'] != '':
            self.jira.transition_issue(issue_key, section['status'])

        jira_server = vim.eval('g:vira_serv')
        print(f'Added {jira_server}/browse/{issue_key}')

    def add_worklog(self, issue, timeSpentSeconds, comment):
        '''
        Calculate the offset for the start time of the time tracking
        '''

        earlier = datetime.now() - datetime.timedelta(seconds=timeSpentSeconds)

        self.jira.add_worklog(issue=issue,
                              timeSpentSeconds=timeSpentSeconds,
                              comment=comment,
                              started=earlier)

    def connect(self, server):
        '''
        Connect to Jira server with supplied auth details
        '''

        self.users = set()
        self.versions = set()
        self.users_type = ''

        try:
            # Specify whether the server's TLS certificate needs to be verified
            if self.vira_servers[server].get('skip_cert_verify'):
                urllib3.disable_warnings(
                    urllib3.exceptions.InsecureRequestWarning)
                cert_verify = False
            else:
                cert_verify = True

            # Get auth for current server
            username = self.vira_servers[server].get('username')
            password_cmd = self.vira_servers[server].get('password_cmd')
            if password_cmd:
                password = run_command(password_cmd)['stdout'].strip().split(
                    '\n')[0]
            else:
                password = self.vira_servers[server]['password']
        except:
            cert_verify = True
            server = vim.eval('input("server: ")')
            vim.command('let g:vira_serv = "' + server + '"')
            username = vim.eval('input("username: "******"password: "******"' + server + '"')

            # Authorize
            self.jira = JIRA(options={
                'server': server,
                'verify': cert_verify,
            },
                             basic_auth=(username, password),
                             timeout=2,
                             async_=True,
                             max_retries=2)

            # Initial list updates
            self.users = self.get_users()
            self.get_projects()
            self.get_versions()

            vim.command('echo "Connection to jira server was successful"')
        except JIRAError as e:
            if 'CAPTCHA' in str(e):
                vim.command(
                    'echo "Could not log into jira! Check authentication details and log in from web browser to enter mandatory CAPTCHA."'
                )
            else:
                #  vim.command('echo "' + str(e) + '"')
                vim.command('let g:vira_serv = ""')
                #  raise e
        except:
            vim.command('let g:vira_serv = ""')
            vim.command(
                'echo "Could not log into jira! See the README for vira_server.json information"'
            )

    def filter_str(self, filterType):
        '''
        Build a filter string to add to a JQL query
        The string will look similar to one of these:
            AND status in ('In Progress')
            AND status in ('In Progress', 'To Do')
        '''

        if self.userconfig_filter.get(filterType, '') == '':
            return

        selection = str(
            self.userconfig_filter[filterType]).strip('[]') if type(
                self.userconfig_filter[filterType]
            ) == list else self.userconfig_filter[filterType] if type(
                self.userconfig_filter[filterType]
            ) == tuple else "'" + self.userconfig_filter[filterType] + "'"

        return str(f"{filterType} in ({selection})").replace(
            "'None'", "Null").replace("'Unassigned'", "Null").replace(
                "'currentUser'", "currentUser()").replace(
                    "'currentUser()'", "currentUser()").replace(
                        "'currentuser'", "currentUser()").replace(
                            "'currentuser()'",
                            "currentUser()").replace("'null'", "Null").replace(
                                f"text in ({selection})",
                                f"text ~ {selection}")

    def get_assign_issue(self):
        '''
        Menu to select users
        '''

        self.print_users()

    def get_assignees(self):
        '''
        Get my issues with JQL
        '''

        self.print_users()

    def get_comments(self, issue):
        '''
        Get all the comments for an issue
        '''

        # Get the issue requested
        issues = self.jira.search_issues('issue = "' + issue.key + '"',
                                         fields='summary,comment',
                                         json_result='True')

        # Loop through all of the comments
        comments = ''
        for comment in issues["issues"][0]["fields"]["comment"]["comments"]:
            comments += (f"{comment['author']['displayName']}" + ' | ',
                         f"{comment['updated'][0:10]}" + ' @ ',
                         f"{comment['updated'][11:16]}" + ' | ',
                         f"{comment['body']} + '\n'")

        return comments

    def get_components(self):
        '''
        Build a vim pop-up menu for a list of components
        '''

        for component in self.jira.project_components(
                self.userconfig_filter['project']):
            print(component.name)
        print('None')

    def get_component(self):
        '''
        Build a vim pop-up menu for a list of components
        '''

        self.get_components()

    def get_epic(self):
        self.get_epics()

    def get_epics(self):
        '''
        Get my issues with JQL
        '''
        hold = dict(self.userconfig_filter)
        project = self.userconfig_filter['project']
        self.reset_filters()
        self.userconfig_filter["issuetype"] = "Epic"
        self.userconfig_filter["project"] = project
        self.get_issues()
        print('None')
        self.userconfig_filter = hold

    def get_issue(self, issue):
        '''
        Get single issue by issue id
        '''

        return self.jira.issue(issue)

    def get_issues(self):
        '''
        Get my issues with JQL
        '''

        issues = []
        key_length = 0
        summary_length = 0
        issuetype_length = 0
        status_length = 4
        user_length = 0

        for issue in self.query_issues():
            fields = issue['fields']

            user = str(fields['assignee']['displayName']) if type(
                fields['assignee']) == dict else 'Unassigned'
            user_length = len(user) if len(user) > user_length else user_length

            key_length = len(
                issue['key']) if len(issue['key']) > key_length else key_length

            summary = fields['summary']
            summary_length = len(
                summary) if len(summary) > summary_length else summary_length

            issuetype = fields['issuetype']['name']
            issuetype_length = len(issuetype) if len(
                issuetype) > issuetype_length else issuetype_length

            status = fields['status']['name']
            status_length = len(
                status) if len(status) > status_length else status_length

            issues.append([
                issue['key'], fields['summary'], fields['issuetype']['name'],
                fields['status']['name'], user
            ])

        # Add min/max limits on summary length
        columns = vim.eval("&columns")
        min_summary_length = 25
        max_summary_length = int(
            columns) - key_length - issuetype_length - status_length - 28
        summary_length = min_summary_length if max_summary_length < min_summary_length else max_summary_length if summary_length > max_summary_length else summary_length

        for issue in issues:
            print(('{: <' + str(key_length) + '}').format(issue[0]) + " │ " +
                  ('{: <' + str(summary_length) +
                   '}').format(issue[1][:summary_length]) + "  │ " +
                  ('{: <' + str(issuetype_length) + '}').format(issue[2]) +
                  " │ " +
                  ('{: <' + str(status_length) + '}').format(issue[3]) +
                  ' │ ' + issue[4])

    def get_issuetypes(self):
        '''
        Get my issues with JQL
        '''

        for issuetype in self.jira.issue_types():
            print(issuetype)

    def get_issuetype(self):
        '''
        Get my issues with JQL
        '''

        for issuetype in self.jira.issue_types():
            print(issuetype)

    def get_priorities(self):
        '''
        Get my issues with JQL
        '''

        for priority in self.jira.priorities():
            print(priority)

    def print_projects(self):
        '''
        Build a vim pop-up menu for a list of projects
        '''

        all_projects = self.get_projects()
        batch_size = 10
        project_batches = [
            all_projects[i:i + batch_size]
            for i in range(0, len(all_projects), batch_size)
        ]

        for batch in project_batches:
            projects = self.jira.createmeta(projectKeys=','.join(batch),
                                            expand='projects')['projects']
            [print(p['key'] + ' ~ ' + p['name']) for p in projects]

    def get_projects(self):
        '''
        Build a vim pop-up menu for a list of projects
        '''

        # Project filter for version list
        self.projects = []
        for project in self.jira.projects():
            self.projects.append(str(project))
        vim.command('let s:projects = ' + str(self.projects))

        return self.projects

    def get_priority(self):
        '''
        Build a vim pop-up menu for a list of projects
        '''

        self.get_priorities()

    def get_prompt_text(self, prompt_type, comment_id=None):
        '''
        Get prompt text used for inputting text into jira
        '''

        self.prompt_type = prompt_type

        # Edit filters
        if prompt_type == 'edit_filter':
            self.prompt_text_commented = '\n# Edit all filters in JSON format'
            self.prompt_text = json.dumps(
                self.userconfig_filter,
                indent=True) + self.prompt_text_commented
            return self.prompt_text

        # Edit summary
        active_issue = vim.eval("g:vira_active_issue")
        if prompt_type == 'summary':
            self.prompt_text_commented = '\n# Edit issue summary'
            summary = self.jira.search_issues(
                'issue = "' + active_issue + '"',
                fields=','.join(['summary']),
                json_result='True')['issues'][0]['fields']['summary']
            self.prompt_text = summary + self.prompt_text_commented
            return self.prompt_text

        # Edit description
        if prompt_type == 'description':
            self.prompt_text_commented = '\n# Edit issue description'
            description = self.jira.search_issues(
                'issue = "' + active_issue + '"',
                fields=','.join(['description']),
                json_result='True')['issues'][0]['fields'].get('description')
            if description:
                description = description.replace('\r\n', '\n')
            else:
                description = ''
            self.prompt_text = description + self.prompt_text_commented
            return self.prompt_text

        self.prompt_text_commented = '''
# ---------------------------------
# Please enter text above this line
# An empty message will abort the operation.
#
# Below is a list of acceptable values for each input field.
#
# Users:'''
        for user in self.users:
            user = user.split(' ~ ')
            name = user[0]
            id = user[1]
            if self.users_type == 'accountId':
                self.prompt_text_commented += f'''
# [{name}|~accountid:{id}]'''
            else:
                self.prompt_text_commented += f'''
# [~{id}]'''

        # Add comment
        if self.prompt_type == 'add_comment':
            self.prompt_text = self.prompt_text_commented
            return self.prompt_text

        # Edit comment
        if self.prompt_type == 'edit_comment':
            self.active_comment = self.jira.comment(active_issue, comment_id)
            self.prompt_text = self.active_comment.body + self.prompt_text_commented
            return self.prompt_text

        statuses = [x.name for x in self.jira.statuses()]
        issuetypes = [x.name for x in self.jira.issue_types()]
        priorities = [x.name for x in self.jira.priorities()]
        components = [
            x.name for x in self.jira.project_components(
                self.userconfig_filter['project'])
        ] if self.userconfig_filter['project'] != '' else ''
        versions = [
            x.name for x in self.jira.project_versions(
                self.userconfig_filter['project'])
        ] if self.userconfig_filter['project'] != '' else ''
        projects = [x.key for x in self.jira.projects()]

        # Extra info for prompt_type == 'issue'
        self.prompt_text_commented += f'''
#
# Projects: {projects}
# IssueTypes: {issuetypes}
# Statuses: {statuses}
# Priorities: {priorities}
# Components in {self.userconfig_filter["project"]} Project: {components}
# Versions in {self.userconfig_filter["project"]} Project: {versions}'''

        self.prompt_text = f'''[*Summary*]
[Description]

[*Project*] {self.userconfig_filter["project"]}
[*IssueType*] {self.userconfig_newissue["issuetype"]}
[Status] {self.userconfig_newissue["status"]}
[Priority] {self.userconfig_newissue["priority"]}
[Component] {self.userconfig_newissue["component"]}
[Version] {self.userconfig_newissue["fixVersion"]}
[Assignee] {self.userconfig_newissue["assignee"]}
{self.prompt_text_commented}'''
        return self.prompt_text

    def format_date(self, date):
        time = datetime.now().strptime(date,
                                       '%Y-%m-%dT%H:%M:%S.%f%z').astimezone()
        return str(time)[0:10] + ' ' + str(time)[11:16]

    def get_report(self):
        '''
        Print a report for the given issue
        '''

        for customfield in self.jira.fields():
            if customfield['name'] == 'Epic Link':
                epicID = customfield['id']

        # Get passed issue content
        active_issue = vim.eval("g:vira_active_issue")
        issues = self.jira.search_issues(
            'issue = "' + active_issue + '"',
            fields=','.join([
                'project', 'summary', 'comment', 'component', 'description',
                'issuetype', 'priority', 'status', 'created', 'updated',
                'assignee', 'reporter', 'fixVersion', 'customfield_10106',
                'labels', epicID
            ]),
            json_result='True')
        issue = issues['issues'][0]['fields']

        # Prepare report data
        open_fold = '{{{'
        close_fold = '}}}'
        summary = issue['summary']
        story_points = str(issue.get('customfield_10106', ''))
        created = self.format_date(issue['created'])
        updated = self.format_date(issue['updated'])
        issuetype = issue['issuetype']['name']
        status = issue['status']['name']
        priority = issue['priority']['name']
        assignee = issue['assignee']['displayName'] if type(
            issue['assignee']) == dict else 'Unassigned'
        reporter = issue['reporter']['displayName']
        component = ', '.join([c['name'] for c in issue['components']])
        version = ', '.join([v['name'] for v in issue['fixVersions']])
        epics = str(issue.get(epicID))
        vim.command(f'let s:vira_epic_field = "{epicID}"')
        description = str(issue.get('description'))

        # Version percent for single version attacted
        #  if len(issue['fixVersions']) == 1 and version != '':
        #  version += ' | ' + self.version_percent(
        #  str(issue['project']['key']), version) + '%'

        comments = ''
        idx = 0
        for idx, comment in enumerate((issue['comment']['comments'])):
            comments += ''.join([
                comment['author']['displayName'] + ' @ ' +
                self.format_date(comment['updated']) + ' {{' + '{2\n' +
                comment['body'] + '\n}}}\n'
            ])
        old_count = idx - 3
        old_comment = 'Comment' if old_count == 1 else 'Comments'
        comments = ''.join(
            [str(old_count) + ' Older ' + old_comment +
             ' {{{1\n']) + comments if old_count >= 1 else comments
        comments = comments.replace('}}}', '}}}}}}', idx - 3)
        comments = comments.replace('}}}}}}', '}}}', idx - 4)

        # Find the length of the longest word [-1]
        words = [
            created, updated, issuetype, status, story_points, priority,
            component, version, assignee, reporter, epics
        ]
        wordslength = sorted(words, key=len)[-1]
        s = '─'
        dashlength = s.join([char * len(wordslength) for char in s])

        active_issue_spacing = int((16 + len(dashlength)) / 2 -
                                   len(active_issue) / 2)
        active_issue_spaces = ' '.join(
            [char * (active_issue_spacing) for char in ' '])
        active_issue_space = ' '.join([
            char * ((len(active_issue) + len(dashlength)) % 2) for char in ' '
        ])

        created_spaces = ' '.join(
            [char * (len(dashlength) - len(created)) for char in ' '])
        updated_spaces = ' '.join(
            [char * (len(dashlength) - len(updated)) for char in ' '])
        task_type_spaces = ' '.join(
            [char * (len(dashlength) - len(issuetype)) for char in ' '])
        status_spaces = ' '.join(
            [char * (len(dashlength) - len(status)) for char in ' '])
        story_points_spaces = ''.join(
            [char * (len(dashlength) - len(story_points)) for char in ' '])
        priority_spaces = ''.join(
            [char * (len(dashlength) - len(priority)) for char in ' '])
        component_spaces = ''.join(
            [char * (len(dashlength) - len(component)) for char in ' '])
        version_spaces = ''.join(
            [char * (len(dashlength) - len(version)) for char in ' '])
        assignee_spaces = ''.join(
            [char * (len(dashlength) - len(assignee)) for char in ' '])
        reporter_spaces = ''.join(
            [char * (len(dashlength) - len(reporter)) for char in ' '])
        epics_spaces = ''.join(
            [char * (len(dashlength) - len(epics)) for char in ' '])

        # Create report template and fill with data
        report = '''┌────────────────{dashlength}─┐
│{active_issue_spaces}{active_issue}{active_issue_spaces}{active_issue_space} │
├──────────────┬─{dashlength}─┤
│      Created │ {created}{created_spaces} │
│      Updated │ {updated}{updated_spaces} │
│         Type │ {issuetype}{task_type_spaces} │
│       Status │ {status}{status_spaces} │
│ Story Points │ {story_points}{story_points_spaces} │
│     Priority │ {priority}{priority_spaces} │
│    Epic Link │ {epics}{epics_spaces} │
│ Component(s) │ {component}{component_spaces} │
│   Version(s) │ {version}{version_spaces} │
│     Assignee │ {assignee}{assignee_spaces} │
│     Reporter │ {reporter}{reporter_spaces} │
└──────────────┴─{dashlength}─┘
┌──────────────┐
│    Summary   │
└──────────────┘
{summary}

┌──────────────┐
│  Description │
└──────────────┘
{description}

┌──────────────┐
│   Comments   │
└──────────────┘
{comments}'''

        self.set_report_lines(report, description, issue)

        self.prompt_text = self.report_users(report.format(**locals()))
        return self.prompt_text

    def report_users(self, report):
        '''
        Replace report accountid with names
        '''

        for user in self.users:
            user = user.split(' ~ ')
            if user[0] != "Unassigned":
                report = report.replace('accountid:',
                                        '').replace('[~' + user[1] + ']',
                                                    '[~' + user[0] + ']')

        return report

    def get_reporters(self):
        '''
        Get my issues with JQL
        '''

        self.print_users()

    def get_servers(self):
        '''
        Get list of servers
        '''

        try:
            for server in self.vira_servers.keys():
                print(server)
            print('Null')
        except:
            self.connect('')

    def get_statuses(self):
        '''
        Get my issues with JQL
        '''

        statuses = []
        for status in self.jira.statuses():
            if str(status) not in statuses:
                statuses.append(str(status))
                print(str(status))

    def get_set_status(self):
        '''
        Get my issues with JQL
        '''

        self.get_statuses()

    def get_version(self):
        '''
        Get my issues with JQL
        '''

        self.print_versions()

    def new_component(self, name, project):
        '''
        New component added to project
        '''

        self.jira.create_component(name=name,
                                   project=project,
                                   description=name)

    def new_version(self, name, project, description):
        '''
        Get my issues with JQL
        '''

        self.jira.create_version(name=name,
                                 project=project,
                                 description=description)

    def print_users(self):
        '''
        Print users
        '''

        print(self.get_current_user() + ' ~ currentUser')
        for user in self.users:
            print(user)
        print('Unassigned')

    def get_users(self):
        '''
        Get my issues with JQL
        '''

        query = 'ORDER BY updated DESC'
        issues = self.jira.search_issues(query,
                                         fields='assignee, reporter',
                                         json_result='True',
                                         maxResults=-1)

        # Determine cloud/server jira
        self.users_type = 'accountId' if issues['issues'][0]['fields'][
            'reporter'].get('accountId') else 'name'

        for issue in issues['issues']:
            user = str(issue['fields']['reporter']['displayName']
                       ) + ' ~ ' + issue['fields']['reporter'][self.users_type]
            self.users.add(user)
            if type(issue['fields']['assignee']) == dict:
                user = str(
                    issue['fields']['assignee']['displayName']
                ) + ' ~ ' + issue['fields']['assignee'][self.users_type]
            self.users.add(user)

        return sorted(self.users)

    def get_current_user(self):
        query = 'reporter = currentUser() or assignee = currentUser()'
        issues = self.jira.search_issues(query,
                                         fields='assignee, reporter',
                                         json_result='True',
                                         maxResults=-1)

        issue = issues['issues'][0]['fields']
        return str(issue['assignee'][self.users_type] if type(
            issue['assignee']) == dict else issue['reporter'][self.users_type]
                   if type(issue['reporter']) == dict else 'Unassigned')

    def print_versions(self):
        '''
        Print version list with project filters
        '''
        try:
            versions = sorted(self.versions)
            wordslength = sorted(versions, key=len)[-1]
            s = ' '
            dashlength = s.join([char * len(wordslength) for char in s])
            for version in versions:
                print(
                    version.split('|')[0] + ''.join([
                        char * (len(dashlength) - len(version)) for char in ' '
                    ]) + '   ' + version.split('|')[1] + ' ' +
                    version.split('|')[2])
        except:
            pass
        print('None')

    def version_percent(self, project, fixVersion):
        project = str(project)
        fixVersion = str(fixVersion)
        if str(project) != '[]' and str(project) != '' and str(
                fixVersion) != '[]' and str(fixVersion) != '':
            query = 'fixVersion = ' + fixVersion + ' AND project = "' + project + '"'
            issues = self.jira.search_issues(query,
                                             fields='fixVersion',
                                             json_result='True',
                                             maxResults=1)

            try:
                issue = issues['issues'][0]['fields']['fixVersions'][0]
                idx = issue['id']

                total = self.jira.version_count_related_issues(
                    idx)['issuesFixedCount']
                pending = self.jira.version_count_unresolved_issues(idx)
                fixed = total - pending
                percent = str(round(fixed / total *
                                    100, 1)) if total != 0 else 1
                space = ''.join([char * (5 - len(percent)) for char in ' '])

                name = fixVersion
                try:
                    description = issue['description']
                except:
                    description = 'None'
                    pass
            except:
                total = 0
                pending = 0
                fixed = total - pending
                percent = "0"
                space = ''.join([char * (5 - len(percent)) for char in ' '])
                name = fixVersion
                description = ''
                pass

            version = str(
                str(name) + ' ~ ' + str(description) + '|' + str(fixed) + '/' +
                str(total) + space + '|' + str(percent) + '%')

            self.versions_hide = vim.eval('g:vira_version_hide')
            if fixed != total or total == 0 or not int(
                    self.versions_hide) == 1:
                self.versions.add(
                    str(project) + ' ~ ' + str(version.replace('\'', '')))

        else:
            percent = 0

        return percent

    def get_versions(self):
        '''
        Build a vim pop-up menu for a list of versions with project filters
        '''

        # Loop through each project and all versions within
        try:
            for v in reversed(
                    self.jira.project_versions(vim.eval('s:projects[0]'))):
                vim.command('let s:versions = add(s:versions,\"' + str(v) +
                            '\")')
        except:
            vim.command('let s:versions = []')

    def load_project_config(self, repo):
        '''
        Load project configuration for the current git repo
        The current repo can either be determined by current files path
        or by the user setting g:vira_repo (part of :ViraLoadProject)

        For example, an entry in projects.yaml may be:

        vira:
          server: https://jira.tgall.ca
          project_name: VIRA
        '''

        # Only proceed if projects file parsed successfully
        if not getattr(self, 'vira_projects', None):
            return

        # If current repo/folder doesn't exist, use __default__ project config if it exists
        if repo == '':
            repo = run_command(
                'git rev-parse --show-toplevel')['stdout'].strip()
            if not self.vira_projects.get(repo):
                repo = repo.split('/')[-1]
            if not self.vira_projects.get(repo):
                repo = run_command('pwd')['stdout'].strip()
            if not self.vira_projects.get(repo):
                repo = repo.split('/')[-1]
            if not self.vira_projects.get(repo):
                repo = '__default__'
            if not self.vira_projects.get('__default__'):
                return

        # Set server
        server = self.vira_projects.get(repo, {}).get('server')
        if server:
            vim.command(f'let g:vira_serv = "{server}"')

        # Set user-defined filters for current project
        for key in self.userconfig_filter.keys():
            value = self.vira_projects.get(repo, {}).get('filter', {}).get(key)
            if value:
                self.userconfig_filter[key] = value

        # Set user-defined new-issue defaults for current project
        for key in self.userconfig_newissue.keys():
            value = self.vira_projects.get(repo, {}).get('newissue',
                                                         {}).get(key)
            if value:
                self.userconfig_newissue[key] = value

        # Set user-defined issue sort options
        sort_order = self.vira_projects.get(repo,
                                            {}).get('issuesort',
                                                    'updated DESC')
        self.userconfig_issuesort = ', '.join(sort_order) if type(
            sort_order) == list else sort_order

    def query_issues(self):
        '''
        Query issues based on current filters
        '''

        q = []
        for filterType in self.userconfig_filter.keys():
            filter_str = self.filter_str(filterType)
            if filter_str:
                q.append(filter_str)

        query = ' AND '.join(q) + ' ORDER BY ' + self.userconfig_issuesort
        issues = self.jira.search_issues(
            query,
            fields='summary,comment,status,statusCategory,issuetype,assignee',
            json_result='True',
            maxResults=vim.eval('g:vira_issue_limit'))

        return issues['issues']

    def reset_filters(self):
        '''
        Reset filters to their default values
        '''

        self.userconfig_filter = dict(self.userconfig_filter_default)

    def set_report_lines(self, report, description, issue):
        '''
        Create dictionary for vira report that shows relationship
        between line numbers and fields to be edited
        '''

        writable_fields = {
            'Assignee': 'ViraSetAssignee',
            'Component': 'ViraSetComponent',
            'Priority': 'ViraSetPriority',
            'Epic Link': 'ViraSetEpic',
            'Status': 'ViraSetStatus',
            'Type': 'ViraSetType',
            'Version': 'ViraSetVersion',
        }

        self.report_lines = {}

        for idx, line in enumerate(report.split('\n')):
            for field, command in writable_fields.items():
                if field in line:
                    self.report_lines[idx + 1] = command
                    continue

        for x in range(16, 21):
            self.report_lines[x] = 'ViraEditSummary'

        description_len = description.count('\n') + 3
        for x in range(21, 23 + description_len):
            self.report_lines[x] = 'ViraEditDescription'

        offset = 2 if len(issue['comment']['comments']) > 4 else 1
        comment_line = 25 + description_len + offset
        for comment in issue['comment']['comments']:
            comment_len = comment['body'].count('\n') + 3
            for x in range(comment_line, comment_line + comment_len):
                self.report_lines[x] = 'ViraEditComment ' + comment['id']
            comment_line = comment_line + comment_len

    def set_prompt_text(self):
        '''
        Take the user prompt text and perform an action
        Usually, this involves writing to the jira server
        '''

        # User input
        issue = vim.eval('g:vira_active_issue')
        userinput = vim.eval('g:vira_input_text')
        input_stripped = userinput.replace(self.prompt_text_commented.strip(),
                                           '').strip()

        # Check if anything was actually entered by user
        if input_stripped == '' or userinput.strip() == self.prompt_text.strip(
        ):
            print("No vira actions performed")
            return

        if self.prompt_type == 'edit_filter':
            self.userconfig_filter = json.loads(input_stripped)
        elif self.prompt_type == 'add_comment':
            self.jira.add_comment(issue, input_stripped)
        elif self.prompt_type == 'edit_comment':
            self.active_comment.update(body=input_stripped)
        elif self.prompt_type == 'summary':
            self.jira.issue(issue).update(summary=input_stripped)
        elif self.prompt_type == 'description':
            self.jira.issue(issue).update(description=input_stripped)
        elif self.prompt_type == 'issue':
            self.create_issue(input_stripped)

    def versions_hide(self, state):
        '''
        Display and hide complete versions
        '''

        if state is True or 1 or 'ture' or 'True':
            self.version_hide = True
        elif state is False or 0 or 'false' or 'False':
            self.version_hide = False
        else:
            self.version_hide = not self.version_hide
Exemple #8
0
###Component match
cMatch=re.compile('^BFB.*')

###Get 'raw' lists (Jira classes are not so handy)
listSrc=[]
listDst=[]

for i in projSrc:
 if cMatch.match(str(i)):
  listSrc.append(str(i))
  
for i in projDst:
 if cMatch.match(str(i)):
  listDst.append(str(i))

###Get absent strings
toAdd=[]

for item in listSrc:
 if item not in listDst:
  toAdd.append(item)

####Add absent strings to project components.
if toAdd != []:
 for item in toAdd:
  print ("Adding absent component:", item)
  jira.create_component(name=item,project=args.dest,description='Business Component',assigneeType='UNASSIGNED')
else:
 print ("Nothing to add.")
            if not version_exists:
                print "The version %s does NOT exist.  Adding..." % version
                jira.create_version(version, app.upper())

            # Make sure Components exists in JIRA Project
            components = jira.project_components(project)
            print "Checking for Components..."
            for c in components:
                if c.name == "webapp":
                    webapp = True
                if c.name == "database":
                    database = True

            if not webapp:
                print "webapp component does not exist.  Adding..."
                jira.create_component("webapp", app.upper(), None, None,
                                      "UNASSIGNED", False)
            if not database:
                print "database component does not exist.  Adding..."
                jira.create_component("database", app.upper(), None, None,
                                      "UNASSIGNED", False)

            print "Checking for Developer Group... %s" % devgroup
            groups = jira.groups(query=devgroup)
            for g in groups:
                if g == devgroup:
                    group = True
            if not group:
                print "Developer group does not exist.  Adding %s" % devgroup
                jira.add_group(devgroup)

            # Populate the KV pairs for the RFD
Exemple #10
0
class JiraWrapper:
    """
    Setting for connecting to JIRA
    """
    def __init__(self, params):
        # general settings
        self.params = params
        self.jira = None

        # Proxy settings

        if "HTTP_PROXY" not in os.environ:
            if params.get_http_proxy_url:
                os.environ["HTTP_PROXY"] = params.get_http_proxy_url

        if "HTTPS_PROXY" not in os.environ:
            if params.get_https_proxy_url:
                os.environ["HTTPS_PROXY"] = params.get_https_proxy_url

        # jira settings
        self.jira_url = self.params.get_jira_url
        self.jira_url = self.jira_url.strip("/")

        # see if we need to use a certificate
        if params.get_use_cert:
            self.jira_options = {
                "server": self.jira_url,
                "verify": True,
                "client_cert": (
                    "mycert-dn.crt",
                    "mycert-dn.key",
                )
            }
        else:
            self.jira_options = {"server": self.jira_url}

    # noinspection PyAttributeOutsideInit
    def connect(self, username, password: str):
        """
        Trigger the connection to jira
        :param username:
        :param password: user password for the connection
        :return: True on success
        """
        try:
            print('Connecting to Jira')
            self.jira = JIRA(options=self.jira_options,
                             basic_auth=(username, password),
                             max_retries=1)
            print('Connected')
            return True, None

        except Exception as e:
            print('Unable to connect')
            print(str(e))
            pass
            return False, e

    @property
    def get_components(self) -> list:
        """
        Get list of components available on the server
        :return: available compnents
        """

        components = self.jira.project_components(self.params.get_project)
        component_list = []
        for i in components:
            component_list.append(i.name)

        return component_list

    def create_components(self, components: list) -> list:
        """
        Create components if the do not already exist
        :param components: components to create
        :return: list of created components
        """
        components_avail = self.get_components
        components_todo = set(components) - set(components_avail)

        for i in components_todo:
            self.jira.create_component(i, self.params.get_project)

        return list(components_todo)

    def create_task_subtask(self, task_name: str, comment: str, reporter: str,
                            parent_assignee: str, sub_assignees: list,
                            duedate: str, labels: [str], priority: str):
        """
        Creat a task and all subtasks for the users
        :param reporter: who reports the bug
        :param priority:
        :param comment:
        :param task_name: Name of the task
        :param parent_assignee: Who is the owner of the parent task
        :param sub_assignees: List of people getting the subtasks. Needs to be jira userids
        :param duedate: what is the duedate for the parent task and the subtasks
        :param labels: Labels the tasks get added
        :return: url to the jira task for the webbrowser
        """

        # return values
        parent_url = None
        error_msg = None

        parent_component = None
        parent_assignee_id = None
        for i in sub_assignees:
            if parent_assignee == i[0]:
                parent_assignee_id = i[1]
                parent_component = i[2]
                break
        assert parent_assignee_id

        # TODO this only works if the reporter is part of the assignee list.
        reporter_id = ''
        for i in sub_assignees:
            if reporter == i[0]:
                reporter_id = i[1]
                break

        assert reporter_id

        # sub_assignees = self.get_users(sub_assignees)
        issue_dict = {
            'project': self.params.get_project,
            'summary': task_name,
            'description': comment,
            'issuetype': {
                'name': 'Task'
            },
            'assignee': {
                'name': parent_assignee_id
            },
            'duedate': duedate,
            'labels': labels,
            'priority': {
                'name': priority
            }
        }
        if parent_component:
            issue_dict['components'] = [{'name': parent_component}]

        # TODO allow change reporter
        if self.params.can_change_reporter:
            issue_dict['reporter'] = {'name': reporter_id}

        # print("Creating task")
        # print(sub_assignees)
        # print(issue_dict['assignee'])

        # for debugging set to false to no swap jira
        create = True
        parent_issue = None
        if create:
            try:
                parent_issue = self.jira.create_issue(fields=issue_dict)
                print("Created task: %s" % parent_issue.key)
            except Exception as e:
                print(e)
                parent_url = None
                error_msg = e.text
                pass

        # we were not able to create a issue. Connection error?
        if not parent_issue:
            return parent_url, error_msg

        # does your handle bulk create?
        can_bulk = True

        # now create the sub-task, linked to the parent task for all users
        child_issue_dict = []
        for val in sub_assignees:
            # val[3] is the bool if the task has to be created
            if val[3]:
                print('Creating Sub-tak for:', val[0])
                cur_issue_dict = copy.deepcopy(issue_dict)
                cur_issue_dict['summary'] = '(Subtask) ' + task_name
                cur_issue_dict['issuetype'] = {'name': 'Sub-task'}
                if create:
                    # noinspection PyUnresolvedReferences
                    # cur_issue_dict['parent'] = {"id": parent_issue.key}
                    cur_issue_dict['parent'] = {"id": parent_issue.id}
                cur_issue_dict['assignee'] = {'name': val[1]}

                # if componets for the user, add it
                if val[2]:
                    cur_issue_dict['components'] = [{'name': val[2]}]
                else:
                    cur_issue_dict['components'] = []

                if not can_bulk:
                    print('Slow call of Sub-task creation')
                    self.jira.create_issue(cur_issue_dict)
                else:
                    child_issue_dict.append(cur_issue_dict)

        if create and len(child_issue_dict) > 0:
            try:
                self.jira.create_issues(child_issue_dict)
            except Exception as e:
                print('Error creating Sub-Tasks. Message:')
                print(e)
                pass

        assert parent_issue

        parent_url = '%s/%s/%s' % (self.jira_url, 'browse', parent_issue.key)
        print(parent_url)
        return parent_url, error_msg

    def get_users(self, userlist):
        """
        For all the users in the self.full_assignee_list get the user ids from JIRA
        :return:
        """
        for i, val in enumerate(userlist):
            tmp = self.jira.search_assignable_users_for_projects(
                val[0], self.params.get_project)
            if not tmp:
                raise Exception('Could not find userid for %s' % val[0])

            userlist[i][1] = tmp[0].key
        return userlist