diff --git a/config/interpolate_funcs.go b/config/interpolate_funcs.go index 32fc2ba4b4..b79334718b 100644 --- a/config/interpolate_funcs.go +++ b/config/interpolate_funcs.go @@ -63,6 +63,7 @@ func Funcs() map[string]ast.Function { "cidrnetmask": interpolationFuncCidrNetmask(), "cidrsubnet": interpolationFuncCidrSubnet(), "coalesce": interpolationFuncCoalesce(), + "coalescelist": interpolationFuncCoalesceList(), "compact": interpolationFuncCompact(), "concat": interpolationFuncConcat(), "dirname": interpolationFuncDirname(), @@ -324,6 +325,30 @@ func interpolationFuncCoalesce() ast.Function { } } +// interpolationFuncCoalesceList implements the "coalescelist" function that +// returns the first non empty list from the provided input +func interpolationFuncCoalesceList() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{ast.TypeList}, + ReturnType: ast.TypeList, + Variadic: true, + VariadicType: ast.TypeList, + Callback: func(args []interface{}) (interface{}, error) { + if len(args) < 2 { + return nil, fmt.Errorf("must provide at least two arguments") + } + for _, arg := range args { + argument := arg.([]ast.Variable) + + if len(argument) > 0 { + return argument, nil + } + } + return make([]ast.Variable, 0), nil + }, + } +} + // interpolationFuncConcat implements the "concat" function that concatenates // multiple lists. func interpolationFuncConcat() ast.Function { diff --git a/config/interpolate_funcs_test.go b/config/interpolate_funcs_test.go index 29c09aa9ea..57e59afa67 100644 --- a/config/interpolate_funcs_test.go +++ b/config/interpolate_funcs_test.go @@ -684,6 +684,33 @@ func TestInterpolateFuncCoalesce(t *testing.T) { }) } +func TestInterpolateFuncCoalesceList(t *testing.T) { + testFunction(t, testFunctionConfig{ + Cases: []testFunctionCase{ + { + `${coalescelist(list("first"), list("second"), list("third"))}`, + []interface{}{"first"}, + false, + }, + { + `${coalescelist(list(), list("second"), list("third"))}`, + []interface{}{"second"}, + false, + }, + { + `${coalescelist(list(), list(), list())}`, + []interface{}{}, + false, + }, + { + `${coalescelist(list("foo"))}`, + nil, + true, + }, + }, + }) +} + func TestInterpolateFuncConcat(t *testing.T) { testFunction(t, testFunctionConfig{ Cases: []testFunctionCase{ diff --git a/website/source/docs/configuration/interpolation.html.md b/website/source/docs/configuration/interpolation.html.md index bd003679e7..aef902d6e9 100644 --- a/website/source/docs/configuration/interpolation.html.md +++ b/website/source/docs/configuration/interpolation.html.md @@ -179,6 +179,9 @@ The supported built-in functions are: * `coalesce(string1, string2, ...)` - Returns the first non-empty value from the given arguments. At least two arguments must be provided. + * `coalescelist(list1, list2, ...)` - Returns the first non-empty list from + the given arguments. At least two arguments must be provided. + * `compact(list)` - Removes empty string elements from a list. This can be useful in some cases, for example when passing joined lists as module variables or when parsing module outputs.