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
6 changes: 1 addition & 5 deletions cmd/environments/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,7 @@ func runGet(
return errors.NewError(output)
}

output, err := output.CmdOutputSingular(
viper.GetString(cliflags.OutputFlag),
response,
output.SingularPlaintextOutputFn,
)
output, err := output.CmdOutput("get", viper.GetString(cliflags.OutputFlag), response)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to know if the plaintext output should include a success message, so we pass in this value.

if err != nil {
return errors.NewError(err.Error())
}
Expand Down
6 changes: 1 addition & 5 deletions cmd/flags/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,7 @@ func runCreate(client flags.Client) func(*cobra.Command, []string) error {
return errors.NewError(output)
}

output, err := output.CmdOutputCreate(
viper.GetString(cliflags.OutputFlag),
response,
output.SingularPlaintextOutputFn,
)
output, err := output.CmdOutput("create", viper.GetString(cliflags.OutputFlag), response)
if err != nil {
return errors.NewError(err.Error())
}
Expand Down
6 changes: 1 addition & 5 deletions cmd/flags/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,7 @@ func runGet(client flags.Client) func(*cobra.Command, []string) error {
return errors.NewError(output)
}

output, err := output.CmdOutputSingular(
viper.GetString(cliflags.OutputFlag),
response,
output.SingularPlaintextOutputFn,
)
output, err := output.CmdOutput("get", viper.GetString(cliflags.OutputFlag), response)
if err != nil {
return errors.NewError(err.Error())
}
Expand Down
6 changes: 1 addition & 5 deletions cmd/flags/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,7 @@ func runUpdate(client flags.Client) func(*cobra.Command, []string) error {
return errors.NewError(output)
}

output, err := output.CmdOutputUpdate(
viper.GetString(cliflags.OutputFlag),
response,
output.SingularPlaintextOutputFn,
)
output, err := output.CmdOutput("update", viper.GetString(cliflags.OutputFlag), response)
if err != nil {
return errors.NewError(err.Error())
}
Expand Down
6 changes: 1 addition & 5 deletions cmd/members/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,7 @@ func runCreate(client members.Client) func(*cobra.Command, []string) error {
return errors.NewError(output)
}

output, err := output.CmdOutputSingular(
viper.GetString(cliflags.OutputFlag),
response,
output.SingularPlaintextOutputFn,
)
output, err := output.CmdOutput("create", viper.GetString(cliflags.OutputFlag), response)
if err != nil {
return errors.NewError(err.Error())
}
Expand Down
6 changes: 1 addition & 5 deletions cmd/members/invite.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,7 @@ func runInvite(client members.Client) func(*cobra.Command, []string) error {
return errors.NewError(output)
}

output, err := output.CmdOutputMultiple(
viper.GetString(cliflags.OutputFlag),
response,
output.MultipleEmailPlaintextOutputFn,
)
output, err := output.CmdOutput("create", viper.GetString(cliflags.OutputFlag), response)
if err != nil {
return errors.NewError(err.Error())
}
Expand Down
6 changes: 1 addition & 5 deletions cmd/projects/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,7 @@ func runCreate(client projects.Client) func(*cobra.Command, []string) error {
return errors.NewError(output)
}

output, err := output.CmdOutputSingular(
viper.GetString(cliflags.OutputFlag),
response,
output.SingularPlaintextOutputFn,
)
output, err := output.CmdOutput("create", viper.GetString(cliflags.OutputFlag), response)
if err != nil {
return errors.NewError(err.Error())
}
Expand Down
6 changes: 1 addition & 5 deletions cmd/projects/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,7 @@ func runList(client projects.Client) func(*cobra.Command, []string) error {
return errors.NewError(output)
}

