Skip to content

Commit 61a9d3a

Browse files
committed
merge prerelease branch
1 parent a18a714 commit 61a9d3a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+2048
-1436
lines changed

.golangci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ linters-settings:
4646
local-prefixes: github.com/launchdarkly
4747

4848
issues:
49+
exclude-rules:
50+
- path: ldvalue/optional_.*.go
51+
linters:
52+
- dupl # This linter would produce false positives due to necessary boilerplate code in ldvalue/optional_*.go
4953
exclude-use-default: false
5054
max-same-issues: 1000
5155
max-per-linter: 1000

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ require (
66
github.com/launchdarkly/go-jsonstream/v3 v3.0.0
77
github.com/launchdarkly/go-test-helpers/v3 v3.0.1
88
github.com/mailru/easyjson v0.7.6
9-
github.com/stretchr/testify v1.6.1
9+
github.com/stretchr/testify v1.7.0
1010
golang.org/x/exp v0.0.0-20220823124025-807a23277127
1111
)
1212

1313
require (
1414
github.com/davecgh/go-spew v1.1.1 // indirect
1515
github.com/josharian/intern v1.0.0 // indirect
16+
github.com/kr/text v0.2.0 // indirect
1617
github.com/pmezard/go-difflib v1.0.0 // indirect
18+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
1719
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
1820
)

go.sum

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1+
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
12
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
23
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
34
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
45
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
56
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
7+
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
8+
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
9+
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
10+
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
11+
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
12+
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
613
github.com/launchdarkly/go-jsonstream/v3 v3.0.0 h1:qJF/WI09EUJ7kSpmP5d1Rhc81NQdYUhP17McKfUq17E=
714
github.com/launchdarkly/go-jsonstream/v3 v3.0.0/go.mod h1:/1Gyml6fnD309JOvunOSfyysWbZ/ZzcA120gF/cQtC4=
815
github.com/launchdarkly/go-test-helpers/v3 v3.0.1 h1:Z4lUVrh7+hIvL47KVjEBE/owbqqjKUEYTp4aBX/5OZM=
@@ -12,11 +19,12 @@ github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
1219
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
1320
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
1421
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
15-
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
16-
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
22+
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
23+
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
1724
golang.org/x/exp v0.0.0-20220823124025-807a23277127 h1:S4NrSKDfihhl3+4jSTgwoIevKxX9p7Iv9x++OEIptDo=
1825
golang.org/x/exp v0.0.0-20220823124025-807a23277127/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
19-
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
2026
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
27+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
28+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
2129
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
2230
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

ldcontext/builder_benchmark_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,13 @@ func BenchmarkBuildFromLocalBuilderNoCustomAttrsNoAlloc(b *testing.B) {
2020
var b Builder
2121
b.Key("key")
2222
b.Name("x")
23-
b.Secondary("y")
2423
benchmarkContext = b.Build()
2524
}
2625
}
2726

2827
func BenchmarkBuildWithNoCustomAttrs(b *testing.B) {
2928
for i := 0; i < b.N; i++ {
30-
benchmarkContext = NewBuilder("key").Name("x").Secondary("y").Build()
29+
benchmarkContext = NewBuilder("key").Name("x").Build()
3130
}
3231
}
3332

ldcontext/builder_multi.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,9 @@ func (m *MultiBuilder) Build() Context {
8080
}
8181
individualErrors[string(c.Kind())] = err
8282
default:
83-
for j := 0; j < i; j++ {
84-
if c.Kind() == m.contexts[j].Kind() { // same kind was seen twice
85-
duplicates = true
86-
break
87-
}
83+
// duplicate check's correctness relies on m.contexts being sorted by kind.
84+
if i > 0 && m.contexts[i-1].Kind() == c.Kind() {
85+
duplicates = true
8886
}
8987
}
9088
}

