Exemplo n.º 1
0
    def add_view(self):
        view_name = pick_value('Which Jenkins view would you like to save?',
                               self.active_connection.get_list_of_views())
        if view_name:
            if view_name == 'Dev':
                dev_view_name = pick_value(
                    'Which Jenkins dev view would you like to save?',
                    self.active_connection.get_list_of_views(view_name))
                if dev_view_name:
                    dev_view_name = 'Dev-{}'.format(dev_view_name)
                    self.active_connection.jenkins_views[
                        dev_view_name] = self.active_connection.get_view(
                            dev_view_name)
                    self.active_connection.save_connection_config()
                    view_name = dev_view_name
            else:
                self.active_connection.jenkins_views[
                    view_name] = self.active_connection.get_view(view_name)
                self.active_connection.save_connection_config()
            print('Successfully added view: {}'.format(view_name))
            pause()

            if is_yes('Would you like to download jobs for this view now?'):
                self.active_connection.download_jobs(view_name)
                self.active_connection.save_job_data()
                print('Successfully downloaded jobs for view: {}'.format(
                    view_name))
                pause()
Exemplo n.º 2
0
    def add_custom_report_job(self):
        if self.connection_names:
            connection_name = pick_value(
                'Which Jenkins Connection would you like to add jobs from?',
                self.connection_names)
            if connection_name:
                connection = self.jenkins_connections[connection_name]
                if connection_name in self.active_report.connection_names:
                    job_options = [
                        job_name for job_name in connection.job_names
                        if job_name not in
                        self.active_report.connection_dict[connection_name]
                    ]
                else:
                    job_options = connection.job_names

                while True:
                    job_name = pick_value(
                        'Which Jenkins job would you like to add?',
                        job_options)
                    if job_name:
                        self.active_report.add_job_to_report(
                            job_name, connection_name)
                        self.active_report.save_report_config()
                        print('Successfully added job: {}'.format(job_name))
                        job_options.remove(job_name)
                    else:
                        break
        else:
            if is_yes(
                    'No Jenkins connections to add jobs from. Would you like to add one now?'
            ):
                self.active_connection = self.add_connection()
                self._main_menu.go_to_jenkins_connection_menu()
Exemplo n.º 3
0
    def download_jobs(self):
        download_method = pick_value(
            'Would you like to download jobs by view or individually?',
            ['By View', 'Individually'],
            sort=False)
        if download_method:
            if download_method == 'By View':
                if self.active_connection.jenkins_views:
                    view_options = self.active_connection.view_names
                    all_views = '* All Views'
                    view_options.append(all_views)
                    view_name = pick_value(
                        'Which saved view would you like to download jobs for?',
                        view_options)
                    if view_name:
                        if view_name == all_views:
                            self.active_connection.download_jobs()
                            self.active_connection.save_job_data()
                            print(
                                'Successfully downloaded jobs for all views.')
                            pause()
                        else:
                            self.active_connection.download_jobs(view_name)
                            self.active_connection.save_job_data()
                            print('Successfully downloaded jobs for view: {}'.
                                  format(view_name))
                            pause()
                else:
                    if is_yes(
                            'No Jenkins views. Would you like to add one now?'
                    ):
                        self.add_view()
                        view_name = self.active_connection.view_names[0]
                        if is_yes('Download jobs for this view?'):
                            self.active_connection.download_jobs(view_name)
                            self.active_connection.save_job_data()
                            print('Successfully downloaded jobs for view: {}'.
                                  format(view_name))
                            pause()

            elif download_method == 'Individually':
                job_name = get_input(
                    'Enter the exact, case-sensitive name of the job, or enter nothing to exit.\n>',
                    lowered=False)
                if job_name:
                    if self.active_connection.download_single_job(job_name):
                        self.active_connection.save_job_data()
                        print('Successfully downloaded Jenkins job: {}'.format(
                            job_name))
                        pause()
                    else:
                        print('Failed to download Jenkins job: {}'.format(
                            job_name))
                        pause()