output, err := output.CmdOutputMultiple(
viper.GetString(cliflags.OutputFlag),
response,
output.MultiplePlaintextOutputFn,
)
output, err := output.CmdOutput("list", viper.GetString(cliflags.OutputFlag), response)
if err != nil {
return errors.NewError(err.Error())
}
Expand Down
4 changes: 2 additions & 2 deletions internal/members/members.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ func (c MembersClient) Create(ctx context.Context, accessToken string, baseURI s
if err != nil {
return nil, errors.NewLDAPIError(err)
}
memberJson, err := json.Marshal(members.Items)
membersJson, err := json.Marshal(members)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated this for consistency with other responses for multiple resources.

if err != nil {
return nil, err
}

return memberJson, nil
return membersJson, nil
}
58 changes: 3 additions & 55 deletions internal/output/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,6 @@ type resources struct {
Items []resource `json:"items"`
}

// resourcesBare is for responses that return a list of resources at the top level of the response,
// not as a value of an "items" property.
type resourcesBare []resource

// CmdOutputSingular builds a command response based on the flag the user provided and the shape of
// the input. The expected shape is a single JSON object.
func CmdOutputSingular(outputKind string, input []byte, fn PlaintextOutputFn) (string, error) {
Expand All @@ -73,67 +69,19 @@ func CmdOutputSingular(outputKind string, input []byte, fn PlaintextOutputFn) (s
return "", err
}

return outputFromKind(outputKind, "", SingularOutputter{
outputFn: fn,
resource: r,
resourceJSON: input,
})
}

// CmdOutputCreate builds a command response based on the flag the user provided and the shape of
// the input with a successfully created message. The expected shape is a single JSON object.
func CmdOutputCreate(outputKind string, input []byte, fn PlaintextOutputFn) (string, error) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed these to have a single CmdOutput function so it's simpler for dynamic resource commands.

return cmdOutputWithMessage(outputKind, "Successfully created ", input, fn)
}

// CmdOutputUpdate builds a command response based on the flag the user provided and the shape of
// the input with a successfully created message. The expected shape is a single JSON object.
func CmdOutputUpdate(outputKind string, input []byte, fn PlaintextOutputFn) (string, error) {
return cmdOutputWithMessage(outputKind, "Successfully updated ", input, fn)
}

func cmdOutputWithMessage(outputKind string, message string, input []byte, fn PlaintextOutputFn) (string, error) {
var r resource
err := json.Unmarshal(input, &r)
if err != nil {
return "", err
}

return outputFromKind(outputKind, message, SingularOutputter{
return outputFromKind(outputKind, SingularOutputter{
outputFn: fn,
resource: r,
resourceJSON: input,
})
}

// CmdOutputMultiple builds a command response based on the flag the user provided and the shape of
// the input. The expected shape is a list of JSON objects.
func CmdOutputMultiple(outputKind string, input []byte, fn PlaintextOutputFn) (string, error) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now unused.

var r resources
err := json.Unmarshal(input, &r)
if err != nil {
// sometimes a response doesn't include each item in an "items" property
var rr resourcesBare
err := json.Unmarshal(input, &rr)
if err != nil {
return "", err
}
r.Items = rr
}

return outputFromKind(outputKind, "", MultipleOutputter{
outputFn: fn,
resources: r,
resourceJSON: input,
})
}

func outputFromKind(outputKind string, additional string, o Outputter) (string, error) {
func outputFromKind(outputKind string, o Outputter) (string, error) {
switch outputKind {
case "json":
return o.JSON(), nil
case "plaintext":
return additional + o.String(), nil
return o.String(), nil
}

return "", ErrInvalidOutputKind
Expand Down
97 changes: 0 additions & 97 deletions internal/output/output_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,100 +64,3 @@ func TestCmdOutputSingular(t *testing.T) {
})
}
}

