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 run_org_report(self, jira_manager: 'JiraManager') -> None: """ Sub-menu driven method to run a specific type of report across multiple teams within an organization """ org_name = None if len(self._organizations) == 0: # We don't prompt for addition now since we'd have to pass in main menu context to do that from here. print('No organizations found. Please use the Team Management menu to define a new organization before running a report.') pause() return while True: clear() if org_name is None: print_separator(40) org_name = pick_value('Run reports against which organization?', list(self._organizations.keys())) # None return from pick_team == cancel if org_name is None: return for team_name in sorted(self._organizations[org_name]): active_team = self._teams[team_name] print('Populating tickets for team: {}'.format(active_team.name)) TeamManager.populate_owned_jira_issues(jira_manager, active_team.members) print('---------------------') print('- Org Menu -') print('---------------------') print('t: Change active org. Current: {}'.format(org_name)) self._print_report_menu() print('q: Cancel') print('---------------------') choice = get_input(':') if choice == 'q': return elif choice == 't': org_name = None try: report_type = ReportType.from_int(int(choice)) if report_type == ReportType.UNKNOWN: print('Bad input: {}. Try again.'.format(choice)) pause() else: report_to_run = TeamManager.reports[report_type] if TeamManager.reports[report_type].needs_duration: report_to_run.since = time_utils.since_now(ReportFilter.get_since()) # making mypy happy assert org_name is not None self._run_org_report(jira_manager, org_name, report_to_run) pause() except (ValueError, TypeError) as e: print('Error on input: {}. Try again'.format(e)) traceback.print_exc() pause()
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 _pick_member_for_linkage_operation(self, action: str) -> Optional[MemberIssuesByStatus]: """ Prompts for both team to remove from and then member. Used on both addition and deletion paths. """ target_team_name = pick_value('{} a linked member on which team?'.format(action), list(self._teams.keys())) if target_team_name is None: return None target_team = self._teams[target_team_name] print_separator(40) print('Detailed status of team members:') for member in target_team.members: print(' {}'.format(member)) print_separator(40) target_member_name = pick_value('{} a linked JIRA user-name on which member?'.format(action), target_team.member_names) if target_member_name is None: return None return target_team.get_member_issues(target_member_name)
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 _resolve_issue_dependencies(self) -> None: """ Since JiraIssues contain str-based 'pointers' to other JiraIssues as dependents, we need to perform this evaluation in batch separately from a single issue or project caching addition. """ self.missing_project_counts = {} for jira_project in self.get_all_cached_jira_projects().values(): jira_project.resolve_dependencies(self) if len(self.missing_project_counts) > 0: print_separator(30) print( 'Encountered some missing offline cached JiraProjects during dependency resolution. Consider caching some of the following projects locally.' ) for project in sorted(self.missing_project_counts, key=self.missing_project_counts.get, reverse=True): print( 'Missing locally cached projects during dependency resolution. Project: {}. Count: {}' .format(project, self.missing_project_counts[project]))
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 edit_view(self, team_manager, jira_manager): # type: (TeamManager, JiraManager) -> None print('Current view contents: {}'.format(self)) while True: print_separator(40) print('- JiraView Menu: {}'.format(self.name)) print_separator(40) print('a: Add a filter on View') print('r: Remove a filter on a JiraView') print('t: Edit teams in View') print('d: Display issues matching this view.') print('q: Return to previous menu') print_separator(40) choice = get_input(':') if choice == 'q': return elif choice == 't': self.edit_team(team_manager) elif choice == 'a': self.add_filter() elif choice == 'r': self.remove_filter() elif choice == 'd': self.display_view(jira_manager)
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 _run_org_report(self, jira_manager: 'JiraManager', org_name: str, report_filter: ReportFilter) -> None: """ Spins within a menu to pull up details on individuals. """ while True: # Print out a menu of the meta information for this report print_separator(40) report_filter.print_description() print_separator(40) print('Report for org: {}'.format(org_name)) print('[{}]'.format(report_filter.header)) count = 1 # Store displayed order at top level, sorted on per-team basis meta_sorted_issues = [] for team_name in self._organizations[org_name]: print_separator(30) print('[Team: {}]'.format(team_name)) print(report_filter.column_headers()) team_members = self._teams[team_name].members sorted_members = sorted(team_members, key=lambda s: s.primary_name.user_name) meta_sorted_issues.extend(sorted_members) # Display in sorted order per team. for member_issues in sorted_members: 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 selection = get_input('[#] to open details for a team member, [q] to return to previous menu') if selection == 'q': break int_sel = as_int(selection) if int_sel is None: continue # 0 indexed on List int_sel -= 1 if int_sel > len(meta_sorted_issues) or int_sel < 0: print('Bad value.') continue tickets = meta_sorted_issues[int_sel] TeamManager._print_member_details(jira_manager, tickets, report_filter)
def _run_report(jira_manager: 'JiraManager', team: Team, report_filter: ReportFilter) -> None: # We prompt for a new 'since' on each iteration of the loop in non-org reporting if report_filter.needs_duration: report_filter.since = time_utils.since_now(ReportFilter.get_since()) report_filter.prompt_for_data() 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) report_filter.print_description() 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 selection = as_int(cmd) if selection is None: break selection -= 1 if selection < 0 or selection > len(sorted_member_issues): print('Bad Selection.') continue full_member_issues = sorted_member_issues[selection] TeamManager._print_member_details(jira_manager, full_member_issues, report_filter) except JIRAError as je: print('Caught a JIRAError attempting to run a query: {}'.format(je)) pause()
def run_debug(self) -> None: while True: print_separator(80) print('Debug menu:') print('t: print a specific ticket\'s data') print('l: list custom fields for a JiraProject') print( 'r: (run current transient) - test print width formatting stuff' ) print('q: quit back to main menu') print_separator(80) menu_choice = get_input(':') if menu_choice == 't': ticket_name = get_input( 'Print what ticket? Note: this will fail unless you\'ve cached this project locally:', lowered=False) project_name = JiraIssue.get_project_from_ticket(ticket_name) if project_name == '' or project_name is None: print( 'Failed to parse project name from ticket: {}. Try again.' .format(ticket_name)) continue jira_project = self.maybe_get_cached_jira_project_no_url( project_name) if jira_project is None: print( 'Could not find cached version of {}. Add via project menu and try again.' .format(project_name)) continue ticket = jira_project.get_issue(ticket_name) if ticket is None: print( 'Failed to get jira issue {} from project {}. Are you sure it is correct and/or cached?' .format(ticket_name, project_name)) continue if jira_project.jira_connection is not None: print('Ticket: {}'.format( ticket.pretty_print(jira_project.jira_connection))) elif menu_choice == 'r': print('TEST: [{:{width}.{width}}]'.format( 'I am testing a 5.5 thing', width=5)) elif menu_choice == 'l': jira_connection = self.pick_jira_connection( 'Show fields for project on which connection?') if jira_connection is None: print('Nothing selected. Continuing.') continue project = self.get_jira_connection( jira_connection.connection_name).pick_and_get_jira_project( ) if project is not None: print('Showing custom fields for project: {}'.format( project.project_name)) for key, value in project._custom_fields: print('Key: {}. Value: {}'.format(key, value)) elif menu_choice == 'q': break else: print('Bad choice. Try again.') pause()
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.')
train = [utils.untokenize_sentence(sentence) for sentence in train_set] dev = [utils.untokenize_sentence(sentence) for sentence in dev_set] print("word level tf-idf") tfidf_vect = TfidfVectorizer(analyzer='word', token_pattern=r'\w{1,}', max_features=5000) tfidf_vect.fit(train) return tfidf_vect.transform(train), tfidf_vect.transform(dev) if __name__ == '__main__': for S_DATASET in DATASET_ARRAY: utils.print_separator('DATASET: {}'.format(S_DATASET)) print('Fetching the data...') train_data, dev_data, test_data, label_dictionary = data_fetching.fetch_data( S_DATASET) if B_UPSAMPLING: print('Performing upsampling...') train_data = tweet_preprocessing.perform_upsampling(train_data) # PRE-PROCESSING print('Data preprocessing...') train_data['preprocessed'] = tweet_preprocessing.preprocess_data( train_data['content'], 'main') dev_data['preprocessed'] = tweet_preprocessing.preprocess_data( dev_data['content'], 'main')
def print_unknown_dependency_types() -> None: print_separator(30) print('Unknown JiraDependency types discovered:') print_separator(30) for unknown_type in sorted(JiraDependency.unknown_dependencies): print('{}'.format(unknown_type))
# for sentence in dataframe: # for word in sentence: # if dictionary.spell(word): # nothing_count.add(word) # else: # if word not in correction_count: # print('{} ----> {}'.format(word, dictionary.suggest(word))) # correction_count.add(word) # print() # print('palabras corregidas:{} palabras sin tocar:{}'.format(len(correction_count), len(nothing_count))) # return if __name__ == '__main__': for S_DATASET in DATASET_ARRAY: utils.print_separator('DATASET: {}'.format(S_DATASET)) print('Fetching the data...') train_data, dev_data, test_data, label_dictionary = data_fetching.fetch_data( S_DATASET) # PRE-PROCESSING print('Data preprocessing...') train_data['preprocessed'] = tweet_preprocessing.preprocess_data( train_data['content'], 'main') dev_data['preprocessed'] = tweet_preprocessing.preprocess_data( dev_data['content'], 'main') if B_TEST_PHASE is True: test_data['preprocessed'] = tweet_preprocessing.preprocess_data( test_data['content'], 'main')
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()
def list_teams(self) -> None: print_separator(40) print('Currently defined teams:') for team in list(self._teams.values()): print('{}'.format(team)) print_separator(40)
def get_issues(self, string_matches=None): # type: (List[str]) -> Dict[str, JiraIssue] """ Applies nested JiraFilters to all associated cached JiraProjects for the contained JiraConnection :param string_matches: substring(s) to match against JiraIssue fields for further refining of a search :return: {} of key -> JiraIssue that match JiraFilters and input regexes """ if string_matches is None: string_matches = [] source_issues = self.jira_connection.cached_jira_issues matching_issues = {} excluded_count = 0 for issue_list in source_issues: for jira_issue in issue_list: matched = False has_or = False matched_or = False if utils.debug: print_separator(30) argus_debug( 'Matching against JiraIssue with key: {key}, assignee: {assignee}, rev: {rev}, rev2: {rev2}, res: {res}' .format( key=jira_issue.issue_key, assignee=jira_issue['assignee'], rev=jira_issue.get_value(self.jira_connection, 'reviewer'), rev2=jira_issue.get_value(self.jira_connection, 'reviewer2'), res=jira_issue.get_value(self.jira_connection, 'resolution'))) for jira_filter in list(self._jira_filters.values()): argus_debug( 'Processing filter: {}'.format(jira_filter)) excluded = False argus_debug('Checking jira_filter match for issue: {}'.format( jira_issue.issue_key)) for jira_filter in list(self._jira_filters.values()): argus_debug('Processing filter: {}'.format(jira_filter)) # if we have an OR filter in the JiraFilter, we need to match at least one to be valid if jira_filter.query_type() == 'OR': has_or = True if not jira_issue.matches_any(self.jira_connection, string_matches): argus_debug( ' Skipping {}. Didn\'t match regexes: {}'.format( jira_filter.extract_value(jira_issue), ','.join(string_matches))) excluded_count += 1 break if jira_filter.includes_jira_issue(jira_issue): argus_debug(' Matched: {} with value: {}'.format( jira_filter, jira_filter.extract_value(jira_issue))) matched = True if jira_filter.query_type() == 'OR': matched_or = True elif jira_filter.excludes_jira_issue(jira_issue): argus_debug(' Excluded by: {} with value: {}'.format( jira_filter, jira_filter.extract_value(jira_issue))) matched = True excluded = True break # Didn't match and is required, we exclude this JiraIssue elif jira_filter.query_type() == 'AND': argus_debug( ' Didn\'t match: {} with value: {} and was AND. Excluding.' .format(jira_filter, jira_filter.extract_value(jira_issue))) excluded = True # Didn't match and was OR, don't flag anything else: argus_debug( ' Didn\'t match: {} with value and was OR. Doing nothing: {}' .format(jira_filter, jira_filter.extract_value(jira_issue))) # Cannot short-circuit on match since exclusion beats inclusion and we have to keep checking, but can # on exclusion bool if excluded: excluded_count += 1 break argus_debug(' key: {} matched: {}. excluded: {}'.format( jira_issue.issue_key, matched, excluded)) if not excluded: if has_or and not matched_or: argus_debug( ' has_or on filter, did not match on or field. Excluding.' ) elif matched: matching_issues[jira_issue.issue_key] = jira_issue print( 'Returning total of {} JiraIssues matching JiraView {}. Excluded count: {}' .format(len(list(matching_issues.keys())), self.name, excluded_count)) return matching_issues
def display_dashboard(self, jira_manager: 'JiraManager', jira_views: Dict[str, JiraView]) -> None: df = DisplayFilter.default() matching_issues = [] for jira_view in list(self._jira_views.values()): matching_issues.extend(list(jira_view.get_issues().values())) filters = {} # type: Dict[Column, str] while True: filtered_issues = df.display_and_return_sorted_issues( jira_manager, matching_issues, 1, filters) print_separator(60) prompt = 'Input [#] integer value to open ticket in browser, [f] to filter column by string, [c] to clear filters, [q] to quit' custom = get_input(prompt) if custom == 'q': return elif custom == 'f': column_name = pick_value( 'Filter against which column?', [column.name for column in df.included_columns], True) if column_name is None: continue to_match = get_input('Filter for what string?', False) # For now, we convert the string name to the Column object as we key by a mapping of Column to filter regex for matching # TODO: This should be changed to a Dict[str, List[ColumnFilter]] objects going forward and made consistent across all users # This will both tidy up this abstraction but also allow matching against multiple regexes per Column rather than the current one, # as well as enforce the 1:many relationship we're going for on filtering instead of the suboptimal many:1 our # data structures currently give us. column_list = [ col for col in df.included_columns if col.name == column_name ] assert len( column_list ) == 1, 'Expected only 1 match with column name {}, got {}'.format( column_name, len(column_list)) filters[column_list[0]] = to_match elif custom == 'c': filters = {} elif custom.isdigit(): intval = int(custom) - 1 issue = filtered_issues[intval] # As we cache JiraProject data on a JiraConnection basis, we need to reach into the JiraView, to their # contained JiraConnections, and check for presence of the owning JiraProject for this issuekey # in order to determine our base url to open a browser to this issue. I'm not in love with this. base_url = 'unknown' for jira_view in list(jira_views.values()): jira_connection = jira_view.jira_connection for jira_project in jira_connection.cached_projects: if jira_project.owns_issue(issue): base_url = jira_connection.url if base_url == 'unknown': print( 'Failed to find JiraConnection for issuekey: {}. Something went wrong.' .format(issue.issue_key)) else: issue_url = '{}browse/{}'.format(base_url, issue) try: Popen([browser(), issue_url]) print('Opened {}. Press enter to continue.'.format( issue_url)) pause() except OSError as oe: print( 'Failed to open browser [{}]. Probably need to configure your environment or update from main menu. Exception: {}' .format(browser(), oe)) else: print('Oops... Unrecognized input. Please try again.') pause()