unleash 4.5.0 → 5.0.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/.rubocop.yml +2 -0
- data/CHANGELOG.md +11 -0
- data/README.md +5 -3
- data/lib/unleash/client.rb +0 -1
- data/lib/unleash/configuration.rb +1 -1
- data/lib/unleash/constraint.rb +1 -1
- data/lib/unleash/feature_toggle.rb +41 -10
- data/lib/unleash/strategy/flexible_rollout.rb +1 -1
- data/lib/unleash/strategy/gradual_rollout_sessionid.rb +1 -1
- data/lib/unleash/strategy/gradual_rollout_userid.rb +1 -1
- data/lib/unleash/strategy/util.rb +3 -2
- 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: 46123d78efc7bf615f2ccf84d20087a6680b7999fed0e4b4e22014b044b7d455
|
4
|
+
data.tar.gz: 9992d9a6da906ab49b7ab5cfb9b8521c3f8bdd849ac76099153157debe3a989b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49a49172df9366a14e26ae3d5486347fd9bf0cab8b154139bceb642a5f586ac2e01b617c4756c8e64a48a96d7f93605e686d98092ba86cd1db5bcb4e24142641
|
7
|
+
data.tar.gz: eb53f5f237afe96847ac14cc9af19a4d517c63e874cc829c957bf729e80cdf05f5d251393d918e36ccedc1e15ad0e8933923b5561674126c518a6322ea0956ad
|
@@ -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
|
53
|
+
run: git clone --depth 5 --branch v5.0.2 https://github.com/Unleash/client-specification.git client-specification
|
54
54
|
- name: Run tests
|
55
55
|
run: bundle exec rake
|
56
56
|
env:
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -13,6 +13,17 @@ Note: These changes are not considered notable:
|
|
13
13
|
|
14
14
|
## [Unreleased]
|
15
15
|
|
16
|
+
## [5.0.0] - 2023-10-30
|
17
|
+
### Added
|
18
|
+
- change seed for variantutils to ensure fair distribution (#160)
|
19
|
+
- client specification is [here](https://github.com/Unleash/client-specification/tree/v5.0.2/specifications)
|
20
|
+
- A new seed is introduced to ensure a fair distribution for variants, addressing the issue of skewed variant distribution due to using the same hash string for both gradual rollout and variant allocation.
|
21
|
+
|
22
|
+
## [4.6.0] - 2023-10-16
|
23
|
+
### Added
|
24
|
+
- dependant toggles (#155)
|
25
|
+
- client specification is [here](https://github.com/Unleash/client-specification/pull/63)
|
26
|
+
|
16
27
|
## [4.5.0] - 2023-07-05
|
17
28
|
### Added
|
18
29
|
- variants in strategies (#148)
|
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', '~>
|
28
|
+
gem 'unleash', '~> 5.0.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
|
531
|
+
`git clone --depth 5 --branch v5.0.2 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
|
|
@@ -539,7 +539,7 @@ To install this gem onto your local machine, run `bundle exec rake install`.
|
|
539
539
|
Choose a new version number following [Semantic Versioning](https://semver.org/spec/v2.0.0.html) semantics and then:
|
540
540
|
|
541
541
|
- update the version number in [./lib/unleash/version.rb](./lib/unleash/version.rb),
|
542
|
-
- if a major or minor version bump, update the [Installation section](#
|
542
|
+
- if a major or minor version bump, update the [Installation section](#installation) in [README.md](README.md)
|
543
543
|
- update [CHANGELOG.md](CHANGELOG.md) following the format on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
|
544
544
|
- commit with message `chore: bump version to x.y.z`
|
545
545
|
- then run `bundle exec rake release`
|
@@ -555,3 +555,5 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/unleas
|
|
555
555
|
Be sure to run both `bundle exec rspec` and `bundle exec rubocop` in your branch before creating a pull request.
|
556
556
|
|
557
557
|
Please include tests with any pull requests, to avoid regressions.
|
558
|
+
|
559
|
+
Check out our guide for more information on how to build and scale [feature flag systems](https://docs.getunleash.io/topics/feature-flags/feature-flag-best-practices)
|
data/lib/unleash/client.rb
CHANGED
data/lib/unleash/constraint.rb
CHANGED
@@ -107,7 +107,7 @@ module Unleash
|
|
107
107
|
context_value = context.get_by_name(self.context_name)
|
108
108
|
|
109
109
|
v.map!(&:upcase) if self.case_insensitive
|
110
|
-
context_value.upcase
|
110
|
+
context_value = context_value.upcase if self.case_insensitive
|
111
111
|
|
112
112
|
OPERATORS[self.operator].call(context_value, v)
|
113
113
|
end
|
@@ -7,7 +7,7 @@ require 'securerandom'
|
|
7
7
|
|
8
8
|
module Unleash
|
9
9
|
class FeatureToggle
|
10
|
-
attr_accessor :name, :enabled, :strategies, :variant_definitions
|
10
|
+
attr_accessor :name, :enabled, :dependencies, :strategies, :variant_definitions
|
11
11
|
|
12
12
|
FeatureEvaluationResult = Struct.new(:enabled?, :strategy)
|
13
13
|
|
@@ -16,6 +16,7 @@ module Unleash
|
|
16
16
|
|
17
17
|
self.name = params.fetch('name', nil)
|
18
18
|
self.enabled = params.fetch('enabled', false)
|
19
|
+
self.dependencies = params.fetch('dependencies', [])
|
19
20
|
|
20
21
|
self.strategies = initialize_strategies(params, segment_map)
|
21
22
|
self.variant_definitions = initialize_variant_definitions(params)
|
@@ -41,11 +42,11 @@ module Unleash
|
|
41
42
|
|
42
43
|
evaluation_result = evaluate(context)
|
43
44
|
|
44
|
-
group_id = evaluation_result
|
45
|
+
group_id = evaluation_result.strategy&.params.to_h['groupId'] || self.name
|
45
46
|
|
46
47
|
variant = resolve_variant(context, evaluation_result, group_id)
|
47
48
|
|
48
|
-
choice = evaluation_result
|
49
|
+
choice = evaluation_result.enabled? ? :yes : :no
|
49
50
|
Unleash.toggle_metrics.increment_variant(self.name, choice, variant.name) unless Unleash.configuration.disable_metrics
|
50
51
|
variant
|
51
52
|
end
|
@@ -57,9 +58,9 @@ module Unleash
|
|
57
58
|
private
|
58
59
|
|
59
60
|
def resolve_variant(context, evaluation_result, group_id)
|
60
|
-
variant_definitions = evaluation_result
|
61
|
+
variant_definitions = evaluation_result.strategy&.variant_definitions
|
61
62
|
variant_definitions = self.variant_definitions if variant_definitions.nil? || variant_definitions.empty?
|
62
|
-
return Unleash::FeatureToggle.disabled_variant unless evaluation_result
|
63
|
+
return Unleash::FeatureToggle.disabled_variant unless evaluation_result.enabled?
|
63
64
|
return Unleash::FeatureToggle.disabled_variant if sum_variant_defs_weights(variant_definitions) <= 0
|
64
65
|
|
65
66
|
variant_from_override_match(context, variant_definitions) ||
|
@@ -72,12 +73,42 @@ module Unleash
|
|
72
73
|
|
73
74
|
# only check if it is enabled, do not do metrics
|
74
75
|
def am_enabled?(context)
|
75
|
-
evaluate(context)
|
76
|
+
evaluate(context).enabled?
|
77
|
+
end
|
78
|
+
|
79
|
+
def parent_dependencies_satisfied?(context)
|
80
|
+
dependencies.empty? || dependencies.all?{ |parent| evaluate_parent(parent, context) }
|
81
|
+
end
|
82
|
+
|
83
|
+
def evaluate_parent(parent, context)
|
84
|
+
parent_toggle = get_parent(parent["feature"])
|
85
|
+
return false if parent_toggle.nil? || !parent_toggle.dependencies.empty?
|
86
|
+
|
87
|
+
evaluation_result = parent_toggle.is_enabled?(context)
|
88
|
+
return !evaluation_result if parent["enabled"] == false
|
89
|
+
|
90
|
+
return false unless evaluation_result
|
91
|
+
|
92
|
+
return evaluation_result if parent["variants"].nil? || parent["variants"].empty?
|
93
|
+
|
94
|
+
parent["variants"].include?(parent_toggle.get_variant(context).name)
|
95
|
+
end
|
96
|
+
|
97
|
+
def get_parent(feature)
|
98
|
+
toggle_as_hash = Unleash&.toggles&.find{ |toggle| toggle['name'] == feature }
|
99
|
+
if toggle_as_hash.nil?
|
100
|
+
Unleash.logger.debug "Unleash::Client.is_enabled? feature: #{feature} not found"
|
101
|
+
return nil
|
102
|
+
end
|
103
|
+
|
104
|
+
Unleash::FeatureToggle.new(toggle_as_hash, Unleash&.segment_cache)
|
76
105
|
end
|
77
106
|
|
78
107
|
def evaluate(context)
|
79
108
|
evaluation_result =
|
80
|
-
if !
|
109
|
+
if !parent_dependencies_satisfied?(context)
|
110
|
+
FeatureEvaluationResult.new(false, nil)
|
111
|
+
elsif !self.enabled
|
81
112
|
FeatureEvaluationResult.new(false, nil)
|
82
113
|
elsif self.strategies.empty?
|
83
114
|
FeatureEvaluationResult.new(true, nil)
|
@@ -86,9 +117,8 @@ module Unleash
|
|
86
117
|
FeatureEvaluationResult.new(!strategy.nil?, strategy)
|
87
118
|
end
|
88
119
|
|
89
|
-
Unleash.logger.debug "Unleash::FeatureToggle (enabled:#{self.enabled} " \
|
90
|
-
"and Strategies combined with
|
91
|
-
|
120
|
+
Unleash.logger.debug "Unleash::FeatureToggle (enabled:#{self.enabled}) " \
|
121
|
+
"and Strategies combined with constraints returned #{evaluation_result})"
|
92
122
|
evaluation_result
|
93
123
|
end
|
94
124
|
|
@@ -133,6 +163,7 @@ module Unleash
|
|
133
163
|
variant_weight = Unleash::Strategy::Util.get_normalized_number(
|
134
164
|
variant_salt(context, stickiness),
|
135
165
|
group_id,
|
166
|
+
Unleash::Strategy::Util::VARIANT_NORMALIZER_SEED,
|
136
167
|
sum_variant_defs_weights(variant_definitions)
|
137
168
|
)
|
138
169
|
prev_weights = 0
|
@@ -24,7 +24,7 @@ module Unleash
|
|
24
24
|
end
|
25
25
|
|
26
26
|
group_id = params.fetch('groupId', '')
|
27
|
-
normalized_number = Util.get_normalized_number(stickiness_id, group_id)
|
27
|
+
normalized_number = Util.get_normalized_number(stickiness_id, group_id, 0)
|
28
28
|
|
29
29
|
return false if stickiness_id.nil?
|
30
30
|
|
@@ -14,7 +14,7 @@ module Unleash
|
|
14
14
|
return false if context.session_id.nil? || context.session_id.empty?
|
15
15
|
|
16
16
|
percentage = Integer(params['percentage'] || 0)
|
17
|
-
(percentage.positive? && Util.get_normalized_number(context.session_id, params['groupId'] || "") <= percentage)
|
17
|
+
(percentage.positive? && Util.get_normalized_number(context.session_id, params['groupId'] || "", 0) <= percentage)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -14,7 +14,7 @@ module Unleash
|
|
14
14
|
return false if context.user_id.nil? || context.user_id.empty?
|
15
15
|
|
16
16
|
percentage = Integer(params['percentage'] || 0)
|
17
|
-
(percentage.positive? && Util.get_normalized_number(context.user_id, params['groupId'] || "") <= percentage)
|
17
|
+
(percentage.positive? && Util.get_normalized_number(context.user_id, params['groupId'] || "", 0) <= percentage)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -6,10 +6,11 @@ module Unleash
|
|
6
6
|
module_function
|
7
7
|
|
8
8
|
NORMALIZER = 100
|
9
|
+
VARIANT_NORMALIZER_SEED = 86_028_157
|
9
10
|
|
10
11
|
# convert the two strings () into a number between 1 and base (100 by default)
|
11
|
-
def get_normalized_number(identifier, group_id, base = NORMALIZER)
|
12
|
-
MurmurHash3::V32.str_hash("#{group_id}:#{identifier}") % base + 1
|
12
|
+
def get_normalized_number(identifier, group_id, seed, base = NORMALIZER)
|
13
|
+
MurmurHash3::V32.str_hash("#{group_id}:#{identifier}", seed) % base + 1
|
13
14
|
end
|
14
15
|
end
|
15
16
|
end
|
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
|
+
version: 5.0.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-10-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: murmurhash3
|