unleash 4.4.4 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/pull_request.yml +1 -1
- data/CHANGELOG.md +8 -0
- data/README.md +2 -2
- data/lib/unleash/activation_strategy.rb +17 -4
- data/lib/unleash/feature_toggle.rb +59 -28
- data/lib/unleash/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b823e18f3a0768928856433b11674d37ea62cc7f2b8b15786920488aba5c063c
|
4
|
+
data.tar.gz: 6c8ec27517214b441c711d2f0069c211492ce3185bf4f1741c7b07077a28b088
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a324e1902ae4e3885a206531e25d6138db8e39fb50b946471d0dcce3aec1ce595c2743b79ad3519af7cb80e83a284428d16bb2f3385313f889938f2ded80feef
|
7
|
+
data.tar.gz: b89d72bb1b7a0fdd6ba65fe92ab1909ec5b02742d6e2d2447d047ed0d3325efe29e0e0f033ad4ff0ad12e80041a2a8697b64e366dd185077953be59073c8e801
|
@@ -50,7 +50,7 @@ jobs:
|
|
50
50
|
- name: Install dependencies
|
51
51
|
run: bundle install
|
52
52
|
- name: Download test cases
|
53
|
-
run: git clone --depth 5 --branch v4.
|
53
|
+
run: git clone --depth 5 --branch v4.3.1 https://github.com/Unleash/client-specification.git client-specification
|
54
54
|
- name: Run tests
|
55
55
|
run: bundle exec rake
|
56
56
|
env:
|
data/CHANGELOG.md
CHANGED
@@ -13,6 +13,14 @@ Note: These changes are not considered notable:
|
|
13
13
|
|
14
14
|
## [Unreleased]
|
15
15
|
|
16
|
+
## [4.5.0] - 2023-07-05
|
17
|
+
### Added
|
18
|
+
- variants in strategies (#148)
|
19
|
+
- issue described here (#147)
|
20
|
+
|
21
|
+
### Fixed
|
22
|
+
- groupId override for variants
|
23
|
+
|
16
24
|
## [4.4.4] - 2023-07-05
|
17
25
|
### Fixed
|
18
26
|
- flexible rollout strategy without context (#146)
|
data/README.md
CHANGED
@@ -25,7 +25,7 @@ Leverage the [Unleash Server](https://github.com/Unleash/unleash) for powerful f
|
|
25
25
|
Add this line to your application's Gemfile:
|
26
26
|
|
27
27
|
```ruby
|
28
|
-
gem 'unleash', '~> 4.
|
28
|
+
gem 'unleash', '~> 4.5.0'
|
29
29
|
```
|
30
30
|
|
31
31
|
And then execute:
|
@@ -528,7 +528,7 @@ You can also run `bin/console` for an interactive prompt that will allow you to
|
|
528
528
|
This SDK is also built against the Unleash Client Specification tests.
|
529
529
|
To run the Ruby SDK against this test suite, you'll need to have a copy on your machine, you can clone the repository directly using:
|
530
530
|
|
531
|
-
`git clone --depth 5 --branch v4.
|
531
|
+
`git clone --depth 5 --branch v4.3.1 https://github.com/Unleash/client-specification.git client-specification`
|
532
532
|
|
533
533
|
After doing this, `rake spec` will also run the client specification tests.
|
534
534
|
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module Unleash
|
2
2
|
class ActivationStrategy
|
3
|
-
attr_accessor :name, :params, :constraints, :disabled
|
3
|
+
attr_accessor :name, :params, :constraints, :disabled, :variant_definitions
|
4
4
|
|
5
|
-
def initialize(name, params, constraints = [])
|
5
|
+
def initialize(name, params, constraints = [], variant_definitions = [])
|
6
6
|
self.name = name
|
7
7
|
self.disabled = false
|
8
8
|
|
@@ -15,17 +15,30 @@ module Unleash
|
|
15
15
|
self.params = {}
|
16
16
|
end
|
17
17
|
|
18
|
-
if constraints.is_a?(Array) && constraints.
|
18
|
+
if constraints.is_a?(Array) && constraints.all?{ |c| c.is_a?(Constraint) }
|
19
19
|
self.constraints = constraints
|
20
20
|
else
|
21
|
-
Unleash.logger.warn "Invalid constraints provided for ActivationStrategy (
|
21
|
+
Unleash.logger.warn "Invalid constraints provided for ActivationStrategy (constraints: #{constraints})"
|
22
22
|
self.disabled = true
|
23
23
|
self.constraints = []
|
24
24
|
end
|
25
|
+
|
26
|
+
self.variant_definitions = valid_variant_definitions(variant_definitions)
|
25
27
|
end
|
26
28
|
|
27
29
|
def matches_context?(context)
|
28
30
|
self.constraints.any?{ |c| c.matches_context? context }
|
29
31
|
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def valid_variant_definitions(variant_definitions)
|
36
|
+
if variant_definitions.is_a?(Array) && variant_definitions.all?{ |variant_definition| variant_definition.is_a?(VariantDefinition) }
|
37
|
+
variant_definitions
|
38
|
+
else
|
39
|
+
Unleash.logger.warn "Invalid variant_definitions provided for ActivationStrategy (variant_definitions: #{variant_definitions})"
|
40
|
+
[]
|
41
|
+
end
|
42
|
+
end
|
30
43
|
end
|
31
44
|
end
|
@@ -9,6 +9,8 @@ module Unleash
|
|
9
9
|
class FeatureToggle
|
10
10
|
attr_accessor :name, :enabled, :strategies, :variant_definitions
|
11
11
|
|
12
|
+
FeatureEvaluationResult = Struct.new(:enabled?, :strategy)
|
13
|
+
|
12
14
|
def initialize(params = {}, segment_map = {})
|
13
15
|
params = {} if params.nil?
|
14
16
|
|
@@ -37,10 +39,13 @@ module Unleash
|
|
37
39
|
|
38
40
|
context = ensure_valid_context(context)
|
39
41
|
|
40
|
-
|
41
|
-
|
42
|
+
evaluation_result = evaluate(context)
|
43
|
+
|
44
|
+
group_id = evaluation_result[:strategy]&.params.to_h['groupId'] || self.name
|
45
|
+
|
46
|
+
variant = resolve_variant(context, evaluation_result, group_id)
|
42
47
|
|
43
|
-
choice =
|
48
|
+
choice = evaluation_result[:enabled?] ? :yes : :no
|
44
49
|
Unleash.toggle_metrics.increment_variant(self.name, choice, variant.name) unless Unleash.configuration.disable_metrics
|
45
50
|
variant
|
46
51
|
end
|
@@ -51,33 +56,40 @@ module Unleash
|
|
51
56
|
|
52
57
|
private
|
53
58
|
|
54
|
-
def resolve_variant(context,
|
55
|
-
|
56
|
-
|
59
|
+
def resolve_variant(context, evaluation_result, group_id)
|
60
|
+
variant_definitions = evaluation_result[:strategy]&.variant_definitions
|
61
|
+
variant_definitions = self.variant_definitions if variant_definitions.nil? || variant_definitions.empty?
|
62
|
+
return Unleash::FeatureToggle.disabled_variant unless evaluation_result[:enabled?]
|
63
|
+
return Unleash::FeatureToggle.disabled_variant if sum_variant_defs_weights(variant_definitions) <= 0
|
57
64
|
|
58
|
-
variant_from_override_match(context) ||
|
65
|
+
variant_from_override_match(context, variant_definitions) ||
|
66
|
+
variant_from_weights(context, resolve_stickiness(variant_definitions), variant_definitions, group_id)
|
59
67
|
end
|
60
68
|
|
61
|
-
def resolve_stickiness
|
62
|
-
|
69
|
+
def resolve_stickiness(variant_definitions)
|
70
|
+
variant_definitions&.map(&:stickiness)&.compact&.first || "default"
|
63
71
|
end
|
64
72
|
|
65
73
|
# only check if it is enabled, do not do metrics
|
66
74
|
def am_enabled?(context)
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
75
|
+
evaluate(context)[:enabled?]
|
76
|
+
end
|
77
|
+
|
78
|
+
def evaluate(context)
|
79
|
+
evaluation_result =
|
80
|
+
if !self.enabled
|
81
|
+
FeatureEvaluationResult.new(false, nil)
|
82
|
+
elsif self.strategies.empty?
|
83
|
+
FeatureEvaluationResult.new(true, nil)
|
73
84
|
else
|
74
|
-
|
85
|
+
strategy = self.strategies.find{ |s| strategy_enabled?(s, context) && strategy_constraint_matches?(s, context) }
|
86
|
+
FeatureEvaluationResult.new(!strategy.nil?, strategy)
|
75
87
|
end
|
76
88
|
|
77
89
|
Unleash.logger.debug "Unleash::FeatureToggle (enabled:#{self.enabled} " \
|
78
|
-
"and Strategies combined with contraints returned #{
|
90
|
+
"and Strategies combined with contraints returned #{evaluation_result})"
|
79
91
|
|
80
|
-
|
92
|
+
evaluation_result
|
81
93
|
end
|
82
94
|
|
83
95
|
def strategy_enabled?(strategy, context)
|
@@ -92,8 +104,8 @@ module Unleash
|
|
92
104
|
strategy.constraints.empty? || strategy.constraints.all?{ |c| c.matches_context?(context) }
|
93
105
|
end
|
94
106
|
|
95
|
-
def sum_variant_defs_weights
|
96
|
-
|
107
|
+
def sum_variant_defs_weights(variant_definitions)
|
108
|
+
variant_definitions.map(&:weight).reduce(0, :+)
|
97
109
|
end
|
98
110
|
|
99
111
|
def variant_salt(context, stickiness = "default")
|
@@ -110,18 +122,22 @@ module Unleash
|
|
110
122
|
SecureRandom.random_number
|
111
123
|
end
|
112
124
|
|
113
|
-
def variant_from_override_match(context)
|
114
|
-
|
115
|
-
return nil if
|
125
|
+
def variant_from_override_match(context, variant_definitions)
|
126
|
+
variant_definition = variant_definitions.find{ |vd| vd.override_matches_context?(context) }
|
127
|
+
return nil if variant_definition.nil?
|
116
128
|
|
117
|
-
Unleash::Variant.new(name:
|
129
|
+
Unleash::Variant.new(name: variant_definition.name, enabled: true, payload: variant_definition.payload)
|
118
130
|
end
|
119
131
|
|
120
|
-
def variant_from_weights(context, stickiness)
|
121
|
-
variant_weight = Unleash::Strategy::Util.get_normalized_number(
|
132
|
+
def variant_from_weights(context, stickiness, variant_definitions, group_id)
|
133
|
+
variant_weight = Unleash::Strategy::Util.get_normalized_number(
|
134
|
+
variant_salt(context, stickiness),
|
135
|
+
group_id,
|
136
|
+
sum_variant_defs_weights(variant_definitions)
|
137
|
+
)
|
122
138
|
prev_weights = 0
|
123
139
|
|
124
|
-
variant_definition =
|
140
|
+
variant_definition = variant_definitions
|
125
141
|
.find do |v|
|
126
142
|
res = (prev_weights + v.weight >= variant_weight)
|
127
143
|
prev_weights += v.weight
|
@@ -148,11 +164,26 @@ module Unleash
|
|
148
164
|
ActivationStrategy.new(
|
149
165
|
s['name'],
|
150
166
|
s['parameters'],
|
151
|
-
resolve_constraints(s, segment_map)
|
167
|
+
resolve_constraints(s, segment_map),
|
168
|
+
resolve_variants(s)
|
152
169
|
)
|
153
170
|
end || []
|
154
171
|
end
|
155
172
|
|
173
|
+
def resolve_variants(strategy)
|
174
|
+
strategy.fetch("variants", [])
|
175
|
+
.select{ |variant| variant.is_a?(Hash) && variant.has_key?("name") }
|
176
|
+
.map do |variant|
|
177
|
+
VariantDefinition.new(
|
178
|
+
variant.fetch("name", ""),
|
179
|
+
variant.fetch("weight", 0),
|
180
|
+
variant.fetch("payload", nil),
|
181
|
+
variant.fetch("stickiness", nil),
|
182
|
+
variant.fetch("overrides", [])
|
183
|
+
)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
156
187
|
def resolve_constraints(strategy, segment_map)
|
157
188
|
segment_constraints = (strategy["segments"] || []).map do |segment_id|
|
158
189
|
segment_map[segment_id]&.fetch("constraints")
|
data/lib/unleash/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unleash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Renato Arruda
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: murmurhash3
|