Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 19 additions & 15 deletions cmd/base/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,27 @@ func CheckFormatterFlags(cmdContext *CmdContext, entities map[string]entities.En
manager := cmdContext.GetManager()
formatter := cmdContext.GetOrCreateFormatter(cmd)

fieldList, err := manager.GetResolvedBoolValue(cmd, "field-list")
if err != nil {
return err
}

entity := findEntity(cmd, entities)
if entity == nil {
return fmt.Errorf("can't find entity")
}
if fieldList {
formatter.ListEntityFields(entity.GetFields())
os.Exit(0)
}

output := formatter.GetOutput()
if output == "json" || output == "yaml" {
switch output {
case "json", "yaml":
return nil
case "text":
default:
return fmt.Errorf("invalid output %q, allowed values: json, text, yaml", output)
}

tmpl := formatter.GetTemplateStr()
Expand All @@ -81,20 +99,6 @@ func CheckFormatterFlags(cmdContext *CmdContext, entities map[string]entities.En
return nil
}

fieldList, err := manager.GetResolvedBoolValue(cmd, "field-list")
if err != nil {
return err
}

entity := findEntity(cmd, entities)
if entity == nil {
return fmt.Errorf("can't find entity")
}
if fieldList {
formatter.ListEntityFields(entity.GetFields())
os.Exit(0)
}

fields, err := manager.GetResolvedStringSliceValue(cmd, "field")
if err != nil {
return err
Expand Down
10 changes: 10 additions & 0 deletions cmd/base/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,13 @@ func findEntity(cmd *cobra.Command, entities map[string]entities.EntityInterface
}
return nil
}

func UsageRun(cmd *cobra.Command, args []string) { _ = cmd.Usage() }

func NoArgs(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
helpStr := fmt.Sprintf("Run '%v --help' for usage.", cmd.CommandPath())
return fmt.Errorf("unknown command %q for %q\n%s", args[0], cmd.CommandPath(), helpStr)
}
return nil
}
10 changes: 8 additions & 2 deletions cmd/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,19 @@ func NewCmd(cmdContext *base.CmdContext) *cobra.Command {
Short: "Manage configuration",
Long: `Manage global and context-specific configurations`,
PersistentPreRunE: base.CheckEmptyContexts(cmdContext),
Args: base.NoArgs,
Run: base.UsageRun,
}

globalCmd := &cobra.Command{
Use: "global",
Use: "global",
Args: base.NoArgs,
Run: base.UsageRun,
}
contextCmd := &cobra.Command{
Use: "context",
Use: "context",
Args: base.NoArgs,
Run: base.UsageRun,
}

globalCmd.AddCommand(newUpdateCmd(cmdContext))
Expand Down
2 changes: 2 additions & 0 deletions cmd/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ func NewCmd(cmdContext *base.CmdContext) *cobra.Command {
Use: "context",
Short: "Manage contexts",
Long: `Manage authentication contexts for different API accounts`,
Args: base.NoArgs,
Run: base.UsageRun,
}

cmd.AddCommand(
Expand Down
5 changes: 2 additions & 3 deletions cmd/entities/hosts/hosts.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,8 @@ func NewCmd(cmdContext *base.CmdContext) *cobra.Command {
base.CheckFormatterFlags(cmdContext, entitiesMap),
base.CheckEmptyContexts(cmdContext),
),
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
},
Args: base.NoArgs,
Run: base.UsageRun,
}

// hosts list cmd
Expand Down
5 changes: 2 additions & 3 deletions cmd/entities/ssh-keys/ssh_keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@ func NewCmd(cmdContext *base.CmdContext) *cobra.Command {
base.CheckFormatterFlags(cmdContext, entitiesMap),
base.CheckEmptyContexts(cmdContext),
),
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
},
Args: base.NoArgs,
Run: base.UsageRun,
}