ldcontext/builder_simple.go

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ type Builder struct {
3535
allowEmptyKey bool
3636
name ldvalue.OptionalString
3737
attributes ldvalue.ValueMapBuilder
38-
secondary ldvalue.OptionalString
3938
anonymous bool
4039
privateAttrs []ldattr.Ref
4140
privateCopyOnWrite bool
@@ -113,7 +112,6 @@ func (b *Builder) Build() Context {
113112
key: b.key,
114113
name: b.name,
115114
anonymous: b.anonymous,
116-
secondary: b.secondary,
117115
}
118116

119117
ret.fullyQualifiedKey = makeFullyQualifiedKeySingleKind(actualKind, ret.key, true)
@@ -360,35 +358,6 @@ func (b *Builder) TrySetValue(attributeName string, value ldvalue.Value) bool {
360358
return true
361359
}
362360

363-
// Secondary sets a secondary key for the Context.
364-
//
365-
// This affects feature flag targeting
366-
// (https://docs.launchdarkly.com/home/flags/targeting-users#targeting-rules-based-on-user-attributes)
367-
// as follows: if you have chosen to bucket users by a specific attribute, the secondary key (if set)
368-
// is used to further distinguish between users who are otherwise identical according to that attribute.
369-
//
370-
// This is a metadata property, rather than an attribute that can be addressed in evaluations: that is,
371-
// a rule clause that references the attribute name "secondary" will not use this value, but instead will
372-
// use whatever value (if any) you have set for the name "secondary" with a method such as SetString.
373-
//
374-
// Setting this value to an empty string is not the same as leaving it unset. If you need to clear this
375-
// attribute to a "no value" state, use OptSecondary().
376-
func (b *Builder) Secondary(value string) *Builder {
377-
return b.OptSecondary(ldvalue.NewOptionalString(value))
378-
}
379-
380-
// OptSecondary sets a secondary key for the Context.
381-
//
382-
// Calling b.OptSecondary(ldvalue.NewOptionalString("x")) is equivalent to b.Secondary("x"), but since it uses
383-
// the OptionalString type, it also allows clearing a previously set name with
384-
// b.OptSecondary(ldvalue.OptionalString{}).
385-
func (b *Builder) OptSecondary(value ldvalue.OptionalString) *Builder {
386-
if b != nil {
387-
b.secondary = value
388-
}
389-
return b
390-
}
391-
392361
// Anonymous sets whether the Context is only intended for flag evaluations and should not be indexed by
393362
// LaunchDarkly.
394363
//
@@ -516,7 +485,6 @@ func (b *Builder) copyFrom(fromContext Context) {
516485
b.kind = fromContext.kind
517486
b.key = fromContext.key
518487
b.name = fromContext.name
519-
b.secondary = fromContext.secondary
520488
b.anonymous = fromContext.anonymous
521489
b.attributes = ldvalue.ValueMapBuilder{}
522490
b.attributes.SetAllFromValueMap(fromContext.attributes)

ldcontext/builder_simple_test.go

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -122,15 +122,6 @@ func TestBuilderBasicSetters(t *testing.T) {
122122
t.Run("Secondary", func(t *testing.T) {
123123
c0 := makeBasicBuilder().Build()
124124
assert.Equal(t, ldvalue.OptionalString{}, c0.Secondary())
125-
126-
c1 := makeBasicBuilder().Secondary("value").Build()
127-
assert.Equal(t, ldvalue.NewOptionalString("value"), c1.Secondary())
128-
129-
c2 := makeBasicBuilder().OptSecondary(ldvalue.OptionalString{}).Build()
130-
assert.Equal(t, ldvalue.OptionalString{}, c2.Secondary())
131-
132-
c3 := makeBasicBuilder().OptSecondary(ldvalue.NewOptionalString("value")).Build()
133-
assert.Equal(t, ldvalue.NewOptionalString("value"), c3.Secondary())
134125
})
135126

136127
t.Run("Anonymous", func(t *testing.T) {
@@ -410,7 +401,7 @@ func TestBuilderPrivate(t *testing.T) {
410401
func TestNewBuilderFromContext(t *testing.T) {
411402
value1, value2 := ldvalue.String("value1"), ldvalue.String("value2")
412403

413-
b1 := NewBuilder("key1").Kind("kind1").Name("name1").Secondary("sec1").Anonymous(true).SetValue("attr", value1)
404+
b1 := NewBuilder("key1").Kind("kind1").Name("name1").Anonymous(true).SetValue("attr", value1)
414405
b1.Private("private1")
415406
c1 := b1.Build()
416407
jsonhelpers.AssertEqual(t, value1, c1.attributes.Get("attr"))
@@ -420,7 +411,6 @@ func TestNewBuilderFromContext(t *testing.T) {
420411
c2 := b2.Build()
421412
assert.Equal(t, Kind("kind1"), c2.Kind())
422413
assert.Equal(t, "key1", c2.Key())
423-
assert.Equal(t, ldvalue.NewOptionalString("sec1"), c2.Secondary())
424414
assert.True(t, c2.Anonymous())
425415
jsonhelpers.AssertEqual(t, value1, c2.attributes.Get("attr"))
426416
assert.Equal(t, c1.privateAttrs, c2.privateAttrs)
@@ -450,7 +440,6 @@ func TestBuilderSafety(t *testing.T) {
450440
var nilPtr *Builder
451441
assert.Nil(t, nilPtr.Key("a"))
452442
assert.Nil(t, nilPtr.Name("a"))
453-
assert.Nil(t, nilPtr.Secondary("a"))
454443
assert.Nil(t, nilPtr.Anonymous(true))
455444
assert.Nil(t, nilPtr.SetValue("a", ldvalue.Bool(true)))
456445
assert.Nil(t, nilPtr.Private("a"))

ldcontext/constants.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package ldcontext
22

33
const (
4-
jsonPropMeta = "_meta"
5-
jsonPropPrivate = "privateAttributes"
6-
jsonPropRedacted = "redactedAttributes"
7-
jsonPropSecondary = "secondary"
8-
jsonPropOldUserCustom = "custom"
9-
jsonPropOldUserPrivate = "privateAttributeNames"
10-
jsonPropOldUserRedacted = "privateAttrs"
4+
jsonPropMeta = "_meta"
5+
jsonPropPrivate = "privateAttributes"
6+
jsonPropRedacted = "redactedAttributes"
7+
jsonPropOldUserCustom = "custom"
8+
jsonPropOldUserPrivate = "privateAttributeNames"
9+
jsonPropOldUserRedacted = "privateAttrs"
10+
jsonPropOldUserSecondary = "secondary"
1111
)

ldcontext/context.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ type Context struct {
3232
secondary ldvalue.OptionalString
3333
anonymous bool
3434
privateAttrs []ldattr.Ref
35+
36+
// Note that the secondary field cannot be set by any builder method. We support this
37+
// meta-attribute internally in order to be able to evaluate flags for old-style users,
38+
// and the only way it can be set is from the user JSON unmarshaling logic.
3539
}
3640

3741
// IsDefined returns true if this is a Context that was created with a constructor or builder
@@ -224,14 +228,14 @@ func (c Context) Anonymous() bool {
224228
return c.anonymous
225229
}
226230

227-
// Secondary returns the secondary key attribute for the Context, if any.
231+
// Secondary returns the deprecated secondary key meta-attribute for the Context, if any.
228232
//
229-
// For a single-kind context, this value can be set by Builder.Secondary(), and is an empty
230-
// ldvalue.OptionalString{} value if not specified.
233+
// This corresponds to the "secondary" attribute in the older LaunchDarkly user schema. Since LaunchDarkly
234+
// still supports evaluating feature flags for old-style users, this attribute is still available to the
235+
// evaluation logic if it was present in user JSON, but it cannot be set via the Context or Builder APIs.
231236
//
232-
// For a multi-kind context, there is no single value, so Secondary() always returns an empty value; use
233-
// IndividualContextByIndex(), IndividualContextByName(), or GetAllIndividualContexts() to inspect
234-
// a Context for a particular kind and then call Secondary() on it.
237+
// Deprecated: Application code should not rely on the availability of this value. It is likely to be
238+
// removed from the product in the future.
235239
func (c Context) Secondary() ldvalue.OptionalString {
236240
return c.secondary
237241
}

ldcontext/context_easyjson.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
//go:build launchdarkly_easyjson
2-
// +build launchdarkly_easyjson
32

43
package ldcontext
54

@@ -171,8 +170,6 @@ func unmarshalSingleKindEasyJSON(c *Context, in *jlexer.Lexer, knownKind Kind, u
171170
key := in.UnsafeBytes() // see comment above
172171
in.WantColon()
173172
switch string(key) {
174-
case jsonPropSecondary:
175-
c.secondary = readOptStringEasyJSON(in)
176173
case jsonPropPrivate:
177174
if usingEventFormat {
178175
in.SkipRecursive()
@@ -266,7 +263,7 @@ func unmarshalOldUserSchemaEasyJSON(c *Context, in *jlexer.Lexer, usingEventForm
266263
hasKey = true
267264
case ldattr.NameAttr:
268265
c.name = readOptStringEasyJSON(in)
269-
case jsonPropSecondary:
266+
case jsonPropOldUserSecondary:
270267
c.secondary = readOptStringEasyJSON(in)
271268
case ldattr.AnonymousAttr:
272269
if in.IsNull() {

0 commit comments

Comments
 (0)