Skip to content

Commit 00feae6

Browse files
authored
feat: flagsmith eval (#53)
beep boop
1 parent 38eaf8c commit 00feae6

12 files changed

Lines changed: 1428 additions & 71 deletions

File tree

README.md

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ flagsmith flag list # list the flags in the current environment
7272
- `flagsmith environment list|get|create|update|delete|clone` (alias `env`) — manage environments (by name or API key).
7373
- `flagsmith environment key list|create|delete <environment>` — manage server-side SDK keys.
7474
- `flagsmith environment document [environment]` — output the environment document (local-evaluation JSON).
75+
- `flagsmith evaluate [feature]` (alias `eval`) — the flags an SDK resolves for the current environment (`--identity`, `--trait key=value`, `--persist`); `--js` writes the state a frontend SDK hydrates from, `--test` fails when a named flag is disabled.
7576
- `flagsmith config` — show the resolved context and where each value comes from.
7677
- `flagsmith login` / `logout` — browser OAuth (PKCE, loopback); also `auth login`/`auth logout`.
7778
- `flagsmith auth status` — identity, organisations, credential source, token expiry.
@@ -83,18 +84,3 @@ flagsmith flag list # list the flags in the current environment
8384
- `--json` (or `FLAGSMITH_JSON_OUTPUT`) for machine-readable output; `--jq <expr>` to filter it.
8485
- Static credentials: `FLAGSMITH_API_KEY` (Admin API), `FLAGSMITH_ENVIRONMENT_KEY` (SDK).
8586
- Self-hosted: `--api-url` or `FLAGSMITH_API_URL`.
86-
87-
## Design
88-
89-
[Installation](docs/design/01-installation.md) ·
90-
[Output & interactivity](docs/design/02-output-and-interactivity.md) ·
91-
[Authentication](docs/design/03-authentication.md) ·
92-
[Project config](docs/design/04-project-config.md) ·
93-
[CRUD conventions](docs/design/05-crud.md) ·
94-
[API](docs/design/06-api.md) ·
95-
[Flags](docs/design/07-flags.md) ·
96-
[Segments](docs/design/08-segments.md) ·
97-
[Features](docs/design/09-features.md) ·
98-
[Projects & organisations](docs/design/10-projects-organisations.md) ·
99-
[Environments](docs/design/11-environments.md) ·
100-
[Evaluate](docs/design/12-evaluate.md)

go.mod

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,22 @@ module github.com/Flagsmith/flagsmith-cli/v2
33
go 1.26
44

55
require (
6+
github.com/Flagsmith/flagsmith-go-client/v5 v5.1.0
67
github.com/charmbracelet/huh v1.0.0
78
github.com/fatih/color v1.19.0
89
github.com/itchyny/gojq v0.12.19
910
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
1011
github.com/spf13/cobra v1.10.2
1112
github.com/spf13/pflag v1.0.9
1213
github.com/zalando/go-keyring v0.2.8
13-
golang.org/x/sync v0.15.0
14+
golang.org/x/sync v0.16.0
1415
golang.org/x/term v0.45.0
1516
)
1617

1718
require (
1819
github.com/atotto/clipboard v0.1.4 // indirect
1920
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
21+
github.com/blang/semver/v4 v4.0.0 // indirect
2022
github.com/catppuccin/go v0.3.0 // indirect
2123
github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 // indirect
2224
github.com/charmbracelet/bubbletea v1.3.6 // indirect
@@ -31,9 +33,11 @@ require (
3133
github.com/danieljoos/wincred v1.2.3 // indirect
3234
github.com/dustin/go-humanize v1.0.1 // indirect
3335
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
36+
github.com/go-resty/resty/v2 v2.17.2 // indirect
3437
github.com/godbus/dbus/v5 v5.2.2 // indirect
3538
github.com/inconshreveable/mousetrap v1.1.0 // indirect
3639
github.com/itchyny/timefmt-go v0.1.8 // indirect
40+
github.com/itlightning/dateparse v0.2.1 // indirect
3741
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
3842
github.com/mattn/go-colorable v0.1.14 // indirect
3943
github.com/mattn/go-isatty v0.0.20 // indirect
@@ -43,8 +47,10 @@ require (
4347
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
4448
github.com/muesli/cancelreader v0.2.2 // indirect
4549
github.com/muesli/termenv v0.16.0 // indirect
50+
github.com/ohler55/ojg v1.28.1 // indirect
4651
github.com/rivo/uniseg v0.4.7 // indirect
4752
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
53+
golang.org/x/net v0.43.0 // indirect
4854
golang.org/x/sys v0.47.0 // indirect
49-
golang.org/x/text v0.23.0 // indirect
55+
golang.org/x/text v0.28.0 // indirect
5056
)

go.sum

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
github.com/Flagsmith/flagsmith-go-client/v5 v5.1.0 h1:/1KMxWHfzo8I7FnZ0mnMw+ICM4HVZvCEYTJ4idM2VEU=
2+
github.com/Flagsmith/flagsmith-go-client/v5 v5.1.0/go.mod h1:CjTs0XAIJXG+08lf4h51W9cjvrNaK92TLVYtjPrnI3w=
13
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
24
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
35
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
@@ -6,6 +8,8 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE
68
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
79
github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3vj1nolY=
810
github.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E=
11+
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
12+
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
913
github.com/catppuccin/go v0.3.0 h1:d+0/YicIq+hSTo5oPuRi5kOpqkVA5tAsU6dNhvRu+aY=
1014
github.com/catppuccin/go v0.3.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
1115
github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 h1:JFgG/xnwFfbezlUnFMJy0nusZvytYysV4SCS2cYbvws=
@@ -53,14 +57,20 @@ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6
5357
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
5458
github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w=
5559
github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE=
60+
github.com/go-resty/resty/v2 v2.17.2 h1:FQW5oHYcIlkCNrMD2lloGScxcHJ0gkjshV3qcQAyHQk=
61+
github.com/go-resty/resty/v2 v2.17.2/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA=
5662
github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ=
5763
github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
64+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
65+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
5866
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
5967
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
6068
github.com/itchyny/gojq v0.12.19 h1:ttXA0XCLEMoaLOz5lSeFOZ6u6Q3QxmG46vfgI4O0DEs=
6169
github.com/itchyny/gojq v0.12.19/go.mod h1:5galtVPDywX8SPSOrqjGxkBeDhSxEW1gSxoy7tn1iZY=
6270
github.com/itchyny/timefmt-go v0.1.8 h1:1YEo1JvfXeAHKdjelbYr/uCuhkybaHCeTkH8Bo791OI=
6371
github.com/itchyny/timefmt-go v0.1.8/go.mod h1:5E46Q+zj7vbTgWY8o5YkMeYb4I6GeWLFnetPy5oBrAI=
72+
github.com/itlightning/dateparse v0.2.1 h1:AB0NJTyI0HYcerEUMovKZOiQVBg1mBPxgAnWQwzLP6g=
73+
github.com/itlightning/dateparse v0.2.1/go.mod h1:xHlmL8lT0L9JIBlaKotRwsoDYpKJskXpiU9ZwbbSkNA=
6474
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
6575
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
6676
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
@@ -79,6 +89,8 @@ github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELU
7989
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
8090
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
8191
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
92+
github.com/ohler55/ojg v1.28.1 h1:Xy93DelhLSZNeWv8GPKtP6qMqkUlZlAxBP/AQcC5RfY=
93+
github.com/ohler55/ojg v1.28.1/go.mod h1:/Y5dGWkekv9ocnUixuETqiL58f+5pAsUfg5P8e7Pa2o=
8294
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
8395
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
8496
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -94,24 +106,30 @@ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
94106
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
95107
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
96108
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
109+
github.com/tailscale/hujson v0.0.0-20250605163823-992244df8c5a h1:a6TNDN9CgG+cYjaeN8l2mc4kSz2iMiCDQxPEyltUV/I=
110+
github.com/tailscale/hujson v0.0.0-20250605163823-992244df8c5a/go.mod h1:EbW0wDK/qEUYI0A5bqq0C2kF8JTQwWONmGDBbzsxxHo=
97111
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
98112
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
99113
github.com/zalando/go-keyring v0.2.8 h1:6sD/Ucpl7jNq10rM2pgqTs0sZ9V3qMrqfIIy5YPccHs=
100114
github.com/zalando/go-keyring v0.2.8/go.mod h1:tsMo+VpRq5NGyKfxoBVjCuMrG47yj8cmakZDO5QGii0=
101115
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
102116
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
103117
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
104-
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
105-
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
118+
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
119+
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
120+
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
121+
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
106122
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
107123
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
108124
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
109125
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
110126
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
111127
golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
112128
golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
113-
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
114-
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
129+
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
130+
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
131+
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
132+
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
115133
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
116134
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
117135
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/cmd/api.go

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"bytes"
55
"context"
66
"encoding/json"
7-
"errors"
87
"fmt"
98
"io"
109
"net/http"
@@ -97,7 +96,7 @@ func runAPI(cmd *cobra.Command, args []string) error {
9796
// apiTarget resolves the base URL and the auth applier for the chosen surface.
9897
func apiTarget(cmd *cobra.Command, pc *projectContext) (string, func(*http.Request), error) {
9998
if apiSDKFlag {
100-
key, err := sdkEnvironmentKey(pc)
99+
key, err := sdkEnvironmentKey(cmd, pc)
101100
if err != nil {
102101
return "", nil, err
103102
}
@@ -112,20 +111,6 @@ func apiTarget(cmd *cobra.Command, pc *projectContext) (string, func(*http.Reque
112111
return apiURL, cred.auth.Apply, nil
113112
}
114113

115-
// sdkEnvironmentKey returns the client- or server-side key for --sdk calls,
116-
// taken verbatim from the environment context (no Admin name resolution).
117-
func sdkEnvironmentKey(pc *projectContext) (string, error) {
118-
sdkURL, _ := pc.SDKAPIURL.Value.(string)
119-
if _, v := envCredential(envEnvironmentKey, sdkURL, defaultSDKAPIURL); v != "" {
120-
return v, nil
121-
}
122-
if k, ok := pc.Environment.Value.(string); ok && k != "" {
123-
return k, nil
124-
}
125-
return "", withHint(errors.New("no environment key"),
126-
"Set FLAGSMITH_ENVIRONMENT_KEY, or pass -e.")
127-
}
128-
129114
// apiRequestBody builds the request body (or query params) and resolves the
130115
// method: explicit --method, else POST when a body/field is present, else GET.
131116
func apiRequestBody(cmd *cobra.Command) (body []byte, contentType string, query url.Values, method string, err error) {

0 commit comments

Comments
 (0)