Skip to content

Commit

Permalink
Merge pull request #10 from AdamKobi/fix_bug_in_xt_flow_run
Browse files Browse the repository at this point in the history
use key pairs instead of flat list
  • Loading branch information
AdamKobi committed Mar 28, 2021
2 parents 9af9699 + 42d257e commit b3256ee
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 88 deletions.
8 changes: 2 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
BUILD_FILES = $(shell go list -f '{{range .GoFiles}}{{$$.Dir}}/{{.}}\
{{end}}' ./...)

# XT_VERSION ?= $(shell git describe --tags 2>/dev/null || git rev-parse --short HEAD)
XT_VERSION = v1.0.0
XT_VERSION ?= $(shell git describe --tags 2>/dev/null || git rev-parse --short HEAD)
# XT_VERSION = v1.0.0
LDFLAGS := -X github.com/adamkobi/xt/internal/build.Version=$(XT_VERSION) $(LDFLAGS)
ifdef XT_OAUTH_CLIENT_SECRET
LDFLAGS := -X github.com/adamkobi/xt/context.oauthClientID=$(XT_OAUTH_CLIENT_ID) $(LDFLAGS)
LDFLAGS := -X github.com/adamkobi/xt/context.oauthClientSecret=$(XT_OAUTH_CLIENT_SECRET) $(LDFLAGS)
endif

