brainzlab 0.1.24 → 0.1.25

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6ab7b5c063e4371cad8decac72f4f0508c3ad4da1fedd8041a97c2f6601ee601
4
- data.tar.gz: c3af39c85de1dee2a20cc4586809c5e7634fe8aa85f4145716b56e342119e48b
3
+ metadata.gz: e904bb588651bb7902dad92287cd8965c3bf4eb2f744b0e325c2e60239d135df
4
+ data.tar.gz: b0b3116d3d81af097d0f88563e6a4e93f6d0cd02ee2a9c8423ee86bd2b0eb14c
5
5
  SHA512:
6
- metadata.gz: 5581a93b79f51388c3d0ea6c5a1681418618bafbabfdb6e688210e7ae07cdf5d1a047fb414434c5f5171b95363734197555b5be6a2b6ad4c7f75cdf5740ce61f
7
- data.tar.gz: 3a71004cb62f9a74fb3fdd5979da80757ffd06b30461bfb970217fb972c01c92904db9949bf52a7b48e4d5b5c20f2f745e63b908b4d49ea5c84ce3bebcc0e553
6
+ metadata.gz: a0bc7313cc6650ad775914d76de538508744e3da8cda7e319777a9fc7fdc0c2d77336b0c53f0f3db172ac686e23539e94b077c0f1641fcf9828d22dbed520740
7
+ data.tar.gz: a84b9e3ce514e58105803243d8f4d608f22643dc2ac73affa8a2c89107383b7f8088a793016c1026ef9577bb4de39e75e85bee79c6574a533b3828e910a5ce0b
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.1.25] - 2026-06-07
6
+
7
+ ### Added
8
+
9
+ - **`BrainzLab::Cortex` management ("send") operations** — the Cortex client can now write feature flags, not just read them:
10
+ - `Cortex.create_flag(:key, name:, type:, description:, tags:)` → `POST /api/v1/flags`
11
+ - `Cortex.enable!(:key, environment:)` / `Cortex.disable!(:key, environment:)` → idempotent `POST /api/v1/flags/:key/toggle` with an explicit `enabled` flag
12
+ - `Cortex.set_percentage(:key, pct, environment:)` → `POST /api/v1/flags/:key/set_percentage`
13
+ - Writes clear the local flag cache. Reads (`enabled?`/`get`/`variant`/`all`/`list_flags`) and provisioning (`POST /api/v1/projects/provision`) now align with the Cortex service contract.
14
+
5
15
  ## [0.1.13] - 2026-02-24
6
16
 
7
17
  ### Fixed
@@ -75,6 +75,50 @@ module BrainzLab
75
75
  nil
76
76
  end
77
77
 
78
+ # Create (push) a flag definition. Returns the created flag hash or nil.
79
+ def create_flag(attrs)
80
+ response = request(:post, '/api/v1/flags', body: { flag: attrs })
81
+
82
+ return nil unless created_or_ok?(response)
83
+
84
+ JSON.parse(response.body, symbolize_names: true)[:flag]
85
+ rescue StandardError => e
86
+ log_error('create_flag', e)
87
+ nil
88
+ end
89
+
90
+ # Set a flag's enabled state in an environment. Returns the new state or nil.
91
+ def toggle(flag_name, enabled:, environment:)
92
+ response = request(
93
+ :post,
94
+ "/api/v1/flags/#{CGI.escape(flag_name)}/toggle",
95
+ body: { enabled: enabled, environment: environment }
96
+ )
97
+
98
+ return nil unless created_or_ok?(response)
99
+
100
+ JSON.parse(response.body, symbolize_names: true)
101
+ rescue StandardError => e
102
+ log_error('toggle', e)
103
+ nil
104
+ end
105
+
106
+ # Set a percentage flag's rollout in an environment. Returns the new state or nil.
107
+ def set_percentage(flag_name, percentage:, environment:)
108
+ response = request(
109
+ :post,
110
+ "/api/v1/flags/#{CGI.escape(flag_name)}/set_percentage",
111
+ body: { percentage: percentage, environment: environment }
112
+ )
113
+
114
+ return nil unless created_or_ok?(response)
115
+
116
+ JSON.parse(response.body, symbolize_names: true)
117
+ rescue StandardError => e
118
+ log_error('set_percentage', e)
119
+ nil
120
+ end
121
+
78
122
  def provision(project_id:, app_name:)
