smplkit 1.0.13 → 1.0.15
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/README.md +14 -3
- data/lib/smplkit/_generated/app/lib/smplkit_app_client/configuration.rb +1 -1
- data/lib/smplkit/_generated/config/lib/smplkit_config_client/configuration.rb +1 -1
- data/lib/smplkit/_generated/flags/lib/smplkit_flags_client/configuration.rb +1 -1
- data/lib/smplkit/_generated/flags/lib/smplkit_flags_client/models/flag_environment.rb +1 -1
- data/lib/smplkit/_generated/logging/lib/smplkit_logging_client/configuration.rb +1 -1
- data/lib/smplkit/client.rb +26 -17
- data/lib/smplkit/config/helpers.rb +0 -26
- data/lib/smplkit/config_resolution.rb +6 -4
- data/lib/smplkit/errors.rb +2 -2
- data/lib/smplkit/flags/helpers.rb +0 -24
- data/lib/smplkit/flags/models.rb +1 -1
- data/lib/smplkit/logging/client.rb +4 -0
- data/lib/smplkit/logging/helpers.rb +0 -26
- data/lib/smplkit/management/client.rb +366 -215
- data/lib/smplkit/ws.rb +9 -5
- data/lib/smplkit.rb +23 -0
- data/sig/smplkit/config.rbs +78 -0
- data/sig/smplkit/flags.rbs +93 -0
- data/sig/smplkit/logging.rbs +92 -0
- data/sig/smplkit/management.rbs +123 -0
- metadata +50 -14
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d5d5ed1af296c517f09ddd0a76660b157184f3bb763a61ae0fcf727c1a3f5a87
|
|
4
|
+
data.tar.gz: 487bcd0200af912fcbb1acdf52967e87bf485c1b1ced27fb564cfc96ac4ee41b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 78bd324f3ab4c18732cf2a0a4bbef41f761ebf347501d721b941083ee4a06657bbd5f3c48e0113e63522515ed5b15566b47ecc727613925b8df866b4459d4f6e
|
|
7
|
+
data.tar.gz: f66aa64fdd45800335739c0d5a8fda29e4b8c51d70c94f5412ee1bdc44f09d161ded9eefd5c9252f438796c2063d53dcdad870dd949b4d2872b9751b6c54d974
|
data/README.md
CHANGED
|
@@ -100,12 +100,23 @@ This creates `config/initializers/smplkit.rb` with documented examples for the p
|
|
|
100
100
|
|
|
101
101
|
```bash
|
|
102
102
|
bundle install
|
|
103
|
-
bundle exec rspec # unit tests
|
|
103
|
+
bundle exec rspec # unit tests — wrapper layer is held to 100% line coverage in CI
|
|
104
104
|
bundle exec rubocop # lint
|
|
105
|
-
make generate # regenerate clients
|
|
105
|
+
make generate # regenerate clients
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
`make generate` shells out to `npx --yes @openapitools/openapi-generator-cli`,
|
|
109
|
+
so it requires:
|
|
110
|
+
|
|
111
|
+
- Node.js 18+ (provides `npx`)
|
|
112
|
+
- A JRE 11+ (the openapi-generator JAR runs under Java)
|
|
113
|
+
|
|
114
|
+
Both are pre-installed on the CI matrix runners. On a developer machine,
|
|
115
|
+
install via Homebrew (`brew install node openjdk`) or your distribution's
|
|
116
|
+
package manager.
|
|
117
|
+
|
|
118
|
+
The repository follows the standard smplkit "every commit lands on `main`"
|
|
119
|
+
workflow — see CLAUDE.md.
|
|
109
120
|
|
|
110
121
|
## License
|
|
111
122
|
|
|
@@ -181,7 +181,7 @@ module SmplkitGeneratedClient::App
|
|
|
181
181
|
@ignore_operation_servers = false
|
|
182
182
|
@inject_format = false
|
|
183
183
|
@force_ending_format = false
|
|
184
|
-
@logger = defined?(Rails) ? Rails.logger : Logger.new(
|
|
184
|
+
@logger = defined?(Rails) ? Rails.logger : ::Logger.new($stdout)
|
|
185
185
|
|
|
186
186
|
yield(self) if block_given?
|
|
187
187
|
end
|
|
@@ -181,7 +181,7 @@ module SmplkitGeneratedClient::Config
|
|
|
181
181
|
@ignore_operation_servers = false
|
|
182
182
|
@inject_format = false
|
|
183
183
|
@force_ending_format = false
|
|
184
|
-
@logger = defined?(Rails) ? Rails.logger : Logger.new(
|
|
184
|
+
@logger = defined?(Rails) ? Rails.logger : ::Logger.new($stdout)
|
|
185
185
|
|
|
186
186
|
yield(self) if block_given?
|
|
187
187
|
end
|
|
@@ -181,7 +181,7 @@ module SmplkitGeneratedClient::Flags
|
|
|
181
181
|
@ignore_operation_servers = false
|
|
182
182
|
@inject_format = false
|
|
183
183
|
@force_ending_format = false
|
|
184
|
-
@logger = defined?(Rails) ? Rails.logger : Logger.new(
|
|
184
|
+
@logger = defined?(Rails) ? Rails.logger : ::Logger.new($stdout)
|
|
185
185
|
|
|
186
186
|
yield(self) if block_given?
|
|
187
187
|
end
|
|
@@ -181,7 +181,7 @@ module SmplkitGeneratedClient::Logging
|
|
|
181
181
|
@ignore_operation_servers = false
|
|
182
182
|
@inject_format = false
|
|
183
183
|
@force_ending_format = false
|
|
184
|
-
@logger = defined?(Rails) ? Rails.logger : Logger.new(
|
|
184
|
+
@logger = defined?(Rails) ? Rails.logger : ::Logger.new($stdout)
|
|
185
185
|
|
|
186
186
|
yield(self) if block_given?
|
|
187
187
|
end
|
data/lib/smplkit/client.rb
CHANGED
|
@@ -31,8 +31,8 @@ module Smplkit
|
|
|
31
31
|
attr_reader :manage, :config, :flags, :logging
|
|
32
32
|
|
|
33
33
|
# Construct, yield to the block, and close on exit.
|
|
34
|
-
def self.open(**)
|
|
35
|
-
client = new(**)
|
|
34
|
+
def self.open(**kwargs)
|
|
35
|
+
client = new(**kwargs)
|
|
36
36
|
begin
|
|
37
37
|
yield client
|
|
38
38
|
ensure
|
|
@@ -185,19 +185,23 @@ module Smplkit
|
|
|
185
185
|
|
|
186
186
|
def schedule_periodic_flush
|
|
187
187
|
@flush_timer = Concurrent::TimerTask.new(execution_interval: PERIODIC_FLUSH_INTERVAL) do
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
begin
|
|
191
|
-
@manage.contexts.flush
|
|
192
|
-
@manage.flags.flush
|
|
193
|
-
@manage.loggers.flush
|
|
194
|
-
rescue StandardError => e
|
|
195
|
-
Smplkit.debug("registration", "periodic flush failed: #{e.class}: #{e.message}")
|
|
196
|
-
end
|
|
188
|
+
run_periodic_flush
|
|
197
189
|
end
|
|
198
190
|
@flush_timer.execute
|
|
199
191
|
end
|
|
200
192
|
|
|
193
|
+
# Extracted as a private method so the timer body is reachable from
|
|
194
|
+
# tests without poking into Concurrent::TimerTask internals.
|
|
195
|
+
def run_periodic_flush
|
|
196
|
+
return if @closed
|
|
197
|
+
|
|
198
|
+
@manage.contexts.flush
|
|
199
|
+
@manage.flags.flush
|
|
200
|
+
@manage.loggers.flush
|
|
201
|
+
rescue StandardError => e
|
|
202
|
+
Smplkit.debug("registration", "periodic flush failed: #{e.class}: #{e.message}")
|
|
203
|
+
end
|
|
204
|
+
|
|
201
205
|
def final_flush
|
|
202
206
|
[@manage.contexts, @manage.flags, @manage.loggers].each do |ns|
|
|
203
207
|
ns.flush
|
|
@@ -206,13 +210,18 @@ module Smplkit
|
|
|
206
210
|
end
|
|
207
211
|
end
|
|
208
212
|
|
|
209
|
-
def register_service_context(
|
|
210
|
-
#
|
|
211
|
-
#
|
|
212
|
-
#
|
|
213
|
-
#
|
|
213
|
+
def register_service_context(mgmt, env, svc, app_url)
|
|
214
|
+
# Bulk-register the environment + service as +Smplkit::Context+
|
|
215
|
+
# instances on the platform so they show up in the Console alongside
|
|
216
|
+
# any user-provided contexts. The buffer dedupes on +(type, key)+, so
|
|
217
|
+
# this is safe to call on every client construction.
|
|
218
|
+
contexts = []
|
|
219
|
+
contexts << Smplkit::Context.new("environment", env) if env
|
|
220
|
+
contexts << Smplkit::Context.new("service", svc, name: svc) if svc
|
|
221
|
+
mgmt.contexts.register(contexts)
|
|
222
|
+
mgmt.contexts.flush
|
|
214
223
|
rescue StandardError => e
|
|
215
|
-
Smplkit.debug("lifecycle", "register service context failed: #{e.class}: #{e.message}")
|
|
224
|
+
Smplkit.debug("lifecycle", "register service context failed (app: #{app_url}): #{e.class}: #{e.message}")
|
|
216
225
|
end
|
|
217
226
|
end
|
|
218
227
|
end
|
|
@@ -40,32 +40,6 @@ module Smplkit
|
|
|
40
40
|
)
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
def build_config_request_body(config)
|
|
44
|
-
items = {}
|
|
45
|
-
config.items.each do |item|
|
|
46
|
-
items[item.name] = {
|
|
47
|
-
"value" => item.value,
|
|
48
|
-
"type" => item.type,
|
|
49
|
-
"description" => item.description
|
|
50
|
-
}.compact
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
environments = config.environments.each_with_object({}) do |(env, env_obj), out|
|
|
54
|
-
out[env] = { "values" => env_obj.values_raw }
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# The Config schema (per the OpenAPI spec) does not include +key+ in
|
|
58
|
-
# attributes — the resource +id+ carries the customer-facing key.
|
|
59
|
-
attributes = {
|
|
60
|
-
"name" => config.name,
|
|
61
|
-
"description" => config.description,
|
|
62
|
-
"parent" => config.parent_id,
|
|
63
|
-
"items" => items,
|
|
64
|
-
"environments" => environments
|
|
65
|
-
}.compact
|
|
66
|
-
{ "data" => { "type" => "config", "id" => config.key, "attributes" => attributes } }
|
|
67
|
-
end
|
|
68
|
-
|
|
69
43
|
# Deep-merge two Hashes, with +override+ winning. Mirrors the Python
|
|
70
44
|
# +deep_merge+ helper used by the resolver.
|
|
71
45
|
def deep_merge(base, override)
|
|
@@ -28,12 +28,14 @@ module Smplkit
|
|
|
28
28
|
"telemetry" => true
|
|
29
29
|
}.freeze
|
|
30
30
|
|
|
31
|
-
ResolvedConfig =
|
|
32
|
-
:api_key, :base_domain, :scheme, :environment, :service, :debug, :telemetry
|
|
31
|
+
ResolvedConfig = Struct.new(
|
|
32
|
+
:api_key, :base_domain, :scheme, :environment, :service, :debug, :telemetry,
|
|
33
|
+
keyword_init: true
|
|
33
34
|
)
|
|
34
35
|
|
|
35
|
-
ResolvedManagementConfig =
|
|
36
|
-
:api_key, :base_domain, :scheme, :debug
|
|
36
|
+
ResolvedManagementConfig = Struct.new(
|
|
37
|
+
:api_key, :base_domain, :scheme, :debug,
|
|
38
|
+
keyword_init: true
|
|
37
39
|
)
|
|
38
40
|
|
|
39
41
|
module_function
|
data/lib/smplkit/errors.rb
CHANGED
|
@@ -47,30 +47,6 @@ module Smplkit
|
|
|
47
47
|
rules: rules
|
|
48
48
|
)
|
|
49
49
|
end
|
|
50
|
-
|
|
51
|
-
# Build the JSON body for a Flag create/update request.
|
|
52
|
-
def build_flag_request_body(flag)
|
|
53
|
-
environments = flag.environments.each_with_object({}) do |(env_key, env), out|
|
|
54
|
-
out[env_key] = {
|
|
55
|
-
"enabled" => env.enabled,
|
|
56
|
-
"default" => env.default,
|
|
57
|
-
"rules" => env.rules.map { |r| { "logic" => r.logic, "value" => r.value, "description" => r.description } }
|
|
58
|
-
}
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
attributes = {
|
|
62
|
-
"id" => flag.id,
|
|
63
|
-
"name" => flag.name,
|
|
64
|
-
"type" => flag.type,
|
|
65
|
-
"default" => flag.default,
|
|
66
|
-
"description" => flag.description,
|
|
67
|
-
"environments" => environments
|
|
68
|
-
}
|
|
69
|
-
values = flag.values
|
|
70
|
-
attributes["values"] = values.map { |v| { "name" => v.name, "value" => v.value } } if values
|
|
71
|
-
|
|
72
|
-
{ "data" => { "type" => "flag", "id" => flag.id, "attributes" => attributes.compact } }
|
|
73
|
-
end
|
|
74
50
|
end
|
|
75
51
|
end
|
|
76
52
|
end
|
data/lib/smplkit/flags/models.rb
CHANGED
|
@@ -6,7 +6,7 @@ module Smplkit
|
|
|
6
6
|
#
|
|
7
7
|
# Lives in +Flag#values+. Frozen — author values via +Flag#add_value+ /
|
|
8
8
|
# +Flag#remove_value+ / +Flag#clear_values+.
|
|
9
|
-
FlagValue =
|
|
9
|
+
FlagValue = Struct.new(:name, :value, keyword_init: true)
|
|
10
10
|
|
|
11
11
|
# A single targeting rule on a +Flag+.
|
|
12
12
|
#
|
|
@@ -102,7 +102,11 @@ module Smplkit
|
|
|
102
102
|
|
|
103
103
|
return unless @adapters.empty?
|
|
104
104
|
|
|
105
|
+
# :nocov: defensive log — unreachable in practice because stdlib
|
|
106
|
+
# +Logger+ is always present, so +StdlibLoggerAdapter+ is always
|
|
107
|
+
# constructible.
|
|
105
108
|
Smplkit.debug("registration", "no logging adapters loaded; runtime features disabled")
|
|
109
|
+
# :nocov:
|
|
106
110
|
end
|
|
107
111
|
|
|
108
112
|
def observe_logger(_adapter, raw_name, level)
|
|
@@ -38,32 +38,6 @@ module Smplkit
|
|
|
38
38
|
updated_at: attrs["updated_at"]
|
|
39
39
|
)
|
|
40
40
|
end
|
|
41
|
-
|
|
42
|
-
def build_logger_body(logger)
|
|
43
|
-
attributes = {
|
|
44
|
-
"name" => logger.name,
|
|
45
|
-
"resolved_level" => logger.resolved_level&.to_s,
|
|
46
|
-
"level" => logger.level&.to_s,
|
|
47
|
-
"service" => logger.service,
|
|
48
|
-
"environment" => logger.environment,
|
|
49
|
-
"log_group_id" => logger.log_group_id,
|
|
50
|
-
"managed" => logger.managed,
|
|
51
|
-
"description" => logger.description
|
|
52
|
-
}.compact
|
|
53
|
-
{ "data" => { "type" => "logger", "id" => logger.id, "attributes" => attributes } }
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def build_log_group_body(group)
|
|
57
|
-
attributes = {
|
|
58
|
-
"key" => group.key,
|
|
59
|
-
"name" => group.name,
|
|
60
|
-
"level" => group.level&.to_s,
|
|
61
|
-
"description" => group.description,
|
|
62
|
-
"parent_id" => group.parent_id,
|
|
63
|
-
"environments" => group.environments
|
|
64
|
-
}.compact
|
|
65
|
-
{ "data" => { "type" => "log_group", "id" => group.key, "attributes" => attributes } }
|
|
66
|
-
end
|
|
67
41
|
end
|
|
68
42
|
end
|
|
69
43
|
end
|