Exemplo n.º 4
0
 def remove_filter(self) -> None:
     print('Removing from JiraFilter: {}'.format(self))
     action = get_input('Remove [i]nclude, [e]xclude, or [q]uit')
     if action == 'i':
         to_remove = pick_value('Remove which include?', self._includes)
         if to_remove is None:
             return
         self._includes.remove(to_remove)
     elif action == 'e':
         to_remove = pick_value('Remove which exclude?', self._excludes)
         if to_remove is None:
             return
         self._excludes.remove(to_remove)
Exemplo n.º 5
0
    def edit_team(self, jira_manager, team_name=None):
        # type: (JiraManager, str) -> None
        if team_name is None:
            team_name = pick_value('Edit which team?',
                                   list(self._teams.keys()), True, 'Cancel')
            if team_name is None:
                return None

        team = self._teams[team_name]
        jira_connection = jira_manager.get_jira_connection(
            team.jira_connection_name)

        while True:
            clear()
            print('-------------------------')
            print('[Edit {}]'.format(team))
            print('-------------------------')
            cmd = get_input(
                '[A]dd more members, [R]emove a member, or [Q]uit?')
            if cmd == 'a':
                assignees = jira_connection.pick_assignees(sys.maxsize)
                if assignees is None or len(assignees) == 0:
                    print('No assignees chosen. Returning.')
                    return None
                for assignee in assignees:
                    if assignee in team.member_names:
                        print(
                            'Assignee already exists in {}. Skipping.'.format(
                                team.name))
                        continue
                    else:
                        team.add_member(assignee, jira_connection)
                        print('Added {} to {}.'.format(assignee, team.name))
                        self._save_config()
            elif cmd == 'r':
                assignee = pick_value('Remove which assignee?',
                                      team.member_names, True, 'Cancel')
                if assignee is None:
                    continue
                confirm = get_input('Delete {} from {}: Are you sure?'.format(
                    assignee, team.name))
                if confirm == 'y':
                    team.delete_member(assignee)
            elif cmd == 'q':
                break
            else:
                print('Bad input. Valid input: A, R, or Q.')
                pause()
        self._save_config()
Exemplo n.º 6
0
    def edit_team(self, team_manager):
        if len(self._teams) > 0:
            print('Currently contained teams:')
            for t in list(self._teams.keys()):
                team = self._teams[t]
                print('   Name: {}'.format(team.name))
                print('      Assignees: {}'.format(','.join(team.members)))

        cmd = get_input('[A]dd a team, [R]emove a team, or [Q]uit?')
        if cmd == 'q':
            return
        elif cmd == 'a':
            if 'assignee' in self._jira_filters or 'reviewer' in self._jira_filters or 'reviewer2' in self._jira_filters:
                conf = get_input(
                    'Adding a team will remove all active assignee or reviewer filters. Are you sure?'
                )
                if conf == 'n':
                    return
                del self._jira_filters['assignee']
                del self._jira_filters['reviewer']
                del self._jira_filters['reviewer2']
            to_add = team_manager.pick_team()
            if to_add is None:
                return
            self._teams[to_add.name] = to_add
        elif cmd == 'r':
            tr = pick_value('Remove which team?', list(self._teams.keys()),
                            True, 'Cancel')
            if tr is None:
                return
            conf = get_input('About to delete {}. Are you sure?'.format(tr))
            if conf == 'y':
                del self._teams[tr]
Exemplo n.º 7
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()
Exemplo n.º 8
0
 def pick_team(self):
     # type: () -> Optional[Team]
     team_name = pick_value('Select a team', list(self._teams.keys()), True,
                            'Cancel')
     if team_name is None:
         return None
     return self._teams[team_name]
