Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support provider defined functions #321

Merged
merged 16 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 8 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ require (
github.com/hashicorp/go-cleanhttp v0.5.2
github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/hc-install v0.6.3
github.com/hashicorp/hcl-lang v0.0.0-20240122101040-f43c27231c10
github.com/hashicorp/hcl/v2 v2.19.1
github.com/hashicorp/hcl-lang v0.0.0-20240326153306-49d737897778
github.com/hashicorp/hcl/v2 v2.20.1
github.com/hashicorp/terraform-exec v0.20.0
github.com/hashicorp/terraform-json v0.21.0
github.com/hashicorp/terraform-registry-address v0.2.3
github.com/mh-cbon/go-fmt-fail v0.0.0-20160815164508-67765b3fbcb5
github.com/zclconf/go-cty v1.14.2
github.com/zclconf/go-cty v1.14.4
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b
)

Expand All @@ -26,9 +26,10 @@ require (
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/mod v0.16.0 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.19.0 // indirect
)
37 changes: 18 additions & 19 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mO
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/hc-install v0.6.3 h1:yE/r1yJvWbtrJ0STwScgEnCanb0U9v7zp0Gbkmcoxqs=
github.com/hashicorp/hc-install v0.6.3/go.mod h1:KamGdbodYzlufbWh4r9NRo8y6GLHWZP2GBtdnms1Ln0=
github.com/hashicorp/hcl-lang v0.0.0-20240122101040-f43c27231c10 h1:tXisNKDNqOGkcRf8NeM4b0Br4Q5SFrpbDj36qSQimjA=
github.com/hashicorp/hcl-lang v0.0.0-20240122101040-f43c27231c10/go.mod h1:HWlBK8JoI8P4yp2reyTc267YoDpypd5fK3OYAPLyUXM=
github.com/hashicorp/hcl/v2 v2.19.1 h1://i05Jqznmb2EXqa39Nsvyan2o5XyMowW5fnCKW5RPI=
github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE=
github.com/hashicorp/hcl-lang v0.0.0-20240326153306-49d737897778 h1:Yw/5Lno+YiOAEQQ6krRpiJ4lCv+x0k7Q6/SxH5AIsus=
github.com/hashicorp/hcl-lang v0.0.0-20240326153306-49d737897778/go.mod h1:2Vwxuf2nQi/095HYVqo0kWhlBLKhwEi/jTf5TxB61MI=
github.com/hashicorp/hcl/v2 v2.20.1 h1:M6hgdyz7HYt1UN9e61j+qKJBqR3orTWbI1HKBJEdxtc=
github.com/hashicorp/hcl/v2 v2.20.1/go.mod h1:TZDqQ4kNKCbh1iJp99FdPiUaVDDUPivbqxZulxDYqL4=
github.com/hashicorp/terraform-exec v0.20.0 h1:DIZnPsqzPGuUnq6cH8jWcPunBfY+C+M8JyYF3vpnuEo=
github.com/hashicorp/terraform-exec v0.20.0/go.mod h1:ckKGkJWbsNqFKV1itgMnE0hY9IYf1HoiekpuN0eWoDw=
github.com/hashicorp/terraform-json v0.21.0 h1:9NQxbLNqPbEMze+S6+YluEdXgJmhQykRyRNd+zTI05U=
Expand All @@ -57,12 +57,9 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/mh-cbon/go-fmt-fail v0.0.0-20160815164508-67765b3fbcb5 h1:shw+DWUaHIyW64Tv30ASCbC6QO6fLy+M5SJb5pJVEI4=
github.com/mh-cbon/go-fmt-fail v0.0.0-20160815164508-67765b3fbcb5/go.mod h1:nHPoxaBUc5CDAMIv0MNmn5PBjWbTs9BI/eh30/n0U6g=
Expand All @@ -78,25 +75,27 @@ github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6Ac
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
github.com/zclconf/go-cty v1.14.2 h1:kTG7lqmBou0Zkx35r6HJHUQTvaRPr5bIAf3AoHS0izI=
github.com/zclconf/go-cty v1.14.2/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI=
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
Expand Down
39 changes: 39 additions & 0 deletions schema/convert_json.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ import (
tfjson "github.com/hashicorp/terraform-json"
tfaddr "github.com/hashicorp/terraform-registry-address"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/function"
)

