Beispiel #1
0
    def display_escalations(self):
        jira_connection_name = pick_value(
            'Select a JIRA Connection to view Escalation type tickets:',
            list(self._jira_connections.keys()))
        jira_connection = self._jira_connections[jira_connection_name]
        jira_issues = JiraUtils.get_issues_by_query(
            jira_connection,
            'type = \'Escalation\' AND resolution = unresolved')
        issue_keys = []
        for issue in jira_issues:
            issue_keys.append(issue.issue_key)

        df = DisplayFilter.default()
        while True:
            print_separator(30)
            print(os.linesep + 'Escalations' + os.linesep)
            print_separator(30)
            clear()
            df.display_and_return_sorted_issues(self, jira_issues)
            i = get_input('[#] Integer to open issue in browser. [q] to quit.')
            if i == 'q':
                break
            try:
                c_input = int(i) - 1
                JiraUtils.open_issue_in_browser(jira_connection.url,
                                                issue_keys[c_input])
            except ValueError:
                print('Bad input. Try again')
                pause()
Beispiel #2
0
    def search_projects(self):
        """
        Does a one-off ad-hoc search for strings in all cached fields for all cached JiraProjects.
        Keeping at scope of JiraManager as search is a meta-scoped search of all cached JiraProjects independent of JiraConnection
        :return:
        """
        tinput = get_input('Search [o]pen issues only, [c]losed, or [a]ll?')
        substring = get_input('Search for what substring?')
        matches = []
        jira_projects = self.get_all_cached_jira_projects()

        # cache list of seen columns for the query
        columns = {}
        for project in list(jira_projects.values()):
            results = project.get_matching_issues(substring, tinput)
            for r in results:
                matches.append(r)
                for k, v in r.items():
                    # This is going to blast out our ability to filter on reviewer or reviewer 2. For now.
                    if 'custom' not in k:
                        columns[k] = True
        original_list = JiraUtils.sort_custom_jiraissues_by_key(matches)
        display_list = original_list

        df = DisplayFilter.default()
        while True:
            df.display_and_return_sorted_issues(self, display_list)
            print_separator(30)
            cinput = get_input(
                '[#] to open an issue in browser, [c] to clear column filters, [f] to specify a specific field to match on, [q] to return to menu:'
            )
            if str.lower(cinput) == 'f':
                col_name = pick_value('Filter on which column?',
                                      list(columns.keys()), False)
                newlist = []
                for ji in display_list:
                    if col_name in ji:
                        if substring in ji[col_name]:
                            newlist.append(ji)
                display_list = newlist
            elif str.lower(cinput) == 'c':
                display_list = original_list
            elif not str.lower(cinput) == 'q':
                try:
                    jira_issue = display_list[int(cinput) - 1]
                    JiraUtils.open_issue_in_browser(
                        self._jira_connections[
                            jira_issue.jira_connection_name].url,
                        jira_issue.issue_key)
                except ValueError:
                    print('Bad input. Try again.')
            elif str.lower(cinput) == 'q':
                break
Beispiel #3
0
    def display_view(self, jira_manager: 'JiraManager') -> None:
        df = DisplayFilter.default()

        working_issues = list(self.get_issues().values())
        while True:
            try:
                issues = df.display_and_return_sorted_issues(
                    jira_manager, working_issues)
                print_separator(60)
                print('[JiraView operations for {}]'.format(self.name))
                input_prompt = (
                    "[f] to manually enter a substring to regex issues in the view\n"
                    "[c] to clear all regex filtering\n"
                    "[#] Integer value to open ticket in browser\n"
                    "[q] to quit\n"
                    ":")
                custom = get_input(input_prompt)
                if custom == 'q':
                    return
                elif custom == 'f':
                    string = get_input('substring to match:', lowered=False)
                    new_issues = []
                    for jira_issue in working_issues:
                        if jira_issue.matches(self.jira_connection, string):
                            new_issues.append(jira_issue)
                    working_issues = new_issues
                elif custom == 'c':
                    working_issues = list(self.get_issues().values())
                elif len(issues) == 0:
                    print(
                        'No matching jira issues found. Skipping attempt to open.'
                    )
                    pause()
                else:
                    try:
                        JiraUtils.open_issue_in_browser(
                            self.jira_connection.url,
                            issues[int(custom) - 1].issue_key)
                    except ValueError:
                        print('Bad input. Try again.')
            except JIRAError as je:
                print('Caught an error: {}'.format(je))
                traceback.print_exc()
                return
