Skip to content

Commit

Permalink
chore(spanner): improve proto bundle creation, add default value to p…
Browse files Browse the repository at this point in the history
…revent_destroy
  • Loading branch information
newtonnthiga committed Jul 29, 2024
1 parent 5befd97 commit 9beea05
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 66 deletions.
9 changes: 6 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ module terraform-provider-alis
go 1.22

require (
cloud.google.com/go/bigtable v1.26.0
cloud.google.com/go/discoveryengine v1.9.0
cloud.google.com/go/iam v1.1.11
cloud.google.com/go/bigtable v1.27.1
cloud.google.com/go/discoveryengine v1.10.0
cloud.google.com/go/iam v1.1.12
cloud.google.com/go/spanner v1.64.0
cloud.google.com/go/storage v1.43.0
github.com/google/go-cmp v0.6.0
Expand Down Expand Up @@ -33,6 +33,7 @@ require (
cloud.google.com/go/auth/oauth2adapt v0.2.3 // indirect
cloud.google.com/go/compute/metadata v0.5.0 // indirect
cloud.google.com/go/longrunning v0.5.10 // indirect
cloud.google.com/go/monitoring v1.20.1 // indirect
github.com/BurntSushi/toml v1.2.1 // indirect
github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.0 // indirect
github.com/Kunde21/markdownfmt/v3 v3.1.0 // indirect
Expand Down Expand Up @@ -108,6 +109,8 @@ require (
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/sdk v1.24.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
Expand Down
16 changes: 10 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/Zur
cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac=
cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q=
cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU=
cloud.google.com/go/bigtable v1.26.0 h1:Gxk6UA21+3uz6QUm8d9wpxHznf6hr29HkwqWekfZ8Rs=
cloud.google.com/go/bigtable v1.26.0/go.mod h1:nqDsH+YoPA1oTmCEfWfsUGYV7NDIaufhwJgs+eh5bGo=
cloud.google.com/go/bigtable v1.27.1 h1:SFKsPZF+ddGmUFcwsHsajVRP1gg8JfvEe7ExqZ4SQ+c=
cloud.google.com/go/bigtable v1.27.1/go.mod h1:AMREzzQzYjiWYan7JvJXINc8dfqemnNBWDHlYONtPLw=
cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY=
cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s=
cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI=
Expand Down Expand Up @@ -254,8 +254,8 @@ cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFM
cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM=
cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4=
cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE=
cloud.google.com/go/discoveryengine v1.9.0 h1:4AXqQRiNtedoR8Ev/s5Rd2R4zaQ74PGNCQnDumCKbr8=
cloud.google.com/go/discoveryengine v1.9.0/go.mod h1:HsuZ6ZcRhS7TYaoJoWgcS17cOFBeDSprgsmh9FnQcpI=
cloud.google.com/go/discoveryengine v1.10.0 h1:LktMurW+kPEAHETzA5kGGG8v1wUW8ETtQahb86I1gw8=
cloud.google.com/go/discoveryengine v1.10.0/go.mod h1:KauPECIzETtH6VShNqCct4hU4ZtEJAoEz4cfIHkPpQc=
cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM=
cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q=
cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4=
Expand Down Expand Up @@ -323,8 +323,8 @@ cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGE
cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY=
cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY=
cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0=
cloud.google.com/go/iam v1.1.11 h1:0mQ8UKSfdHLut6pH9FM3bI55KWR46ketn0PuXleDyxw=
cloud.google.com/go/iam v1.1.11/go.mod h1:biXoiLWYIKntto2joP+62sd9uW5EpkZmKIvfNcTWlnQ=
cloud.google.com/go/iam v1.1.12 h1:JixGLimRrNGcxvJEQ8+clfLxPlbeZA6MuRJ+qJNQ5Xw=
cloud.google.com/go/iam v1.1.12/go.mod h1:9LDX8J7dN5YRyzVHxwQzrQs9opFFqn0Mxs9nAeB+Hhg=
cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc=
cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A=
cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk=
Expand Down Expand Up @@ -382,6 +382,8 @@ cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhI
cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4=
cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w=
cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw=
cloud.google.com/go/monitoring v1.20.1 h1:XmM6uk4+mI2ZhWdI2n/2GNhJdpeQN+1VdG2UWEDhX48=
cloud.google.com/go/monitoring v1.20.1/go.mod h1:FYSe/brgfuaXiEzOQFhTjsEsJv+WePyK71X7Y8qo6uQ=
cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA=
cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o=
cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM=
Expand Down Expand Up @@ -1115,6 +1117,8 @@ go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGX
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
go.opentelemetry.io/otel/sdk/metric v1.24.0 h1:yyMQrPzF+k88/DbH7o4FMAs80puqd+9osbiBrJrz/w8=
go.opentelemetry.io/otel/sdk/metric v1.24.0/go.mod h1:I6Y5FjH6rvEnTTAYQz3Mmv2kl6Ek5IIrmwTLqMrrOE0=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
Expand Down
5 changes: 4 additions & 1 deletion internal/spanner/alis_google_spanner_table_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
Expand Down Expand Up @@ -268,8 +269,10 @@ func (r *spannerTableResource) Schema(_ context.Context, _ resource.SchemaReques
},
"prevent_destroy": schema.BoolAttribute{
Optional: true,
Computed: true,
Description: "Prevent the table from being destroyed.\n" +
"**This only applies to the terraform state and does not prevent the actual table from being deleted via another source.**",
Default: booldefault.StaticBool(true),
},
},
Description: "A Google Cloud Spanner table resource.\n" +
Expand Down Expand Up @@ -756,7 +759,7 @@ func (r *spannerTableResource) Delete(ctx context.Context, req resource.DeleteRe
if state.PreventDestroy.ValueBool() {
resp.Diagnostics.AddError(
"Error Deleting Table",
"Table ("+state.Name.ValueString()+") is protected from deletion by terraform configuration.",
"Table ("+state.Name.ValueString()+") is protected from deletion by terraform configuration. Set `prevent_destroy` to false.",
)
return
}
Expand Down
56 changes: 27 additions & 29 deletions internal/spanner/services/services_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,35 +351,34 @@ func TestCreateSpannerTable(t *testing.T) {
Schema: &SpannerTableSchema{
Columns: []*SpannerTableColumn{
{
Name: "id",
Name: "key",
IsPrimaryKey: wrapperspb.Bool(true),
Unique: wrapperspb.Bool(false),
Type: "INT64",
Size: wrapperspb.Int64(255),
Required: wrapperspb.Bool(true),
},
{
Name: "portfolio",
Name: "test",
IsPrimaryKey: wrapperspb.Bool(false),
Unique: wrapperspb.Bool(false),
Type: "PROTO",
ProtoFileDescriptorSet: &ProtoFileDescriptorSet{
ProtoPackage: wrapperspb.String("alis.px.resources.portfolios.v1.Portfolio"),
ProtoPackage: wrapperspb.String("alis.px.services.data.v2.SpannerTest.NestedEnum"),
FileDescriptorSetPath: wrapperspb.String("gcs:gs://internal.descriptorset.alis-px-product-g51dmvo.alis.services/descriptorset.pb"),
FileDescriptorSetPathSource: ProtoFileDescriptorSetSourceGcs,
},
},
{
Name: "portfolio_name",
IsPrimaryKey: wrapperspb.Bool(true),
Unique: wrapperspb.Bool(false),
Type: "STRING",
IsComputed: wrapperspb.Bool(true),
ComputationDdl: wrapperspb.String("portfolio.name"),
Required: wrapperspb.Bool(true),
Size: wrapperspb.Int64(255),
DefaultValue: wrapperspb.String("default"),
},
//{
// Name: "branch_test",
// IsPrimaryKey: wrapperspb.Bool(false),
// Unique: wrapperspb.Bool(false),
// Type: "STRING",
// //IsComputed: wrapperspb.Bool(true),
// //ComputationDdl: wrapperspb.String("branch.name"),
// Required: wrapperspb.Bool(false),
// Size: wrapperspb.Int64(255),
//},
},
},
},
Expand Down Expand Up @@ -455,35 +454,34 @@ func TestUpdateSpannerTable(t *testing.T) {
Schema: &SpannerTableSchema{
Columns: []*SpannerTableColumn{
{
Name: "id",
Name: "key",
IsPrimaryKey: wrapperspb.Bool(true),
Unique: wrapperspb.Bool(false),
Type: "INT64",
Size: wrapperspb.Int64(255),
Required: wrapperspb.Bool(true),
},
{
Name: "portfolio",
Name: "test",
IsPrimaryKey: wrapperspb.Bool(false),
Unique: wrapperspb.Bool(false),
Type: "PROTO",
ProtoFileDescriptorSet: &ProtoFileDescriptorSet{
ProtoPackage: wrapperspb.String("alis.px.resources.portfolios.v1.Portfolio"),
ProtoPackage: wrapperspb.String("alis.px.resources.portfolios.v1.Branch"),
//FileDescriptorSetPath: wrapperspb.String("gcs:gs://internal.descriptorset.alis-px-product-g51dmvo.alis.services/descriptorset.pb"),
//FileDescriptorSetPathSource: ProtoFileDescriptorSetSourceGcs,
},
},
//{
// Name: "portfolio_name",
// IsPrimaryKey: wrapperspb.Bool(true),
// Unique: wrapperspb.Bool(false),
// Type: "STRING",
// IsComputed: wrapperspb.Bool(true),
// ComputationDdl: wrapperspb.String("portfolio.name"),
// Required: wrapperspb.Bool(true),
// Size: wrapperspb.Int64(255),
// DefaultValue: wrapperspb.String("default"),
//},
{
Name: "branch_tests",
//IsPrimaryKey: wrapperspb.Bool(false),
//Unique: wrapperspb.Bool(false),
Type: "ARRAY<STRING>",
//IsComputed: wrapperspb.Bool(true),
//ComputationDdl: wrapperspb.String("test.name"),
Required: wrapperspb.Bool(true),
//Size: wrapperspb.Int64(255),
},
},
},
},
Expand Down Expand Up @@ -1314,7 +1312,7 @@ func TestCreateProtoBundle(t *testing.T) {
args: args{
ctx: context.Background(),
databaseName: fmt.Sprintf("projects/%s/instances/%s/databases/%s", TestProject, TestInstance, "tf-test"),
protoPackageName: "alis.px.resources.portfolios.v1.NAVCommit",
protoPackageName: "alis.px.services.data.v2.SpannerTest",
},
},
}
Expand Down
104 changes: 77 additions & 27 deletions internal/spanner/services/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"log"
"sort"
"strings"
"time"
Expand Down Expand Up @@ -504,56 +503,107 @@ func CreateProtoBundle(ctx context.Context, databaseName string, protoPackageNam
return err
}

var getNestedProtoPackageNames func(ctx context.Context, desc protoreflect.Descriptor) ([]string, error)
getNestedProtoPackageNames = func(ctx context.Context, desc protoreflect.Descriptor) ([]string, error) {
// Unmarshal the proto file descriptor set
fds := &descriptorpb.FileDescriptorSet{}
if err := proto.Unmarshal(descriptorSet, fds); err != nil {
return status.Errorf(codes.Internal, "Error unmarshalling proto file descriptor set: %v", err)
}

files, err := protodesc.NewFiles(fds)
if err != nil {
return status.Errorf(codes.Internal, "Error creating proto files: %v", err)
}

var getProtoPackageNamesFn func(ctx context.Context, parent string, desc protoreflect.Descriptor) ([]string, error)
getProtoPackageNamesFn = func(ctx context.Context, parent string, desc protoreflect.Descriptor) ([]string, error) {
var protoPackageNames []string
switch d := desc.(type) {
case protoreflect.MessageDescriptor:
// Add the proto package name
protoPackageNames = append(protoPackageNames, fmt.Sprintf("%s", d.FullName()))

// Add the proto package names for the enums
for i := 0; i < d.Enums().Len(); i++ {
protoPackageNames = append(protoPackageNames, fmt.Sprintf("%s", d.Enums().Get(i).FullName()))
nestedProtoPackageParentNamesMap := map[string]protoreflect.Descriptor{}

for i := 0; i < d.Fields().Len(); i++ {
field := d.Fields().Get(i)

switch field.Kind() {
case protoreflect.MessageKind:
// Get nested proto package names
nestedProtoPackageNames, err := getProtoPackageNamesFn(ctx, parent, field.Message())
if err != nil {
return nil, err
}
protoPackageNames = append(protoPackageNames, nestedProtoPackageNames...)

// Get the nested proto package names of the parent
if field.Message().Parent() != nil {
nestedProtoPackageParentName := fmt.Sprintf("%s", field.Message().Parent().FullName())
nestedProtoPackageParentNamesMap[nestedProtoPackageParentName] = field.Message().Parent()
}
case protoreflect.EnumKind:
protoPackageNames = append(protoPackageNames, fmt.Sprintf("%s", field.Enum().FullName()))

// Get the nested proto package names of the parent
if field.Enum().Parent() != nil {
nestedProtoPackageParentName := fmt.Sprintf("%s", field.Enum().Parent().FullName())
nestedProtoPackageParentNamesMap[nestedProtoPackageParentName] = field.Enum().Parent()
}
}
}

// Add the proto package names for the nested messages
for i := 0; i < d.Messages().Len(); i++ {
nestedProtoPackageNames, err := getNestedProtoPackageNames(ctx, d.Messages().Get(i))
// Get the nested proto package names of the parents
for nestedProtoPackageParentName, nestedDesc := range nestedProtoPackageParentNamesMap {
if nestedProtoPackageParentName == parent {
continue
}

nestedProtoPackageNames, err := getProtoPackageNamesFn(ctx, nestedProtoPackageParentName, nestedDesc)
if err != nil {
return nil, err
}

protoPackageNames = append(protoPackageNames, nestedProtoPackageNames...)
}
}
case protoreflect.EnumDescriptor:
// Add the proto package name
protoPackageNames = append(protoPackageNames, fmt.Sprintf("%s", d.FullName()))

return protoPackageNames, nil
}
if d.Parent() != nil {
// Get the nested proto package names of the parent
nestedProtoPackageParentName := fmt.Sprintf("%s", d.Parent().FullName())

// Unmarshal the proto file descriptor set
fds := &descriptorpb.FileDescriptorSet{}
if err := proto.Unmarshal(descriptorSet, fds); err != nil {
return status.Errorf(codes.Internal, "Error unmarshalling proto file descriptor set: %v", err)
}
// Get the nested proto package names of the parents
nestedProtoPackageNames, err := getProtoPackageNamesFn(ctx, nestedProtoPackageParentName, d.Parent())
if err != nil {
return nil, err
}

files, err := protodesc.NewFiles(fds)
if err != nil {
return status.Errorf(codes.Internal, "Error creating proto files: %v", err)
protoPackageNames = append(protoPackageNames, nestedProtoPackageNames...)

}
}

return protoPackageNames, nil
}

// Get the message/enum descriptor
desc, err := files.FindDescriptorByName(protoreflect.FullName(protoPackageName))
if err != nil {
return status.Errorf(codes.Internal, "Error finding descriptor for %s: %v", protoPackageName, err)
}

// TODO: Revisit later
nestedProtoPackageNames, err := getNestedProtoPackageNames(ctx, desc)
// Get the proto package names including nested messages and enums
protoPackageNames, err := getProtoPackageNamesFn(ctx, protoPackageName, desc)
if err != nil {
return err
}

log.Printf("nestedProtoPackageNames: %v", nestedProtoPackageNames)
// Remove any duplicates
protoPackageNames = alUtils.Unique(protoPackageNames)

// Sort the proto package names
sort.Strings(protoPackageNames)

updateDatabaseDdl := func(ctx context.Context, databaseName string, statements []string, descriptorSet []byte) error {
// Create the proto bundle
Expand All @@ -569,27 +619,27 @@ func CreateProtoBundle(ctx context.Context, databaseName string, protoPackageNam
return updateDdlOp.Wait(ctx)
}

formattedNestedProtoPackageNames := alUtils.Transform(nestedProtoPackageNames, func(name string) string {
formattedProtoPackageNames := alUtils.Transform(protoPackageNames, func(name string) string {
return fmt.Sprintf("`%s`", name)
})

createStatement := fmt.Sprintf("CREATE PROTO BUNDLE (%s)", strings.Join(formattedNestedProtoPackageNames, ", "))
createStatement := fmt.Sprintf("CREATE PROTO BUNDLE (%s)", strings.Join(formattedProtoPackageNames, ", "))
err = updateDatabaseDdl(ctx, databaseName, []string{createStatement}, descriptorSet)
if err != nil {
if status.Code(err) != codes.AlreadyExists && status.Code(err) != codes.InvalidArgument {
return err
}

// Try to insert the proto bundle
insertStatement := fmt.Sprintf("ALTER PROTO BUNDLE INSERT (%s)", strings.Join(formattedNestedProtoPackageNames, ", "))
insertStatement := fmt.Sprintf("ALTER PROTO BUNDLE INSERT (%s)", strings.Join(formattedProtoPackageNames, ", "))
err = updateDatabaseDdl(ctx, databaseName, []string{insertStatement}, descriptorSet)
if err != nil {
if status.Code(err) != codes.AlreadyExists && status.Code(err) != codes.InvalidArgument {
return err
}

// Try to update the proto bundle
updateStatement := fmt.Sprintf("ALTER PROTO BUNDLE UPDATE (%s)", strings.Join(formattedNestedProtoPackageNames, ", "))
updateStatement := fmt.Sprintf("ALTER PROTO BUNDLE UPDATE (%s)", strings.Join(formattedProtoPackageNames, ", "))
err = updateDatabaseDdl(ctx, databaseName, []string{updateStatement}, descriptorSet)
if err != nil {
return err
Expand Down

0 comments on commit 9beea05

Please sign in to comment.