Skip to content

Commit

Permalink
feat: create command to invite members (#68)
Browse files Browse the repository at this point in the history
* add members command

* add create member command and add client method

* create members client

* remove unused client

* remove spacing

* fix existing tests, add mock members client

* add tests

* remove run func

* add member create cmd tests
  • Loading branch information
k3llymariee authored Mar 26, 2024
1 parent ab854d9 commit e1a2ca5
Show file tree
Hide file tree
Showing 11 changed files with 369 additions and 17 deletions.
4 changes: 3 additions & 1 deletion cmd/cmdtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/stretchr/testify/require"

"ldcli/internal/flags"
"ldcli/internal/members"
"ldcli/internal/projects"
)

Expand All @@ -16,10 +17,11 @@ var ValidResponse = `{"valid": true}`
func CallCmd(
t *testing.T,
flagsClient *flags.MockClient,
membersClient *members.MockClient,
projectsClient *projects.MockClient,
args []string,
) ([]byte, error) {
rootCmd, err := NewRootCommand(flagsClient, projectsClient)
rootCmd, err := NewRootCommand(flagsClient, membersClient, projectsClient)
require.NoError(t, err)
b := bytes.NewBufferString("")
rootCmd.SetOut(b)
Expand Down
8 changes: 4 additions & 4 deletions cmd/flags/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestCreate(t *testing.T) {
"--projKey", "test-proj-key",
}

output, err := cmd.CallCmd(t, &client, nil, args)
output, err := cmd.CallCmd(t, &client, nil, nil, args)

require.NoError(t, err)
assert.JSONEq(t, `{"valid": true}`, string(output))
Expand All @@ -51,7 +51,7 @@ func TestCreate(t *testing.T) {
"--projKey", "test-proj-key",
}

_, err := cmd.CallCmd(t, &client, nil, args)
_, err := cmd.CallCmd(t, &client, nil, nil, args)

require.EqualError(t, err, "An error")
})
Expand All @@ -61,7 +61,7 @@ func TestCreate(t *testing.T) {
"flags", "create",
}

_, err := cmd.CallCmd(t, &flags.MockClient{}, nil, args)
_, err := cmd.CallCmd(t, &flags.MockClient{}, nil, nil, args)

assert.EqualError(t, err, `required flag(s) "accessToken", "data", "projKey" not set`)
})
Expand All @@ -75,7 +75,7 @@ func TestCreate(t *testing.T) {
"--projKey", "test-proj-key",
}

_, err := cmd.CallCmd(t, &flags.MockClient{}, nil, args)
_, err := cmd.CallCmd(t, &flags.MockClient{}, nil, nil, args)

assert.EqualError(t, err, "baseUri is invalid")
})
Expand Down
78 changes: 78 additions & 0 deletions cmd/members/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package members

import (
"context"
"encoding/json"
"fmt"
"net/url"

"github.com/spf13/cobra"
"github.com/spf13/viper"

"ldcli/internal/errors"
"ldcli/internal/members"
)

func NewCreateCmd(client members.Client) (*cobra.Command, error) {
cmd := &cobra.Command{
Use: "create",
Short: "Create a new member",
Long: "Create a new member",
PreRunE: validate,
RunE: runCreate(client),
}

cmd.Flags().StringP("data", "d", "", "Input data in JSON")
err := cmd.MarkFlagRequired("data")
if err != nil {
return nil, err
}
err = viper.BindPFlag("data", cmd.Flags().Lookup("data"))
if err != nil {
return nil, err
}

return cmd, nil
}

type inputData struct {
Email string `json:"email"`
Role string `json:"role"`
}

func runCreate(client members.Client) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {
var data inputData
// TODO: why does viper.GetString("data") not work?
err := json.Unmarshal([]byte(cmd.Flags().Lookup("data").Value.String()), &data)
if err != nil {
return err
}

response, err := client.Create(
context.Background(),
viper.GetString("accessToken"),
viper.GetString("baseUri"),
data.Email,
data.Role,
)
if err != nil {
return err
}

fmt.Fprintf(cmd.OutOrStdout(), string(response)+"\n")

return nil
}
}