Beispiel #4
0
    def _print_member_details(jira_manager: 'JiraManager', tickets: MemberIssuesByStatus, report_filter: ReportFilter) -> None:
        # We need to re-populate this report filter with this user for matching logic to work
        report_filter.clear()
        report_filter.process_issues(tickets)
        displayed_issues = tickets.display_member_issues(jira_manager, report_filter)

        while True:
            if len(displayed_issues) == 0:
                print('No issues found matching category.')
                pause()
                break
            cmd = get_input('[#] Integer value to open JIRA issue in browser. [q] to return to report results:')
            if cmd == 'q':
                break
            try:
                jira_issue = displayed_issues[int(cmd) - 1]
                jira_connection = jira_manager.get_jira_connection(jira_issue.jira_connection_name)
                JiraUtils.open_issue_in_browser(jira_connection.url, jira_issue.issue_key)
            except ValueError as ve:
                print('Bad input. Try again.')
                print('ValueError : {}'.format(ve))
                pause()
Beispiel #5
0
    def display_view(self, jira_manager):
        # type: (JiraManager) -> None
        df = DisplayFilter.default()

        working_issues = list(self.get_issues().values())
        while True:
            try:
                issues = df.display_and_return_sorted_issues(
                    jira_manager, working_issues)
                print_separator(60)
                print('[JiraView operations for {}]'.format(self.name))
                custom = get_input(
                    '[f] to manually enter a substring to regex issues in the view'
                    + os.linesep + '[c] to clear all regex filtering' +
                    os.linesep +
                    '[#] Integer value to open ticket in browser ' +
                    os.linesep + '[q] to quit' + os.linesep + ':')
                if custom == 'q':
                    return
                elif custom == 'f':
                    string = get_input('substring to match:', lowered=False)
                    new_issues = []
                    for jira_issue in working_issues:
                        if jira_issue.matches(self.jira_connection, string):
                            new_issues.append(jira_issue)
                    working_issues = new_issues
                elif custom == 'c':
                    working_issues = list(self.get_issues().values())
                else:
                    try:
                        JiraUtils.open_issue_in_browser(
                            self.jira_connection.url,
                            issues[int(custom) - 1].issue_key)
                    except ValueError:
                        print('Bad input. Try again.')
            except JIRAError as je:
                print('Caught an error: {}'.format(je))
                traceback.print_exc()
                return
Beispiel #6
0
    def save_config(self) -> None:
        # .cfg file
        config_parser = configparser.RawConfigParser()
        config_parser.add_section('Config')
        if self.jira_connection is not None:
            config_parser.set('Config', 'connection_name',
                              self.jira_connection.connection_name)
        config_parser.set('Config', 'project_name', self.project_name)
        config_parser.set('Config', 'updated', self.updated)
        config_parser.set('Config', 'url', self._url)
        config_parser.set('Config', 'custom_fields',
                          ','.join(list(self._custom_fields.keys())))
        for field in list(self._custom_fields.keys()):
            config_parser.set('Config', field, self._custom_fields[field])

        save_argus_config(config_parser, self.config_file())

        # Protect against saving during init wiping out the local data file. Shouldn't be an issue but seen it pop up
        # during dev once or twice.
        if len(self.jira_issues.keys()) > 0:
            JiraUtils.save_argus_data(list(self.jira_issues.values()),
                                      self._data_file())
