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
|
||||
}
|
||||
|
||||
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 {
|
||||
je.Logger.DebugWithID(reqID, fmt.Sprintf("requested flag is disabled: %s", flagKey))
|
||||
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)
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(transposedConfig), &newFlags)
|
||||
var configData ConfigWithMetadata
|
||||
err = json.Unmarshal([]byte(transposedConfig), &configData)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,11 @@ type Evaluators struct {
|
|||
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 {
|
||||
Flags map[string]model.Flag `json:"flags"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1184,6 +1184,222 @@ func TestState_Evaluator(t *testing.T) {
|
|||
expectedError: true,
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ type Flag struct {
|
|||
Targeting json.RawMessage `json:"targeting,omitempty"`
|
||||
Source string `json:"source"`
|
||||
Selector string `json:"selector"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type Evaluators struct {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ type Flags struct {
|
|||
mx sync.RWMutex
|
||||
Flags map[string]model.Flag `json:"flags"`
|
||||
FlagSources []string
|
||||
SourceMetadata map[string]SourceDetails
|
||||
SourceMetadata map[string]SourceDetails `json:"sourceMetadata,omitempty"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type SourceDetails struct {
|
||||
|
|
|
|||
Loading…
Reference in New Issue