Exemple #1
0
class TestComponents(unittest.TestCase):
    def setUp(self):
        self.jira = JIRA(options=dict(server=TEST_URL, verify=False),
                         basic_auth=(TEST_USERNAME, TEST_PASSWORD))
        self.purge_test_components()

    def tearDown(self):
        self.purge_test_components()

    def get_component(self, name):
        components = [
            _ for _ in self.jira.project_components('KB') if _.name == 'test-1'
        ]
        return components[0] if len(components) == 1 else None

    def purge_test_components(self):
        for _ in self.jira.project_components('KB'):
            if _.name.startswith('test-'):
                _.delete()

    def test_create_component(self):
        result = CliRunner().invoke(
            topcli,
            ['component', 'create', 'KB', 'test-1', '-d', 'Some description'])
        self.assertEqual(result.exit_code, 0)

    def test_delete_component(self):
        result = CliRunner().invoke(topcli,
                                    ['component', 'create', 'KB', 'test-1'])
        self.assertEqual(result.exit_code, 0)
        self.assertIsNotNone(self.get_component('test-1'))
        result = CliRunner().invoke(topcli,
                                    ['component', 'delete', 'KB', 'test-1'])
        self.assertEqual(result.exit_code, 0)
        self.assertIsNone(self.get_component('test-1'))

    def test_update_component(self):
        result = CliRunner().invoke(
            topcli, ['component', 'create', 'KB', 'test-1', '-d', 'before'])
        before = self.get_component('test-1')
        self.assertEqual(before.description, 'before')
        result = CliRunner().invoke(
            topcli, ['component', 'update', 'KB', 'test-1', '-d', 'after'])
        self.assertEqual(result.exit_code, 0)
        after = self.get_component('test-1')
        self.assertEqual(after.description, 'after')

    def test_search_component(self):
        result = CliRunner().invoke(
            topcli,
            ['component', 'create', 'KB', 'test-1', '-d', 'Some description'])
        result = CliRunner().invoke(topcli, ['component', 'search', 'KB'])
        self.assertEqual(result.exit_code, 0)
        self.assertIn('test-1', result.output)
        self.assertIn('Some description', result.output)
Exemple #2
0
class TestComponents(unittest.TestCase):
    def setUp(self):
        self.jira = JIRA(options=dict(server=TEST_URL, verify=False), basic_auth=(TEST_USERNAME, TEST_PASSWORD))
        self.purge_test_components()

    def tearDown(self):
        self.purge_test_components()

    def get_component(self, name):
        components = [_ for _ in self.jira.project_components('KB') if _.name == 'test-1']
        return components[0] if len(components) == 1 else None

    def purge_test_components(self):
        for _ in self.jira.project_components('KB'):
            if _.name.startswith('test-'):
                _.delete()

    def test_create_component(self):
        result = CliRunner().invoke(topcli, ['component', 'create', 'KB', 'test-1', '-d', 'Some description'])
        self.assertEqual(result.exit_code, 0)

    def test_delete_component(self):
        result = CliRunner().invoke(topcli, ['component', 'create', 'KB', 'test-1'])
        self.assertEqual(result.exit_code, 0)
        self.assertIsNotNone(self.get_component('test-1'))
        result = CliRunner().invoke(topcli, ['component', 'delete', 'KB', 'test-1'])
        self.assertEqual(result.exit_code, 0)
        self.assertIsNone(self.get_component('test-1'))

    def test_update_component(self):
        result = CliRunner().invoke(topcli, ['component', 'create', 'KB', 'test-1', '-d', 'before'])
        before = self.get_component('test-1')
        self.assertEqual(before.description, 'before')
        result = CliRunner().invoke(topcli, ['component', 'update', 'KB', 'test-1', '-d', 'after'])
        self.assertEqual(result.exit_code, 0)
        after = self.get_component('test-1')
        self.assertEqual(after.description, 'after')

    def test_search_component(self):
        result = CliRunner().invoke(topcli, ['component', 'create', 'KB', 'test-1', '-d', 'Some description'])
        result = CliRunner().invoke(topcli, ['component', 'search', 'KB'])
        self.assertEqual(result.exit_code, 0)
        self.assertIn('test-1', result.output)
        self.assertIn('Some description', result.output)
Exemple #3
0
class JiraInit(object):



    @except_decorate("获取jira服务器错误,请确认能在网页中正确登录JIRA服务")
    def __init__(self,jurl,juser,jpasswd):
        self.jurl = jurl
        self.juser = juser
        self.jpasswd = jpasswd
        self.nowtime = datetime.datetime.now().strftime('%Y年%m月%d日')
        self.jr = JIRA(self.jurl,basic_auth=(self.juser,self.jpasswd))



    @except_decorate("用户错误")
    def authuser(self):
        name = self.jr.current_user()
        logger().info(u"当前登录用户:%s" % name)

    # 查询项目是否存在
    @except_decorate("未查询到项目")
    def ExistProject(self, jproject):

        projects = str(self.jr.projects())
        if jproject in projects:
            logger().info("存在项目%s" % jproject)
        else:
            logger().error("不存在项目%s" % jproject)
            exit(2)

    @staticmethod
    def JqlProjrct(jproject):
        jproject_ql = "project = %s "%jproject
        return jproject_ql

    @staticmethod
    def JqlText(jversion):
        jtext_ql = "AND text ~ %s "%jversion
        return jtext_ql

    @staticmethod
    def JqlBugType(jbugtype):
        jbugtype_ql = "AND bug类型 = %s "%jbugtype
        return jbugtype_ql

    @staticmethod
    def JqlModel(jmodel):
        jmodel_ql = "AND component = %s "%jmodel
        return jmodel_ql

    #获取全部模块类型
    def GetComponents(self,project):
        components = self.jr.project_components(project)
        return components
Exemple #4
0
    print("%s assigned these issues." % assignee)
    print(top_ten)
    while top_ten:
        item = top_ten.pop()
        prj_name = item[0]
        issue_count = item[1]
        print("Project name : {name}, Assigned Count : {count}".format(
            name=prj_name, count=issue_count))

        #project 상세 정보 표출
        if prj_name == "BTVD":
            prj = jira.project(prj_name)
            print("=" * 30)
            print("Project name : %s" % prj.name)
            print("Project leader name : %s" % prj.lead.displayName)
            components = jira.project_components(prj)
            print("Components : " + str([c.name for c in components]))
            print("Roles : " + str(jira.project_roles(prj)))
            versions = jira.project_versions(prj)
            print("Versions : " + str([v.name for v in reversed(versions)]))
            print("=" * 30)
        else:
            continue

    break_loop = False
    for issue in issues:
        print("Issue summary : " + issue.fields.summary)
        watcher = jira.watchers(issue)
        if watcher.watchCount > 1:
            print("Issue has {} watchers(s)".format(watcher.watchCount))
            for watcher in watcher.watchers:
