feat: update tools

This commit is contained in:
franklin 2023-05-25 10:03:43 +02:00
parent adaf7d480a
commit ca1e91d231
31 changed files with 918 additions and 381 deletions

View File

@ -57,7 +57,7 @@ linters:
#- gci # Gci controls golang package import order and makes it always deterministic. [fast: true, auto-fix: false] #- gci # Gci controls golang package import order and makes it always deterministic. [fast: true, auto-fix: false]
#- gochecknoglobals # check that no global variables exist [fast: true, auto-fix: false] #- gochecknoglobals # check that no global variables exist [fast: true, auto-fix: false]
#- gochecknoinits # Checks that no init functions are present in Go code [fast: true, auto-fix: false] #- gochecknoinits # Checks that no init functions are present in Go code [fast: true, auto-fix: false]
- gocognit # Computes and checks the cognitive complexity of functions [fast: true, auto-fix: false] #- gocognit # Computes and checks the cognitive complexity of functions [fast: true, auto-fix: false]
- goconst # Finds repeated strings that could be replaced by a constant [fast: true, auto-fix: false] - goconst # Finds repeated strings that could be replaced by a constant [fast: true, auto-fix: false]
- gocritic # Provides diagnostics that check for bugs, performance and style issues. [fast: false, auto-fix: false] - gocritic # Provides diagnostics that check for bugs, performance and style issues. [fast: false, auto-fix: false]
- gocyclo # Computes and checks the cyclomatic complexity of functions [fast: true, auto-fix: false] - gocyclo # Computes and checks the cyclomatic complexity of functions [fast: true, auto-fix: false]

View File

@ -149,14 +149,30 @@ func (c *Command) execute(ctx context.Context, r *readline.Readline) error {
return err return err
} }
if route.Username != nil && route.Password != nil { if route.BasicAuth != nil {
if username, err := c.op.Get(ctx, *route.Username); err != nil { var (
return err username string
} else if password, err := c.op.Get(ctx, *route.Password); err != nil { password string
return err )
} else { {
u.User = url.UserPassword(username, password) secret := *route.BasicAuth
secret.Field = "username"
if value, err := c.op.Get(ctx, secret); err != nil {
return err
} else {
username = value
}
} }
{
secret := *route.BasicAuth
secret.Field = "password"
if value, err := c.op.Get(ctx, secret); err != nil {
return err
} else {
password = value
}
}
u.User = url.UserPassword(username, password)
} }
return browser.OpenURL(u) return browser.OpenURL(u)

View File

@ -14,7 +14,6 @@ type (
ConfigRoute struct { ConfigRoute struct {
Path string `yaml:"path"` Path string `yaml:"path"`
Description string `yaml:"description"` Description string `yaml:"description"`
Username *onepassword.Secret `yaml:"username"` BasicAuth *onepassword.Secret `yaml:"basicAuth"`
Password *onepassword.Secret `yaml:"password"`
} }
) )

View File

