Unify core functions address handling (#3445)

Signed-off-by: Andrei Ciobanu <andrei.ciobanu@opentofu.org>
This commit is contained in:
Andrei Ciobanu
2025-10-31 08:41:52 +02:00
committed by GitHub
parent 0503163e28
commit 481798ab36
8 changed files with 129 additions and 20 deletions

View File

@@ -9,7 +9,7 @@ import (
"encoding/json"
"fmt"
"github.com/opentofu/opentofu/internal/lang"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/tfdiags"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/function"
@@ -58,10 +58,14 @@ func Marshal(f map[string]function.Function) ([]byte, tfdiags.Diagnostics) {
signatures := newFunctions()
for name, v := range f {
switch name {
case "can", lang.CoreNamespace + "can":
// Even though it's not possible to have a provider namespaced function end up in here,
// we want to qualify the function name to be sure that we check exactly for the
// function that we have custom marshaller for.
fqFuncAddr := addrs.ParseFunction(name).FullyQualified().String()
switch fqFuncAddr {
case addrs.ParseFunction("can").FullyQualified().String():
signatures.Signatures[name] = marshalCan(v)
case "try", lang.CoreNamespace + "try":
case addrs.ParseFunction("try").FullyQualified().String():
signatures.Signatures[name] = marshalTry(v)
default:
signature, err := marshalFunction(v)

View File

@@ -10,6 +10,7 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/hcl/v2/ext/tryfunc"
"github.com/zclconf/go-cty-debug/ctydebug"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/function"
@@ -113,6 +114,72 @@ func TestMarshal(t *testing.T) {
"",
"Failed to serialize function \"fun\": error",
},
{
"try function marshalled correctly",
map[string]function.Function{
"try": tryfunc.TryFunc,
},
`{"format_version":"1.0","function_signatures":{"try":{"return_type":"dynamic","variadic_parameter":{"name":"expressions","type":"dynamic"}}}}`,
"",
},
{
"core::try function marshalled correctly",
map[string]function.Function{
"core::try": tryfunc.TryFunc,
},
`{"format_version":"1.0","function_signatures":{"core::try":{"return_type":"dynamic","variadic_parameter":{"name":"expressions","type":"dynamic"}}}}`,
"",
},
{
// This checks that if a provider contains a function named the same as one of the core with custom marshaller, we identify that correctly
"provider::test::try function marshalled correctly",
map[string]function.Function{
"provider::test::try": function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "list",
Type: cty.List(cty.String),
},
},
Type: function.StaticReturnType(cty.List(cty.String)),
}),
},
`{"format_version":"1.0","function_signatures":{"provider::test::try":{"return_type":["list","string"],"parameters":[{"name":"list","type":["list","string"]}]}}}`,
"",
},
{
"can function marshalled correctly",
map[string]function.Function{
"can": tryfunc.CanFunc,
},
`{"format_version":"1.0","function_signatures":{"can":{"return_type":"bool","parameters":[{"name":"expression","type":"dynamic"}]}}}`,
"",
},
{
"core::can function marshalled correctly",
map[string]function.Function{
"core::can": tryfunc.CanFunc,
},
`{"format_version":"1.0","function_signatures":{"core::can":{"return_type":"bool","parameters":[{"name":"expression","type":"dynamic"}]}}}`,
"",
},
{
// This checks that if a provider contains a function named the same as one of the core with custom marshaller, we identify that correctly
"provider::test::can function marshalled correctly",
map[string]function.Function{
"provider::test::can": function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "list",
Type: cty.List(cty.String),
},
},
Type: function.StaticReturnType(cty.List(cty.String)),
}),
},
`{"format_version":"1.0","function_signatures":{"provider::test::can":{"return_type":["list","string"],"parameters":[{"name":"list","type":["list","string"]}]}}}`,
"",
},
}
for i, test := range tests {