feat: support flag metadata (#1476)
- Adds functionality to return flag metadata as part of the response. Signed-off-by: Aasif Khan <aasifk106@gmail.com>
This commit is contained in:
parent
26b0b1af8b
commit
13fbbad4d8
|
|
@ -327,6 +327,13 @@ func (je *Resolver) evaluateVariant(ctx context.Context, reqID string, flagKey s
|
||||||
metadata[SelectorMetadataKey] = selector
|
metadata[SelectorMetadataKey] = selector
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for key, value := range flag.Metadata {
|
||||||
|
// If value is not nil or empty, copy to metadata
|
||||||
|
if value != nil {
|
||||||
|
metadata[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if flag.State == Disabled {
|
if flag.State == Disabled {
|
||||||
je.Logger.DebugWithID(reqID, fmt.Sprintf("requested flag is disabled: %s", flagKey))
|
je.Logger.DebugWithID(reqID, fmt.Sprintf("requested flag is disabled: %s", flagKey))
|
||||||
return "", flag.Variants, model.ErrorReason, metadata, errors.New(model.FlagDisabledErrorCode)
|
return "", flag.Variants, model.ErrorReason, metadata, errors.New(model.FlagDisabledErrorCode)
|
||||||
|
|
@ -460,11 +467,28 @@ func configToFlags(log *logger.Logger, config string, newFlags *Flags) error {
|
||||||
return fmt.Errorf("transposing evaluators: %w", err)
|
return fmt.Errorf("transposing evaluators: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.Unmarshal([]byte(transposedConfig), &newFlags)
|
var configData ConfigWithMetadata
|
||||||
|
err = json.Unmarshal([]byte(transposedConfig), &configData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unmarshalling provided configurations: %w", err)
|
return fmt.Errorf("unmarshalling provided configurations: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Assign the flags from the unmarshalled config to the newFlags struct
|
||||||
|
newFlags.Flags = configData.Flags
|
||||||
|
|
||||||
|
// Assign metadata as a map to each flag's metadata
|
||||||
|
for key, flag := range newFlags.Flags {
|
||||||
|
if flag.Metadata == nil {
|
||||||
|
flag.Metadata = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
for metaKey, metaValue := range configData.Metadata {
|
||||||
|
if _, exists := flag.Metadata[metaKey]; !exists {
|
||||||
|
flag.Metadata[metaKey] = metaValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newFlags.Flags[key] = flag
|
||||||
|
}
|
||||||
|
|
||||||
return validateDefaultVariants(newFlags)
|
return validateDefaultVariants(newFlags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,11 @@ type Evaluators struct {
|
||||||
Evaluators map[string]json.RawMessage `json:"$evaluators"`
|
Evaluators map[string]json.RawMessage `json:"$evaluators"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ConfigWithMetadata struct {
|
||||||
|
Flags map[string]model.Flag `json:"flags"`
|
||||||
|
Metadata map[string]interface{} `json:"metadata"`
|
||||||
|
}
|
||||||
|
|
||||||
type Flags struct {
|
type Flags struct {
|
||||||
Flags map[string]model.Flag `json:"flags"`
|
Flags map[string]model.Flag `json:"flags"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1184,6 +1184,222 @@ func TestState_Evaluator(t *testing.T) {
|
||||||
expectedError: true,
|
expectedError: true,
|
||||||
expectedResync: false,
|
expectedResync: false,
|
||||||
},
|
},
|
||||||
|
"flag metadata": {
|
||||||
|
inputState: `
|
||||||
|
{
|
||||||
|
"flags": {
|
||||||
|
"fibAlgo": {
|
||||||
|
"variants": {
|
||||||
|
"recursive": "recursive",
|
||||||
|
"memo": "memo",
|
||||||
|
"loop": "loop",
|
||||||
|
"binet": "binet"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"defaultVariant": "recursive",
|
||||||
|
"state": "ENABLED",
|
||||||
|
"targeting": {
|
||||||
|
"if": [
|
||||||
|
{
|
||||||
|
"$ref": "emailWithFaas"
|
||||||
|
}, "binet", null
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$evaluators": {
|
||||||
|
"emailWithFaas": {
|
||||||
|
"in": ["@faas.com", {
|
||||||
|
"var": ["email"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
inputSyncType: sync.ALL,
|
||||||
|
expectedOutputState: `
|
||||||
|
{
|
||||||
|
"flags": {
|
||||||
|
"fibAlgo": {
|
||||||
|
"variants": {
|
||||||
|
"recursive": "recursive",
|
||||||
|
"memo": "memo",
|
||||||
|
"loop": "loop",
|
||||||
|
"binet": "binet"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": 1
|
||||||
|
},
|
||||||
|
"defaultVariant": "recursive",
|
||||||
|
"state": "ENABLED",
|
||||||
|
"source":"",
|
||||||
|
"selector":"",
|
||||||
|
"targeting": {
|
||||||
|
"if": [
|
||||||
|
{
|
||||||
|
"in": ["@faas.com", {
|
||||||
|
"var": ["email"]
|
||||||
|
}]
|
||||||
|
}, "binet", null
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flagSources":null
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"flagSet and flag metadata": {
|
||||||
|
inputState: `
|
||||||
|
{
|
||||||
|
"flags": {
|
||||||
|
"fibAlgo": {
|
||||||
|
"variants": {
|
||||||
|
"recursive": "recursive",
|
||||||
|
"memo": "memo",
|
||||||
|
"loop": "loop",
|
||||||
|
"binet": "binet"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": "sso/dev",
|
||||||
|
"version": "1.0.0"
|
||||||
|
},
|
||||||
|
"defaultVariant": "recursive",
|
||||||
|
"state": "ENABLED",
|
||||||
|
"targeting": {
|
||||||
|
"if": [
|
||||||
|
{
|
||||||
|
"$ref": "emailWithFaas"
|
||||||
|
}, "binet", null
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"flagSetId": "test",
|
||||||
|
"flagSetVersion": "1"
|
||||||
|
},
|
||||||
|
"$evaluators": {
|
||||||
|
"emailWithFaas": {
|
||||||
|
"in": ["@faas.com", {
|
||||||
|
"var": ["email"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
inputSyncType: sync.ALL,
|
||||||
|
expectedOutputState: `
|
||||||
|
{
|
||||||
|
"flags": {
|
||||||
|
"fibAlgo": {
|
||||||
|
"variants": {
|
||||||
|
"recursive": "recursive",
|
||||||
|
"memo": "memo",
|
||||||
|
"loop": "loop",
|
||||||
|
"binet": "binet"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": "sso/dev",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"flagSetId": "test",
|
||||||
|
"flagSetVersion": "1"
|
||||||
|
},
|
||||||
|
"defaultVariant": "recursive",
|
||||||
|
"state": "ENABLED",
|
||||||
|
"source":"",
|
||||||
|
"selector":"",
|
||||||
|
"targeting": {
|
||||||
|
"if": [
|
||||||
|
{
|
||||||
|
"in": ["@faas.com", {
|
||||||
|
"var": ["email"]
|
||||||
|
}]
|
||||||
|
}, "binet", null
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flagSources":null
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"flag metadata priority": {
|
||||||
|
inputState: `
|
||||||
|
{
|
||||||
|
"flags": {
|
||||||
|
"fibAlgo": {
|
||||||
|
"variants": {
|
||||||
|
"recursive": "recursive",
|
||||||
|
"memo": "memo",
|
||||||
|
"loop": "loop",
|
||||||
|
"binet": "binet"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": "sso/dev",
|
||||||
|
"version": "1.0.0"
|
||||||
|
},
|
||||||
|
"defaultVariant": "recursive",
|
||||||
|
"state": "ENABLED",
|
||||||
|
"targeting": {
|
||||||
|
"if": [
|
||||||
|
{
|
||||||
|
"$ref": "emailWithFaas"
|
||||||
|
}, "binet", null
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": "test",
|
||||||
|
"flagSetVersion": "1"
|
||||||
|
},
|
||||||
|
"$evaluators": {
|
||||||
|
"emailWithFaas": {
|
||||||
|
"in": ["@faas.com", {
|
||||||
|
"var": ["email"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
inputSyncType: sync.ALL,
|
||||||
|
expectedOutputState: `
|
||||||
|
{
|
||||||
|
"flags": {
|
||||||
|
"fibAlgo": {
|
||||||
|
"variants": {
|
||||||
|
"recursive": "recursive",
|
||||||
|
"memo": "memo",
|
||||||
|
"loop": "loop",
|
||||||
|
"binet": "binet"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"id": "sso/dev",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"flagSetVersion": "1"
|
||||||
|
},
|
||||||
|
"defaultVariant": "recursive",
|
||||||
|
"state": "ENABLED",
|
||||||
|
"source":"",
|
||||||
|
"selector":"",
|
||||||
|
"targeting": {
|
||||||
|
"if": [
|
||||||
|
{
|
||||||
|
"in": ["@faas.com", {
|
||||||
|
"var": ["email"]
|
||||||
|
}]
|
||||||
|
}, "binet", null
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flagSources":null
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, tt := range tests {
|
for name, tt := range tests {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ type Flag struct {
|
||||||
Targeting json.RawMessage `json:"targeting,omitempty"`
|
Targeting json.RawMessage `json:"targeting,omitempty"`
|
||||||
Source string `json:"source"`
|
Source string `json:"source"`
|
||||||
Selector string `json:"selector"`
|
Selector string `json:"selector"`
|
||||||
|
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Evaluators struct {
|
type Evaluators struct {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,8 @@ type Flags struct {
|
||||||
mx sync.RWMutex
|
mx sync.RWMutex
|
||||||
Flags map[string]model.Flag `json:"flags"`
|
Flags map[string]model.Flag `json:"flags"`
|
||||||
FlagSources []string
|
FlagSources []string
|
||||||
SourceMetadata map[string]SourceDetails
|
SourceMetadata map[string]SourceDetails `json:"sourceMetadata,omitempty"`
|
||||||
|
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SourceDetails struct {
|
type SourceDetails struct {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue