unleash 3.2.2 → 4.3.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/add-to-project.yml +14 -0
- data/.github/workflows/pull_request.yml +79 -0
- data/.gitignore +5 -1
- data/.rubocop.yml +114 -6
- data/README.md +263 -27
- data/bin/unleash-client +15 -5
- data/examples/bootstrap.rb +51 -0
- data/examples/default-toggles.json +42 -0
- data/examples/simple.rb +5 -4
- data/lib/unleash/bootstrap/configuration.rb +25 -0
- data/lib/unleash/bootstrap/handler.rb +22 -0
- data/lib/unleash/bootstrap/provider/base.rb +14 -0
- data/lib/unleash/bootstrap/provider/from_file.rb +14 -0
- data/lib/unleash/bootstrap/provider/from_url.rb +19 -0
- data/lib/unleash/client.rb +27 -17
- data/lib/unleash/configuration.rb +41 -19
- data/lib/unleash/constraint.rb +88 -10
- data/lib/unleash/context.rb +3 -2
- data/lib/unleash/feature_toggle.rb +26 -19
- data/lib/unleash/metrics_reporter.rb +18 -4
- data/lib/unleash/scheduled_executor.rb +5 -2
- data/lib/unleash/strategy/application_hostname.rb +1 -0
- data/lib/unleash/strategy/flexible_rollout.rb +5 -5
- data/lib/unleash/strategy/remote_address.rb +17 -1
- data/lib/unleash/toggle_fetcher.rb +51 -42
- data/lib/unleash/util/http.rb +7 -6
- data/lib/unleash/variant_definition.rb +5 -4
- data/lib/unleash/version.rb +1 -1
- data/lib/unleash.rb +0 -5
- data/unleash-client.gemspec +3 -2
- metadata +35 -13
- data/.travis.yml +0 -15
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'unleash/configuration'
|
2
|
+
require 'unleash/bootstrap/handler'
|
2
3
|
require 'net/http'
|
3
4
|
require 'json'
|
4
5
|
|
@@ -13,10 +14,15 @@ module Unleash
|
|
13
14
|
self.toggle_resource = ConditionVariable.new
|
14
15
|
self.retry_count = 0
|
15
16
|
|
16
|
-
# start by fetching synchronously, and failing back to reading the backup file.
|
17
17
|
begin
|
18
|
-
|
18
|
+
# if bootstrap configuration is available, initialize. An immediate API read is also triggered
|
19
|
+
if Unleash.configuration.use_bootstrap?
|
20
|
+
bootstrap
|
21
|
+
else
|
22
|
+
fetch
|
23
|
+
end
|
19
24
|
rescue StandardError => e
|
25
|
+
# fail back to reading the backup file
|
20
26
|
Unleash.logger.warn "ToggleFetcher was unable to fetch from the network, attempting to read from backup file."
|
21
27
|
Unleash.logger.debug "Exception Caught: #{e}"
|
22
28
|
read!
|
@@ -36,7 +42,9 @@ module Unleash
|
|
36
42
|
# rename to refresh_from_server! ??
|
37
43
|
def fetch
|
38
44
|
Unleash.logger.debug "fetch()"
|
39
|
-
|
45
|
+
return if Unleash.configuration.disable_client
|
46
|
+
|
47
|
+
response = Unleash::Util::Http.get(Unleash.configuration.fetch_toggles_uri, etag)
|
40
48
|
|
41
49
|
if response.code == '304'
|
42
50
|
Unleash.logger.debug "No changes according to the unleash server, nothing to do."
|
@@ -46,14 +54,7 @@ module Unleash
|
|
46
54
|
end
|
47
55
|
|
48
56
|
self.etag = response['ETag']
|
49
|
-
|
50
|
-
|
51
|
-
if response_hash['version'] == 1
|
52
|
-
features = response_hash['features']
|
53
|
-
else
|
54
|
-
raise NotImplemented, "Version of features provided by unleash server" \
|
55
|
-
" is unsupported by this client."
|
56
|
-
end
|
57
|
+
features = get_features(response.body)
|
57
58
|
|
58
59
|
# always synchronize with the local cache when fetching:
|
59
60
|
synchronize_with_local_cache!(features)
|
@@ -64,24 +65,20 @@ module Unleash
|
|
64
65
|
|
65
66
|
def save!
|
66
67
|
Unleash.logger.debug "Will save toggles to disk now"
|
67
|
-
begin
|
68
|
-
backup_file = Unleash.configuration.backup_file
|
69
|
-
backup_file_tmp = "#{backup_file}.tmp"
|
70
68
|
|
71
|
-
|
72
|
-
|
69
|
+
backup_file = Unleash.configuration.backup_file
|
70
|
+
backup_file_tmp = "#{backup_file}.tmp"
|
71
|
+
|
72
|
+
self.toggle_lock.synchronize do
|
73
|
+
File.open(backup_file_tmp, "w") do |file|
|
73
74
|
file.write(self.toggle_cache.to_json)
|
74
|
-
file.close
|
75
|
-
File.rename(backup_file_tmp, backup_file)
|
76
75
|
end
|
77
|
-
|
78
|
-
# This is not really the end of the world. Swallowing the exception.
|
79
|
-
Unleash.logger.error "Unable to save backup file. Exception thrown #{e.class}:'#{e}'"
|
80
|
-
Unleash.logger.error "stacktrace: #{e.backtrace}"
|
81
|
-
ensure
|
82
|
-
file&.close if defined?(file)
|
83
|
-
self.toggle_lock.unlock if self.toggle_lock.locked?
|
76
|
+
File.rename(backup_file_tmp, backup_file)
|
84
77
|
end
|
78
|
+
rescue StandardError => e
|
79
|
+
# This is not really the end of the world. Swallowing the exception.
|
80
|
+
Unleash.logger.error "Unable to save backup file. Exception thrown #{e.class}:'#{e}'"
|
81
|
+
Unleash.logger.error "stacktrace: #{e.backtrace}"
|
85
82
|
end
|
86
83
|
|
87
84
|
private
|
@@ -106,24 +103,36 @@ module Unleash
|
|
106
103
|
|
107
104
|
def read!
|
108
105
|
Unleash.logger.debug "read!()"
|
109
|
-
|
106
|
+
backup_file = Unleash.configuration.backup_file
|
107
|
+
return nil unless File.exist?(backup_file)
|
110
108
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
109
|
+
backup_as_hash = JSON.parse(File.read(backup_file))
|
110
|
+
synchronize_with_local_cache!(backup_as_hash)
|
111
|
+
update_running_client!
|
112
|
+
rescue IOError => e
|
113
|
+
Unleash.logger.error "Unable to read the backup_file: #{e}"
|
114
|
+
rescue JSON::ParserError => e
|
115
|
+
Unleash.logger.error "Unable to parse JSON from existing backup_file: #{e}"
|
116
|
+
rescue StandardError => e
|
117
|
+
Unleash.logger.error "Unable to extract valid data from backup_file. Exception thrown: #{e}"
|
118
|
+
end
|
119
|
+
|
120
|
+
def bootstrap
|
121
|
+
bootstrap_payload = Unleash::Bootstrap::Handler.new(Unleash.configuration.bootstrap_config).retrieve_toggles
|
122
|
+
synchronize_with_local_cache! get_features bootstrap_payload
|
123
|
+
update_running_client!
|
124
|
+
|
125
|
+
# reset Unleash.configuration.bootstrap_data to free up memory, as we will never use it again
|
126
|
+
Unleash.configuration.bootstrap_config = nil
|
127
|
+
end
|
128
|
+
|
129
|
+
# @param response_body [String]
|
130
|
+
def get_features(response_body)
|
131
|
+
response_hash = JSON.parse(response_body)
|
132
|
+
return response_hash['features'] if response_hash['version'] >= 1
|
133
|
+
|
134
|
+
raise NotImplemented, "Version of features provided by unleash server" \
|
135
|
+
" is unsupported by this client."
|
127
136
|
end
|
128
137
|
end
|
129
138
|
end
|
data/lib/unleash/util/http.rb
CHANGED
@@ -4,17 +4,15 @@ require 'uri'
|
|
4
4
|
module Unleash
|
5
5
|
module Util
|
6
6
|
module Http
|
7
|
-
def self.get(
|
8
|
-
uri = URI(url)
|
7
|
+
def self.get(uri, etag = nil, headers_override = nil)
|
9
8
|
http = http_connection(uri)
|
10
9
|
|
11
|
-
request = Net::HTTP::Get.new(uri.request_uri, http_headers(etag))
|
10
|
+
request = Net::HTTP::Get.new(uri.request_uri, http_headers(etag, headers_override))
|
12
11
|
|
13
12
|
http.request(request)
|
14
13
|
end
|
15
14
|
|
16
|
-
def self.post(
|
17
|
-
uri = URI(url)
|
15
|
+
def self.post(uri, body)
|
18
16
|
http = http_connection(uri)
|
19
17
|
|
20
18
|
request = Net::HTTP::Post.new(uri.request_uri, http_headers)
|
@@ -32,10 +30,13 @@ module Unleash
|
|
32
30
|
http
|
33
31
|
end
|
34
32
|
|
35
|
-
|
33
|
+
# @param etag [String, nil]
|
34
|
+
# @param headers_override [Hash, nil]
|
35
|
+
def self.http_headers(etag = nil, headers_override = nil)
|
36
36
|
Unleash.logger.debug "ETag: #{etag}" unless etag.nil?
|
37
37
|
|
38
38
|
headers = (Unleash.configuration.http_headers || {}).dup
|
39
|
+
headers = headers_override if headers_override.is_a?(Hash)
|
39
40
|
headers['Content-Type'] = 'application/json'
|
40
41
|
headers['If-None-Match'] = etag unless etag.nil?
|
41
42
|
|
@@ -2,13 +2,13 @@ require 'unleash/variant_override'
|
|
2
2
|
|
3
3
|
module Unleash
|
4
4
|
class VariantDefinition
|
5
|
-
attr_accessor :name, :weight, :payload, :overrides
|
5
|
+
attr_accessor :name, :weight, :payload, :overrides, :stickiness
|
6
6
|
|
7
|
-
def initialize(name, weight = 0, payload = nil, overrides = [])
|
7
|
+
def initialize(name, weight = 0, payload = nil, stickiness = nil, overrides = [])
|
8
8
|
self.name = name
|
9
9
|
self.weight = weight
|
10
10
|
self.payload = payload
|
11
|
-
|
11
|
+
self.stickiness = stickiness
|
12
12
|
self.overrides = (overrides || [])
|
13
13
|
.select{ |v| v.is_a?(Hash) && v.has_key?('contextName') }
|
14
14
|
.map{ |v| VariantOverride.new(v.fetch('contextName', ''), v.fetch('values', [])) } || []
|
@@ -19,7 +19,8 @@ module Unleash
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def to_s
|
22
|
-
"<VariantDefinition: name=#{self.name},weight=#{self.weight},payload=#{self.payload},
|
22
|
+
"<VariantDefinition: name=#{self.name},weight=#{self.weight},payload=#{self.payload},stickiness=#{self.stickiness}" \
|
23
|
+
",overrides=#{self.overrides}>"
|
23
24
|
end
|
24
25
|
end
|
25
26
|
end
|
data/lib/unleash/version.rb
CHANGED
data/lib/unleash.rb
CHANGED
@@ -24,11 +24,6 @@ module Unleash
|
|
24
24
|
attr_accessor :configuration, :toggle_fetcher, :toggles, :toggle_metrics, :reporter, :logger
|
25
25
|
end
|
26
26
|
|
27
|
-
def self.initialize
|
28
|
-
self.toggles = []
|
29
|
-
self.toggle_metrics = {}
|
30
|
-
end
|
31
|
-
|
32
27
|
# Support for configuration via yield:
|
33
28
|
def self.configure
|
34
29
|
self.configuration ||= Unleash::Configuration.new
|
data/unleash-client.gemspec
CHANGED
@@ -31,6 +31,7 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.add_development_dependency "rspec-json_expectations", "~> 2.2"
|
32
32
|
spec.add_development_dependency "webmock", "~> 3.8"
|
33
33
|
|
34
|
-
spec.add_development_dependency "
|
35
|
-
spec.add_development_dependency "
|
34
|
+
spec.add_development_dependency "rubocop", "< 1.0.0"
|
35
|
+
spec.add_development_dependency "simplecov", "~> 0.21.2"
|
36
|
+
spec.add_development_dependency "simplecov-lcov", "~> 0.8.0"
|
36
37
|
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: 3.
|
4
|
+
version: 4.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Renato Arruda
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-07-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: murmurhash3
|
@@ -95,33 +95,47 @@ dependencies:
|
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '3.8'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "<"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 1.0.0
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "<"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.0.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
100
114
|
requirements:
|
101
115
|
- - "~>"
|
102
116
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
117
|
+
version: 0.21.2
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
122
|
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
124
|
+
version: 0.21.2
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
126
|
+
name: simplecov-lcov
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
114
128
|
requirements:
|
115
129
|
- - "~>"
|
116
130
|
- !ruby/object:Gem::Version
|
117
|
-
version:
|
131
|
+
version: 0.8.0
|
118
132
|
type: :development
|
119
133
|
prerelease: false
|
120
134
|
version_requirements: !ruby/object:Gem::Requirement
|
121
135
|
requirements:
|
122
136
|
- - "~>"
|
123
137
|
- !ruby/object:Gem::Version
|
124
|
-
version:
|
138
|
+
version: 0.8.0
|
125
139
|
description: |-
|
126
140
|
This is the ruby client for Unleash, a powerful feature toggle system
|
127
141
|
that gives you a great overview over all feature toggles across all your applications and services.
|
@@ -132,10 +146,11 @@ executables:
|
|
132
146
|
extensions: []
|
133
147
|
extra_rdoc_files: []
|
134
148
|
files:
|
149
|
+
- ".github/workflows/add-to-project.yml"
|
150
|
+
- ".github/workflows/pull_request.yml"
|
135
151
|
- ".gitignore"
|
136
152
|
- ".rspec"
|
137
153
|
- ".rubocop.yml"
|
138
|
-
- ".travis.yml"
|
139
154
|
- Gemfile
|
140
155
|
- LICENSE
|
141
156
|
- README.md
|
@@ -143,9 +158,16 @@ files:
|
|
143
158
|
- bin/console
|
144
159
|
- bin/setup
|
145
160
|
- bin/unleash-client
|
161
|
+
- examples/bootstrap.rb
|
162
|
+
- examples/default-toggles.json
|
146
163
|
- examples/simple.rb
|
147
164
|
- lib/unleash.rb
|
148
165
|
- lib/unleash/activation_strategy.rb
|
166
|
+
- lib/unleash/bootstrap/configuration.rb
|
167
|
+
- lib/unleash/bootstrap/handler.rb
|
168
|
+
- lib/unleash/bootstrap/provider/base.rb
|
169
|
+
- lib/unleash/bootstrap/provider/from_file.rb
|
170
|
+
- lib/unleash/bootstrap/provider/from_url.rb
|
149
171
|
- lib/unleash/client.rb
|
150
172
|
- lib/unleash/configuration.rb
|
151
173
|
- lib/unleash/constraint.rb
|
@@ -175,7 +197,7 @@ homepage: https://github.com/unleash/unleash-client-ruby
|
|
175
197
|
licenses:
|
176
198
|
- Apache-2.0
|
177
199
|
metadata: {}
|
178
|
-
post_install_message:
|
200
|
+
post_install_message:
|
179
201
|
rdoc_options: []
|
180
202
|
require_paths:
|
181
203
|
- lib
|
@@ -190,8 +212,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
190
212
|
- !ruby/object:Gem::Version
|
191
213
|
version: '0'
|
192
214
|
requirements: []
|
193
|
-
rubygems_version: 3.
|
194
|
-
signing_key:
|
215
|
+
rubygems_version: 3.3.6
|
216
|
+
signing_key:
|
195
217
|
specification_version: 4
|
196
218
|
summary: Unleash feature toggle client.
|
197
219
|
test_files: []
|
data/.travis.yml
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
sudo: false
|
2
|
-
language: ruby
|
3
|
-
rvm:
|
4
|
-
- jruby
|
5
|
-
- 3.0
|
6
|
-
- 2.7
|
7
|
-
- 2.6
|
8
|
-
- 2.5
|
9
|
-
before_install:
|
10
|
-
- gem install bundler -v 2.1.4
|
11
|
-
- git clone --depth 5 --branch v3.3.0 https://github.com/Unleash/client-specification.git client-specification
|
12
|
-
|
13
|
-
notifications:
|
14
|
-
slack:
|
15
|
-
secure: x593zOjdl2yVB8uP54v8CmuCOat8GFHnK99NPvPHKvif5U7PGe0YOgYh4DC1+Jc9vfjn1ke+0++m+Gif4quowpeOaA/t45xpB494lyziXsBulYml245jRp9yzoUmIIt7KxHhv4rlo3Q1ztMJgh6a5yDCornKHW2bKTkLsvqVTwxBRatLOrt6K9O8FivO/NaqgcoXl7Rw0fOx/bsZtx2IAFueTCH19NoqW1mk9KFEZ96YqJSvuqmfDC0AO7siq03WKlB++nPlKe1QcrlPalCrcsSzrYNhYJ3akBTt/ZbE1v6YJv2L+zUqRnAPTY2H+qp8WejFQtdhIjfeJ/SWox0iWv/Wy/mTFfj+EhFO9Aq+xhMjJ1OOLtNAPoYJyatEVgJkILb6M26igTFcuI60xBbGNmh5ZYeyRdn5/xFb7G2zyJ2Swc3PvN1uLzMHfTF0R7WzGq4CRNGIOjrHTGncyB3IGAONOdJdM3iT9XKY6cdlRK0VkQjEsEMe0eNv2fxxLVSGna4sdJoTND6LhJ6qCfuS9DEDXwoRdLxAXxefycCh9VNp7gloMJx8IbHYxOW0BFZqc3hxNU9X2SwOj6j72DZMrdYDg2aPAW69HG0iMontQ37Di87JEW2F2Cpgb49+4twByrQNIx+st+DGNce1vpc0DN+KuJVdIcmha654lT7Ffe8=
|