Exemplo n.º 9
0
 def add_label_view(self):
     name = get_input('Name this view: ')
     jira_connection_name = pick_value(
         'Which JIRA Connection does this belong to? ',
         list(self._jira_connections.keys()))
     jira_connection = self._jira_connections[jira_connection_name]
     new_view = JiraView(name, jira_connection)
     self.jira_views[name] = new_view
     jira_filter = JiraFilter('labels', jira_connection)
     while True:
         label = get_input('Add which label? ([q] to quit)')
         if label == 'q':
             break
         if label.isspace() or label == '':
             continue
         print('Adding label: [{}]'.format(label))
         jira_filter.include(label)
     res_jf = JiraFilter('Resolution', jira_connection)
     res_jf.include('unresolved')
     new_view.add_raw_filter(jira_filter)
     new_view.add_raw_filter(res_jf)
     self._save_config()
     new_view.display_view(self)
     print('Creating new view with label(s): {}'.format(','.join(
         jira_filter._includes)))
Exemplo n.º 10
0
    def remove_view(self):
        if len(self.jira_views) == 0:
            print('No views to remove.')
            return
        to_remove = pick_value('Select a view to delete or [q]uit: ',
                               list(self.jira_views.keys()))
        if to_remove is None:
            return

        # Build list of Dashboards this is going to invalidate to confirm
        affected_dashes = []
        for dash in list(self.jira_dashboards.values()):
            if dash.contains_jira_view(to_remove):
                print(
                    'WARNING: Removing this view will also remove JiraDashboard: {}.'
                    .format(dash))
                affected_dashes.append(dash.name)

        if is_yes('Are you sure you want to delete {}?'.format(to_remove)):
            self.jira_views[to_remove].delete_config()
            del self.jira_views[to_remove]

            # Determine if any dashboards exist w/this view and delete them
            for dash_name in affected_dashes:
                del self.jira_dashboards[dash_name]

            self._save_config()
Exemplo n.º 11
0
    def remove_custom_report_job(self):
        if self.active_report.job_names:
            job_options = self.active_report.job_names

            while True:
                job_name = pick_value(
                    'Which Jenkins job would you like to remove?', job_options)
                if job_name:
                    for connection_name, job_name_list in self.active_report.connection_dict.iteritems(
                    ):
                        if job_name in job_name_list:
                            self.active_report.remove_job_from_report(
                                job_name, connection_name)
                    for connection_name in self.active_report.connection_names:
                        if not self.active_report.connection_dict[
                                connection_name]:
                            self.active_report.connection_dict.pop(
                                connection_name)
                    self.active_report.save_report_config()
                    print('Successfully removed job: {}'.format(job_name))
                    job_options.remove(job_name)
                else:
                    break
        else:
            print('No Jenkins jobs to remove from report.')
            pause()
Exemplo n.º 12
0
 def display_view(self):
     view_name = pick_value('Which view?', list(self.jira_views.keys()),
                            True, 'Back')
     if view_name is None:
         return
     self.jira_views[view_name].display_view(self)
     self._save_config()
Exemplo n.º 13
0
 def view_cached_jobs(self):
     if self.active_connection.job_names:
         view_options = sorted(self.active_connection.view_names)
         all_jobs = '* All Jobs'
         view_options.append(all_jobs)
         view_name = pick_value('Which jobs would you like to view?',
                                view_options)
         if view_name:
             if view_name == all_jobs:
                 self.print_job_options(self.active_connection.jobs,
                                        connection=True)
             else:
                 jobs_to_print = []
                 job_names = self.active_connection.jenkins_views[
                     view_name].job_names
                 if job_names:
                     for job_name in job_names:
                         jobs_to_print.append(
                             self.active_connection.jenkins_jobs[job_name])
                     self.print_job_options(jobs_to_print, connection=True)
                 else:
                     print('No jobs to print in this view.')
     else:
         if is_yes(
                 'There are no cached jobs for the current connection. Would you like to download jobs now?'
         ):
             self.download_jobs()
