Skip to content

Commit

Permalink
feat: allow YAML output
Browse files Browse the repository at this point in the history
  • Loading branch information
phm07 committed Dec 12, 2023
1 parent 9464cc0 commit 6b99149
Show file tree
Hide file tree
Showing 26 changed files with 124 additions and 81 deletions.
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/cheggaaa/pb/v3 v3.1.4
github.com/dustin/go-humanize v1.0.1
github.com/fatih/structs v1.1.0
github.com/goccy/go-yaml v1.11.2
github.com/golang/mock v1.6.0
github.com/google/go-cmp v0.6.0
github.com/guptarohit/asciigraph v0.5.6
Expand All @@ -25,11 +26,11 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
Expand All @@ -43,6 +44,7 @@ require (
golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.6.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
22 changes: 16 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,18 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/goccy/go-yaml v1.11.2 h1:joq77SxuyIs9zzxEjgyLBugMQ9NEgTWxXfz2wVqwAaQ=
github.com/goccy/go-yaml v1.11.2/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
Expand All @@ -37,17 +45,17 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand Down Expand Up @@ -127,6 +135,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
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-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
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.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
Expand Down
19 changes: 9 additions & 10 deletions internal/cmd/all/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package all

import (
"context"
"encoding/json"
"strings"

"github.com/spf13/cobra"
Expand All @@ -21,6 +20,7 @@ import (
"github.com/hetznercloud/cli/internal/cmd/primaryip"
"github.com/hetznercloud/cli/internal/cmd/server"
"github.com/hetznercloud/cli/internal/cmd/sshkey"
"github.com/hetznercloud/cli/internal/cmd/util"
"github.com/hetznercloud/cli/internal/cmd/volume"
"github.com/hetznercloud/cli/internal/hcapi2"
"github.com/hetznercloud/cli/internal/state"
Expand Down Expand Up @@ -63,7 +63,7 @@ Listed resources are:

cmd.Flags().Bool("paid", false, "Only list resources that cost money")

output.AddFlag(cmd, output.OptionJSON())
output.AddFlag(cmd, output.OptionJSON(), output.OptionYAML())

return cmd
},
Expand Down Expand Up @@ -148,17 +148,16 @@ Listed resources are:
resources[i] = response.result
}

if outOpts.IsSet("json") {
jsonSchema := make(map[string]any)
if outOpts.IsSet("json") || outOpts.IsSet("yaml") {
schema := make(map[string]any)
for i, lc := range cmds {
jsonSchema[lc.JSONKeyGetByName] = lc.JSONSchema(resources[i])
schema[lc.JSONKeyGetByName] = lc.Schema(resources[i])
}
jsonBytes, err := json.Marshal(jsonSchema)
if err != nil {
return err
if outOpts.IsSet("json") {
return util.DescribeJSON(schema)
} else {
return util.DescribeYAML(schema)
}
cmd.Printf("%s\n", jsonBytes)
return nil
}

for i, lc := range cmds {
Expand Down
24 changes: 14 additions & 10 deletions internal/cmd/base/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (cc *CreateCmd) CobraCommand(
) *cobra.Command {
cmd := cc.BaseCobraCommand(client)

output.AddFlag(cmd, output.OptionJSON())
output.AddFlag(cmd, output.OptionJSON(), output.OptionYAML())

if cmd.Args == nil {
cmd.Args = cobra.NoArgs
Expand All @@ -46,8 +46,8 @@ func (cc *CreateCmd) CobraCommand(
cmd.RunE = func(cmd *cobra.Command, args []string) error {
outputFlags := output.FlagsForCommand(cmd)

isJson := outputFlags.IsSet("json")
if isJson {
isSchema := outputFlags.IsSet("json") || outputFlags.IsSet("yaml")
if isSchema {
cmd.SetOut(os.Stderr)
} else {
cmd.SetOut(os.Stdout)
Expand All @@ -58,19 +58,23 @@ func (cc *CreateCmd) CobraCommand(
return err
}

if isJson {
if isSchema {
bytes, _ := io.ReadAll(response.Body)

var data map[string]any
if err := json.Unmarshal(bytes, &data); err != nil {
var schema map[string]any
if err := json.Unmarshal(bytes, &schema); err != nil {
return err
}

delete(data, "action")
delete(data, "actions")
delete(data, "next_actions")
delete(schema, "action")
delete(schema, "actions")
delete(schema, "next_actions")

return util.DescribeJSON(data)
if outputFlags.IsSet("json") {
return util.DescribeJSON(schema)
} else {
return util.DescribeYAML(schema)
}
} else if resource != nil {
cc.PrintResource(ctx, client, cmd, resource)
}
Expand Down
13 changes: 9 additions & 4 deletions internal/cmd/base/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type ListCmd struct {
Fetch func(context.Context, hcapi2.Client, *pflag.FlagSet, hcloud.ListOpts, []string) ([]interface{}, error)
AdditionalFlags func(*cobra.Command)
OutputTable func(client hcapi2.Client) *output.Table
JSONSchema func([]interface{}) interface{}
Schema func([]interface{}) interface{}
}

// CobraCommand creates a command that can be registered with cobra.
Expand All @@ -45,7 +45,7 @@ func (lc *ListCmd) CobraCommand(
return lc.Run(ctx, client, cmd)
},
}
output.AddFlag(cmd, output.OptionNoHeader(), output.OptionColumns(outputColumns), output.OptionJSON())
output.AddFlag(cmd, output.OptionNoHeader(), output.OptionColumns(outputColumns), output.OptionJSON(), output.OptionYAML())
cmd.Flags().StringP("selector", "l", "", "Selector to filter by labels")
if lc.AdditionalFlags != nil {
lc.AdditionalFlags(cmd)
Expand All @@ -70,8 +70,13 @@ func (lc *ListCmd) Run(ctx context.Context, client hcapi2.Client, cmd *cobra.Com
return err
}

if outOpts.IsSet("json") {
return util.DescribeJSON(lc.JSONSchema(resources))
if outOpts.IsSet("json") || outOpts.IsSet("yaml") {
schema := lc.Schema(resources)
if outOpts.IsSet("json") {
return util.DescribeJSON(schema)
} else {
return util.DescribeYAML(schema)
}
}

cols := lc.DefaultColumns
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/certificate/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ var ListCmd = base.ListCmd{
}))
},

JSONSchema: func(resources []interface{}) interface{} {
Schema: func(resources []interface{}) interface{} {
certSchemas := make([]schema.Certificate, 0, len(resources))
for _, resource := range resources {
cert := resource.(*hcloud.Certificate)
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/datacenter/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ var ListCmd = base.ListCmd{
}))
},

JSONSchema: func(resources []interface{}) interface{} {
Schema: func(resources []interface{}) interface{} {
dcSchemas := make([]schema.Datacenter, 0, len(resources))
for _, resource := range resources {
dc := resource.(*hcloud.Datacenter)
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/firewall/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ var ListCmd = base.ListCmd{
}))
},

JSONSchema: func(resources []interface{}) interface{} {
Schema: func(resources []interface{}) interface{} {
firewallSchemas := make([]schema.Firewall, 0, len(resources))
for _, resource := range resources {
firewall := resource.(*hcloud.Firewall)
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/floatingip/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ var ListCmd = base.ListCmd{
}))
},

JSONSchema: func(resources []interface{}) interface{} {
Schema: func(resources []interface{}) interface{} {
floatingIPSchemas := make([]schema.FloatingIP, 0, len(resources))
for _, resource := range resources {
floatingIP := resource.(*hcloud.FloatingIP)
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/image/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ var ListCmd = base.ListCmd{
}))
},

JSONSchema: func(resources []interface{}) interface{} {
Schema: func(resources []interface{}) interface{} {
imageSchemas := make([]schema.Image, 0, len(resources))
for _, resource := range resources {
image := resource.(*hcloud.Image)
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/iso/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ var ListCmd = base.ListCmd{
})
},

JSONSchema: func(resources []interface{}) interface{} {
Schema: func(resources []interface{}) interface{} {
isoSchemas := make([]schema.ISO, 0, len(resources))
for _, resource := range resources {
iso := resource.(*hcloud.ISO)
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/loadbalancer/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ var ListCmd = base.ListCmd{
}))
},

JSONSchema: func(resources []interface{}) interface{} {
Schema: func(resources []interface{}) interface{} {
loadBalancerSchemas := make([]schema.LoadBalancer, 0, len(resources))
for _, resource := range resources {
loadBalancer := resource.(*hcloud.LoadBalancer)
Expand Down
14 changes: 9 additions & 5 deletions internal/cmd/loadbalancer/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ var MetricsCmd = base.Cmd{
cmd.Flags().String("start", "", "ISO 8601 timestamp")
cmd.Flags().String("end", "", "ISO 8601 timestamp")

output.AddFlag(cmd, output.OptionJSON())
output.AddFlag(cmd, output.OptionJSON(), output.OptionYAML())
return cmd
},
Run: func(ctx context.Context, client hcapi2.Client, waiter state.ActionWaiter, cmd *cobra.Command, args []string) error {
Expand Down Expand Up @@ -83,12 +83,16 @@ var MetricsCmd = base.Cmd{
return err
}
switch {
case outputFlags.IsSet("json"):
var data map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
case outputFlags.IsSet("json") || outputFlags.IsSet("yaml"):
var schema map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&schema); err != nil {
return err
}
return util.DescribeJSON(data)
if outputFlags.IsSet("json") {
return util.DescribeJSON(schema)
} else {
return util.DescribeYAML(schema)
}
default:
var keys []string
for k := range m.TimeSeries {
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/loadbalancertype/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ var ListCmd = base.ListCmd{
AddAllowedFields(hcloud.LoadBalancerType{})
},

JSONSchema: func(resources []interface{}) interface{} {
Schema: func(resources []interface{}) interface{} {
loadBalancerTypeSchemas := make([]schema.LoadBalancerType, 0, len(resources))
for _, resource := range resources {
loadBalancerType := resource.(*hcloud.LoadBalancerType)
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/location/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ var ListCmd = base.ListCmd{
AddAllowedFields(hcloud.Location{})
},

JSONSchema: func(resources []interface{}) interface{} {
Schema: func(resources []interface{}) interface{} {
locationSchemas := make([]schema.Location, 0, len(resources))
for _, resource := range resources {
location := resource.(*hcloud.Location)
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/network/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ var ListCmd = base.ListCmd{
return util.Age(network.Created, time.Now())
}))
},
JSONSchema: func(resources []interface{}) interface{} {
Schema: func(resources []interface{}) interface{} {
networkSchemas := make([]schema.Network, 0, len(resources))
for _, resource := range resources {
network := resource.(*hcloud.Network)
Expand Down
Loading

0 comments on commit 6b99149

Please sign in to comment.