@ -75,6 +75,15 @@ func NewCommand(l log.Logger, kubectl *kubectl.Kubectl, squadron *squadron.Squad
Suggest: inst.completeSquadrons, Suggest: inst.completeSquadrons,
}, },
}, },
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
if r.Args().HasIndex(0) {
fs.Internal().String("profile", "", "Profile to use.")
if err := fs.Internal().SetValues("profile", inst.kubectl.Cluster(r.Args().At(0)).Profiles(ctx)...); err != nil {
return err
}
}
return nil
},
Execute: inst.execute, Execute: inst.execute,
}) })
return inst return inst
@ -109,10 +118,17 @@ func (c *Command) Help(ctx context.Context, r *readline.Readline) string {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
func (c *Command) execute(ctx context.Context, r *readline.Readline) error { func (c *Command) execute(ctx context.Context, r *readline.Readline) error {
ifs := r.FlagSets().Internal()
cluster, fleet, squad := r.Args().At(0), r.Args().At(1), r.Args().At(2) cluster, fleet, squad := r.Args().At(0), r.Args().At(1), r.Args().At(2)
profile, err := ifs.GetString("profile")
if err != nil {
return err
}
return shell.New(ctx, c.l, "k9s", "-n", c.namespaceFn(cluster, fleet, squad), "--logoless"). return shell.New(ctx, c.l, "k9s", "-n", c.namespaceFn(cluster, fleet, squad), "--logoless").
Args(r.AdditionalArgs()...). Args(r.AdditionalArgs()...).
Env(c.kubectl.Cluster(cluster).Env()). Env(c.kubectl.Cluster(cluster).Env(profile)).
Run() Run()
} }

View File

@ -112,9 +112,9 @@ func (c *Command) completePaths(ctx context.Context) []goprompt.Suggest {
//nolint:forcetypeassert //nolint:forcetypeassert
func (c *Command) paths(ctx context.Context) []string { func (c *Command) paths(ctx context.Context) []string {
return c.cache.Get("paths", func() any { return c.cache.Get("paths", func() any {
if value, err := files.Find(ctx, ".", "zeus"); err != nil { if value, err := files.Find(ctx, ".", "zeus", files.FindWithIgnore(`^\.`, "node_modules"), files.FindWithIsDir(true)); err != nil {
c.l.Debug("failed to walk files", err.Error()) c.l.Debug("failed to walk files", err.Error())
return nil return []string{}
} else { } else {
return value return value
} }

View File

@ -9,7 +9,9 @@ import (
"strings" "strings"
prompt2 "github.com/c-bata/go-prompt" prompt2 "github.com/c-bata/go-prompt"
"github.com/foomo/posh-providers/kubernets/kubectl"
"github.com/foomo/posh/pkg/command/tree" "github.com/foomo/posh/pkg/command/tree"
"github.com/foomo/posh/pkg/env"
"github.com/foomo/posh/pkg/log" "github.com/foomo/posh/pkg/log"
"github.com/foomo/posh/pkg/prompt/goprompt" "github.com/foomo/posh/pkg/prompt/goprompt"
"github.com/foomo/posh/pkg/readline" "github.com/foomo/posh/pkg/readline"
@ -21,6 +23,7 @@ import (
type Command struct { type Command struct {
l log.Logger l log.Logger
etcd *ETCD etcd *ETCD
kubectl *kubectl.Kubectl
commandTree tree.Root commandTree tree.Root
} }
@ -28,21 +31,33 @@ type Command struct {
// ~ Constructor // ~ Constructor
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
func NewCommand(l log.Logger, etcd *ETCD, opts ...Option) *Command { func NewCommand(l log.Logger, etcd *ETCD, kubectl *kubectl.Kubectl, opts ...Option) *Command {
inst := &Command{ inst := &Command{
l: l.Named("etcd"), l: l.Named("etcd"),
etcd: etcd, etcd: etcd,
kubectl: kubectl,
} }
pathArg := &tree.Arg{ args := tree.Args{
Name: "path", {
Suggest: func(ctx context.Context, t tree.Root, r *readline.Readline) []prompt2.Suggest { Name: "path",
if value, ok := inst.etcd.cfg.Cluster(r.Args().At(0)); ok { Suggest: func(ctx context.Context, t tree.Root, r *readline.Readline) []prompt2.Suggest {
return suggests.List(value.Paths) if value, ok := inst.etcd.cfg.Cluster(r.Args().At(0)); ok {
} return suggests.List(value.Paths)
return nil }
return nil
},
}, },
} }
flags := func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
if r.Args().HasIndex(0) {
fs.Internal().String("profile", "", "Profile to use.")
if err := fs.Internal().SetValues("profile", inst.kubectl.Cluster(r.Args().At(0)).Profiles(ctx)...); err != nil {
return err
}
}
return nil
}
inst.commandTree = tree.New(&tree.Node{ inst.commandTree = tree.New(&tree.Node{
Name: "etcd", Name: "etcd",
@ -62,12 +77,14 @@ func NewCommand(l log.Logger, etcd *ETCD, opts ...Option) *Command {
Nodes: tree.Nodes{ Nodes: tree.Nodes{
{ {
Name: "get", Name: "get",
Args: tree.Args{pathArg}, Args: args,
Flags: flags,
Execute: inst.get, Execute: inst.get,
}, },
{ {
Name: "edit", Name: "edit",
Args: tree.Args{pathArg}, Args: args,
Flags: flags,
Execute: inst.edit, Execute: inst.edit,
}, },
}, },
@ -108,9 +125,16 @@ func (c *Command) Help(ctx context.Context, r *readline.Readline) string {
func (c *Command) get(ctx context.Context, r *readline.Readline) error { func (c *Command) get(ctx context.Context, r *readline.Readline) error {
etcdPath := r.Args().At(2) etcdPath := r.Args().At(2)
ifs := r.FlagSets().Internal()
profile, err := ifs.GetString("profile")
if err != nil {
return err
}
if cluster, ok := c.etcd.cfg.Cluster(r.Args().At(0)); !ok { if cluster, ok := c.etcd.cfg.Cluster(r.Args().At(0)); !ok {
return errors.New("invalid cluster") return errors.New("invalid cluster")
} else if out, err := c.etcd.GetPath(ctx, cluster, etcdPath); err != nil { } else if out, err := c.etcd.GetPath(ctx, cluster, profile, etcdPath); err != nil {
return errors.Wrap(err, out) return errors.Wrap(err, out)
} else { } else {
prints.Code(c.l, etcdPath, out+"\n", "yaml") prints.Code(c.l, etcdPath, out+"\n", "yaml")
@ -129,10 +153,16 @@ func (c *Command) edit(ctx context.Context, r *readline.Readline) error {
} }
etcdPath := r.Args().At(2) etcdPath := r.Args().At(2)
filename := path.Join(os.Getenv("PROJECT_ROOT"), c.etcd.cfg.ConfigPath, etcdPath) ifs := r.FlagSets().Internal()
filename := env.Path(c.etcd.cfg.ConfigPath, etcdPath)
profile, err := ifs.GetString("profile")
if err != nil {
return err
}
{ // retrieve data { // retrieve data
if value, err := c.etcd.GetPath(ctx, cluster, etcdPath); err != nil { if value, err := c.etcd.GetPath(ctx, cluster, profile, etcdPath); err != nil {
return err return err
} else { } else {
prev = []byte(strings.ReplaceAll(value, "\r\r\n", "\n")) prev = []byte(strings.ReplaceAll(value, "\r\r\n", "\n"))
@ -173,7 +203,7 @@ func (c *Command) edit(ctx context.Context, r *readline.Readline) error {
} }
c.l.Info("updating config") c.l.Info("updating config")
if out, err := c.etcd.SetPath(ctx, cluster, etcdPath, string(next)); err != nil { if out, err := c.etcd.SetPath(ctx, cluster, profile, etcdPath, string(next)); err != nil {
return errors.Wrap(err, out) return errors.Wrap(err, out)
} }
return nil return nil

View File

@ -65,13 +65,13 @@ func New(l log.Logger, kubectl *kubectl.Kubectl, opts ...Option) (*ETCD, error)
// ~ Public methods // ~ Public methods
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
func (c *ETCD) GetPath(ctx context.Context, cluster Cluster, path string) (string, error) { func (c *ETCD) GetPath(ctx context.Context, cluster Cluster, profile, path string) (string, error) {
if out, err := shell.New(ctx, c.l, "kubectl", "exec", if out, err := shell.New(ctx, c.l, "kubectl", "exec",
"-it", cluster.PodName, "-it", cluster.PodName,
"--namespace", cluster.Namespace, "--namespace", cluster.Namespace,
"--", "/bin/sh", "-c", "'etcdctl get "+path+" --print-value-only'", "--", "/bin/sh", "-c", "'etcdctl get "+path+" --print-value-only'",
). ).
Env(c.kubectl.Cluster(cluster.Name).Env()). Env(c.kubectl.Cluster(cluster.Name).Env(profile)).
Output(); err != nil { Output(); err != nil {
return "", err return "", err
} else { } else {
@ -79,13 +79,13 @@ func (c *ETCD) GetPath(ctx context.Context, cluster Cluster, path string) (strin
} }
} }
func (c *ETCD) SetPath(ctx context.Context, cluster Cluster, path, value string) (string, error) { func (c *ETCD) SetPath(ctx context.Context, cluster Cluster, profile, path, value string) (string, error) {
if out, err := shell.New(ctx, c.l, "kubectl", "exec", if out, err := shell.New(ctx, c.l, "kubectl", "exec",
"-it", cluster.PodName, "-it", cluster.PodName,
"--namespace", cluster.Namespace, "--namespace", cluster.Namespace,
"--", "/bin/sh", "-c", fmt.Sprintf("'echo \"%s\" | etcdctl put "+path+"'", strings.ReplaceAll(value, "\n", "\\n")), "--", "/bin/sh", "-c", fmt.Sprintf("'echo \"%s\" | etcdctl put "+path+"'", strings.ReplaceAll(value, "\n", "\\n")),
). ).
Env(c.kubectl.Cluster(cluster.Name).Env()). Env(c.kubectl.Cluster(cluster.Name).Env(profile)).
Output(); err != nil { Output(); err != nil {
return "", err return "", err
} else { } else {

View File

@ -159,7 +159,7 @@ func (c *Command) execute(ctx context.Context, r *readline.Readline) error {
//nolint:forcetypeassert //nolint:forcetypeassert
func (c *Command) paths(ctx context.Context) []string { func (c *Command) paths(ctx context.Context) []string {
return c.cache.Get("paths", func() any { return c.cache.Get("paths", func() any {
if value, err := files.Find(ctx, ".", "gocontentful.yml"); err != nil { if value, err := files.Find(ctx, ".", "gocontentful.yaml", files.FindWithIgnore(`^\.`, "node_modules")); err != nil {
c.l.Debug("failed to walk files", err.Error()) c.l.Debug("failed to walk files", err.Error())
return []string{} return []string{}
} else { } else {

View File

@ -40,8 +40,9 @@ func NewCommand(l log.Logger, cache cache.Cache) *Command {
}, },
Args: tree.Args{ Args: tree.Args{
{ {
Name: "path", Name: "path",
Suggest: inst.completePaths, Optional: true,
Suggest: inst.completePaths,
}, },
}, },
Execute: inst.execute, Execute: inst.execute,

View File

@ -101,6 +101,15 @@ func NewCommand(l log.Logger, squadron *Squadron, kubectl *kubectl.Kubectl, op *
fs.Internal().Bool("slack", false, "send slack notification") fs.Internal().Bool("slack", false, "send slack notification")
} }
} }
profileFlag := func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
if r.Args().HasIndex(0) {
fs.Internal().String("profile", "", "Profile to use.")
if err := fs.Internal().SetValues("profile", inst.kubectl.Cluster(r.Args().At(0)).Profiles(ctx)...); err != nil {
return err
}
}
return nil
}
commonFlags := func(fs *readline.FlagSets) { commonFlags := func(fs *readline.FlagSets) {
fs.Internal().Bool("no-override", false, "ignore override files") fs.Internal().Bool("no-override", false, "ignore override files")
fs.Default().Bool("verbose", inst.l.IsLevel(log.LevelDebug), "set verbose level") fs.Default().Bool("verbose", inst.l.IsLevel(log.LevelDebug), "set verbose level")
@ -153,6 +162,9 @@ func NewCommand(l log.Logger, squadron *Squadron, kubectl *kubectl.Kubectl, op *
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
slackFlag(fs) slackFlag(fs)
commonFlags(fs) commonFlags(fs)
if err := profileFlag(ctx, r, fs); err != nil {
return err
}
fs.Default().Bool("diff", false, "show diff") fs.Default().Bool("diff", false, "show diff")
fs.Default().Bool("push", false, "push image") fs.Default().Bool("push", false, "push image")
fs.Default().Bool("build", false, "build image") fs.Default().Bool("build", false, "build image")
@ -178,8 +190,11 @@ func NewCommand(l log.Logger, squadron *Squadron, kubectl *kubectl.Kubectl, op *
Description: "Uninstalls the squadron chart", Description: "Uninstalls the squadron chart",
Args: tree.Args{unitsArg}, Args: tree.Args{unitsArg},
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
commonFlags(fs)
slackFlag(fs) slackFlag(fs)
commonFlags(fs)
if err := profileFlag(ctx, r, fs); err != nil {
return err
}
return nil return nil
}, },
Execute: inst.execute, Execute: inst.execute,
@ -216,6 +231,9 @@ func NewCommand(l log.Logger, squadron *Squadron, kubectl *kubectl.Kubectl, op *
Args: tree.Args{unitsArg}, Args: tree.Args{unitsArg},
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
commonFlags(fs) commonFlags(fs)
if err := profileFlag(ctx, r, fs); err != nil {
return err
}
return nil return nil
}, },
Execute: inst.execute, Execute: inst.execute,
@ -236,9 +254,12 @@ func NewCommand(l log.Logger, squadron *Squadron, kubectl *kubectl.Kubectl, op *
Description: "Roll back the squadron chart", Description: "Roll back the squadron chart",
Args: tree.Args{unitsArg}, Args: tree.Args{unitsArg},
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
slackFlag(fs)
commonFlags(fs) commonFlags(fs)
fs.Default().String("revision", "", "revision number to rollback to") fs.Default().String("revision", "", "revision number to rollback to")
slackFlag(fs) if err := profileFlag(ctx, r, fs); err != nil {
return err
}
return nil return nil
}, },
Execute: inst.execute, Execute: inst.execute,
@ -316,9 +337,14 @@ func (c *Command) execute(ctx context.Context, r *readline.Readline) error {
tag, _ := ifs.GetString("tag") tag, _ := ifs.GetString("tag")
noOverride := log.MustGet(ifs.GetBool("no-override"))(c.l) noOverride := log.MustGet(ifs.GetBool("no-override"))(c.l)
profile, err := ifs.GetString("profile")
if err != nil {
return err
}
{ // handle 1password { // handle 1password
if c.op != nil { if c.op != nil {
if ok, _ := c.op.Session(); !ok { if ok, _ := c.op.IsAuthenticated(); !ok {
c.l.Info("missing 1password session, please login") c.l.Info("missing 1password session, please login")
if err := c.op.SignIn(ctx); err != nil { if err := c.op.SignIn(ctx); err != nil {
return err return err
@ -343,7 +369,7 @@ func (c *Command) execute(ctx context.Context, r *readline.Readline) error {
if tag != "" { if tag != "" {
env = append(env, fmt.Sprintf("TAG=%q", tag)) env = append(env, fmt.Sprintf("TAG=%q", tag))
} }
env = append(env, c.kubectl.Cluster(cluster).Env()) env = append(env, c.kubectl.Cluster(cluster).Env(profile))
} }
{ // handle squadrons { // handle squadrons

29
go.mod
View File

@ -8,30 +8,35 @@ require (
github.com/1Password/connect-sdk-go v1.5.0 github.com/1Password/connect-sdk-go v1.5.0
github.com/c-bata/go-prompt v0.2.6 github.com/c-bata/go-prompt v0.2.6
github.com/cloudrecipes/packagejson v1.0.0 github.com/cloudrecipes/packagejson v1.0.0
github.com/foomo/posh v0.4.0 github.com/foomo/posh v0.4.1
github.com/google/go-github/v47 v47.1.0
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/pterm/pterm v0.12.57 github.com/pterm/pterm v0.12.62
github.com/samber/lo v1.38.1 github.com/samber/lo v1.38.1
github.com/slack-go/slack v0.12.1 github.com/slack-go/slack v0.12.2
github.com/spf13/viper v1.15.0 github.com/spf13/viper v1.15.0
golang.org/x/exp v0.0.0-20230126173853-a67bb567ff2e golang.org/x/exp v0.0.0-20230307190834-24139beb5833
golang.org/x/sync v0.1.0 golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783
golang.org/x/sync v0.2.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )
require ( require (
atomicgo.dev/cursor v0.1.1 // indirect atomicgo.dev/cursor v0.1.1 // indirect
atomicgo.dev/keyboard v0.2.9 // indirect atomicgo.dev/keyboard v0.2.9 // indirect
atomicgo.dev/schedule v0.0.2 // indirect
github.com/alecthomas/chroma v0.10.0 // indirect github.com/alecthomas/chroma v0.10.0 // indirect
github.com/charlievieth/fastwalk v1.0.1 // indirect github.com/charlievieth/fastwalk v1.0.1 // indirect
github.com/containerd/console v1.0.3 // indirect github.com/containerd/console v1.0.3 // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gookit/color v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/gookit/color v1.5.3 // indirect
github.com/gorilla/websocket v1.4.2 // indirect github.com/gorilla/websocket v1.4.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/lithammer/fuzzysearch v1.1.5 // indirect github.com/lithammer/fuzzysearch v1.1.8 // indirect
github.com/magiconair/properties v1.8.7 // indirect github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-isatty v0.0.14 // indirect
@ -51,9 +56,13 @@ require (
github.com/uber/jaeger-lib v2.4.1+incompatible // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
go.uber.org/atomic v1.9.0 // indirect go.uber.org/atomic v1.9.0 // indirect
golang.org/x/sys v0.6.0 // indirect golang.org/x/crypto v0.7.0 // indirect
golang.org/x/term v0.5.0 // indirect golang.org/x/net v0.8.0 // indirect
golang.org/x/text v0.8.0 // indirect golang.org/x/sys v0.8.0 // indirect
golang.org/x/term v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
) )

74
go.sum
View File

@ -3,6 +3,8 @@ atomicgo.dev/cursor v0.1.1 h1:0t9sxQomCTRh5ug+hAMCs59x/UmC9QL6Ci5uosINKD4=
atomicgo.dev/cursor v0.1.1/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU= atomicgo.dev/cursor v0.1.1/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU=
atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8= atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8=
atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ= atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ=
atomicgo.dev/schedule v0.0.2 h1:2e/4KY6t3wokja01Cyty6qgkQM8MotJzjtqCH70oX2Q=
atomicgo.dev/schedule v0.0.2/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
@ -86,8 +88,8 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/foomo/posh v0.4.0 h1:vL+EJ+nQKaswAnrqvMn9ptx+s/BY6xOddHY/aJPIxug= github.com/foomo/posh v0.4.1 h1:2gUEzrwlNS/KqVOq5DcQi7oHovrsDQOJ6wJSjchxDV0=
github.com/foomo/posh v0.4.0/go.mod h1:+ir4dZiQ3ReOQP3cfpK8IAYd4xymMOEpHaOxbWJ32mc= github.com/foomo/posh v0.4.1/go.mod h1:Q631XvEisDS5UDJe4UO10R8ENBMO9c9+qmSPM0CV2WI=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/franklinkim/go-prompt v0.2.7-0.20210427061716-a8f4995d7aa5 h1:kXNtle4AoQnngdm+gwt4ku6Llbzw3EFHgZYpL618JaI= github.com/franklinkim/go-prompt v0.2.7-0.20210427061716-a8f4995d7aa5 h1:kXNtle4AoQnngdm+gwt4ku6Llbzw3EFHgZYpL618JaI=
github.com/franklinkim/go-prompt v0.2.7-0.20210427061716-a8f4995d7aa5/go.mod h1:+syUfnvYJUO5A+6QMQYXAyzkxHMNlj9dH2LIeQfBSjc= github.com/franklinkim/go-prompt v0.2.7-0.20210427061716-a8f4995d7aa5/go.mod h1:+syUfnvYJUO5A+6QMQYXAyzkxHMNlj9dH2LIeQfBSjc=
@ -124,6 +126,9 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@ -135,8 +140,13 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-github/v47 v47.1.0 h1:Cacm/WxQBOa9lF0FT0EMjZ2BWMetQ1TQfyurn4yF1z8=
github.com/google/go-github/v47 v47.1.0/go.mod h1:VPZBXNbFSJGjyjFRUKo9vZGawTajnWzC/YjGw/oFKi0=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@ -159,8 +169,8 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI= github.com/gookit/color v1.5.3 h1:twfIhZs4QLCtimkP7MOxlF3A0U/5cDPseRT9M/+2SCE=
github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg= github.com/gookit/color v1.5.3/go.mod h1:NUzwzeehUfl7GIb36pqId+UGmRfQcU/WiiyTTeNjHtE=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -188,8 +198,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lithammer/fuzzysearch v1.1.5 h1:Ag7aKU08wp0R9QCfF4GoGST9HbmAIeLP7xwMrOBEp1c= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
github.com/lithammer/fuzzysearch v1.1.5/go.mod h1:1R1LRNk7yKid1BaQkmuLQaHruxcC4HmAH30Dh61Ih1Q= github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@ -230,8 +240,8 @@ github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEej
github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE=
github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8=
github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s=
github.com/pterm/pterm v0.12.57 h1:HTjDUmILmh6hIsEidRdpxQAiqcoHCdvRCxIR3KZ0/XE= github.com/pterm/pterm v0.12.62 h1:Xjj5Wl6UR4Il9xOiDUOZRwReRTdO75if/JdWsn9I59s=
github.com/pterm/pterm v0.12.57/go.mod h1:7rswprkyxYOse1IMh79w42jvReNHxro4z9oHfqjIdzM= github.com/pterm/pterm v0.12.62/go.mod h1:+c3ujjE7N5qmNx6eKAa7YVSC6m/gCorJJKhzwYTbL90=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
@ -241,8 +251,8 @@ github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/slack-go/slack v0.12.1 h1:X97b9g2hnITDtNsNe5GkGx6O2/Sz/uC20ejRZN6QxOw= github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ=
github.com/slack-go/slack v0.12.1/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/slack-go/slack v0.12.2/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw=
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
@ -266,7 +276,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
@ -280,6 +290,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@ -294,7 +305,10 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -308,8 +322,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20230126173853-a67bb567ff2e h1:nEzRHNOazEST44vMvEwxGxnYGrzXEmxJmnti5mKSWTk= golang.org/x/exp v0.0.0-20230307190834-24139beb5833 h1:SChBja7BCQewoTAU7IgvucQKMIXrEpFxNMs0spT3/5s=
golang.org/x/exp v0.0.0-20230126173853-a67bb567ff2e/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20230307190834-24139beb5833/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@ -334,6 +348,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -365,6 +381,10 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -374,6 +394,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 h1:nt+Q6cXKz4MosCSpnbMtqiQ8Oz0pxTef2B4Vca2lvfk=
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -384,8 +406,10 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -432,15 +456,19 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -448,8 +476,9 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -502,6 +531,8 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -535,6 +566,7 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@ -598,6 +630,10 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

147
goharbor/harbor/command.go Normal file
View File

@ -0,0 +1,147 @@
package harbor
import (
"context"
"os"
"github.com/foomo/posh/pkg/command/tree"
"github.com/foomo/posh/pkg/log"
"github.com/foomo/posh/pkg/prompt/goprompt"
"github.com/foomo/posh/pkg/readline"
"github.com/foomo/posh/pkg/shell"
"github.com/foomo/posh/pkg/util"
"github.com/foomo/posh/pkg/util/browser"
"github.com/google/go-github/v47/github"
"github.com/pterm/pterm"
"github.com/spf13/viper"
"golang.org/x/oauth2"
)
type (
Command struct {
l log.Logger
cfg Config
name string
configKey string
commandTree tree.Root
}
CommandOption func(*Command)
)
// ------------------------------------------------------------------------------------------------
// ~ Options
// ------------------------------------------------------------------------------------------------
func CommandWithName(v string) CommandOption {
return func(o *Command) {
o.name = v
}
}
func WithConfigKey(v string) CommandOption {
return func(o *Command) {
o.configKey = v
}
}
// ------------------------------------------------------------------------------------------------
// ~ Constructor
// ------------------------------------------------------------------------------------------------
func NewCommand(l log.Logger, opts ...CommandOption) *Command {
inst := &Command{
l: l.Named("harbor"),
name: "harbor",
configKey: "open",
}
for _, opt := range opts {
if opt != nil {
opt(inst)
}
}
if err := viper.UnmarshalKey(inst.configKey, &inst.cfg); err != nil {
return nil
}
inst.commandTree = tree.New(&tree.Node{
Name: inst.name,
Description: "Run harbor",
Execute: inst.auth,
Nodes: tree.Nodes{
{
Name: "auth",
Args: nil,
Description: "Sign in to Harbor",
Execute: inst.auth,
},
{
Name: "docker",
Args: nil,
Description: "Configure docker.",
Execute: inst.docker,
},
},
})
return inst
}
// ------------------------------------------------------------------------------------------------
// ~ Public methods
// ------------------------------------------------------------------------------------------------
func (c *Command) Name() string {
return c.commandTree.Node().Name
}
func (c *Command) Description() string {
return c.commandTree.Node().Description
}
func (c *Command) Complete(ctx context.Context, r *readline.Readline) []goprompt.Suggest {
return c.commandTree.Complete(ctx, r)
}
func (c *Command) Execute(ctx context.Context, r *readline.Readline) error {
return c.commandTree.Execute(ctx, r)
}
func (c *Command) Help(ctx context.Context, r *readline.Readline) string {
return c.commandTree.Help(ctx, r)
}
// ------------------------------------------------------------------------------------------------
// ~ Private methods
// ------------------------------------------------------------------------------------------------
func (c *Command) auth(ctx context.Context, r *readline.Readline) error {
return browser.OpenRawURL(c.cfg.AuthURL)
}
func (c *Command) docker(ctx context.Context, r *readline.Readline) error {
client := github.NewClient(
oauth2.NewClient(
ctx,
oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: os.Getenv("GITHUB_TOKEN")},
),
),
)
var username string
user, _, err := client.Users.Get(ctx, "")
if err == nil && user != nil && user.Login != nil {
username = *user.Login
} else if username, err = util.Prompt("github username"); err != nil {
return err
}
pterm.Info.Println("registry: " + c.cfg.URL)
pterm.Info.Println("username: " + username)
pterm.Info.Println("please enter your CLI secret as password...")
return shell.New(ctx, c.l, "docker", "login", c.cfg.URL, "-u", username).
Args(r.AdditionalArgs()...).
Args(r.AdditionalFlags()...).
Run()
}

View File

@ -0,0 +1,6 @@
package harbor
type Config struct {
URL string `json:"url" yaml:"url"`
AuthURL string `json:"authUrl" yaml:"authUrl"`
}

View File

@ -2,18 +2,19 @@ package gcloud
import ( import (
"context" "context"
"fmt"
"github.com/foomo/posh/pkg/log" "github.com/foomo/posh/pkg/log"
"github.com/foomo/posh/pkg/prompt/check" "github.com/foomo/posh/pkg/prompt/check"
) )
func AccountChecker(p *GCloud) check.Checker { func AuthChecker(p *GCloud) check.Checker {
return func(ctx context.Context, l log.Logger) check.Info { return func(ctx context.Context, l log.Logger) check.Info {
name := "GCloud: Account" name := "GCloud"
if account, err := p.ActiveAccount(ctx, l); err != nil { if account, err := p.ActiveAccount(ctx, l); err != nil {
return check.NewFailureInfo(name, "Error: "+err.Error()) return check.NewFailureInfo(name, "Error: "+err.Error())
} else { } else {
return check.NewSuccessInfo(name, account) return check.NewSuccessInfo(name, fmt.Sprintf("Authenticated (%s)", account))
} }
} }
} }

View File

@ -108,6 +108,10 @@ func NewCommand(l log.Logger, gcloud *GCloud, kubectl *kubectl.Kubectl, opts ...
}, },
}, },
}, },
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
fs.Internal().String("profile", "", "Store credentials in given profile.")
return fs.Internal().SetValues("profile", "gcloud")
},
Execute: inst.containerClustersGetCredentials, Execute: inst.containerClustersGetCredentials,
}, },
}, },
@ -206,11 +210,14 @@ func (c *Command) authConfigureDocker(ctx context.Context, r *readline.Readline)
func (c *Command) containerClustersGetCredentials(ctx context.Context, r *readline.Readline) error { func (c *Command) containerClustersGetCredentials(ctx context.Context, r *readline.Readline) error {
var args []string var args []string
ifs := r.FlagSets().Internal()
clusterName := r.Args().At(1) clusterName := r.Args().At(1)
cluster, err := c.gcloud.cfg.Cluster(clusterName) cluster, err := c.gcloud.cfg.Cluster(clusterName)
if err != nil { if err != nil {
return errors.Errorf("failed to retrieve cluster for: %q", clusterName) return errors.Errorf("failed to retrieve cluster for: %q", clusterName)
} }
kubectlCluster := c.kubectl.Cluster(c.clusterNameFn(clusterName, cluster)) kubectlCluster := c.kubectl.Cluster(c.clusterNameFn(clusterName, cluster))
if kubectlCluster == nil { if kubectlCluster == nil {
return errors.Errorf("failed to retrieve kubectl cluster for: %q", cluster.Name) return errors.Errorf("failed to retrieve kubectl cluster for: %q", cluster.Name)
@ -224,12 +231,17 @@ func (c *Command) containerClustersGetCredentials(ctx context.Context, r *readli
} }
} }
profile, err := ifs.GetString("profile")
if err != nil {
return err
}
return shell.New(ctx, c.l, "gcloud", "container", "clusters", "get-credentials", cluster.Name, return shell.New(ctx, c.l, "gcloud", "container", "clusters", "get-credentials", cluster.Name,
"--project", cluster.Project, "--project", cluster.Project,
"--region", cluster.Region, "--region", cluster.Region,
). ).
Args(args...). Args(args...).
Args(r.AdditionalArgs()...). Args(r.AdditionalArgs()...).
Env(kubectlCluster.Env()). Env(kubectlCluster.Env(profile)).
Run() Run()
} }

View File

@ -0,0 +1,19 @@
package teleport
import (
"context"
"github.com/foomo/posh/pkg/log"
"github.com/foomo/posh/pkg/prompt/check"
)
func AuthChecker(p *Teleport) check.Checker {
return func(ctx context.Context, l log.Logger) check.Info {
name := "Teleport"
if p.IsAuthenticated(ctx) {
return check.NewSuccessInfo(name, "Authenticated")
} else {
return check.NewFailureInfo(name, "Run `teleport auth` to sign into teleport")
}
}
}

View File

@ -14,34 +14,54 @@ import (
"github.com/foomo/posh/pkg/util/suggests" "github.com/foomo/posh/pkg/util/suggests"
) )
type Command struct { type (
l log.Logger Command struct {
name string l log.Logger
cache cache.Cache name string
kubectl *kubectl.Kubectl cache cache.Cache
teleport *Teleport kubectl *kubectl.Kubectl
commandTree tree.Root teleport *Teleport
commandTree tree.Root
}
CommandOption func(*Command)
)
// ------------------------------------------------------------------------------------------------
// ~ Options
// ------------------------------------------------------------------------------------------------
func CommandWithName(v string) CommandOption {
return func(o *Command) {
o.name = v
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// ~ Constructor // ~ Constructor
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
func NewCommand(l log.Logger, cache cache.Cache, teleport *Teleport, kubectl *kubectl.Kubectl, opts ...Option) *Command { func NewCommand(l log.Logger, cache cache.Cache, teleport *Teleport, kubectl *kubectl.Kubectl, opts ...CommandOption) *Command {
inst := &Command{ inst := &Command{
l: l.Named("teleport"), l: l.Named("teleport"),
name: "teleport",
cache: cache, cache: cache,
kubectl: kubectl, kubectl: kubectl,
teleport: teleport, teleport: teleport,
} }
for _, opt := range opts {
if opt != nil {
opt(inst)
}
}
inst.commandTree = tree.New(&tree.Node{ inst.commandTree = tree.New(&tree.Node{
Name: "teleport", Name: "teleport",
Description: "Manage access points through teleport", Description: "Manage access points through teleport",
Execute: inst.auth,
Nodes: tree.Nodes{ Nodes: tree.Nodes{
{ {
Name: "login", Name: "auth",
Execute: inst.login, Execute: inst.auth,
}, },
{ {
Name: "kubeconfig", Name: "kubeconfig",
@ -55,6 +75,10 @@ func NewCommand(l log.Logger, cache cache.Cache, teleport *Teleport, kubectl *ku
}, },
}, },
}, },
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
fs.Internal().String("profile", "", "Profile to use.")
return fs.Internal().SetValues("profile", "teleport")
},
Execute: inst.kubeconfig, Execute: inst.kubeconfig,
}, },
{ {
@ -74,64 +98,6 @@ func NewCommand(l log.Logger, cache cache.Cache, teleport *Teleport, kubectl *ku
}, },
}) })
/*
// Execute ...
func (c *Teleport) Execute(args, passArgs, pipeArgs []string) error {
var env []string
cmd, args := args[0], args[1:]
env = append(env, "HOME="+path.Join(os.Getenv("PROJECT_ROOT"), "devops", "config"))
switch cmd {
case "login":
if err := shell.New("tsh", "login").
WithArgs(
"--auth=github",
fmt.Sprintf("--proxy=%s:443", c.config().Hostname),
).
WithPassArgs(passArgs...).
WithPipeArgs(pipeArgs...).
WithEnv(env).
Run(); err != nil {
return err
}
case "database":
database, _ := args[0], args[1:]
databaseUser := "developers"
if value := os.Getenv("TELEPORT_DATABASE_USER"); value != "" {
databaseUser = value
}
if err := shell.New("tsh", "db", "login", "--db-user", databaseUser, database).
WithPassArgs(passArgs...).
WithPipeArgs(pipeArgs...).
WithEnv(env).
Run(); err != nil {
return err
}
case "kubeconfig":
cluster, _ := args[0], args[1:]
env = append(env, fmt.Sprintf("KUBECONFIG=%s", kubectl.Cluster(cluster).GetConfig()))
// delete old config
kubectl.Cluster(cluster).DeleteConfig()
// generate & filter new config
if err := shell.New("tsh", "kube", "login", cluster).
WithPassArgs(passArgs...).
WithPipeArgs(pipeArgs...).
WithEnv(env).
Run(); err != nil {
return err
} else if err = config.GenerateTeleportKubeconfig(kubectl.Cluster(cluster).GetConfig(), cluster); err != nil {
return errors.Wrap(err, "failed to create teleport kubeconfig")
}
}
cache.Clear("")
return nil
}
*/
return inst return inst
} }
@ -167,7 +133,6 @@ func (c *Command) database(ctx context.Context, r *readline.Readline) error {
databse := r.Args().At(1) databse := r.Args().At(1)
return shell.New(ctx, c.l, "tsh", "db", "login", return shell.New(ctx, c.l, "tsh", "db", "login",
fmt.Sprintf("--proxy=%s", c.teleport.Config().Hostname),
"--db-user", c.teleport.Config().Database.EnvUser(), "--db-user", c.teleport.Config().Database.EnvUser(),
databse, databse,
). ).
@ -178,26 +143,31 @@ func (c *Command) database(ctx context.Context, r *readline.Readline) error {
} }
func (c *Command) kubeconfig(ctx context.Context, r *readline.Readline) error { func (c *Command) kubeconfig(ctx context.Context, r *readline.Readline) error {
ifs := r.FlagSets().Internal()
cluster := c.kubectl.Cluster(r.Args().At(1)) cluster := c.kubectl.Cluster(r.Args().At(1))
profile, err := ifs.GetString("profile")
if err != nil {
return err
}
// delete old config // delete old config
if err := cluster.DeleteConfig(); err != nil { if err := cluster.DeleteConfig(profile); err != nil {
return err return err
} }
// generate & filter new config // generate & filter new config
return shell.New(ctx, c.l, "tsh", "kube", "login", return shell.New(ctx, c.l, "tsh", "kube", "login",
fmt.Sprintf("--proxy=%s", c.teleport.Config().Hostname),
cluster.Name(), cluster.Name(),
). ).
Env(cluster.Env()). Env(cluster.Env(profile)).
Args(r.Flags()...). Args(r.Flags()...).
Args(r.AdditionalArgs()...). Args(r.AdditionalArgs()...).
Args(r.AdditionalFlags()...). Args(r.AdditionalFlags()...).
Run() Run()
} }
func (c *Command) login(ctx context.Context, r *readline.Readline) error { func (c *Command) auth(ctx context.Context, r *readline.Readline) error {
if err := shell.New(ctx, c.l, "tsh", "login", if err := shell.New(ctx, c.l, "tsh", "login",
fmt.Sprintf("--proxy=%s", c.teleport.Config().Hostname), fmt.Sprintf("--proxy=%s", c.teleport.Config().Hostname),
"--auth=github", "--auth=github",

View File

@ -76,7 +76,7 @@ func (t *Teleport) Config() Config {
return t.cfg return t.cfg
} }
func (t *Teleport) IsSignedIn(ctx context.Context) bool { func (t *Teleport) IsAuthenticated(ctx context.Context) bool {
if t.signedIn && time.Since(t.signedInTime) < 12*time.Hour { if t.signedIn && time.Since(t.signedInTime) < 12*time.Hour {
return true return true
} else if _, err := shell.New(ctx, t.l, "tsh", "status").Quiet().Output(); err != nil { } else if _, err := shell.New(ctx, t.l, "tsh", "status").Quiet().Output(); err != nil {
@ -90,8 +90,10 @@ func (t *Teleport) IsSignedIn(ctx context.Context) bool {
} }
// Clusters returns a list of cluster // Clusters returns a list of cluster
//
//nolint:forcetypeassert
func (t *Teleport) Clusters(ctx context.Context) []string { func (t *Teleport) Clusters(ctx context.Context) []string {
if !t.IsSignedIn(ctx) { if !t.IsAuthenticated(ctx) {
return nil return nil
} }
return t.cache.Get("clusters", func() interface{} { return t.cache.Get("clusters", func() interface{} {
@ -102,7 +104,6 @@ func (t *Teleport) Clusters(ctx context.Context) []string {
} }
value, err := shell.New(ctx, t.l, "tsh", "kube", "ls", value, err := shell.New(ctx, t.l, "tsh", "kube", "ls",
fmt.Sprintf("--proxy=%s", t.cfg.Hostname),
fmt.Sprintf("--query='%s'", t.cfg.Query()), fmt.Sprintf("--query='%s'", t.cfg.Query()),
"--format", "json", "--format", "json",
). ).
@ -126,8 +127,10 @@ func (t *Teleport) Clusters(ctx context.Context) []string {
} }
// Databases returns a list of cluster // Databases returns a list of cluster
//
//nolint:forcetypeassert
func (t *Teleport) Databases(ctx context.Context) []string { func (t *Teleport) Databases(ctx context.Context) []string {
if !t.IsSignedIn(ctx) { if !t.IsAuthenticated(ctx) {
return nil return nil
} }
return t.cache.Get("databases", func() interface{} { return t.cache.Get("databases", func() interface{} {
@ -142,7 +145,6 @@ func (t *Teleport) Databases(ctx context.Context) []string {
} }
) )
value, err := shell.New(ctx, t.l, "tsh", "db", "ls", value, err := shell.New(ctx, t.l, "tsh", "db", "ls",
fmt.Sprintf("--proxy=%s", t.cfg.Hostname),
fmt.Sprintf("--query='%s'", t.cfg.Query()), fmt.Sprintf("--query='%s'", t.cfg.Query()),
"--format", "json", "--format", "json",
). ).

18
hashicorp/cdktf/README.md Normal file
View File

@ -0,0 +1,18 @@
# POSH CDKTF provider
## Config
```yaml
cdktf:
path: devops/cdktf
```
## Usage
```go
func New(l log.Logger) (plugin.Plugin, error) {
// ...
inst.commands.Add(helm.NewCommand(l, kubectl))
// ...
}
```

181
hashicorp/cdktf/command.go Normal file
View File

@ -0,0 +1,181 @@
package cdktf
import (
"context"
"errors"
"os/exec"
"github.com/foomo/posh/pkg/cache"
"github.com/foomo/posh/pkg/command/tree"
"github.com/foomo/posh/pkg/log"
"github.com/foomo/posh/pkg/prompt/goprompt"
"github.com/foomo/posh/pkg/readline"
"github.com/foomo/posh/pkg/shell"
"github.com/spf13/viper"
)
type (
Command struct {
l log.Logger
cfg Config
name string
cache cache.Namespace
configKey string
commandTree tree.Root
}
CommandOption func(*Command)
)
// ------------------------------------------------------------------------------------------------
// ~ Options
// ------------------------------------------------------------------------------------------------
func CommandWithName(v string) CommandOption {
return func(o *Command) {
o.name = v
}
}
func WithConfigKey(v string) CommandOption {
return func(o *Command) {
o.configKey = v
}
}
// ------------------------------------------------------------------------------------------------
// ~ Constructor
// ------------------------------------------------------------------------------------------------
func NewCommand(l log.Logger, cache cache.Cache, opts ...CommandOption) (*Command, error) {
inst := &Command{
l: l.Named("cdktf"),
name: "cdktf",
cache: cache.Get("cdktf"),
}
for _, opt := range opts {
if opt != nil {
opt(inst)
}
}
if err := viper.UnmarshalKey(inst.configKey, &inst.cfg); err != nil {
return nil, err
}
inst.commandTree = tree.New(&tree.Node{
Name: inst.name,
Description: "Run cdktf",
Nodes: tree.Nodes{
{
Name: "list",
Description: "List stacks in app",
Execute: inst.list,
},
{
Name: "diff",
Description: "Perform a diff (terraform plan) for the given stack",
Execute: inst.diff,
},
{
Name: "deploy",
Description: "Deploy the given stacks",
Execute: inst.deploy,
},
{
Name: "destroy",
Description: "Destroy the given stacks",
Execute: inst.destroy,
},
{
Name: "output",
Description: "Prints the output of stacks",
Execute: inst.output,
},
},
})
return inst, nil
}
// ------------------------------------------------------------------------------------------------
// ~ Public methods
// ------------------------------------------------------------------------------------------------
func (c *Command) Name() string {
return c.commandTree.Node().Name
}
func (c *Command) Description() string {
return c.commandTree.Node().Description
}
func (c *Command) Complete(ctx context.Context, r *readline.Readline) []goprompt.Suggest {
return c.commandTree.Complete(ctx, r)
}
func (c *Command) Execute(ctx context.Context, r *readline.Readline) error {
return c.commandTree.Execute(ctx, r)
}
func (c *Command) Validate(ctx context.Context, r *readline.Readline) error {
if _, err := exec.LookPath("cdktf"); err != nil {
c.l.Print()
return errors.New(`
Please ensure you have the cdktf installed!
- Install binary:
$ npm install --global cdktf-cli
`)
}
return nil
}
func (c *Command) Help(ctx context.Context, r *readline.Readline) string {
return c.commandTree.Help(ctx, r)
}
// ------------------------------------------------------------------------------------------------
// ~ Private methods
// ------------------------------------------------------------------------------------------------
func (c *Command) list(ctx context.Context, r *readline.Readline) error {
return shell.New(ctx, c.l, "cdktf", "list").
Dir(c.cfg.Path).
Run()
}
func (c *Command) diff(ctx context.Context, r *readline.Readline) error {
return shell.New(ctx, c.l, "cdktf", "diff").
Dir(c.cfg.Path).
Run()
}
func (c *Command) deploy(ctx context.Context, r *readline.Readline) error {
return shell.New(ctx, c.l, "cdktf", "deploy").
Dir(c.cfg.Path).
Run()
}
func (c *Command) destroy(ctx context.Context, r *readline.Readline) error {
return shell.New(ctx, c.l, "cdktf", "destroy").
Dir(c.cfg.Path).
Run()
}
func (c *Command) output(ctx context.Context, r *readline.Readline) error {
return shell.New(ctx, c.l, "cdktf", "output").
Dir(c.cfg.Path).
Run()
}
//nolint:forcetypeassert
//func (c *Command) paths(ctx context.Context) []string {
// return c.cache.Get("paths", func() any {
// if value, err := files.Find(ctx, ".", "cdktf.yml"); err != nil {
// c.l.Debug("failed to walk files", err.Error())
// return []string{}
// } else {
// return value
// }
// }).([]string)
//}

View File

@ -0,0 +1,5 @@
package cdktf
type Config struct {
Path string `yaml:"path"`
}

View File

@ -2,6 +2,7 @@ package helm
import ( import (
"context" "context"
"fmt"
"github.com/foomo/posh-providers/kubernets/kubectl" "github.com/foomo/posh-providers/kubernets/kubectl"
"github.com/foomo/posh/pkg/command/tree" "github.com/foomo/posh/pkg/command/tree"
@ -43,7 +44,8 @@ func NewCommand(l log.Logger, kubectl *kubectl.Kubectl) *Command {
name: "helm", name: "helm",
kubectl: kubectl, kubectl: kubectl,
} }
allFlags := func(fs *readline.FlagSets) {
allFlags := func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
fs.Default().Bool("help", false, "help for helm") fs.Default().Bool("help", false, "help for helm")
fs.Default().Bool("debug", false, "enable verbose output") fs.Default().Bool("debug", false, "enable verbose output")
fs.Default().String("namespace", "", "namespace scope for this request") fs.Default().String("namespace", "", "namespace scope for this request")
@ -53,6 +55,13 @@ func NewCommand(l log.Logger, kubectl *kubectl.Kubectl) *Command {
fs.Default().Bool("dry-run", false, "assume aws profile") fs.Default().Bool("dry-run", false, "assume aws profile")
fs.Default().Bool("atomic", false, "delete installation on failure") fs.Default().Bool("atomic", false, "delete installation on failure")
fs.Default().Bool("wait", false, "wait until all resources a ready") fs.Default().Bool("wait", false, "wait until all resources a ready")
fs.Internal().String("profile", "", "Profile to use.")
if r.Args().HasIndex(0) {
if err := fs.Internal().SetValues("profile", inst.kubectl.Cluster(r.Args().At(0)).Profiles(ctx)...); err != nil {
return err
}
}
return nil
} }
inst.commandTree = tree.New(&tree.Node{ inst.commandTree = tree.New(&tree.Node{
@ -69,46 +78,33 @@ func NewCommand(l log.Logger, kubectl *kubectl.Kubectl) *Command {
{ {
Name: "create", Name: "create",
Description: "Create a new chart with the given name", Description: "Create a new chart with the given name",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "dependency", Name: "dependency",
Description: "Manage a chart's dependencies", Description: "Manage a chart's dependencies",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "diff", Name: "diff",
Description: "Preview helm upgrade changes as a diff", Description: "Preview helm upgrade changes as a diff",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "env", Name: "env",
Description: "Helm client environment information", Description: "Helm client environment information",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "get", Name: "get",
Description: "Download extended information of a named release", Description: "Download extended information of a named release",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
allFlags(fs)
fs.Default().String("revision", "", "get the named release with revision") fs.Default().String("revision", "", "get the named release with revision")
return nil return allFlags(ctx, r, fs)
}, },
Args: tree.Args{ Args: tree.Args{
{ {
@ -131,174 +127,119 @@ func NewCommand(l log.Logger, kubectl *kubectl.Kubectl) *Command {
{ {
Name: "help", Name: "help",
Description: "Help about any command", Description: "Help about any command",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "history", Name: "history",
Description: "Fetch release history", Description: "Fetch release history",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "install", Name: "install",
Description: "Install a chart", Description: "Install a chart",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "lint", Name: "lint",
Description: "Examine a chart for possible issues", Description: "Examine a chart for possible issues",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "list", Name: "list",
Description: "List releases", Description: "List releases",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "package", Name: "package",
Description: "Package a chart directory into a chart archive", Description: "Package a chart directory into a chart archive",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "plugin", Name: "plugin",
Description: "Install, list, or uninstall Helm plugins", Description: "Install, list, or uninstall Helm plugins",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "pull", Name: "pull",
Description: "Download a chart from a repository and (optionally) unpack it in local directory", Description: "Download a chart from a repository and (optionally) unpack it in local directory",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "repo", Name: "repo",
Description: "Add, list, remove, update, and index chart repositories", Description: "Add, list, remove, update, and index chart repositories",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "rollback", Name: "rollback",
Description: "Roll back a release to a previous revision", Description: "Roll back a release to a previous revision",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "search", Name: "search",
Description: "Search for a keyword in charts", Description: "Search for a keyword in charts",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "show", Name: "show",
Description: "Show information of a chart", Description: "Show information of a chart",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "status", Name: "status",
Description: "Display the status of the named release", Description: "Display the status of the named release",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
allFlags(fs)
fs.Default().Bool("show-desc", false, "show description") fs.Default().Bool("show-desc", false, "show description")
return nil return allFlags(ctx, r, fs)
}, },
Execute: inst.execute, Execute: inst.execute,
}, },
{ {
Name: "template", Name: "template",
Description: "Locally render templates", Description: "Locally render templates",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "test", Name: "test",
Description: "Run tests for a release", Description: "Run tests for a release",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "uninstall", Name: "uninstall",
Description: "Uninstall a release", Description: "Uninstall a release",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "upgrade", Name: "upgrade",
Description: "Upgrade a release", Description: "Upgrade a release",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "verify", Name: "verify",
Description: "Verify that a chart at the given path has been signed and is valid", Description: "Verify that a chart at the given path has been signed and is valid",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
{ {
Name: "version", Name: "version",
Description: "Print the client version information", Description: "Print the client version information",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error { Flags: allFlags,
allFlags(fs) Execute: inst.execute,
return nil
},
Execute: inst.execute,
}, },
}, },
}, },
@ -328,7 +269,7 @@ func (c *Command) Validate(ctx context.Context, r *readline.Readline) error {
switch { switch {
case r.Args().LenIs(0): case r.Args().LenIs(0):
return errors.New("missing [CLUSTER] argument") return errors.New("missing [CLUSTER] argument")
case !c.kubectl.Cluster(r.Args().At(0)).ConfigExists(): case !c.kubectl.Cluster(r.Args().At(0)).ConfigExists(""):
return errors.New("invalid [CLUSTER] argument") return errors.New("invalid [CLUSTER] argument")
case r.Args().LenIs(1): case r.Args().LenIs(1):
return errors.New("missing [CMD] argument") return errors.New("missing [CMD] argument")
@ -350,12 +291,22 @@ func (c *Command) Help(ctx context.Context, r *readline.Readline) string {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
func (c *Command) execute(ctx context.Context, r *readline.Readline) error { func (c *Command) execute(ctx context.Context, r *readline.Readline) error {
fs := r.FlagSets().Default()
ifs := r.FlagSets().Internal()
cluster, args := c.kubectl.Cluster(r.Args().At(0)), r.Args()[1:] cluster, args := c.kubectl.Cluster(r.Args().At(0)), r.Args()[1:]
profile, err := ifs.GetString("profile")
if err != nil {
return err
}
fmt.Println(args)
return shell.New(ctx, c.l, "helm"). return shell.New(ctx, c.l, "helm").
Args(args...). Args(args...).
Args(r.Flags()...). Args(fs.Visited().Args()...).
Args(r.AdditionalArgs()...). Args(r.AdditionalArgs()...).
Env(cluster.Env()). Args(r.AdditionalFlags()...).
Env(cluster.Env(profile)).
Run() Run()
} }

View File

@ -36,6 +36,15 @@ func NewCommand(l log.Logger, kubectl *kubectl.Kubectl) *Command {
Suggest: inst.completeClusters, Suggest: inst.completeClusters,
}, },
}, },
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
if r.Args().HasIndex(0) {
fs.Internal().String("profile", "", "Profile to use.")
if err := fs.Internal().SetValues("profile", inst.kubectl.Cluster(r.Args().At(0)).Profiles(ctx)...); err != nil {
return err
}
}
return nil
},
Execute: inst.execute, Execute: inst.execute,
}) })
@ -71,9 +80,16 @@ func (c *Command) Help(ctx context.Context, r *readline.Readline) string {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
func (c *Command) execute(ctx context.Context, r *readline.Readline) error { func (c *Command) execute(ctx context.Context, r *readline.Readline) error {
ifs := r.FlagSets().Internal()
profile, err := ifs.GetString("profile")
if err != nil {
return err
}
return shell.New(ctx, c.l, "kube-prompt"). return shell.New(ctx, c.l, "kube-prompt").
Args(r.AdditionalArgs()...). Args(r.AdditionalArgs()...).
Env(c.kubectl.Cluster(r.Args().At(0)).Env()). Env(c.kubectl.Cluster(r.Args().At(0)).Env(profile)).
Run() Run()
} }

View File

@ -41,32 +41,54 @@ func (c *Cluster) String() string {
return c.name return c.name
} }
func (c *Cluster) Env() string { func (c *Cluster) Env(profile string) string {
return fmt.Sprintf("KUBECONFIG=%s", c.Config()) return fmt.Sprintf("KUBECONFIG=%s", c.Config(profile))
} }
func (c *Cluster) Config() string { func (c *Cluster) Config(profile string) string {
if profile != "" {
return env.Path(c.kubectl.cfg.ConfigPath, profile, c.Name()+".yaml")
}
return env.Path(c.kubectl.cfg.ConfigPath, c.Name()+".yaml") return env.Path(c.kubectl.cfg.ConfigPath, c.Name()+".yaml")
} }
func (c *Cluster) ConfigExists() bool { func (c *Cluster) ConfigExists(profile string) bool {
if _, err := os.Stat(c.Config()); err == nil { if _, err := os.Stat(c.Config(profile)); err == nil {
return true return true
} }
return false return false
} }
func (c *Cluster) DeleteConfig() error { func (c *Cluster) DeleteConfig(profile string) error {
if !c.ConfigExists() { if !c.ConfigExists(profile) {
return nil return nil
} }
return os.Remove(c.Config()) return os.Remove(c.Config(profile))
} }
//nolint:forcetypeassert //nolint:forcetypeassert
func (c *Cluster) Namespaces(ctx context.Context) []string { func (c *Cluster) Profiles(ctx context.Context) []string {
return c.kubectl.cache.Get(c.name+"-namespaces", func() any { return c.kubectl.cache.Get("profiles", func() any {
if sh, err := c.shell(ctx, files, err := os.ReadDir(c.kubectl.cfg.ConfigPath)
if err != nil {
c.l.Debug(err.Error())
return []string{}
}
ret := []string{}
for _, f := range files {
if f.IsDir() && !strings.HasPrefix(f.Name(), ".") {
ret = append(ret, f.Name())
}
}
return ret
}).([]string)
}
//nolint:forcetypeassert
func (c *Cluster) Namespaces(ctx context.Context, profile string) []string {
return c.kubectl.cache.Get(profile+"-"+c.name+"-namespaces", func() any {
if sh, err := c.shell(ctx, profile,
"get", "namespaces", "get", "namespaces",
"-o", "jsonpath='{.items[*].metadata.name}'", "-o", "jsonpath='{.items[*].metadata.name}'",
); err != nil { ); err != nil {
@ -82,9 +104,9 @@ func (c *Cluster) Namespaces(ctx context.Context) []string {
} }
//nolint:forcetypeassert //nolint:forcetypeassert
func (c *Cluster) Pods(ctx context.Context, namespace string) []string { func (c *Cluster) Pods(ctx context.Context, profile, namespace string) []string {
return c.kubectl.cache.Get(c.name+"-"+namespace+"-pods", func() any { return c.kubectl.cache.Get(profile+"-"+c.name+"-"+namespace+"-pods", func() any {
if sh, err := c.shell(ctx, if sh, err := c.shell(ctx, profile,
"get", "pods", "get", "pods",
"-n", namespace, "-n", namespace,
"-o", "jsonpath='{.items[*].metadata.name}'", "-o", "jsonpath='{.items[*].metadata.name}'",
@ -104,7 +126,7 @@ func (c *Cluster) Pods(ctx context.Context, namespace string) []string {
// ~ Private methods // ~ Private methods
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
func (c *Cluster) shell(ctx context.Context, args ...string) (*shell.Shell, error) { func (c *Cluster) shell(ctx context.Context, profile string, args ...string) (*shell.Shell, error) {
sh := shell.New(ctx, c.l, "kubectl").Args(args...) sh := shell.New(ctx, c.l, "kubectl").Args(args...)
if c.kubectl.authTokenProvider != nil { if c.kubectl.authTokenProvider != nil {
if token, err := c.kubectl.authTokenProvider(ctx, c.Name()); err != nil { if token, err := c.kubectl.authTokenProvider(ctx, c.Name()); err != nil {
@ -113,5 +135,6 @@ func (c *Cluster) shell(ctx context.Context, args ...string) (*shell.Shell, erro
sh.Args("--token", token) sh.Args("--token", token)
} }
} }
return sh.Env(c.Env()), nil
return sh.Env(c.Env(profile)), nil
} }

View File

@ -7,13 +7,13 @@ import (
"github.com/foomo/posh/pkg/prompt/check" "github.com/foomo/posh/pkg/prompt/check"
) )
func SessionChecker(p *OnePassword) check.Checker { func AuthChecker(p *OnePassword) check.Checker {
return func(ctx context.Context, l log.Logger) check.Info { return func(ctx context.Context, l log.Logger) check.Info {
name := "1Password: Session" name := "1Password"
if ok, _ := p.Session(); ok { if ok, _ := p.IsAuthenticated(); ok {
return check.NewSuccessInfo(name, "Signed in") return check.NewSuccessInfo(name, "Authenticated")
} else { } else {
return check.NewFailureInfo(name, "Run `op signin` to sign into 1password") return check.NewFailureInfo(name, "Run `op auth` to sign into 1password")
} }
} }
} }

View File

@ -42,12 +42,12 @@ func NewCommand(l log.Logger, op *OnePassword, opts ...CommandOption) (*Command,
inst.commandTree = tree.New(&tree.Node{ inst.commandTree = tree.New(&tree.Node{
Name: "op", Name: "op",
Description: "Execute 1Password commands", Description: "Execute 1Password commands",
Execute: inst.signin, Execute: inst.auth,
Nodes: tree.Nodes{ Nodes: tree.Nodes{
{ {
Name: "signin", Name: "auth",
Description: "Sign into your account", Description: "Sign into your account",
Execute: inst.signin, Execute: inst.auth,
}, },
{ {
Name: "get", Name: "get",
@ -125,8 +125,8 @@ func (c *Command) register(ctx context.Context, r *readline.Readline) error {
Wait() Wait()
} }
func (c *Command) signin(ctx context.Context, r *readline.Readline) error { func (c *Command) auth(ctx context.Context, r *readline.Readline) error {
if ok, _ := c.op.Session(); ok { if ok, _ := c.op.IsAuthenticated(); ok {
c.l.Info("Already signed in") c.l.Info("Already signed in")
return nil return nil
} else if err := c.op.SignIn(ctx); err != nil { } else if err := c.op.SignIn(ctx); err != nil {

View File

@ -85,7 +85,7 @@ func New(l log.Logger, cache cache.Cache, opts ...Option) (*OnePassword, error)
// ~ Public methods // ~ Public methods
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
func (op *OnePassword) Session() (bool, error) { func (op *OnePassword) IsAuthenticated() (bool, error) {
var sessChanged bool var sessChanged bool
sess := os.Getenv("OP_SESSION_" + op.cfg.Account) sess := os.Getenv("OP_SESSION_" + op.cfg.Account)
op.isSignedInLock.Lock() op.isSignedInLock.Lock()
@ -127,7 +127,7 @@ func (op *OnePassword) Session() (bool, error) {
} }
func (op *OnePassword) SignIn(ctx context.Context) error { func (op *OnePassword) SignIn(ctx context.Context) error {
if ok, _ := op.Session(); ok { if ok, _ := op.IsAuthenticated(); ok {
return nil return nil
} }
@ -189,7 +189,7 @@ func (op *OnePassword) Get(ctx context.Context, secret Secret) (string, error) {
return strings.ReplaceAll(strings.TrimSpace(value), "\\n", "\n"), nil return strings.ReplaceAll(strings.TrimSpace(value), "\\n", "\n"), nil
} }
} else { } else {
if ok, _ := op.Session(); !ok { if ok, _ := op.IsAuthenticated(); !ok {
return "", ErrNotSignedIn return "", ErrNotSignedIn
} else if fields := op.clientGet(ctx, secret.Vault, secret.Item); len(fields) == 0 { } else if fields := op.clientGet(ctx, secret.Vault, secret.Item); len(fields) == 0 {
return "", fmt.Errorf("could not find secret '%s' '%s'", secret.Vault, secret.Item) return "", fmt.Errorf("could not find secret '%s' '%s'", secret.Vault, secret.Item)
@ -209,7 +209,7 @@ func (op *OnePassword) GetDocument(ctx context.Context, secret Secret) (string,
return value, nil return value, nil
} }
} else { } else {
if ok, _ := op.Session(); !ok { if ok, _ := op.IsAuthenticated(); !ok {
return "", ErrNotSignedIn return "", ErrNotSignedIn
} else if value := op.clientGetDoument(ctx, secret.Vault, secret.Item); len(value) == 0 { } else if value := op.clientGetDoument(ctx, secret.Vault, secret.Item); len(value) == 0 {
return "", fmt.Errorf("could not find document '%s' '%s'", secret.Vault, secret.Item) return "", fmt.Errorf("could not find document '%s' '%s'", secret.Vault, secret.Item)
@ -220,7 +220,7 @@ func (op *OnePassword) GetDocument(ctx context.Context, secret Secret) (string,
} }
func (op *OnePassword) GetOnetimePassword(ctx context.Context, account, uuid string) (string, error) { func (op *OnePassword) GetOnetimePassword(ctx context.Context, account, uuid string) (string, error) {
if ok, _ := op.Session(); !ok { if ok, _ := op.IsAuthenticated(); !ok {
return "", ErrNotSignedIn return "", ErrNotSignedIn
} }
@ -421,7 +421,7 @@ func (op *OnePassword) watch() {
if v, ok := op.watching[op.cfg.Account]; !ok || !v { if v, ok := op.watching[op.cfg.Account]; !ok || !v {
go func() { go func() {
for { for {
if ok, err := op.Session(); err != nil { if ok, err := op.IsAuthenticated(); err != nil {
op.l.Warnf("\n1password session keep alive failed for '%s' (%s)", op.cfg.Account, err.Error()) op.l.Warnf("\n1password session keep alive failed for '%s' (%s)", op.cfg.Account, err.Error())
op.watching[op.cfg.Account] = false op.watching[op.cfg.Account] = false
return return

View File

@ -2,9 +2,9 @@ package licensefinder
import ( import (
"context" "context"
"os"
"os/exec" "os/exec"
"path" "path"
"sort"
"strings" "strings"
"github.com/foomo/posh/pkg/cache" "github.com/foomo/posh/pkg/cache"
@ -15,6 +15,8 @@ import (
"github.com/foomo/posh/pkg/shell" "github.com/foomo/posh/pkg/shell"
"github.com/foomo/posh/pkg/util/files" "github.com/foomo/posh/pkg/util/files"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/samber/lo"
"github.com/spf13/viper"
) )
type ( type (
@ -49,11 +51,11 @@ func CommandWithConfigKey(v string) CommandOption {
// ~ Constructor // ~ Constructor
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
func NewCommand(l log.Logger, cache cache.Cache, opts ...CommandOption) *Command { func NewCommand(l log.Logger, cache cache.Cache, opts ...CommandOption) (*Command, error) {
inst := &Command{ inst := &Command{
l: l.Named("licensefinder"), l: l.Named("licensefinder"),
name: "licensefinder", name: "licensefinder",
configKey: "licensefinder", configKey: "licenseFinder",
cache: cache.Get("licensefinder"), cache: cache.Get("licensefinder"),
} }
for _, opt := range opts { for _, opt := range opts {
@ -61,77 +63,82 @@ func NewCommand(l log.Logger, cache cache.Cache, opts ...CommandOption) *Command
opt(inst) opt(inst)
} }
} }
if err := viper.UnmarshalKey(inst.configKey, &inst.cfg); err != nil {
return nil, err
}
addNode := tree.Node{ nameArg := &tree.Arg{
Name: "add", Name: "name",
Args: tree.Args{{Name: "name"}}, Description: "Name of the license",
Description: "Add entry",
Execute: inst.execute,
}
listNode := tree.Node{
Name: "list",
Description: "List entry",
Execute: inst.execute,
}
removeNode := tree.Node{
Name: "remove",
Args: tree.Args{{Name: "name"}},
Description: "Remove entry",
Execute: inst.execute,
} }
inst.commandTree = tree.New(&tree.Node{ inst.commandTree = tree.New(&tree.Node{
Name: inst.name, Name: inst.name,
Description: "Run license finder", Description: "List unapproved dependencies",
Execute: inst.execute, Execute: inst.actionItems,
Nodes: tree.Nodes{ Nodes: tree.Nodes{
{ {
Name: "restricted_licenses", Name: "report",
Description: "Manage restricted licenses", Description: "Print a report of the project's dependencies",
Execute: inst.report,
},
{
Name: "add",
Description: "Add licenses or dependencies",
Nodes: tree.Nodes{ Nodes: tree.Nodes{
&addNode, {
&listNode, Name: "permitted",
&removeNode, Description: "Add permitted licenses",
Args: tree.Args{nameArg},
Execute: inst.addPermitted,
},
{
Name: "ignored",
Description: "Add ignored dependencies",
Args: tree.Args{nameArg},
Execute: inst.addIgnored,
},
}, },
}, },
{ {
Name: "ignored_dependencies", Name: "list",
Description: "Manage ignored dependencies", Description: "List licenses or dependencies",
Nodes: tree.Nodes{ Nodes: tree.Nodes{
&addNode, {
&listNode, Name: "permitted",
&removeNode, Description: "Add permitted licenses",
Execute: inst.listPermitted,
},
{
Name: "ignored",
Description: "List ignored dependencies",
Args: tree.Args{nameArg},
Execute: inst.listIgnored,
},
}, },
}, },
{ {
Name: "permitted_licenses", Name: "remove",
Description: "Manage permitted licenses", Description: "Remove licenses or dependencies",
Nodes: tree.Nodes{ Nodes: tree.Nodes{
&addNode, {
&listNode, Name: "permitted",
&removeNode, Description: "Add permitted licenses",
}, Args: tree.Args{nameArg},
}, Execute: inst.removePermitted,
{ },
Name: "approvals", {
Description: "Manage approvals", Name: "ignored",
Nodes: tree.Nodes{ Description: "Remove ignored dependencies",
&addNode, Args: tree.Args{nameArg},
&removeNode, Execute: inst.removeIgnored,
}, },
},
{
Name: "licenses",
Description: "Manage licenses",
Nodes: tree.Nodes{
&addNode,
&removeNode,
}, },
}, },
}, },
}) })
return inst return inst, nil
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -162,17 +169,6 @@ $ brew update
$ brew install licensefinder $ brew install licensefinder
`) `)
} }
switch {
case r.Args().LenIs(0):
return nil
case r.Args().LenGt(1):
return errors.New("too many arguments")
}
if info, err := os.Stat(r.Args().At(0)); err != nil || info.IsDir() {
return errors.New("invalid [path] parameter")
}
return nil return nil
} }
@ -188,31 +184,70 @@ func (c *Command) Help(ctx context.Context, r *readline.Readline) string {
// ~ Private methods // ~ Private methods
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
func (c *Command) execute(ctx context.Context, r *readline.Readline) error { func (c *Command) addPermitted(ctx context.Context, r *readline.Readline) error {
var paths []string return c.execute(ctx, r, append([]string{"permitted_licenses", "add"}, r.Args().From(2)...)...)
args := []string{ }
"--log-directory=" + c.cfg.LogPath,
"--decisions_file=" + c.cfg.DecisionsPath, func (c *Command) listPermitted(ctx context.Context, r *readline.Readline) error {
} return c.execute(ctx, r, "permitted_licenses", "list")
if r.Args().LenIs(0) { }
paths = append(paths, c.paths(ctx, "go.sum")...)
paths = append(paths, c.paths(ctx, "yarn.lock")...) func (c *Command) removePermitted(ctx context.Context, r *readline.Readline) error {
args = append(args, "--aggregate_paths="+strings.Join(paths, " ")) return c.execute(ctx, r, append([]string{"permitted_licenses", "remove"}, r.Args().From(2)...)...)
} }
func (c *Command) addIgnored(ctx context.Context, r *readline.Readline) error {
return c.execute(ctx, r, append([]string{"ignored_dependencies", "add"}, r.Args().From(2)...)...)
}
func (c *Command) listIgnored(ctx context.Context, r *readline.Readline) error {
return c.execute(ctx, r, "ignored_dependencies", "list")
}
func (c *Command) removeIgnored(ctx context.Context, r *readline.Readline) error {
return c.execute(ctx, r, append([]string{"ignored_dependencies", "remove"}, r.Args().From(2)...)...)
}
func (c *Command) actionItems(ctx context.Context, r *readline.Readline) error {
return c.execute(ctx, r, "action_items", c.aggregatePaths(ctx))
}
func (c *Command) report(ctx context.Context, r *readline.Readline) error {
return c.execute(ctx, r, "report", c.aggregatePaths(ctx))
}
func (c *Command) execute(ctx context.Context, r *readline.Readline, args ...string) error {
return shell.New(ctx, c.l, "license_finder"). return shell.New(ctx, c.l, "license_finder").
Args(args...). Args(args...).
Args(r.Args()...). Args(
"--log-directory="+c.cfg.LogPath,
"--decisions-file="+c.cfg.DecisionsPath,
).
Args(r.Flags()...). Args(r.Flags()...).
Args(r.AdditionalArgs()...). Args(r.AdditionalArgs()...).
Args(r.AdditionalFlags()...).
Run() Run()
} }
func (c *Command) aggregatePaths(ctx context.Context) string {
var paths []string
paths = append(paths, c.paths(ctx, "go.sum")...)
paths = append(paths, c.paths(ctx, "yarn.lock")...)
paths = lo.Uniq(paths)
sort.Strings(paths)
c.l.Info("Aggregating liceses from:")
for _, value := range paths {
c.l.Info("└ " + value)
}
return "--aggregate_paths=" + strings.Join(paths, " ")
}
//nolint:forcetypeassert //nolint:forcetypeassert
func (c *Command) paths(ctx context.Context, filename string) []string { func (c *Command) paths(ctx context.Context, filename string) []string {
return c.cache.Get("paths-"+filename, func() any { return c.cache.Get("paths-"+filename, func() any {
if value, err := files.Find(ctx, ".", filename); err != nil { if value, err := files.Find(ctx, ".", filename, files.FindWithIgnore(`^\.`, "vendor", "node_modules")); err != nil {
c.l.Debug("failed to walk files", err.Error()) c.l.Debug("failed to walk files", err.Error())
return nil return []string{}
} else { } else {
for i, s := range value { for i, s := range value {
value[i] = path.Dir(s) value[i] = path.Dir(s)

View File

@ -69,6 +69,12 @@ func NewCommand(l log.Logger, kubectl *kubectl.Kubectl, squadron *squadron.Squad
fs.Default().String("selector", "", "Selector (label query) to filter on. If present, default to \".*\" for the pod-query.") fs.Default().String("selector", "", "Selector (label query) to filter on. If present, default to \".*\" for the pod-query.")
fs.Default().String("since", "", "Return logs newer than a relative duration like 5s, 2m, or 3h. Defaults to 48h") fs.Default().String("since", "", "Return logs newer than a relative duration like 5s, 2m, or 3h. Defaults to 48h")
fs.Default().String("tail", "", "The number of lines from the end of the logs to show. Defaults to -1, showing all logs. (default -1)") fs.Default().String("tail", "", "The number of lines from the end of the logs to show. Defaults to -1, showing all logs. (default -1)")
fs.Internal().String("profile", "", "Profile to use.")
if r.Args().HasIndex(0) {
if err := fs.Internal().SetValues("profile", inst.kubectl.Cluster(r.Args().At(0)).Profiles(ctx)...); err != nil {
return err
}
}
return nil return nil
}, },
Args: tree.Args{ Args: tree.Args{
@ -124,9 +130,16 @@ func (c *Command) Help(ctx context.Context, r *readline.Readline) string {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
func (c *Command) execute(ctx context.Context, r *readline.Readline) error { func (c *Command) execute(ctx context.Context, r *readline.Readline) error {
ifs := r.FlagSets().Internal()
cluster, fleet, squad, unit := r.Args().At(0), r.Args().At(1), r.Args().At(2), r.Args().At(3) cluster, fleet, squad, unit := r.Args().At(0), r.Args().At(1), r.Args().At(2), r.Args().At(3)
profile, err := ifs.GetString("profile")
if err != nil {
return err
}
return shell.New(ctx, c.l, "stern"). return shell.New(ctx, c.l, "stern").
Env(c.kubectl.Cluster(cluster).Env()). Env(c.kubectl.Cluster(cluster).Env(profile)).
Args("--namespace", c.namespaceFn(cluster, fleet, squad)). Args("--namespace", c.namespaceFn(cluster, fleet, squad)).
Args("--selector", "\"app.kubernetes.io/name="+squad+"-"+unit+"\""). Args("--selector", "\"app.kubernetes.io/name="+squad+"-"+unit+"\"").
Args(r.AdditionalArgs()...). Args(r.AdditionalArgs()...).
@ -152,6 +165,7 @@ func (c *Command) completeSquadrons(ctx context.Context, t tree.Root, r *readlin
return suggests.List(value) return suggests.List(value)
} }
} }
func (c *Command) completeSquadronUnits(ctx context.Context, t tree.Root, r *readline.Readline) []goprompt.Suggest { func (c *Command) completeSquadronUnits(ctx context.Context, t tree.Root, r *readline.Readline) []goprompt.Suggest {
cluster, fleet, squad := r.Args().At(0), r.Args().At(1), r.Args().At(2) cluster, fleet, squad := r.Args().At(0), r.Args().At(1), r.Args().At(2)
if value, err := c.squadron.ListUnits(ctx, squad, cluster, fleet, true); err != nil { if value, err := c.squadron.ListUnits(ctx, squad, cluster, fleet, true); err != nil {

View File

@ -195,17 +195,21 @@ func (c *Command) execute(ctx context.Context, r *readline.Readline) error {
if log.MustGet(ifs.GetBool("debug"))(c.l) { if log.MustGet(ifs.GetBool("debug"))(c.l) {
envs = append(envs, fmt.Sprintf("debug=%s", "true")) envs = append(envs, fmt.Sprintf("debug=%s", "true"))
} }
if log.MustGet(ifs.GetBool("headless"))(c.l) { if log.MustGet(ifs.GetBool("headless"))(c.l) {
envs = append(envs, fmt.Sprintf("HEADLESS=%s", "true")) envs = append(envs, fmt.Sprintf("HEADLESS=%s", "true"))
} }
if log.MustGet(ifs.GetBool("ci"))(c.l) { if log.MustGet(ifs.GetBool("ci"))(c.l) {
envs = append(envs, fmt.Sprintf("E2E_ENV=%s", "ci")) envs = append(envs, fmt.Sprintf("E2E_ENV=%s", "ci"))
} else { } else {
envs = append(envs, fmt.Sprintf("E2E_ENV=%s", "chromium")) envs = append(envs, fmt.Sprintf("E2E_ENV=%s", "chromium"))
} }
if value := log.MustGet(ifs.GetString("scenario"))(c.l); value != "" { if value := log.MustGet(ifs.GetString("scenario"))(c.l); value != "" {
envs = append(envs, fmt.Sprintf("SCENARIOS=%s", strings.Trim(value, "\""))) envs = append(envs, fmt.Sprintf("SCENARIOS=%s", strings.Trim(value, "\"")))
} }
if value := log.MustGet(ifs.GetString("tag"))(c.l); value != "" { if value := log.MustGet(ifs.GetString("tag"))(c.l); value != "" {
args = append(args, "--cucumberOpts.tagExpression", "'"+strings.Trim(value, "\"")+"'") args = append(args, "--cucumberOpts.tagExpression", "'"+strings.Trim(value, "\"")+"'")
} }