Exemplo n.º 14
0
    def add_filter(self):
        filter_value = None
        # Adding to prevent PEP complaint.
        filter_name = None
        while filter_value is None:
            filters = JiraView.PRE_FILTERS[:]
            filters.append('Remove a filter')
            filters.append('Other')
            filter_name = pick_value('Select a field to filter on:', filters,
                                     True, 'Cancel view edit')
            if filter_name is None:
                return

            # Special logic to handle things we have known values for
            if filter_name in self._known_fields:
                filter_value = pick_value('Select {}'.format(filter_name),
                                          self._known_fields[filter_name])
            # since potential assignees vary by project, we don't store them in _known_fields
            elif filter_name == 'assignee' or filter_name == 'reviewer' or filter_name == 'reviewer2' or filter_name == 'reporter':
                # Disallow addition of assignee/reviewer/reviewer2 if a team filter is active
                if len(self._teams) > 0:
                    if filter_name != 'reporter':
                        print(
                            'Cannot add a[n] {} filter when a team filter is active. Remove team filter if you would like to add this.'
                            .format(filter_name))
                        return
                filter_value = self.jira_connection.pick_single_assignee()
                if filter_value is None:
                    return
            elif filter_name == 'Project':
                filter_value = self.jira_connection.pick_project()
                if filter_value is None:
                    return
            elif filter_name == 'Remove a filter':
                self.remove_filter()
                return
            else:
                filter_value = get_input('{}:'.format(filter_name))

        while True:
            filter_type = get_input('[i]nclude or [e]xclude?')
            if not filter_type == 'i' and not filter_type == 'e':
                print('Try again.')
            else:
                break

        self.add_single_filter(filter_name, filter_value, filter_type, 'AND')
Exemplo n.º 15
0
 def edit_dashboard(self):
     dn = pick_value('Which dashboard?', list(self.jira_dashboards.keys()),
                     True, 'Cancel')
     if dn is None:
         return
     dash = self.jira_dashboards[dn]
     dash.edit_dashboard(self.jira_views)
     self._save_config()
Exemplo n.º 16
0
    def prompt_for_team_addition(self, jira_manager: 'JiraManager') -> None:
        name = get_input('Name this new team:', lowered=False)

        jira_connection_name = pick_value('Which JIRA Connection owns this team?', jira_manager.possible_connections(), True, 'Cancel')
        if jira_connection_name is None:
            return
        self._teams[name] = Team(name, jira_connection_name)
        self.edit_team(jira_manager, name)
Exemplo n.º 17
0
 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)
Exemplo n.º 18
0
 def remove_dashboard(self):
     dn = pick_value('Remove which dashboard?',
                     list(self.jira_dashboards.keys()), True, 'Cancel')
     if dn is None:
         return
     prompt = get_input('About to delete [{}]. Are you sure?'.format(dn))
     if prompt == 'y':
         del self.jira_dashboards[dn]
         self._save_config()
Exemplo n.º 19
0
 def remove_filter(self):
     to_remove = pick_value('Remove value from which JiraFilter?',
                            list(self._jira_filters.keys()))
     if to_remove is None:
         return
     self._jira_filters[to_remove].remove_filter()
     if self._jira_filters[to_remove].is_empty():
         del self._jira_filters[to_remove]
     self.save_config()
Exemplo n.º 20
0
 def remove_custom_report(self):
     report_name = pick_value(
         'Which custom report would you like to remove?',
         list(self.jenkins_reports.keys()))
     if report_name:
         self.jenkins_reports.pop(report_name)
         self.save_jenkins_config()
         print('Successfully removed custom report: {}'.format(report_name))
         pause()
Exemplo n.º 21
0
 def pick_team(self, skip_list: Optional[List[str]] = None) -> Optional[Team]:
     if skip_list is None:
         valid_names = list(self._teams.keys())
     else:
         valid_names = [x for x in self._teams.keys() if x not in skip_list]
     team_name = pick_value('Select a team', valid_names, True, 'Cancel')
     if team_name is None:
         return None
     return self._teams[team_name]