Beispiel #7
0
 def refresh(self):
     new_issues = JiraUtils.get_issues_for_project(self.jira_connection,
                                                   self.project_name,
                                                   self.updated)
     if len(new_issues) > 0:
         print('Found {} updated/new issues for {}. Saving to disk.'.format(
             len(new_issues), self.project_name))
         for jira_issue in new_issues:
             if 'updated' not in jira_issue:
                 print(
                     'Missing updated field in issue: {}. Skipping in latest updated calculation.'
                     .format(jira_issue.issue_key))
             else:
                 clean_ts = JiraProject.clean_ts(jira_issue['updated'])
                 if clean_ts > self.updated:
                     self.updated = clean_ts
             self.jira_issues[jira_issue.issue_key] = jira_issue
         self.save_config()
Beispiel #8
0
    def _build_issue_row(self,
                         jira_manager: 'JiraManager',
                         issue: 'JiraIssue',
                         filters: Dict['Column', str],
                         dependency: Optional['JiraDependency'] = None) -> str:
        """
        :param filters: Inclusion-based column-value filters: skips entire row based on this inclusion.
        :param dependency: Optional JiraDependency. Presence of this field indicates this JiraIssue is a dependent ticket,
        which changes our logic somewhat on how we format things (paren, indentation, etc)
        """
        if dependency is None:
            issue_key = issue.issue_key
        else:
            # Preface with a hyphen per dependency depth
            issue_key = '{}{}'.format('-' * DisplayFilter._current_depth,
                                      dependency.target.issue_key)

        issue_string = '{:4}:{}'.format(
            self._current_index,
            str(issue_key)[:self._key_len].ljust(self._key_len))

        for column in list(self.included_columns):
            if dependency is not None and column.pretty_name == DisplayFilter.RELATIONSHIP_STRING:
                val = dependency.pretty_type()
            else:
                val = JiraUtils.retrieve_field_value(jira_manager, issue,
                                                     column.name)

            # filters are include-only, so if we don't have a value but do have includes, drop it
            if filters is not None:
                # On non-matches, we don't return this row at all
                if val is None and column.name in filters:
                    return ''
                elif column in filters and val is not None and filters[
                        column] not in val:
                    return ''

            val = '' if val is None else val
            issue_string += '| {} '.format(
                str(val)[:column.width].ljust(column.width))
        issue_string += os.linesep
        self._current_index += 1
        return issue_string
