Skip to content

Commit 42d6d54

Browse files
author
Mike Davis
authored
Add simple CLI support. (#41)
1 parent 6c4ae6e commit 42d6d54

File tree

8 files changed

+255
-12
lines changed

8 files changed

+255
-12
lines changed

README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,55 @@
11
# Optimizely Go SDK
2+
3+
## Command line interface
4+
A CLI has been provided to illustrate the functionality of the SDK. Simply run `go-sdk` for help.
5+
```$sh
6+
go-sdk provides cli access to your Optimizely fullstack project
7+
8+
Usage:
9+
go-sdk [command]
10+
11+
Available Commands:
12+
help Help about any command
13+
is_feature_enabled Is feature enabled?
14+
15+
Flags:
16+
-h, --help help for go-sdk
17+
-s, --sdkKey string Optimizely project SDK key
18+
19+
Use "go-sdk [command] --help" for more information about a command.
20+
```
21+
22+
Each supported SDK API method is it's own [cobra](https://github.com/spf13/cobra) command and requires the
23+
input of an `--sdkKey`.
24+
25+
### Installation
26+
Install the CLI from github:
27+
28+
```$sh
29+
go install github.com/optimizely/go-sdk
30+
```
31+
32+
Install the CLI from source:
33+
```$sh
34+
go get github.com/optimizely/go-sdk
35+
cd $GOPATH/src/github.com/optimizely/go-sdk
36+
go install
37+
```
38+
39+
### Commands
40+
41+
#### is_feature_enabled
42+
```
43+
Determines if a feature is enabled
44+
45+
Usage:
46+
go-sdk is_feature_enabled [flags]
47+
48+
Flags:
49+
-f, --featureKey string feature key to enable
50+
-h, --help help for is_feature_enabled
51+
-u, --userId string user id
52+
53+
Global Flags:
54+
-s, --sdkKey string Optimizely project SDK key
55+
```

cmd/is_feature_enabled.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/****************************************************************************
2+
* Copyright 2019, Optimizely, Inc. and contributors *
3+
* *
4+
* Licensed under the Apache License, Version 2.0 (the "License"); *
5+
* you may not use this file except in compliance with the License. *
6+
* You may obtain a copy of the License at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* Unless required by applicable law or agreed to in writing, software *
11+
* distributed under the License is distributed on an "AS IS" BASIS, *
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13+
* See the License for the specific language governing permissions and *
14+
* limitations under the License. *
15+
***************************************************************************/
16+
17+
package cmd
18+
19+
import (
20+
"fmt"
21+
"github.com/optimizely/go-sdk/optimizely/client"
22+
"github.com/optimizely/go-sdk/optimizely/entities"
23+
"github.com/spf13/cobra"
24+
)
25+
26+
var (
27+
userId string
28+
featurekKey string
29+
)
30+
31+
var isFeatureEnabledCmd = &cobra.Command{
32+
Use: "is_feature_enabled",
33+
Short: "Is feature enabled?",
34+
Long: `Determines if a feature is enabled`,
35+
Run: func(cmd *cobra.Command, args []string) {
36+
optimizelyFactory := &client.OptimizelyFactory{
37+
SDKKey: sdkKey,
38+
}
39+
40+
client, err := optimizelyFactory.Client()
41+
42+
if err != nil {
43+
fmt.Printf("Error instantiating client: %s\n", err)
44+
return
45+
}
46+
47+
user := entities.UserContext{
48+
ID: userId,
49+
Attributes: entities.UserAttributes{},
50+
}
51+
52+
enabled, _ := client.IsFeatureEnabled(featurekKey, user)
53+
fmt.Printf("Is feature \"%s\" enabled for \"%s\"? %t\n", featurekKey, userId, enabled)
54+
},
55+
}
56+
57+
func init() {
58+
rootCmd.AddCommand(isFeatureEnabledCmd)
59+
isFeatureEnabledCmd.Flags().StringVarP(&userId, "userId", "u", "", "user id")
60+
isFeatureEnabledCmd.MarkFlagRequired("userId")
61+
isFeatureEnabledCmd.Flags().StringVarP(&featurekKey, "featureKey", "f", "", "feature key to enable")
62+
isFeatureEnabledCmd.MarkFlagRequired("featureKey")
63+
}

cmd/root.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/****************************************************************************
2+
* Copyright 2019, Optimizely, Inc. and contributors *
3+
* *
4+
* Licensed under the Apache License, Version 2.0 (the "License"); *
5+
* you may not use this file except in compliance with the License. *
6+
* You may obtain a copy of the License at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* Unless required by applicable law or agreed to in writing, software *
11+
* distributed under the License is distributed on an "AS IS" BASIS, *
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13+
* See the License for the specific language governing permissions and *
14+
* limitations under the License. *
15+
***************************************************************************/
16+
17+
package cmd
18+
19+
import (
20+
"fmt"
21+
"os"
22+
23+
"github.com/spf13/cobra"
24+
)
25+
26+
var sdkKey string
27+
28+
var rootCmd = &cobra.Command{
29+
Use: "go-sdk",
30+
Short: "go-sdk provides cli access to your Optimizely fullstack project",
31+
}
32+
33+
func Execute() {
34+
if err := rootCmd.Execute(); err != nil {
35+
fmt.Println(err)
36+
os.Exit(1)
37+
}
38+
}
39+
40+
func init() {
41+
rootCmd.PersistentFlags().StringVarP(&sdkKey, "sdkKey", "s", "", "Optimizely project SDK key")
42+
rootCmd.MarkPersistentFlagRequired("sdkKey")
43+
}

examples/main.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ func main() {
1414
optimizelyFactory := &client.OptimizelyFactory{
1515
SDKKey: "ABC",
1616
}
17-
client := optimizelyFactory.Client()
17+
client, err := optimizelyFactory.Client()
18+
19+
if err != nil {
20+
fmt.Printf("Error instantiating client: %s", err)
21+
return
22+
}
1823

1924
user := entities.UserContext{
2025
ID: "mike ng",

main.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/****************************************************************************
2+
* Copyright 2019, Optimizely, Inc. and contributors *
3+
* *
4+
* Licensed under the Apache License, Version 2.0 (the "License"); *
5+
* you may not use this file except in compliance with the License. *
6+
* You may obtain a copy of the License at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* Unless required by applicable law or agreed to in writing, software *
11+
* distributed under the License is distributed on an "AS IS" BASIS, *
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13+
* See the License for the specific language governing permissions and *
14+
* limitations under the License. *
15+
***************************************************************************/
16+
17+
package main
18+
19+
import "github.com/optimizely/go-sdk/cmd"
20+
21+
func main() {
22+
cmd.Execute()
23+
}

optimizely/client/factory.go

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@
1717
package client
1818

1919
import (
20+
2021
"github.com/optimizely/go-sdk/optimizely"
22+
"fmt"
2123
"github.com/optimizely/go-sdk/optimizely/config"
22-
"github.com/optimizely/go-sdk/optimizely/config/datafileProjectConfig"
2324
"github.com/optimizely/go-sdk/optimizely/decision"
2425
)
2526

@@ -30,16 +31,27 @@ type OptimizelyFactory struct {
3031
}
3132

3233
// Client returns a client initialized with the defaults
33-
func (f OptimizelyFactory) Client() OptimizelyClient {
34-
var projectConfig optimizely.ProjectConfig
34+
func (f OptimizelyFactory) Client() (*OptimizelyClient, error) {
3535
var configManager optimizely.ProjectConfigManager
36-
if f.Datafile != nil {
37-
projectConfig = datafileProjectConfig.NewDatafileProjectConfig(f.Datafile)
3836

39-
if f.SDKKey == "" {
40-
staticConfigManager := config.NewStaticProjectConfigManager(projectConfig)
41-
configManager = staticConfigManager
37+
if f.SDKKey != "" {
38+
url := fmt.Sprintf("https://cdn.optimizely.com/datafiles/%s.json", f.SDKKey)
39+
staticConfigManager, err := config.NewStaticProjectConfigManagerFromUrl(url)
40+
41+
if err != nil {
42+
return nil, err
4243
}
44+
45+
configManager = staticConfigManager
46+
47+
} else if f.Datafile != nil {
48+
staticConfigManager, err := config.NewStaticProjectConfigManagerFromPayload(f.Datafile)
49+
50+
if err != nil {
51+
return nil, err
52+
}
53+
54+
configManager = staticConfigManager
4355
}
4456

4557
decisionService := decision.NewCompositeService()
@@ -48,5 +60,5 @@ func (f OptimizelyFactory) Client() OptimizelyClient {
4860
configManager: configManager,
4961
isValid: true,
5062
}
51-
return client
63+
return &client, nil
5264
}

optimizely/config/datafileProjectConfig/config.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,11 @@ func (c DatafileProjectConfig) GetBotFiltering() bool {
6868
}
6969

7070
// NewDatafileProjectConfig initializes a new datafile from a json byte array using the default JSON datafile parser
71-
func NewDatafileProjectConfig(jsonDatafile []byte) *DatafileProjectConfig {
71+
func NewDatafileProjectConfig(jsonDatafile []byte) (*DatafileProjectConfig, error) {
7272
datafile, err := Parse(jsonDatafile)
7373
if err != nil {
7474
logger.Error("Error parsing datafile.", err)
75+
return nil, err
7576
}
7677

7778
experiments, experimentKeyMap := mappers.MapExperiments(datafile.Experiments)
@@ -82,7 +83,7 @@ func NewDatafileProjectConfig(jsonDatafile []byte) *DatafileProjectConfig {
8283
}
8384

8485
logger.Info("Datafile is valid.")
85-
return config
86+
return config, nil
8687
}
8788

8889
// GetEventByKey returns the event with the given key

optimizely/config/static_manager.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,14 @@
1717
package config
1818

1919
import (
20+
"bytes"
21+
"errors"
22+
"io"
23+
"net/http"
2024
"sync"
2125

2226
"github.com/optimizely/go-sdk/optimizely"
27+
"github.com/optimizely/go-sdk/optimizely/config/datafileProjectConfig"
2328
)
2429

2530
// StaticProjectConfigManager maintains a static copy of the project config
@@ -28,6 +33,43 @@ type StaticProjectConfigManager struct {
2833
configLock sync.Mutex
2934
}
3035

36+
func NewStaticProjectConfigManagerFromUrl(URL string) (*StaticProjectConfigManager, error) {
37+
downloadFile := func(URL string) ([]byte, error) {
38+
response, err := http.Get(URL)
39+
if err != nil {
40+
return nil, err
41+
}
42+
defer response.Body.Close()
43+
if response.StatusCode != http.StatusOK {
44+
return nil, errors.New(response.Status)
45+
}
46+
var data bytes.Buffer
47+
_, err = io.Copy(&data, response.Body)
48+
if err != nil {
49+
return nil, err
50+
}
51+
return data.Bytes(), nil
52+
}
53+
54+
body, err := downloadFile(URL)
55+
56+
if err != nil {
57+
return nil, err
58+
}
59+
60+
return NewStaticProjectConfigManagerFromPayload(body)
61+
}
62+
63+
func NewStaticProjectConfigManagerFromPayload(payload []byte) (*StaticProjectConfigManager, error) {
64+
projectConfig, err := datafileProjectConfig.NewDatafileProjectConfig(payload)
65+
66+
if err != nil {
67+
return nil, err
68+
}
69+
70+
return NewStaticProjectConfigManager(projectConfig), nil
71+
}
72+
3173
// NewStaticProjectConfigManager creates a new instance of the manager with the given project config
3274
func NewStaticProjectConfigManager(config optimizely.ProjectConfig) *StaticProjectConfigManager {
3375
return &StaticProjectConfigManager{

0 commit comments

Comments
 (0)