Exemplo n.º 22
0
    def display_dashboard(self):
        if len(self.jira_dashboards) == 0:
            print('No dashboards. Create one first.')
            return
        dn = pick_value('Display which dashboard\'s results?',
                        list(self.jira_dashboards.keys()), True, 'Cancel')
        if dn is None:
            return

        self.jira_dashboards[dn].display_dashboard(self, self.jira_views)
Exemplo n.º 23
0
    def delete_cached_jira_project(self):
        jira_connection_name = pick_value(
            'Delete cached project data for which JiraConnection?',
            [x.connection_name for x in self.jira_connections()])
        if jira_connection_name is None:
            return

        jira_connection = self._jira_connections[jira_connection_name]
        project_cache_to_delete = pick_value(
            'Delete cached data for which JiraProject?',
            jira_connection.cached_project_names)
        if project_cache_to_delete is None:
            return

        if is_yes('About to delete locally cached content: {}. Are you sure?'.
                  format(
                      jira_connection.maybe_get_cached_jira_project(
                          project_cache_to_delete))):
            jira_connection.delete_cached_jira_project(project_cache_to_delete)
Exemplo n.º 24
0
    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()
Exemplo n.º 25
0
    def remove_alias(self) -> bool:
        if len(self._aliased_names) == 0:
            print('No aliases. Returning.')
            return False

        to_remove = pick_value('Remove which alias from this member?', list(self._aliased_names.keys()))
        if to_remove is None:
            return False

        del self._aliased_names[to_remove]
        return True
Exemplo n.º 26
0
 def prompt_to_remove_member(self):
     # type: () -> bool
     """
     :return: Whether deletion too place or not so parent can save team config on change
     """
     to_remove = pick_value('Remove which member?',
                            list(self._team_members.keys()))
     if to_remove is None:
         return False
     del self._team_members[to_remove]
     return True
Exemplo n.º 27
0
    def pick_jira_connection(
            self,
            prompt: str = 'Which JIRA connection?'
    ) -> Optional[JiraConnection]:
        if not self._prompt_connection_add_if_none():
            return None

        choice = pick_value(prompt, list(self._jira_connections.keys()), True)
        if choice is None:
            return None

        return self._jira_connections[choice]
Exemplo n.º 28
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
Exemplo n.º 29
0
 def prompt_to_remove_member(self) -> bool:
     """
     :return: Whether deletion took place or not so parent can save team config on change
     """
     to_remove = pick_value('Remove which member?', self.member_names)
     if to_remove is None:
         return False
     to_del = self.convert_name_to_jira_user_name(to_remove)
     if to_del is None:
         return False
     del self._team_members[to_del]
     return True
Exemplo n.º 30
0
    def build(cls, jira_views: Dict[str,
                                    JiraView]) -> Optional['JiraDashboard']:
        """
        Links 2 or more JiraViews together, combining their results for display
        """
        if len(jira_views) <= 1:
            print(
                'Need at least 2 JiraViews to create a dashboard. Please create more JiraViews first.'
            )
            return None

        view_name_options = list(jira_views.keys())
        dash_name = get_input('Name this dashboard:', lowered=False)
        view_name = pick_value('Include which view?', view_name_options, True,
                               'Cancel')
        if view_name is None:
            return None

        dash_views = {view_name: jira_views[view_name]}
        view_name_options.remove(view_name)

        view_name = pick_value('Second view?', view_name_options, False)
        # make mypy happy - doesn't realize False means we can't have None
        if view_name is None:
            return None
        dash_views[view_name] = jira_views[view_name]
        view_name_options.remove(view_name)

        while len(view_name_options) > 0:
            if is_yes('Add another?'):
                view_name = pick_value('What view?', view_name_options, True,
                                       '[q] Cancel')
                if view_name == 'q' or view_name is None:
                    break
                dash_views[view_name] = jira_views[view_name]
                view_name_options.remove(view_name)
            else:
                break

        return JiraDashboard(dash_name, dash_views)