Skip to content

Commit be42330

Browse files
committed
feat: code cleanup with test updates and README update
1 parent fb6c994 commit be42330

17 files changed

Lines changed: 190 additions & 125 deletions

File tree

README.md

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,30 @@
11
# Feature Flags Client
22

33
The purpose of this project is to expose an interface to use the Gitlab Feature-Flags feature across the
4-
Operations-Framework projects.
4+
one Gitlab specific group of repositories.
55
[Feature-Flags](https://docs.gitlab.com/ee/operations/feature_flags.html) is a Gitlab integrated system that gives the
66
possibility to dynamically Toggle features in live environments.
77

8-
9-
## How to Add a New Feature Flag
10-
11-
1. Add the new `feature-flag` to the
12-
repository [feature-flags section](https://gitlab.com/docebo/architecture/operations-framework/feature-flags/-/feature_flags).
13-
2. Add the new `feature-flag` to the [feature flags constants list](./featureflags/feature_flags.go).
14-
3. Update this repo dependency in the projects where you need to use it with the command:
15-
`go get -u gitlab.com/docebo/architecture/operations-framework/feature-flags{@version}`
16-
17-
18-
## How to Delete a Feature Flag
19-
20-
1. Delete the `feature-flag` from the
21-
repository [feature-flags section](https://gitlab.com/docebo/architecture/operations-framework/feature-flags/-/feature_flags).
22-
2. Remove the `feature-flag` from the [feature flags constants list](./featureflags/feature_flags.go).
23-
3. Update this repo dependency in the projects where you need to use it with the command:
24-
`go get -u gitlab.com/docebo/architecture/operations-framework/feature-flags{@version}`
25-
26-
278
## Initialization
289

29-
- You must initialize the FeatureFlags client before using it.
10+
- The FeatureFlags client mu be initialized before it can be used.
3011
This is typically done in your application's initialization phase.
3112

3213
````go
33-
// Initialize the client with default configuration
34-
client.Init(YourProjectUrl, YourProjectId)
35-
36-
// Or, initialize it with custom configuration
37-
client.InitWithConfig(config.ClientConfig{
14+
// Initialize the ffclient keeping the default configurations
15+
ffclient.Init(YourProjectUrl, YourProjectId)
16+
17+
// Or, initialize it with custom configurations
18+
ffclient.InitWithConfig(config.ClientConfig{
19+
// Project URL and ProjectId can be found in your giltab repository [Deploy -> Feature flags] section
20+
// clicking on the 'Configure' button.
21+
ProjectUrl "https://foo.gitlab.com"
22+
ProjectId "1234"
3823
Logger: myCustomLogger,
3924
EnvironmentType: enums.Staging,
40-
EnvironmentTypeVariableName: "MY_ENV_TYPE",
25+
EnvironmentTypeVariableName: "MY_ENV_TYPE",
26+
ValidEnvironmentTypes []enums.EnvType
27+
AsyncInitialization false
4128
})
4229
````
4330

@@ -47,13 +34,13 @@ client.InitWithConfig(config.ClientConfig{
4734
- After initialization, you can obtain the client instance using the Get function:
4835

4936
````go
50-
client := client.Get()
37+
ffclient := ffclient.Get()
5138
````
5239

5340
- Check if a feature is enabled without User context:
5441

5542
````go
56-
isEnabled := client.IsFeatureEnabled(featureflags.SpecificUserFlag)
43+
isEnabled := ffclient.Get().IsFeatureEnabled(featureflags.SpecificUserFlag)
5744

5845
if isEnabled {
5946
// Feature is enabled, proceed with feature logic
@@ -65,7 +52,7 @@ if isEnabled {
6552
- Check if a feature is enabled for a specific User.
6653

6754
````go
68-
isEnabled := client.IsFeatureEnabledForUser(featureflags.SpecificUserFlag, "user@docebo.com")
55+
isEnabled := ffclient.Get().IsFeatureEnabledForUser(featureflags.SpecificUserFlag, "user@docebo.com")
6956

7057
if isEnabled {
7158
// Feature is enabled for the specific user, proceed with feature logic
@@ -78,5 +65,12 @@ if isEnabled {
7865
## Additional Notes
7966

8067
- This library tries by default to retrieve the environment type (Production, Staging, Development, etc.) from the
81-
[EnvTypeVariableName](./constants/constants.go) environment variable.
82-
You can configure the environment variable name and type by using the client.InitWithConfig function.
68+
[EnvTypeVariableName](./constants/constants.go) environment variable if the EnvType is not explicitly passed through
69+
in the configurations.
70+
You can configure the environment variable name and type by using the ffclient.InitWithConfig function.
71+
72+
````go
73+
// An example of how to set the default Environment variable in order to send the Gitlab environment property as Development
74+
os.Setenv(constants.EnvTypeVariableName, enums.Development.ToString())
75+
76+
````

client/config/clientConfig.go

Lines changed: 0 additions & 14 deletions
This file was deleted.

constants/constants.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package constants
22

3-
// EnvTypeVariableName is the default Environment Variable that the client.FeatureFlagsClient will search to
3+
// EnvTypeVariableName is the default Environment Variable that the ffclient.FeatureFlagsClient will search to
44
// set its environment type
55
const EnvTypeVariableName = "ENVIRONMENT_TYPE"

enums/envType.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
11
package enums
22

3-
// ValidEnvTypes holds an array of EnvTypes that are considered valid and can be used by the client.FeatureFlagsClient.
4-
var ValidEnvTypes = []EnvType{Production, Staging, Development, Client}
5-
63
type EnvType string
74

85
const (
96
Production EnvType = "production"
107
Staging EnvType = "staging"
118
Development EnvType = "development"
12-
Client EnvType = "client"
9+
Client EnvType = "ffclient"
1310

1411
// Undefined will be used when the EnvType is not correctly defined
1512
Undefined EnvType = "undefined"
1613
)
1714

18-
// ToString cast and returns the EnvType as string.
15+
// ToString returns the EnvType string value.
1916
func (e EnvType) ToString() string {
2017
return string(e)
2118
}

featureflags/feature_flags.go

Lines changed: 0 additions & 10 deletions
This file was deleted.

client/client.go renamed to ffclient/client.go

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
package client
1+
package ffclient
22

33
import (
4+
"github.com/pho3b/tiny-logger/logs"
5+
"github.com/pho3b/tiny-logger/logs/log_level"
46
"strings"
57

68
"github.com/Unleash/unleash-client-go/v4"
79
"github.com/Unleash/unleash-client-go/v4/context"
8-
"github.com/pho3b/gitlab-ff-wrapper/client/config"
910
pubconst "github.com/pho3b/gitlab-ff-wrapper/constants"
1011
"github.com/pho3b/gitlab-ff-wrapper/enums"
12+
"github.com/pho3b/gitlab-ff-wrapper/ffclient/ffconfig"
1113
"github.com/pho3b/gitlab-ff-wrapper/internal/constants"
1214
"github.com/pho3b/gitlab-ff-wrapper/internal/service"
13-
"github.com/pho3b/tiny-logger/logs"
14-
"github.com/pho3b/tiny-logger/logs/log_level"
1515
"github.com/pho3b/tiny-logger/shared"
1616
)
1717

@@ -20,7 +20,7 @@ var clientInstance *FeatureFlagsClient = nil
2020
type FeatureFlagsClient struct {
2121
// UnleashClientInterface is an interface that defines the methods used to interact with the Unleash feature flag service.
2222
unleashClient UnleashClientInterface
23-
// envType represents the environment type (e.g., Production, Staging, Development) that the client is configured for.
23+
// envType represents the environment type (e.g., Production, Staging, Development) that the ffclient is configured for.
2424
envType enums.EnvType
2525
// envTypeVariableName is the name of the environment variable that is used to determine the environment type.
2626
envTypeVariableName string
@@ -48,31 +48,27 @@ func (c *FeatureFlagsClient) IsFeatureEnabledForUser(featureName string, userId
4848
)
4949
}
5050

51-
// GetEnvironmentType returns the EnvironmentType that is currently set in the FeatureFlags client
51+
// GetEnvironmentType returns the EnvironmentType that is currently set in the FeatureFlags ffclient
5252
func (c *FeatureFlagsClient) GetEnvironmentType() enums.EnvType {
5353
return c.envType
5454
}
5555

5656
// Init initialized the FeatureFlagsClient instance with default configurations and binds it to the project
5757
// referred to the given 'projectId' and 'projectUrl'
5858
//
59-
// This function initializes the client with the default logger (Warn level),
59+
// This function initializes the ffclient with the default logger (Warn level),
6060
// and uses the default environment type variable name from constants.EnvTypeVariableName.
6161
func Init(projectUrl string, projectId string) {
62-
InitWithConfig(config.ClientConfig{ProjectId: projectId, ProjectUrl: projectUrl})
62+
InitWithConfig(ffconfig.ClientConfig{ProjectId: projectId, ProjectUrl: projectUrl})
6363
}
6464

65-
// InitWithConfig initializes the FeatureFlagsClient instance using the provided config.ClientConfig.
65+
// InitWithConfig initializes the FeatureFlagsClient instance using the provided ffconfig.ClientConfig.
6666
//
67-
// This function initializes the client with the provided logger and environment type variable name.
67+
// This function initializes the ffclient with the provided logger and environment type variable name.
6868
// If no logger is provided, a default logger with Warn level is created.
6969
// If no environment type variable name is provided, the default value from constants.EnvTypeVariableName is used.
70-
// The environment type is determined from the config or the environment variable.
71-
func InitWithConfig(config config.ClientConfig) {
72-
if clientInstance != nil {
73-
return
74-
}
75-
70+
// The environment type is determined from the ffconfig or the environment variable.
71+
func InitWithConfig(config ffconfig.ClientConfig) {
7672
var logger shared.LoggerInterface
7773
var envType enums.EnvType
7874
var envTypeVariableName, projectUrl, projectId string
@@ -84,27 +80,38 @@ func InitWithConfig(config config.ClientConfig) {
8480
AddDateTime(true)
8581
}
8682

87-
if envTypeVariableName = config.EnvironmentTypeVariableName; config.EnvironmentTypeVariableName == "" {
88-
envTypeVariableName = pubconst.EnvTypeVariableName
83+
if projectUrl = config.ProjectUrl; projectUrl == "" {
84+
logger.Error("ProjectUrl not specified, it cannot be empty")
85+
return
8986
}
9087

91-
envTypeService := service.NewEnvTypeService(logger)
92-
if envType = config.EnvironmentType; !envTypeService.IsEnvTypeValid(envType) {
93-
envType = envTypeService.GetEnvTypeFromEnvironment(envTypeVariableName)
88+
if projectId = config.ProjectId; projectId == "" {
89+
logger.Error("ProjectId not specified, it cannot be empty")
90+
return
9491
}
9592

96-
if projectUrl = config.ProjectUrl; projectUrl == "" {
97-
logger.Error("ProjectUrl not specified and cannot be empty")
93+
if clientInstance != nil {
94+
logger.Warn("FeatureFlagsClient already initialized")
9895
return
9996
}
10097

101-
if projectId = config.ProjectId; projectId == "" {
102-
logger.Error("ProjectId not specified and cannot be empty")
103-
return
98+
if envTypeVariableName = config.EnvironmentTypeVariableName; config.EnvironmentTypeVariableName == "" {
99+
envTypeVariableName = pubconst.EnvTypeVariableName
100+
}
101+
102+
envTypeService := service.NewEnvTypeService(logger)
103+
if len(config.ValidEnvironmentTypes) > 0 {
104+
for _, validEnvType := range config.ValidEnvironmentTypes {
105+
envTypeService.AddValidEnvType(validEnvType)
106+
}
107+
}
108+
109+
if envType = config.EnvironmentType; !envTypeService.IsEnvTypeValid(envType) {
110+
envType = envTypeService.GetEnvTypeFromEnvironment(envTypeVariableName)
104111
}
105112

106113
clientInstance = &FeatureFlagsClient{
107-
initUnleashClient(logger, envType, projectUrl, projectId),
114+
initUnleashClient(logger, envType, projectUrl, projectId, config.AsyncInitialization),
108115
envType,
109116
envTypeVariableName,
110117
logger,
@@ -116,16 +123,17 @@ func Get() *FeatureFlagsClient {
116123
return clientInstance
117124
}
118125

119-
// initUnleashClient initializes and returns a new Unleash client that will be configured to use the
126+
// initUnleashClient initializes and returns a new Unleash ffclient that will be configured to use the
120127
// provided logger and environment type.
121128
//
122-
// It also sets the necessary configuration options for the Unleash client.
123-
// If the client fails to initialize, an error message is logged and nil is returned.
129+
// It also sets the necessary configuration options for the Unleash ffclient.
130+
// If the ffclient fails to initialize, an error message is logged and nil is returned.
124131
func initUnleashClient(
125132
logger shared.LoggerInterface,
126133
envType enums.EnvType,
127134
projectUrl string,
128135
projectId string,
136+
asyncInitialization bool,
129137
) UnleashClientInterface {
130138
unleashClient, err := unleash.NewClient(
131139
unleash.WithUrl(projectUrl),
@@ -137,11 +145,13 @@ func initUnleashClient(
137145
)
138146

139147
if err != nil {
140-
logger.Error("Feature Flags client initialization error ", err.Error())
148+
logger.Error("Feature Flags ffclient initialization error ", err.Error())
141149
return nil
142150
}
143151

144-
unleashClient.WaitForReady()
152+
if !asyncInitialization {
153+
unleashClient.WaitForReady()
154+
}
145155

146156
return unleashClient
147157
}
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
package client
1+
package ffclient
22

33
import (
44
"github.com/Unleash/unleash-client-go/v4/api"
55
"github.com/h2non/gock"
6-
"github.com/pho3b/gitlab-ff-wrapper/client/config"
76
pubconst "github.com/pho3b/gitlab-ff-wrapper/constants"
87
"github.com/pho3b/gitlab-ff-wrapper/enums"
8+
"github.com/pho3b/gitlab-ff-wrapper/ffclient/ffconfig"
99
"github.com/pho3b/gitlab-ff-wrapper/tests"
1010
"github.com/pho3b/tiny-logger/logs"
1111
"github.com/stretchr/testify/assert"
@@ -112,7 +112,7 @@ func TestInitWithCustomConfigGivenEnvironmentType(t *testing.T) {
112112
gock.New(MockProjectUrl).Post("/client/register").Reply(200)
113113
gock.New(MockProjectUrl).Get("/client/features").Reply(200).JSON(api.FeatureResponse{})
114114

115-
InitWithConfig(config.ClientConfig{
115+
InitWithConfig(ffconfig.ClientConfig{
116116
EnvironmentType: "staging",
117117
EnvironmentTypeVariableName: "MY_CUSTOM_VARIABLE",
118118
ProjectUrl: MockProjectUrl,
@@ -138,7 +138,7 @@ func TestNotGivenEnvironmentType(t *testing.T) {
138138
gock.New(MockProjectUrl).Post("/client/register").Reply(200)
139139
gock.New(MockProjectUrl).Get("/client/features").Reply(200).JSON(api.FeatureResponse{})
140140

141-
InitWithConfig(config.ClientConfig{
141+
InitWithConfig(ffconfig.ClientConfig{
142142
EnvironmentTypeVariableName: "MY_CUSTOM_VARIABLE",
143143
ProjectUrl: MockProjectUrl,
144144
ProjectId: MockProjectId,
@@ -165,7 +165,7 @@ func TestNotGivenEnvironmentTypeAndSetCustomEnvVariable(t *testing.T) {
165165
gock.New(MockProjectUrl).Get("/client/features").Reply(200).JSON(api.FeatureResponse{})
166166
os.Setenv("MY_CUSTOM_VARIABLE", enums.Development.ToString())
167167

168-
InitWithConfig(config.ClientConfig{
168+
InitWithConfig(ffconfig.ClientConfig{
169169
EnvironmentTypeVariableName: "MY_CUSTOM_VARIABLE",
170170
ProjectUrl: MockProjectUrl,
171171
ProjectId: MockProjectId,
@@ -193,7 +193,7 @@ func TestNotGivenEnvironmentTypeAndSetClientEnvType(t *testing.T) {
193193
gock.New(MockProjectUrl).Post("/client/register").Reply(200)
194194
gock.New(MockProjectUrl).Get("/client/features").Reply(200).JSON(api.FeatureResponse{})
195195

196-
InitWithConfig(config.ClientConfig{
196+
InitWithConfig(ffconfig.ClientConfig{
197197
EnvironmentType: enums.Client,
198198
ProjectUrl: MockProjectUrl,
199199
ProjectId: MockProjectId,
@@ -223,7 +223,7 @@ func TestInitWithEmptyOrMissingProjectIDOrUrlType(t *testing.T) {
223223
Init("", MockProjectId)
224224
assert.Nil(t, clientInstance)
225225

226-
InitWithConfig(config.ClientConfig{
226+
InitWithConfig(ffconfig.ClientConfig{
227227
EnvironmentType: "",
228228
Logger: nil,
229229
EnvironmentTypeVariableName: "",
@@ -232,7 +232,7 @@ func TestInitWithEmptyOrMissingProjectIDOrUrlType(t *testing.T) {
232232
})
233233
assert.Nil(t, clientInstance)
234234

235-
InitWithConfig(config.ClientConfig{
235+
InitWithConfig(ffconfig.ClientConfig{
236236
EnvironmentType: "",
237237
Logger: nil,
238238
EnvironmentTypeVariableName: "",

0 commit comments

Comments
 (0)