func ProviderSchemaFromJson(jsonSchema *tfjson.ProviderSchema, pAddr tfaddr.Provider) *ProviderSchema {
ps := &ProviderSchema{
Resources: map[string]*schema.BodySchema{},
DataSources: map[string]*schema.BodySchema{},
Functions: map[string]*schema.FunctionSignature{},
}

if jsonSchema.ConfigSchema != nil {
Expand All @@ -37,6 +39,11 @@ func ProviderSchemaFromJson(jsonSchema *tfjson.ProviderSchema, pAddr tfaddr.Prov
ps.DataSources[dsName].Detail = detailForSrcAddr(pAddr, nil)
}

for fnName, fnSig := range jsonSchema.Functions {
ps.Functions[fnName] = functionSignatureFromJson(fnSig)
ps.Functions[fnName].Detail = detailForSrcAddr(pAddr, nil)
}

return ps
}

Expand Down Expand Up @@ -396,3 +403,35 @@ func detailForSrcAddr(addr tfaddr.Provider, v *version.Version) string {

return detail
}

func functionSignatureFromJson(fnSig *tfjson.FunctionSignature) *schema.FunctionSignature {
if fnSig == nil {
return &schema.FunctionSignature{}
}

varParam := convertParameterFromJson(fnSig.VariadicParameter)
params := make([]function.Parameter, len(fnSig.Parameters))
for i, param := range fnSig.Parameters {
params[i] = *convertParameterFromJson(param)
}

return &schema.FunctionSignature{
Description: fnSig.Description,
ReturnType: fnSig.ReturnType,
Params: params,
VarParam: varParam,
}
}

func convertParameterFromJson(param *tfjson.FunctionParameter) *function.Parameter {
if param == nil {
return nil
}

return &function.Parameter{
Name: param.Name,
Type: param.Type,
Description: param.Description,
dbanck marked this conversation as resolved.
Show resolved Hide resolved
AllowNull: param.IsNullable,
}
}
143 changes: 143 additions & 0 deletions schema/convert_json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package schema

import (
"encoding/json"
"fmt"
"testing"

"github.com/google/go-cmp/cmp"
Expand All @@ -13,6 +14,7 @@ import (
"github.com/hashicorp/terraform-schema/internal/addr"
"github.com/zclconf/go-cty-debug/ctydebug"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/function"
)

func TestProviderSchemaFromJson_empty(t *testing.T) {
Expand All @@ -23,6 +25,7 @@ func TestProviderSchemaFromJson_empty(t *testing.T) {
expectedPs := &ProviderSchema{
Resources: map[string]*schema.BodySchema{},
DataSources: map[string]*schema.BodySchema{},
Functions: map[string]*schema.FunctionSignature{},
}

if diff := cmp.Diff(expectedPs, ps, ctydebug.CmpOptions); diff != "" {
Expand Down Expand Up @@ -291,6 +294,7 @@ func TestProviderSchemaFromJson_basic(t *testing.T) {
},
},
DataSources: map[string]*schema.BodySchema{},
Functions: map[string]*schema.FunctionSignature{},
}

if diff := cmp.Diff(expectedPs, ps, ctydebug.CmpOptions); diff != "" {
Expand Down Expand Up @@ -498,9 +502,148 @@ func TestProviderSchemaFromJson_nested_set_list(t *testing.T) {
},
},
DataSources: map[string]*schema.BodySchema{},
Functions: map[string]*schema.FunctionSignature{},
}

if diff := cmp.Diff(expectedPs, ps, ctydebug.CmpOptions); diff != "" {
t.Fatalf("provider schema mismatch: %s", diff)
}
}

func TestProviderSchemaFromJson_function(t *testing.T) {
ansgarm marked this conversation as resolved.
Show resolved Hide resolved
testCases := []struct {
testName string
rawSchema string
expectedSchema ProviderSchema
}{
{
"basic",
`{
"functions": {
"example": {
"description": "Echoes given argument as result",
"summary": "Example function",
"return_type": "string",
"parameters": [
{
"name": "input",
"description": "String to echo",
"type": "string"
}
]
}
}
}`,
ProviderSchema{
Resources: map[string]*schema.BodySchema{},
DataSources: map[string]*schema.BodySchema{},
Functions: map[string]*schema.FunctionSignature{
"example": {
Description: "Echoes given argument as result",
Detail: "hashicorp/aws",
ReturnType: cty.String,
Params: []function.Parameter{
{
Name: "input",
Description: "String to echo",
Type: cty.String,
},
},
VarParam: nil,
},
},
},
},
{
"no parameters",
`{
"functions": {
"example": {
"description": "Returns a string",
"summary": "Example function",
"return_type": "string",
"parameters": []
}
}
}`,
ProviderSchema{
Resources: map[string]*schema.BodySchema{},
DataSources: map[string]*schema.BodySchema{},
Functions: map[string]*schema.FunctionSignature{
"example": {
Description: "Returns a string",
Detail: "hashicorp/aws",
ReturnType: cty.String,
Params: []function.Parameter{},
VarParam: nil,
},
},
},
},
{
"with variadic parameter",
`{
"functions": {
"example": {
"description": "Echoes given argument as result",
"summary": "Example function",
"return_type": "string",
"parameters": [
{
"name": "input",
"description": "String to echo",
"type": "string"
}
],
"variadic_parameter": {
"name": "vars",
"description": "Optional additional arguments",
"type": "string"
}
}
}
}`,
ProviderSchema{
Resources: map[string]*schema.BodySchema{},
DataSources: map[string]*schema.BodySchema{},
Functions: map[string]*schema.FunctionSignature{
"example": {
Description: "Echoes given argument as result",
Detail: "hashicorp/aws",
ReturnType: cty.String,
Params: []function.Parameter{
{
Name: "input",
Description: "String to echo",
Type: cty.String,
},
},
VarParam: &function.Parameter{
Name: "vars",
Type: cty.String,
Description: "Optional additional arguments",
},
},
},
},
},
}

for i, tc := range testCases {
t.Run(fmt.Sprintf("%2d-%s", i, tc.testName), func(t *testing.T) {

jsonSchema := &tfjson.ProviderSchema{}
err := json.Unmarshal([]byte(tc.rawSchema), jsonSchema)
if err != nil {
t.Fatal(err)
}
providerAddr := addr.NewDefaultProvider("aws")

ps := ProviderSchemaFromJson(jsonSchema, providerAddr)
if diff := cmp.Diff(&tc.expectedSchema, ps, ctydebug.CmpOptions); diff != "" {
t.Fatalf("provider schema mismatch: %s", diff)
}
})
}

}
6 changes: 6 additions & 0 deletions schema/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ func (e coreSchemaRequiredErr) Error() string {
return "core schema required (none provided)"
}

type coreFunctionsRequiredErr struct{}

func (e coreFunctionsRequiredErr) Error() string {
return "core functions required (none provided)"
}

type NoCompatibleSchemaErr struct {
Version *version.Version
Constraints version.Constraints
Expand Down
Loading
Loading