From f33199bd7b720e5ff5c56596ec7e5a08cab060d2 Mon Sep 17 00:00:00 2001 From: Ryan D McGuire Date: Wed, 17 Jan 2024 08:13:58 -0500 Subject: [PATCH] Move RemoteInfo and CloneProto to info package --- cmd/config_generate.go | 7 ++--- cmd/root.go | 2 ++ cmd/util_completion.go | 14 ++++++++++ cmd/util_init.go | 13 +++++---- internal/cache/cache.go | 8 +++--- internal/cache/cache_load.go | 2 +- internal/config/config.go | 39 +++++++++++++-------------- internal/remotes/gitea/gitea.go | 12 ++++++--- internal/remotes/gitlab/gitlab.go | 12 ++++++--- internal/remotes/gitlab/gitlab_api.go | 7 ++--- internal/remotes/info/info.go | 24 +++++++++++++++++ internal/remotes/remote/remote.go | 18 ++++--------- 12 files changed, 100 insertions(+), 58 deletions(-) create mode 100644 internal/remotes/info/info.go diff --git a/cmd/config_generate.go b/cmd/config_generate.go index c757dfd..c90984c 100644 --- a/cmd/config_generate.go +++ b/cmd/config_generate.go @@ -9,6 +9,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/config" + "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/info" "gopkg.in/yaml.v3" ) @@ -102,13 +103,13 @@ func promptConfigSettings(c *config.Config) *config.Config { } if proto, err := pterm.DefaultInteractiveSelect. - WithOptions([]string{string(config.CloneProtoHTTP), string(config.CloneProtoSSH)}). + WithOptions([]string{string(info.CloneProtoHTTP), string(info.CloneProtoSSH)}). WithDefaultText("Git Clone Protocol"). Show(); err == nil { if proto == "ssh" { - gitlabConfig.CloneProto = config.CloneProtoSSH + gitlabConfig.CloneProto = info.CloneProtoSSH } else { - gitlabConfig.CloneProto = config.CloneProtoHTTP + gitlabConfig.CloneProto = info.CloneProtoHTTP } } diff --git a/cmd/root.go b/cmd/root.go index 9a39e3f..d2d4d82 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -53,6 +53,8 @@ func init() { "Sets a path for local clones of projects") rootCmd.PersistentFlags().String("logLevel", defLogLevel, "Default log level -- info, warn, error, debug") + rootCmd.PersistentFlags().StringSlice("remote", []string{}, + "Specify remotes by host for any sub-command. Provide multiple times or comma delimited.") rootCmd.RegisterFlagCompletionFunc("logLevel", validLogLevelsFunc) diff --git a/cmd/util_completion.go b/cmd/util_completion.go index 8c7faa6..fece2d3 100644 --- a/cmd/util_completion.go +++ b/cmd/util_completion.go @@ -27,6 +27,20 @@ func validProjectsOrAliasesFunc(cmd *cobra.Command, args []string, toComplete st return append(projectStrings, aliasStrings...), cobra.ShellCompDirectiveDefault } +func validRemotesFunc(cmd *cobra.Command, args []string, toComplete string) ( + []string, cobra.ShellCompDirective) { + var ttlRemotes int + ttlRemotes += len(conf.Gitlabs) + ttlRemotes += len(conf.Giteas) + remotes := make([]string, 0, ttlRemotes) + for _, remote := range conf.Gitlabs { + if strings.HasPrefix(remote.Host, toComplete) { + remotes = append(remotes, remote.Host) + } + } + return remotes, cobra.ShellCompDirectiveNoFileComp +} + func validGitlabRemotesFunc(cmd *cobra.Command, args []string, toComplete string) ( []string, cobra.ShellCompDirective) { remotes := make([]string, 0, len(conf.Gitlabs)) diff --git a/cmd/util_init.go b/cmd/util_init.go index 962f98e..097f61c 100644 --- a/cmd/util_init.go +++ b/cmd/util_init.go @@ -12,6 +12,7 @@ import ( "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes" gitearemote "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/gitea" gitlabremote "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/gitlab" + "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/info" "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/remote" "golang.org/x/sys/unix" ) @@ -60,13 +61,14 @@ func getGiteaRemotes(cmd *cobra.Command) []remote.Remote { gitRemotes := make([]remote.Remote, 0) for _, gitea := range conf.Giteas { if gitea.CloneProto == "" { - gitea.CloneProto = config.DefaultCloneProto + gitea.CloneProto = info.DefaultCloneProto } - giteaRemote, err := gitearemote.NewGiteaRemote(&remote.RemoteInfo{ + giteaRemote, err := gitearemote.NewGiteaRemote(&info.RemoteInfo{ Ctx: cmd.Context(), Host: gitea.Host, Name: gitea.Name, Token: gitea.Token, + Type: "gitea", CloneProto: gitea.CloneProto, }) if err != nil { @@ -89,20 +91,21 @@ func getGitLabRemotes(cmd *cobra.Command) []remote.Remote { Host: conf.GitlabHost, Name: conf.GitlabHost, Token: conf.GitlabToken, - CloneProto: config.CloneProtoSSH, + CloneProto: info.CloneProtoSSH, }) } // Load Gitlabs for _, gl := range conf.Gitlabs { if gl.CloneProto == "" { - gl.CloneProto = config.DefaultCloneProto + gl.CloneProto = info.DefaultCloneProto } - gitlabRemote, err := gitlabremote.NewGitlabRemote(&remote.RemoteInfo{ + gitlabRemote, err := gitlabremote.NewGitlabRemote(&info.RemoteInfo{ Ctx: cmd.Context(), Host: gl.Host, Name: gl.Name, Token: gl.Token, + Type: "gitlab", CloneProto: gl.CloneProto, }) if err != nil { diff --git a/internal/cache/cache.go b/internal/cache/cache.go index 51421b4..ef7958d 100644 --- a/internal/cache/cache.go +++ b/internal/cache/cache.go @@ -17,6 +17,7 @@ type Cache struct { Projects []*projects.Project Aliases []*ProjectAlias Updated time.Time + Remotes *remotes.Remotes config *config.Config readFromFile bool lock *sync.Mutex // Lock the entire cache @@ -25,7 +26,6 @@ type Cache struct { file string log *pterm.Logger path string - remotes *remotes.Remotes } type CacheOpts struct { @@ -161,9 +161,9 @@ func (c *Cache) String() string { c.Updated.String(), len(c.Projects), len(c.Aliases), - len(*c.remotes), + len(*c.Remotes), ) - for _, r := range *c.remotes { + for _, r := range *c.Remotes { cacheString += " " + r.GetInfo().Host } return cacheString @@ -202,7 +202,7 @@ func NewProjectCache(opts *CacheOpts) (*Cache, error) { lock: &sync.Mutex{}, contentLock: &sync.Mutex{}, log: opts.Logger, - remotes: opts.Remotes, + Remotes: opts.Remotes, path: opts.ProjectsPath, } diff --git a/internal/cache/cache_load.go b/internal/cache/cache_load.go index 85c7218..03e588c 100644 --- a/internal/cache/cache_load.go +++ b/internal/cache/cache_load.go @@ -14,7 +14,7 @@ func (c *Cache) LoadRemotes() { wg := &sync.WaitGroup{} writer := pterm.DefaultMultiPrinter - for _, r := range *c.remotes { + for _, r := range *c.Remotes { if !remote.IsAlive(r) { c.log.Error("Skipping load of remote, not alive", c.log.Args( "remote", r.String(), diff --git a/internal/config/config.go b/internal/config/config.go index 5f91914..86d1a9e 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,6 +1,10 @@ package config -import "time" +import ( + "time" + + "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/info" +) type Config struct { // Named keys above maintained for backwards compatibility @@ -9,9 +13,10 @@ type Config struct { GitlabToken string `yaml:"gitlabToken,omitempty" json:"gitlabToken,omitempty"` Gitlabs []GitlabConfig `yaml:"gitlabs" json:"gitlabs"` Giteas []GiteaConfig `yaml:"giteas" json:"giteas"` - LogLevel string `yaml:"logLevel" json:"logLevel" enum:"info,warn,debug,error"` - ProjectPath string `yaml:"projectPath" json:"projectPath"` - Cache cacheConfig `yaml:"cache" json:"cache"` + Remotes []info.RemoteInfo + LogLevel string `yaml:"logLevel" json:"logLevel" enum:"info,warn,debug,error"` + ProjectPath string `yaml:"projectPath" json:"projectPath"` + Cache cacheConfig `yaml:"cache" json:"cache"` Dump struct { Full bool `yaml:"full" json:"full"` } `yaml:"dump" json:"dump"` @@ -19,27 +24,19 @@ type Config struct { } type GiteaConfig struct { - Host string `yaml:"host" json:"host"` - Name string `yaml:"name" json:"name"` - Token string `yaml:"token" json:"token"` - CloneProto CloneProto `yaml:"cloneProto" json:"cloneProto"` + Host string `yaml:"host" json:"host"` + Name string `yaml:"name" json:"name"` + Token string `yaml:"token" json:"token"` + CloneProto info.CloneProto `yaml:"cloneProto" json:"cloneProto"` } type GitlabConfig struct { - Host string `yaml:"host" json:"host"` - Name string `yaml:"name" json:"name"` - Token string `yaml:"token" json:"token"` - CloneProto CloneProto `yaml:"cloneProto" json:"cloneProto"` + Host string `yaml:"host" json:"host"` + Name string `yaml:"name" json:"name"` + Token string `yaml:"token" json:"token"` + CloneProto info.CloneProto `yaml:"cloneProto" json:"cloneProto"` } -type CloneProto string - -const ( - CloneProtoSSH CloneProto = "ssh" - CloneProtoHTTP CloneProto = "http" - DefaultCloneProto CloneProto = CloneProtoSSH -) - type editorConfig struct { DisplayName string `yaml:"displanName,omitempty" json:"displanName,omitempty"` Binary string `yaml:"binary,omitempty" json:"binary,omitempty"` @@ -69,7 +66,7 @@ var DefaultConfig = Config{ Gitlabs: []GitlabConfig{{ Host: "https://gitlab.com", Token: "yourtokenhere", - CloneProto: CloneProtoSSH, + CloneProto: info.CloneProtoSSH, Name: "GitLab", }}, Cache: cacheConfig{ diff --git a/internal/remotes/gitea/gitea.go b/internal/remotes/gitea/gitea.go index 783d0d8..9b92e2b 100644 --- a/internal/remotes/gitea/gitea.go +++ b/internal/remotes/gitea/gitea.go @@ -4,24 +4,28 @@ import ( "fmt" "code.gitea.io/sdk/gitea" - "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/remote" + "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/info" ) type GiteaRemote struct { - info *remote.RemoteInfo + info *info.RemoteInfo api *gitea.Client } -func (r *GiteaRemote) GetInfo() *remote.RemoteInfo { +func (r *GiteaRemote) GetInfo() *info.RemoteInfo { return r.info } +func (r *GiteaRemote) GetType() string { + return r.info.Type +} + func (r *GiteaRemote) String() string { return fmt.Sprintf("Gitea %s (%s), clone proto %s", r.GetInfo().Name, r.GetInfo().Host, r.GetInfo().CloneProto) } -func NewGiteaRemote(remoteInfo *remote.RemoteInfo) (*GiteaRemote, error) { +func NewGiteaRemote(remoteInfo *info.RemoteInfo) (*GiteaRemote, error) { client, err := gitea.NewClient(remoteInfo.Host, gitea.SetContext(remoteInfo.Ctx), gitea.SetToken(remoteInfo.Token), diff --git a/internal/remotes/gitlab/gitlab.go b/internal/remotes/gitlab/gitlab.go index 5d23c7c..538a6df 100644 --- a/internal/remotes/gitlab/gitlab.go +++ b/internal/remotes/gitlab/gitlab.go @@ -4,24 +4,28 @@ import ( "fmt" "github.com/xanzy/go-gitlab" - "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/remote" + "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/info" ) type GitlabRemote struct { - info *remote.RemoteInfo + info *info.RemoteInfo api *gitlab.Client } -func (r *GitlabRemote) GetInfo() *remote.RemoteInfo { +func (r *GitlabRemote) GetInfo() *info.RemoteInfo { return r.info } +func (r *GitlabRemote) GetType() string { + return r.info.Type +} + func (r *GitlabRemote) String() string { return fmt.Sprintf("GitLab %s (%s), clone proto %s", r.GetInfo().Name, r.GetInfo().Host, r.GetInfo().CloneProto) } -func NewGitlabRemote(remoteInfo *remote.RemoteInfo) (*GitlabRemote, error) { +func NewGitlabRemote(remoteInfo *info.RemoteInfo) (*GitlabRemote, error) { api, err := NewGitlabApi(remoteInfo) if err != nil { return nil, err diff --git a/internal/remotes/gitlab/gitlab_api.go b/internal/remotes/gitlab/gitlab_api.go index 16b80cd..632f8dd 100644 --- a/internal/remotes/gitlab/gitlab_api.go +++ b/internal/remotes/gitlab/gitlab_api.go @@ -5,6 +5,7 @@ import ( "github.com/pterm/pterm" "github.com/xanzy/go-gitlab" + "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/info" "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/projects" "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/remote" ) @@ -22,10 +23,10 @@ var ( defApiWaitMax time.Duration = 5 * time.Second ) -func NewGitlabApi(info *remote.RemoteInfo) (*gitlab.Client, error) { +func NewGitlabApi(remoteInfo *info.RemoteInfo) (*gitlab.Client, error) { client, err := gitlab.NewClient( - info.Token, - gitlab.WithBaseURL(info.Host), + remoteInfo.Token, + gitlab.WithBaseURL(remoteInfo.Host), gitlab.WithCustomRetryWaitMinMax(defApiWaitMin, defApiWaitMax), ) if err != nil { diff --git a/internal/remotes/info/info.go b/internal/remotes/info/info.go new file mode 100644 index 0000000..50f5905 --- /dev/null +++ b/internal/remotes/info/info.go @@ -0,0 +1,24 @@ +package info + +import ( + "context" +) + +type CloneProto string + +const ( + CloneProtoSSH CloneProto = "ssh" + CloneProtoHTTP CloneProto = "http" + DefaultCloneProto CloneProto = CloneProtoSSH +) + +// Globally shared info for all remote types +// Stub package to prevent import cycle +type RemoteInfo struct { + Ctx context.Context + Host string + Name string + Token string + Type string + CloneProto CloneProto +} diff --git a/internal/remotes/remote/remote.go b/internal/remotes/remote/remote.go index 9ef818b..c7c33e1 100644 --- a/internal/remotes/remote/remote.go +++ b/internal/remotes/remote/remote.go @@ -1,24 +1,15 @@ package remote import ( - "context" "fmt" "net" "net/url" "time" - "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/config" + "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/info" "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/load" ) -type RemoteInfo struct { - Ctx context.Context - Host string - Name string - Token string - CloneProto config.CloneProto -} - const defNetDialTimeoutSecs = 3 // Any remote needs to be able to return @@ -26,8 +17,9 @@ const defNetDialTimeoutSecs = 3 // stream all projects along with updates to channels // provided by *load.ProgressInfo type Remote interface { - GetInfo() *RemoteInfo // Returns basic RemoteInfo struct String() string // String info for remote + GetInfo() *info.RemoteInfo // Returns basic RemoteInfo struct + GetType() string // Returns the remote type (e.g. GitLab, Gitea) GetNumProjects(*RemoteQueryOpts) int // Returns total number of accessible projects StreamProjects(*load.ProgressInfo, *RemoteQueryOpts) // Streams projects to chans provided in load.ProgressInfo } @@ -35,9 +27,9 @@ type Remote interface { func IsAlive(remote Remote) bool { var port int switch remote.GetInfo().CloneProto { - case config.CloneProtoHTTP: + case info.CloneProtoHTTP: port = 443 - case config.CloneProtoSSH: + case info.CloneProtoSSH: port = 22 }