Exemple #5
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': '',
            'statusCategory': ['To Do', 'In Progress'],
            'text': ''
        }
        self.reset_filters()

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

    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.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
        '''

        # 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()
        else:
            password = self.vira_servers[server]['password']

        # Connect to jira server
        try:
            self.jira = JIRA(options={
                'server': server,
                'verify': cert_verify,
            },
                             basic_auth=(username, password),
                             timeout=5)
            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:
                raise e

    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(
            "'null'", "Null").replace("'Unassigned'",
                                      "Null").replace(f"text in ({selection})",
                                                      f"text ~ {selection}")

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

        self.get_users()

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

        self.get_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 popup menu for a list of components
        '''

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

    def get_component(self):
        '''
        Build a vim popup menu for a list of components
        '''

        self.get_components()

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

        for issue in self.query_issues(issuetypes="Epic"):
            print(issue["key"] + '  -  ' + issue["fields"]['summary'])

    def get_issue(self, issue):
        '''
        Get single issue by isuue 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 get_projects(self):
        '''
        Build a vim popup menu for a list of projects
        '''

        for project in self.jira.projects():
            print(project)

    def get_priority(self):
        '''
        Build a vim popup 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
        '''

        # Edit summary
        self.prompt_type = prompt_type
        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']
            return summary + self.prompt_text_commented

        # 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 = ''
            return description + self.prompt_text_commented

        # Prepare dynamic variables for prompt text
        query = 'ORDER BY updated DESC'
        issues = self.jira.search_issues(query,
                                         fields='assignee, reporter',
                                         json_result='True',
                                         maxResults=-1)

        # Determine cloud/server jira
        id = 'accountId' if issues['issues'][0]['fields']['reporter'].get(
            'accountId') else 'name'
        users = set()
        for issue in issues['issues']:
            user = str(issue['fields']['reporter']['displayName']
                       ) + ' ~ ' + issue['fields']['reporter'][id]
            users.add(user)
            if type(issue['fields']['assignee']) == dict:
                user = str(issue['fields']['assignee']['displayName']
                           ) + ' ~ ' + issue['fields']['assignee'][id]
            users.add(user)

        self.prompt_text_commented = f'''
# ---------------------------------
# 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: {users}
'''
        # Add comment
        if self.prompt_type == 'add_comment':
            return self.prompt_text_commented

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

        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}
'''
        return 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}'''

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

        # Get passed issue content
        active_issue = vim.eval("g:vira_active_issue")
        issues = self.jira.search_issues(
            'issue = "' + active_issue + '"',
            #  fields='*',
            fields=','.join([
                'summary', 'comment', 'component', 'description', 'issuetype',
                'priority', 'status', 'created', 'updated', 'assignee',
                'reporter', 'fixVersion', 'customfield_10106'
            ]),
            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 = issue['created'][0:10] + ' ' + issues['issues'][0]['fields'][
            'created'][11:16]
        updated = issue['updated'][0:10] + ' ' + issues['issues'][0]['fields'][
            'updated'][11:16]
        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']])
        description = str(issue.get('description'))

        comments = ''
        idx = 0
        for idx, comment in enumerate((issue['comment']['comments'])):
            comments += ''.join([
                comment['author']['displayName'] + ' @ ' +
                #  comment['body'] + '\n}}}\n'
                comment['updated'][0:10] + ' ' + comment['updated'][11:16] +
                ' {{{2\n' + comment['body'] + '\n}}}\n'
            ])
        comments = ''.join(['Old Comments {{{1\n'
                            ]) + comments if idx > 3 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
        ]
        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) % 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 ' '])

        # 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} │
│    Component │ {component}{component_spaces} │
│      Version │ {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)

        return report.format(**locals())

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

        self.get_users()

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

        for server in self.vira_servers.keys():
            print(server)

    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.get_versions()

    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)

        users = []
        for issue in issues["issues"]:

            id = str(issue['fields']['reporter']['self']).split("=")[1]
            user = issue['fields']['reporter']['displayName']
            if user + ' ~ ' + id not in users:
                users.append(user + ' ~ ' + str(id))

        for user in sorted(users):
            print(user)
        print('Unassigned')

    def get_versions(self):
        '''
        Build a vim popup menu for a list of versions
        '''

        for version in self.jira.project_versions(
                self.userconfig_filter['project']):
            print(version.name)
        print('null')

    def load_project_config(self):
        '''
        Load project configuration for the current git repo

        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

        repo = run_command(
            'git rev-parse --show-toplevel')['stdout'].strip().split('/')[-1]

        # If curren't repo doesn't exist, use __default__ project config if it exists
        if not self.vira_projects.get(repo):
            if self.vira_projects.get('__default__'):
                repo = '__default__'
            else:
                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

    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 updated DESC'
        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',
            'Status': 'ViraSetStatus',
            'Type': 'ViraSetType',
            'Version': 'ViraSetVersion',
            'Summary': 'ViraEditSummary',
        }

        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
                    if field == 'Summary':
                        self.report_lines[idx + 2] = command
                        self.report_lines[idx + 3] = command
                    continue

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

        offset = 2 if len(issue['comment']['comments']) > 4 else 1
        comment_line = 18 + 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 write_jira(self):
        '''
        Write to jira
        Can be issue name, description, comment, etc...
        '''

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

        # Check if anything was actually entered by user
        if input_stripped == '':
            print("No vira actions performed")
            return

        if self.prompt_type == 'add_comment':
            return self.jira.add_comment(issue, input_stripped)
        if self.prompt_type == 'edit_comment':
            return self.active_comment.update(body=input_stripped)
        elif self.prompt_type == 'summary':
            return self.jira.issue(issue).update(summary=input_stripped)
        elif self.prompt_type == 'description':
            return self.jira.issue(issue).update(description=input_stripped)
        elif self.prompt_type == 'issue':
            return self.create_issue(input_stripped)
