diff --git a/hcl2template/function/alltrue.go b/hcl2template/function/alltrue.go new file mode 100644 index 00000000000..6e9f0d7f217 --- /dev/null +++ b/hcl2template/function/alltrue.go @@ -0,0 +1,36 @@ +package function + +import ( + "github.com/zclconf/go-cty/cty" + "github.com/zclconf/go-cty/cty/function" +) + +// AllTrueFunc constructs a function that returns true if all elements of the +// list are true. If the list is empty, return true. +var AllTrue = function.New(&function.Spec{ + Params: []function.Parameter{ + { + Name: "list", + Type: cty.List(cty.Bool), + }, + }, + Type: function.StaticReturnType(cty.Bool), + RefineResult: refineNotNull, + Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { + result := cty.True + for it := args[0].ElementIterator(); it.Next(); { + _, v := it.Element() + if !v.IsKnown() { + return cty.UnknownVal(cty.Bool), nil + } + if v.IsNull() { + return cty.False, nil + } + result = result.And(v) + if result.False() { + return cty.False, nil + } + } + return result, nil + }, +}) diff --git a/hcl2template/function/alltrue_test.go b/hcl2template/function/alltrue_test.go new file mode 100644 index 00000000000..1359de76eda --- /dev/null +++ b/hcl2template/function/alltrue_test.go @@ -0,0 +1,89 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package function + +import ( + "fmt" + "testing" + + "github.com/zclconf/go-cty/cty" +) + +func TestAllTrue(t *testing.T) { + tests := []struct { + Collection cty.Value + Want cty.Value + Err bool + }{ + { + cty.ListValEmpty(cty.Bool), + cty.True, + false, + }, + { + cty.ListVal([]cty.Value{cty.True}), + cty.True, + false, + }, + { + cty.ListVal([]cty.Value{cty.False}), + cty.False, + false, + }, + { + cty.ListVal([]cty.Value{cty.True, cty.False}), + cty.False, + false, + }, + { + cty.ListVal([]cty.Value{cty.False, cty.True}), + cty.False, + false, + }, + { + cty.ListVal([]cty.Value{cty.True, cty.NullVal(cty.Bool)}), + cty.False, + false, + }, + { + cty.ListVal([]cty.Value{cty.UnknownVal(cty.Bool)}), + cty.UnknownVal(cty.Bool).RefineNotNull(), + false, + }, + { + cty.ListVal([]cty.Value{ + cty.UnknownVal(cty.Bool), + cty.UnknownVal(cty.Bool), + }), + cty.UnknownVal(cty.Bool).RefineNotNull(), + false, + }, + { + cty.UnknownVal(cty.List(cty.Bool)), + cty.UnknownVal(cty.Bool).RefineNotNull(), + false, + }, + { + cty.NullVal(cty.List(cty.Bool)), + cty.NilVal, + true, + }, + } + + for _, tc := range tests { + t.Run(fmt.Sprintf("alltrue(%#v)", tc.Collection), func(t *testing.T) { + got, err := AllTrue.Call([]cty.Value{tc.Collection}) + + if tc.Err && err == nil { + t.Fatal("succeeded; want error") + } + if !tc.Err && err != nil { + t.Fatalf("unexpected error: %s", err) + } + if !got.RawEquals(tc.Want) { + t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, tc.Want) + } + }) + } +} diff --git a/hcl2template/functions.go b/hcl2template/functions.go index 4e832cf9380..6a2dbc61a42 100644 --- a/hcl2template/functions.go +++ b/hcl2template/functions.go @@ -34,6 +34,7 @@ func Functions(basedir string) map[string]function.Function { funcs := map[string]function.Function{ "abs": stdlib.AbsoluteFunc, "abspath": filesystem.AbsPathFunc, + "alltrue": pkrfunction.AllTrue, "aws_secretsmanager": pkrfunction.AWSSecret, "basename": filesystem.BasenameFunc, "base64decode": encoding.Base64DecodeFunc, diff --git a/website/content/docs/templates/hcl_templates/functions/collection/alltrue.mdx b/website/content/docs/templates/hcl_templates/functions/collection/alltrue.mdx new file mode 100644 index 00000000000..3d5db274312 --- /dev/null +++ b/website/content/docs/templates/hcl_templates/functions/collection/alltrue.mdx @@ -0,0 +1,25 @@ +--- +page_title: alltrue - Functions - Configuration Language +description: |- + The alltrue function determines whether all elements of a collection + are true or "true". If the collection is empty, it returns true. +--- + +# `alltrue` Function + +`alltrue` returns `true` if all elements in a given collection are `true` +or `"true"`. It also returns `true` if the collection is empty. + +```hcl +alltrue(list) +``` + +## Examples + +```command +> alltrue(["true", true]) +true +> alltrue([true, false]) +false +``` + diff --git a/website/data/docs-nav-data.json b/website/data/docs-nav-data.json index 24c55feb678..55dfc244e30 100644 --- a/website/data/docs-nav-data.json +++ b/website/data/docs-nav-data.json @@ -326,6 +326,10 @@ { "title": "Collection Functions", "routes": [ + { + "title": "alltrue", + "path": "templates/hcl_templates/functions/collection/alltrue" + }, { "title": "chunklist", "path": "templates/hcl_templates/functions/collection/chunklist"