From c8bdd6b78601b81009e40117fba46e86d631ac62 Mon Sep 17 00:00:00 2001 From: Ryan McGuire Date: Sun, 10 Dec 2023 11:15:52 -0500 Subject: [PATCH] Merged alias fuzzy search --- README.md | 3 ++ cmd/project_list.go | 2 +- cmd/project_show.go | 11 +++--- cmd/util_fzf.go | 54 ++++++++++++++++++++++++++---- internal/projects/cache_aliases.go | 11 ++++++ 5 files changed, 69 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 10cae45..9a0c573 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,9 @@ - config should exist for editor (vim, code, etc..) - Update README for shell completion, aliases, usage - Make a Makefile +- Add git repo status to project go (up-to-date, pending commits, etc..) +- Merge aliases together for same project when selecting +- If after merging there is only one project, go there by default ## Purpose diff --git a/cmd/project_list.go b/cmd/project_list.go index 988adb5..31748bf 100644 --- a/cmd/project_list.go +++ b/cmd/project_list.go @@ -10,7 +10,7 @@ import ( var projectListCmd = &cobra.Command{ Use: "list", Short: "List GitLab Projects", - Aliases: []string{"ls"}, + Aliases: []string{"ls", "l"}, Long: projListCmdLong, Run: projectListCmdRun, } diff --git a/cmd/project_show.go b/cmd/project_show.go index 9e9d314..a434239 100644 --- a/cmd/project_show.go +++ b/cmd/project_show.go @@ -7,11 +7,12 @@ import ( ) var projectShowCmd = &cobra.Command{ - Use: "show [fuzzy alias search]", - Short: "Show detail for a GitLab project", - Args: cobra.ArbitraryArgs, - Long: projShowCmdLong, - Run: projectShowCmdRun, + Use: "show [fuzzy alias search]", + Short: "Show detail for a GitLab project", + Aliases: []string{"cat", "s"}, + Args: cobra.ArbitraryArgs, + Long: projShowCmdLong, + Run: projectShowCmdRun, } func projectShowCmdRun(cmd *cobra.Command, args []string) { diff --git a/cmd/util_fzf.go b/cmd/util_fzf.go index 8302a90..9e5b7fd 100644 --- a/cmd/util_fzf.go +++ b/cmd/util_fzf.go @@ -8,6 +8,8 @@ import ( "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/projects" ) +// This will try to find a project by alias if a search term +// is given, otherwise will fuzzy find by project func fzfFindProject(searchString string) *gitlab.Project { var project *gitlab.Project @@ -24,6 +26,8 @@ func fzfFindProject(searchString string) *gitlab.Project { return project } +// This will fuzzy search only aliases, preferring an exact +// match if one is given func fzfSearchProjectAliases(searchString string) *gitlab.Project { var project *gitlab.Project var alias *projects.ProjectAlias @@ -34,15 +38,22 @@ func fzfSearchProjectAliases(searchString string) *gitlab.Project { // Get fuzzy if we don't have an exact match aliases := cache.FuzzyFindAlias(searchString) if len(aliases) > 1 { - alias = fzfAliasFromAliases(rootCmd.Context(), aliases) + // If multiple aliases were found, switch over to project + // by alias mode with merging + // alias = fzfAliasFromAliases(rootCmd.Context(), aliases) + project, _ = fzfProjectFromAliases(rootCmd.Context(), aliases) } else if len(aliases) == 1 { alias = aliases[0] + project = cache.GetProjectByAlias(alias) } - project = cache.GetProjectByAlias(alias) } return project } +// Given a list of aliases, will fuzzy-find and return +// a single one. Replaced by fzfProjectFromAliases in fzfSearchProjectAliases +// as merging is preferred, but can be used if it's ever desirable to +// return a single alias from all aliases func fzfAliasFromAliases(ctx context.Context, aliases []*projects.ProjectAlias) *projects.ProjectAlias { var alias *projects.ProjectAlias i, err := fzf.Find( @@ -61,6 +72,31 @@ func fzfAliasFromAliases(ctx context.Context, aliases []*projects.ProjectAlias) return alias } +// Given a list of aliases, merge them together and use the resulting +// list of projects to return a project +func fzfProjectFromAliases(ctx context.Context, aliases []*projects.ProjectAlias) ( + *gitlab.Project, error) { + mergedProjects := projectsFromAliases(aliases) + return fzfProjectFromProjects(ctx, mergedProjects) +} + +func projectsFromAliases(aliases []*projects.ProjectAlias) []*gitlab.Project { + projects := make([]*gitlab.Project, 0) + +ALIASES: + for _, a := range aliases { + for _, p := range projects { + // Already have it + if a.ProjectID == p.ID { + continue ALIASES + } + } + projects = append(projects, cache.GetProjectByAlias(a)) + } + + return projects +} + // If a bool=true is provided, will only allow selection of projects // that have at least one alias defined func fzfProject(ctx context.Context, mustHaveAlias ...bool) (*gitlab.Project, error) { @@ -70,14 +106,20 @@ func fzfProject(ctx context.Context, mustHaveAlias ...bool) (*gitlab.Project, er } else { searchableProjects = cache.Projects } + return fzfProjectFromProjects(ctx, searchableProjects) +} - i, err := fzf.Find(searchableProjects, +// Takes a list of projects and performs a fuzzyfind +func fzfProjectFromProjects(ctx context.Context, projects []*gitlab.Project) ( + *gitlab.Project, error) { + i, err := fzf.Find(projects, func(i int) string { - return searchableProjects[i].String() + // Display the project along with its aliases + return cache.GetProjectStringWithAliases(projects[i]) }, fzf.WithPreviewWindow( func(i, width, height int) string { - return cache.ProjectString(searchableProjects[i]) + return cache.ProjectString(projects[i]) }, ), fzf.WithContext(ctx), @@ -86,7 +128,7 @@ func fzfProject(ctx context.Context, mustHaveAlias ...bool) (*gitlab.Project, er if err != nil || i < 0 { return nil, err } - return searchableProjects[i], nil + return projects[i], nil } func fzfPreviewWindow(i, w, h int) string { diff --git a/internal/projects/cache_aliases.go b/internal/projects/cache_aliases.go index 6a43792..33eb41b 100644 --- a/internal/projects/cache_aliases.go +++ b/internal/projects/cache_aliases.go @@ -2,6 +2,8 @@ package projects import ( "errors" + "fmt" + "strings" "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/gitlab" "golang.org/x/exp/slices" @@ -61,3 +63,12 @@ func (c *Cache) GetProjectAliasStrings(project *gitlab.Project) []string { } return strings } + +func (c *Cache) GetProjectStringWithAliases(project *gitlab.Project) string { + aliases := c.GetProjectAliasStrings(project) + return fmt.Sprintf("%s (%s) -> %s", + project.Name, + strings.Join(aliases, ", "), + project.PathWithNamespace, + ) +}