Move RemoteInfo and CloneProto to info package

This commit is contained in:
Ryan McGuire 2024-01-17 08:13:58 -05:00
parent 1e4e9147f1
commit f33199bd7b
12 changed files with 100 additions and 58 deletions

View File

@ -9,6 +9,7 @@ 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/config" "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" "gopkg.in/yaml.v3"
) )
@ -102,13 +103,13 @@ func promptConfigSettings(c *config.Config) *config.Config {
} }
if proto, err := pterm.DefaultInteractiveSelect. 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"). WithDefaultText("Git Clone Protocol").
Show(); err == nil { Show(); err == nil {
if proto == "ssh" { if proto == "ssh" {
gitlabConfig.CloneProto = config.CloneProtoSSH gitlabConfig.CloneProto = info.CloneProtoSSH
} else { } else {
gitlabConfig.CloneProto = config.CloneProtoHTTP gitlabConfig.CloneProto = info.CloneProtoHTTP
} }
} }

View File

@ -53,6 +53,8 @@ func init() {
"Sets a path for local clones of projects") "Sets a path for local clones of projects")
rootCmd.PersistentFlags().String("logLevel", defLogLevel, rootCmd.PersistentFlags().String("logLevel", defLogLevel,
"Default log level -- info, warn, error, debug") "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) rootCmd.RegisterFlagCompletionFunc("logLevel", validLogLevelsFunc)

View File

@ -27,6 +27,20 @@ func validProjectsOrAliasesFunc(cmd *cobra.Command, args []string, toComplete st
return append(projectStrings, aliasStrings...), cobra.ShellCompDirectiveDefault 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) ( func validGitlabRemotesFunc(cmd *cobra.Command, args []string, toComplete string) (
[]string, cobra.ShellCompDirective) { []string, cobra.ShellCompDirective) {
remotes := make([]string, 0, len(conf.Gitlabs)) remotes := make([]string, 0, len(conf.Gitlabs))

View File

@ -12,6 +12,7 @@ import (
"gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes" "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes"
gitearemote "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/gitea" 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" 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" "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/remote"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
@ -60,13 +61,14 @@ func getGiteaRemotes(cmd *cobra.Command) []remote.Remote {
gitRemotes := make([]remote.Remote, 0) gitRemotes := make([]remote.Remote, 0)
for _, gitea := range conf.Giteas { for _, gitea := range conf.Giteas {
if gitea.CloneProto == "" { 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(), Ctx: cmd.Context(),
Host: gitea.Host, Host: gitea.Host,
Name: gitea.Name, Name: gitea.Name,
Token: gitea.Token, Token: gitea.Token,
Type: "gitea",
CloneProto: gitea.CloneProto, CloneProto: gitea.CloneProto,
}) })
if err != nil { if err != nil {
@ -89,20 +91,21 @@ func getGitLabRemotes(cmd *cobra.Command) []remote.Remote {
Host: conf.GitlabHost, Host: conf.GitlabHost,
Name: conf.GitlabHost, Name: conf.GitlabHost,
Token: conf.GitlabToken, Token: conf.GitlabToken,
CloneProto: config.CloneProtoSSH, CloneProto: info.CloneProtoSSH,
}) })
} }
// Load Gitlabs // Load Gitlabs
for _, gl := range conf.Gitlabs { for _, gl := range conf.Gitlabs {
if gl.CloneProto == "" { 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(), Ctx: cmd.Context(),
Host: gl.Host, Host: gl.Host,
Name: gl.Name, Name: gl.Name,
Token: gl.Token, Token: gl.Token,
Type: "gitlab",
CloneProto: gl.CloneProto, CloneProto: gl.CloneProto,
}) })
if err != nil { if err != nil {

View File

@ -17,6 +17,7 @@ type Cache struct {
Projects []*projects.Project Projects []*projects.Project
Aliases []*ProjectAlias Aliases []*ProjectAlias
Updated time.Time Updated time.Time
Remotes *remotes.Remotes
config *config.Config config *config.Config
readFromFile bool readFromFile bool
lock *sync.Mutex // Lock the entire cache lock *sync.Mutex // Lock the entire cache
@ -25,7 +26,6 @@ type Cache struct {
file string file string
log *pterm.Logger log *pterm.Logger
path string path string
remotes *remotes.Remotes
} }
type CacheOpts struct { type CacheOpts struct {
@ -161,9 +161,9 @@ func (c *Cache) String() string {
c.Updated.String(), c.Updated.String(),
len(c.Projects), len(c.Projects),
len(c.Aliases), len(c.Aliases),
len(*c.remotes), len(*c.Remotes),
) )
for _, r := range *c.remotes { for _, r := range *c.Remotes {
cacheString += " " + r.GetInfo().Host cacheString += " " + r.GetInfo().Host
} }
return cacheString return cacheString
@ -202,7 +202,7 @@ func NewProjectCache(opts *CacheOpts) (*Cache, error) {
lock: &sync.Mutex{}, lock: &sync.Mutex{},
contentLock: &sync.Mutex{}, contentLock: &sync.Mutex{},
log: opts.Logger, log: opts.Logger,
remotes: opts.Remotes, Remotes: opts.Remotes,
path: opts.ProjectsPath, path: opts.ProjectsPath,
} }

View File

@ -14,7 +14,7 @@ func (c *Cache) LoadRemotes() {
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
writer := pterm.DefaultMultiPrinter writer := pterm.DefaultMultiPrinter
for _, r := range *c.remotes { for _, r := range *c.Remotes {
if !remote.IsAlive(r) { if !remote.IsAlive(r) {
c.log.Error("Skipping load of remote, not alive", c.log.Args( c.log.Error("Skipping load of remote, not alive", c.log.Args(
"remote", r.String(), "remote", r.String(),

View File

@ -1,6 +1,10 @@
package config package config
import "time" import (
"time"
"gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/info"
)
type Config struct { type Config struct {
// Named keys above maintained for backwards compatibility // Named keys above maintained for backwards compatibility
@ -9,6 +13,7 @@ type Config struct {
GitlabToken string `yaml:"gitlabToken,omitempty" json:"gitlabToken,omitempty"` GitlabToken string `yaml:"gitlabToken,omitempty" json:"gitlabToken,omitempty"`
Gitlabs []GitlabConfig `yaml:"gitlabs" json:"gitlabs"` Gitlabs []GitlabConfig `yaml:"gitlabs" json:"gitlabs"`
Giteas []GiteaConfig `yaml:"giteas" json:"giteas"` Giteas []GiteaConfig `yaml:"giteas" json:"giteas"`
Remotes []info.RemoteInfo
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"`
@ -22,24 +27,16 @@ type GiteaConfig struct {
Host string `yaml:"host" json:"host"` Host string `yaml:"host" json:"host"`
Name string `yaml:"name" json:"name"` Name string `yaml:"name" json:"name"`
Token string `yaml:"token" json:"token"` Token string `yaml:"token" json:"token"`
CloneProto CloneProto `yaml:"cloneProto" json:"cloneProto"` CloneProto info.CloneProto `yaml:"cloneProto" json:"cloneProto"`
} }
type GitlabConfig struct { type GitlabConfig struct {
Host string `yaml:"host" json:"host"` Host string `yaml:"host" json:"host"`
Name string `yaml:"name" json:"name"` Name string `yaml:"name" json:"name"`
Token string `yaml:"token" json:"token"` Token string `yaml:"token" json:"token"`
CloneProto CloneProto `yaml:"cloneProto" json:"cloneProto"` CloneProto info.CloneProto `yaml:"cloneProto" json:"cloneProto"`
} }
type CloneProto string
const (
CloneProtoSSH CloneProto = "ssh"
CloneProtoHTTP CloneProto = "http"
DefaultCloneProto CloneProto = CloneProtoSSH
)
type editorConfig struct { type editorConfig struct {
DisplayName string `yaml:"displanName,omitempty" json:"displanName,omitempty"` DisplayName string `yaml:"displanName,omitempty" json:"displanName,omitempty"`
Binary string `yaml:"binary,omitempty" json:"binary,omitempty"` Binary string `yaml:"binary,omitempty" json:"binary,omitempty"`
@ -69,7 +66,7 @@ var DefaultConfig = Config{
Gitlabs: []GitlabConfig{{ Gitlabs: []GitlabConfig{{
Host: "https://gitlab.com", Host: "https://gitlab.com",
Token: "yourtokenhere", Token: "yourtokenhere",
CloneProto: CloneProtoSSH, CloneProto: info.CloneProtoSSH,
Name: "GitLab", Name: "GitLab",
}}, }},
Cache: cacheConfig{ Cache: cacheConfig{

View File

@ -4,24 +4,28 @@ import (
"fmt" "fmt"
"code.gitea.io/sdk/gitea" "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 { type GiteaRemote struct {
info *remote.RemoteInfo info *info.RemoteInfo
api *gitea.Client api *gitea.Client
} }
func (r *GiteaRemote) GetInfo() *remote.RemoteInfo { func (r *GiteaRemote) GetInfo() *info.RemoteInfo {
return r.info return r.info
} }
func (r *GiteaRemote) GetType() string {
return r.info.Type
}
func (r *GiteaRemote) String() string { func (r *GiteaRemote) String() string {
return fmt.Sprintf("Gitea %s (%s), clone proto %s", return fmt.Sprintf("Gitea %s (%s), clone proto %s",
r.GetInfo().Name, r.GetInfo().Host, r.GetInfo().CloneProto) 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, client, err := gitea.NewClient(remoteInfo.Host,
gitea.SetContext(remoteInfo.Ctx), gitea.SetContext(remoteInfo.Ctx),
gitea.SetToken(remoteInfo.Token), gitea.SetToken(remoteInfo.Token),

View File

@ -4,24 +4,28 @@ import (
"fmt" "fmt"
"github.com/xanzy/go-gitlab" "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 { type GitlabRemote struct {
info *remote.RemoteInfo info *info.RemoteInfo
api *gitlab.Client api *gitlab.Client
} }
func (r *GitlabRemote) GetInfo() *remote.RemoteInfo { func (r *GitlabRemote) GetInfo() *info.RemoteInfo {
return r.info return r.info
} }
func (r *GitlabRemote) GetType() string {
return r.info.Type
}
func (r *GitlabRemote) String() string { func (r *GitlabRemote) String() string {
return fmt.Sprintf("GitLab %s (%s), clone proto %s", return fmt.Sprintf("GitLab %s (%s), clone proto %s",
r.GetInfo().Name, r.GetInfo().Host, r.GetInfo().CloneProto) 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) api, err := NewGitlabApi(remoteInfo)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -5,6 +5,7 @@ import (
"github.com/pterm/pterm" "github.com/pterm/pterm"
"github.com/xanzy/go-gitlab" "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/projects"
"gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/remote" "gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/remotes/remote"
) )
@ -22,10 +23,10 @@ var (
defApiWaitMax time.Duration = 5 * time.Second 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( client, err := gitlab.NewClient(
info.Token, remoteInfo.Token,
gitlab.WithBaseURL(info.Host), gitlab.WithBaseURL(remoteInfo.Host),
gitlab.WithCustomRetryWaitMinMax(defApiWaitMin, defApiWaitMax), gitlab.WithCustomRetryWaitMinMax(defApiWaitMin, defApiWaitMax),
) )
if err != nil { if err != nil {

View File

@ -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
}

View File

@ -1,24 +1,15 @@
package remote package remote
import ( import (
"context"
"fmt" "fmt"
"net" "net"
"net/url" "net/url"
"time" "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" "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 const defNetDialTimeoutSecs = 3
// Any remote needs to be able to return // Any remote needs to be able to return
@ -26,8 +17,9 @@ const defNetDialTimeoutSecs = 3
// stream all projects along with updates to channels // stream all projects along with updates to channels
// provided by *load.ProgressInfo // provided by *load.ProgressInfo
type Remote interface { type Remote interface {
GetInfo() *RemoteInfo // Returns basic RemoteInfo struct
String() string // String info for remote 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 GetNumProjects(*RemoteQueryOpts) int // Returns total number of accessible projects
StreamProjects(*load.ProgressInfo, *RemoteQueryOpts) // Streams projects to chans provided in load.ProgressInfo StreamProjects(*load.ProgressInfo, *RemoteQueryOpts) // Streams projects to chans provided in load.ProgressInfo
} }
@ -35,9 +27,9 @@ type Remote interface {
func IsAlive(remote Remote) bool { func IsAlive(remote Remote) bool {
var port int var port int
switch remote.GetInfo().CloneProto { switch remote.GetInfo().CloneProto {
case config.CloneProtoHTTP: case info.CloneProtoHTTP:
port = 443 port = 443
case config.CloneProtoSSH: case info.CloneProtoSSH:
port = 22 port = 22
} }