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()
def __init__(self, name: str, jira_connection: JiraConnection) -> None: self.name = name self.jira_connection = jira_connection # Collection of filters, keyed by the name of the field they filter on self._jira_filters = {} # type: Dict[str, JiraFilter] self._teams = {} # type: Dict[str, Team] self.display_filter = DisplayFilter()
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
def __init__(self, name, jira_connection): # type: (str, JiraConnection) -> None self.name = name self.jira_connection = jira_connection # Collection of filters, keyed by the name of the field they filter on self._jira_filters = {} # type: Dict[str, JiraFilter] self._teams = {} # type: Dict[str, Team] # TODO: Allow / support customization of display filter on per-view basis in Edit View dialog self.display_filter = DisplayFilter()
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
def run_debug(self): """ Used during development to bypass complex menu operations and try out a single new operation outside unit testing """ print_separator(60) print('Resolving deps') self._resolve_issue_dependencies() default_filter = DisplayFilter.default() default_filter.open_only = True utils.show_dependencies = True utils.show_only_open_dependencies = True for jira_connection in self.jira_connections(): if jira_connection.connection_name == 'ds': print_separator(30) print('Results for connection: {}'.format(jira_connection)) for issue_list in jira_connection.cached_jira_issues: default_filter.display_and_return_sorted_issues( self, issue_list, 1, None) for dep_type in sorted(JiraDependency.unknown_dependencies): print('Found unknown dependency: {}'.format(dep_type)) pause()
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
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 __init__(self, team_manager): """ Recreates any JiraConnections and JiraViews based on saved data in conf/jira.cfg """ # Holds connected Jira objects to be queried by JiraViews self._jira_connections = {} # type: Dict[str, JiraConnection] # JiraViews, caching filters for different ways to view Jira Data. Implicit 1:1 JiraConnection to JiraView self.jira_views = {} # type: Dict[str, JiraView] self.jira_dashboards = {} # type: Dict[str, JiraDashboard] # Used during JiraDependency resolution to notify user of missing JiraProjects self.missing_project_counts = {} # type: Dict[str, int] self._display_filter = DisplayFilter.default() if os.path.exists(jira_conf_file): config_parser = configparser.RawConfigParser() config_parser.read(jira_conf_file) connection_names = [] if config_parser.has_section( 'JiraManager') and config_parser.has_option( 'JiraManager', 'Connections'): connection_names = config_parser.get('JiraManager', 'Connections').split(',') # JiraConnections are the root of our container hierarchy for connection_name in connection_names: if connection_name == '': pass try: jira_connection = JiraConnection.from_file(connection_name) # If we had an error on init we obviously cannot add this if jira_connection is None: continue self._jira_connections[ jira_connection.connection_name] = jira_connection except ConfigError as ce: print('ConfigError with project {}: {}'.format( connection_name, ce)) # Construct JiraViews so they can be used during JiraDashboard creation. view_names = [] if config_parser.has_option('JiraManager', 'Views'): view_names = config_parser.get('JiraManager', 'Views').split(',') for name in view_names: try: jv = JiraView.from_file(self, name, team_manager) self.jira_views[jv.name] = jv except ConfigError as ce: print('ConfigError with jira view {}: {}'.format(name, ce)) if config_parser.has_section('Dashboards'): for dash in config_parser.options('Dashboards'): dash_views = {} for view in view_names: if view not in self.jira_views: print( 'Found dashboard {} with invalid view: {}. Skipping init: manually remove from config.' .format(dash, view)) break dash_views[view] = self.jira_views[view] self.jira_dashboards[dash] = JiraDashboard( dash, dash_views) if len(self._jira_connections) == 0: print_separator(30) print( 'No JIRA Connections found. Prompting to add first connection.' ) self.add_connection() # Initialize JiraProjects from locally cached files for file_name in os.listdir(jira_project_dir): full_path = os.path.join(jira_project_dir, file_name) print( 'Processing locally cached JiraProject: {}'.format(full_path)) # Init based on matching the name of this connection and .cfg print_separator(30) try: new_jira_project = JiraProject.from_file(full_path, self) if new_jira_project is None: print('Error initializing from {}. Skipping'.format( full_path)) break if new_jira_project.jira_connection is None: add = get_input( 'Did not find JiraConnection for JiraProject: {}. Would you like to add one now? (y/n)' ) if add == 'y': new_jira_connection = self.add_connection( 'Name the connection (reference url: {}):'.format( new_jira_project.url)) new_jira_connection.save_config() new_jira_project.jira_connection = new_jira_connection else: print( 'Did not add JiraConnection, so cannot link and use JiraProject.' ) continue print('Updating with new data from JIRA instance') new_jira_project.refresh() new_jira_project.jira_connection.add_and_link_jira_project( new_jira_project) except (configparser.NoSectionError, ConfigError) as e: print( 'WARNING! Encountered error initializing JiraProject from file {}: {}' .format(full_path, e)) print( 'This JiraProject will not be initialized. Remove it manually from disk in conf/jira/projects and data/jira/' ) if os.path.exists('conf/custom_params.cfg'): config_parser = configparser.RawConfigParser() config_parser.read('conf/custom_params.cfg') custom_projects = config_parser.get('CUSTOM_PROJECTS', 'project_names').split(',') for project_name in custom_projects: argus_debug( 'Processing immutable config for custom project: {}'. format(project_name)) # Find the JiraConnection w/matching URL, if any url = config_parser.get(project_name, 'url').rstrip('/') jira_project = self.maybe_get_cached_jira_project( url, project_name) if jira_project is not None: # Don't need to cache since already done on ctor for JiraProject argus_debug('Project already initialized. Skipping.') continue # Didn't find the JiraProject, so we need to build one, cache, and link. custom_fields = {} field_names = config_parser.get(project_name, 'custom_fields').split(',') for field in field_names: custom_fields[field] = config_parser.get( project_name, field) parent_jira_connection = None for jira_connection in list(self._jira_connections.values()): if jira_connection.url == url: parent_jira_connection = jira_connection break # Create a JiraConnection for this JiraProject if we do not yet have one if parent_jira_connection is None: print( 'WARNING! Did not find JiraConnection for project: {}, attempting to match url: {}' .format(project_name, url)) print('Known JiraConnections and their urls:') for jira_connection in list( self._jira_connections.values()): print(' {}: {}'.format( jira_connection.connection_name, jira_connection.url)) if is_yes('Would you like to add one now?'): parent_jira_connection = self.add_connection( 'Name the connection (reference url: {}):'.format( url)) else: print( 'JiraProject data and config will not be added nor cached. Either add it manually or restart Argus and reply y' ) break new_jira_project = JiraProject(parent_jira_connection, project_name, url, custom_fields) new_jira_project.refresh() parent_jira_connection.add_and_link_jira_project( new_jira_project) print('Resolving dependencies between JiraIssues') self._resolve_issue_dependencies() print('JiraManager initialization complete.')
def __init__(self): parser = optparse.OptionParser( description=DESCRIPTION, usage='Usage: %prog [options] [host [port]]', version='argus ' + __version__) parser.add_option( '-p', '--password', help= 'provide local password on command-line rather than being prompted' ) parser.add_option('-d', '--dashboard', help='name of dashboard to auto-execute into') parser.add_option( '-j', '--jenkins_report', help= 'TODO:#106 execute and print a jenkins report, exiting upon completion', default=False, action='store_true') parser.add_option( '-n', '--jenkins_project_name', help='Name of consistent root of project names in Jenkins') parser.add_option( '-b', '--jenkins_branch', help='TODO:#107 Used with -j, specify branch to run reports against' ) parser.add_option( '-t', '--jenkins_type', help= 'TODO:#108 Used with -j, specify type of test [u]nit test, or [d]test to report against' ) # parser.add_option('-c', '--triage_csv', help='Specifies local file containing [link, key, summary, assignee, reviewer, status, prio, repro, scope, component] triage file to update against live JIRA data') # parser.add_option('-o', '--triage_out', help='Output file name for updated triage data. If not provided, prints to stdout.') parser.add_option( '-u', '--unit_test', help= 'Unit testing mode, does not connect servers, saves config changes to test/ folder', action='store_true', dest='unit_test') parser.add_option( '-v', '--verbose', help='Log verbose debug output to console and argus.log', action='store_true', dest='verbose') optvalues = optparse.Values() (options, arguments) = parser.parse_args(sys.argv[1:], values=optvalues) signal.signal(signal.SIGINT, self.signal_handler) if hasattr(options, 'verbose'): utils.debug = True utils.argus_log = open('argus.log', 'w') Config.init_argus() # determine if this is a first run, prompt differently pending that msg = None if hasattr(options, 'password'): Config.MenuPass = options.password else: msg = 'Enter Argus Password (local JIRA credentials will be encrypted with this):' while Config.MenuPass == '': Config.MenuPass = getpass(msg) if hasattr(options, 'unit_test'): if os.path.exists('test'): shutil.rmtree('test') os.mkdir('test') os.mkdir(os.path.join('test', 'conf')) os.mkdir(os.path.join('test', 'data')) utils.unit_test = True # Run one-off test on time utils # now = time_converter.current_time() # print('Now is: {}'.format(now)) # # four_weeks_ago = time_converter.since_now('-4w') # print('Four weeks ago is: {}'.format(four_weeks_ago)) # # one_m_two_days_ago = time_converter.since_now('-1m -2d') # print('One M 2 D ago is: {}'.format(one_m_two_days_ago)) # exit(-1) try: self._team_manager = TeamManager.from_file() except ConfigError as ce: print('ConfigError: {}. Initializing empty JiraManager'.format(ce)) self._team_manager = TeamManager() self._jira_manager = JiraManager(self._team_manager) self._jenkins_manager = JenkinsManager(self) if hasattr(options, 'triage_csv'): jira_connections = {} for jira_connection in self._jira_manager.jira_connections(): jira_connections[ jira_connection.connection_name] = jira_connection tu = TriageUpdate( jira_connections, self._jira_manager.get_all_cached_jira_projects()) triage_out = options.triage_out if hasattr(options, 'triage_out') else None tu.process(options.triage_csv, triage_out) if hasattr(options, 'dashboard'): user_key = optvalues.__dict__['dashboard'] dash_keys = list(self._jira_manager.jira_dashboards.keys()) if user_key in dash_keys: self._jira_manager.jira_dashboards[user_key].display_dashboard( self._jira_manager.jira_views) else: print('Oops... Error with dashboard name {}'.format(user_key)) print('Possible dashboard names : {}'.format( ','.join(dash_keys))) print('Starting Argus normally...') if hasattr(options, 'verbose'): utils.debug = True utils.argus_log = open('argus.log', 'w') self._display_filter = DisplayFilter() self.main_menu = [ MenuOption('d', 'Dashboards', self.go_to_dashboards_menu, pause=False), MenuOption('v', 'Jira Views', self.go_to_jira_views_menu, pause=False), MenuOption('p', 'JiraProject Queries', self.go_to_projects_menu, pause=False), MenuOption.print_blank_line(), MenuOption('t', 'Run a Team-Based Report', self._run_team_report, pause=False), MenuOption('e', 'View Escalations', self._jira_manager.display_escalations, pause=False), MenuOption.print_blank_line(), MenuOption('r', 'Generate a Pre-Determined Report', self.go_to_reports_menu, pause=False), MenuOption('m', 'Team Management', self.go_to_teams_menu, pause=False), MenuOption('c', 'Jira Connections', self.go_to_jira_connections_menu, pause=False), MenuOption.print_blank_line(), MenuOption('j', 'Jenkins Menu', self.go_to_jenkins_menu, pause=False), MenuOption.print_blank_line(), MenuOption('o', 'Change Options', self.go_to_options_menu, pause=False), MenuOption('x', 'Debug', self._jira_manager.run_debug, pause=False), MenuOption.print_blank_line(), MenuOption('h', 'Help', self._display_readme, pause=False), MenuOption.quit_program() ] self.dashboards_menu = [ MenuOption('l', 'List all available dashboards', self._jira_manager.list_dashboards), MenuOption('d', 'Display a dashboard\'s results', self._jira_manager.display_dashboard), MenuOption('c', 'Create a dashboard', self._jira_manager.add_dashboard), MenuOption('e', 'Edit a dashboard', self._jira_manager.edit_dashboard), MenuOption('r', 'Remove a dashboard', self._jira_manager.remove_dashboard), MenuOption.print_blank_line(), MenuOption.return_to_previous_menu(self.go_to_main_menu) ] self.jira_views_menu = [ MenuOption('l', 'List all defined JiraViews', self._jira_manager.list_all_jira_views), MenuOption('d', 'Display a JiraView\'s results', self._jira_manager.display_view), MenuOption('a', 'Add a JiraView', self._add_view), MenuOption('e', 'Edit a JiraView', self._edit_view), MenuOption('r', 'Remove a JiraView', self._jira_manager.remove_view), MenuOption.print_blank_line(), MenuOption.return_to_previous_menu(self.go_to_main_menu) ] self.reports_menu = [ MenuOption( 'f', 'FixVersion report (release). Query all tickets with a specified FixVersion', self._jira_manager.report_fix_version), MenuOption('s', 'Add a single-user multi-JIRA open ticket dashboard', self._add_multi_jira_dashboard), MenuOption('l', 'Add a label-based cross-cutting view', self._jira_manager.add_label_view), MenuOption.print_blank_line(), MenuOption.return_to_previous_menu(self.go_to_main_menu) ] self.team_menu = [ MenuOption('l', 'List all defined Teams', self._team_manager.list_teams), MenuOption('a', 'Add a new team', self._add_team), MenuOption('e', 'Edit an existing team', self._edit_team), MenuOption('r', 'Remove a team', self._remove_team), MenuOption( 'x', 'Link a team member to two accounts across JiraConnections', self.add_linked_member), MenuOption('d', 'Delete a cross-Jira link', self._team_manager.remove_linked_member), MenuOption.print_blank_line(), MenuOption.return_to_previous_menu(self.go_to_main_menu) ] self.jira_connections_menu = [ MenuOption('a', 'Add a JIRA connection', self._jira_manager.add_connection), MenuOption('r', 'Remove a JIRA connection and all related views', self._jira_manager.remove_connection), MenuOption( 'c', 'Cache offline ticket data for a JiraProject on a connection', self._jira_manager.cache_new_jira_project_data), MenuOption( 'd', 'Delete offline cached ticket data for a JiraProject on a connection', self._jira_manager.delete_cached_jira_project), MenuOption('l', 'List all configured Jiraconnections', self._jira_manager.list_jira_connections), MenuOption.print_blank_line(), MenuOption.return_to_previous_menu(self.go_to_main_menu) ] self.jenkins_menu = [ MenuOption('r', 'Reports Manager', self.go_to_jenkins_reports_manager_menu, pause=False), MenuOption('c', 'Connections Manager', self.go_to_jenkins_connections_manager_menu, pause=False), MenuOption.print_blank_line(), MenuOption.return_to_previous_menu(self.go_to_main_menu) ] self.jenkins_reports_manager_menu = [ MenuOption('o', 'Open custom report', self._jenkins_manager.select_active_report, pause=False), MenuOption('a', 'Add a custom report', self._jenkins_manager.add_custom_report, pause=False), MenuOption('r', 'Remove a custom report', self._jenkins_manager.remove_custom_report, pause=False), MenuOption('l', 'List custom reports', self._jenkins_manager.list_custom_reports), MenuOption.print_blank_line(), MenuOption.return_to_previous_menu(self.go_to_jenkins_menu) ] self.jenkins_report_menu = [ MenuOption('v', 'View report', self._jenkins_manager.view_custom_report), MenuOption('a', 'Add a job', self._jenkins_manager.add_custom_report_job, pause=False), MenuOption('r', 'Remove a job', self._jenkins_manager.remove_custom_report_job, pause=False), MenuOption.print_blank_line(), MenuOption.return_to_previous_menu( self.go_to_jenkins_reports_manager_menu) ] self.jenkins_connections_manager_menu = [ MenuOption('o', 'Open connection', self._jenkins_manager.select_active_connection, pause=False), MenuOption('a', 'Add a connection', self._jenkins_manager.add_connection, pause=False), MenuOption('r', 'Remove a connection', self._jenkins_manager.remove_connection, pause=False), MenuOption('l', 'List connections', self._jenkins_manager.list_connections), MenuOption.print_blank_line(), MenuOption.return_to_previous_menu(self.go_to_jenkins_menu) ] self.jenkins_connection_menu = [ MenuOption('v', 'View cached jobs', self._jenkins_manager.view_cached_jobs, pause=False), MenuOption('d', 'Download jobs to cache', self._jenkins_manager.download_jobs, pause=False), MenuOption.print_blank_line(), MenuOption('l', 'List saved views', self._jenkins_manager.list_views), MenuOption('a', 'Add a view', self._jenkins_manager.add_view, pause=False), MenuOption('r', 'Remove a view', self._jenkins_manager.remove_view, pause=False), MenuOption.print_blank_line(), MenuOption.return_to_previous_menu( self.go_to_jenkins_connections_manager_menu) ] self.options_menu = [ MenuOption('p', 'Change Argus password', self._change_password), MenuOption('b', 'Change browser', self._change_browser), MenuOption('v', 'Toggle Verbose/Debug', self._change_debug), MenuOption('d', 'Toggle Display dependencies', self._change_show_dependencies), MenuOption('o', 'Toggle show open dependencies only', self._change_dependency_type), MenuOption.print_blank_line(), MenuOption.return_to_previous_menu(self.go_to_main_menu) ] self.projects_menu = [ MenuOption('l', 'List locally cached projects', self._jira_manager.list_projects, pause=True), MenuOption('s', 'Search locally cached JiraIssues for a string', self._jira_manager.search_projects, pause=False), MenuOption('a', 'Add new JiraProject offline cache', self._jira_manager.cache_new_jira_project_data, pause=True), MenuOption( 'd', 'Delete offline cached ticket data for a JiraProject on a connection', self._jira_manager.delete_cached_jira_project), MenuOption('u', 'Update all locally cached project JIRA data', self._jira_manager.update_cached_jira_project_data, pause=False), MenuOption.print_blank_line(), MenuOption.return_to_previous_menu(self.go_to_main_menu) ] self.active_menu = None self.menu_header = None self.go_to_main_menu() self._load_config() # let user read startup info pause()
def display_member_issues(self, jira_manager, report_filter): # type: (JiraManager, ReportFilter) -> List[JiraIssue] """ Prints details for tickets by category. This method is always executed in the context of having a relevant ReportFilter in use for the display. Can use a no-op all-inclusive ReportFilter if you want to report all issues for this MemberIssuesByStatus. :param: jira_manager: Needed for display of 'pretty names' of custom columns by DisplayFilter :param: report_filter: Used to determine which issues to display :return: Sorted list of keys printed in this report """ print('[Detailed report for {}]'.format(self.primary_name)) # TODO: Allow configuration of format for DisplayFilter df = DisplayFilter.team_details() idx = 1 issues_displayed = [] # Use a scratch array so we don't print a summary for something we don't have details for scratch = [x for x in self.assigned if report_filter.contains_issue(x)] if len(scratch) > 0: print('\n[ASSIGNED]') sorted_issues = df.display_and_return_sorted_issues(jira_manager, scratch, idx) idx += len(sorted_issues) for jira_issue in sorted_issues: issues_displayed.append(jira_issue) scratch = [x for x in self.reviewer if report_filter.contains_issue(x)] if len(scratch) > 0: print('\n[REVIEWER]') sorted_issues = df.display_and_return_sorted_issues(jira_manager, scratch, idx) idx += len(sorted_issues) for jira_issue in sorted_issues: issues_displayed.append(jira_issue) closed_test = [] closed_non_test = [] for jira_issue in [x for x in self.closed if report_filter.contains_issue(x)]: # Note: designation of tickets as being 'test' related is via a label, not a component or issuetype if jira_issue.matches_label('test', False): closed_test.append(jira_issue) issues_displayed.append(jira_issue) else: closed_non_test.append(jira_issue) issues_displayed.append(jira_issue) if len(closed_test) > 0: print('\n[CLOSED TEST]') printed = df.display_and_return_sorted_issues(jira_manager, closed_test, idx) idx += len(printed) if len(closed_non_test) > 0: print('\n[CLOSED NON-TEST]') printed = df.display_and_return_sorted_issues(jira_manager, closed_non_test, idx) idx += len(printed) scratch = [x for x in self.reviewed if report_filter.contains_issue(x)] if len(scratch) > 0: print('\n[REVIEWED]') printed = df.display_and_return_sorted_issues(jira_manager, scratch, idx) idx += len(printed) for jira_issue in printed: issues_displayed.append(jira_issue) return issues_displayed