From 667b9c92a3ff28419b1333e3d28256ebe97b8221 Mon Sep 17 00:00:00 2001 From: Martin Polden Date: Thu, 23 Nov 2023 10:52:40 +0100 Subject: Add format option to status command --- client/go/internal/cli/cmd/status.go | 63 +++++++++++++++++++++++-------- client/go/internal/cli/cmd/status_test.go | 10 ++++- 2 files changed, 55 insertions(+), 18 deletions(-) (limited to 'client/go') diff --git a/client/go/internal/cli/cmd/status.go b/client/go/internal/cli/cmd/status.go index a0602494bff..29a4a5775db 100644 --- a/client/go/internal/cli/cmd/status.go +++ b/client/go/internal/cli/cmd/status.go @@ -17,7 +17,10 @@ import ( ) func newStatusCmd(cli *CLI) *cobra.Command { - var waitSecs int + var ( + waitSecs int + format string + ) cmd := &cobra.Command{ Use: "status", Aliases: []string{ @@ -32,7 +35,8 @@ This command shows the current endpoints, and their status, of a deployed Vespa application.`, Example: `$ vespa status $ vespa status --cluster mycluster -$ vespa status --cluster mycluster --wait 600`, +$ vespa status --cluster mycluster --wait 600 +$ vepsa status --format plain --cluster mycluster`, DisableAutoGenTag: true, SilenceUsage: true, Args: cobra.MaximumNArgs(1), @@ -42,6 +46,9 @@ $ vespa status --cluster mycluster --wait 600`, if err != nil { return err } + if err := verifyFormat(format); err != nil { + return err + } waiter := cli.waiter(time.Duration(waitSecs) * time.Second) var failingContainers []*vespa.Service if cluster == "" { @@ -53,7 +60,7 @@ $ vespa status --cluster mycluster --wait 600`, return errHint(fmt.Errorf("no services exist"), "Deployment may not be ready yet", "Try 'vespa status deployment'") } for _, s := range services { - if !printServiceStatus(s, waiter, cli) { + if !printServiceStatus(s, format, waiter, cli) { failingContainers = append(failingContainers, s) } } @@ -62,7 +69,7 @@ $ vespa status --cluster mycluster --wait 600`, if err != nil { return err } - if !printServiceStatus(s, waiter, cli) { + if !printServiceStatus(s, format, waiter, cli) { failingContainers = append(failingContainers, s) } } @@ -70,9 +77,19 @@ $ vespa status --cluster mycluster --wait 600`, }, } cli.bindWaitFlag(cmd, 0, &waitSecs) + cmd.PersistentFlags().StringVarP(&format, "format", "", "human", "Output format. Must be 'human' (human-readable) or 'plain' (cluster URL only)") return cmd } +func verifyFormat(format string) error { + switch format { + case "human", "plain": + return nil + default: + return fmt.Errorf("invalid format: %s", format) + } +} + func failingServicesErr(services ...*vespa.Service) error { if len(services) == 0 { return nil @@ -89,7 +106,10 @@ func failingServicesErr(services ...*vespa.Service) error { } func newStatusDeployCmd(cli *CLI) *cobra.Command { - var waitSecs int + var ( + waitSecs int + format string + ) cmd := &cobra.Command{ Use: "deploy", Short: "Show status of the Vespa deploy service", @@ -102,18 +122,22 @@ func newStatusDeployCmd(cli *CLI) *cobra.Command { if err != nil { return err } + if err := verifyFormat(format); err != nil { + return err + } waiter := cli.waiter(time.Duration(waitSecs) * time.Second) s, err := waiter.DeployService(t) if err != nil { return err } - if !printServiceStatus(s, waiter, cli) { + if !printServiceStatus(s, format, waiter, cli) { return failingServicesErr(s) } return nil }, } cli.bindWaitFlag(cmd, 0, &waitSecs) + cmd.PersistentFlags().StringVarP(&format, "format", "", "human", "Output format. Must be 'human' (human-readable text) or 'plain' (cluster URL only)") return cmd } @@ -167,18 +191,25 @@ $ vespa status deployment -t local [session-id] --wait 600 return cmd } -func printServiceStatus(s *vespa.Service, waiter *Waiter, cli *CLI) bool { - desc := s.Description() - desc = strings.ToUpper(string(desc[0])) + string(desc[1:]) +func printServiceStatus(s *vespa.Service, format string, waiter *Waiter, cli *CLI) bool { err := s.Wait(waiter.Timeout) var sb strings.Builder - sb.WriteString(fmt.Sprintf("%s at %s is ", desc, color.CyanString(s.BaseURL))) - if err == nil { - sb.WriteString(color.GreenString("ready")) - } else { - sb.WriteString(color.RedString("not ready")) - sb.WriteString(": ") - sb.WriteString(err.Error()) + switch format { + case "human": + desc := s.Description() + desc = strings.ToUpper(string(desc[0])) + string(desc[1:]) + sb.WriteString(fmt.Sprintf("%s at %s is ", desc, color.CyanString(s.BaseURL))) + if err == nil { + sb.WriteString(color.GreenString("ready")) + } else { + sb.WriteString(color.RedString("not ready")) + sb.WriteString(": ") + sb.WriteString(err.Error()) + } + case "plain": + sb.WriteString(s.BaseURL) + default: + panic("invalid format: " + format) } fmt.Fprintln(cli.Stdout, sb.String()) return err == nil diff --git a/client/go/internal/cli/cmd/status_test.go b/client/go/internal/cli/cmd/status_test.go index 1473e39ff54..8bd8449d5a1 100644 --- a/client/go/internal/cli/cmd/status_test.go +++ b/client/go/internal/cli/cmd/status_test.go @@ -197,7 +197,7 @@ func assertStatus(expectedTarget string, args []string, t *testing.T) { t.Helper() client := &mock.HTTPClient{} clusterName := "" - for i := 0; i < 2; i++ { + for i := 0; i < 3; i++ { if isLocalTarget(args) { clusterName = "foo" mockServiceStatus(client, clusterName) @@ -216,11 +216,17 @@ func assertStatus(expectedTarget string, args []string, t *testing.T) { assert.Equal(t, expectedTarget+"/status.html", client.LastRequest.URL.String()) // Test legacy command - statusArgs = []string{"status query"} + statusArgs = []string{"status", "query"} stdout.Reset() assert.Nil(t, cli.Run(append(statusArgs, args...)...)) assert.Equal(t, prefix+" at "+expectedTarget+" is ready\n", stdout.String()) assert.Equal(t, expectedTarget+"/status.html", client.LastRequest.URL.String()) + + // Plain format + statusArgs = []string{"status", "--format=plain"} + stdout.Reset() + assert.Nil(t, cli.Run(append(statusArgs, args...)...)) + assert.Equal(t, expectedTarget+"\n", stdout.String()) } func assertDocumentStatus(target string, args []string, t *testing.T) { -- cgit v1.2.3