From 8687d0a6c56ff19b0a2b7d3311d50bb0eee5a32e Mon Sep 17 00:00:00 2001 From: Sergey Passichenko Date: Tue, 17 Oct 2023 16:16:00 -0700 Subject: [PATCH 1/6] 1 --- proto/lekko/feature/v1beta1/feature.proto | 2 ++ 1 file changed, 2 insertions(+) diff --git a/proto/lekko/feature/v1beta1/feature.proto b/proto/lekko/feature/v1beta1/feature.proto index 1204ebca..b96c058d 100644 --- a/proto/lekko/feature/v1beta1/feature.proto +++ b/proto/lekko/feature/v1beta1/feature.proto @@ -17,6 +17,7 @@ syntax = "proto3"; package lekko.feature.v1beta1; import "google/protobuf/any.proto"; +import "google/protobuf/struct.proto"; import "lekko/rules/v1beta2/rules.proto"; import "lekko/rules/v1beta3/rules.proto"; @@ -30,6 +31,7 @@ message Feature { string description = 2; Tree tree = 3; FeatureType type = 4; + google.protobuf.Value metadata = 7; } // Enumerates the canonical types that lekko supports From 867ec3e6ce49568b549f17e1ebac8c5c9ffca96b Mon Sep 17 00:00:00 2001 From: Sergey Passichenko Date: Thu, 19 Oct 2023 14:58:22 -0700 Subject: [PATCH 2/6] support config metadata --- pkg/star/feature.go | 18 ++++++++++ pkg/star/static/traverse.go | 17 ++++++++++ pkg/star/static/walk.go | 42 ++++++++++++++++++++++-- proto/lekko/feature/v1beta1/static.proto | 2 ++ 4 files changed, 77 insertions(+), 2 deletions(-) diff --git a/pkg/star/feature.go b/pkg/star/feature.go index 1509ef25..eef59491 100644 --- a/pkg/star/feature.go +++ b/pkg/star/feature.go @@ -39,6 +39,7 @@ const ( ResultVariableName string = "result" DefaultValueAttrName string = "default" DescriptionAttrName string = "description" + MetadataAttrName string = "metadata" // TODO: Fully migrate to overrides over rules RulesAttrName string = "rules" OverridesAttrName string = "overrides" @@ -54,6 +55,7 @@ var ( OverridesAttrName: {}, validatorAttrName: {}, unitTestsAttrName: {}, + MetadataAttrName: {}, } ) @@ -295,6 +297,22 @@ func (fb *featureBuilder) getDescription(featureVal *starlarkstruct.Struct) (str return dsc.GoString(), nil } +func (fb *featureBuilder) getMetadata(featureVal *starlarkstruct.Struct) (*structpb.Value, error) { + metadataVal, err := featureVal.Attr(MetadataAttrName) + if err != nil { + return nil, errors.Wrap(err, "metadata attribute") + } + metadataDict, ok := metadataVal.(*starlark.Dict) + if !ok { + return nil, fmt.Errorf("metadata must be a dict (got a %s)", metadataVal.Type()) + } + metadataMap, err := translateContext(metadataDict) + if err != nil { + return nil, errors.Wrap(err, "translate metadata attribute") + } + return structpb.NewValue(metadataMap) +} + func (fb *featureBuilder) addOverrides(f *feature.Feature, featureVal *starlarkstruct.Struct) ([]starlark.Value, error) { overridesVal, err := featureVal.Attr(OverridesAttrName) if err != nil { diff --git a/pkg/star/static/traverse.go b/pkg/star/static/traverse.go index acf21a82..406f5589 100644 --- a/pkg/star/static/traverse.go +++ b/pkg/star/static/traverse.go @@ -30,6 +30,7 @@ const ( ResultVariableName string = "result" DefaultValueAttrName string = "default" DescriptionAttrName string = "description" + MetadataAttrName string = "metadata" // TODO: Fully migrate to overrides over rules RulesAttrName string = "rules" OverridesAttrName string = "overrides" @@ -40,11 +41,13 @@ func defaultNoop(v *build.Expr) error { return nil } func descriptionNoop(v *build.StringExpr) error { return nil } func rulesNoop(rules *overridesWrapper) error { return nil } func importsNoop(imports *importsWrapper) error { return nil } +func metadataNoop(ast *starFeatureAST) error { return nil} type defaultFn func(v *build.Expr) error type descriptionFn func(v *build.StringExpr) error type overridesFn func(rules *overridesWrapper) error type importsFn func(imports *importsWrapper) error +type metadataFn func(ast *starFeatureAST) error // Traverses a lekko starlark file, running methods on various // components of the file. Methods can be provided to read the @@ -57,6 +60,7 @@ type traverser struct { descriptionFn descriptionFn overridesFn overridesFn protoImportsFn importsFn + metadataFn metadataFn } func newTraverser(f *build.File, nv feature.NamespaceVersion) *traverser { @@ -67,6 +71,7 @@ func newTraverser(f *build.File, nv feature.NamespaceVersion) *traverser { descriptionFn: descriptionNoop, overridesFn: rulesNoop, protoImportsFn: importsNoop, + metadataFn: metadataNoop, } } @@ -90,6 +95,11 @@ func (t *traverser) withProtoImportsFn(fn importsFn) *traverser { return t } +func (t *traverser) withMetadataFn(fn metadataFn) *traverser { + t.metadataFn = fn + return t +} + func (t *traverser) traverse() error { imports := t.getProtoImports() if err := t.protoImportsFn(imports); err != nil { @@ -118,6 +128,9 @@ func (t *traverser) traverse() error { if err := t.descriptionFn(descriptionStr); err != nil { return errors.Wrap(err, "description fn") } + if err := t.metadataFn(ast); err != nil { + return errors.Wrap(err, "metadata fn") + } // rules if err := ast.parseOverrides(t.overridesFn, t.nv); err != nil { return err @@ -326,6 +339,10 @@ type importVal struct { assignExpr *build.AssignExpr } +type metadataWrapper struct { + metadataExpr *build.DictExpr +} + func newOverride(li build.Expr) (*override, error) { tupleV, ok := li.(*build.TupleExpr) if !ok { diff --git a/pkg/star/static/walk.go b/pkg/star/static/walk.go index f355e6fd..1b5587cf 100644 --- a/pkg/star/static/walk.go +++ b/pkg/star/static/walk.go @@ -85,7 +85,8 @@ func (w *walker) Build() (*featurev1beta1.StaticFeature, error) { withDefaultFn(w.buildDefaultFn(ret)). withDescriptionFn(w.buildDescriptionFn(ret)). withOverridesFn(w.buildRulesFn(ret)). - withProtoImportsFn(w.buildProtoImportsFn(ret)) + withProtoImportsFn(w.buildProtoImportsFn(ret)). + withMetadataFn(w.buildMetadataFn(ret)) if err := t.traverse(); err != nil { return nil, errors.Wrap(err, "traverse") @@ -101,7 +102,8 @@ func (w *walker) Mutate(f *featurev1beta1.StaticFeature) ([]byte, error) { t := newTraverser(ast, w.nv). withDefaultFn(w.mutateDefaultFn(f)). withDescriptionFn(w.mutateDescriptionFn(f)). - withOverridesFn(w.mutateOverridesFn(f)) + withOverridesFn(w.mutateOverridesFn(f)). + withMetadataFn(w.mutateMetadataFn(f)) if err := t.traverse(); err != nil { return nil, errors.Wrap(err, "traverse") @@ -240,6 +242,27 @@ func (w *walker) buildDescriptionFn(f *featurev1beta1.StaticFeature) description } } +func (w *walker) buildMetadataFn(f *featurev1beta1.StaticFeature) metadataFn { + return func(ast *starFeatureAST) error { + metadataExprPtr, found := ast.get(MetadataAttrName) + if !found { + return nil + } + metadataExpr := *metadataExprPtr + metadataDict, ok := metadataExpr.(*build.DictExpr) + if !ok { + return errors.Wrapf(ErrUnsupportedStaticParsing, "metadata kwarg: expected dict, got %T", metadataExpr) + } + metadataValue, err := w.extractJSONValue(metadataDict) + if err != nil { + return errors.Wrap(err, "extract metadata") + } + f.Feature.Metadata = metadataValue + f.FeatureOld.Metadata = metadataValue + return nil + } +} + func (w *walker) buildRulesFn(f *featurev1beta1.StaticFeature) overridesFn { return func(overridesW *overridesWrapper) error { for i, o := range overridesW.overrides { @@ -485,6 +508,21 @@ func (w *walker) mutateDescriptionFn(f *featurev1beta1.StaticFeature) descriptio } } +func (w *walker) mutateMetadataFn(f *featurev1beta1.StaticFeature) metadataFn { + return func(ast *starFeatureAST) error { + metadataProto := f.FeatureOld.GetMetadata() + if metadataProto == nil { + return nil + } + metadataStarDict, err := w.genJSONValue(metadataProto, nil) + if err != nil { + return err + } + ast.set(MetadataAttrName, metadataStarDict) + return nil + } +} + func (w *walker) mutateOverridesFn(f *featurev1beta1.StaticFeature) overridesFn { return func(overridesW *overridesWrapper) error { var newOverrides []override diff --git a/proto/lekko/feature/v1beta1/static.proto b/proto/lekko/feature/v1beta1/static.proto index e6a7db68..4e47aa3a 100644 --- a/proto/lekko/feature/v1beta1/static.proto +++ b/proto/lekko/feature/v1beta1/static.proto @@ -16,6 +16,7 @@ syntax = "proto3"; package lekko.feature.v1beta1; +import "google/protobuf/struct.proto"; import "lekko/feature/v1beta1/feature.proto"; // Represents a statically parsed feature. @@ -47,6 +48,7 @@ message FeatureStruct { string description = 2; StarExpr default = 3; Rules rules = 4; + google.protobuf.Value metadata = 7; } message Rules { From 58099749430586e2e3717e35c918f05e20baaf17 Mon Sep 17 00:00:00 2001 From: Sergey Passichenko Date: Thu, 19 Oct 2023 15:27:44 -0700 Subject: [PATCH 3/6] lint + extract metadata when compiling from cli --- pkg/feature/feature.go | 1 + pkg/star/feature.go | 11 ++++++++--- pkg/star/static/traverse.go | 10 +++------- pkg/star/static/walk.go | 2 +- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/pkg/feature/feature.go b/pkg/feature/feature.go index 2957ed26..13351e3c 100644 --- a/pkg/feature/feature.go +++ b/pkg/feature/feature.go @@ -361,6 +361,7 @@ type Feature struct { Value interface{} FeatureType eval.ConfigType Namespace string + Metadata map[string]any Overrides []*Override UnitTests []UnitTest diff --git a/pkg/star/feature.go b/pkg/star/feature.go index eef59491..ed3878c9 100644 --- a/pkg/star/feature.go +++ b/pkg/star/feature.go @@ -155,6 +155,10 @@ func (fb *featureBuilder) Build() (*feature.CompiledFeature, error) { return nil, errors.Wrap(err, "description") } f.Namespace = fb.namespace + f.Metadata, err = fb.getMetadata(featureVal) + if err != nil { + return nil, errors.Wrap(err, "metadata") + } overrideVals, err := fb.addOverrides(f, featureVal) if err != nil { @@ -297,10 +301,11 @@ func (fb *featureBuilder) getDescription(featureVal *starlarkstruct.Struct) (str return dsc.GoString(), nil } -func (fb *featureBuilder) getMetadata(featureVal *starlarkstruct.Struct) (*structpb.Value, error) { +func (fb *featureBuilder) getMetadata(featureVal *starlarkstruct.Struct) (map[string]any, error) { metadataVal, err := featureVal.Attr(MetadataAttrName) if err != nil { - return nil, errors.Wrap(err, "metadata attribute") + //lint:ignore nilerr `Struct.Attr` returns error if attribute doesn't exist + return nil, nil } metadataDict, ok := metadataVal.(*starlark.Dict) if !ok { @@ -310,7 +315,7 @@ func (fb *featureBuilder) getMetadata(featureVal *starlarkstruct.Struct) (*struc if err != nil { return nil, errors.Wrap(err, "translate metadata attribute") } - return structpb.NewValue(metadataMap) + return metadataMap, nil } func (fb *featureBuilder) addOverrides(f *feature.Feature, featureVal *starlarkstruct.Struct) ([]starlark.Value, error) { diff --git a/pkg/star/static/traverse.go b/pkg/star/static/traverse.go index 406f5589..aea6534f 100644 --- a/pkg/star/static/traverse.go +++ b/pkg/star/static/traverse.go @@ -41,7 +41,7 @@ func defaultNoop(v *build.Expr) error { return nil } func descriptionNoop(v *build.StringExpr) error { return nil } func rulesNoop(rules *overridesWrapper) error { return nil } func importsNoop(imports *importsWrapper) error { return nil } -func metadataNoop(ast *starFeatureAST) error { return nil} +func metadataNoop(ast *starFeatureAST) error { return nil } type defaultFn func(v *build.Expr) error type descriptionFn func(v *build.StringExpr) error @@ -71,7 +71,7 @@ func newTraverser(f *build.File, nv feature.NamespaceVersion) *traverser { descriptionFn: descriptionNoop, overridesFn: rulesNoop, protoImportsFn: importsNoop, - metadataFn: metadataNoop, + metadataFn: metadataNoop, } } @@ -98,7 +98,7 @@ func (t *traverser) withProtoImportsFn(fn importsFn) *traverser { func (t *traverser) withMetadataFn(fn metadataFn) *traverser { t.metadataFn = fn return t -} +} func (t *traverser) traverse() error { imports := t.getProtoImports() @@ -339,10 +339,6 @@ type importVal struct { assignExpr *build.AssignExpr } -type metadataWrapper struct { - metadataExpr *build.DictExpr -} - func newOverride(li build.Expr) (*override, error) { tupleV, ok := li.(*build.TupleExpr) if !ok { diff --git a/pkg/star/static/walk.go b/pkg/star/static/walk.go index 1b5587cf..8816a9bf 100644 --- a/pkg/star/static/walk.go +++ b/pkg/star/static/walk.go @@ -514,7 +514,7 @@ func (w *walker) mutateMetadataFn(f *featurev1beta1.StaticFeature) metadataFn { if metadataProto == nil { return nil } - metadataStarDict, err := w.genJSONValue(metadataProto, nil) + metadataStarDict, err := w.genJSONValue(metadataProto, nil) if err != nil { return err } From a3f03166e85bae5ea7387a6ab7f5683b559c664e Mon Sep 17 00:00:00 2001 From: Sergey Passichenko Date: Thu, 19 Oct 2023 15:41:45 -0700 Subject: [PATCH 4/6] update protos from buf --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 15e65462..f849ced8 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/lekkodev/cli go 1.20 require ( - buf.build/gen/go/lekkodev/cli/bufbuild/connect-go v1.10.0-20230808195657-843d07fa9e34.1 - buf.build/gen/go/lekkodev/cli/protocolbuffers/go v1.31.0-20230808195657-843d07fa9e34.1 + buf.build/gen/go/lekkodev/cli/bufbuild/connect-go v1.10.0-20231019182200-bf5993a63215.1 + buf.build/gen/go/lekkodev/cli/protocolbuffers/go v1.31.0-20231019182200-bf5993a63215.1 github.com/AlecAivazis/survey/v2 v2.3.6 github.com/bazelbuild/buildtools v0.0.0-20220907133145-b9bfff5d7f91 github.com/bufbuild/connect-go v1.10.0 diff --git a/go.sum b/go.sum index e2a8478b..f3829f5b 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ -buf.build/gen/go/lekkodev/cli/bufbuild/connect-go v1.10.0-20230808195657-843d07fa9e34.1 h1:mt4QLKZtQwEBqRm2bi7aj4/PJ8AJQg2Tq0G3hJHzwHc= -buf.build/gen/go/lekkodev/cli/bufbuild/connect-go v1.10.0-20230808195657-843d07fa9e34.1/go.mod h1:15ARpvleKTFJ7xogv/ihJL1cigfDJij4juFMBQzY+Eo= -buf.build/gen/go/lekkodev/cli/protocolbuffers/go v1.31.0-20230808195657-843d07fa9e34.1 h1:VA17A//BYMH5yjd1ADllRk5p+fmIUQ7mauEZ31zKdDM= -buf.build/gen/go/lekkodev/cli/protocolbuffers/go v1.31.0-20230808195657-843d07fa9e34.1/go.mod h1:mYcnts9MJhUckfRD5/qOThXC7Kaj7O714LOw5GoGZ9c= +buf.build/gen/go/lekkodev/cli/bufbuild/connect-go v1.10.0-20231019182200-bf5993a63215.1 h1:BwvI+w/S2N1l+UxOypD6B97J9yQOuraDHtmd6p1DVwA= +buf.build/gen/go/lekkodev/cli/bufbuild/connect-go v1.10.0-20231019182200-bf5993a63215.1/go.mod h1:wn4VgRwpFL7yJp8F+7REWc5WtA+7cmZia4n8iV2nzcw= +buf.build/gen/go/lekkodev/cli/protocolbuffers/go v1.31.0-20231019182200-bf5993a63215.1 h1:8ax4GaVV2IIKJuSCsZqJPEZiLVPOrIQiwip9j45Y+zs= +buf.build/gen/go/lekkodev/cli/protocolbuffers/go v1.31.0-20231019182200-bf5993a63215.1/go.mod h1:mYcnts9MJhUckfRD5/qOThXC7Kaj7O714LOw5GoGZ9c= buf.build/gen/go/lekkodev/sdk/protocolbuffers/go v1.31.0-20230419180142-0694c10ef23c.1/go.mod h1:UOnQUnbc9uR4s5SlhBKspO4dffz+T3A6X200yYBnaZg= buf.build/gen/go/lekkodev/sdk/protocolbuffers/go v1.31.0-20230810202034-1c821065b9a0.1 h1:jd5EUbnTPSEuCL+U3TsK4fjym4eVveXJCOssOUOiJcM= buf.build/gen/go/lekkodev/sdk/protocolbuffers/go v1.31.0-20230810202034-1c821065b9a0.1/go.mod h1:UOnQUnbc9uR4s5SlhBKspO4dffz+T3A6X200yYBnaZg= From 09685e578116d832e922fe10e53820a228d6b98b Mon Sep 17 00:00:00 2001 From: Sergey Passichenko Date: Thu, 19 Oct 2023 17:30:36 -0700 Subject: [PATCH 5/6] bump namespace version --- pkg/feature/feature.go | 2 ++ pkg/feature/version.go | 3 +++ pkg/feature/version_test.go | 1 + pkg/star/feature.go | 8 +++++--- pkg/star/static/traverse.go | 6 ++++-- proto/lekko/feature/v1beta1/feature.proto | 2 +- proto/lekko/feature/v1beta1/static.proto | 6 +++--- 7 files changed, 19 insertions(+), 9 deletions(-) diff --git a/pkg/feature/feature.go b/pkg/feature/feature.go index 13351e3c..fcdd8445 100644 --- a/pkg/feature/feature.go +++ b/pkg/feature/feature.go @@ -171,6 +171,8 @@ func GroupFeatureFiles( func ComplianceCheck(f FeatureFile, nsMD *metadata.NamespaceConfigRepoMetadata) error { switch nsMD.Version { + case "v1beta7": + fallthrough case "v1beta6": fallthrough case "v1beta5": diff --git a/pkg/feature/version.go b/pkg/feature/version.go index 72638667..d3f61546 100644 --- a/pkg/feature/version.go +++ b/pkg/feature/version.go @@ -30,6 +30,8 @@ const ( NamespaceVersionV1Beta5 NamespaceVersion = "v1beta5" // Supports using "overrides" instead of "rules" and "export(Config(...))" instead of "result = feature(...)" (dual support) NamespaceVersionV1Beta6 NamespaceVersion = "v1beta6" + // Supports `metadata` field + NamespaceVersionV1Beta7 NamespaceVersion = "v1beta7" ) var ( @@ -50,6 +52,7 @@ func AllNamespaceVersions() []NamespaceVersion { NamespaceVersionV1Beta4, NamespaceVersionV1Beta5, NamespaceVersionV1Beta6, + NamespaceVersionV1Beta7, } } diff --git a/pkg/feature/version_test.go b/pkg/feature/version_test.go index 9fa98c9a..9d840f51 100644 --- a/pkg/feature/version_test.go +++ b/pkg/feature/version_test.go @@ -28,6 +28,7 @@ func TestPriorVersionsSupported(t *testing.T) { assert.Contains(t, supported, NamespaceVersionV1Beta4) assert.Contains(t, supported, NamespaceVersionV1Beta5) assert.Contains(t, supported, NamespaceVersionV1Beta6) + assert.Contains(t, supported, NamespaceVersionV1Beta7) } func TestVersionOrder(t *testing.T) { diff --git a/pkg/star/feature.go b/pkg/star/feature.go index ed3878c9..034a09e7 100644 --- a/pkg/star/feature.go +++ b/pkg/star/feature.go @@ -155,9 +155,11 @@ func (fb *featureBuilder) Build() (*feature.CompiledFeature, error) { return nil, errors.Wrap(err, "description") } f.Namespace = fb.namespace - f.Metadata, err = fb.getMetadata(featureVal) - if err != nil { - return nil, errors.Wrap(err, "metadata") + if fb.nv >= feature.NamespaceVersionV1Beta7 { + f.Metadata, err = fb.getMetadata(featureVal) + if err != nil { + return nil, errors.Wrap(err, "metadata") + } } overrideVals, err := fb.addOverrides(f, featureVal) diff --git a/pkg/star/static/traverse.go b/pkg/star/static/traverse.go index aea6534f..7f4d97a2 100644 --- a/pkg/star/static/traverse.go +++ b/pkg/star/static/traverse.go @@ -128,8 +128,10 @@ func (t *traverser) traverse() error { if err := t.descriptionFn(descriptionStr); err != nil { return errors.Wrap(err, "description fn") } - if err := t.metadataFn(ast); err != nil { - return errors.Wrap(err, "metadata fn") + if t.nv >= feature.NamespaceVersionV1Beta7 { + if err := t.metadataFn(ast); err != nil { + return errors.Wrap(err, "metadata fn") + } } // rules if err := ast.parseOverrides(t.overridesFn, t.nv); err != nil { diff --git a/proto/lekko/feature/v1beta1/feature.proto b/proto/lekko/feature/v1beta1/feature.proto index b96c058d..068171d2 100644 --- a/proto/lekko/feature/v1beta1/feature.proto +++ b/proto/lekko/feature/v1beta1/feature.proto @@ -31,7 +31,7 @@ message Feature { string description = 2; Tree tree = 3; FeatureType type = 4; - google.protobuf.Value metadata = 7; + google.protobuf.Struct metadata = 7; } // Enumerates the canonical types that lekko supports diff --git a/proto/lekko/feature/v1beta1/static.proto b/proto/lekko/feature/v1beta1/static.proto index 4e47aa3a..eb446892 100644 --- a/proto/lekko/feature/v1beta1/static.proto +++ b/proto/lekko/feature/v1beta1/static.proto @@ -41,14 +41,14 @@ message StaticFeature { lekko.feature.v1beta1.Feature feature_old = 5; } -// Represents everything stored in the feature struct in starlark. -// i.e. `feature(...)` +// Represents everything stored in the config struct in starlark. +// i.e. `Config(...)` message FeatureStruct { StarMeta meta = 1; string description = 2; StarExpr default = 3; Rules rules = 4; - google.protobuf.Value metadata = 7; + google.protobuf.Struct metadata = 7; } message Rules { From bda6981643f443d9e437c9da38575c8df7e34506 Mon Sep 17 00:00:00 2001 From: Sergey Passichenko Date: Fri, 20 Oct 2023 09:44:21 -0700 Subject: [PATCH 6/6] proto value -> proto struct --- go.mod | 4 +- go.sum | 8 ++-- pkg/star/static/walk.go | 82 ++++++++++++++++++++++++----------------- 3 files changed, 55 insertions(+), 39 deletions(-) diff --git a/go.mod b/go.mod index f849ced8..ce6dd935 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/lekkodev/cli go 1.20 require ( - buf.build/gen/go/lekkodev/cli/bufbuild/connect-go v1.10.0-20231019182200-bf5993a63215.1 - buf.build/gen/go/lekkodev/cli/protocolbuffers/go v1.31.0-20231019182200-bf5993a63215.1 + buf.build/gen/go/lekkodev/cli/bufbuild/connect-go v1.10.0-20231020162356-e763402ec965.1 + buf.build/gen/go/lekkodev/cli/protocolbuffers/go v1.31.0-20231020162356-e763402ec965.1 github.com/AlecAivazis/survey/v2 v2.3.6 github.com/bazelbuild/buildtools v0.0.0-20220907133145-b9bfff5d7f91 github.com/bufbuild/connect-go v1.10.0 diff --git a/go.sum b/go.sum index f3829f5b..1f7e716a 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ -buf.build/gen/go/lekkodev/cli/bufbuild/connect-go v1.10.0-20231019182200-bf5993a63215.1 h1:BwvI+w/S2N1l+UxOypD6B97J9yQOuraDHtmd6p1DVwA= -buf.build/gen/go/lekkodev/cli/bufbuild/connect-go v1.10.0-20231019182200-bf5993a63215.1/go.mod h1:wn4VgRwpFL7yJp8F+7REWc5WtA+7cmZia4n8iV2nzcw= -buf.build/gen/go/lekkodev/cli/protocolbuffers/go v1.31.0-20231019182200-bf5993a63215.1 h1:8ax4GaVV2IIKJuSCsZqJPEZiLVPOrIQiwip9j45Y+zs= -buf.build/gen/go/lekkodev/cli/protocolbuffers/go v1.31.0-20231019182200-bf5993a63215.1/go.mod h1:mYcnts9MJhUckfRD5/qOThXC7Kaj7O714LOw5GoGZ9c= +buf.build/gen/go/lekkodev/cli/bufbuild/connect-go v1.10.0-20231020162356-e763402ec965.1 h1:iGIRelUi9fFwQ15Op90jP73+L8T0M8uewZeI6WXW8+s= +buf.build/gen/go/lekkodev/cli/bufbuild/connect-go v1.10.0-20231020162356-e763402ec965.1/go.mod h1:hJtG6Y49OSN1DhCYPGaCkfN1jibDflptgnHnLJo/Nl0= +buf.build/gen/go/lekkodev/cli/protocolbuffers/go v1.31.0-20231020162356-e763402ec965.1 h1:YzjpTz4MgOa+EhI6lbIFLBAUTgQf2aVSIUoZlPBBv2k= +buf.build/gen/go/lekkodev/cli/protocolbuffers/go v1.31.0-20231020162356-e763402ec965.1/go.mod h1:mYcnts9MJhUckfRD5/qOThXC7Kaj7O714LOw5GoGZ9c= buf.build/gen/go/lekkodev/sdk/protocolbuffers/go v1.31.0-20230419180142-0694c10ef23c.1/go.mod h1:UOnQUnbc9uR4s5SlhBKspO4dffz+T3A6X200yYBnaZg= buf.build/gen/go/lekkodev/sdk/protocolbuffers/go v1.31.0-20230810202034-1c821065b9a0.1 h1:jd5EUbnTPSEuCL+U3TsK4fjym4eVveXJCOssOUOiJcM= buf.build/gen/go/lekkodev/sdk/protocolbuffers/go v1.31.0-20230810202034-1c821065b9a0.1/go.mod h1:UOnQUnbc9uR4s5SlhBKspO4dffz+T3A6X200yYBnaZg= diff --git a/pkg/star/static/walk.go b/pkg/star/static/walk.go index 8816a9bf..1eb43ea2 100644 --- a/pkg/star/static/walk.go +++ b/pkg/star/static/walk.go @@ -213,27 +213,35 @@ func (w *walker) extractJSONValue(v build.Expr) (*structpb.Value, error) { } return structpb.NewListValue(listVal), nil case *build.DictExpr: - structVal := structpb.Struct{ - Fields: map[string]*structpb.Value{}, - } - for _, kvExpr := range t.List { - kvExpr := kvExpr - keyExpr, ok := kvExpr.Key.(*build.StringExpr) - if !ok { - return nil, errors.Wrapf(ErrUnsupportedStaticParsing, "json structs must have keys of type string, not %T", kvExpr.Key) - } - key := keyExpr.Value - vVar, err := w.extractJSONValue(kvExpr.Value) - if err != nil { - return nil, errors.Wrap(err, "extract struct elem value") - } - structVal.Fields[key] = vVar + structVal, err := w.extractJSONStruct(t) + if err != nil { + return nil, err } - return structpb.NewStructValue(&structVal), nil + return structpb.NewStructValue(structVal), nil } return nil, errors.Wrapf(ErrUnsupportedStaticParsing, "type %T", v) } +func (w *walker) extractJSONStruct(d *build.DictExpr) (*structpb.Struct, error) { + structVal := structpb.Struct{ + Fields: map[string]*structpb.Value{}, + } + for _, kvExpr := range d.List { + kvExpr := kvExpr + keyExpr, ok := kvExpr.Key.(*build.StringExpr) + if !ok { + return nil, errors.Wrapf(ErrUnsupportedStaticParsing, "json structs must have keys of type string, not %T", kvExpr.Key) + } + key := keyExpr.Value + vVar, err := w.extractJSONValue(kvExpr.Value) + if err != nil { + return nil, errors.Wrap(err, "extract struct elem value") + } + structVal.Fields[key] = vVar + } + return &structVal, nil +} + func (w *walker) buildDescriptionFn(f *featurev1beta1.StaticFeature) descriptionFn { return func(v *build.StringExpr) error { f.Feature.Description = v.Value @@ -253,12 +261,12 @@ func (w *walker) buildMetadataFn(f *featurev1beta1.StaticFeature) metadataFn { if !ok { return errors.Wrapf(ErrUnsupportedStaticParsing, "metadata kwarg: expected dict, got %T", metadataExpr) } - metadataValue, err := w.extractJSONValue(metadataDict) + metadataStruct, err := w.extractJSONStruct(metadataDict) if err != nil { return errors.Wrap(err, "extract metadata") } - f.Feature.Metadata = metadataValue - f.FeatureOld.Metadata = metadataValue + f.Feature.Metadata = metadataStruct + f.FeatureOld.Metadata = metadataStruct return nil } } @@ -428,6 +436,24 @@ func (w *walker) genValue(a *anypb.Any, sf *featurev1beta1.StaticFeature, meta * } } +func (w *walker) genJSONStruct(s *structpb.Struct, meta *featurev1beta1.StarMeta) (*build.DictExpr, error) { + dictExpr := &build.DictExpr{ + ForceMultiLine: true, + } + for key, value := range s.Fields { + valExpr, err := w.genJSONValue(value, meta) + if err != nil { + return nil, errors.Wrap(err, "gen value dict elem") + } + dictExpr.List = append(dictExpr.List, &build.KeyValueExpr{ + Key: starString(key), + Value: valExpr, + }) + } + sortKVs(dictExpr.List) + return dictExpr, nil +} + func (w *walker) genJSONValue(val *structpb.Value, meta *featurev1beta1.StarMeta) (build.Expr, error) { switch k := val.Kind.(type) { case *structpb.Value_NullValue: @@ -457,20 +483,10 @@ func (w *walker) genJSONValue(val *structpb.Value, meta *featurev1beta1.StarMeta } return listExpr, nil case *structpb.Value_StructValue: - dictExpr := &build.DictExpr{ - ForceMultiLine: true, - } - for key, value := range k.StructValue.Fields { - valExpr, err := w.genJSONValue(value, meta) - if err != nil { - return nil, errors.Wrap(err, "gen value dict elem") - } - dictExpr.List = append(dictExpr.List, &build.KeyValueExpr{ - Key: starString(key), - Value: valExpr, - }) + dictExpr, err := w.genJSONStruct(k.StructValue, meta) + if err != nil { + return nil, err } - sortKVs(dictExpr.List) return dictExpr, nil default: return nil, errors.Wrapf(ErrUnsupportedStaticParsing, "structpb val type %T", k) @@ -514,7 +530,7 @@ func (w *walker) mutateMetadataFn(f *featurev1beta1.StaticFeature) metadataFn { if metadataProto == nil { return nil } - metadataStarDict, err := w.genJSONValue(metadataProto, nil) + metadataStarDict, err := w.genJSONStruct(metadataProto, nil) if err != nil { return err }