Merged alias fuzzy search

This commit is contained in:
Ryan McGuire 2023-12-10 11:15:52 -05:00
parent e0d86a7662
commit c8bdd6b786
5 changed files with 69 additions and 12 deletions

View File

@ -13,6 +13,9 @@
- config should exist for editor (vim, code, etc..) - config should exist for editor (vim, code, etc..)
- Update README for shell completion, aliases, usage - Update README for shell completion, aliases, usage
- Make a Makefile - 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 ## Purpose

View File

@ -10,7 +10,7 @@ import (
var projectListCmd = &cobra.Command{ var projectListCmd = &cobra.Command{
Use: "list", Use: "list",
Short: "List GitLab Projects", Short: "List GitLab Projects",
Aliases: []string{"ls"}, Aliases: []string{"ls", "l"},
Long: projListCmdLong, Long: projListCmdLong,
Run: projectListCmdRun, Run: projectListCmdRun,
} }

View File

@ -7,11 +7,12 @@ import (
) )
var projectShowCmd = &cobra.Command{ var projectShowCmd = &cobra.Command{
Use: "show [fuzzy alias search]", Use: "show [fuzzy alias search]",
Short: "Show detail for a GitLab project", Short: "Show detail for a GitLab project",
Args: cobra.ArbitraryArgs, Aliases: []string{"cat", "s"},
Long: projShowCmdLong, Args: cobra.ArbitraryArgs,
Run: projectShowCmdRun, Long: projShowCmdLong,
Run: projectShowCmdRun,
} }
func projectShowCmdRun(cmd *cobra.Command, args []string) { func projectShowCmdRun(cmd *cobra.Command, args []string) {

View File

@ -8,6 +8,8 @@ import (
"gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/projects" "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 { func fzfFindProject(searchString string) *gitlab.Project {
var project *gitlab.Project var project *gitlab.Project
@ -24,6 +26,8 @@ func fzfFindProject(searchString string) *gitlab.Project {
return project return project
} }
// This will fuzzy search only aliases, preferring an exact
// match if one is given
func fzfSearchProjectAliases(searchString string) *gitlab.Project { func fzfSearchProjectAliases(searchString string) *gitlab.Project {
var project *gitlab.Project var project *gitlab.Project
var alias *projects.ProjectAlias var alias *projects.ProjectAlias
@ -34,15 +38,22 @@ func fzfSearchProjectAliases(searchString string) *gitlab.Project {
// Get fuzzy if we don't have an exact match // Get fuzzy if we don't have an exact match
aliases := cache.FuzzyFindAlias(searchString) aliases := cache.FuzzyFindAlias(searchString)
if len(aliases) > 1 { 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 { } else if len(aliases) == 1 {
alias = aliases[0] alias = aliases[0]
project = cache.GetProjectByAlias(alias)
} }
project = cache.GetProjectByAlias(alias)
} }
return project 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 { func fzfAliasFromAliases(ctx context.Context, aliases []*projects.ProjectAlias) *projects.ProjectAlias {
var alias *projects.ProjectAlias var alias *projects.ProjectAlias
i, err := fzf.Find( i, err := fzf.Find(
@ -61,6 +72,31 @@ func fzfAliasFromAliases(ctx context.Context, aliases []*projects.ProjectAlias)
return alias 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 // If a bool=true is provided, will only allow selection of projects
// that have at least one alias defined // that have at least one alias defined
func fzfProject(ctx context.Context, mustHaveAlias ...bool) (*gitlab.Project, error) { 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 { } else {
searchableProjects = cache.Projects 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 { func(i int) string {
return searchableProjects[i].String() // Display the project along with its aliases
return cache.GetProjectStringWithAliases(projects[i])
}, },
fzf.WithPreviewWindow( fzf.WithPreviewWindow(
func(i, width, height int) string { func(i, width, height int) string {
return cache.ProjectString(searchableProjects[i]) return cache.ProjectString(projects[i])
}, },
), ),
fzf.WithContext(ctx), fzf.WithContext(ctx),
@ -86,7 +128,7 @@ func fzfProject(ctx context.Context, mustHaveAlias ...bool) (*gitlab.Project, er
if err != nil || i < 0 { if err != nil || i < 0 {
return nil, err return nil, err
} }
return searchableProjects[i], nil return projects[i], nil
} }
func fzfPreviewWindow(i, w, h int) string { func fzfPreviewWindow(i, w, h int) string {

View File

@ -2,6 +2,8 @@ package projects
import ( import (
"errors" "errors"
"fmt"
"strings"
"gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/gitlab" "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/gitlab"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
@ -61,3 +63,12 @@ func (c *Cache) GetProjectAliasStrings(project *gitlab.Project) []string {
} }
return strings 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,
)
}