Exemple #6
0
    def create_bug_issue(self,
                         channel,
                         summary,
                         description,
                         component,
                         version,
                         labels,
                         user=JIRA_USER,
                         passwd=JIRA_PASS,
                         project=JIRA_PROJECT):
        """
        Creates a bug issue on Jira
        :param channel: The channel to notify
        :param summary: The title summary
        :param description: Description field
        :param component: Component bug affects
        :param version: Version this bug affects
        :param labels: Labels to attach to the issue
        :param user: User to report bug as
        :param passwd: Password
        :param project: Jira project
        """
        if user and passwd and project:
            try:
                jira = JIRA(server='https://issues.voltdb.com/',
                            basic_auth=(user, passwd))
            except:
                self.logger.exception('Could not connect to Jira')
                return
        else:
            self.logger.error(
                'Did not provide either a Jira user, a Jira password or a Jira project'
            )
            return

        # Check for existing bug with same summary
        existing = jira.search_issues('summary ~ \'%s\'' % summary)
        if len(existing) > 0:
            # Already reported
            self.logger.info('OLD: Already reported issue with summary "' +
                             summary + '"')
            return

        issue_dict = {
            'project': project,
            'summary': summary,
            'description': description,
            'issuetype': {
                'name': 'Bug'
            },
            'labels': labels
        }

        jira_component = None
        components = jira.project_components(project)
        for c in components:
            if c.name == component:
                jira_component = {'name': c.name, 'id': c.id}
                break
        if jira_component:
            issue_dict['components'] = [jira_component]
        else:
            # Components is still a required field
            issue_dict['components'] = ['Core']

        jira_version = None
        versions = jira.project_versions(project)
        for v in versions:
            if v.name == version:
                jira_version = {'name': v.name, 'id': v.id}
                break
        if jira_version:
            issue_dict['versions'] = [jira_version]
        else:
            # Versions is still a required field
            issue_dict['versions'] = ['DEPLOY-Integration']

        new_issue = jira.create_issue(fields=issue_dict)
        self.logger.info('NEW: Reported issue with summary "' + summary + '"')

        if self.connect_to_slack():
            self.post_message(
                channel, 'Opened issue at https://issues.voltdb.com/browse/' +
                new_issue.key)
Exemple #7
0
if not options.usernameJIRA or not options.passwordJIRA or not options.jiraserver or not options.frombranch or not options.jbidefixversion or not options.jbdsfixversion or not options.taskdescription:
    parser.error("Must to specify ALL commandline flags")

jiraserver = options.jiraserver
jbide_fixversion = options.jbidefixversion
jbds_fixversion = options.jbdsfixversion

from components import checkFixVersionsExist, queryComponentLead, defaultAssignee