func TestCmdOutput_WithSuccessMessage(t *testing.T) {
tests := map[string]struct {
expected string
fn func(string, []byte, output.PlaintextOutputFn) (string, error)
input string
outputKind string
}{
"when creating with json": {
expected: `{
"key": "test-key",
"name": "test-name"
}`,
fn: output.CmdOutputCreate,
input: `{
"key": "test-key",
"name": "test-name"
}`,
outputKind: "json",
},
"when creating with plaintext": {
expected: "Successfully created test-name (test-key)",
fn: output.CmdOutputCreate,
input: `{
"key": "test-key",
"name": "test-name"
}`,
outputKind: "plaintext",
},
"when updating with json": {
expected: `{
"key": "test-key",
"name": "test-name"
}`,
fn: output.CmdOutputUpdate,
input: `{
"key": "test-key",
"name": "test-name"
}`,
outputKind: "json",
},
"when updating with plaintext": {
expected: "Successfully updated test-name (test-key)",
fn: output.CmdOutputUpdate,
input: `{
"key": "test-key",
"name": "test-name"
}`,
outputKind: "plaintext",
},
}
for name, tt := range tests {
tt := tt
t.Run(name, func(t *testing.T) {
output, err := tt.fn(
tt.outputKind,
[]byte(tt.input),
output.SingularPlaintextOutputFn,
)

require.NoError(t, err)
assert.Equal(t, tt.expected, output)
})
}
}

func TestCmdOutputMultiple(t *testing.T) {
tests := map[string]struct {
expected string
fn output.PlaintextOutputFn
input string
}{
"with multiple emails not as items property": {
expected: "* test-email1 (test-id1)\n* test-email2 (test-id2)",
fn: output.MultipleEmailPlaintextOutputFn,
input: `[{"_id": "test-id1", "email": "test-email1"}, {"_id": "test-id2", "email": "test-email2"}]`,
},
"with multiple items": {
expected: "* test-name1 (test-key1)\n* test-name2 (test-key2)",
fn: output.MultiplePlaintextOutputFn,
input: `{"items": [{"key": "test-key1", "name": "test-name1"}, {"key": "test-key2", "name": "test-name2"}]}`,
},
}
for name, tt := range tests {
tt := tt
t.Run(name, func(t *testing.T) {
output, err := output.CmdOutputMultiple(
"plaintext",
[]byte(tt.input),
tt.fn,
)

require.NoError(t, err)
assert.Equal(t, tt.expected, output)
})
}
}
68 changes: 68 additions & 0 deletions internal/output/resource_output.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package output

import (
"encoding/json"
"fmt"
"strings"
)

// CmdOutput returns a response from a resource create action formatted based on the
// output flag along with an optional message based on the action.
func CmdOutput(action string, outputKind string, input []byte) (string, error) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the "do all the things" function.

if outputKind == "json" {
return string(input), nil
}

var (
maybeResource resource
maybeResources resources
isMultipleResponse bool
)

// unmarshal either a singular resource or a list of them
err := json.Unmarshal(input, &maybeResource)
_, isMultipleResponse = maybeResource["items"]
if err != nil || isMultipleResponse {
err := json.Unmarshal(input, &maybeResources)
if err != nil {
return "", err
}
}

var successMessage string
switch action {
case "create":
successMessage = "Successfully created"
case "delete":
successMessage = "Successfully deleted"
case "update":
successMessage = "Successfully updated"
default:
// no success message
}

if isMultipleResponse {
// the response could have various properties we want to show
outputFn := MultiplePlaintextOutputFn
if _, ok := maybeResources.Items[0]["email"]; ok {
outputFn = MultipleEmailPlaintextOutputFn
}

items := make([]string, 0, len(maybeResources.Items))
for _, i := range maybeResources.Items {
items = append(items, outputFn(i))
}

return plaintextOutput("\n"+strings.Join(items, "\n"), successMessage), nil
}

return plaintextOutput(SingularPlaintextOutputFn(maybeResource), successMessage), nil
}

func plaintextOutput(out string, successMessage string) string {
if successMessage != "" {
return fmt.Sprintf("%s %s", successMessage, out)
}

return out
}
Loading