From 615299909ec157e999a4f3a4dbed868391af7fe6 Mon Sep 17 00:00:00 2001 From: Jens Feodor Nielsen Date: Tue, 10 Dec 2024 09:50:27 +0100 Subject: [PATCH] refactor root command --- cmd/root.go | 182 --------------------------------------------- cmd/root/cmd.go | 94 +++++++++++++++++++++++ cmd/root/logo.go | 18 +++++ cmd/root/prerun.go | 87 ++++++++++++++++++++++ main.go | 4 +- 5 files changed, 201 insertions(+), 184 deletions(-) delete mode 100644 cmd/root.go create mode 100644 cmd/root/cmd.go create mode 100644 cmd/root/logo.go create mode 100644 cmd/root/prerun.go diff --git a/cmd/root.go b/cmd/root.go deleted file mode 100644 index 90a6a8e1..00000000 --- a/cmd/root.go +++ /dev/null @@ -1,182 +0,0 @@ -package cmd - -import ( - "errors" - "log/slog" - "net/http" - "os" - - "numerous.com/cli/cmd/app" - "numerous.com/cli/cmd/config" - "numerous.com/cli/cmd/deletecmd" - "numerous.com/cli/cmd/deploy" - "numerous.com/cli/cmd/download" - "numerous.com/cli/cmd/errorhandling" - cmdinit "numerous.com/cli/cmd/init" - "numerous.com/cli/cmd/legacy" - "numerous.com/cli/cmd/login" - "numerous.com/cli/cmd/logout" - "numerous.com/cli/cmd/logs" - "numerous.com/cli/cmd/organization" - "numerous.com/cli/cmd/output" - "numerous.com/cli/cmd/token" - cmdversion "numerous.com/cli/cmd/version" - "numerous.com/cli/internal/auth" - "numerous.com/cli/internal/gql" - "numerous.com/cli/internal/logging" - "numerous.com/cli/internal/version" - - "github.com/spf13/cobra" -) - -var ( - ErrNotAuthorized = errors.New("not authorized") - ErrIncompatibleVersion = errors.New("incompatible version") -) - -var args = struct { - logLevel logging.Level -}{ - logLevel: logging.LevelError, -} - -var cmd = &cobra.Command{ - Use: "numerous", - Long: "\n ~~~ \n" + - " --- ~~~~~~~ \n" + - " ° ------- ~~~~~~~~~~ \n" + - " °°°° ----------- ~~~~~~~~~\n" + - " °°°°°°° ----------- ~~~~~~~~ _ _ \n" + - " °°°°°°°°°° ------- ~~~~~~~~ | \\ | | \n" + - " °°°°°°°°°°°°° ----- ~~~~~~~ | \\| |_ _ _ __ ___ ___ _ __ ___ _ _ ___\n" + - " °°°°°°°°°°°°° ----- ~~~~~~~ | . ` | | | | '_ ` _ \\ / _ \\ '__/ _ \\| | | / __|\n" + - " °°°°°°°°°°°°° ----- ~~~~ | |\\ | |_| | | | | | | __/ | | (_) | |_| \\__ \\\n" + - " °°°°°°°°°°°°° ---- ~~ |_| \\_|\\__,_|_| |_| |_|\\___|_| \\___/ \\__,_|___/\n" + - " °°°°°°°°°° --\n" + - " °°°°°°°° \n" + - " °°°°° \n" + - " °° \n" + - "", - SilenceErrors: true, - SilenceUsage: true, - PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - output.NotifyFeedbackMaybe() - - if !cmdversion.Check(version.NewService(gql.NewClient())) { - return errorhandling.ErrorAlreadyPrinted(ErrIncompatibleVersion) - } - - if !commandRequiresAuthentication(cmd.CommandPath()) { - return nil - } - - if os.Getenv("NUMEROUS_ACCESS_TOKEN") != "" { - return nil - } - - user := auth.NumerousTenantAuthenticator.GetLoggedInUserFromKeyring() - if user.CheckAuthenticationStatus() == auth.ErrUserNotLoggedIn { - output.PrintErrorLoginForCommand(cmd) - return ErrNotAuthorized - } - - if err := user.RefreshAccessToken(http.DefaultClient, auth.NumerousTenantAuthenticator); err != nil { - return err - } - - return nil - }, -} - -func commandRequiresAuthentication(invokedCommandName string) bool { - commandsWithAuthRequired := []string{ - "numerous legacy list", - "numerous legacy push", - "numerous legacy log", - "numerous organization create", - "numerous organization list", - "numerous deploy", - "numerous delete", - "numerous download", - "numerous logs", - "numerous token create", - "numerous token list", - "numerous token revoke", - "numerous app list", - "numerous app share", - "numerous app unshare", - } - - for _, cmd := range commandsWithAuthRequired { - if cmd == invokedCommandName { - return true - } - } - - return false -} - -func Execute() { - executedCmd, err := cmd.ExecuteC() - if err != nil { - if !errors.Is(err, errorhandling.ErrAlreadyPrinted) { - output.PrintError("Error: %s", "", err.Error()) - println() - executedCmd.Usage() // nolint: errcheck - } - os.Exit(1) - } -} - -func init() { - cmd.PersistentFlags().VarP(&args.logLevel, "log-level", "l", "The log level, one of \"debug\", \"info\", \"warning\", or \"error\". Defaults to \"error\".") - - cmd.AddGroup(&cobra.Group{ - Title: "Numerous App Commands:", - ID: "app-cmds", - }) - cmd.AddGroup(&cobra.Group{ - Title: "Additional Numerous Commands:", - ID: "additional-cmds", - }) - - cmd.AddCommand( - cmdinit.Cmd, - login.Cmd, - logout.Cmd, - organization.Cmd, - legacy.Cmd, - deletecmd.Cmd, - deploy.Cmd, - logs.Cmd, - download.Cmd, - token.Cmd, - cmdversion.Cmd, - app.Cmd, - config.Cmd, - - // dummy commands to display helpful messages for legacy commands - dummyLegacyCmd("push"), - dummyLegacyCmd("publish"), - dummyLegacyCmd("unpublish"), - dummyLegacyCmd("list"), - dummyLegacyCmd("log"), - ) - - cobra.OnInitialize(func() { - logOpts := &slog.HandlerOptions{Level: args.logLevel.ToSlogLevel()} - logHandler := slog.NewTextHandler(os.Stderr, logOpts) - logger := slog.New(logHandler) - slog.SetDefault(logger) - }) -} - -func dummyLegacyCmd(cmd string) *cobra.Command { - return &cobra.Command{ - Hidden: true, - Use: cmd, - Run: func(*cobra.Command, []string) { - output.NotifyCmdMoved("numerous "+cmd, "numerous legacy "+cmd) - }, - } -} diff --git a/cmd/root/cmd.go b/cmd/root/cmd.go new file mode 100644 index 00000000..f7bd45d7 --- /dev/null +++ b/cmd/root/cmd.go @@ -0,0 +1,94 @@ +package root + +import ( + "errors" + "log/slog" + "os" + + "github.com/spf13/cobra" + "numerous.com/cli/cmd/app" + "numerous.com/cli/cmd/config" + "numerous.com/cli/cmd/deletecmd" + "numerous.com/cli/cmd/deploy" + "numerous.com/cli/cmd/download" + "numerous.com/cli/cmd/errorhandling" + cmdinit "numerous.com/cli/cmd/init" + "numerous.com/cli/cmd/legacy" + "numerous.com/cli/cmd/login" + "numerous.com/cli/cmd/logout" + "numerous.com/cli/cmd/logs" + "numerous.com/cli/cmd/organization" + "numerous.com/cli/cmd/output" + "numerous.com/cli/cmd/token" + cmdversion "numerous.com/cli/cmd/version" + "numerous.com/cli/internal/logging" +) + +var args = struct { + logLevel logging.Level +}{ + logLevel: logging.LevelError, +} + +var cmd = &cobra.Command{ + Use: "numerous", + Long: logo, + SilenceErrors: true, + SilenceUsage: true, + PersistentPreRunE: prerun, +} + +func Execute() { + executedCmd, err := cmd.ExecuteC() + if err != nil { + if !errors.Is(err, errorhandling.ErrAlreadyPrinted) { + output.PrintError("Error: %s", "", err.Error()) + println() + executedCmd.Usage() // nolint: errcheck + } + os.Exit(1) + } +} + +func init() { + cmd.PersistentFlags().VarP(&args.logLevel, "log-level", "l", "The log level, one of \"debug\", \"info\", \"warning\", or \"error\". Defaults to \"error\".") + + cmd.AddGroup(&cobra.Group{ + Title: "Numerous App Commands:", + ID: "app-cmds", + }) + cmd.AddGroup(&cobra.Group{ + Title: "Additional Numerous Commands:", + ID: "additional-cmds", + }) + + cmd.AddCommand( + cmdinit.Cmd, + login.Cmd, + logout.Cmd, + organization.Cmd, + legacy.Cmd, + deletecmd.Cmd, + deploy.Cmd, + logs.Cmd, + download.Cmd, + token.Cmd, + cmdversion.Cmd, + app.Cmd, + config.Cmd, + + // dummy commands to display helpful messages for legacy commands + dummyLegacyCmd("push"), + dummyLegacyCmd("publish"), + dummyLegacyCmd("unpublish"), + dummyLegacyCmd("list"), + dummyLegacyCmd("log"), + ) + + cobra.OnInitialize(func() { + logOpts := &slog.HandlerOptions{Level: args.logLevel.ToSlogLevel()} + logHandler := slog.NewTextHandler(os.Stderr, logOpts) + logger := slog.New(logHandler) + slog.SetDefault(logger) + }) +} diff --git a/cmd/root/logo.go b/cmd/root/logo.go new file mode 100644 index 00000000..182dc4da --- /dev/null +++ b/cmd/root/logo.go @@ -0,0 +1,18 @@ +package root + +const logo = ` + ~~~ + --- ~~~~~~~ + ° ------- ~~~~~~~~~~ + °°°° ----------- ~~~~~~~~~ + °°°°°°° ----------- ~~~~~~~~ _ _ + °°°°°°°°°° ------- ~~~~~~~~ | \ | | + °°°°°°°°°°°°° ----- ~~~~~~~ | \| |_ _ _ __ ___ ___ _ __ ___ _ _ ___ + °°°°°°°°°°°°° ----- ~~~~~~~ | . ` + "`" + ` | | | | '_ ` + "`" + ` _ \ / _ \ '__/ _ \| | | / __| + °°°°°°°°°°°°° ----- ~~~~ | |\ | |_| | | | | | | __/ | | (_) | |_| \__ \ + °°°°°°°°°°°°° ---- ~~ |_| \_|\__,_|_| |_| |_|\___|_| \___/ \__,_|___/ + °°°°°°°°°° -- + °°°°°°°° + °°°°° + °° +` diff --git a/cmd/root/prerun.go b/cmd/root/prerun.go new file mode 100644 index 00000000..da772ca0 --- /dev/null +++ b/cmd/root/prerun.go @@ -0,0 +1,87 @@ +package root + +import ( + "errors" + "net/http" + "os" + + "numerous.com/cli/cmd/errorhandling" + "numerous.com/cli/cmd/output" + cmdversion "numerous.com/cli/cmd/version" + "numerous.com/cli/internal/auth" + "numerous.com/cli/internal/gql" + "numerous.com/cli/internal/version" + + "github.com/spf13/cobra" +) + +var ( + ErrNotAuthorized = errors.New("not authorized") + ErrIncompatibleVersion = errors.New("incompatible version") +) + +func prerun(cmd *cobra.Command, args []string) error { + output.NotifyFeedbackMaybe() + + if !cmdversion.Check(version.NewService(gql.NewClient())) { + return errorhandling.ErrorAlreadyPrinted(ErrIncompatibleVersion) + } + + if !commandRequiresAuthentication(cmd.CommandPath()) { + return nil + } + + if os.Getenv("NUMEROUS_ACCESS_TOKEN") != "" { + return nil + } + + user := auth.NumerousTenantAuthenticator.GetLoggedInUserFromKeyring() + if user.CheckAuthenticationStatus() == auth.ErrUserNotLoggedIn { + output.PrintErrorLoginForCommand(cmd) + return ErrNotAuthorized + } + + if err := user.RefreshAccessToken(http.DefaultClient, auth.NumerousTenantAuthenticator); err != nil { + return err + } + + return nil +} + +func commandRequiresAuthentication(invokedCommandName string) bool { + commandsWithAuthRequired := []string{ + "numerous legacy list", + "numerous legacy push", + "numerous legacy log", + "numerous organization create", + "numerous organization list", + "numerous deploy", + "numerous delete", + "numerous download", + "numerous logs", + "numerous token create", + "numerous token list", + "numerous token revoke", + "numerous app list", + "numerous app share", + "numerous app unshare", + } + + for _, cmd := range commandsWithAuthRequired { + if cmd == invokedCommandName { + return true + } + } + + return false +} + +func dummyLegacyCmd(cmd string) *cobra.Command { + return &cobra.Command{ + Hidden: true, + Use: cmd, + Run: func(*cobra.Command, []string) { + output.NotifyCmdMoved("numerous "+cmd, "numerous legacy "+cmd) + }, + } +} diff --git a/main.go b/main.go index 92c3d33e..70a03ef3 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,7 @@ package main -import "numerous.com/cli/cmd" +import "numerous.com/cli/cmd/root" func main() { - cmd.Execute() + root.Execute() }