if checkFixVersionsExist(jbide_fixversion, jbds_fixversion, jiraserver,
                         options.usernameJIRA, options.passwordJIRA) == True:

    frombranch = options.frombranch
    jira = JIRA(options={'server': jiraserver},
                basic_auth=(options.usernameJIRA, options.passwordJIRA))
    CLJBIDE = jira.project_components(
        jira.project('JBIDE'))  # full list of components in JBIDE
    CLJBDS = jira.project_components(
        jira.project('JBDS'))  # full list of components in JBIDE

    taskdescription = options.taskdescription
    taskdescriptionfull = options.taskdescriptionfull
    if not options.taskdescriptionfull:
        taskdescriptionfull = options.taskdescription

    ## The jql query across for all task issues
    tasksearchquery = '((project in (JBDS) and fixVersion = "' + jbds_fixversion + '") or (project in (JBIDE) and fixVersion = "' + jbide_fixversion + '")) AND labels = task'

    tasksearch = jiraserver + '/issues/?jql=' + urllib.quote_plus(
        tasksearchquery)

    rootJBDS_dict = {
Exemple #8
0
password=creds[1]
server=creds[2]

##Get arguments.
parser = argparse.ArgumentParser(description='You have to specify 2 arguments that describes source project and destionation peroject.')
parser.add_argument('--source', action='store', help='Source Project')
parser.add_argument('--dest', action='store', help='Destination Project')
args = parser.parse_args()

if not args.source or not args.dest:
 parser.print_help()
 sys.exit()

##Acess Jira and get info.
jira = JIRA(server=server,basic_auth=(username,password))
projSrc = jira.project_components(args.source)
projDst = jira.project_components(args.dest)

###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)):
class AntonJira():
    def __init__(self, server, email, apitoken):
        self.jira_instance = JIRA(server=server, basic_auth=(email, apitoken))

    def get_project(self, project_key):
        """
		name -- project name
		lead.displayName -- leader name
		"""
        return self.jira_instance.project(project_key)

    def get_project_components(self, project):
        """
		requires : project instance
		returns : list of components
		"""
        return [
            comp.name
            for comp in self.jira_instance.project_components(project)
        ]

    def get_issue_detail(self, issue_key):
        """
		.fields.summary -- summary
		.fields.votes.votes -- votes
		.fields.description
		.fields.comment : [{
			.author.displayName
			.body
		}]
		"""
        return self.jira_instance.issue(issue_key)

    def get_issues_in_project(self, project_key):
        """
		[
			.fields.summary -- summary
			.fields.votes.votes -- votes
			.fields.description
			.fields.comment : [{
				.author.displayName
				.body
			}]
		]
		"""
        return self.jira_instance.search_issues(f"project={project_key}")

    def get_issues_of_current_user_in_project(self, project_key):
        """
		[
			.fields.summary -- summary
			.fields.votes.votes -- votes
			.fields.description
			.fields.comment : [{
				.author.displayName
				.body
			}]
		]
		"""
        return self.jira_instance.search_issues(
            f"project={project_key} and assignee=currentuser()")

    def get_issues_of_current_user(self):
        """
		[
			.fields.summary -- summary
			.fields.votes.votes -- votes
			.fields.description
			.fields.comment : [{
				.author.displayName
				.body
			}]
		]
		"""
        return self.jira_instance.search_issues(f"assignee=currentuser()")


# jira = JIRA('https://anton3.atlassian.net',basic_auth=('*****@*****.**', 'TKLhcdc5zw2anmiX8DQ946BD'))
# jra = jira.project('AN')
# print(jra.name)
# print(jra.lead.displayName)

# email:[email protected]
# password: pratikbaid@2471

# jira = AntonJira('https://anton3.atlassian.net','*****@*****.**', 'TKLhcdc5zw2anmiX8DQ946BD')
# print(jira.get_issues_of_current_user('AN'))
Exemple #10
0
    def create_bug_issue(self,
                         channel,
                         summary,
                         description,
                         component,
                         version,
                         labels,
                         user=JIRA_USER,
                         passwd=JIRA_PASS,
                         project=JIRA_PROJECT,
                         DRY_RUN=False):
        """
        Creates a bug issue on Jira
        :param channel: The channel to notify
        :param summary: The title summary
        :param description: Description field
        :param component: Component bug affects
        :param version: Version this bug affects
        :param labels: Labels to attach to the issue
        :param user: User to report bug as
        :param passwd: Password
        :param project: Jira project
        """
        if user and passwd and project:
            try:
                jira = JIRA(server='https://issues.voltdb.com/',
                            basic_auth=(user, passwd),
                            options=dict(verify=False))
            except:
                self.logger.exception('Could not connect to Jira')
                return
        else:
            self.logger.error(
                'Did not provide either a Jira user, a Jira password or a Jira project'
            )
            return

        # Check for existing bugs for the same test case, if there are any, suppress filing another
        test_case = summary.split(' ')[0]
        existing = jira.search_issues(
            'summary ~ \'%s\' and labels = automatic and status != Closed' %
            test_case)
        if len(existing) > 0:
            # Already reported
            self.logger.info('Found open issue(s) for "' + test_case + '" ' +
                             ' '.join([k.key for k in existing]))
            return

        issue_dict = {
            'project': project,
            'summary': summary,
            'description': description,
            'issuetype': {
                'name': 'Bug'
            },
            'labels': labels
        }

        jira_component = None
        components = jira.project_components(project)
        for c in components:
            if c.name == component:
                jira_component = {'name': c.name, 'id': c.id}
                break
        if jira_component:
            issue_dict['components'] = [jira_component]
        else:
            # Components is still a required field
            issue_dict['components'] = ['Core']

        jira_version = None
        versions = jira.project_versions(project)
        version = 'V' + version
        for v in versions:
            if str(v.name) == version.strip():
                jira_version = {'name': v.name, 'id': v.id}
                break
        if jira_version:
            issue_dict['versions'] = [jira_version]
        else:
            # Versions is still a required field
            issue_dict['versions'] = ['DEPLOY-Integration']

        issue_dict['fixVersions'] = [{'name': 'Backlog'}]
        issue_dict['priority'] = {'name': 'Blocker'}

        self.logger.info("Filing ticket: %s" % summary)
        if not DRY_RUN:
            new_issue = jira.create_issue(fields=issue_dict)
            #self.logger.info('NEW: Reported issue with summary "' + summary + '"')
            if self.connect_to_slack():
                self.post_message(
                    channel,
                    'Opened issue at https://issues.voltdb.com/browse/' +
                    new_issue.key)
        else:
            new_issue = None

        return new_issue
Exemple #11
0
    def create_bug_issue(self,
                         channel,
                         summary,
                         description,
                         component,
                         version,
                         labels,
                         attachments={},
                         user=JIRA_USER,
                         passwd=JIRA_PASS,
                         project=JIRA_PROJECT,
                         DRY_RUN=False):
        """
        Creates a bug issue on Jira
        :param channel: The channel to notify
        :param summary: The title summary
        :param description: Description field
        :param component: Component bug affects
        :param version: Version this bug affects
        :param labels: Labels to attach to the issue
        :param user: User to report bug as
        :param passwd: Password
        :param project: Jira project
        """
        def add_attachments(jira, ticketId, attachments):
            for file in attachments:
                urlretrieve(attachments[file], file)
                jira.add_attachment(ticketId, os.getcwd() + '/' + file, file)
                os.unlink(file)

        if user and passwd and project:
            try:
                jira = JIRA(server='https://issues.voltdb.com/',
                            basic_auth=(user, passwd),
                            options=dict(verify=False))
            except:
                self.logger.exception('Could not connect to Jira')
                return
        else:
            self.logger.error(
                'Did not provide either a Jira user, a Jira password or a Jira project'
            )
            return

        # Check for existing bugs for the same test case, if there are any, suppress filing another
        test_case = summary.split(' ')[0]
        existing = jira.search_issues(
            'summary ~ \'%s\' and labels = automatic and status != Closed' %
            test_case)
        if len(existing) > 0:
            self.logger.info('Found open issue(s) for "' + test_case + '" ' +
                             ' '.join([k.key for k in existing]))

            # Check if new failure is on different job than existing ticket, if so comments
            job = summary.split()[-2]
            existing_ticket = jira.issue(existing[0].id)
            if job not in existing_ticket.fields.summary:
                comments = jira.comments(existing[0].id)
                for comment in comments:
                    # Check for existing comment for same job, if there are any, suppress commenting another
                    if job in comment.body:
                        self.logger.info('Found existing comment(s) for "' +
                                         job + '" on open issue')
                        return

                self.logger.info(
                    'Commenting about separate job failure for %s on open issue'
                    % test_case)
                if not DRY_RUN:
                    jira.add_comment(existing[0].id,
                                     summary + '\n\n' + description)
                    add_attachments(jira, existing[0].id, attachments)
            return

        issue_dict = {
            'project': project,
            'summary': summary,
            'description': description,
            'issuetype': {
                'name': 'Bug'
            },
            'labels': labels
        }

        jira_component = None
        components = jira.project_components(project)
        for c in components:
            if c.name == component:
                jira_component = {'name': c.name, 'id': c.id}
                break
        if jira_component:
            issue_dict['components'] = [jira_component]
        else:
            # Components is still a required field
            issue_dict['components'] = ['Core']

        jira_version = None
        versions = jira.project_versions(project)
        version = 'V' + version
        for v in versions:
            if str(v.name) == version.strip():
                jira_version = {'name': v.name, 'id': v.id}
                break
        if jira_version:
            issue_dict['versions'] = [jira_version]
        else:
            # Versions is still a required field
            issue_dict['versions'] = ['DEPLOY-Integration']

        issue_dict['fixVersions'] = [{'name': 'Backlog'}]
        issue_dict['priority'] = {'name': 'Blocker'}

        self.logger.info("Filing ticket: %s" % summary)
        if not DRY_RUN:
            new_issue = jira.create_issue(fields=issue_dict)
            add_attachments(jira, new_issue.id, attachments)
            #self.logger.info('NEW: Reported issue with summary "' + summary + '"')
            if self.connect_to_slack():
                self.post_message(
                    channel,
                    'Opened issue at https://issues.voltdb.com/browse/' +
                    new_issue.key)
            suite = summary.split('.')[-3]
            # Find all tickets within same test suite and link them
            link_tickets = jira.search_issues(
                'summary ~ \'%s\' and labels = automatic and status != Closed and reporter in (voltdbci)'
                % suite)
            for ticket in link_tickets:
                jira.create_issue_link('Related', new_issue.key, ticket)
        else:
            new_issue = None

        return new_issue
Exemple #12
0
class JiraReporter:
    """Main interface for creating and searching issues on JIRA"""

    JQL_NOT_IN_STATUS = "status != '{status}'"
    JQL_DESCRIPTION_CONTAINS = "description ~ '{hash_value}'"

    STATUS_CLOSED = 'Closed'
    STATUS_OPEN = 'Open'

    def __init__(self):
        self._projects = CFG['projects']
        self._jira = JIRA(server=CFG['url'],
                          basic_auth=(CFG['user'], CFG['password']))

    def existing_issue(self, issue_hash: str):
        """Checks if JIRA issues with issue_hash in description exists.

        Searches for 'Open' JIRA issues which contains issue_hash in their
        description.

        Args:
            issue_hash: hash that will be searched in JIRA description field

        Returns:
            first JIRA issue which is not in status 'Closed'
            and contains issue_hash or None

        """
        issues = self._search_for_issues(issue_hash, self.STATUS_CLOSED)

        if issues:
            return issues[0]
        else:
            return None

    def create_or_update_issue(self, issue):
        """Creates an JIRA issue or updates and existing one

        Creates JIRA issue at project taken from configuration file.

        Args:
            issue: an instance of kapajira.jira.Issue class

        """

        existing_issue = self.existing_issue(issue.get_issue_hash())

        issue_dict = {
            'project': self._projects[0],
            'summary': issue.get_summary(),
            'description': issue.get_description(),
            'issuetype': issue.get_issue_type(),
            'labels': issue.get_labels()
        }

        if issue.get_component() is not None:
            for project in self._projects:
                if self._component_exists(issue.get_component(), project):
                    issue_dict['project'] = project
                    issue_dict['components'] = [{
                        'name': issue.get_component()
                    }]
                    break

        if existing_issue is not None:
            existing_issue.update(
                fields={'description': issue_dict['description']})
        else:
            self._jira.create_issue(fields=issue_dict)

    def _search_for_issues(self, issue_hash, status):
        jql_query = ' AND '.join([
            self.JQL_DESCRIPTION_CONTAINS.format(hash_value=issue_hash),
            self.JQL_NOT_IN_STATUS.format(status=status)
        ])

        return self._jira.search_issues(jql_query)

    def _component_exists(self, component_name: str, project: str) -> bool:
        components_for_project = self._jira.project_components(project=project)
        for x in components_for_project:
            if component_name == x.name:
                return True
        return False
Exemple #13
0
    def create_bug_issue(self, channel, summary, description, component, version, labels,
                         user=JIRA_USER, passwd=JIRA_PASS, project=JIRA_PROJECT):
        """
        Creates a bug issue on Jira
        :param channel: The channel to notify
        :param summary: The title summary
        :param description: Description field
        :param component: Component bug affects
        :param version: Version this bug affects
        :param labels: Labels to attach to the issue
        :param user: User to report bug as
        :param passwd: Password
        :param project: Jira project
        """
        if user and passwd and project:
            try:
                jira = JIRA(server='https://issues.voltdb.com/', basic_auth=(user, passwd))
            except:
                self.logger.exception('Could not connect to Jira')
                return
        else:
            self.logger.error('Did not provide either a Jira user, a Jira password or a Jira project')
            return

        # Check for existing bug with same summary
        existing = jira.search_issues('summary ~ \'%s\'' % summary)
        if len(existing) > 0:
            # Already reported
            self.logger.info('OLD: Already reported issue with summary "' + summary + '"')
            return

        issue_dict = {
            'project': project,
            'summary': summary,
            'description': description,
            'issuetype': {
                'name': 'Bug'
            },
            'labels': labels
        }

        jira_component = None
        components = jira.project_components(project)
        for c in components:
            if c.name == component:
                jira_component = {
                    'name': c.name,
                    'id': c.id
                }
                break
        if jira_component:
            issue_dict['components'] = [jira_component]
        else:
            # Components is still a required field
            issue_dict['components'] = ['Core']

        jira_version = None
        versions = jira.project_versions(project)
        version = 'V' + version
        for v in versions:
            if str(v.name) == version.strip():
                jira_version = {
                    'name': v.name,
                    'id': v.id
                }
                break
        if jira_version:
            issue_dict['versions'] = [jira_version]
        else:
            # Versions is still a required field
            issue_dict['versions'] = ['DEPLOY-Integration']

        issue_dict['fixVersions'] = [{'name':'Backlog'}]
        issue_dict['priority'] = {'name': 'Blocker'}

        new_issue = jira.create_issue(fields=issue_dict)
        self.logger.info('NEW: Reported issue with summary "' + summary + '"')

        if self.connect_to_slack():
            self.post_message(channel, 'Opened issue at https://issues.voltdb.com/browse/' + new_issue.key)
Exemple #14
0
def create_issues_in_jira(*, issue_dicts, server_url, basic_auth, project_name,
                          board_name, assignee_key, components, epic_link,
                          max_results):
    jira = JIRA(server=server_url, basic_auth=basic_auth)

    def get_board(board_name):
        for board in jira.boards():
            if board.name == board_name:
                return board
        return None

    def get_project(project_name):
        for project in jira.projects():
            if project.name == project_name:
                return project
        return None

    project = get_project(project_name)
    if not project:
        raise Exception('project not found: \'{}\''.format(board_name))

    board = get_board(board_name)
    if not board:
        raise Exception('board not found: \'{}\''.format(board_name))

    component_ids = None
    if components is not None:
        component_objs = jira.project_components(project)

        def get_component(component_name):
            for component_obj in component_objs:
                if component_obj.name == component_name:
                    return component_obj
            return None

        component_ids = []
        for component in components:
            component_obj = get_component(component)
            if component_obj is None:
                raise Exception(
                    'component not found: \'{}\''.format(component))
            component_ids.append(component_obj.id)

    if epic_link:
        search_result = jira.search_issues(
            'summary ~ "{}"'.format(f'\\"{epic_link}\\"'))
        if len(search_result) == 0:
            raise Exception('epic not found: \'{}\''.format(epic_link))
        elif len(search_result) > 1:
            raise Exception(
                'more than one epic found for name \'{}\''.format(epic_link))
        epic = search_result[0]
    else:
        epic = None

    create_issues_results = []

    def _create_issue(issue_dict, parent=None):
        fields_list = [{
            'project': {
                'key': project.key
            },
            'summary': issue_dict['summary'],
            'description': issue_dict['description'],
            'issuetype': {
                'name': 'Task' if parent is None else 'Sub Task'
            },
        }]
        if parent is None:
            fields_list[0]['assignee'] = {
                'name':
                issue_dict['assignee']
                if issue_dict['assignee'] else assignee_key
            }
        if component_ids is not None:
            fields_list[0]['components'] = [{
                'id': component_id
            } for component_id in component_ids]
        if parent is not None:
            fields_list[0]['parent'] = {'key': parent.key}
        results = jira.create_issues(fields_list)
        assert len(results) == 1
        result = results[0]
        issue_obj = result['issue']
        for sub_issue_dict in issue_dict['sub_issues']:
            _create_issue(sub_issue_dict, issue_obj)
        create_issues_results.append(
            dict(issue_dict=issue_dict, issue_obj=issue_obj))

    for issue_dict in issue_dicts:
        _create_issue(issue_dict)

    if epic is not None:
        jira.add_issues_to_epic(epic.id, [
            create_issues_result['issue_obj'].key
            for create_issues_result in create_issues_results if
            create_issues_result['issue_obj'].fields.issuetype.name == 'Task'
        ])

    issues_to_add_to_sprint = [
        create_issues_result['issue_obj'].key
        for create_issues_result in create_issues_results
        if create_issues_result['issue_dict'].get('add_to_sprint', False)
    ]
    if issues_to_add_to_sprint:
        sprints = jira.sprints(board.id,
                               extended=['startDate', 'endDate'],
                               maxResults=max_results)
        if len(sprints) == 0:
            raise Exception('There\'s no open sprint')
        last_sprint = sprints[-1]
        jira.add_issues_to_sprint(last_sprint.id, issues_to_add_to_sprint)
Exemple #15
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 #16
0
    def report_issue(self, build):
        try:
            jira = JIRA(server='https://issues.voltdb.com/', basic_auth=(JIRA_USER, JIRA_PASS))
        except:
            logging.exception('Could not connect to Jira')
            return

        build_report_url = self.jhost + '/job/' + job + '/' + str(build) + '/api/python'
        build_report = eval(self.read_url(build_report_url))
        build_url = build_report.get('url')
        build_result = build_report.get('result')

        if build_result == 'SUCCESS':  # only generate Jira issue if the test fails
            print 'No new issue created. Build ' + str(build) + 'resulted in: ' + build_result
            return

        summary_url = self.jhost + '/job/' + job + '/' + str(build) + '/artifact/tests/sqlgrammar/summary.out'
        summary_report = self.read_url(summary_url)

        pframe_split = summary_report.split('Problematic frame:')
        pframe_split = pframe_split[1].split('C')
        pframe_split = pframe_split[1].split(']')
        pframe_split = pframe_split[1].split('#')
        pframe = pframe_split[0].strip()

        summary = job + ':' + str(build) + ' - ' + pframe
        # search_issues gets a parsing error on (), so escape it.
        existing = jira.search_issues('summary ~ \'%s\'' % summary.replace('()','\\\\(\\\\)',10))
        if len(existing) > 0:
            print 'No new Jira issue created. Build ' + str(build) + ' has already been reported.'
            return 'Already reported'

        old_issue = ''
        existing = jira.search_issues('summary ~ \'%s\'' % pframe_split[0].strip().replace('()','\\\\(\\\\)',10))
        for issue in existing:
            if str(issue.fields.status) != 'Closed' and u'grammar-gen' in issue.fields.labels:
                old_issue = issue

        build_artifacts = build_report.get('artifacts')[0]
        pid_fileName = build_artifacts['fileName']
        pid_url = build_url + 'artifact/' + pid_fileName

        query_split = summary_report.split('(or it was never started??), after SQL statement:')
        crash_query = query_split[1]

        hash_split = summary_report.split('#', 1)
        hash_split = hash_split[1].split('# See problematic frame for where to report the bug.')
        sigsegv_message = hash_split[0] + '# See problematic frame for where to report the bug.\n#'

        description = job + ' build ' + str(build) + ' : ' + str(build_result) + '\n' \
            + 'Jenkins build: ' + build_url + ' \n \n' \
            + 'DDL: ' + 'https://github.com/VoltDB/voltdb/blob/master/tests/sqlgrammar/DDL.sql' + ' \n \n' \
            + 'hs_err_pid: ' + pid_url + ' \n \n' \
            + 'SIGSEGV Message: \n' + '#' + sigsegv_message + ' \n \n' \
            + 'Query that Caused the Crash: ' + crash_query
        description = description.replace('#', '\#')

        labels = ['grammar-gen']

        component = 'Core'
        components = jira.project_components(JIRA_PROJECT)
        jira_component = {}
        for c in components:
            if c.name == component:
                jira_component = {
                    'name': c.name,
                    'id': c.id
                }
                break

        current_version_raw = str(self.read_url('https://raw.githubusercontent.com/VoltDB/voltdb/master/version.txt'))
        current_version_float = float(current_version_raw)
        current_version = 'V' + current_version_raw
        current_version = current_version.strip()
        next_version = current_version_float + .1
        next_version = str(next_version)
        next_version = 'V' + next_version
        next_version = next_version[:4]

        jira_versions = jira.project_versions(JIRA_PROJECT)
        this_version = {}
        new_version = {}

        for v in jira_versions:
            if str(v.name) == current_version:
                this_version = {
                    'name': v.name,
                    'id': v.id
                }
            if str(v.name) == next_version:
                new_version = {
                    'name': v.name,
                    'id': v.id
                }

        issue_dict = {
            'project': JIRA_PROJECT,
            'summary': summary,
            'description': description,
            'issuetype': {'name': 'Bug'},
            'priority': {'name': 'Blocker'},
            'labels': labels,
            'customfield_10430': {'value': 'CORE team'},
            'components': [jira_component]
        }

        if new_version:
            issue_dict['versions'] = [new_version]
            issue_dict['fixVersions'] = [new_version]

        elif this_version:
            issue_dict['versions'] = [this_version]
            issue_dict['fixVersions'] = [this_version]

        if old_issue:
            new_comment = jira.add_comment(old_issue, description)
            print 'JIRA-action: New comment on issue: ' + str(old_issue) + ' created for failure on build ' + str(build)
        else:
            new_issue = jira.create_issue(fields=issue_dict)
            print 'JIRA-action: New issue ' + new_issue.key + ' created for failure on build ' + str(build)
Exemple #17
0
class Util(object):
    """

    """
    def __init__(self, **kwargs):
        """

        """

        if 'config' in kwargs:
            self._config = kwargs['config']
        else:
            logging.critical("config was not defined")
            raise Exception("config was not defined")

        if 'username' in kwargs:
            self._username = kwargs['username']
        else:
            logging.critical("username was not defined")
            raise Exception("username was not defined")

        if 'password' in kwargs:
            self._password = kwargs['password']
        else:
            logging.critical("password was not defined")
            raise Exception("password was not defined")

        if 'project' in kwargs:
            self._project = kwargs['project']
        else:
            if 'project' in self._config:
                self._project = self._config['project']
                logging.info(
                    "project was set to '%s' from the configuration file" %
                    self._project)
            else:
                self._project = DEFAULT_PROJECT
                logging.info("project was set to default '%s'" % self._project)

        if 'base_url' in kwargs:
            self._base_url = kwargs['base_url']
        else:
            if 'base_url' in self._config:
                self._base_url = self._config['base_url']
                logging.info(
                    "base_url was set to '%s' from the configuration file" %
                    self._base_url)
            else:
                self._base_url = DEFAULT_BASE_URL
                logging.info("base_url was set to default '%s'" %
                             self._base_url)

        if 'add_missing_watchers' in kwargs:
            self._add_missing_watchers = kwargs['add_missing_watchers']
        else:
            if 'add_missing_watchers' in self._config:
                self._add_missing_watchers = self._config[
                    'add_missing_watchers']
                logging.info(
                    "add_missing_watchers was set to '%s' from the configuration file"
                    % self._add_missing_watchers)
            else:
                self._add_missing_watchers = DEFAULT_ADD_MISSING_WATCHERS
                logging.info("add_missing_watchers was set to default '%s'" %
                             self._add_missing_watchers)

        self._jira = None
        self._jra = None

        self._initialize()

    def setProject(self, project):
        """

        :param project:
        :return:
        """
        self._project = project

    def setAddMissingWatchers(self, add_missing_watchers):
        """

        :param add_missing_watchers:
        :return:
        """
        self._add_missing_watchers = add_missing_watchers

    def _initialize(self):
        """

        :return:
        """
        print("Attempting to connect to JIRA at '%s'" % self._base_url)
        self._jira = JIRA(self._base_url,
                          basic_auth=(self._username, self._password))

        print("Attempting to retrieve info for project '%s'" % self._project)
        self._jra = self._jira.project(self._project)

    def getReport(self):
        """

        :return:
        """
        self.report_misc()
        self.report_components()
        self.report_roles()
        self.report_versions()
        self.report_open_issues()

    def report_misc(self):
        """

        :return:
        """
        print(Fore.BLUE + "Project name '%s'" % self._jra.name)

        print(Fore.BLUE + "Project lead '%s'" % self._jra.lead.displayName)

        print(Style.RESET_ALL)

    def report_components(self):
        """

        :return:
        """
        components = self._jira.project_components(self._jra)

        if len(components) > 0:

            print(Fore.BLUE + "Here are the components")

            print(Style.RESET_ALL)

            for c in components:
                print(c.name)
        else:
            print(Fore.RED + "There are no components")

        print(Style.RESET_ALL)

    def report_roles(self):
        """

        :return:
        """
        roles = self._jira.project_roles(self._jra)

        if len(roles) > 0:

            print(Fore.BLUE + "Here are the roles")

            print(Style.RESET_ALL)

            for r in roles:
                print(r)
        else:
            print(Fore.RED + "There are no roles")

        print(Style.RESET_ALL)

    def report_versions(self):
        """

        :return:
        """
        versions = self._jira.project_versions(self._jra)

        if len(versions) > 0:

            print(Fore.BLUE + "Here are the versions")

            print(Style.RESET_ALL)

            for v in reversed(versions):
                print(v.name)
        else:
            print(Fore.RED + "There are no versions")

        print(Style.RESET_ALL)

    def report_watchers(self, issue):
        """

        :param issue:
        :return:
        """

        watcher = self._jira.watchers(issue)

        print("Issue '%s' has '%d' watcher(s)" %
              (issue.key, watcher.watchCount))

        current_watchers_email = {}

        for watcher in watcher.watchers:
            current_watchers_email[watcher.emailAddress] = True
            print("'%s' - '%s'" % (watcher, watcher.emailAddress))
            # watcher is instance of jira.resources.User:
            # print(watcher.emailAddress)

        for watcher_email in self._config['members_email_lookup']:
            if not watcher_email in current_watchers_email:
                print(Fore.RED +
                      "member '%s' needs to be added as a watcher to '%s'" %
                      (watcher_email, issue.key))
                username = self._config['members_email_lookup'][watcher_email]
                print("Need to add username '%s'" % username)
                print(Style.RESET_ALL)
                if self._add_missing_watchers:
                    self._jira.add_watcher(issue, username)
                    print("Exiting")
                    sys.exit(0)

        print(Style.RESET_ALL)

    def checkWatchers(self):
        """

        :return:
        """

        issues = self._jira.search_issues('project= LO AND status !=  Done',
                                          maxResults=DEFAULT_MAX_RESULTS)

        if len(issues) > 0:

            for issue in issues:
                self.report_watchers(issue)

    def report_open_issues(self):

        issues = self._jira.search_issues('project= LO AND status !=  Done',
                                          maxResults=DEFAULT_MAX_RESULTS)

        if len(issues) > 0:
            print(Fore.BLUE +
                  "Found the following '%d' open issues" % len(issues))

            print(Style.RESET_ALL)

            for issue in issues:
                summary = issue.fields.summary
                id = issue.id
                key = issue.key
                print("id '%s' key '%s' summary : '%s'" % (id, key, summary))
                if DEFAULT_REPORT_WATCHERS:
                    self._report_watchers(issue)

        print(Style.RESET_ALL)

    def getComments(self, key):
        """

        :param key:
        :return:
        """
        logging.info("Attempting to retrieve the issue with key '%s'" % key)

        issues = self._jira.search_issues('key = ' + key)
        if len(issues) > 1:
            raise Exception("Expected only one issue for '%s' but found '%d'" %
                            (key, len(issues)))

        if len(issues) == 1:
            # comments = issues[0].fields.comment.comments
            # comments = issues[0].raw['fields']['comment']['comments']
            comments = self._jira.comments(issues[0])

            if len(comments) > 0:
                print("Found the following '%d' comments" % len(comments))
                comment_ctr = 0
                for comment_id in comments:
                    print("-----------------------------------")
                    comment_ctr += 1
                    comment = self._jira.comment(key, comment_id)
                    author = comment.author.displayName
                    date_created = comment.created
                    body = comment.body
                    print(Fore.BLUE + "%d. author '%s' date '%s'" %
                          (comment_ctr, author, date_created))
                    print(Style.RESET_ALL)
                    print(body)
Exemple #18
0
##Get arguments.
parser = argparse.ArgumentParser(
    description=
    'You have to specify 2 arguments that describes source project and destionation peroject.'
)
parser.add_argument('--source', action='store', help='Source Project')
parser.add_argument('--dest', action='store', help='Destination Project')
args = parser.parse_args()

if not args.source or not args.dest:
    parser.print_help()
    sys.exit()

##Acess Jira and get info.
jira = JIRA(server=server, basic_auth=(username, password))
projSrc = jira.project_components(args.source)
projDst = jira.project_components(args.dest)

###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)):
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 #20
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 #21
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
			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
Exemple #23
0
    def report_issue(self, build):
        try:
            jira = JIRA(server='https://issues.voltdb.com/',
                        basic_auth=(JIRA_USER, JIRA_PASS),
                        options=dict(verify=False))
        except:
            logging.exception('Could not connect to Jira')
            return

        build_report_url = self.jhost + '/job/' + job + '/' + str(
            build) + '/api/python'
        build_report = eval(self.read_url(build_report_url))
        build_url = build_report.get('url')
        build_result = build_report.get('result')

        if build_result == 'SUCCESS':  # only generate Jira issue if the test fails
            print 'No new issue created. Build ' + str(
                build) + 'resulted in: ' + build_result
            return

        summary_url = self.jhost + '/job/' + job + '/' + str(
            build) + '/artifact/summary.out'
        summary_report = self.read_url(summary_url)

        pframe_split = summary_report.split('Problematic frame:')
        pframe_split = pframe_split[1].split('C')
        pframe_split = pframe_split[1].split(']')
        pframe_split = pframe_split[1].split('#')
        pframe = pframe_split[0].strip()

        summary = job + ':' + str(build) + ' - ' + pframe
        # search_issues gets a parsing error on (), so escape it.
        existing = jira.search_issues('summary ~ \'%s\'' %
                                      summary.replace('()', '\\\\(\\\\)', 10))
        if len(existing) > 0:
            print 'No new Jira issue created. Build ' + str(
                build) + ' has already been reported.'
            return 'Already reported'

        old_issue = ''
        existing = jira.search_issues(
            'summary ~ \'%s\'' %
            pframe_split[0].strip().replace('()', '\\\\(\\\\)', 10))
        for issue in existing:
            if str(issue.fields.status
                   ) != 'Closed' and u'grammar-gen' in issue.fields.labels:
                old_issue = issue

        build_artifacts = build_report.get('artifacts')[0]
        pid_fileName = build_artifacts['fileName']
        pid_url = build_url + 'artifact/' + pid_fileName

        query_split = summary_report.split(
            '(or it was never started??), after SQL statement:')
        crash_query = query_split[1]

        hash_split = summary_report.split('#', 1)
        hash_split = hash_split[1].split(
            '# See problematic frame for where to report the bug.')
        sigsegv_message = hash_split[
            0] + '# See problematic frame for where to report the bug.\n#'

        description = job + ' build ' + str(build) + ' : ' + str(build_result) + '\n' \
            + 'Jenkins build: ' + build_url + ' \n \n' \
            + 'DDL: ' + 'https://github.com/VoltDB/voltdb/blob/master/tests/sqlgrammar/DDL.sql' + ' \n \n' \
            + 'hs_err_pid: ' + pid_url + ' \n \n' \
            + 'SIGSEGV Message: \n' + '#' + sigsegv_message + ' \n \n' \
            + 'Query that Caused the Crash: ' + crash_query
        description = description.replace('#', '\#')

        labels = ['grammar-gen']

        component = 'Core'
        components = jira.project_components(JIRA_PROJECT)
        jira_component = {}
        for c in components:
            if c.name == component:
                jira_component = {'name': c.name, 'id': c.id}
                break

        current_version_raw = str(
            self.read_url(
                'https://raw.githubusercontent.com/VoltDB/voltdb/master/version.txt'
            ))
        current_version_float = float(current_version_raw)
        current_version = 'V' + current_version_raw
        current_version = current_version.strip()
        next_version = current_version_float + .1
        next_version = str(next_version)
        next_version = 'V' + next_version
        next_version = next_version[:4]

        jira_versions = jira.project_versions(JIRA_PROJECT)
        this_version = {}
        new_version = {}

        for v in jira_versions:
            if str(v.name) == current_version:
                this_version = {'name': v.name, 'id': v.id}
            if str(v.name) == next_version:
                new_version = {'name': v.name, 'id': v.id}

        issue_dict = {
            'project': JIRA_PROJECT,
            'summary': summary,
            'description': description,
            'issuetype': {
                'name': 'Bug'
            },
            'priority': {
                'name': 'Blocker'
            },
            'labels': labels,
            'customfield_10430': {
                'value': 'CORE team'
            },
            'components': [jira_component]
        }

        if new_version:
            issue_dict['versions'] = [new_version]
            issue_dict['fixVersions'] = [new_version]

        elif this_version:
            issue_dict['versions'] = [this_version]
            issue_dict['fixVersions'] = [this_version]

        if old_issue:
            new_comment = jira.add_comment(old_issue, description)
            print 'JIRA-action: New comment on issue: ' + str(
                old_issue) + ' created for failure on build ' + str(build)
        else:
            new_issue = jira.create_issue(fields=issue_dict)
            print 'JIRA-action: New issue ' + new_issue.key + ' created for failure on build ' + str(
                build)
Exemple #24
0
jbide_fixversion = options.jbidefixversion
jbds_fixversion = options.jbdsfixversion
if options.fusefixversion:
    fuse_fixversion = options.fusefixversion
else:
    # set fuse fixversion a.b.c.d = JBDS fixversion (a-1).b.c.d
    fuse_bits = jbds_fixversion.split(".")
    fuse_fixversion = str(
        int(fuse_bits[0]) -
        1) + "." + fuse_bits[1] + "." + fuse_bits[2] + "." + fuse_bits[3]
# sys.exit("jbds_fixversion = " + jbds_fixversion + "\n" + "fuse_fixversion = " + fuse_fixversion) # debug

jiraserver = options.jiraserver
jira = JIRA(options={'server': jiraserver},
            basic_auth=(options.jirauser, options.jirapwd))
CL = jira.project_components(
    jira.project('JBIDE'))  # full list of components in JBIDE

from components import checkFixVersionsExist, queryComponentLead, defaultAssignee


def setComponentLead(theissue, componentLead):
    try:
        jira.assign_issue(theissue, componentLead)
    except:
        print "[WARNING] Unexpected error! User {0} tried to assign {1} to {2}: {3}".format(
            options.jirauser, theissue, componentLead,
            sys.exc_info()[0])


def setTaskLabel(theissue):
    try:
Exemple #25
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())
Exemple #26
0
            print("Watchers:", watcher.emailAddress)
            print("")
        print("CreatedOn:", issue.fields.created)
        print("Updated:", issue.fields.updated)
        print("Components:", issue.fields.components)
        print("Labels:", issue.fields.labels)
        print("--------------------------\n")