Beispiel #9
0
    def report_fix_version(self) -> None:
        """
        Creates a report of all tickets, including dependencies, to the input FixVersion.
        """

        # Only support creating of this on a single JiraConnection, with the assumption that multiple projects on that
        # connection can share a FixVersion, but these won't straddle to exterior Jira instances
        target_connection = self.pick_jira_connection(
            'FixVersion report for which JiraConnection?')
        if target_connection is None:
            return

        open_only = is_yes('Show only unresolved issues?')

        to_match = get_input('Input substring to search fixversions for:',
                             False)
        available_versions = set()
        for jira_project in target_connection.cached_projects:
            for jira_issue in jira_project.jira_issues.values():
                for fix in jira_issue['fixVersions'].split(','):
                    if to_match in fix:
                        available_versions.add(fix)

        report_version = pick_value('Generate report for which FixVersion?',
                                    list(available_versions))
        if report_version is None:
            return

        print('Generating report on: {}'.format(report_version))

        # Now find all "primary root" members on this FixVersion, generate a list of matching, then display w/dependency
        # chains enabled
        matching_issues = set()
        for jira_project in target_connection.cached_projects:
            for jira_issue in jira_project.jira_issues.values():
                if jira_issue.has_fix_version(report_version):
                    if (open_only and jira_issue.is_open) or not open_only:
                        matching_issues.add(jira_issue)

        df = DisplayFilter.default()
        df.open_only = open_only
        df.include_column('fixVersions', 'FixVersion', 10, 2)

        # sort our keys by issuekey
        sorted_results = JiraUtils.sort_custom_jiraissues_by_key(
            list(matching_issues))
        del matching_issues

        issues = df.display_and_return_sorted_issues(self, sorted_results, 1,
                                                     None, True)
        while True:
            choice = get_input(
                '[#] to open an issue in browser, [p] to print report again, [q] to quit report: '
            )
            if choice == 'q':
                break
            elif choice == 'p':
                df.display_and_return_sorted_issues(self, sorted_results, 1,
                                                    None, True)
            try:
                int_choice = int(choice) - 1
                if int_choice < 0 or int_choice > len(issues) - 1:
                    raise ValueError('oops')
                chosen_issue = issues[int_choice]
                if not chosen_issue.is_cached:
                    print(
                        'Cannot open browser for non-cached issue (don\'t know url). Cache offline to inspect {}.'
                        .format(chosen_issue.issue_key))
                else:
                    jira_conn = self._jira_connections[
                        chosen_issue.jira_connection_name]
                    JiraUtils.open_issue_in_browser(jira_conn.url,
                                                    chosen_issue.issue_key)
            except ValueError:
                print('Bad input. Try again.')
 def sort_tickets(self):
     self.assigned = JiraUtils.sort_jira_issues(self.assigned)
     self.closed = JiraUtils.sort_jira_issues(self.closed)
     self.reviewer = JiraUtils.sort_jira_issues(self.reviewer)
     self.reviewed = JiraUtils.sort_jira_issues(self.reviewed)
Beispiel #11
0
    def _run_report(jira_manager, team, report_filter):
        # type: (JiraManager, Team, ReportFilter) -> None
        # We prompt for a new 'since' on each iteration of the loop
        if report_filter.needs_duration:
            report_filter.since = time_utils.since_now(
                ReportFilter.get_since())

        try:
            sorted_member_issues = sorted(
                team.members, key=lambda s: s.primary_name.user_name)

            while True:
                # Print out a menu of the meta information for each team member
                print_separator(40)
                print('[{}]'.format(report_filter.header))
                print(report_filter.column_headers())

                count = 1

                for member_issues in sorted_member_issues:
                    report_filter.clear()
                    # We perform pre-processing and one-off prompting for time duration in .process call
                    report_filter.process_issues(member_issues)
                    print('{:5}: {}'.format(
                        count,
                        report_filter.print_all_counts(
                            member_issues.primary_name.user_name)))
                    count += 1

                print_separator(40)
                cmd = get_input(
                    '[#] Integer value to see a detailed breakdown by category. [q] to return to menu:'
                )
                if cmd == 'q':
                    break

                # Received detailed breakdown input
                try:
                    c_input = int(cmd) - 1

                    # Pull out the MemberIssuesByStatus object for the chosen member for detailed printing
                    # We need to re-populate this report filter with this user for matching logic to work
                    full_member_issues = sorted_member_issues[c_input]
                    report_filter.clear()
                    report_filter.process_issues(full_member_issues)
                    displayed_issues = full_member_issues.display_member_issues(
                        jira_manager, report_filter)

                    while True:
                        cmd = get_input(
                            '[#] Integer value to open JIRA issue in browser. [q] to return to report results:'
                        )
                        if cmd == 'q':
                            break
                        try:
                            jira_issue = displayed_issues[int(cmd) - 1]
                            jira_connection = jira_manager.get_jira_connection(
                                jira_issue.jira_connection_name)
                            JiraUtils.open_issue_in_browser(
                                jira_connection.url, jira_issue.issue_key)
                        except ValueError as ve:
                            print('Bad input. Try again.')
                            print('ValueError : {}'.format(ve))
                            pause()
                except ValueError:
                    break
        except JIRAError as je:
            print(
                'Caught a JIRAError attempting to run a query: {}'.format(je))
            pause()