// validate ensures the flags are valid before using them.
// TODO: refactor with flags & projects validate().
func validate(cmd *cobra.Command, args []string) error {
_, err := url.ParseRequestURI(viper.GetString("baseUri"))
if err != nil {
return errors.ErrInvalidBaseURI
}

return nil
}
86 changes: 86 additions & 0 deletions cmd/members/create_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package members_test

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"ldcli/cmd"
"ldcli/internal/errors"
"ldcli/internal/members"
)

func TestCreate(t *testing.T) {
mockArgs := []interface{}{
"testAccessToken",
"http://test.com",
"testemail@test.com",
"writer",
}
t.Run("with valid flags calls members API", func(t *testing.T) {
client := members.MockClient{}
client.
On("Create", mockArgs...).
Return([]byte(cmd.ValidResponse), nil)
args := []string{
"members",
"create",
"-t",
"testAccessToken",
"-u",
"http://test.com",
"-d",
`{"email": "testemail@test.com", "role": "writer"}`,
}

output, err := cmd.CallCmd(t, nil, &client, nil, args)

require.NoError(t, err)
assert.JSONEq(t, `{"valid": true}`, string(output))
})

t.Run("with an error response is an error", func(t *testing.T) {
client := members.MockClient{}
client.
On("Create", mockArgs...).
Return([]byte(`{}`), errors.NewError("An error"))
args := []string{
"members",
"create",
"-t",
"testAccessToken",
"-u",
"http://test.com",
"-d",
`{"email": "testemail@test.com", "role": "writer"}`,
}

_, err := cmd.CallCmd(t, nil, &client, nil, args)

require.EqualError(t, err, "An error")
})

t.Run("with missing required flags is an error", func(t *testing.T) {
args := []string{
"members",
"create",
}

_, err := cmd.CallCmd(t, nil, &members.MockClient{}, nil, args)

assert.EqualError(t, err, `required flag(s) "accessToken", "data" not set`)
})

t.Run("with invalid baseUri is an error", func(t *testing.T) {
args := []string{
"projects",
"create",
"--baseUri", "invalid",
}

_, err := cmd.CallCmd(t, nil, &members.MockClient{}, nil, args)

assert.EqualError(t, err, "baseUri is invalid")
})
}
25 changes: 25 additions & 0 deletions cmd/members/members.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package members

import (
"github.com/spf13/cobra"

"ldcli/internal/members"
)

func NewMembersCmd(client members.Client) (*cobra.Command, error) {
cmd := &cobra.Command{
Use: "members",
Short: "Make requests (create/invite) on members",
Long: "Make requests (create/invite) on members",
}

createCmd, err := NewCreateCmd(client)
if err != nil {
return nil, err
}

cmd.AddCommand(createCmd)

return cmd, nil

}
8 changes: 4 additions & 4 deletions cmd/projects/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func TestCreate(t *testing.T) {
`{"key": "test-key", "name": "test-name"}`,
}

output, err := cmd.CallCmd(t, nil, &client, args)
output, err := cmd.CallCmd(t, nil, nil, &client, args)

require.NoError(t, err)
assert.JSONEq(t, `{"valid": true}`, string(output))
Expand All @@ -56,7 +56,7 @@ func TestCreate(t *testing.T) {
`{"key": "test-key", "name": "test-name"}`,
}

_, err := cmd.CallCmd(t, nil, &client, args)
_, err := cmd.CallCmd(t, nil, nil, &client, args)

require.EqualError(t, err, "An error")
})
Expand All @@ -67,7 +67,7 @@ func TestCreate(t *testing.T) {
"create",
}