#-------------Get list of all SSO and LMS components in project-------------
jiraProject = jira.project('LLSTC')
components = jira.project_components(jiraProject)
componentList = []
if debug:
    print("-------------beginning of LMS Components------------\n")
for c in components:
    if "LMS" in c.name:
        componentList.append(c.name)
        if debug:
            print(c.name)
            print("-------------end of LMS Components------------\n")
            print("-------------beginning of Auth Components------------\n")
for c in components:
    if "SSO" in c.name:
        componentList.append(c.name)
        if debug:
            print(c.name)
Exemple #27
0
class AntonJira():
    def __init__(self, server, email, apitoken):
        self.jira_instance = JIRA(server=server, basic_auth=(email, apitoken))

    def get_project(self, project_key):
        """
		name -- project name
		lead.displayName -- leader name
		"""
        return self.jira_instance.project(project_key)

    def get_project_components(self, project):
        """
		requires : project instance
		returns : list of components
		"""
        return [
            comp.name
            for comp in self.jira_instance.project_components(project)
        ]

    def get_issue_detail(self, issue_key):
        """
		.fields.summary -- summary
		.fields.votes.votes -- votes
		.fields.description
		.fields.comment : [{
			.author.displayName
			.body
		}]
		"""
        return self.jira_instance.issue(issue_key)

    def get_issues_in_project(self, project_key):
        """
		[
			.fields.summary -- summary
			.fields.votes.votes -- votes
			.fields.description
			.fields.comment : [{
				.author.displayName
				.body
			}]
		]
		"""
        return self.jira_instance.search_issues(f"project={project_key}")

    def get_issues_of_current_user_in_project(self, project_key):
        """
		[
			.fields.summary -- summary
			.fields.votes.votes -- votes
			.fields.description
			.fields.comment : [{
				.author.displayName
				.body
			}]
		]
		"""
        return self.jira_instance.search_issues(
            f"project={project_key} and assignee=currentuser()")

    def get_issues_of_current_user(self):
        """
		[
			.fields.summary -- summary
			.fields.votes.votes -- votes
			.fields.description
			.fields.comment : [{
				.author.displayName
				.body
			}]
		]
		"""
        return self.jira_instance.search_issues(f"assignee=currentuser()")