Update config, add manual cache unlocking

This commit is contained in:
Ryan McGuire 2023-12-29 10:24:12 -05:00
parent ea0157a997
commit 156ddc2009
13 changed files with 141 additions and 50 deletions

View File

@ -11,12 +11,10 @@ import (
var cache *projects.Cache var cache *projects.Cache
var cacheCmd = &cobra.Command{ var cacheCmd = &cobra.Command{
Use: "cache", Use: "cache",
Aliases: []string{"a", "ln"}, Aliases: []string{"a", "ln"},
Short: "Manage GitLab project cache", Short: "Manage GitLab project cache",
Long: cacheCmdLong, Long: cacheCmdLong,
PersistentPreRun: runCacheCmd,
PersistentPostRun: postCacheCmd,
} }
func runCacheCmd(cmd *cobra.Command, args []string) { func runCacheCmd(cmd *cobra.Command, args []string) {

View File

@ -11,10 +11,12 @@ const longDesc = `Used to reset a project cache, forcing it to be rebuilt.
If --clearAliases is provided, will also reset aliases. Use with caution.` If --clearAliases is provided, will also reset aliases. Use with caution.`
var clearCmd = &cobra.Command{ var clearCmd = &cobra.Command{
Use: "clear", Use: "clear",
Short: "Clear GitLab Project Cache", Short: "Clear GitLab Project Cache",
Long: longDesc, PreRun: runCacheCmd,
Run: clearCache, PostRun: postCacheCmd,
Long: longDesc,
Run: clearCache,
} }
func clearCache(cmd *cobra.Command, args []string) { func clearCache(cmd *cobra.Command, args []string) {

View File

@ -8,9 +8,11 @@ import (
) )
var dumpCmd = &cobra.Command{ var dumpCmd = &cobra.Command{
Use: "dump", Use: "dump",
Short: "Dump GitLab project cache", Short: "Dump GitLab project cache",
Long: `Dumps cache to display`, Long: `Dumps cache to display`,
PreRun: runCacheCmd,
PostRun: postCacheCmd,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
if conf.Dump.Full { if conf.Dump.Full {
fmt.Println(cache.DumpString(true)) fmt.Println(cache.DumpString(true))

View File

@ -11,7 +11,9 @@ var loadCmd = &cobra.Command{
Long: `Used to initialize or update a new GitLab cache. With thousands Long: `Used to initialize or update a new GitLab cache. With thousands
of projects, it would be too much work to hit the API every time a user of projects, it would be too much work to hit the API every time a user
wants to find a new project.`, wants to find a new project.`,
Run: loadCache, PreRun: runCacheCmd,
PostRun: postCacheCmd,
Run: loadCache,
} }
func loadCache(cmd *cobra.Command, args []string) { func loadCache(cmd *cobra.Command, args []string) {

31
cmd/cache_unlock.go Normal file
View File

@ -0,0 +1,31 @@
package cmd
import (
"github.com/pterm/pterm"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var unlockCmd = &cobra.Command{
Use: "unlock",
Short: "unlock GitLab project cache",
Long: `unlocks cache to display`,
Run: func(cmd *cobra.Command, args []string) {
initProjectCache(cmd, args)
if viper.GetBool("cache.unlock.force") {
cache.UnlockCache()
} else if yes, _ := pterm.DefaultInteractiveConfirm.
WithDefaultValue(false).
Show("Are you sure you want to manually unlock?"); yes {
cache.UnlockCache()
} else {
plog.Error("You failed to confirm cache unlock")
}
},
}
func init() {
cacheCmd.AddCommand(unlockCmd)
unlockCmd.PersistentFlags().BoolP("force", "f", false, "force unlocks cache (don't ask)")
viper.BindPFlag("cache.unlock.force", unlockCmd.LocalFlags().Lookup("force"))
}

View File

@ -19,12 +19,7 @@ var projectCmd = &cobra.Command{
} }
func getProject(args []string) *gitlab.Project { func getProject(args []string) *gitlab.Project {
var searchString string project := fzfFindProject(searchStringFromArgs(args))
if len(args) > 0 {
searchString = args[0]
}
project := fzfFindProject(searchString)
if project == nil { if project == nil {
plog.Fatal("Failed to find a project, nothing to do") plog.Fatal("Failed to find a project, nothing to do")

View File

@ -20,12 +20,7 @@ var projectGoCmd = &cobra.Command{
} }
func projectGoCmdRun(cmd *cobra.Command, args []string) { func projectGoCmdRun(cmd *cobra.Command, args []string) {
var term string project := fzfSearchProjectAliases(searchStringFromArgs(args))
if len(args) > 0 {
term = args[0]
}
project := fzfSearchProjectAliases(term)
if project == nil { if project == nil {
plog.Fatal("No project selected, nowhere to go") plog.Fatal("No project selected, nowhere to go")

View File

@ -8,7 +8,6 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/gitlab"
) )
var projectOpenCmd = &cobra.Command{ var projectOpenCmd = &cobra.Command{
@ -53,23 +52,9 @@ func projectOpenCmdRun(cmd *cobra.Command, args []string) {
} }
// Identify search terms // Identify search terms
var searchTerm string project := fzfCwdOrSearchProjectAliases(searchStringFromArgs(args))
if len(args) > 0 {
searchTerm = args[0]
}
// Try to open local project
var project *gitlab.Project
if searchTerm == "." {
project, _ = cache.GetProjectFromCwd()
}
// Find a project if not local
if project == nil { if project == nil {
project = fzfSearchProjectAliases(searchTerm) plog.Fatal("No project to open, nothing to do")
if project == nil {
plog.Fatal("No project to open, nothing to do")
}
} }
// Check the project // Check the project

30
cmd/project_run.go Normal file
View File

@ -0,0 +1,30 @@
package cmd
import (
"github.com/spf13/cobra"
)
var projectRunCmd = &cobra.Command{
Use: "run",
Short: "Run the project (e.g. go run .)",
Aliases: []string{"exec", "r"},
Long: projRunCmdLong,
Run: projectRunCmdRun,
}
func projectRunCmdRun(cmd *cobra.Command, args []string) {
project := fzfCwdOrSearchProjectAliases(searchStringFromArgs(args))
if project == nil {
plog.Fatal("No project selected, nothing to open")
}
plog.Info("Running Projet", plog.Args("lang", project.Language))
if project.Language == nil {
plog.Fatal("GitLab isn't sure what language this project is... can't run.")
}
}
func init() {
projectCmd.AddCommand(projectRunCmd)
}

View File

@ -35,6 +35,9 @@ will be cloned from source control.
If conf.projects.alwaysPull, a git pull will be ran automatically` If conf.projects.alwaysPull, a git pull will be ran automatically`
const projRunCmdLong = `Runs the current project. Tries to detect
the language and runs accordingly (e.g. go run .)`
const projListCmdLong = `List locally cloned projects. Optionally const projListCmdLong = `List locally cloned projects. Optionally
lists all projects in project cache` lists all projects in project cache`

View File

@ -26,6 +26,19 @@ func fzfFindProject(searchString string) *gitlab.Project {
return project return project
} }
// If . is given as a project, will open project from the
// current working directory. Otherwise, will attempt to fuzzy-find
// a project given a search term if provided
func fzfCwdOrSearchProjectAliases(searchString string) *gitlab.Project {
var project *gitlab.Project
if searchString == "." {
project, _ = cache.GetProjectFromCwd()
} else {
project = fzfSearchProjectAliases(searchString)
}
return project
}
// This will fuzzy search only aliases, preferring an exact // This will fuzzy search only aliases, preferring an exact
// match if one is given // match if one is given
func fzfSearchProjectAliases(searchString string) *gitlab.Project { func fzfSearchProjectAliases(searchString string) *gitlab.Project {
@ -138,3 +151,13 @@ func fzfPreviewWindow(i, w, h int) string {
p := cache.Projects[i] p := cache.Projects[i]
return cache.ProjectString(p) return cache.ProjectString(p)
} }
// Nearly useless function that simply returns either an
// empty string, or a string from the first arg if one is provided
func searchStringFromArgs(args []string) string {
var term string
if len(args) > 0 {
term = args[0]
}
return term
}

View File

@ -5,7 +5,7 @@ import "time"
type Config struct { type Config struct {
Editor editorConfig `yaml:"editor" json:"editor"` Editor editorConfig `yaml:"editor" json:"editor"`
GitlabHost string `yaml:"gitlabHost" json:"gitlabHost"` GitlabHost string `yaml:"gitlabHost" json:"gitlabHost"`
GitlabToken string `yaml:"gitlabToken" json:"gitlabToken"` GitlabToken string `yaml:"gitlabToken,omitempty" json:"gitlabToken,omitempty"`
LogLevel string `yaml:"logLevel" json:"logLevel" enum:"info,warn,debug,error"` LogLevel string `yaml:"logLevel" json:"logLevel" enum:"info,warn,debug,error"`
ProjectPath string `yaml:"projectPath" json:"projectPath"` ProjectPath string `yaml:"projectPath" json:"projectPath"`
Cache cacheConfig `yaml:"cache" json:"cache"` Cache cacheConfig `yaml:"cache" json:"cache"`
@ -15,9 +15,9 @@ type Config struct {
} }
type editorConfig struct { type editorConfig struct {
DisplayName string `yaml:"displanName,omitempty" json:"displanName"` DisplayName string `yaml:"displanName,omitempty" json:"displanName,omitempty"`
Binary string `yaml:"binary,omitempty" json:"binary"` Binary string `yaml:"binary,omitempty" json:"binary,omitempty"`
OpenFlags string `yaml:"openFlags,omitempty" json:"openFlags"` OpenFlags string `yaml:"openFlags,omitempty" json:"openFlags,omitempty"`
OpenDirectory bool `yaml:"openDirectory" json:"openDirectory" description:"Don't open well-known files, open directory"` OpenDirectory bool `yaml:"openDirectory" json:"openDirectory" description:"Don't open well-known files, open directory"`
} }
@ -26,9 +26,12 @@ type loadConfig struct {
} }
type cacheConfig struct { type cacheConfig struct {
Ttl time.Duration `yaml:"ttl,omitempty" json:"ttl,omitempty"` Ttl time.Duration `yaml:"ttl,omitempty" json:"ttl,omitempty"`
File string `yaml:"file,omitempty" json:"file,omitempty"` File string `yaml:"file,omitempty" json:"file,omitempty"`
Load loadConfig `yaml:"load" json:"load"` Load loadConfig `yaml:"load" json:"load"`
Unlock struct {
Force bool `yaml:"force" json:"force"`
} `yaml:"unlock" json:"unlock"`
Clear struct { Clear struct {
ClearAliases bool `yaml:"clearAliases,omitempty" json:"clearAliases,omitempty"` ClearAliases bool `yaml:"clearAliases,omitempty" json:"clearAliases,omitempty"`
} `yaml:"clear,omitempty" json:"clear,omitempty"` } `yaml:"clear,omitempty" json:"clear,omitempty"`

View File

@ -31,6 +31,7 @@ type Project struct {
AvatarURL string AvatarURL string
LastActivityAt time.Time LastActivityAt time.Time
Readme string Readme string
Language *string
gitRepo *git.Repository gitRepo *git.Repository
} }
@ -196,12 +197,33 @@ func (c *Client) handleProjects(projects []*gitlab.Project) []*Project {
AvatarURL: project.AvatarURL, AvatarURL: project.AvatarURL,
LastActivityAt: *project.LastActivityAt, LastActivityAt: *project.LastActivityAt,
Readme: project.ReadmeURL, Readme: project.ReadmeURL,
Language: c.GetProjectLanguage(project),
} }
pList = append(pList, p) pList = append(pList, p)
} }
return pList return pList
} }
// A nil return indicates an API error or GitLab doesn't know what
// language the project uses.
func (c *Client) GetProjectLanguage(project *gitlab.Project) *string {
l, _, e := c.gitlab.Projects.GetProjectLanguages(project.ID, gitlab.WithContext(c.Ctx))
if e != nil {
pterm.Error.Printfln("Failed requesting project languages: %s", e.Error())
return nil
}
var mainLang *string
var mostUsed float32
for name, p := range *l {
if p > mostUsed {
mainLang = &name
}
}
return mainLang
}
func NewGitlabClient(ctx context.Context, host, token string) (*Client, error) { func NewGitlabClient(ctx context.Context, host, token string) (*Client, error) {
client, err := gitlab.NewClient(token, gitlab.WithBaseURL(host)) client, err := gitlab.NewClient(token, gitlab.WithBaseURL(host))
if err != nil { if err != nil {