cmd.AddCommand(
Expand Down
6 changes: 5 additions & 1 deletion cmd/login/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package login

import (
"bufio"
"errors"
"fmt"
"io"
"log"
Expand Down Expand Up @@ -33,6 +34,9 @@ func NewCmd(cmdContext *base.CmdContext, clientFactory client.ClientFactory) *co
Example: srvctl login context-name`,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
if !term.IsTerminal(int(os.Stdout.Fd())) {
return errors.New("TTY required to enter the token.")
}
manager := cmdContext.GetManager()

var contextName string
Expand All @@ -41,7 +45,7 @@ Example: srvctl login context-name`,
} else {
contextName = manager.GetDefaultContextName()
if contextName == "" {
return fmt.Errorf("no contexts found")
return errors.New("no contexts found")
}
}

Expand Down
24 changes: 24 additions & 0 deletions cmd/login/login_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package login

import (
"io"
"os"
"path/filepath"
"strings"
"testing"

"github.com/creack/pty"
. "github.com/onsi/gomega"
serverscom "github.com/serverscom/serverscom-go-client/pkg"
"github.com/serverscom/srvctl/cmd/testutils"
Expand All @@ -26,6 +28,7 @@ func TestLoginCmd(t *testing.T) {
configureMock func(*mocks.MockCollection[serverscom.Host])
expectedOutput []byte
expectError bool
tty bool
}{
{
name: "login with empty token",
Expand All @@ -43,6 +46,7 @@ func TestLoginCmd(t *testing.T) {
List(gomock.Any()).
Return([]serverscom.Host{}, nil)
},
tty: true,
},
{
name: "login with force",
Expand All @@ -54,12 +58,20 @@ func TestLoginCmd(t *testing.T) {
List(gomock.Any()).
Return([]serverscom.Host{}, nil)
},
tty: true,
},
{
name: "login with invalid context name",
args: []string{"_invalid"},
expectError: true,
},
{
name: "no TTY",
args: []string{"notty"},
input: strings.NewReader("token\n"),
expectError: true,
tty: false,
},
}

mockCtrl := gomock.NewController(t)
Expand Down Expand Up @@ -92,6 +104,18 @@ func TestLoginCmd(t *testing.T) {
if tc.configureMock != nil {
tc.configureMock(collectionHandler)
}
if tc.tty {
ptmx, tty, err := pty.Open()
if err != nil {
t.Fatalf("failed to open pty: %v", err)
}
defer ptmx.Close()
defer tty.Close()

oldStdout := os.Stdout
defer func() { os.Stdout = oldStdout }()
os.Stdout = tty
}

loginCmd := NewCmd(testCmdContext, testClientFactory)

Expand Down
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func NewRootCmd(version string) *cobra.Command {
Long: `A command line interface for managing servers.com resources`,
Version: version,
PersistentPreRunE: base.InitCmdContext(cmdContext),
SilenceUsage: true,
}

// Global flags
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/serverscom/srvctl
go 1.23.0

require (
github.com/creack/pty v1.1.24
github.com/jmespath/go-jmespath v0.4.0
github.com/onsi/gomega v1.36.2
github.com/serverscom/serverscom-go-client v1.0.10
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
Expand Down
2 changes: 1 addition & 1 deletion internal/output/entities/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func mapHandler(w io.Writer, v interface{}, indent string, _ *Field) error {
return err
}

func structPVHandler(w io.Writer, v interface{}, indent string, f *Field) error {
func structPVHandler(w io.Writer, v any, indent string, f *Field) error {
if v == nil {
fmt.Fprintf(w, "\t<none>")
return nil
Expand Down
6 changes: 3 additions & 3 deletions internal/output/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func processValue(value reflect.Value, processor func(any) error) error {

switch value.Kind() {
case reflect.Slice:
for i := 0; i < value.Len(); i++ {
for i := range value.Len() {
if err := processor(value.Index(i).Interface()); err != nil {
return err
}
Expand All @@ -134,7 +134,7 @@ func (f *Formatter) formatRow(w io.Writer, item any, fields []entities.Field) er
values := make([]string, 0, len(fields))

for _, field := range fields {
fieldValue, err := utils.GetFieldValue(item, field.Path)
fieldValue, err := utils.GetFieldValue(item, field.GetPath())
if err != nil {
return err
}
Expand Down Expand Up @@ -169,7 +169,7 @@ func (f *Formatter) formatPageView(v any, entity entities.EntityInterface) error

switch value.Kind() {
case reflect.Slice:
for i := 0; i < value.Len(); i++ {
for i := range value.Len() {
if err := f.formatPageViewItem(w, value.Index(i).Interface(), orderedFields); err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion internal/output/utils/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func Humanize(input string) string {
}

// GetFieldValue returns the value of a given field for an item.
func GetFieldValue(item interface{}, jsonPath string) (interface{}, error) {
func GetFieldValue(item any, jsonPath string) (any, error) {
if jsonPath == "" || jsonPath == "." {
return item, nil
}
Expand Down
4 changes: 2 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package main

import (
"fmt"
"log"
"os"

"github.com/serverscom/srvctl/cmd"
)
Expand All @@ -19,6 +19,6 @@ func main() {
rootCmd := cmd.NewRootCmd(version)

if err := rootCmd.Execute(); err != nil {
log.Fatal(err)
os.Exit(1)
}
}
Loading