Skip to content
This repository has been archived by the owner on Jul 12, 2022. It is now read-only.

Adding feature containsAny, containsAll, containsOnly, notContainsAny and notContainsAll in conditional options #874

Merged
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
2 changes: 2 additions & 0 deletions pkg/formula/input/flag/flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (

const (
errInvalidInputItemsMsg = "the value [%v] is not valid, only these input items [%s] are accepted in the %q flag"
TypeSuffix = "__type"
)

type InputManager struct {
Expand Down Expand Up @@ -89,6 +90,7 @@ func (in InputManager) Inputs(cmd *exec.Cmd, setup formula.Setup, flags *pflag.F

if len(inputVal) != 0 {
input.AddEnv(cmd, i.Name, inputVal)
input.AddEnv(cmd, i.Name+TypeSuffix, i.Type)
} else {
emptyInputs = append(emptyInputs, i)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/formula/input/flag/flag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func TestInputs(t *testing.T) {
in: in{
operator: "eq",
},
want: errors.New("config.json: conditional operator eq not valid. Use any of (==, !=, >, >=, <, <=)"),
want: errors.New("config.json: conditional operator eq not valid. Use any of (==, !=, >, >=, <, <=, containsAny, containsAll, containsOnly, notContainsAny, notContainsAll)"),
},
{
name: "mismatch error operator",
Expand Down
96 changes: 92 additions & 4 deletions pkg/formula/input/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const (
DynamicType = "dynamic"
MultiselectType = "multiselect"
MultiselectSeparator = "|"
TypeSuffix = "__type"
)

// addEnv Add environment variable to run formulas.
Expand All @@ -42,6 +43,15 @@ func HasRegex(input formula.Input) bool {
return len(input.Pattern.Regex) > 0
}

func containsArray(s []string, str string) bool {
andressaabreuzup marked this conversation as resolved.
Show resolved Hide resolved
for _, v := range s {
if v == str {
return true
}
}
return false
}

func inputConditionVariableExistsOnInputList(variable string, inputList formula.Inputs) bool {
for _, inputListElement := range inputList {
if inputListElement.Name == variable {
Expand All @@ -51,30 +61,98 @@ func inputConditionVariableExistsOnInputList(variable string, inputList formula.
return false
}

func containsSubstring(s string, substr string) bool {
return strings.Contains(s, substr)
}

func valueContainsAny(inputType string, value string, input string) bool {
splitInput := strings.Split(input, "|")
andressaabreuzup marked this conversation as resolved.
Show resolved Hide resolved
if inputType == MultiselectType {
splitValue := strings.Split(value, "|")
for _, i := range splitInput {
if containsArray(splitValue, i) {
return true
}
}
} else {
andressaabreuzup marked this conversation as resolved.
Show resolved Hide resolved
for _, i := range splitInput {
if containsSubstring(value, i) {
return true
}
}
}
return false
}

func valueContainsAll(inputType string, value string, input string) bool {
splitInput := strings.Split(input, "|")
if inputType == MultiselectType {
splitValue := strings.Split(value, "|")
for _, v := range splitInput {
if !containsArray(splitValue, v) {
return false
}
}
} else {
andressaabreuzup marked this conversation as resolved.
Show resolved Hide resolved
for _, v := range splitInput {
if !containsSubstring(value, v) {
return false
}
}
}
return true
}

func valueContainsOnly(inputType string, value string, input string) bool {
if inputType == MultiselectType {
splitInput := strings.Split(input, "|")
splitValue := strings.Split(value, "|")
if len(splitValue) != len(splitInput) {
return false
}
for _, v := range splitInput {
if !containsArray(splitValue, v) {
return false
}
}
} else {
return strings.EqualFold(value, input)
}
return true
}

func VerifyConditional(cmd *exec.Cmd, input formula.Input, inputList formula.Inputs) (bool, error) {

if input.Condition.Variable == "" {
return true, nil
}

var typeValue string
andressaabreuzup marked this conversation as resolved.
Show resolved Hide resolved
var value string

variable := input.Condition.Variable

if !inputConditionVariableExistsOnInputList(variable, inputList) {
return false, fmt.Errorf("config.json: conditional variable %s not found", variable)
}

var value string
for _, envVal := range cmd.Env {
components := strings.Split(envVal, "=")
if strings.ToLower(components[0]) == variable {
if strings.EqualFold(components[0], variable) {
value = components[1]
break
} else if strings.EqualFold(components[0], variable+TypeSuffix) {
typeValue = components[1]
}
}

if value == "" {
return false, nil
}

if typeValue == "" {
return false, fmt.Errorf("config.json: conditional variable %s has no type", variable)
}

// Currently using case implementation to avoid adding a dependency module or exposing
// the code to the risks of running an eval function on a user-defined variable
// optimizations are welcome, being mindful of the points above
Expand All @@ -91,9 +169,19 @@ func VerifyConditional(cmd *exec.Cmd, input formula.Input, inputList formula.Inp
return value < input.Condition.Value, nil
case "<=":
return value <= input.Condition.Value, nil
case "containsAny":
andressaabreuzup marked this conversation as resolved.
Show resolved Hide resolved
return valueContainsAny(typeValue, value, input.Condition.Value), nil
case "containsAll":
return valueContainsAll(typeValue, value, input.Condition.Value), nil
case "containsOnly":
return valueContainsOnly(typeValue, value, input.Condition.Value), nil
case "notContainsAny":
return !valueContainsAny(typeValue, value, input.Condition.Value), nil
case "notContainsAll":
return !valueContainsAll(typeValue, value, input.Condition.Value), nil
default:
return false, fmt.Errorf(
"config.json: conditional operator %s not valid. Use any of (==, !=, >, >=, <, <=)",
"config.json: conditional operator %s not valid. Use any of (==, !=, >, >=, <, <=, containsAny, containsAll, containsOnly, notContainsAny, notContainsAll)",
input.Condition.Operator,
)
}
Expand Down
5 changes: 5 additions & 0 deletions pkg/formula/input/prompt/prompt.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const (
DefaultCacheNewLabel = "Type new value?"
DefaultCacheQty = 5
EmptyItems = "no items were provided. Please insert a list of items for the input %s in the config.json file of your formula"
TypeSuffix = "__type"
)

type InputManager struct {
Expand Down Expand Up @@ -113,8 +114,12 @@ func (in InputManager) Inputs(cmd *exec.Cmd, setup formula.Setup, f *pflag.FlagS
in.persistCache(setup.FormulaPath, inputVal, i, items)
checkForSameEnv(i.Name)
input.AddEnv(cmd, i.Name, inputVal)
checkForSameEnv(i.Name + TypeSuffix)
input.AddEnv(cmd, i.Name+TypeSuffix, i.Type)
}

}

return nil
}

Expand Down
Loading