79
123
  response = request(
80
124
  :post,
@@ -91,6 +135,10 @@ module BrainzLab
91
135
 
92
136
  private
93
137
 
138
+ def created_or_ok?(response)
139
+ response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPCreated)
140
+ end
141
+
94
142
  def request(method, path, headers: {}, body: nil, params: nil, use_service_key: false)
95
143
  uri = URI.parse("#{@base_url}#{path}")
96
144
 
@@ -123,6 +123,52 @@ module BrainzLab
123
123
  client.get_flag(flag_name.to_s)
124
124
  end
125
125
 
126
+ # === Management ("send" / write operations) ===
127
+
128
+ # Create (push) a new feature flag definition.
129
+ # @param flag_name [String, Symbol] flag key (lowercase, underscores)
130
+ # @param name [String] human-readable name (defaults to the key)
131
+ # @param type [String] boolean | percentage | variant | segment
132
+ # @return [Hash, nil] the created flag, or nil if disabled/unconfigured
133
+ #
134
+ # @example
135
+ # BrainzLab::Cortex.create_flag(:new_checkout, name: "New Checkout")
136
+ def create_flag(flag_name, name: nil, type: 'boolean', description: nil, tags: [])
137
+ return nil unless writable?
138
+
139
+ client.create_flag(
140
+ key: flag_name.to_s,
141
+ name: name || flag_name.to_s,
142
+ flag_type: type,
143
+ description: description,
144
+ tags: tags
145
+ )
146
+ end
147
+
148
+ # Enable a flag in an environment (idempotent).
149
+ # @return [Hash, nil] the new state, or nil if disabled/unconfigured
150
+ def enable!(flag_name, environment: nil)
151
+ set_enabled(flag_name, true, environment: environment)
152
+ end
153
+
154
+ # Disable a flag in an environment (idempotent).
155
+ def disable!(flag_name, environment: nil)
156
+ set_enabled(flag_name, false, environment: environment)
157
+ end
158
+
159
+ # Set the rollout percentage (0-100) for a percentage flag.
160
+ def set_percentage(flag_name, percentage, environment: nil)
161
+ return nil unless writable?
162
+
163
+ result = client.set_percentage(
164
+ flag_name.to_s,
165
+ percentage: percentage,
166
+ environment: environment || BrainzLab.configuration.environment
167
+ )
168
+ clear_cache!
169
+ result
170
+ end
171
+
126
172
  # Clear the flag cache
127
173
  def clear_cache!
128
174
  cache.clear!
@@ -186,6 +232,26 @@ module BrainzLab
186
232
  BrainzLab.configuration.cortex_enabled
187
233
  end
188
234
 
235
+ # Write operations require the module on, a provisioned project, and a key.
236
+ def writable?
237
+ return false unless module_enabled?
238
+
239
+ ensure_provisioned!
240
+ BrainzLab.configuration.cortex_valid?
241
+ end
242
+
243
+ def set_enabled(flag_name, enabled, environment:)
244
+ return nil unless writable?
245
+
246
+ result = client.toggle(
247
+ flag_name.to_s,
248
+ enabled: enabled,
249
+ environment: environment || BrainzLab.configuration.environment
250
+ )
251
+ clear_cache!
252
+ result
253
+ end
254
+
189
255
  def merge_context(context)
190
256
  default_context = BrainzLab.configuration.cortex_default_context || {}
191
257
  thread_context = Thread.current[:cortex_context] || {}
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BrainzLab
4
- VERSION = '0.1.24'
4
+ VERSION = '0.1.25'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brainzlab
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.24
4
+ version: 0.1.25
5
5
  platform: ruby
6
6
  authors:
7
7
  - BrainzLab