unleash 4.4.4 → 4.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f59bcc61a5b2adc71f82f31ee80d02e8957854b86b85147fa33ad1f8bd3ee3ab
4
- data.tar.gz: 691a79a57aba051ab5111d71a038e6c8f2d21ee747ee39fdb6676108fc1ef777
3
+ metadata.gz: b823e18f3a0768928856433b11674d37ea62cc7f2b8b15786920488aba5c063c
4
+ data.tar.gz: 6c8ec27517214b441c711d2f0069c211492ce3185bf4f1741c7b07077a28b088
5
5
  SHA512:
6
- metadata.gz: c6d4c9efc598b2eae5958c7c68c362832988d6ed8cc4f51d47e0ede588b37599c0d104d4a7c08060761564653bdb68d1c6a20dedafc7b6d3bbb22c489ac8c4ec
7
- data.tar.gz: 003b0d345c5f1ccc22361ddce4213e40054ec57a7e3404ca8d99ce3b120fb072b506a75f1fe64053e7b57c67688ed0b6aa6532dd99f3f7bfaa729c520d2c290c
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.2.2 https://github.com/Unleash/client-specification.git client-specification
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.4.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.2.2 https://github.com/Unleash/client-specification.git client-specification`
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.each{ |c| c.is_a?(Constraint) }
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 (contraints: #{constraints})"
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
- toggle_enabled = am_enabled?(context)
41
- variant = resolve_variant(context, toggle_enabled)
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 = toggle_enabled ? :yes : :no
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, toggle_enabled)
55
- return Unleash::FeatureToggle.disabled_variant unless toggle_enabled
56
- return Unleash::FeatureToggle.disabled_variant if sum_variant_defs_weights <= 0
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) || variant_from_weights(context, resolve_stickiness)
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
- self.variant_definitions&.map(&:stickiness)&.compact&.first || "default"
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
- result =
68
- if self.enabled
69
- self.strategies.empty? ||
70
- self.strategies.any? do |s|
71
- strategy_enabled?(s, context) && strategy_constraint_matches?(s, context)
72
- end
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
- false
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 #{result})"
90
+ "and Strategies combined with contraints returned #{evaluation_result})"
79
91
 
80
- result
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
- self.variant_definitions.map(&:weight).reduce(0, :+)
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
- variant = self.variant_definitions.find{ |vd| vd.override_matches_context?(context) }
115
- return nil if variant.nil?
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: variant.name, enabled: true, payload: variant.payload)
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(variant_salt(context, stickiness), self.name, sum_variant_defs_weights)
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 = self.variant_definitions
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")
@@ -1,3 +1,3 @@
1
1
  module Unleash
2
- VERSION = "4.4.4".freeze
2
+ VERSION = "4.5.0".freeze
3
3
  end
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.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-07-05 00:00:00.000000000 Z
11
+ date: 2023-08-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: murmurhash3