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.
@@ -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
- fetch
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
- response = Unleash::Util::Http.get(Unleash.configuration.fetch_toggles_url, etag)
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
- response_hash = JSON.parse(response.body)
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
- self.toggle_lock.synchronize do
72
- file = File.open(backup_file_tmp, "w")
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
- rescue StandardError => e
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
- return nil unless File.exist?(Unleash.configuration.backup_file)
106
+ backup_file = Unleash.configuration.backup_file
107
+ return nil unless File.exist?(backup_file)
110
108
 
111
- begin
112
- file = File.new(Unleash.configuration.backup_file, "r")
113
- file_content = file.read
114
-
115
- backup_as_hash = JSON.parse(file_content)
116
- synchronize_with_local_cache!(backup_as_hash)
117
- update_running_client!
118
- rescue IOError => e
119
- Unleash.logger.error "Unable to read the backup_file: #{e}"
120
- rescue JSON::ParserError => e
121
- Unleash.logger.error "Unable to parse JSON from existing backup_file: #{e}"
122
- rescue StandardError => e
123
- Unleash.logger.error "Unable to extract valid data from backup_file. Exception thrown: #{e}"
124
- ensure
125
- file&.close
126
- end
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
@@ -4,17 +4,15 @@ require 'uri'
4
4
  module Unleash
5
5
  module Util
6
6
  module Http
7
- def self.get(url, etag = nil)
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(url, body)
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
- def self.http_headers(etag = nil)
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
- # self.overrides = overrides
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},overrides=#{self.overrides}>"
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
@@ -1,3 +1,3 @@
1
1
  module Unleash
2
- VERSION = "3.2.2".freeze
2
+ VERSION = "4.3.0".freeze
3
3
  end
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
@@ -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 "coveralls", "~> 0.8"
35
- spec.add_development_dependency "rubocop", "~> 0.80"
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.2.2
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: 2021-03-26 00:00:00.000000000 Z
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: coveralls
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: '0.8'
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: '0.8'
124
+ version: 0.21.2
111
125
  - !ruby/object:Gem::Dependency
112
- name: rubocop
126
+ name: simplecov-lcov
113
127
  requirement: !ruby/object:Gem::Requirement
114
128
  requirements:
115
129
  - - "~>"
116
130
  - !ruby/object:Gem::Version
117
- version: '0.80'
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: '0.80'
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.2.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=