Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: config management and error handling #155

Merged
merged 16 commits into from
Aug 19, 2022
Merged
Show file tree
Hide file tree
Changes from 8 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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ build
.env
.DS_Store
.idea/
.vscode/
proxies/*.yaml
proxies/*.yml
.temp
Expand All @@ -18,3 +19,5 @@ ignore/
vendor/
buf.lock
buf.yaml
resources_config
rules
9 changes: 7 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ GOVERSION := $(shell go version | cut -d ' ' -f 3 | cut -d '.' -f 2)

.PHONY: build check fmt lint test test-race vet test-cover-html help install proto
.DEFAULT_GOAL := build
PROTON_COMMIT := "1497165f2f48facb3ec6f5c5556ccd44f0a7119f"

install:
@echo "Clean up imports..."
Expand All @@ -26,8 +27,12 @@ coverage: ## print code coverage
clean :
rm -rf dist

proto:
./buf.gen.yaml && cp -R proto/odpf/shield/* proto/ && rm -Rf proto/odpf
proto: ## Generate the protobuf files
@echo " > generating protobuf from odpf/proton"
@echo " > [info] make sure correct version of dependencies are installed using 'make install'"
@buf generate https://github.com/odpf/proton/archive/${PROTON_COMMIT}.zip#strip_components=1 --template buf.gen.yaml --path odpf/shield
@cp -R proto/odpf/shield/* proto/ && rm -Rf proto/odpf
@echo " > protobuf compilation finished"

help:
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
Expand Down
1 change: 0 additions & 1 deletion buf.gen.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env -S buf generate buf.build/odpf/proton:1497165f2f48facb3ec6f5c5556ccd44f0a7119f --path odpf/shield --template
---
version: "v1"
plugins:
Expand Down
47 changes: 22 additions & 25 deletions cmd/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,15 @@ import (
"context"
"fmt"
"os"
"strconv"

"github.com/MakeNowJust/heredoc"
"github.com/odpf/salt/log"
"github.com/odpf/salt/printer"
"github.com/odpf/shield/config"
"github.com/odpf/shield/pkg/file"
shieldv1beta1 "github.com/odpf/shield/proto/v1beta1"
cli "github.com/spf13/cobra"
)

func ActionCommand(logger log.Logger, appConfig *config.Shield) *cli.Command {
func ActionCommand(cliConfig *Config) *cli.Command {
cmd := &cli.Command{
Use: "action",
Aliases: []string{"actions"},
Expand All @@ -29,19 +27,22 @@ func ActionCommand(logger log.Logger, appConfig *config.Shield) *cli.Command {
$ shield action list
`),
Annotations: map[string]string{
"action:core": "true",
"group:core": "true",
"client": "true",
},
}

cmd.AddCommand(createActionCommand(logger, appConfig))
cmd.AddCommand(editActionCommand(logger, appConfig))
cmd.AddCommand(viewActionCommand(logger, appConfig))
cmd.AddCommand(listActionCommand(logger, appConfig))
cmd.AddCommand(createActionCommand(cliConfig))
cmd.AddCommand(editActionCommand(cliConfig))
cmd.AddCommand(viewActionCommand(cliConfig))
cmd.AddCommand(listActionCommand(cliConfig))

bindFlagsFromClientConfig(cmd)

return cmd
}

func createActionCommand(logger log.Logger, appConfig *config.Shield) *cli.Command {
func createActionCommand(cliConfig *Config) *cli.Command {
var filePath, header string

cmd := &cli.Command{
Expand All @@ -59,7 +60,7 @@ func createActionCommand(logger log.Logger, appConfig *config.Shield) *cli.Comma
defer spinner.Stop()

var reqBody shieldv1beta1.ActionRequestBody
if err := parseFile(filePath, &reqBody); err != nil {
if err := file.Parse(filePath, &reqBody); err != nil {
return err
}

Expand All @@ -68,9 +69,8 @@ func createActionCommand(logger log.Logger, appConfig *config.Shield) *cli.Comma
return err
}

host := appConfig.App.Host + ":" + strconv.Itoa(appConfig.App.Port)
ctx := context.Background()
client, cancel, err := createClient(ctx, host)
client, cancel, err := createClient(cmd)
if err != nil {
return err
}
Expand All @@ -86,7 +86,7 @@ func createActionCommand(logger log.Logger, appConfig *config.Shield) *cli.Comma
}

spinner.Stop()
logger.Info(fmt.Sprintf("successfully created action %s with id %s", res.GetAction().GetName(), res.GetAction().GetId()))
fmt.Printf("successfully created action %s with id %s\n", res.GetAction().GetName(), res.GetAction().GetId())
return nil
},
}
Expand All @@ -99,7 +99,7 @@ func createActionCommand(logger log.Logger, appConfig *config.Shield) *cli.Comma
return cmd
}

func editActionCommand(logger log.Logger, appConfig *config.Shield) *cli.Command {
func editActionCommand(cliConfig *Config) *cli.Command {
var filePath string

cmd := &cli.Command{
Expand All @@ -117,7 +117,7 @@ func editActionCommand(logger log.Logger, appConfig *config.Shield) *cli.Command
defer spinner.Stop()

var reqBody shieldv1beta1.ActionRequestBody
if err := parseFile(filePath, &reqBody); err != nil {
if err := file.Parse(filePath, &reqBody); err != nil {
return err
}

Expand All @@ -126,9 +126,8 @@ func editActionCommand(logger log.Logger, appConfig *config.Shield) *cli.Command
return err
}

host := appConfig.App.Host + ":" + strconv.Itoa(appConfig.App.Port)
ctx := context.Background()
client, cancel, err := createClient(ctx, host)
client, cancel, err := createClient(cmd)
if err != nil {
return err
}
Expand All @@ -144,7 +143,7 @@ func editActionCommand(logger log.Logger, appConfig *config.Shield) *cli.Command
}

spinner.Stop()
logger.Info(fmt.Sprintf("successfully edited action with id %s", actionID))
fmt.Printf("successfully edited action with id %s\n", actionID)
return nil
},
}
Expand All @@ -155,7 +154,7 @@ func editActionCommand(logger log.Logger, appConfig *config.Shield) *cli.Command
return cmd
}

func viewActionCommand(logger log.Logger, appConfig *config.Shield) *cli.Command {
func viewActionCommand(cliConfig *Config) *cli.Command {
cmd := &cli.Command{
Use: "view",
Short: "View an action",
Expand All @@ -170,9 +169,8 @@ func viewActionCommand(logger log.Logger, appConfig *config.Shield) *cli.Command
spinner := printer.Spin("")
defer spinner.Stop()

host := appConfig.App.Host + ":" + strconv.Itoa(appConfig.App.Port)
ctx := context.Background()
client, cancel, err := createClient(ctx, host)
client, cancel, err := createClient(cmd)
if err != nil {
return err
}
Expand Down Expand Up @@ -207,7 +205,7 @@ func viewActionCommand(logger log.Logger, appConfig *config.Shield) *cli.Command
return cmd
}

func listActionCommand(logger log.Logger, appConfig *config.Shield) *cli.Command {
func listActionCommand(cliConfig *Config) *cli.Command {
cmd := &cli.Command{
Use: "list",
Short: "List all actions",
Expand All @@ -222,9 +220,8 @@ func listActionCommand(logger log.Logger, appConfig *config.Shield) *cli.Command
spinner := printer.Spin("")
defer spinner.Stop()

host := appConfig.App.Host + ":" + strconv.Itoa(appConfig.App.Port)
ctx := context.Background()
client, cancel, err := createClient(ctx, host)
client, cancel, err := createClient(cmd)
if err != nil {
return err
}
Expand Down
119 changes: 119 additions & 0 deletions cmd/action_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package cmd_test

import (
"bytes"
"context"
"errors"
"testing"

"github.com/MakeNowJust/heredoc"
"github.com/odpf/shield/cmd"
"github.com/stretchr/testify/assert"
)

var expectedActionUsageHelp = heredoc.Doc(`

USAGE
shield action [flags]

CORE COMMANDS
create Create an action
edit Edit an action
list List all actions
view View an action

FLAGS
-h, --host string Shield API service to connect to

INHERITED FLAGS
--help Show help for command

EXAMPLES
$ shield action create
$ shield action edit
$ shield action view
$ shield action list

`)

func TestClientAction(t *testing.T) {
t.Run("without config file", func(t *testing.T) {
tests := []struct {
name string
cliConfig *cmd.Config
subCommands []string
want string
err error
}{
{
name: "`action` only should show usage help",
want: expectedActionUsageHelp,
err: nil,
},
{
name: "`action` list only should throw error host not found",
want: "",
subCommands: []string{"list"},
err: cmd.ErrClientConfigHostNotFound,
},
{
name: "`action` list with host flag should pass",
want: "",
subCommands: []string{"list", "-h", "test"},
err: context.DeadlineExceeded,
},
{
name: "`action` create only should throw error host not found",
want: "",
subCommands: []string{"create"},
err: cmd.ErrClientConfigHostNotFound,
},
{
name: "`action` create with host flag should throw error missing required flag",
want: "",
subCommands: []string{"create", "-h", "test"},
err: errors.New("required flag(s) \"file\", \"header\" not set"),
},
{
name: "`action` edit without host should throw error host not found",
want: "",
subCommands: []string{"edit", "123"},
err: cmd.ErrClientConfigHostNotFound,
},
{
name: "`action` edit with host flag should throw error missing required flag",
want: "",
subCommands: []string{"edit", "123", "-h", "test"},
err: errors.New("required flag(s) \"file\" not set"),
},
{
name: "`action` view without host should throw error host not found",
want: "",
subCommands: []string{"view", "123"},
err: cmd.ErrClientConfigHostNotFound,
},
{
name: "`action` view with host flag should pass",
want: "",
subCommands: []string{"view", "123", "-h", "test"},
err: context.DeadlineExceeded,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cli := cmd.New(tt.cliConfig)

buf := new(bytes.Buffer)
cli.SetOutput(buf)
args := append([]string{"action"}, tt.subCommands...)
cli.SetArgs(args)

err := cli.Execute()
got := buf.String()

assert.Equal(t, tt.err, err)
assert.Equal(t, tt.want, got)
})
}
})
}
33 changes: 30 additions & 3 deletions cmd/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,27 @@ import (
"time"

shieldv1beta1 "github.com/odpf/shield/proto/v1beta1"
"github.com/spf13/cobra"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)

func createConnection(ctx context.Context, host string) (*grpc.ClientConn, error) {
opts := []grpc.DialOption{
grpc.WithInsecure(),
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithBlock(),
}

return grpc.DialContext(ctx, host, opts...)
}

func createClient(ctx context.Context, host string) (shieldv1beta1.ShieldServiceClient, func(), error) {
dialTimeoutCtx, dialCancel := context.WithTimeout(ctx, time.Second*2)
func createClient(cmd *cobra.Command) (shieldv1beta1.ShieldServiceClient, func(), error) {
mabdh marked this conversation as resolved.
Show resolved Hide resolved
dialTimeoutCtx, dialCancel := context.WithTimeout(cmd.Context(), time.Second*2)
host, err := cmd.Flags().GetString("host")
if err != nil {
dialCancel()
return nil, nil, err
}
conn, err := createConnection(dialTimeoutCtx, host)
if err != nil {
dialCancel()
Expand All @@ -33,3 +40,23 @@ func createClient(ctx context.Context, host string) (shieldv1beta1.ShieldService
client := shieldv1beta1.NewShieldServiceClient(conn)
return client, cancel, nil
}

func isClientCLI(cmd *cobra.Command) bool {
mabdh marked this conversation as resolved.
Show resolved Hide resolved
for c := cmd; c.Parent() != nil; c = c.Parent() {
if c.Annotations != nil && c.Annotations["client"] == "true" {
return true
}
}
return false
}

func clientConfigHostExist(cmd *cobra.Command) bool {
host, err := cmd.Flags().GetString("host")
if err != nil {
return false
}
if host != "" {
return true
}
return false
}
Loading