From 25889a6ce51d899175a1d1de1f0cd805d504308f Mon Sep 17 00:00:00 2001 From: gunishmatta Date: Fri, 29 Mar 2024 20:16:23 +0530 Subject: [PATCH 01/24] added support for domains Signed-off-by: gunishmatta --- openfeature/api.go | 4 ++-- openfeature/client.go | 22 +++++++++++----------- openfeature/client_example_test.go | 4 ++-- openfeature/client_test.go | 8 ++++---- openfeature/event_executor.go | 4 ++-- openfeature/event_executor_test.go | 10 +++++----- openfeature/noop_provider_test.go | 2 +- openfeature/openfeature.go | 4 ++-- openfeature/openfeature_test.go | 14 +++++++------- openfeature/provider.go | 2 +- openfeature/provider_test.go | 4 ++-- pkg/openfeature/client.go | 2 +- 12 files changed, 40 insertions(+), 40 deletions(-) diff --git a/openfeature/api.go b/openfeature/api.go index 155c5e2b..99021cbe 100644 --- a/openfeature/api.go +++ b/openfeature/api.go @@ -70,7 +70,7 @@ func (api *evaluationAPI) getProvider() FeatureProvider { return api.defaultProvider } -// setProvider sets a provider with client name. Returns an error if FeatureProvider is nil +// setProvider sets a provider with client domain. Returns an error if FeatureProvider is nil func (api *evaluationAPI) setNamedProvider(clientName string, provider FeatureProvider, async bool) error { api.mu.Lock() defer api.mu.Unlock() @@ -159,7 +159,7 @@ func (api *evaluationAPI) getHooks() []Hook { } // forTransaction is a helper to retrieve transaction(flag evaluation) scoped operators. -// Returns the default FeatureProvider if no provider mapping exist for the given client name. +// Returns the default FeatureProvider if no provider mapping exist for the given client domain. func (api *evaluationAPI) forTransaction(clientName string) (FeatureProvider, []Hook, EvaluationContext) { api.mu.RLock() defer api.mu.RUnlock() diff --git a/openfeature/client.go b/openfeature/client.go index 3391531a..ce6ae000 100644 --- a/openfeature/client.go +++ b/openfeature/client.go @@ -32,20 +32,20 @@ type IClient interface { // ClientMetadata provides a client's metadata type ClientMetadata struct { - name string + domain string } // NewClientMetadata constructs ClientMetadata // Allows for simplified hook test cases while maintaining immutability -func NewClientMetadata(name string) ClientMetadata { +func NewClientMetadata(domain string) ClientMetadata { return ClientMetadata{ - name: name, + domain: domain, } } -// Name returns the client's name -func (cm ClientMetadata) Name() string { - return cm.name +// Domain returns the client's domain +func (cm ClientMetadata) Domain() string { + return cm.domain } // Client implements the behaviour required of an openfeature client @@ -57,10 +57,10 @@ type Client struct { logger func() logr.Logger } -// NewClient returns a new Client. Name is a unique identifier for this client +// NewClient returns a new Client. Domain is a unique identifier for this client func NewClient(name string) *Client { return &Client{ - metadata: ClientMetadata{name: name}, + metadata: ClientMetadata{domain: name}, hooks: []Hook{}, evaluationContext: EvaluationContext{}, logger: globalLogger, @@ -91,12 +91,12 @@ func (c *Client) AddHooks(hooks ...Hook) { // AddHandler allows to add Client level event handler func (c *Client) AddHandler(eventType EventType, callback EventCallback) { - addClientHandler(c.metadata.Name(), eventType, callback) + addClientHandler(c.metadata.Domain(), eventType, callback) } // RemoveHandler allows to remove Client level event handler func (c *Client) RemoveHandler(eventType EventType, callback EventCallback) { - removeClientHandler(c.metadata.Name(), eventType, callback) + removeClientHandler(c.metadata.Domain(), eventType, callback) } // SetEvaluationContext sets the client's evaluation context @@ -596,7 +596,7 @@ func (c *Client) evaluate( } // ensure that the same provider & hooks are used across this transaction to avoid unexpected behaviour - provider, globalHooks, globalCtx := forTransaction(c.metadata.name) + provider, globalHooks, globalCtx := forTransaction(c.metadata.domain) evalCtx = mergeContexts(evalCtx, c.evaluationContext, globalCtx) // API (global) -> client -> invocation apiClientInvocationProviderHooks := append(append(append(globalHooks, c.hooks...), options.hooks...), provider.Hooks()...) // API, Client, Invocation, Provider diff --git a/openfeature/client_example_test.go b/openfeature/client_example_test.go index 4c257f94..cd0bc2f3 100644 --- a/openfeature/client_example_test.go +++ b/openfeature/client_example_test.go @@ -11,8 +11,8 @@ import ( func ExampleNewClient() { client := openfeature.NewClient("example-client") - fmt.Printf("Client Name: %s", client.Metadata().Name()) - // Output: Client Name: example-client + fmt.Printf("Client Domain: %s", client.Metadata().Domain()) + // Output: Client Domain: example-client } func ExampleClient_BooleanValue() { diff --git a/openfeature/client_test.go b/openfeature/client_test.go index d02d8bdb..debcc1dd 100644 --- a/openfeature/client_test.go +++ b/openfeature/client_test.go @@ -28,15 +28,15 @@ func TestRequirement_1_2_1(t *testing.T) { } // The client interface MUST define a `metadata` member or accessor, -// containing an immutable `name` field or accessor of type string, -// which corresponds to the `name` value supplied during client creation. +// containing an immutable `domain` field or accessor of type string, +// which corresponds to the `domain` value supplied during client creation. func TestRequirement_1_2_2(t *testing.T) { defer t.Cleanup(initSingleton) clientName := "test-client" client := NewClient(clientName) - if client.Metadata().Name() != clientName { - t.Errorf("client name not initiated as expected, got %s, want %s", client.Metadata().Name(), clientName) + if client.Metadata().Domain() != clientName { + t.Errorf("client domain not initiated as expected, got %s, want %s", client.Metadata().Domain(), clientName) } } diff --git a/openfeature/event_executor.go b/openfeature/event_executor.go index b3df6cb3..a5fc12ef 100644 --- a/openfeature/event_executor.go +++ b/openfeature/event_executor.go @@ -42,8 +42,8 @@ func newEventExecutor(logger logr.Logger) *eventExecutor { return &executor } -// scopedCallback is a helper struct to hold client name associated callbacks. -// Here, the scope correlates to the client and provider name +// scopedCallback is a helper struct to hold client domain associated callbacks. +// Here, the scope correlates to the client and provider domain type scopedCallback struct { scope string callbacks map[EventType][]EventCallback diff --git a/openfeature/event_executor_test.go b/openfeature/event_executor_test.go index d4783e99..fec36577 100644 --- a/openfeature/event_executor_test.go +++ b/openfeature/event_executor_test.go @@ -43,12 +43,12 @@ func TestEventHandler_RegisterUnregisterEventProvider(t *testing.T) { t.Error("implementation should register default eventing provider") } - err = executor.registerNamedEventingProvider("name", eventingProvider) + err = executor.registerNamedEventingProvider("domain", eventingProvider) if err != nil { t.Fatal(err) } - if _, ok := executor.namedProviderReference["name"]; !ok { + if _, ok := executor.namedProviderReference["domain"]; !ok { t.Errorf("implementation should register named eventing provider") } }) @@ -137,7 +137,7 @@ func TestEventHandler_Eventing(t *testing.T) { eventingImpl, } - // associated to client name + // associated to client domain associatedName := "providerForClient" err := SetNamedProviderAndWait(associatedName, eventingProvider) @@ -220,7 +220,7 @@ func TestEventHandler_clientAssociation(t *testing.T) { t.Fatal(err) } - // named provider(associated to name someClient) + // named provider(associated to domain someClient) err = SetNamedProviderAndWait("someClient", struct { FeatureProvider EventHandler @@ -672,7 +672,7 @@ func TestEventHandler_ProviderReadiness(t *testing.T) { } }) - t.Run("for name associated handler", func(t *testing.T) { + t.Run("for domain associated handler", func(t *testing.T) { defer t.Cleanup(initSingleton) readyEventingProvider := struct { diff --git a/openfeature/noop_provider_test.go b/openfeature/noop_provider_test.go index 82986e21..ea0ace69 100644 --- a/openfeature/noop_provider_test.go +++ b/openfeature/noop_provider_test.go @@ -18,7 +18,7 @@ func TestNoopProvider_Metadata(t *testing.T) { t.Run(name, func(t *testing.T) { e := openfeature.NoopProvider{} if got := e.Metadata(); got != tt.want { - t.Errorf("Name() = %v, want %v", got, tt.want) + t.Errorf("Domain() = %v, want %v", got, tt.want) } }) } diff --git a/openfeature/openfeature.go b/openfeature/openfeature.go index 40cf61a9..5df85ee3 100644 --- a/openfeature/openfeature.go +++ b/openfeature/openfeature.go @@ -29,13 +29,13 @@ func SetProviderAndWait(provider FeatureProvider) error { return api.setProvider(provider, false) } -// SetNamedProvider sets a provider mapped to the given Client name. Provider initialization is asynchronous and +// SetNamedProvider sets a provider mapped to the given Client domain. Provider initialization is asynchronous and // status can be checked from provider status func SetNamedProvider(clientName string, provider FeatureProvider) error { return api.setNamedProvider(clientName, provider, true) } -// SetNamedProviderAndWait sets a provider mapped to the given Client name and waits for its initialization. +// SetNamedProviderAndWait sets a provider mapped to the given Client domain and waits for its initialization. // Returns an error if initialization cause error func SetNamedProviderAndWait(clientName string, provider FeatureProvider) error { return api.setNamedProvider(clientName, provider, false) diff --git a/openfeature/openfeature_test.go b/openfeature/openfeature_test.go index 7fa8d0c2..a41cbc29 100644 --- a/openfeature/openfeature_test.go +++ b/openfeature/openfeature_test.go @@ -214,7 +214,7 @@ func TestRequirement_1_1_2_3(t *testing.T) { } }) - t.Run("ignore shutdown for multiple references - name client bound", func(t *testing.T) { + t.Run("ignore shutdown for multiple references - domain client bound", func(t *testing.T) { defer t.Cleanup(initSingleton) // setup @@ -393,8 +393,8 @@ func TestRequirement_1_1_2_4(t *testing.T) { }) } -// The `API` MUST provide a function to bind a given `provider` to one or more client `name`s. -// If the client-name already has a bound provider, it is overwritten with the new mapping. +// The `API` MUST provide a function to bind a given `provider` to one or more client `domain`s. +// If the client-domain already has a bound provider, it is overwritten with the new mapping. func TestRequirement_1_1_3(t *testing.T) { defer t.Cleanup(initSingleton) @@ -445,7 +445,7 @@ func TestRequirement_1_1_3(t *testing.T) { t.Errorf("expected %s, but got %s", "providerB", providerA.Metadata().Name) } - // Validate overriding: If the client-name already has a bound provider, it is overwritten with the new mapping. + // Validate overriding: If the client-domain already has a bound provider, it is overwritten with the new mapping. providerB2 := NewMockFeatureProvider(ctrl) providerB2.EXPECT().Metadata().Return(Metadata{Name: "providerB2"}).AnyTimes() @@ -495,7 +495,7 @@ func TestRequirement_1_1_5(t *testing.T) { } // The `API` MUST provide a function for creating a `client` which accepts the following options: -// - name (optional): A logical string identifier for the client. +// - domain (optional): A logical string identifier for the client. func TestRequirement_1_1_6(t *testing.T) { defer t.Cleanup(initSingleton) NewClient("test-client") @@ -563,7 +563,7 @@ func TestRequirement_EventCompliance(t *testing.T) { registry := getClientRegistry(clientName) if registry == nil { - t.Fatalf("no event handler registry present for client name %s", clientName) + t.Fatalf("no event handler registry present for client domain %s", clientName) } if len(registry.callbacks[ProviderReady]) < 1 { @@ -661,7 +661,7 @@ func TestRequirement_EventCompliance(t *testing.T) { // Non-spec bound validations -// If there is no client name bound provider, then return the default provider +// If there is no client domain bound provider, then return the default provider func TestDefaultClientUsage(t *testing.T) { defer t.Cleanup(initSingleton) diff --git a/openfeature/provider.go b/openfeature/provider.go index 634b23b3..389ffcac 100644 --- a/openfeature/provider.go +++ b/openfeature/provider.go @@ -186,7 +186,7 @@ type InterfaceResolutionDetail struct { ProviderResolutionDetail } -// Metadata provides provider name +// Metadata provides provider domain type Metadata struct { Name string } diff --git a/openfeature/provider_test.go b/openfeature/provider_test.go index 2dbddd3b..bc57996d 100644 --- a/openfeature/provider_test.go +++ b/openfeature/provider_test.go @@ -8,7 +8,7 @@ import ( "github.com/golang/mock/gomock" ) -// The provider interface MUST define a `metadata` member or accessor, containing a `name` field or accessor +// The provider interface MUST define a `metadata` member or accessor, containing a `domain` field or accessor // of type string, which identifies the provider implementation. func TestRequirement_2_1_1(t *testing.T) { ctrl := gomock.NewController(t) @@ -26,7 +26,7 @@ func TestRequirement_2_1_1(t *testing.T) { metadata := Metadata{} metaValue := reflect.ValueOf(&metadata).Elem() - fieldName := "Name" + fieldName := "Domain" field := metaValue.FieldByName(fieldName) if field == (reflect.Value{}) { diff --git a/pkg/openfeature/client.go b/pkg/openfeature/client.go index 9abe3c9e..80ddb4fe 100644 --- a/pkg/openfeature/client.go +++ b/pkg/openfeature/client.go @@ -29,7 +29,7 @@ func NewClientMetadata(name string) ClientMetadata { // Deprecated: use github.com/open-feature/go-sdk/openfeature.Client, instead. type Client = openfeature.Client -// NewClient returns a new Client. Name is a unique identifier for this client +// NewClient returns a new Client. Domain is a unique identifier for this client // // Deprecated: use github.com/open-feature/go-sdk/openfeature.NewClient, // instead. From ebd1e4a5d649bf5ba7a0ff3fe56129f2e67ae896 Mon Sep 17 00:00:00 2001 From: gunishmatta Date: Sat, 30 Mar 2024 17:10:55 +0530 Subject: [PATCH 02/24] added support for domains Signed-off-by: gunishmatta --- openfeature/api.go | 2 +- openfeature/event_executor.go | 4 +-- openfeature/event_executor_test.go | 8 +++--- openfeature/memprovider/in_memory_provider.go | 2 +- .../memprovider/in_memory_provider_test.go | 4 +-- openfeature/noop_provider.go | 2 +- openfeature/noop_provider_test.go | 2 +- openfeature/openfeature_test.go | 26 +++++++++---------- openfeature/provider.go | 2 +- 9 files changed, 26 insertions(+), 26 deletions(-) diff --git a/openfeature/api.go b/openfeature/api.go index 99021cbe..81003fc5 100644 --- a/openfeature/api.go +++ b/openfeature/api.go @@ -213,7 +213,7 @@ func (api *evaluationAPI) initNewAndShutdownOld(newProvider FeatureProvider, old // It also returns an error if the initialization resulted in an error func initializer(provider FeatureProvider, apiCtx EvaluationContext) (Event, error) { var event = Event{ - ProviderName: provider.Metadata().Name, + ProviderName: provider.Metadata().Domain, EventType: ProviderReady, ProviderEventDetails: ProviderEventDetails{ Message: "Provider initialization successful", diff --git a/openfeature/event_executor.go b/openfeature/event_executor.go index a5fc12ef..ff15ce43 100644 --- a/openfeature/event_executor.go +++ b/openfeature/event_executor.go @@ -189,7 +189,7 @@ func (e *eventExecutor) emitOnRegistration( if message != "" { (*callback)(EventDetails{ - ProviderName: providerReference.featureProvider.Metadata().Name, + ProviderName: providerReference.featureProvider.Metadata().Domain, ProviderEventDetails: ProviderEventDetails{ Message: message, }, @@ -290,7 +290,7 @@ func (e *eventExecutor) startListeningAndShutdownOld(newProvider providerReferen return nil case <-time.After(200 * time.Millisecond): return fmt.Errorf("old event handler %s timeout waiting for handler shutdown", - oldReference.featureProvider.Metadata().Name) + oldReference.featureProvider.Metadata().Domain) } } diff --git a/openfeature/event_executor_test.go b/openfeature/event_executor_test.go index fec36577..0100fd0a 100644 --- a/openfeature/event_executor_test.go +++ b/openfeature/event_executor_test.go @@ -160,7 +160,7 @@ func TestEventHandler_Eventing(t *testing.T) { // trigger event from provider implementation eventingImpl.Invoke(Event{ - ProviderName: eventingProvider.Metadata().Name, + ProviderName: eventingProvider.Metadata().Domain, EventType: ProviderReady, ProviderEventDetails: ProviderEventDetails{ Message: "ReadyMessage", @@ -178,8 +178,8 @@ func TestEventHandler_Eventing(t *testing.T) { t.Fatalf("timeout - event did not trigger") } - if result.ProviderName != eventingProvider.Metadata().Name { - t.Errorf("expected %s, but got %s", eventingProvider.Metadata().Name, result.ProviderName) + if result.ProviderName != eventingProvider.Metadata().Domain { + t.Errorf("expected %s, but got %s", eventingProvider.Metadata().Domain, result.ProviderName) } if result.Message != "ReadyMessage" { @@ -245,7 +245,7 @@ func TestEventHandler_clientAssociation(t *testing.T) { // invoke default provider eventingImpl.Invoke(Event{ - ProviderName: defaultProvider.Metadata().Name, + ProviderName: defaultProvider.Metadata().Domain, EventType: event, ProviderEventDetails: ProviderEventDetails{}, }) diff --git a/openfeature/memprovider/in_memory_provider.go b/openfeature/memprovider/in_memory_provider.go index 3f833f24..9cf5884d 100644 --- a/openfeature/memprovider/in_memory_provider.go +++ b/openfeature/memprovider/in_memory_provider.go @@ -24,7 +24,7 @@ func NewInMemoryProvider(from map[string]InMemoryFlag) InMemoryProvider { func (i InMemoryProvider) Metadata() openfeature.Metadata { return openfeature.Metadata{ - Name: "InMemoryProvider", + Domain: "InMemoryProvider", } } diff --git a/openfeature/memprovider/in_memory_provider_test.go b/openfeature/memprovider/in_memory_provider_test.go index f0aec0ba..e51bf1cc 100644 --- a/openfeature/memprovider/in_memory_provider_test.go +++ b/openfeature/memprovider/in_memory_provider_test.go @@ -252,11 +252,11 @@ func TestInMemoryProvider_Metadata(t *testing.T) { metadata := memoryProvider.Metadata() - if metadata.Name == "" { + if metadata.Domain == "" { t.Errorf("expected non-empty name for in-memory provider") } - if metadata.Name != "InMemoryProvider" { + if metadata.Domain != "InMemoryProvider" { t.Errorf("incorrect name for in-memory provider") } } diff --git a/openfeature/noop_provider.go b/openfeature/noop_provider.go index 12a72555..b3024056 100644 --- a/openfeature/noop_provider.go +++ b/openfeature/noop_provider.go @@ -8,7 +8,7 @@ type NoopProvider struct { // Metadata returns the metadata of the provider func (e NoopProvider) Metadata() Metadata { - return Metadata{Name: "NoopProvider"} + return Metadata{Domain: "NoopProvider"} } // BooleanEvaluation returns a boolean flag. diff --git a/openfeature/noop_provider_test.go b/openfeature/noop_provider_test.go index ea0ace69..7134b8e7 100644 --- a/openfeature/noop_provider_test.go +++ b/openfeature/noop_provider_test.go @@ -11,7 +11,7 @@ func TestNoopProvider_Metadata(t *testing.T) { want openfeature.Metadata }{ "Given a NOOP provider, then Metadata() will return NoopProvider": { - want: openfeature.Metadata{Name: "NoopProvider"}, + want: openfeature.Metadata{Domain: "NoopProvider"}, }, } for name, tt := range tests { diff --git a/openfeature/openfeature_test.go b/openfeature/openfeature_test.go index a41cbc29..69f249e5 100644 --- a/openfeature/openfeature_test.go +++ b/openfeature/openfeature_test.go @@ -40,7 +40,7 @@ func TestRequirement_1_1_2_1(t *testing.T) { mockProvider := NewMockFeatureProvider(ctrl) mockProviderName := "mock-provider" - mockProvider.EXPECT().Metadata().Return(Metadata{Name: mockProviderName}).AnyTimes() + mockProvider.EXPECT().Metadata().Return(Metadata{Domain: mockProviderName}).AnyTimes() err := SetProvider(mockProvider) if err != nil { @@ -402,10 +402,10 @@ func TestRequirement_1_1_3(t *testing.T) { ctrl := gomock.NewController(t) providerA := NewMockFeatureProvider(ctrl) - providerA.EXPECT().Metadata().Return(Metadata{Name: "providerA"}).AnyTimes() + providerA.EXPECT().Metadata().Return(Metadata{Domain: "providerA"}).AnyTimes() providerB := NewMockFeatureProvider(ctrl) - providerB.EXPECT().Metadata().Return(Metadata{Name: "providerB"}).AnyTimes() + providerB.EXPECT().Metadata().Return(Metadata{Domain: "providerB"}).AnyTimes() err := SetNamedProvider("clientA", providerA) if err != nil { @@ -436,19 +436,19 @@ func TestRequirement_1_1_3(t *testing.T) { // Validate provider retrieval by client evaluation. This uses forTransaction("clientName") provider, _, _ := forTransaction("clientA") - if provider.Metadata().Name != "providerA" { - t.Errorf("expected %s, but got %s", "providerA", providerA.Metadata().Name) + if provider.Metadata().Domain != "providerA" { + t.Errorf("expected %s, but got %s", "providerA", providerA.Metadata().Domain) } provider, _, _ = forTransaction("clientB") - if provider.Metadata().Name != "providerB" { - t.Errorf("expected %s, but got %s", "providerB", providerA.Metadata().Name) + if provider.Metadata().Domain != "providerB" { + t.Errorf("expected %s, but got %s", "providerB", providerA.Metadata().Domain) } // Validate overriding: If the client-domain already has a bound provider, it is overwritten with the new mapping. providerB2 := NewMockFeatureProvider(ctrl) - providerB2.EXPECT().Metadata().Return(Metadata{Name: "providerB2"}).AnyTimes() + providerB2.EXPECT().Metadata().Return(Metadata{Domain: "providerB2"}).AnyTimes() err = SetNamedProvider("clientB", providerB2) if err != nil { @@ -463,8 +463,8 @@ func TestRequirement_1_1_3(t *testing.T) { // Validate provider retrieval by client evaluation. This uses forTransaction("clientName") provider, _, _ = forTransaction("clientB") - if provider.Metadata().Name != "providerB2" { - t.Errorf("expected %s, but got %s", "providerB2", providerA.Metadata().Name) + if provider.Metadata().Domain != "providerB2" { + t.Errorf("expected %s, but got %s", "providerB2", providerA.Metadata().Domain) } } @@ -667,7 +667,7 @@ func TestDefaultClientUsage(t *testing.T) { ctrl := gomock.NewController(t) defaultProvider := NewMockFeatureProvider(ctrl) - defaultProvider.EXPECT().Metadata().Return(Metadata{Name: "defaultClientReplacement"}).AnyTimes() + defaultProvider.EXPECT().Metadata().Return(Metadata{Domain: "defaultClientReplacement"}).AnyTimes() err := SetProvider(defaultProvider) if err != nil { @@ -677,8 +677,8 @@ func TestDefaultClientUsage(t *testing.T) { // Validate provider retrieval by client evaluation provider, _, _ := forTransaction("ClientName") - if provider.Metadata().Name != "defaultClientReplacement" { - t.Errorf("expected %s, but got %s", "defaultClientReplacement", provider.Metadata().Name) + if provider.Metadata().Domain != "defaultClientReplacement" { + t.Errorf("expected %s, but got %s", "defaultClientReplacement", provider.Metadata().Domain) } } diff --git a/openfeature/provider.go b/openfeature/provider.go index 389ffcac..13313acb 100644 --- a/openfeature/provider.go +++ b/openfeature/provider.go @@ -188,5 +188,5 @@ type InterfaceResolutionDetail struct { // Metadata provides provider domain type Metadata struct { - Name string + Domain string } From b3a6b61bcd4168d87d7556dd50708970862015b5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:14:22 -0400 Subject: [PATCH 03/24] chore(deps): update actions/setup-go action to v5 (#237) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Signed-off-by: gunishmatta --- .github/workflows/pr-checks.yml | 4 ++-- .github/workflows/release-please.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 16d8bb43..6c941f9c 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Install Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ${{ env.DEFAULT_GO_VERSION }} - name: Checkout repository @@ -37,7 +37,7 @@ jobs: steps: - name: Install Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ${{ env.DEFAULT_GO_VERSION }} - name: Checkout repository diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 725f7d43..71cef896 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -35,7 +35,7 @@ jobs: ref: ${{ needs.release-please.outputs.release_tag_name }} - name: Set up Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ${{ env.DEFAULT_GO_VERSION }} From fa84bd9abc92def81423b7c4517c79596c802c10 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:17:49 -0400 Subject: [PATCH 04/24] chore(deps): update cyclonedx/gh-gomod-generate-sbom action to v2 (#179) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Signed-off-by: gunishmatta --- .github/workflows/release-please.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 71cef896..77530ae1 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -40,7 +40,7 @@ jobs: go-version: ${{ env.DEFAULT_GO_VERSION }} - name: Install cyclonedx-gomod - uses: CycloneDX/gh-gomod-generate-sbom@v1 + uses: CycloneDX/gh-gomod-generate-sbom@v2 with: version: v1.3.0 From f0440a306dc9c58808f277a4c0954f6eaa2eb557 Mon Sep 17 00:00:00 2001 From: Gunish Matta <33680363+gunishmatta@users.noreply.github.com> Date: Thu, 25 Apr 2024 22:29:10 +0530 Subject: [PATCH 05/24] Update openfeature/client.go Co-authored-by: Michael Beemer Signed-off-by: Gunish Matta <33680363+gunishmatta@users.noreply.github.com> Signed-off-by: gunishmatta --- openfeature/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfeature/client.go b/openfeature/client.go index ce6ae000..e561368d 100644 --- a/openfeature/client.go +++ b/openfeature/client.go @@ -58,7 +58,7 @@ type Client struct { } // NewClient returns a new Client. Domain is a unique identifier for this client -func NewClient(name string) *Client { +func NewClient(domain string) *Client { return &Client{ metadata: ClientMetadata{domain: name}, hooks: []Hook{}, From 44ac3ad457ca00639c5759e7abcaa6770eebf9c3 Mon Sep 17 00:00:00 2001 From: Gunish Matta <33680363+gunishmatta@users.noreply.github.com> Date: Thu, 25 Apr 2024 22:29:19 +0530 Subject: [PATCH 06/24] Update openfeature/client.go Co-authored-by: Michael Beemer Signed-off-by: Gunish Matta <33680363+gunishmatta@users.noreply.github.com> Signed-off-by: gunishmatta --- openfeature/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfeature/client.go b/openfeature/client.go index e561368d..30b6bcc5 100644 --- a/openfeature/client.go +++ b/openfeature/client.go @@ -60,7 +60,7 @@ type Client struct { // NewClient returns a new Client. Domain is a unique identifier for this client func NewClient(domain string) *Client { return &Client{ - metadata: ClientMetadata{domain: name}, + metadata: ClientMetadata{domain: domain}, hooks: []Hook{}, evaluationContext: EvaluationContext{}, logger: globalLogger, From 84d7dd49bb42414fdf8efb1cd13a107f31febd16 Mon Sep 17 00:00:00 2001 From: gunishmatta Date: Thu, 25 Apr 2024 22:46:57 +0530 Subject: [PATCH 07/24] code review changes Signed-off-by: gunishmatta --- openfeature/api.go | 2 +- openfeature/event_executor.go | 4 +-- openfeature/event_executor_test.go | 8 +++--- openfeature/memprovider/in_memory_provider.go | 2 +- .../memprovider/in_memory_provider_test.go | 4 +-- openfeature/noop_provider.go | 2 +- openfeature/noop_provider_test.go | 4 +-- openfeature/openfeature_test.go | 26 +++++++++---------- openfeature/provider.go | 2 +- openfeature/provider_test.go | 2 +- 10 files changed, 28 insertions(+), 28 deletions(-) diff --git a/openfeature/api.go b/openfeature/api.go index 81003fc5..99021cbe 100644 --- a/openfeature/api.go +++ b/openfeature/api.go @@ -213,7 +213,7 @@ func (api *evaluationAPI) initNewAndShutdownOld(newProvider FeatureProvider, old // It also returns an error if the initialization resulted in an error func initializer(provider FeatureProvider, apiCtx EvaluationContext) (Event, error) { var event = Event{ - ProviderName: provider.Metadata().Domain, + ProviderName: provider.Metadata().Name, EventType: ProviderReady, ProviderEventDetails: ProviderEventDetails{ Message: "Provider initialization successful", diff --git a/openfeature/event_executor.go b/openfeature/event_executor.go index ff15ce43..a5fc12ef 100644 --- a/openfeature/event_executor.go +++ b/openfeature/event_executor.go @@ -189,7 +189,7 @@ func (e *eventExecutor) emitOnRegistration( if message != "" { (*callback)(EventDetails{ - ProviderName: providerReference.featureProvider.Metadata().Domain, + ProviderName: providerReference.featureProvider.Metadata().Name, ProviderEventDetails: ProviderEventDetails{ Message: message, }, @@ -290,7 +290,7 @@ func (e *eventExecutor) startListeningAndShutdownOld(newProvider providerReferen return nil case <-time.After(200 * time.Millisecond): return fmt.Errorf("old event handler %s timeout waiting for handler shutdown", - oldReference.featureProvider.Metadata().Domain) + oldReference.featureProvider.Metadata().Name) } } diff --git a/openfeature/event_executor_test.go b/openfeature/event_executor_test.go index 0100fd0a..fec36577 100644 --- a/openfeature/event_executor_test.go +++ b/openfeature/event_executor_test.go @@ -160,7 +160,7 @@ func TestEventHandler_Eventing(t *testing.T) { // trigger event from provider implementation eventingImpl.Invoke(Event{ - ProviderName: eventingProvider.Metadata().Domain, + ProviderName: eventingProvider.Metadata().Name, EventType: ProviderReady, ProviderEventDetails: ProviderEventDetails{ Message: "ReadyMessage", @@ -178,8 +178,8 @@ func TestEventHandler_Eventing(t *testing.T) { t.Fatalf("timeout - event did not trigger") } - if result.ProviderName != eventingProvider.Metadata().Domain { - t.Errorf("expected %s, but got %s", eventingProvider.Metadata().Domain, result.ProviderName) + if result.ProviderName != eventingProvider.Metadata().Name { + t.Errorf("expected %s, but got %s", eventingProvider.Metadata().Name, result.ProviderName) } if result.Message != "ReadyMessage" { @@ -245,7 +245,7 @@ func TestEventHandler_clientAssociation(t *testing.T) { // invoke default provider eventingImpl.Invoke(Event{ - ProviderName: defaultProvider.Metadata().Domain, + ProviderName: defaultProvider.Metadata().Name, EventType: event, ProviderEventDetails: ProviderEventDetails{}, }) diff --git a/openfeature/memprovider/in_memory_provider.go b/openfeature/memprovider/in_memory_provider.go index 9cf5884d..3f833f24 100644 --- a/openfeature/memprovider/in_memory_provider.go +++ b/openfeature/memprovider/in_memory_provider.go @@ -24,7 +24,7 @@ func NewInMemoryProvider(from map[string]InMemoryFlag) InMemoryProvider { func (i InMemoryProvider) Metadata() openfeature.Metadata { return openfeature.Metadata{ - Domain: "InMemoryProvider", + Name: "InMemoryProvider", } } diff --git a/openfeature/memprovider/in_memory_provider_test.go b/openfeature/memprovider/in_memory_provider_test.go index e51bf1cc..f0aec0ba 100644 --- a/openfeature/memprovider/in_memory_provider_test.go +++ b/openfeature/memprovider/in_memory_provider_test.go @@ -252,11 +252,11 @@ func TestInMemoryProvider_Metadata(t *testing.T) { metadata := memoryProvider.Metadata() - if metadata.Domain == "" { + if metadata.Name == "" { t.Errorf("expected non-empty name for in-memory provider") } - if metadata.Domain != "InMemoryProvider" { + if metadata.Name != "InMemoryProvider" { t.Errorf("incorrect name for in-memory provider") } } diff --git a/openfeature/noop_provider.go b/openfeature/noop_provider.go index b3024056..12a72555 100644 --- a/openfeature/noop_provider.go +++ b/openfeature/noop_provider.go @@ -8,7 +8,7 @@ type NoopProvider struct { // Metadata returns the metadata of the provider func (e NoopProvider) Metadata() Metadata { - return Metadata{Domain: "NoopProvider"} + return Metadata{Name: "NoopProvider"} } // BooleanEvaluation returns a boolean flag. diff --git a/openfeature/noop_provider_test.go b/openfeature/noop_provider_test.go index 7134b8e7..82986e21 100644 --- a/openfeature/noop_provider_test.go +++ b/openfeature/noop_provider_test.go @@ -11,14 +11,14 @@ func TestNoopProvider_Metadata(t *testing.T) { want openfeature.Metadata }{ "Given a NOOP provider, then Metadata() will return NoopProvider": { - want: openfeature.Metadata{Domain: "NoopProvider"}, + want: openfeature.Metadata{Name: "NoopProvider"}, }, } for name, tt := range tests { t.Run(name, func(t *testing.T) { e := openfeature.NoopProvider{} if got := e.Metadata(); got != tt.want { - t.Errorf("Domain() = %v, want %v", got, tt.want) + t.Errorf("Name() = %v, want %v", got, tt.want) } }) } diff --git a/openfeature/openfeature_test.go b/openfeature/openfeature_test.go index 69f249e5..a41cbc29 100644 --- a/openfeature/openfeature_test.go +++ b/openfeature/openfeature_test.go @@ -40,7 +40,7 @@ func TestRequirement_1_1_2_1(t *testing.T) { mockProvider := NewMockFeatureProvider(ctrl) mockProviderName := "mock-provider" - mockProvider.EXPECT().Metadata().Return(Metadata{Domain: mockProviderName}).AnyTimes() + mockProvider.EXPECT().Metadata().Return(Metadata{Name: mockProviderName}).AnyTimes() err := SetProvider(mockProvider) if err != nil { @@ -402,10 +402,10 @@ func TestRequirement_1_1_3(t *testing.T) { ctrl := gomock.NewController(t) providerA := NewMockFeatureProvider(ctrl) - providerA.EXPECT().Metadata().Return(Metadata{Domain: "providerA"}).AnyTimes() + providerA.EXPECT().Metadata().Return(Metadata{Name: "providerA"}).AnyTimes() providerB := NewMockFeatureProvider(ctrl) - providerB.EXPECT().Metadata().Return(Metadata{Domain: "providerB"}).AnyTimes() + providerB.EXPECT().Metadata().Return(Metadata{Name: "providerB"}).AnyTimes() err := SetNamedProvider("clientA", providerA) if err != nil { @@ -436,19 +436,19 @@ func TestRequirement_1_1_3(t *testing.T) { // Validate provider retrieval by client evaluation. This uses forTransaction("clientName") provider, _, _ := forTransaction("clientA") - if provider.Metadata().Domain != "providerA" { - t.Errorf("expected %s, but got %s", "providerA", providerA.Metadata().Domain) + if provider.Metadata().Name != "providerA" { + t.Errorf("expected %s, but got %s", "providerA", providerA.Metadata().Name) } provider, _, _ = forTransaction("clientB") - if provider.Metadata().Domain != "providerB" { - t.Errorf("expected %s, but got %s", "providerB", providerA.Metadata().Domain) + if provider.Metadata().Name != "providerB" { + t.Errorf("expected %s, but got %s", "providerB", providerA.Metadata().Name) } // Validate overriding: If the client-domain already has a bound provider, it is overwritten with the new mapping. providerB2 := NewMockFeatureProvider(ctrl) - providerB2.EXPECT().Metadata().Return(Metadata{Domain: "providerB2"}).AnyTimes() + providerB2.EXPECT().Metadata().Return(Metadata{Name: "providerB2"}).AnyTimes() err = SetNamedProvider("clientB", providerB2) if err != nil { @@ -463,8 +463,8 @@ func TestRequirement_1_1_3(t *testing.T) { // Validate provider retrieval by client evaluation. This uses forTransaction("clientName") provider, _, _ = forTransaction("clientB") - if provider.Metadata().Domain != "providerB2" { - t.Errorf("expected %s, but got %s", "providerB2", providerA.Metadata().Domain) + if provider.Metadata().Name != "providerB2" { + t.Errorf("expected %s, but got %s", "providerB2", providerA.Metadata().Name) } } @@ -667,7 +667,7 @@ func TestDefaultClientUsage(t *testing.T) { ctrl := gomock.NewController(t) defaultProvider := NewMockFeatureProvider(ctrl) - defaultProvider.EXPECT().Metadata().Return(Metadata{Domain: "defaultClientReplacement"}).AnyTimes() + defaultProvider.EXPECT().Metadata().Return(Metadata{Name: "defaultClientReplacement"}).AnyTimes() err := SetProvider(defaultProvider) if err != nil { @@ -677,8 +677,8 @@ func TestDefaultClientUsage(t *testing.T) { // Validate provider retrieval by client evaluation provider, _, _ := forTransaction("ClientName") - if provider.Metadata().Domain != "defaultClientReplacement" { - t.Errorf("expected %s, but got %s", "defaultClientReplacement", provider.Metadata().Domain) + if provider.Metadata().Name != "defaultClientReplacement" { + t.Errorf("expected %s, but got %s", "defaultClientReplacement", provider.Metadata().Name) } } diff --git a/openfeature/provider.go b/openfeature/provider.go index 13313acb..389ffcac 100644 --- a/openfeature/provider.go +++ b/openfeature/provider.go @@ -188,5 +188,5 @@ type InterfaceResolutionDetail struct { // Metadata provides provider domain type Metadata struct { - Domain string + Name string } diff --git a/openfeature/provider_test.go b/openfeature/provider_test.go index bc57996d..546a28fa 100644 --- a/openfeature/provider_test.go +++ b/openfeature/provider_test.go @@ -26,7 +26,7 @@ func TestRequirement_2_1_1(t *testing.T) { metadata := Metadata{} metaValue := reflect.ValueOf(&metadata).Elem() - fieldName := "Domain" + fieldName := "Name" field := metaValue.FieldByName(fieldName) if field == (reflect.Value{}) { From 2bcb40f98907fb00f03d94b946e484241c7dd60a Mon Sep 17 00:00:00 2001 From: gunishmatta Date: Thu, 25 Apr 2024 22:51:19 +0530 Subject: [PATCH 08/24] code review changes Signed-off-by: gunishmatta --- openfeature/provider.go | 2 +- openfeature/provider_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openfeature/provider.go b/openfeature/provider.go index 389ffcac..634b23b3 100644 --- a/openfeature/provider.go +++ b/openfeature/provider.go @@ -186,7 +186,7 @@ type InterfaceResolutionDetail struct { ProviderResolutionDetail } -// Metadata provides provider domain +// Metadata provides provider name type Metadata struct { Name string } diff --git a/openfeature/provider_test.go b/openfeature/provider_test.go index 546a28fa..2dbddd3b 100644 --- a/openfeature/provider_test.go +++ b/openfeature/provider_test.go @@ -8,7 +8,7 @@ import ( "github.com/golang/mock/gomock" ) -// The provider interface MUST define a `metadata` member or accessor, containing a `domain` field or accessor +// The provider interface MUST define a `metadata` member or accessor, containing a `name` field or accessor // of type string, which identifies the provider implementation. func TestRequirement_2_1_1(t *testing.T) { ctrl := gomock.NewController(t) From 0f0411a4d69e15cde4f2036a1e6f1404e868e1b0 Mon Sep 17 00:00:00 2001 From: gunishmatta Date: Thu, 25 Apr 2024 23:46:59 +0530 Subject: [PATCH 09/24] code review changes Signed-off-by: gunishmatta --- openfeature/client.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openfeature/client.go b/openfeature/client.go index 30b6bcc5..9fe6c9a5 100644 --- a/openfeature/client.go +++ b/openfeature/client.go @@ -33,6 +33,7 @@ type IClient interface { // ClientMetadata provides a client's metadata type ClientMetadata struct { domain string + name string } // NewClientMetadata constructs ClientMetadata @@ -43,6 +44,12 @@ func NewClientMetadata(domain string) ClientMetadata { } } +// Name returns the client's name +// Deprecated: Name() exists for historical compatibility, use Domain() instead. +func (cm ClientMetadata) Name() string { + return cm.name +} + // Domain returns the client's domain func (cm ClientMetadata) Domain() string { return cm.domain From 5c61d0a4ecbcfba2164e747aaa5481904e97ab14 Mon Sep 17 00:00:00 2001 From: gunishmatta Date: Fri, 26 Apr 2024 00:04:33 +0530 Subject: [PATCH 10/24] code review changes Signed-off-by: gunishmatta --- openfeature/api.go | 4 ++-- openfeature/openfeature.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openfeature/api.go b/openfeature/api.go index 99021cbe..97dae5df 100644 --- a/openfeature/api.go +++ b/openfeature/api.go @@ -160,13 +160,13 @@ func (api *evaluationAPI) getHooks() []Hook { // forTransaction is a helper to retrieve transaction(flag evaluation) scoped operators. // Returns the default FeatureProvider if no provider mapping exist for the given client domain. -func (api *evaluationAPI) forTransaction(clientName string) (FeatureProvider, []Hook, EvaluationContext) { +func (api *evaluationAPI) forTransaction(clientDomain string) (FeatureProvider, []Hook, EvaluationContext) { api.mu.RLock() defer api.mu.RUnlock() var provider FeatureProvider - provider = api.namedProviders[clientName] + provider = api.namedProviders[clientDomain] if provider == nil { provider = api.defaultProvider } diff --git a/openfeature/openfeature.go b/openfeature/openfeature.go index 5df85ee3..399e72e5 100644 --- a/openfeature/openfeature.go +++ b/openfeature/openfeature.go @@ -122,6 +122,6 @@ func globalLogger() logr.Logger { // forTransaction is a helper to retrieve transaction scoped operators by Client. // Here, transaction means a flag evaluation. -func forTransaction(clientName string) (FeatureProvider, []Hook, EvaluationContext) { - return api.forTransaction(clientName) +func forTransaction(clientDomain string) (FeatureProvider, []Hook, EvaluationContext) { + return api.forTransaction(clientDomain) } From 7fffad383c13432a055e04d2db25f58fbf4703d1 Mon Sep 17 00:00:00 2001 From: Dave Henderson Date: Tue, 9 Apr 2024 07:17:14 -0400 Subject: [PATCH 11/24] feat: Added domain scoping #261 Please enter the commit message for your chanes. Lines starting Author: Gunish Matta Signed-off-by: gunishmatta --- openfeature/client.go | 104 ++++++++++++++++++++++++++--- openfeature/client_example_test.go | 49 ++++++++++++++ 2 files changed, 145 insertions(+), 8 deletions(-) diff --git a/openfeature/client.go b/openfeature/client.go index 9fe6c9a5..4d54d007 100644 --- a/openfeature/client.go +++ b/openfeature/client.go @@ -28,19 +28,24 @@ type IClient interface { FloatValueDetails(ctx context.Context, flag string, defaultValue float64, evalCtx EvaluationContext, options ...Option) (FloatEvaluationDetails, error) IntValueDetails(ctx context.Context, flag string, defaultValue int64, evalCtx EvaluationContext, options ...Option) (IntEvaluationDetails, error) ObjectValueDetails(ctx context.Context, flag string, defaultValue interface{}, evalCtx EvaluationContext, options ...Option) (InterfaceEvaluationDetails, error) + + Boolean(ctx context.Context, flag string, defaultValue bool, evalCtx EvaluationContext, options ...Option) bool + String(ctx context.Context, flag string, defaultValue string, evalCtx EvaluationContext, options ...Option) string + Float(ctx context.Context, flag string, defaultValue float64, evalCtx EvaluationContext, options ...Option) float64 + Int(ctx context.Context, flag string, defaultValue int64, evalCtx EvaluationContext, options ...Option) int64 + Object(ctx context.Context, flag string, defaultValue interface{}, evalCtx EvaluationContext, options ...Option) interface{} } // ClientMetadata provides a client's metadata type ClientMetadata struct { - domain string - name string + name string } // NewClientMetadata constructs ClientMetadata // Allows for simplified hook test cases while maintaining immutability -func NewClientMetadata(domain string) ClientMetadata { +func NewClientMetadata(name string) ClientMetadata { return ClientMetadata{ - domain: domain, + name: name, } } @@ -52,7 +57,7 @@ func (cm ClientMetadata) Name() string { // Domain returns the client's domain func (cm ClientMetadata) Domain() string { - return cm.domain + return cm.name } // Client implements the behaviour required of an openfeature client @@ -64,10 +69,13 @@ type Client struct { logger func() logr.Logger } -// NewClient returns a new Client. Domain is a unique identifier for this client +// interface guard to ensure that Client implements IClient +var _ IClient = (*Client)(nil) + +// NewClient returns a new Client. Name is a unique identifier for this client func NewClient(domain string) *Client { return &Client{ - metadata: ClientMetadata{domain: domain}, + metadata: ClientMetadata{name: domain}, hooks: []Hook{}, evaluationContext: EvaluationContext{}, logger: globalLogger, @@ -587,6 +595,86 @@ func (c *Client) ObjectValueDetails(ctx context.Context, flag string, defaultVal return c.evaluate(ctx, flag, Object, defaultValue, evalCtx, *evalOptions) } +// Boolean performs a flag evaluation that returns a boolean. Any error +// encountered during the evaluation will result in the default value being +// returned. To explicitly handle errors, use [BooleanValue] or [BooleanValueDetails] +// +// Parameters: +// - ctx is the standard go context struct used to manage requests (e.g. timeouts) +// - flag is the key that uniquely identifies a particular flag +// - defaultValue is returned if an error occurs +// - evalCtx is the evaluation context used in a flag evaluation (not to be confused with ctx) +// - options are optional additional evaluation options e.g. WithHooks & WithHookHints +func (c *Client) Boolean(ctx context.Context, flag string, defaultValue bool, evalCtx EvaluationContext, options ...Option) bool { + value, _ := c.BooleanValue(ctx, flag, defaultValue, evalCtx, options...) + + return value +} + +// String performs a flag evaluation that returns a string. Any error +// encountered during the evaluation will result in the default value being +// returned. To explicitly handle errors, use [StringValue] or [StringValueDetails] +// +// Parameters: +// - ctx is the standard go context struct used to manage requests (e.g. timeouts) +// - flag is the key that uniquely identifies a particular flag +// - defaultValue is returned if an error occurs +// - evalCtx is the evaluation context used in a flag evaluation (not to be confused with ctx) +// - options are optional additional evaluation options e.g. WithHooks & WithHookHints +func (c *Client) String(ctx context.Context, flag string, defaultValue string, evalCtx EvaluationContext, options ...Option) string { + value, _ := c.StringValue(ctx, flag, defaultValue, evalCtx, options...) + + return value +} + +// Float performs a flag evaluation that returns a float64. Any error +// encountered during the evaluation will result in the default value being +// returned. To explicitly handle errors, use [FloatValue] or [FloatValueDetails] +// +// Parameters: +// - ctx is the standard go context struct used to manage requests (e.g. timeouts) +// - flag is the key that uniquely identifies a particular flag +// - defaultValue is returned if an error occurs +// - evalCtx is the evaluation context used in a flag evaluation (not to be confused with ctx) +// - options are optional additional evaluation options e.g. WithHooks & WithHookHints +func (c *Client) Float(ctx context.Context, flag string, defaultValue float64, evalCtx EvaluationContext, options ...Option) float64 { + value, _ := c.FloatValue(ctx, flag, defaultValue, evalCtx, options...) + + return value +} + +// Int performs a flag evaluation that returns an int64. Any error +// encountered during the evaluation will result in the default value being +// returned. To explicitly handle errors, use [IntValue] or [IntValueDetails] +// +// Parameters: +// - ctx is the standard go context struct used to manage requests (e.g. timeouts) +// - flag is the key that uniquely identifies a particular flag +// - defaultValue is returned if an error occurs +// - evalCtx is the evaluation context used in a flag evaluation (not to be confused with ctx) +// - options are optional additional evaluation options e.g. WithHooks & WithHookHints +func (c *Client) Int(ctx context.Context, flag string, defaultValue int64, evalCtx EvaluationContext, options ...Option) int64 { + value, _ := c.IntValue(ctx, flag, defaultValue, evalCtx, options...) + + return value +} + +// Object performs a flag evaluation that returns an object. Any error +// encountered during the evaluation will result in the default value being +// returned. To explicitly handle errors, use [ObjectValue] or [ObjectValueDetails] +// +// Parameters: +// - ctx is the standard go context struct used to manage requests (e.g. timeouts) +// - flag is the key that uniquely identifies a particular flag +// - defaultValue is returned if an error occurs +// - evalCtx is the evaluation context used in a flag evaluation (not to be confused with ctx) +// - options are optional additional evaluation options e.g. WithHooks & WithHookHints +func (c *Client) Object(ctx context.Context, flag string, defaultValue interface{}, evalCtx EvaluationContext, options ...Option) interface{} { + value, _ := c.ObjectValue(ctx, flag, defaultValue, evalCtx, options...) + + return value +} + func (c *Client) evaluate( ctx context.Context, flag string, flagType Type, defaultValue interface{}, evalCtx EvaluationContext, options EvaluationOptions, ) (InterfaceEvaluationDetails, error) { @@ -603,7 +691,7 @@ func (c *Client) evaluate( } // ensure that the same provider & hooks are used across this transaction to avoid unexpected behaviour - provider, globalHooks, globalCtx := forTransaction(c.metadata.domain) + provider, globalHooks, globalCtx := forTransaction(c.metadata.name) evalCtx = mergeContexts(evalCtx, c.evaluationContext, globalCtx) // API (global) -> client -> invocation apiClientInvocationProviderHooks := append(append(append(globalHooks, c.hooks...), options.hooks...), provider.Hooks()...) // API, Client, Invocation, Provider diff --git a/openfeature/client_example_test.go b/openfeature/client_example_test.go index cd0bc2f3..f72290e0 100644 --- a/openfeature/client_example_test.go +++ b/openfeature/client_example_test.go @@ -80,3 +80,52 @@ func ExampleClient_ObjectValue() { fmt.Printf("test-flag value: %v", string(str)) // Output: test-flag value: {"foo":"bar"} } + +func ExampleClient_Boolean() { + ctx := context.Background() + client := openfeature.NewClient("example-client") + + if client.Boolean(ctx, "myflag", true, openfeature.EvaluationContext{}) { + fmt.Println("myflag is true") + } else { + fmt.Println("myflag is false") + } + + // Output: myflag is true +} + +func ExampleClient_String() { + ctx := context.Background() + client := openfeature.NewClient("example-client") + + fmt.Println(client.String(ctx, "myflag", "default", openfeature.EvaluationContext{})) + + // Output: default +} + +func ExampleClient_Float() { + ctx := context.Background() + client := openfeature.NewClient("example-client") + + fmt.Println(client.Float(ctx, "myflag", 0.5, openfeature.EvaluationContext{})) + + // Output: 0.5 +} + +func ExampleClient_Int() { + ctx := context.Background() + client := openfeature.NewClient("example-client") + + fmt.Println(client.Int(ctx, "myflag", 5, openfeature.EvaluationContext{})) + + // Output: 5 +} + +func ExampleClient_Object() { + ctx := context.Background() + client := openfeature.NewClient("example-client") + + fmt.Println(client.Object(ctx, "myflag", map[string]string{"foo": "bar"}, openfeature.EvaluationContext{})) + + // Output: map[foo:bar] +} From 69985f6f59c74c241be25b19435a75c63777c7f3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 13:15:59 -0400 Subject: [PATCH 12/24] chore(main): release 1.11.0 (#254) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Signed-off-by: gunishmatta --- .release-please-manifest.json | 2 +- CHANGELOG.md | 14 ++++++++++++++ README.md | 4 ++-- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index eb4e0dba..caf14871 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.10.0" + ".": "1.11.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b36eb3f..a4a6ea9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [1.11.0](https://github.com/open-feature/go-sdk/compare/v1.10.0...v1.11.0) (2024-04-09) + + +### โœจ New Features + +* Adding simplified evaluation methods ([#263](https://github.com/open-feature/go-sdk/issues/263)) ([7b610c7](https://github.com/open-feature/go-sdk/commit/7b610c7c5019535ffde98c0ad725a0e73e7703a1)) + + +### ๐Ÿงน Chore + +* **deps:** update actions/checkout action to v4 ([#212](https://github.com/open-feature/go-sdk/issues/212)) ([2944608](https://github.com/open-feature/go-sdk/commit/2944608562d04521fcf92000948a22012e630471)) +* **deps:** update actions/setup-go action to v5 ([#237](https://github.com/open-feature/go-sdk/issues/237)) ([53d9e7e](https://github.com/open-feature/go-sdk/commit/53d9e7e4fd0127b4819de5d4d8c82735ee9d0c83)) +* **deps:** update cyclonedx/gh-gomod-generate-sbom action to v2 ([#179](https://github.com/open-feature/go-sdk/issues/179)) ([b624a43](https://github.com/open-feature/go-sdk/commit/b624a43fc2fa132399543de79b9ecf5008312aaf)) + ## [1.10.0](https://github.com/open-feature/go-sdk/compare/v1.9.0...v1.10.0) (2024-02-07) diff --git a/README.md b/README.md index 053b5050..05a552f7 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ Specification - - Release + + Release
From 2e3fe32ce1d1790e9d38562d992a362e409da9b2 Mon Sep 17 00:00:00 2001 From: odubajDT <93584209+odubajDT@users.noreply.github.com> Date: Tue, 9 Apr 2024 22:15:33 +0200 Subject: [PATCH 13/24] chore: bump Go to version 1.20 (#255) * chore: bump Go to version 1.21 Signed-off-by: odubajDT * update readme with go version and note Signed-off-by: Kavindu Dodanduwa * Update README.md Co-authored-by: Michael Beemer Signed-off-by: Kavindu Dodanduwa --------- Signed-off-by: odubajDT Signed-off-by: Kavindu Dodanduwa Signed-off-by: Kavindu Dodanduwa Co-authored-by: Kavindu Dodanduwa Co-authored-by: Kavindu Dodanduwa Co-authored-by: Michael Beemer Signed-off-by: gunishmatta --- .github/workflows/pr-checks.yml | 2 +- .github/workflows/release-please.yml | 2 +- README.md | 5 ++++- go.mod | 8 ++++---- go.sum | 6 ++++++ 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 6c941f9c..44e58259 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -7,7 +7,7 @@ on: pull_request: env: # Default minimum version of Go to support. - DEFAULT_GO_VERSION: 1.19 + DEFAULT_GO_VERSION: "~1.20" jobs: lint: runs-on: ubuntu-latest diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 77530ae1..58e562be 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -7,7 +7,7 @@ env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} # Default minimum version of Go to support. - DEFAULT_GO_VERSION: 1.19 + DEFAULT_GO_VERSION: "~1.20" jobs: release-please: diff --git a/README.md b/README.md index 05a552f7..290740d4 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,10 @@ ### Requirements -- Go 1.19+ +Go language version: [1.20](https://go.dev/doc/devel/release#go1.20) + +> [!NOTE] +> The OpenFeature Go SDK only supports currently maintained Go language versions. ### Install diff --git a/go.mod b/go.mod index 3a03a461..5c3b603c 100644 --- a/go.mod +++ b/go.mod @@ -1,22 +1,22 @@ module github.com/open-feature/go-sdk -go 1.19 +go 1.20 require ( github.com/cucumber/godog v0.14.0 github.com/go-logr/logr v1.4.1 github.com/golang/mock v1.6.0 - golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 golang.org/x/text v0.14.0 ) require ( github.com/cucumber/gherkin/go/v26 v26.2.0 // indirect github.com/cucumber/messages/go/v21 v21.0.1 // indirect - github.com/gofrs/uuid v4.3.1+incompatible // indirect + github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-memdb v1.3.4 // indirect - github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/testify v1.8.4 // indirect ) diff --git a/go.sum b/go.sum index 79be9c6c..d4d39715 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,8 @@ github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4 github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI= github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -27,6 +29,8 @@ github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -51,6 +55,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 h1:/RIbNt/Zr7rVhIkQhooTxCxFcdWLGIKnZA4IXNFSrvo= golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= From 9785fac773a4729283f6f22ecabfa96bc086bf88 Mon Sep 17 00:00:00 2001 From: gunishmatta Date: Fri, 26 Apr 2024 00:33:39 +0530 Subject: [PATCH 14/24] code review changes Signed-off-by: gunishmatta --- README.md | 27 +++++++++++++-------------- openfeature/api.go | 8 ++++---- openfeature/event_executor.go | 10 +++++----- openfeature/openfeature.go | 16 ++++++++-------- 4 files changed, 30 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 290740d4..f8f0bcb7 100644 --- a/README.md +++ b/README.md @@ -89,16 +89,17 @@ See [here](https://pkg.go.dev/github.com/open-feature/go-sdk/pkg/openfeature) fo ## ๐ŸŒŸ Features -| Status | Features | Description | -| ------ | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -| โœ… | [Providers](#providers) | Integrate with a commercial, open source, or in-house feature management tool. | +| Status | Features | Description | +| ------ |---------------------------------| --------------------------------------------------------------------------------------------------------------------------------- | +| โœ… | [Providers](#providers) | Integrate with a commercial, open source, or in-house feature management tool. | | โœ… | [Targeting](#targeting) | Contextually-aware flag evaluation using [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context). | -| โœ… | [Hooks](#hooks) | Add functionality to various stages of the flag evaluation life-cycle. | -| โœ… | [Logging](#logging) | Integrate with popular logging packages. | -| โœ… | [Named clients](#named-clients) | Utilize multiple providers in a single application. | -| โœ… | [Eventing](#eventing) | React to state changes in the provider or flag management system. | -| โœ… | [Shutdown](#shutdown) | Gracefully clean up a provider during application shutdown. | -| โœ… | [Extending](#extending) | Extend OpenFeature with custom providers and hooks. | +| โœ… | [Hooks](#hooks) | Add functionality to various stages of the flag evaluation life-cycle. | +| โœ… | [Logging](#logging) | Integrate with popular logging packages. | +| โœ… | [Domains](#domains) | Logically bind clients with providers.| +| โœ… | [Named clients](#named-clients) | Utilize multiple providers in a single application. | +| โœ… | [Eventing](#eventing) | React to state changes in the provider or flag management system. | +| โœ… | [Shutdown](#shutdown) | Gracefully clean up a provider during application shutdown. | +| โœ… | [Extending](#extending) | Extend OpenFeature with custom providers and hooks. | Implemented: โœ… | In-progress: โš ๏ธ | Not implemented yet: โŒ @@ -190,11 +191,8 @@ c := openfeature.NewClient("log").WithLogger(l) // set the logger at client leve [logr](https://github.com/go-logr/logr) uses incremental verbosity levels (akin to named levels but in integer form). The SDK logs `info` at level `0` and `debug` at level `1`. Errors are always logged. -### Named clients - -Clients can be given a name. -A name is a logical identifier which can be used to associate clients with a particular provider. -If a name has no associated provider, the global provider is used. +### Domains +Clients can be assigned to a domain. A domain is a logical identifier which can be used to associate clients with a particular provider. If a domain has no associated provider, the default provider is used. ```go import "github.com/open-feature/go-sdk/openfeature" @@ -210,6 +208,7 @@ clientWithDefault := openfeature.NewClient("") clientForCache := openfeature.NewClient("clientForCache") ``` + ### Eventing Events allow you to react to state changes in the provider or underlying flag management system, such as flag definition changes, provider readiness, or error conditions. diff --git a/openfeature/api.go b/openfeature/api.go index 97dae5df..fc04de3e 100644 --- a/openfeature/api.go +++ b/openfeature/api.go @@ -71,7 +71,7 @@ func (api *evaluationAPI) getProvider() FeatureProvider { } // setProvider sets a provider with client domain. Returns an error if FeatureProvider is nil -func (api *evaluationAPI) setNamedProvider(clientName string, provider FeatureProvider, async bool) error { +func (api *evaluationAPI) setNamedProvider(clientDomain string, provider FeatureProvider, async bool) error { api.mu.Lock() defer api.mu.Unlock() @@ -81,15 +81,15 @@ func (api *evaluationAPI) setNamedProvider(clientName string, provider FeaturePr // Initialize new named provider and shutdown the old one // Provider update must be non-blocking, hence initialization & shutdown happens concurrently - oldProvider := api.namedProviders[clientName] - api.namedProviders[clientName] = provider + oldProvider := api.namedProviders[clientDomain] + api.namedProviders[clientDomain] = provider err := api.initNewAndShutdownOld(provider, oldProvider, async) if err != nil { return err } - err = api.eventExecutor.registerNamedEventingProvider(clientName, provider) + err = api.eventExecutor.registerNamedEventingProvider(clientDomain, provider) if err != nil { return err } diff --git a/openfeature/event_executor.go b/openfeature/event_executor.go index a5fc12ef..53843972 100644 --- a/openfeature/event_executor.go +++ b/openfeature/event_executor.go @@ -111,16 +111,16 @@ func (e *eventExecutor) removeApiHandler(t EventType, c EventCallback) { } // registerClientHandler registers a client level handler -func (e *eventExecutor) registerClientHandler(clientName string, t EventType, c EventCallback) { +func (e *eventExecutor) registerClientHandler(clientDomain string, t EventType, c EventCallback) { e.mu.Lock() defer e.mu.Unlock() - _, ok := e.scopedRegistry[clientName] + _, ok := e.scopedRegistry[clientDomain] if !ok { - e.scopedRegistry[clientName] = newScopedCallback(clientName) + e.scopedRegistry[clientDomain] = newScopedCallback(clientDomain) } - registry := e.scopedRegistry[clientName] + registry := e.scopedRegistry[clientDomain] if registry.callbacks[t] == nil { registry.callbacks[t] = []EventCallback{c} @@ -128,7 +128,7 @@ func (e *eventExecutor) registerClientHandler(clientName string, t EventType, c registry.callbacks[t] = append(registry.callbacks[t], c) } - reference, ok := e.namedProviderReference[clientName] + reference, ok := e.namedProviderReference[clientDomain] if !ok { // fallback to default reference = e.defaultProviderReference diff --git a/openfeature/openfeature.go b/openfeature/openfeature.go index 399e72e5..69b02964 100644 --- a/openfeature/openfeature.go +++ b/openfeature/openfeature.go @@ -31,14 +31,14 @@ func SetProviderAndWait(provider FeatureProvider) error { // SetNamedProvider sets a provider mapped to the given Client domain. Provider initialization is asynchronous and // status can be checked from provider status -func SetNamedProvider(clientName string, provider FeatureProvider) error { - return api.setNamedProvider(clientName, provider, true) +func SetNamedProvider(clientDomain string, provider FeatureProvider) error { + return api.setNamedProvider(clientDomain, provider, true) } // SetNamedProviderAndWait sets a provider mapped to the given Client domain and waits for its initialization. // Returns an error if initialization cause error -func SetNamedProviderAndWait(clientName string, provider FeatureProvider) error { - return api.setNamedProvider(clientName, provider, false) +func SetNamedProviderAndWait(clientDomain string, provider FeatureProvider) error { + return api.setNamedProvider(clientDomain, provider, false) } // SetEvaluationContext sets the global evaluation context. @@ -67,8 +67,8 @@ func AddHandler(eventType EventType, callback EventCallback) { } // addClientHandler is a helper for Client to add an event handler -func addClientHandler(name string, t EventType, c EventCallback) { - api.eventExecutor.registerClientHandler(name, t, c) +func addClientHandler(domain string, t EventType, c EventCallback) { + api.eventExecutor.registerClientHandler(domain, t, c) } // RemoveHandler allows to remove API level event handler @@ -77,8 +77,8 @@ func RemoveHandler(eventType EventType, callback EventCallback) { } // removeClientHandler is a helper for Client to add an event handler -func removeClientHandler(name string, t EventType, c EventCallback) { - api.eventExecutor.removeClientHandler(name, t, c) +func removeClientHandler(domain string, t EventType, c EventCallback) { + api.eventExecutor.removeClientHandler(domain, t, c) } // getAPIEventRegistry is a helper for testing From 11235b0cc6a2a4ce277a4cd886f6e9e9978b0c08 Mon Sep 17 00:00:00 2001 From: gunishmatta Date: Fri, 26 Apr 2024 00:34:12 +0530 Subject: [PATCH 15/24] code review changes Signed-off-by: gunishmatta --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index f8f0bcb7..ca530e8c 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,6 @@ See [here](https://pkg.go.dev/github.com/open-feature/go-sdk/pkg/openfeature) fo | โœ… | [Hooks](#hooks) | Add functionality to various stages of the flag evaluation life-cycle. | | โœ… | [Logging](#logging) | Integrate with popular logging packages. | | โœ… | [Domains](#domains) | Logically bind clients with providers.| -| โœ… | [Named clients](#named-clients) | Utilize multiple providers in a single application. | | โœ… | [Eventing](#eventing) | React to state changes in the provider or flag management system. | | โœ… | [Shutdown](#shutdown) | Gracefully clean up a provider during application shutdown. | | โœ… | [Extending](#extending) | Extend OpenFeature with custom providers and hooks. | From 22e5dba10a2d9724af1b98a4483ab39de549d6ef Mon Sep 17 00:00:00 2001 From: gunishmatta Date: Fri, 26 Apr 2024 00:35:46 +0530 Subject: [PATCH 16/24] code review changes Signed-off-by: gunishmatta --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ca530e8c..37fc7ebd 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ openfeature.SetProvider(MyProvider{}) ``` In some situations, it may be beneficial to register multiple providers in the same application. -This is possible using [named clients](#named-clients), which is covered in more details below. +This is possible using [domains](#domains), which is covered in more details below. ### Targeting From 7427db969a9891c97f697012c4c5d5c00f1480f3 Mon Sep 17 00:00:00 2001 From: gunishmatta Date: Fri, 3 May 2024 13:32:42 +0530 Subject: [PATCH 17/24] code review changes Signed-off-by: gunishmatta --- pkg/openfeature/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/openfeature/client.go b/pkg/openfeature/client.go index 80ddb4fe..9abe3c9e 100644 --- a/pkg/openfeature/client.go +++ b/pkg/openfeature/client.go @@ -29,7 +29,7 @@ func NewClientMetadata(name string) ClientMetadata { // Deprecated: use github.com/open-feature/go-sdk/openfeature.Client, instead. type Client = openfeature.Client -// NewClient returns a new Client. Domain is a unique identifier for this client +// NewClient returns a new Client. Name is a unique identifier for this client // // Deprecated: use github.com/open-feature/go-sdk/openfeature.NewClient, // instead. From 543f05326aa279a28c56c006774f30255eee67b1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 16:55:34 +0000 Subject: [PATCH 18/24] fix(deps): update module github.com/cucumber/godog to v0.14.1 (#267) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Signed-off-by: gunishmatta --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 5c3b603c..cbdb63ec 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/open-feature/go-sdk go 1.20 require ( - github.com/cucumber/godog v0.14.0 + github.com/cucumber/godog v0.14.1 github.com/go-logr/logr v1.4.1 github.com/golang/mock v1.6.0 golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 diff --git a/go.sum b/go.sum index d4d39715..b7a97dae 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,8 @@ github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0= github.com/cucumber/godog v0.14.0 h1:h/K4t7XBxsFBF+UJEahNqJ1/2VHVepRXCSq3WWWnehs= github.com/cucumber/godog v0.14.0/go.mod h1:FX3rzIDybWABU4kuIXLZ/qtqEe1Ac5RdXmqvACJOces= +github.com/cucumber/godog v0.14.1 h1:HGZhcOyyfaKclHjJ+r/q93iaTJZLKYW6Tv3HkmUE6+M= +github.com/cucumber/godog v0.14.1/go.mod h1:FX3rzIDybWABU4kuIXLZ/qtqEe1Ac5RdXmqvACJOces= github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI= github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s= github.com/cucumber/messages/go/v22 v22.0.0/go.mod h1:aZipXTKc0JnjCsXrJnuZpWhtay93k7Rn3Dee7iyPJjs= From 617110a138bb57d07a34eedc588d4d96e5171d65 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 15:33:58 -0400 Subject: [PATCH 19/24] chore(deps): update goreleaser/goreleaser-action action to v5 (#219) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Signed-off-by: gunishmatta --- .github/workflows/release-please.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 58e562be..8a50db6e 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -45,7 +45,7 @@ jobs: version: v1.3.0 - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v4 + uses: goreleaser/goreleaser-action@v5 with: args: release --rm-dist env: From 10661be9fa6cdeccc13f0b20a5331cb9e219473e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 15:43:31 -0400 Subject: [PATCH 20/24] chore(deps): update codecov/codecov-action action to v4 (#250) * chore(deps): update codecov/codecov-action action to v4 * add codecov upload token Signed-off-by: Michael Beemer --------- Signed-off-by: Michael Beemer Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Michael Beemer Signed-off-by: gunishmatta --- .github/workflows/pr-checks.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 44e58259..523f023f 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -58,4 +58,9 @@ jobs: - name: Run tests run: go test -race -coverprofile=coverage.out -covermode=atomic ./... - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4.3.0 + with: + name: Code Coverage for GO SDK + fail_ci_if_error: true + verbose: true + token: ${{ secrets.CODECOV_UPLOAD_TOKEN }} From 7cd6656c523011d7862d1a0b80f073f6a6f2f3c4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 1 May 2024 13:37:04 +0000 Subject: [PATCH 21/24] fix(deps): update module golang.org/x/exp to v0.0.0-20240416160154-fe59bbe5cc7f (#269) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Signed-off-by: gunishmatta --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index cbdb63ec..68358668 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/cucumber/godog v0.14.1 github.com/go-logr/logr v1.4.1 github.com/golang/mock v1.6.0 - golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 + golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f golang.org/x/text v0.14.0 ) diff --git a/go.sum b/go.sum index b7a97dae..b2c39315 100644 --- a/go.sum +++ b/go.sum @@ -59,6 +59,8 @@ golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 h1:/RIbNt/Zr7rVhIkQhooTxCxFc golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= From 98d651caa268c7fccda247d3df923be3d6fcd426 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 1 May 2024 18:53:43 +0000 Subject: [PATCH 22/24] chore(deps): update codecov/codecov-action action to v4.3.1 (#270) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Signed-off-by: gunishmatta --- .github/workflows/pr-checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 523f023f..5617ab2a 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -58,7 +58,7 @@ jobs: - name: Run tests run: go test -race -coverprofile=coverage.out -covermode=atomic ./... - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4.3.0 + uses: codecov/codecov-action@v4.3.1 with: name: Code Coverage for GO SDK fail_ci_if_error: true From b2e2d17b0296b0477483a65f9c66234a8f9ac0de Mon Sep 17 00:00:00 2001 From: gunishmatta Date: Fri, 3 May 2024 14:43:40 +0530 Subject: [PATCH 23/24] Revert "code review changes" This reverts commit 3472ee897827542991935111b8895e8c18fa6bec. Signed-off-by: gunishmatta --- openfeature/client.go | 13 +++++++------ pkg/openfeature/client.go | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/openfeature/client.go b/openfeature/client.go index 4d54d007..4a357a81 100644 --- a/openfeature/client.go +++ b/openfeature/client.go @@ -38,14 +38,15 @@ type IClient interface { // ClientMetadata provides a client's metadata type ClientMetadata struct { - name string + domain string + name string } // NewClientMetadata constructs ClientMetadata // Allows for simplified hook test cases while maintaining immutability -func NewClientMetadata(name string) ClientMetadata { +func NewClientMetadata(domain string) ClientMetadata { return ClientMetadata{ - name: name, + domain: domain, } } @@ -57,7 +58,7 @@ func (cm ClientMetadata) Name() string { // Domain returns the client's domain func (cm ClientMetadata) Domain() string { - return cm.name + return cm.domain } // Client implements the behaviour required of an openfeature client @@ -75,7 +76,7 @@ var _ IClient = (*Client)(nil) // NewClient returns a new Client. Name is a unique identifier for this client func NewClient(domain string) *Client { return &Client{ - metadata: ClientMetadata{name: domain}, + metadata: ClientMetadata{domain: domain}, hooks: []Hook{}, evaluationContext: EvaluationContext{}, logger: globalLogger, @@ -691,7 +692,7 @@ func (c *Client) evaluate( } // ensure that the same provider & hooks are used across this transaction to avoid unexpected behaviour - provider, globalHooks, globalCtx := forTransaction(c.metadata.name) + provider, globalHooks, globalCtx := forTransaction(c.metadata.domain) evalCtx = mergeContexts(evalCtx, c.evaluationContext, globalCtx) // API (global) -> client -> invocation apiClientInvocationProviderHooks := append(append(append(globalHooks, c.hooks...), options.hooks...), provider.Hooks()...) // API, Client, Invocation, Provider diff --git a/pkg/openfeature/client.go b/pkg/openfeature/client.go index 9abe3c9e..80ddb4fe 100644 --- a/pkg/openfeature/client.go +++ b/pkg/openfeature/client.go @@ -29,7 +29,7 @@ func NewClientMetadata(name string) ClientMetadata { // Deprecated: use github.com/open-feature/go-sdk/openfeature.Client, instead. type Client = openfeature.Client -// NewClient returns a new Client. Name is a unique identifier for this client +// NewClient returns a new Client. Domain is a unique identifier for this client // // Deprecated: use github.com/open-feature/go-sdk/openfeature.NewClient, // instead. From 4e9a2d2b623c2497aec7af2232e16518d929c468 Mon Sep 17 00:00:00 2001 From: gunishmatta Date: Fri, 3 May 2024 14:45:39 +0530 Subject: [PATCH 24/24] code review changes Signed-off-by: gunishmatta --- openfeature/client.go | 13 ++++++------- pkg/openfeature/client.go | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/openfeature/client.go b/openfeature/client.go index 4a357a81..4d54d007 100644 --- a/openfeature/client.go +++ b/openfeature/client.go @@ -38,15 +38,14 @@ type IClient interface { // ClientMetadata provides a client's metadata type ClientMetadata struct { - domain string - name string + name string } // NewClientMetadata constructs ClientMetadata // Allows for simplified hook test cases while maintaining immutability -func NewClientMetadata(domain string) ClientMetadata { +func NewClientMetadata(name string) ClientMetadata { return ClientMetadata{ - domain: domain, + name: name, } } @@ -58,7 +57,7 @@ func (cm ClientMetadata) Name() string { // Domain returns the client's domain func (cm ClientMetadata) Domain() string { - return cm.domain + return cm.name } // Client implements the behaviour required of an openfeature client @@ -76,7 +75,7 @@ var _ IClient = (*Client)(nil) // NewClient returns a new Client. Name is a unique identifier for this client func NewClient(domain string) *Client { return &Client{ - metadata: ClientMetadata{domain: domain}, + metadata: ClientMetadata{name: domain}, hooks: []Hook{}, evaluationContext: EvaluationContext{}, logger: globalLogger, @@ -692,7 +691,7 @@ func (c *Client) evaluate( } // ensure that the same provider & hooks are used across this transaction to avoid unexpected behaviour - provider, globalHooks, globalCtx := forTransaction(c.metadata.domain) + provider, globalHooks, globalCtx := forTransaction(c.metadata.name) evalCtx = mergeContexts(evalCtx, c.evaluationContext, globalCtx) // API (global) -> client -> invocation apiClientInvocationProviderHooks := append(append(append(globalHooks, c.hooks...), options.hooks...), provider.Hooks()...) // API, Client, Invocation, Provider diff --git a/pkg/openfeature/client.go b/pkg/openfeature/client.go index 80ddb4fe..9abe3c9e 100644 --- a/pkg/openfeature/client.go +++ b/pkg/openfeature/client.go @@ -29,7 +29,7 @@ func NewClientMetadata(name string) ClientMetadata { // Deprecated: use github.com/open-feature/go-sdk/openfeature.Client, instead. type Client = openfeature.Client -// NewClient returns a new Client. Domain is a unique identifier for this client +// NewClient returns a new Client. Name is a unique identifier for this client // // Deprecated: use github.com/open-feature/go-sdk/openfeature.NewClient, // instead.