bin/xt: $(BUILD_FILES)
@go build -trimpath -ldflags "$(LDFLAGS)" -o "$@" ./cmd/main.go
Expand Down
12 changes: 6 additions & 6 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ func main() {

cmdFactory := factory.New()
stderr := cmdFactory.IOStreams.ErrOut
_, err := cmdFactory.Config()
if err != nil {
fmt.Fprintf(stderr, "failed to read configuration: %s\n", err)
os.Exit(2)
}

if !cmdFactory.IOStreams.ColorEnabled() {
surveyCore.DisableColor = true
} else {
Expand All @@ -58,12 +64,6 @@ func main() {

rootCmd := root.NewCmd(cmdFactory, buildVersion, buildDate)

_, err := cmdFactory.Config()
if err != nil {
fmt.Fprintf(stderr, "failed to read configuration: %s\n", err)
os.Exit(2)
}

if cmd, err := rootCmd.ExecuteC(); err != nil {
printError(stderr, err, cmd, hasDebug)
os.Exit(1)
Expand Down
49 changes: 41 additions & 8 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,17 @@ type Config struct {
}

type FlowOptions struct {
Run string `yaml:"run"`
Selector string `yaml:"selector,omitempty"`
Keys []string `yaml:"keys,omitempty"`
Root string `yaml:"root,omitempty"`
OutputFormat string `yaml:"output_format"`
Print bool `yaml:"print,omitempty"`
Run string `yaml:"run"`
Selector string `yaml:"selector"`
Keys []Pair `yaml:"keys,omitempty"`
Root string `yaml:"root,omitempty"`
OutputFormat string `yaml:"output_format"`
Print bool `yaml:"print,omitempty"`
}

type Pair struct {
Name string `yaml:"name"`
Path string `yaml:"path"`
}

type ProfileOptions struct {
Expand Down Expand Up @@ -201,11 +206,39 @@ func (f *FlowOptions) Validate() error {
if f.Root == "" {
return fmt.Errorf("parse must be set when using json type")
}
if len(f.Selector) == 0 {
return fmt.Errorf("selector must be set when using json type")
if len(f.Keys) < 1 {
return fmt.Errorf("keys must be set when using json type")
}
if f.Selector != "" {
valid := false
for _, key := range f.Keys {
if f.Selector == key.Name {
valid = true
}
}
if !valid {
return fmt.Errorf("selector must equal to one of keys provided")
}
}
return nil
default:
return nil
}
}

func (f *FlowOptions) GetSelector() *Pair {
for _, key := range f.Keys {
if f.Selector == key.Name {
return &key
}
}
return nil
}

func (f *FlowOptions) GetKeys() []string {
var keys []string
for _, key := range f.Keys {
keys = append(keys, key.Name)
}
return keys
}
24 changes: 16 additions & 8 deletions pkg/command/flow/add/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,13 @@ func runAdd(opts *Options) error {
Help: "Selector will return a picker to select the correct data set to collect from.\nFor nested keys use dot notation",
}

key := &survey.Input{
Message: "JSON key to parse from command output",
keyName := &survey.Input{
Message: "JSON key name, this will be used in next commands as placeholder for replacement",
Help: "JSON key is collected from output and than can be used on next commands.\nFor nested keys use dot notation",
}

keyValue := &survey.Input{
Message: "JSON key path to parse from command output",
Help: "JSON key is collected from output and than can be used on next commands.\nFor nested keys use dot notation",
}

Expand Down Expand Up @@ -99,10 +104,6 @@ func runAdd(opts *Options) error {
}

if cmd.OutputFormat == "json" {
if err := survey.AskOne(selector, &cmd.Selector); err != nil {
return err
}

addKeysAnswer := false
if err := survey.AskOne(addKeys, &addKeysAnswer); err != nil {
return err
Expand All @@ -113,8 +114,11 @@ func runAdd(opts *Options) error {
if !addMoreKeysAnswer {
break
}
var keyAnswer string
if err := survey.AskOne(key, &keyAnswer); err != nil {
var keyAnswer config.Pair
if err := survey.AskOne(keyName, &keyAnswer.Name); err != nil {
return err
}
if err := survey.AskOne(keyValue, &keyAnswer.Path); err != nil {
return err
}
cmd.Keys = append(cmd.Keys, keyAnswer)
Expand All @@ -125,6 +129,10 @@ func runAdd(opts *Options) error {
}
}

if err := survey.AskOne(selector, &cmd.Keys[0]); err != nil {
return err
}

if err := survey.AskOne(table, &cmd.Print); err != nil {
return err
}
Expand Down
89 changes: 29 additions & 60 deletions pkg/command/flow/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ func NewCmdRun(f *cmdutil.Factory) *cobra.Command {

return cmd
}

func runFlow(opts *Options) error {
cfg, _ := opts.Config()
profile, err := cfg.Profile(opts.Profile)
Expand Down Expand Up @@ -110,22 +111,23 @@ func runFlow(opts *Options) error {
}
return runCommands(cmdOpts, flow)
}

func runCommands(opts *executer.Options, flow []config.FlowOptions) error {
var (
keys map[string]string
selectedKeys map[string]string
runCmd string
renderedTempl bytes.Buffer
)

for idx, cmd := range flow {

runCmdTempl, err := template.New(fmt.Sprintf("cmd_%d", idx)).Parse(cmd.Run)
if err != nil {
return err
}
if selectedKeys != nil {
runCmdTempl, err := template.New(fmt.Sprintf("cmd_%d", idx)).Parse(cmd.Run)
if err != nil {
return err
}

if keys != nil {
runCmdTempl.Execute(&renderedTempl, keys)
runCmdTempl.Execute(&renderedTempl, selectedKeys)
runCmd = renderedTempl.String()
} else {
runCmd = cmd.Run
Expand All @@ -151,7 +153,7 @@ func runCommands(opts *executer.Options, flow []config.FlowOptions) error {
}

if cmd.Print {
printJSON(optsClone.IO, parsedOutput)
printJSON(optsClone.IO, cmd.GetKeys(), parsedOutput)
}

if idx < len(flow)-1 {
Expand All @@ -160,10 +162,8 @@ func runCommands(opts *executer.Options, flow []config.FlowOptions) error {
return err
}

keys, err = selectorKeys(parsedOutput, selectorName)
if err != nil {
return err
}
selectedKeys = getDataFromSelected(parsedOutput, selectorName)

}
default:
if err := e.Connect(); err != nil {
Expand All @@ -176,32 +176,24 @@ func runCommands(opts *executer.Options, flow []config.FlowOptions) error {

//parseJSONFromFlow fetches all selectors from input json and returns an json with selectors and values
func parseJSONFromFlow(json string, cmd config.FlowOptions) ([]map[string]string, error) {
var parsedJSON []map[string]string
rootSlice := gjson.Get(json, cmd.Root)
if !rootSlice.IsArray() {
return nil, fmt.Errorf("%s is not a list, parse must be a list", cmd.Root)
}

var parsedJSON []map[string]string
for _, item := range rootSlice.Array() {
var parsedItem = make(map[string]string)
result := item.Get(cmd.Selector)
if result.Exists() {
parsedItem[cmd.Selector] = result.String()
parsedJSON = append(parsedJSON, parsedItem)
} else {
return nil, fmt.Errorf("selector `%s` not found", cmd.Selector)
}

var parsedObject = make(map[string]string)
for _, key := range cmd.Keys {
result := item.Get(key)
result := item.Get(key.Path)
if result.Exists() {
parsedItem[key] = result.String()
parsedObject[key.Name] = result.String()
} else {
return nil, fmt.Errorf("key `%s` not found", key)
}
}
parsedJSON = append(parsedJSON, parsedObject)
}

return parsedJSON, nil
}

Expand All @@ -217,62 +209,39 @@ func getSelectors(data []map[string]string, cmd config.FlowOptions) []string {
}

//selectorKeys returns a map of the selected selector
func selectorKeys(data []map[string]string, selector string) (map[string]string, error) {
var wantedItem map[string]string
normalizedKeys := make(map[string]string)
func getDataFromSelected(data []map[string]string, selected string) map[string]string {
for _, item := range data {
for _, v := range item {
if v == selector {
wantedItem = item
break
if v == selected {
return item
}
}
}

for k, v := range wantedItem {
normalizedKeys[strings.ReplaceAll(k, ".", "_")] = v
}

if len(normalizedKeys) == 0 {
return nil, fmt.Errorf("selector %s not found: lookup error", selector)
}
return normalizedKeys, nil
return nil
}

//printJSON writes the fields requested by user to console in a formated table
func printJSON(io *iostreams.IOStreams, data []map[string]string) {
func printJSON(io *iostreams.IOStreams, headers []string, data []map[string]string) {
cs := io.ColorScheme()
if len(data) == 0 {
fmt.Fprintf(io.ErrOut, cs.Gray("no data received"))
}

table := utils.NewTablePrinter(io)
var header []string
for key := range data[0] {
nameSlice := strings.Split(key, ".")
normalizedName := nameSlice[len(nameSlice)-1]
if validateHeader(header, normalizedName) {
normalizedName = nameSlice[len(nameSlice)-2] + "." + normalizedName
}
table.AddField(normalizedName, nil, cs.MagentaBold)

for _, header := range headers {
table.AddField(header, nil, cs.MagentaBold)
}
table.EndRow()

for _, item := range data {
for _, v := range item {
table.AddField(v, nil, cs.Green)
for _, header := range headers {
if val, ok := item[header]; ok {
table.AddField(val, nil, cs.Green)
}
}
table.EndRow()
}

_ = table.Render()
}

func validateHeader(headers []string, testedHeader string) bool {
for _, h := range headers {
if h == testedHeader {
return true
}
}
return false
}

0 comments on commit b3256ee

Please sign in to comment.