From 72bcb66be597b35a1a3186acb6debb9e9c4fc051 Mon Sep 17 00:00:00 2001 From: Fahad Heylaal Date: Sun, 17 Aug 2025 21:39:36 +0200 Subject: [PATCH 1/5] bring sdk to root directory --- Makefile | 2 +- ...ility_test.go => api_compatibility_test.go | 0 sdk/bucketer.go => bucketer.go | 2 +- sdk/bucketer_test.go => bucketer_test.go | 2 +- sdk/child.go => child.go | 2 +- cli/commands/assess_distribution.go | 18 ++-- cli/commands/benchmark.go | 30 +++---- cli/commands/test.go | 90 +++++++++---------- cli/commands/test_types.go | 82 ++++++++--------- ...compare_versions.go => compare_versions.go | 2 +- ...rsions_test.go => compare_versions_test.go | 2 +- sdk/conditions.go => conditions.go | 2 +- sdk/conditions_test.go => conditions_test.go | 2 +- sdk/datafile_reader.go => datafile_reader.go | 2 +- ..._reader_test.go => datafile_reader_test.go | 2 +- sdk/emitter.go => emitter.go | 2 +- sdk/emitter_test.go => emitter_test.go | 2 +- sdk/evaluate.go => evaluate.go | 2 +- sdk/evaluation.go => evaluation.go | 2 +- sdk/events.go => events.go | 2 +- go.work | 1 - sdk/helpers.go => helpers.go | 2 +- sdk/hooks.go => hooks.go | 2 +- sdk/instance.go => instance.go | 2 +- ...go => instance_deprecated_features_test.go | 2 +- ...stance_individually_named_segments_test.go | 2 +- ....go => instance_mutually_exclusive_test.go | 2 +- ...st.go => instance_overridden_flags_test.go | 2 +- ...t.go => instance_required_features_test.go | 2 +- ...est.go => instance_sticky_features_test.go | 2 +- sdk/instance_test.go => instance_test.go | 2 +- ...> instance_variables_no_variations_test.go | 2 +- ...bles_test.go => instance_variables_test.go | 2 +- ...ons_test.go => instance_variations_test.go | 2 +- sdk/logger.go => logger.go | 2 +- sdk/logger_test.go => logger_test.go | 2 +- sdk/murmurhash.go => murmurhash.go | 2 +- sdk/murmurhash_test.go => murmurhash_test.go | 2 +- sdk/go.mod | 3 - sdk/sdk_types.go => sdk_types.go | 2 +- sdk/sdk_types_test.go => sdk_types_test.go | 2 +- 41 files changed, 144 insertions(+), 148 deletions(-) rename sdk/api_compatibility_test.go => api_compatibility_test.go (100%) rename sdk/bucketer.go => bucketer.go (99%) rename sdk/bucketer_test.go => bucketer_test.go (99%) rename sdk/child.go => child.go (99%) rename sdk/compare_versions.go => compare_versions.go (99%) rename sdk/compare_versions_test.go => compare_versions_test.go (99%) rename sdk/conditions.go => conditions.go (99%) rename sdk/conditions_test.go => conditions_test.go (99%) rename sdk/datafile_reader.go => datafile_reader.go (99%) rename sdk/datafile_reader_test.go => datafile_reader_test.go (99%) rename sdk/emitter.go => emitter.go (99%) rename sdk/emitter_test.go => emitter_test.go (99%) rename sdk/evaluate.go => evaluate.go (99%) rename sdk/evaluation.go => evaluation.go (99%) rename sdk/events.go => events.go (99%) rename sdk/helpers.go => helpers.go (98%) rename sdk/hooks.go => hooks.go (99%) rename sdk/instance.go => instance.go (99%) rename sdk/instance_deprecated_features_test.go => instance_deprecated_features_test.go (99%) rename sdk/instance_individually_named_segments_test.go => instance_individually_named_segments_test.go (99%) rename sdk/instance_mutually_exclusive_test.go => instance_mutually_exclusive_test.go (98%) rename sdk/instance_overridden_flags_test.go => instance_overridden_flags_test.go (98%) rename sdk/instance_required_features_test.go => instance_required_features_test.go (99%) rename sdk/instance_sticky_features_test.go => instance_sticky_features_test.go (99%) rename sdk/instance_test.go => instance_test.go (99%) rename sdk/instance_variables_no_variations_test.go => instance_variables_no_variations_test.go (98%) rename sdk/instance_variables_test.go => instance_variables_test.go (99%) rename sdk/instance_variations_test.go => instance_variations_test.go (99%) rename sdk/logger.go => logger.go (99%) rename sdk/logger_test.go => logger_test.go (99%) rename sdk/murmurhash.go => murmurhash.go (99%) rename sdk/murmurhash_test.go => murmurhash_test.go (98%) delete mode 100644 sdk/go.mod rename sdk/sdk_types.go => sdk_types.go (99%) rename sdk/sdk_types_test.go => sdk_types_test.go (99%) diff --git a/Makefile b/Makefile index b5a5c89..90a777a 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ build: go build -o build/featurevisor-go cli/main.go test: - go test ./sdk -v + go test ./... -v clean: rm -rf build diff --git a/sdk/api_compatibility_test.go b/api_compatibility_test.go similarity index 100% rename from sdk/api_compatibility_test.go rename to api_compatibility_test.go diff --git a/sdk/bucketer.go b/bucketer.go similarity index 99% rename from sdk/bucketer.go rename to bucketer.go index e8068ef..c2b1283 100644 --- a/sdk/bucketer.go +++ b/bucketer.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "fmt" diff --git a/sdk/bucketer_test.go b/bucketer_test.go similarity index 99% rename from sdk/bucketer_test.go rename to bucketer_test.go index adbe75f..e66d4cd 100644 --- a/sdk/bucketer_test.go +++ b/bucketer_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "testing" diff --git a/sdk/child.go b/child.go similarity index 99% rename from sdk/child.go rename to child.go index cb34326..afcc82a 100644 --- a/sdk/child.go +++ b/child.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor // ChildInstanceOptions contains options for creating a child instance type ChildInstanceOptions struct { diff --git a/cli/commands/assess_distribution.go b/cli/commands/assess_distribution.go index 26616f8..d2799dc 100644 --- a/cli/commands/assess_distribution.go +++ b/cli/commands/assess_distribution.go @@ -8,7 +8,7 @@ import ( "sort" "strings" - "github.com/featurevisor/featurevisor-go/sdk" + "github.com/featurevisor/featurevisor-go" ) // UUID_LENGTHS matches the TypeScript implementation @@ -96,28 +96,28 @@ func runAssessDistribution(opts CLIOptions) { return } - var context sdk.Context + var context featurevisor.Context if opts.Context != "" { json.Unmarshal([]byte(opts.Context), &context) } else { - context = make(sdk.Context) + context = make(featurevisor.Context) } populateUuid := opts.PopulateUuid levelStr := getLoggerLevel(opts) - level := sdk.LogLevel(levelStr) + level := featurevisor.LogLevel(levelStr) datafilesByEnvironment := buildDatafiles(featurevisorProjectPath, []string{opts.Environment}, "", 0) // Create SDK instance datafile := datafilesByEnvironment[opts.Environment] // Convert datafile to proper format - var datafileContent sdk.DatafileContent + var datafileContent featurevisor.DatafileContent if datafileBytes, err := json.Marshal(datafile); err == nil { json.Unmarshal(datafileBytes, &datafileContent) } - instance := sdk.CreateInstance(sdk.InstanceOptions{ + instance := featurevisor.CreateInstance(featurevisor.InstanceOptions{ Datafile: datafileContent, LogLevel: &level, }) @@ -148,7 +148,7 @@ func runAssessDistribution(opts CLIOptions) { // Run evaluations for i := 0; i < opts.N; i++ { // Create a copy of context for this iteration - contextCopy := make(sdk.Context) + contextCopy := make(featurevisor.Context) for k, v := range context { contextCopy[k] = v } @@ -162,7 +162,7 @@ func runAssessDistribution(opts CLIOptions) { } // Evaluate flag - flagEvaluation := instance.IsEnabled(opts.Feature, contextCopy, sdk.OverrideOptions{}) + flagEvaluation := instance.IsEnabled(opts.Feature, contextCopy, featurevisor.OverrideOptions{}) if flagEvaluation { flagEvaluations["enabled"]++ } else { @@ -171,7 +171,7 @@ func runAssessDistribution(opts CLIOptions) { // Evaluate variation if feature has variations if hasVariations { - variationEvaluation := instance.GetVariation(opts.Feature, contextCopy, sdk.OverrideOptions{}) + variationEvaluation := instance.GetVariation(opts.Feature, contextCopy, featurevisor.OverrideOptions{}) if variationEvaluation != nil { // Dereference the pointer to get the actual string value variationValue := *variationEvaluation diff --git a/cli/commands/benchmark.go b/cli/commands/benchmark.go index 0f21e3b..20a7c45 100644 --- a/cli/commands/benchmark.go +++ b/cli/commands/benchmark.go @@ -6,7 +6,7 @@ import ( "strings" "time" - "github.com/featurevisor/featurevisor-go/sdk" + featurevisor "github.com/featurevisor/featurevisor-go" ) // BenchmarkOutput represents the result of a benchmark operation @@ -17,16 +17,16 @@ type BenchmarkOutput struct { // benchmarkFeatureFlag benchmarks the feature flag evaluation func benchmarkFeatureFlag( - instance *sdk.Featurevisor, + instance *featurevisor.Featurevisor, featureKey string, - context sdk.Context, + context featurevisor.Context, n int, ) BenchmarkOutput { start := time.Now() var value interface{} for i := 0; i < n; i++ { - value = instance.IsEnabled(featureKey, context, sdk.OverrideOptions{}) + value = instance.IsEnabled(featureKey, context, featurevisor.OverrideOptions{}) } duration := time.Since(start) @@ -39,16 +39,16 @@ func benchmarkFeatureFlag( // benchmarkFeatureVariation benchmarks the feature variation evaluation func benchmarkFeatureVariation( - instance *sdk.Featurevisor, + instance *featurevisor.Featurevisor, featureKey string, - context sdk.Context, + context featurevisor.Context, n int, ) BenchmarkOutput { start := time.Now() var value interface{} for i := 0; i < n; i++ { - value = instance.GetVariation(featureKey, context, sdk.OverrideOptions{}) + value = instance.GetVariation(featureKey, context, featurevisor.OverrideOptions{}) } duration := time.Since(start) @@ -61,17 +61,17 @@ func benchmarkFeatureVariation( // benchmarkFeatureVariable benchmarks the feature variable evaluation func benchmarkFeatureVariable( - instance *sdk.Featurevisor, + instance *featurevisor.Featurevisor, featureKey string, variableKey string, - context sdk.Context, + context featurevisor.Context, n int, ) BenchmarkOutput { start := time.Now() var value interface{} for i := 0; i < n; i++ { - value = instance.GetVariable(featureKey, variableKey, context, sdk.OverrideOptions{}) + value = instance.GetVariable(featureKey, variableKey, context, featurevisor.OverrideOptions{}) } duration := time.Since(start) @@ -139,15 +139,15 @@ func runBenchmark(opts CLIOptions) { return } - var context sdk.Context + var context featurevisor.Context if opts.Context != "" { json.Unmarshal([]byte(opts.Context), &context) } else { - context = make(sdk.Context) + context = make(featurevisor.Context) } levelStr := getLoggerLevel(opts) - level := sdk.LogLevel(levelStr) + level := featurevisor.LogLevel(levelStr) fmt.Println("") fmt.Printf("Running benchmark for feature \"%s\"...\n", opts.Feature) @@ -165,7 +165,7 @@ func runBenchmark(opts CLIOptions) { datafile := datafilesByEnvironment[opts.Environment] // Convert datafile to proper format - var datafileContent sdk.DatafileContent + var datafileContent featurevisor.DatafileContent var datafileBytes []byte var err error if datafileBytes, err = json.Marshal(datafile); err == nil { @@ -176,7 +176,7 @@ func runBenchmark(opts CLIOptions) { datafileSize := len(datafileBytes) fmt.Printf("Datafile size: %.2f kB\n", float64(datafileSize)/1024.0) - instance := sdk.CreateInstance(sdk.InstanceOptions{ + instance := featurevisor.CreateInstance(featurevisor.InstanceOptions{ Datafile: datafileContent, LogLevel: &level, }) diff --git a/cli/commands/test.go b/cli/commands/test.go index 26e05a6..0923a24 100644 --- a/cli/commands/test.go +++ b/cli/commands/test.go @@ -8,24 +8,24 @@ import ( "strings" "time" - "github.com/featurevisor/featurevisor-go/sdk" + "github.com/featurevisor/featurevisor-go" ) // TestFeature tests a feature with the given assertion -func RunTestFeature(assertion map[string]interface{}, featureKey string, instance *sdk.Featurevisor, level string) AssertionResult { - context := sdk.Context{} +func RunTestFeature(assertion map[string]interface{}, featureKey string, instance *featurevisor.Featurevisor, level string) AssertionResult { + context := featurevisor.Context{} if ctx, ok := assertion["context"].(map[string]interface{}); ok { - context = sdk.Context(ctx) + context = featurevisor.Context(ctx) } // Set context and sticky for this assertion instance.SetContext(context, false) if sticky, ok := assertion["sticky"].(map[string]interface{}); ok { // Convert sticky to proper format - stickyFeatures := sdk.StickyFeatures{} + stickyFeatures := featurevisor.StickyFeatures{} for key, value := range sticky { if featureSticky, ok := value.(map[string]interface{}); ok { - evaluatedFeature := sdk.EvaluatedFeature{} + evaluatedFeature := featurevisor.EvaluatedFeature{} if enabled, ok := featureSticky["enabled"].(bool); ok { evaluatedFeature.Enabled = enabled } @@ -35,19 +35,19 @@ func RunTestFeature(assertion map[string]interface{}, featureKey string, instanc } } if variables, ok := featureSticky["variables"].(map[string]interface{}); ok { - evaluatedFeature.Variables = make(map[sdk.VariableKey]sdk.VariableValue) + evaluatedFeature.Variables = make(map[featurevisor.VariableKey]featurevisor.VariableValue) for varKey, varValue := range variables { - evaluatedFeature.Variables[sdk.VariableKey(varKey)] = varValue + evaluatedFeature.Variables[featurevisor.VariableKey(varKey)] = varValue } } - stickyFeatures[sdk.FeatureKey(key)] = evaluatedFeature + stickyFeatures[featurevisor.FeatureKey(key)] = evaluatedFeature } } instance.SetSticky(stickyFeatures, false) } // Create override options - overrideOptions := sdk.OverrideOptions{ + overrideOptions := featurevisor.OverrideOptions{ DefaultVariationValue: getDefaultVariationValue(assertion), } @@ -165,7 +165,7 @@ func RunTestFeature(assertion map[string]interface{}, featureKey string, instanc if variableEvals, ok := expectedEvaluations["variables"].(map[string]interface{}); ok { for variableKey, expectedEval := range variableEvals { if expectedEvalMap, ok := expectedEval.(map[string]interface{}); ok { - evaluation := instance.EvaluateVariable(featureKey, sdk.VariableKey(variableKey), context, overrideOptions) + evaluation := instance.EvaluateVariable(featureKey, featurevisor.VariableKey(variableKey), context, overrideOptions) for key, expectedValue := range expectedEvalMap { actualValue := getEvaluationValue(evaluation, key) if !compareValues(actualValue, expectedValue) { @@ -182,13 +182,13 @@ func RunTestFeature(assertion map[string]interface{}, featureKey string, instanc if children, ok := assertion["children"].([]interface{}); ok { for _, child := range children { if childMap, ok := child.(map[string]interface{}); ok { - childContext := sdk.Context{} + childContext := featurevisor.Context{} if childCtx, ok := childMap["context"].(map[string]interface{}); ok { - childContext = sdk.Context(childCtx) + childContext = featurevisor.Context(childCtx) } // Create override options for child with sticky values - childOverrideOptions := sdk.OverrideOptions{ + childOverrideOptions := featurevisor.OverrideOptions{ DefaultVariationValue: getDefaultVariationValue(childMap), } @@ -198,10 +198,10 @@ func RunTestFeature(assertion map[string]interface{}, featureKey string, instanc // Set sticky values for child if they exist if sticky, ok := assertion["sticky"].(map[string]interface{}); ok { // Convert sticky to proper format - stickyFeatures := sdk.StickyFeatures{} + stickyFeatures := featurevisor.StickyFeatures{} for key, value := range sticky { if featureSticky, ok := value.(map[string]interface{}); ok { - evaluatedFeature := sdk.EvaluatedFeature{} + evaluatedFeature := featurevisor.EvaluatedFeature{} if enabled, ok := featureSticky["enabled"].(bool); ok { evaluatedFeature.Enabled = enabled } @@ -211,12 +211,12 @@ func RunTestFeature(assertion map[string]interface{}, featureKey string, instanc } } if variables, ok := featureSticky["variables"].(map[string]interface{}); ok { - evaluatedFeature.Variables = make(map[sdk.VariableKey]sdk.VariableValue) + evaluatedFeature.Variables = make(map[featurevisor.VariableKey]featurevisor.VariableValue) for varKey, varValue := range variables { - evaluatedFeature.Variables[sdk.VariableKey(varKey)] = varValue + evaluatedFeature.Variables[featurevisor.VariableKey(varKey)] = varValue } } - stickyFeatures[sdk.FeatureKey(key)] = evaluatedFeature + stickyFeatures[featurevisor.FeatureKey(key)] = evaluatedFeature } } childInstance.SetSticky(stickyFeatures, false) @@ -242,14 +242,14 @@ func RunTestFeature(assertion map[string]interface{}, featureKey string, instanc } // TestFeatureChild tests a feature with child assertions -func RunTestFeatureChild(assertion map[string]interface{}, featureKey string, instance *sdk.FeaturevisorChild, level string) AssertionResult { - context := sdk.Context{} +func RunTestFeatureChild(assertion map[string]interface{}, featureKey string, instance *featurevisor.FeaturevisorChild, level string) AssertionResult { + context := featurevisor.Context{} if ctx, ok := assertion["context"].(map[string]interface{}); ok { - context = sdk.Context(ctx) + context = featurevisor.Context(ctx) } // Create override options - overrideOptions := sdk.OverrideOptions{ + overrideOptions := featurevisor.OverrideOptions{ DefaultVariationValue: getDefaultVariationValue(assertion), } @@ -348,23 +348,23 @@ func RunTestFeatureChild(assertion map[string]interface{}, featureKey string, in // TestSegment tests a segment with the given assertion func RunTestSegment(assertion map[string]interface{}, segment map[string]interface{}, level string) AssertionResult { - context := sdk.Context{} + context := featurevisor.Context{} if ctx, ok := assertion["context"].(map[string]interface{}); ok { - context = sdk.Context(ctx) + context = featurevisor.Context(ctx) } conditions := segment["conditions"] - datafile := sdk.DatafileContent{ + datafile := featurevisor.DatafileContent{ SchemaVersion: "2", Revision: "tester", - Features: make(map[sdk.FeatureKey]sdk.Feature), - Segments: make(map[sdk.SegmentKey]sdk.Segment), + Features: make(map[featurevisor.FeatureKey]featurevisor.Feature), + Segments: make(map[featurevisor.SegmentKey]featurevisor.Segment), } - levelStr := sdk.LogLevel(level) - logger := sdk.NewLogger(sdk.CreateLoggerOptions{Level: &levelStr}) - datafileReader := sdk.NewDatafileReader(sdk.DatafileReaderOptions{ + levelStr := featurevisor.LogLevel(level) + logger := featurevisor.NewLogger(featurevisor.CreateLoggerOptions{Level: &levelStr}) + datafileReader := featurevisor.NewDatafileReader(featurevisor.DatafileReaderOptions{ Datafile: datafile, Logger: logger, }) @@ -400,7 +400,7 @@ func getDefaultVariationValue(assertion map[string]interface{}) *string { } // getEvaluationValue extracts a value from an evaluation based on the key -func getEvaluationValue(evaluation sdk.Evaluation, key string) interface{} { +func getEvaluationValue(evaluation featurevisor.Evaluation, key string) interface{} { switch key { case "type": return string(evaluation.Type) @@ -464,10 +464,10 @@ func getEvaluationValue(evaluation sdk.Evaluation, key string) interface{} { } } -func getDefaultVariableValue(assertion map[string]interface{}, variableKey string) sdk.VariableValue { +func getDefaultVariableValue(assertion map[string]interface{}, variableKey string) featurevisor.VariableValue { if defaultValues, ok := assertion["defaultVariableValues"].(map[string]interface{}); ok { if defaultVal, ok := defaultValues[variableKey]; ok { - if val, ok := defaultVal.(sdk.VariableValue); ok { + if val, ok := defaultVal.(featurevisor.VariableValue); ok { return val } } @@ -686,26 +686,26 @@ func runTest(opts CLIOptions) { } // Create SDK instances for each environment - sdkInstancesByEnvironment := make(map[string]*sdk.Featurevisor) + sdkInstancesByEnvironment := make(map[string]*featurevisor.Featurevisor) for _, environment := range environments { if envStr, ok := environment.(string); ok { datafile := datafilesByEnvironment[envStr] // Convert datafile to proper format - var datafileContent sdk.DatafileContent + var datafileContent featurevisor.DatafileContent if datafileBytes, err := json.Marshal(datafile); err == nil { json.Unmarshal(datafileBytes, &datafileContent) } - levelStr := sdk.LogLevel(level) - instance := sdk.CreateInstance(sdk.InstanceOptions{ + levelStr := featurevisor.LogLevel(level) + instance := featurevisor.CreateInstance(featurevisor.InstanceOptions{ Datafile: datafileContent, LogLevel: &levelStr, - Hooks: []*sdk.Hook{ + Hooks: []*featurevisor.Hook{ { Name: "tester-hook", - BucketValue: func(options sdk.ConfigureBucketValueOptions) int { + BucketValue: func(options featurevisor.ConfigureBucketValueOptions) int { // This will be overridden per assertion if needed return options.BucketValue }, @@ -749,19 +749,19 @@ func runTest(opts CLIOptions) { // If "at" parameter is provided, create a new instance with the specific hook if _, hasAt := assertionMap["at"]; hasAt { datafile := datafilesByEnvironment[environment] - var datafileContent sdk.DatafileContent + var datafileContent featurevisor.DatafileContent if datafileBytes, err := json.Marshal(datafile); err == nil { json.Unmarshal(datafileBytes, &datafileContent) } - levelStr := sdk.LogLevel(level) - instance = sdk.CreateInstance(sdk.InstanceOptions{ + levelStr := featurevisor.LogLevel(level) + instance = featurevisor.CreateInstance(featurevisor.InstanceOptions{ Datafile: datafileContent, LogLevel: &levelStr, - Hooks: []*sdk.Hook{ + Hooks: []*featurevisor.Hook{ { Name: "tester-hook", - BucketValue: func(options sdk.ConfigureBucketValueOptions) int { + BucketValue: func(options featurevisor.ConfigureBucketValueOptions) int { if at, ok := assertionMap["at"].(float64); ok { // Match JavaScript implementation exactly: assertion.at * (MAX_BUCKETED_NUMBER / 100) // MAX_BUCKETED_NUMBER is 100000, so this gives us 0-100000 range diff --git a/cli/commands/test_types.go b/cli/commands/test_types.go index 7ef9c1a..f3e7b17 100644 --- a/cli/commands/test_types.go +++ b/cli/commands/test_types.go @@ -1,66 +1,66 @@ package commands -import "github.com/featurevisor/featurevisor-go/sdk" +import "github.com/featurevisor/featurevisor-go" // AssertionMatrix represents a matrix of assertions -type AssertionMatrix map[string][]sdk.AttributeValue +type AssertionMatrix map[string][]featurevisor.AttributeValue // ExpectedEvaluations represents expected evaluations type ExpectedEvaluations struct { - Flag map[string]interface{} `json:"flag,omitempty"` - Variation map[string]interface{} `json:"variation,omitempty"` - Variables map[sdk.VariableKey]map[string]interface{} `json:"variables,omitempty"` + Flag map[string]interface{} `json:"flag,omitempty"` + Variation map[string]interface{} `json:"variation,omitempty"` + Variables map[featurevisor.VariableKey]map[string]interface{} `json:"variables,omitempty"` } // FeatureChildAssertion represents a child assertion for a feature type FeatureChildAssertion struct { - Sticky *sdk.StickyFeatures `json:"sticky,omitempty"` - Context *sdk.Context `json:"context,omitempty"` - DefaultVariationValue *string `json:"defaultVariationValue,omitempty"` - DefaultVariableValues map[string]sdk.VariableValue `json:"defaultVariableValues,omitempty"` - ExpectedToBeEnabled *bool `json:"expectedToBeEnabled,omitempty"` - ExpectedVariation *string `json:"expectedVariation,omitempty"` - ExpectedVariables map[sdk.VariableKey]sdk.VariableValue `json:"expectedVariables,omitempty"` - ExpectedEvaluations *ExpectedEvaluations `json:"expectedEvaluations,omitempty"` + Sticky *featurevisor.StickyFeatures `json:"sticky,omitempty"` + Context *featurevisor.Context `json:"context,omitempty"` + DefaultVariationValue *string `json:"defaultVariationValue,omitempty"` + DefaultVariableValues map[string]featurevisor.VariableValue `json:"defaultVariableValues,omitempty"` + ExpectedToBeEnabled *bool `json:"expectedToBeEnabled,omitempty"` + ExpectedVariation *string `json:"expectedVariation,omitempty"` + ExpectedVariables map[featurevisor.VariableKey]featurevisor.VariableValue `json:"expectedVariables,omitempty"` + ExpectedEvaluations *ExpectedEvaluations `json:"expectedEvaluations,omitempty"` } // FeatureAssertion represents an assertion for a feature type FeatureAssertion struct { - Matrix *AssertionMatrix `json:"matrix,omitempty"` - Description *string `json:"description,omitempty"` - Environment sdk.EnvironmentKey `json:"environment"` - At *sdk.Weight `json:"at,omitempty"` - Sticky *sdk.StickyFeatures `json:"sticky,omitempty"` - Context *sdk.Context `json:"context,omitempty"` - DefaultVariationValue *string `json:"defaultVariationValue,omitempty"` - DefaultVariableValues map[string]sdk.VariableValue `json:"defaultVariableValues,omitempty"` - ExpectedToBeEnabled *bool `json:"expectedToBeEnabled,omitempty"` - ExpectedVariation *string `json:"expectedVariation,omitempty"` - ExpectedVariables map[sdk.VariableKey]sdk.VariableValue `json:"expectedVariables,omitempty"` - ExpectedEvaluations *ExpectedEvaluations `json:"expectedEvaluations,omitempty"` - Children []FeatureChildAssertion `json:"children,omitempty"` + Matrix *AssertionMatrix `json:"matrix,omitempty"` + Description *string `json:"description,omitempty"` + Environment featurevisor.EnvironmentKey `json:"environment"` + At *featurevisor.Weight `json:"at,omitempty"` + Sticky *featurevisor.StickyFeatures `json:"sticky,omitempty"` + Context *featurevisor.Context `json:"context,omitempty"` + DefaultVariationValue *string `json:"defaultVariationValue,omitempty"` + DefaultVariableValues map[string]featurevisor.VariableValue `json:"defaultVariableValues,omitempty"` + ExpectedToBeEnabled *bool `json:"expectedToBeEnabled,omitempty"` + ExpectedVariation *string `json:"expectedVariation,omitempty"` + ExpectedVariables map[featurevisor.VariableKey]featurevisor.VariableValue `json:"expectedVariables,omitempty"` + ExpectedEvaluations *ExpectedEvaluations `json:"expectedEvaluations,omitempty"` + Children []FeatureChildAssertion `json:"children,omitempty"` } // TestFeature represents a test feature type TestFeature struct { - Key *string `json:"key,omitempty"` - Feature sdk.FeatureKey `json:"feature"` - Assertions []FeatureAssertion `json:"assertions"` + Key *string `json:"key,omitempty"` + Feature featurevisor.FeatureKey `json:"feature"` + Assertions []FeatureAssertion `json:"assertions"` } // SegmentAssertion represents an assertion for a segment type SegmentAssertion struct { - Matrix *AssertionMatrix `json:"matrix,omitempty"` - Description *string `json:"description,omitempty"` - Context sdk.Context `json:"context"` - ExpectedToMatch bool `json:"expectedToMatch"` + Matrix *AssertionMatrix `json:"matrix,omitempty"` + Description *string `json:"description,omitempty"` + Context featurevisor.Context `json:"context"` + ExpectedToMatch bool `json:"expectedToMatch"` } // TestSegment represents a test segment type TestSegment struct { - Key *string `json:"key,omitempty"` - Segment sdk.SegmentKey `json:"segment"` - Assertions []SegmentAssertion `json:"assertions"` + Key *string `json:"key,omitempty"` + Segment featurevisor.SegmentKey `json:"segment"` + Assertions []SegmentAssertion `json:"assertions"` } // Test represents a test @@ -68,11 +68,11 @@ type Test interface{} // TestResultAssertionError represents an error in a test assertion type TestResultAssertionError struct { - Type string `json:"type"` - Expected sdk.AttributeValue `json:"expected"` - Actual sdk.AttributeValue `json:"actual"` - Message *string `json:"message,omitempty"` - Details map[string]sdk.AttributeValue `json:"details,omitempty"` + Type string `json:"type"` + Expected featurevisor.AttributeValue `json:"expected"` + Actual featurevisor.AttributeValue `json:"actual"` + Message *string `json:"message,omitempty"` + Details map[string]featurevisor.AttributeValue `json:"details,omitempty"` } // TestResultAssertion represents a test assertion result diff --git a/sdk/compare_versions.go b/compare_versions.go similarity index 99% rename from sdk/compare_versions.go rename to compare_versions.go index 3d14f78..59e68da 100644 --- a/sdk/compare_versions.go +++ b/compare_versions.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "fmt" diff --git a/sdk/compare_versions_test.go b/compare_versions_test.go similarity index 99% rename from sdk/compare_versions_test.go rename to compare_versions_test.go index 1bdcb85..5201151 100644 --- a/sdk/compare_versions_test.go +++ b/compare_versions_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "testing" diff --git a/sdk/conditions.go b/conditions.go similarity index 99% rename from sdk/conditions.go rename to conditions.go index ec2bfda..1944075 100644 --- a/sdk/conditions.go +++ b/conditions.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "regexp" diff --git a/sdk/conditions_test.go b/conditions_test.go similarity index 99% rename from sdk/conditions_test.go rename to conditions_test.go index be170b8..87553e9 100644 --- a/sdk/conditions_test.go +++ b/conditions_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "regexp" diff --git a/sdk/datafile_reader.go b/datafile_reader.go similarity index 99% rename from sdk/datafile_reader.go rename to datafile_reader.go index 5529f44..adac297 100644 --- a/sdk/datafile_reader.go +++ b/datafile_reader.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "encoding/json" diff --git a/sdk/datafile_reader_test.go b/datafile_reader_test.go similarity index 99% rename from sdk/datafile_reader_test.go rename to datafile_reader_test.go index 04630f3..27dcf35 100644 --- a/sdk/datafile_reader_test.go +++ b/datafile_reader_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "testing" diff --git a/sdk/emitter.go b/emitter.go similarity index 99% rename from sdk/emitter.go rename to emitter.go index 057da81..6604521 100644 --- a/sdk/emitter.go +++ b/emitter.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "log" diff --git a/sdk/emitter_test.go b/emitter_test.go similarity index 99% rename from sdk/emitter_test.go rename to emitter_test.go index 3f95f6c..572045e 100644 --- a/sdk/emitter_test.go +++ b/emitter_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "sync" diff --git a/sdk/evaluate.go b/evaluate.go similarity index 99% rename from sdk/evaluate.go rename to evaluate.go index 16bde43..2fb744a 100644 --- a/sdk/evaluate.go +++ b/evaluate.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "fmt" diff --git a/sdk/evaluation.go b/evaluation.go similarity index 99% rename from sdk/evaluation.go rename to evaluation.go index 9edebc5..68be060 100644 --- a/sdk/evaluation.go +++ b/evaluation.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor // EvaluationReason represents the reason for an evaluation result type EvaluationReason string diff --git a/sdk/events.go b/events.go similarity index 99% rename from sdk/events.go rename to events.go index 19c0e0e..9f238fe 100644 --- a/sdk/events.go +++ b/events.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor // getParamsForDatafileSetEvent gets parameters for datafile set event func getParamsForDatafileSetEvent(previousDatafileReader *DatafileReader, newDatafileReader *DatafileReader) LogDetails { diff --git a/go.work b/go.work index fa3e799..84120d6 100644 --- a/go.work +++ b/go.work @@ -3,5 +3,4 @@ go 1.22.0 use ( . ./cli - ./sdk ) diff --git a/sdk/helpers.go b/helpers.go similarity index 98% rename from sdk/helpers.go rename to helpers.go index bdefe5d..2e9c50b 100644 --- a/sdk/helpers.go +++ b/helpers.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "strconv" diff --git a/sdk/hooks.go b/hooks.go similarity index 99% rename from sdk/hooks.go rename to hooks.go index 3059937..a7d1243 100644 --- a/sdk/hooks.go +++ b/hooks.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor // ConfigureBucketKeyOptions contains options for configuring bucket key type ConfigureBucketKeyOptions struct { diff --git a/sdk/instance.go b/instance.go similarity index 99% rename from sdk/instance.go rename to instance.go index 6204d77..60c6c26 100644 --- a/sdk/instance.go +++ b/instance.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "encoding/json" diff --git a/sdk/instance_deprecated_features_test.go b/instance_deprecated_features_test.go similarity index 99% rename from sdk/instance_deprecated_features_test.go rename to instance_deprecated_features_test.go index f63643c..09aadc4 100644 --- a/sdk/instance_deprecated_features_test.go +++ b/instance_deprecated_features_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "strings" diff --git a/sdk/instance_individually_named_segments_test.go b/instance_individually_named_segments_test.go similarity index 99% rename from sdk/instance_individually_named_segments_test.go rename to instance_individually_named_segments_test.go index da6ca5d..f14e3ad 100644 --- a/sdk/instance_individually_named_segments_test.go +++ b/instance_individually_named_segments_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "testing" diff --git a/sdk/instance_mutually_exclusive_test.go b/instance_mutually_exclusive_test.go similarity index 98% rename from sdk/instance_mutually_exclusive_test.go rename to instance_mutually_exclusive_test.go index d6f4962..c88b782 100644 --- a/sdk/instance_mutually_exclusive_test.go +++ b/instance_mutually_exclusive_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "testing" diff --git a/sdk/instance_overridden_flags_test.go b/instance_overridden_flags_test.go similarity index 98% rename from sdk/instance_overridden_flags_test.go rename to instance_overridden_flags_test.go index b294b05..4c733d2 100644 --- a/sdk/instance_overridden_flags_test.go +++ b/instance_overridden_flags_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "testing" diff --git a/sdk/instance_required_features_test.go b/instance_required_features_test.go similarity index 99% rename from sdk/instance_required_features_test.go rename to instance_required_features_test.go index 125bbb0..e8a9cbe 100644 --- a/sdk/instance_required_features_test.go +++ b/instance_required_features_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "testing" diff --git a/sdk/instance_sticky_features_test.go b/instance_sticky_features_test.go similarity index 99% rename from sdk/instance_sticky_features_test.go rename to instance_sticky_features_test.go index 68ae3a0..4217fd7 100644 --- a/sdk/instance_sticky_features_test.go +++ b/instance_sticky_features_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "testing" diff --git a/sdk/instance_test.go b/instance_test.go similarity index 99% rename from sdk/instance_test.go rename to instance_test.go index c67d525..00b0471 100644 --- a/sdk/instance_test.go +++ b/instance_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "reflect" diff --git a/sdk/instance_variables_no_variations_test.go b/instance_variables_no_variations_test.go similarity index 98% rename from sdk/instance_variables_no_variations_test.go rename to instance_variables_no_variations_test.go index cd26650..4a5eded 100644 --- a/sdk/instance_variables_no_variations_test.go +++ b/instance_variables_no_variations_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "testing" diff --git a/sdk/instance_variables_test.go b/instance_variables_test.go similarity index 99% rename from sdk/instance_variables_test.go rename to instance_variables_test.go index 7669477..e8a0b28 100644 --- a/sdk/instance_variables_test.go +++ b/instance_variables_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "testing" diff --git a/sdk/instance_variations_test.go b/instance_variations_test.go similarity index 99% rename from sdk/instance_variations_test.go rename to instance_variations_test.go index 5a62ea9..6832033 100644 --- a/sdk/instance_variations_test.go +++ b/instance_variations_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "testing" diff --git a/sdk/logger.go b/logger.go similarity index 99% rename from sdk/logger.go rename to logger.go index d0efe71..ee44468 100644 --- a/sdk/logger.go +++ b/logger.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "fmt" diff --git a/sdk/logger_test.go b/logger_test.go similarity index 99% rename from sdk/logger_test.go rename to logger_test.go index 76ca515..f48dfd2 100644 --- a/sdk/logger_test.go +++ b/logger_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "bytes" diff --git a/sdk/murmurhash.go b/murmurhash.go similarity index 99% rename from sdk/murmurhash.go rename to murmurhash.go index 6c1934d..9cd4032 100644 --- a/sdk/murmurhash.go +++ b/murmurhash.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import "fmt" diff --git a/sdk/murmurhash_test.go b/murmurhash_test.go similarity index 98% rename from sdk/murmurhash_test.go rename to murmurhash_test.go index aa36378..0f3c697 100644 --- a/sdk/murmurhash_test.go +++ b/murmurhash_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "testing" diff --git a/sdk/go.mod b/sdk/go.mod deleted file mode 100644 index 81406d0..0000000 --- a/sdk/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/featurevisor/featurevisor-go/sdk - -go 1.21.3 diff --git a/sdk/sdk_types.go b/sdk_types.go similarity index 99% rename from sdk/sdk_types.go rename to sdk_types.go index b90d38e..96907e9 100644 --- a/sdk/sdk_types.go +++ b/sdk_types.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "encoding/json" diff --git a/sdk/sdk_types_test.go b/sdk_types_test.go similarity index 99% rename from sdk/sdk_types_test.go rename to sdk_types_test.go index 2fe0236..01caf4f 100644 --- a/sdk/sdk_types_test.go +++ b/sdk_types_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "testing" From f682cd507bfc70980b747665de8d37369785f5b9 Mon Sep 17 00:00:00 2001 From: Fahad Heylaal Date: Sun, 17 Aug 2025 21:44:44 +0200 Subject: [PATCH 2/5] package declaration fix in test --- api_compatibility_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api_compatibility_test.go b/api_compatibility_test.go index 3380008..cd1aef7 100644 --- a/api_compatibility_test.go +++ b/api_compatibility_test.go @@ -1,4 +1,4 @@ -package sdk +package featurevisor import ( "testing" From 12d009fc46e2899ca65d4a1f3aa5a7dd05aeb2c7 Mon Sep 17 00:00:00 2001 From: Fahad Heylaal Date: Sun, 17 Aug 2025 21:47:59 +0200 Subject: [PATCH 3/5] readme updates --- README.md | 104 +++++++++++++++++++++++++++--------------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index cf495c9..795b9fe 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ See example application [here](https://github.com/featurevisor/featurevisor-exam In your Go application, install the SDK using Go modules: ```bash -go get github.com/featurevisor/featurevisor-go/sdk +go get github.com/featurevisor/featurevisor-go ``` ## Initialization @@ -70,7 +70,7 @@ import ( "io" "net/http" - "github.com/featurevisor/featurevisor-go/sdk" + "github.com/featurevisor/featurevisor-go" ) func main() { @@ -87,12 +87,12 @@ func main() { panic(err) } - var datafileContent sdk.DatafileContent + var datafileContent featurevisor.DatafileContent if err := datafileContent.FromJSON(string(datafileBytes)); err != nil { panic(err) } - f := sdk.CreateInstance(sdk.InstanceOptions{ + f := featurevisor.CreateInstance(featurevisor.InstanceOptions{ Datafile: datafileContent, }) } @@ -117,7 +117,7 @@ Think of the conditions that you define in your [segments](https://featurevisor. They are plain maps: ```go -context := sdk.Context{ +context := featurevisor.Context{ "userId": "123", "country": "nl", // ...other attributes @@ -132,11 +132,11 @@ You can set context at the time of initialization: ```go import ( - "github.com/featurevisor/featurevisor-go/sdk" + "github.com/featurevisor/featurevisor-go" ) -f := sdk.CreateInstance(sdk.InstanceOptions{ - Context: sdk.Context{ +f := featurevisor.CreateInstance(featurevisor.InstanceOptions{ + Context: featurevisor.Context{ "deviceId": "123", "country": "nl", }, @@ -150,7 +150,7 @@ This is useful for values that don't change too frequently and available at the You can also set more context after the SDK has been initialized: ```go -f.SetContext(sdk.Context{ +f.SetContext(featurevisor.Context{ "userId": "234", }) ``` @@ -162,7 +162,7 @@ This will merge the new context with the existing one (if already set). If you wish to fully replace the existing context, you can pass `true` in second argument: ```go -f.SetContext(sdk.Context{ +f.SetContext(featurevisor.Context{ "deviceId": "123", "userId": "234", "country": "nl", @@ -175,7 +175,7 @@ f.SetContext(sdk.Context{ You can optionally pass additional context manually for each and every evaluation separately, without needing to set it to the SDK instance affecting all evaluations: ```go -context := sdk.Context{ +context := featurevisor.Context{ "userId": "123", "country": "nl", } @@ -206,7 +206,7 @@ if isEnabled { You can also pass additional context per evaluation: ```go -isEnabled := f.IsEnabled(featureKey, sdk.Context{ +isEnabled := f.IsEnabled(featureKey, featurevisor.Context{ // ...additional context }) ``` @@ -230,7 +230,7 @@ if variation != nil && *variation == "treatment" { Additional context per evaluation can also be passed: ```go -variation := f.GetVariation(featureKey, sdk.Context{ +variation := f.GetVariation(featureKey, featurevisor.Context{ // ...additional context }) ``` @@ -248,7 +248,7 @@ bgColorValue := f.GetVariable("my_feature", variableKey) Additional context per evaluation can also be passed: ```go -bgColorValue := f.GetVariable("my_feature", variableKey, sdk.Context{ +bgColorValue := f.GetVariable("my_feature", variableKey, featurevisor.Context{ // ...additional context }) ``` @@ -272,7 +272,7 @@ f.GetVariableJSON(featureKey, variableKey, context) You can get evaluations of all features available in the SDK instance: ```go -allEvaluations := f.GetAllEvaluations(sdk.Context{}) +allEvaluations := f.GetAllEvaluations(featurevisor.Context{}) fmt.Printf("%+v\n", allEvaluations) // { @@ -301,20 +301,20 @@ For the lifecycle of the SDK instance in your application, you can set some feat ```go import ( - "github.com/featurevisor/featurevisor-go/sdk" + "github.com/featurevisor/featurevisor-go" ) -f := sdk.CreateInstance(sdk.InstanceOptions{ +f := featurevisor.CreateInstance(featurevisor.InstanceOptions{ Sticky: &StickyFeatures{ - "myFeatureKey": sdk.StickyFeature{ + "myFeatureKey": featurevisor.StickyFeature{ Enabled: true, // optional - Variation: &sdk.VariationValue{Value: "treatment"}, + Variation: &featurevisor.VariationValue{Value: "treatment"}, Variables: map[string]interface{}{ "myVariableKey": "myVariableValue", }, }, - "anotherFeatureKey": sdk.StickyFeature{ + "anotherFeatureKey": featurevisor.StickyFeature{ Enabled: false, }, }, @@ -328,15 +328,15 @@ Once initialized with sticky features, the SDK will look for values there first You can also set sticky features after the SDK is initialized: ```go -f.SetSticky(sdk.StickyFeatures{ - "myFeatureKey": sdk.StickyFeature{ +f.SetSticky(featurevisor.StickyFeatures{ + "myFeatureKey": featurevisor.StickyFeature{ Enabled: true, - Variation: &sdk.VariationValue{Value: "treatment"}, + Variation: &featurevisor.VariationValue{Value: "treatment"}, Variables: map[string]interface{}{ "myVariableKey": "myVariableValue", }, }, - "anotherFeatureKey": sdk.StickyFeature{ + "anotherFeatureKey": featurevisor.StickyFeature{ Enabled: false, }, }, true) // replace existing sticky features (false by default) @@ -371,10 +371,10 @@ import ( "io" "net/http" - "github.com/featurevisor/featurevisor-go/sdk" + "github.com/featurevisor/featurevisor-go" ) -func updateDatafile(f *sdk.Featurevisor, datafileURL string) { +func updateDatafile(f *featurevisor.Featurevisor, datafileURL string) { ticker := time.NewTicker(5 * time.Minute) defer ticker.Stop() @@ -390,7 +390,7 @@ func updateDatafile(f *sdk.Featurevisor, datafileURL string) { continue } - var datafileContent sdk.DatafileContent + var datafileContent featurevisor.DatafileContent if err := datafileContent.FromJSON(string(datafileBytes)); err != nil { continue } @@ -424,11 +424,11 @@ Setting `debug` level will print out all logs, including `info`, `warn`, and `er ```go import ( - "github.com/featurevisor/featurevisor-go/sdk" + "github.com/featurevisor/featurevisor-go" ) -logLevel := sdk.LogLevelDebug -f := sdk.CreateInstance(sdk.InstanceOptions{ +logLevel := featurevisor.LogLevelDebug +f := featurevisor.CreateInstance(featurevisor.InstanceOptions{ LogLevel: &logLevel, }) ``` @@ -436,8 +436,8 @@ f := sdk.CreateInstance(sdk.InstanceOptions{ Alternatively, you can also set `logLevel` directly: ```go -logLevel := sdk.LogLevelDebug -f := sdk.CreateInstance(sdk.InstanceOptions{ +logLevel := featurevisor.LogLevelDebug +f := featurevisor.CreateInstance(featurevisor.InstanceOptions{ LogLevel: &logLevel, }) ``` @@ -445,7 +445,7 @@ f := sdk.CreateInstance(sdk.InstanceOptions{ You can also set log level from SDK instance afterwards: ```go -f.SetLogLevel(sdk.LogLevelDebug) +f.SetLogLevel(featurevisor.LogLevelDebug) ``` ### Handler @@ -454,17 +454,17 @@ You can also pass your own log handler, if you do not wish to print the logs to ```go import ( - "github.com/featurevisor/featurevisor-go/sdk" + "github.com/featurevisor/featurevisor-go" ) -logger := sdk.NewLogger(sdk.CreateLoggerOptions{ - Level: &sdk.LogLevelInfo, - Handler: func(level sdk.LogLevel, message string, details interface{}) { +logger := featurevisor.NewLogger(featurevisor.CreateLoggerOptions{ + Level: &featurevisor.LogLevelInfo, + Handler: func(level featurevisor.LogLevel, message string, details interface{}) { // do something with the log }, }) -f := sdk.CreateInstance(sdk.InstanceOptions{ +f := featurevisor.CreateInstance(featurevisor.InstanceOptions{ Logger: logger, }) ``` @@ -480,7 +480,7 @@ You can listen to these events that can occur at various stages in your applicat ### `datafile_set` ```go -unsubscribe := f.On(sdk.EventNameDatafileSet, func(event sdk.Event) { +unsubscribe := f.On(featurevisor.EventNameDatafileSet, func(event featurevisor.Event) { revision := event.Revision // new revision previousRevision := event.PreviousRevision revisionChanged := event.RevisionChanged // true if revision has changed @@ -507,7 +507,7 @@ compared to the previous datafile content that existed in the SDK instance. ### `context_set` ```go -unsubscribe := f.On(sdk.EventNameContextSet, func(event sdk.Event) { +unsubscribe := f.On(featurevisor.EventNameContextSet, func(event featurevisor.Event) { replaced := event.Replaced // true if context was replaced context := event.Context // the new context @@ -518,7 +518,7 @@ unsubscribe := f.On(sdk.EventNameContextSet, func(event sdk.Event) { ### `sticky_set` ```go -unsubscribe := f.On(sdk.EventNameStickySet, func(event sdk.Event) { +unsubscribe := f.On(featurevisor.EventNameStickySet, func(event featurevisor.Event) { replaced := event.Replaced // true if sticky features got replaced features := event.Features // list of all affected feature keys @@ -568,27 +568,27 @@ A hook is a simple struct with a unique required `Name` and optional functions: ```go import ( - "github.com/featurevisor/featurevisor-go/sdk" + "github.com/featurevisor/featurevisor-go" ) -myCustomHook := &sdk.Hook{ +myCustomHook := &featurevisor.Hook{ // only required property Name: "my-custom-hook", // rest of the properties below are all optional per hook // before evaluation - Before: func(options sdk.EvaluateOptions) sdk.EvaluateOptions { + Before: func(options featurevisor.EvaluateOptions) featurevisor.EvaluateOptions { // update context before evaluation if options.Context == nil { - options.Context = sdk.Context{} + options.Context = featurevisor.Context{} } options.Context["someAdditionalAttribute"] = "value" return options }, // after evaluation - After: func(evaluation sdk.Evaluation, options sdk.EvaluateOptions) { + After: func(evaluation featurevisor.Evaluation, options featurevisor.EvaluateOptions) { if evaluation.Reason == "error" { // log error return @@ -596,13 +596,13 @@ myCustomHook := &sdk.Hook{ }, // configure bucket key - BucketKey: func(options sdk.EvaluateOptions) string { + BucketKey: func(options featurevisor.EvaluateOptions) string { // return custom bucket key return options.BucketKey }, // configure bucket value (between 0 and 100,000) - BucketValue: func(options sdk.EvaluateOptions) int { + BucketValue: func(options featurevisor.EvaluateOptions) int { // return custom bucket value return options.BucketValue }, @@ -615,11 +615,11 @@ You can register hooks at the time of SDK initialization: ```go import ( - "github.com/featurevisor/featurevisor-go/sdk" + "github.com/featurevisor/featurevisor-go" ) -f := sdk.CreateInstance(sdk.InstanceOptions{ - Hooks: []*sdk.Hook{ +f := featurevisor.CreateInstance(featurevisor.InstanceOptions{ + Hooks: []*featurevisor.Hook{ myCustomHook, }, }) @@ -640,7 +640,7 @@ But when using Featurevisor SDK in server-side applications, where a single serv That's where child instances come in handy: ```go -childF := f.Spawn(sdk.Context{ +childF := f.Spawn(featurevisor.Context{ // user or request specific context "userId": "123", }) From 33cabd1ab6b6a55cf25b8e81aad292df04547ad2 Mon Sep 17 00:00:00 2001 From: Fahad Heylaal Date: Sun, 17 Aug 2025 22:03:16 +0200 Subject: [PATCH 4/5] rename cli/ to cmd/ --- README.md | 14 +++++++------- cli/go.mod | 3 --- {cli => cmd}/commands/assess_distribution.go | 0 {cli => cmd}/commands/benchmark.go | 0 {cli => cmd}/commands/commands.go | 0 {cli => cmd}/commands/test.go | 0 {cli => cmd}/commands/test_types.go | 0 cmd/go.mod | 3 +++ {cli => cmd}/main.go | 2 +- go.work | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) delete mode 100644 cli/go.mod rename {cli => cmd}/commands/assess_distribution.go (100%) rename {cli => cmd}/commands/benchmark.go (100%) rename {cli => cmd}/commands/commands.go (100%) rename {cli => cmd}/commands/test.go (100%) rename {cli => cmd}/commands/test_types.go (100%) create mode 100644 cmd/go.mod rename {cli => cmd}/main.go (89%) diff --git a/README.md b/README.md index 795b9fe..5706512 100644 --- a/README.md +++ b/README.md @@ -682,20 +682,20 @@ f.Close() ## CLI usage -This package also provides a CLI tool for running your Featurevisor project's test specs and benchmarking against this Go SDK: +This package also provides a CLI tool for running your Featurevisor [project](https://featurevisor.com/docs/projects/)'s test specs and benchmarking against this Go SDK: ### Test Learn more about testing [here](https://featurevisor.com/docs/testing/). ```bash -go run cli/main.go test --projectDirectoryPath="/absolute/path/to/your/featurevisor/project" +go run cmd/main.go test --projectDirectoryPath="/absolute/path/to/your/featurevisor/project" ``` Additional options that are available: ```bash -go run cli/main.go test \ +go run cmd/main.go test \ --projectDirectoryPath="/absolute/path/to/your/featurevisor/project" \ --quiet|verbose \ --onlyFailures \ @@ -705,10 +705,10 @@ go run cli/main.go test \ ### Benchmark -Learn more about benchmarking [here](https://featurevisor.com/docs/cli/#benchmarking). +Learn more about benchmarking [here](https://featurevisor.com/docs/cmd/#benchmarking). ```bash -go run cli/main.go benchmark \ +go run cmd/main.go benchmark \ --projectDirectoryPath="/absolute/path/to/your/featurevisor/project" \ --environment="production" \ --feature="myFeatureKey" \ @@ -718,10 +718,10 @@ go run cli/main.go benchmark \ ### Assess distribution -Learn more about assessing distribution [here](https://featurevisor.com/docs/cli/#assess-distribution). +Learn more about assessing distribution [here](https://featurevisor.com/docs/cmd/#assess-distribution). ```bash -go run cli/main.go assess-distribution \ +go run cmd/main.go assess-distribution \ --projectDirectoryPath="/absolute/path/to/your/featurevisor/project" \ --environment=production \ --feature=foo \ diff --git a/cli/go.mod b/cli/go.mod deleted file mode 100644 index 84a1243..0000000 --- a/cli/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/featurevisor/featurevisor-go/cli - -go 1.21 diff --git a/cli/commands/assess_distribution.go b/cmd/commands/assess_distribution.go similarity index 100% rename from cli/commands/assess_distribution.go rename to cmd/commands/assess_distribution.go diff --git a/cli/commands/benchmark.go b/cmd/commands/benchmark.go similarity index 100% rename from cli/commands/benchmark.go rename to cmd/commands/benchmark.go diff --git a/cli/commands/commands.go b/cmd/commands/commands.go similarity index 100% rename from cli/commands/commands.go rename to cmd/commands/commands.go diff --git a/cli/commands/test.go b/cmd/commands/test.go similarity index 100% rename from cli/commands/test.go rename to cmd/commands/test.go diff --git a/cli/commands/test_types.go b/cmd/commands/test_types.go similarity index 100% rename from cli/commands/test_types.go rename to cmd/commands/test_types.go diff --git a/cmd/go.mod b/cmd/go.mod new file mode 100644 index 0000000..1b1840b --- /dev/null +++ b/cmd/go.mod @@ -0,0 +1,3 @@ +module github.com/featurevisor/featurevisor-go/cmd + +go 1.21 diff --git a/cli/main.go b/cmd/main.go similarity index 89% rename from cli/main.go rename to cmd/main.go index 4487c39..d12649e 100644 --- a/cli/main.go +++ b/cmd/main.go @@ -4,7 +4,7 @@ import ( "fmt" "os" - "github.com/featurevisor/featurevisor-go/cli/commands" + "github.com/featurevisor/featurevisor-go/cmd/commands" ) func main() { diff --git a/go.work b/go.work index 84120d6..d9f2345 100644 --- a/go.work +++ b/go.work @@ -2,5 +2,5 @@ go 1.22.0 use ( . - ./cli + ./cmd ) From 1ad5dbde0e731f14b35b6bbea634c98235ff755f Mon Sep 17 00:00:00 2001 From: Fahad Heylaal Date: Sun, 17 Aug 2025 22:04:55 +0200 Subject: [PATCH 5/5] update workflow --- .github/workflows/checks.yml | 2 +- Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 6f402e7..ffd65d4 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -39,4 +39,4 @@ jobs: (cd example-1 && npx featurevisor test) - name: Run Featurevisor project tests against Go SDK - run: go run ./cli/main.go test --projectDirectoryPath=./example-1 + run: go run ./cmd/main.go test --projectDirectoryPath=./example-1 diff --git a/Makefile b/Makefile index 90a777a..04ce8e8 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ build: mkdir -p build - go build -o build/featurevisor-go cli/main.go + go build -o build/featurevisor-go cmd/main.go test: go test ./... -v