_, err := cmd.CallCmd(t, nil, &projects.MockClient{}, args)
_, err := cmd.CallCmd(t, nil, nil, &projects.MockClient{}, args)

assert.EqualError(t, err, `required flag(s) "accessToken", "data" not set`)
})
Expand All @@ -79,7 +79,7 @@ func TestCreate(t *testing.T) {
"--baseUri", "invalid",
}

_, err := cmd.CallCmd(t, nil, &projects.MockClient{}, args)
_, err := cmd.CallCmd(t, nil, nil, &projects.MockClient{}, args)

assert.EqualError(t, err, "baseUri is invalid")
})
Expand Down
8 changes: 4 additions & 4 deletions cmd/projects/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func TestList(t *testing.T) {
"-u", "http://test.com",
}

output, err := cmd.CallCmd(t, nil, &client, args)
output, err := cmd.CallCmd(t, nil, nil, &client, args)

require.NoError(t, err)
assert.JSONEq(t, `{"valid": true}`, string(output))
Expand All @@ -44,7 +44,7 @@ func TestList(t *testing.T) {
"-u", "http://test.com",
}

_, err := cmd.CallCmd(t, nil, &client, args)
_, err := cmd.CallCmd(t, nil, nil, &client, args)

require.EqualError(t, err, "an error")
})
Expand All @@ -54,7 +54,7 @@ func TestList(t *testing.T) {
"projects", "list",
}

_, err := cmd.CallCmd(t, nil, &projects.MockClient{}, args)
_, err := cmd.CallCmd(t, nil, nil, &projects.MockClient{}, args)

assert.EqualError(t, err, `required flag(s) "accessToken" not set`)
})
Expand All @@ -66,7 +66,7 @@ func TestList(t *testing.T) {
"-u", "invalid",
}

_, err := cmd.CallCmd(t, nil, &projects.MockClient{}, args)
_, err := cmd.CallCmd(t, nil, nil, &projects.MockClient{}, args)

assert.EqualError(t, err, "baseUri is invalid")
})
Expand Down
16 changes: 12 additions & 4 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ import (
"github.com/spf13/viper"

flagscmd "ldcli/cmd/flags"
mbrscmd "ldcli/cmd/members"
projcmd "ldcli/cmd/projects"
errs "ldcli/internal/errors"
"ldcli/internal/flags"
"ldcli/internal/members"
"ldcli/internal/projects"
)

func NewRootCommand(flagsClient flags.Client, projectsClient projects.Client) (*cobra.Command, error) {
func NewRootCommand(flagsClient flags.Client, membersClient members.Client, projectsClient projects.Client) (*cobra.Command, error) {

cmd := &cobra.Command{
Use: "ldcli",
Short: "LaunchDarkly CLI",
Expand Down Expand Up @@ -56,24 +59,29 @@ func NewRootCommand(flagsClient flags.Client, projectsClient projects.Client) (*
return nil, err
}

projectsCmd, err := projcmd.NewProjectsCmd(projectsClient)
flagsCmd, err := flagscmd.NewFlagsCmd(flagsClient)
if err != nil {
return nil, err
}
flagsCmd, err := flagscmd.NewFlagsCmd(flagsClient)
membersCmd, err := mbrscmd.NewMembersCmd(membersClient)
if err != nil {
return nil, err
}
projectsCmd, err := projcmd.NewProjectsCmd(projectsClient)
if err != nil {
return nil, err
}

cmd.AddCommand(flagsCmd)
cmd.AddCommand(membersCmd)
cmd.AddCommand(projectsCmd)
cmd.AddCommand(setupCmd)

return cmd, nil
}

func Execute() {
rootCmd, err := NewRootCommand(flags.NewClient(), projects.NewClient())
rootCmd, err := NewRootCommand(flags.NewClient(), members.NewClient(), projects.NewClient())
if err != nil {
log.Fatal(err)
}
Expand Down
Loading

0 comments on commit e1a2ca5

Please sign in to comment.