Skip to content

Commit

Permalink
feat: Golang Local Evaluation V2 (#18)
Browse files Browse the repository at this point in the history
* feat: update to local evaluation v2

* fix: build action

* fix: formatting

* fix: lint

* test: add local client tests

* feat: add details to assignment event
  • Loading branch information
bgiori authored Dec 21, 2023
1 parent 98a2931 commit f0d4504
Show file tree
Hide file tree
Showing 37 changed files with 2,554 additions and 1,038 deletions.
34 changes: 7 additions & 27 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ defaults:

jobs:
lint:
name: Lint files
name: Lint
runs-on: 'ubuntu-latest'
steps:
- uses: actions/checkout@v3
Expand All @@ -24,36 +24,16 @@ jobs:
uses: golangci/golangci-lint-action@v3
with:
version: latest

build:
name: Build binary
test:
runs-on: 'ubuntu-latest'
strategy:
matrix:
goosarch:
- 'darwin/amd64'
- 'darwin/arm64'
- 'linux/amd64'
- 'linux/arm'
- 'linux/arm64'

steps:
- name: Checkout code
- name: Checkout
uses: actions/checkout@v3
- uses: actions/setup-go@v3
- name: Setup
uses: actions/setup-go@v3
with:
go-version: '1.17'
check-latest: true
- name: Get OS and arch info
run: |
GOOSARCH=${{matrix.goosarch}}
GOOS=${GOOSARCH%/*}
GOARCH=${GOOSARCH#*/}
BINARY_NAME=${{github.repository}}-$GOOS-$GOARCH
echo "BINARY_NAME=$BINARY_NAME" >> $GITHUB_ENV
echo "GOOS=$GOOS" >> $GITHUB_ENV
echo "GOARCH=$GOARCH" >> $GITHUB_ENV
- name: Build
- name: Test
run: |
cd pkg/experiment
go build -o "$BINARY_NAME" -v
go test ./...
45 changes: 5 additions & 40 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
xpmt: clean
CGO_ENABLED=1 go build -o xpmt cmd/xpmt/main.go
go build -o xpmt cmd/xpmt/main.go

docker:
docker build -t experiment . --progress plain
docker run -it --rm --name experiment-run experiment

release: copy-lib-release xpmt

debug: copy-lib-debug xpmt

clean:
rm -f xpmt

Expand All @@ -19,44 +15,13 @@ darwin: darwin-amd64 darwin-arm64
linux: linux-amd64 linux-arm64

darwin-amd64:
CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 go build -o cmd/xpmt/bin/darwin/amd64/xpmt cmd/xpmt/main.go
go build -o cmd/xpmt/bin/darwin/amd64/xpmt cmd/xpmt/main.go

darwin-arm64:
CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 go build -o cmd/xpmt/bin/darwin/arm64/xpmt cmd/xpmt/main.go
go build -o cmd/xpmt/bin/darwin/arm64/xpmt cmd/xpmt/main.go

linux-amd64:
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -o cmd/xpmt/bin/linux/amd64/xpmt cmd/xpmt/main.go
go build -o cmd/xpmt/bin/linux/amd64/xpmt cmd/xpmt/main.go

linux-arm64:
CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build -o cmd/xpmt/bin/linux/arm64/xpmt cmd/xpmt/main.go

# expects experiment-evaluation lives in same directory and experiment-go-server
copy-lib-debug:
# macosX64
cp ../experiment-evaluation/evaluation-interop/build/bin/macosX64/debugStatic/libevaluation_interop_api.h internal/evaluation/lib/macosX64/
cp ../experiment-evaluation/evaluation-interop/build/bin/macosX64/debugStatic/libevaluation_interop.a internal/evaluation/lib/macosX64/
# macosArm64
cp ../experiment-evaluation/evaluation-interop/build/bin/macosArm64/debugStatic/libevaluation_interop_api.h internal/evaluation/lib/macosArm64/
cp ../experiment-evaluation/evaluation-interop/build/bin/macosArm64/debugStatic/libevaluation_interop.a internal/evaluation/lib/macosArm64/
# linuxX64
cp ../experiment-evaluation/evaluation-interop/build/bin/linuxX64/debugStatic/libevaluation_interop_api.h internal/evaluation/lib/linuxX64/
cp ../experiment-evaluation/evaluation-interop/build/bin/linuxX64/debugStatic/libevaluation_interop.a internal/evaluation/lib/linuxX64/
# linuxArm64
cp ../experiment-evaluation/evaluation-interop/build/bin/linuxArm64/debugStatic/libevaluation_interop_api.h internal/evaluation/lib/linuxArm64/
cp ../experiment-evaluation/evaluation-interop/build/bin/linuxArm64/debugStatic/libevaluation_interop.a internal/evaluation/lib/linuxArm64/


# expects experiment-evaluation lives in same directory and experiment-go-server
copy-lib-release:
# macosX64
cp ../experiment-evaluation/evaluation-interop/build/bin/macosX64/releaseStatic/libevaluation_interop_api.h internal/evaluation/lib/macosX64/
cp ../experiment-evaluation/evaluation-interop/build/bin/macosX64/releaseStatic/libevaluation_interop.a internal/evaluation/lib/macosX64/
# macosArm64
cp ../experiment-evaluation/evaluation-interop/build/bin/macosArm64/releaseStatic/libevaluation_interop_api.h internal/evaluation/lib/macosArm64/
cp ../experiment-evaluation/evaluation-interop/build/bin/macosArm64/releaseStatic/libevaluation_interop.a internal/evaluation/lib/macosArm64/
# linuxX64
cp ../experiment-evaluation/evaluation-interop/build/bin/linuxX64/releaseStatic/libevaluation_interop_api.h internal/evaluation/lib/linuxX64/
cp ../experiment-evaluation/evaluation-interop/build/bin/linuxX64/releaseStatic/libevaluation_interop.a internal/evaluation/lib/linuxX64/
# linuxArm64
cp ../experiment-evaluation/evaluation-interop/build/bin/linuxArm64/releaseStatic/libevaluation_interop_api.h internal/evaluation/lib/linuxArm64/
cp ../experiment-evaluation/evaluation-interop/build/bin/linuxArm64/releaseStatic/libevaluation_interop.a internal/evaluation/lib/linuxArm64/
go build -o cmd/xpmt/bin/linux/arm64/xpmt cmd/xpmt/main.go
9 changes: 3 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,14 @@ The `xpmt` command-line interface tool allows you to make Experiment SDK calls f

### Build

**Makefile currently only builds for macos (amd64 & x64), add a line to the `Makefile` to support your OS and Architecture.**

```
make xpmt
```

### Run

!!!warning Setting the deployment key
All examples below assume the `EXPERIMENT_KEY` environment variable has been set. Alternatively, use the `-k`
flag to set the key in the command.
> **Warning** All examples below assume the `EXPERIMENT_KEY` environment variable has been set. Alternatively, use the `-k`
flag to set the key in the command.

#### Subcommands
* `fetch`: fetch variants for a user from the server
Expand Down Expand Up @@ -112,4 +109,4 @@ Fetch variants for a user given an experiment user JSON object
./xpmt evaluate -u '{"user_id":"[email protected]","user_properties":{"premium":true}}'
```

> Note: must use single quotes around JSON object string
> Note: must use single quotes around JSON object string
56 changes: 3 additions & 53 deletions cmd/xpmt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"flag"
"fmt"
"os"
"strconv"
"time"

"github.com/amplitude/experiment-go-server/pkg/experiment"
Expand All @@ -19,7 +18,6 @@ func main() {
fmt.Printf("Available commands:\n" +
" fetch\n" +
" flags\n" +
" rules\n" +
" evaluate\n")
return
}
Expand All @@ -28,8 +26,6 @@ func main() {
fetch()
case "flags":
flags()
case "rules":
rules()
case "evaluate":
evaluate()
default:
Expand Down Expand Up @@ -141,59 +137,13 @@ func flags() {
}

client := local.Initialize(*apiKey, config)
flags, err := client.Flags()
flags, err := client.FlagsV2()
if err != nil {
fmt.Printf("error: %v\n", err)
os.Exit(1)
return
}
println(*flags)
}

func rules() {
rulesCmd := flag.NewFlagSet("rules", flag.ExitOnError)
apiKey := rulesCmd.String("k", "", "Api key for authorization, or use EXPERIMENT_KEY env var.")
url := rulesCmd.String("url", "", "The server url to use to fetch variants from.")
debug := rulesCmd.Bool("debug", false, "Log additional debug output to std out.")
staging := rulesCmd.Bool("staging", false, "Use skylab staging environment.")
_ = rulesCmd.Parse(os.Args[2:])

if len(os.Args) == 3 && os.Args[1] == "--help" {
rulesCmd.Usage()
return
}

if apiKey == nil || *apiKey == "" {
envKey := os.Getenv("EXPERIMENT_KEY")
if envKey == "" {
rulesCmd.Usage()
fmt.Printf("error: must set experiment api key using cli flag or EXPERIMENT_KEY env var\n")
os.Exit(1)
return
}
apiKey = &envKey
}

config := &local.Config{
Debug: *debug,
}

if *url != "" {
config.ServerUrl = *url
} else if *staging {
config.ServerUrl = "https://skylab-api.staging.amplitude.com"
}

client := local.Initialize(*apiKey, config)
variants, err := client.Rules()
if err != nil {
fmt.Printf("error: %v\n", err)
os.Exit(1)
return
}
b, _ := json.Marshal(variants)
st, _ := strconv.Unquote(string(b))
fmt.Println(st)
println(flags)
}

func evaluate() {
Expand Down Expand Up @@ -270,7 +220,7 @@ func evaluate() {
// fmt.Println(duration)
//}

variants, err := client.Evaluate(user, nil)
variants, err := client.EvaluateV2(user, nil)
if err != nil {
fmt.Printf("error: %v\n", err)
os.Exit(1)
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ module github.com/amplitude/experiment-go-server

go 1.12

require github.com/spaolacci/murmur3 v1.1.0

require github.com/amplitude/analytics-go v1.0.1
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
Expand Down
61 changes: 61 additions & 0 deletions internal/evaluation/context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package evaluation

import "github.com/amplitude/experiment-go-server/pkg/experiment"

func UserToContext(user *experiment.User) map[string]interface{} {
if user == nil {
return nil
}
context := make(map[string]interface{})
userMap := make(map[string]interface{})
if len(user.UserId) != 0 {
userMap["user_id"] = user.UserId
}
if len(user.DeviceId) != 0 {
userMap["device_id"] = user.DeviceId
}
if len(user.Country) != 0 {
userMap["country"] = user.Country
}
if len(user.Region) != 0 {
userMap["region"] = user.Region
}
if len(user.Dma) != 0 {
userMap["dma"] = user.Dma
}
if len(user.City) != 0 {
userMap["city"] = user.City
}
if len(user.Language) != 0 {
userMap["language"] = user.Language
}
if len(user.Platform) != 0 {
userMap["platform"] = user.Platform
}
if len(user.Version) != 0 {
userMap["version"] = user.Version
}
if len(user.Os) != 0 {
userMap["os"] = user.Os
}
if len(user.DeviceManufacturer) != 0 {
userMap["device_manufacturer"] = user.DeviceManufacturer
}
if len(user.DeviceBrand) != 0 {
userMap["device_brand"] = user.DeviceBrand
}
if len(user.DeviceModel) != 0 {
userMap["device_model"] = user.DeviceModel
}
if len(user.Carrier) != 0 {
userMap["carrier"] = user.Carrier
}
if len(user.Library) != 0 {
userMap["library"] = user.Library
}
if len(user.UserProperties) != 0 {
userMap["user_properties"] = user.UserProperties
}
context["user"] = userMap
return context
}
Loading

0 comments on commit f0d4504

Please sign in to comment.