Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions .github/workflows/ruby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
- '3.4'

steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
Comment thread
msiebert marked this conversation as resolved.
- name: Set up Ruby
uses: ruby/setup-ruby@d697be2f83c6234b20877c3b5eac7a7f342f0d0c # v1.269.0
with:
Expand All @@ -31,7 +31,36 @@ jobs:
- name: Run tests
run: bundle exec rake
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: mixpanel/mixpanel-ruby

test-openfeature:

runs-on: ubuntu-latest
strategy:
matrix:
ruby-version:
- '3.1'
- '3.2'
- '3.3'
- '3.4'

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Set up Ruby
uses: ruby/setup-ruby@d697be2f83c6234b20877c3b5eac7a7f342f0d0c # v1.269.0
with:
ruby-version: ${{ matrix.ruby-version }}
- name: Install dependencies
run: cd openfeature-provider && bundle install
- name: Run OpenFeature provider tests
run: cd openfeature-provider && bundle exec rspec
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: mixpanel/mixpanel-ruby
flags: openfeature
directory: openfeature-provider
20 changes: 12 additions & 8 deletions lib/mixpanel-ruby/flags/flags_provider.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,25 +56,29 @@ def call_flags_endpoint(additional_params = nil)
request.basic_auth(@provider_config[:token], '')

request['Content-Type'] = 'application/json'
request['traceparent'] = Utils.generate_traceparent()
request['traceparent'] = Utils.generate_traceparent

begin
response = http.request(request)
rescue Net::OpenTimeout, Net::ReadTimeout => e
raise ConnectionError.new("Request timeout: #{e.message}")
rescue StandardError => e
raise ConnectionError.new("Network error: #{e.message}")
end

unless response.code.to_i == 200
raise ServerError.new("HTTP #{response.code}: #{response.body}")
end
unless response.code == '200'
raise ServerError.new("HTTP #{response.code}: #{response.body}")
end

begin
JSON.parse(response.body)
rescue Net::OpenTimeout, Net::ReadTimeout => e
raise ConnectionError.new("Request timeout: #{e.message}")
rescue JSON::ParserError => e
raise ServerError.new("Invalid JSON response: #{e.message}")
rescue StandardError => e
raise ConnectionError.new("Network error: #{e.message}")
end
end

def shutdown; end

# Track exposure event to Mixpanel
# @param flag_key [String] Feature flag key
# @param selected_variant [SelectedVariant] The selected variant
Expand Down
41 changes: 19 additions & 22 deletions lib/mixpanel-ruby/flags/local_flags_provider.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ def stop_polling_for_definitions!
@polling_thread = nil
end

def shutdown
stop_polling_for_definitions!
end

# Check if flag is enabled (for boolean flags)
# @param flag_key [String] Feature flag key
# @param context [Hash] Evaluation context (must include 'distinct_id')
Expand Down Expand Up @@ -107,24 +111,17 @@ def get_variant(flag_key, fallback_variant, context, report_exposure: true)

context_value = context[context_key] || context[context_key.to_sym]

selected_variant = nil
selected_variant = get_variant_override_for_test_user(flag, context)

test_variant = get_variant_override_for_test_user(flag, context)
if test_variant
selected_variant = test_variant
else
unless selected_variant
rollout = get_assigned_rollout(flag, context_value, context)
if rollout
selected_variant = get_assigned_variant(flag, context_value, flag_key, rollout)
end
selected_variant = get_assigned_variant(flag, context_value, flag_key, rollout) if rollout
end

if selected_variant
track_exposure_event(flag_key, selected_variant, context) if report_exposure
return selected_variant
end
return fallback_variant unless selected_variant

fallback_variant
track_exposure_event(flag_key, selected_variant, context) if report_exposure
selected_variant
end

# Get all variants for user context
Expand All @@ -147,11 +144,9 @@ def get_all_variants(context)
def fetch_flag_definitions
response = call_flags_endpoint

new_definitions = {}
(response['flags'] || []).each do |flag_data|
new_definitions[flag_data['key']] = flag_data
new_definitions = (response['flags'] || []).each_with_object({}) do |flag_data, definitions|
definitions[flag_data['key']] = flag_data
end

@flag_definitions = new_definitions

response
Expand All @@ -175,9 +170,10 @@ def get_variant_override_for_test_user(flag, context)
end

def get_matching_variant(variant_key, flag)
return nil unless flag['ruleset'] && flag['ruleset']['variants']
variants = flag.dig('ruleset', 'variants')
return nil unless variants

flag['ruleset']['variants'].each do |v|
variants.each do |v|
if variant_key.downcase == v['key'].downcase
return SelectedVariant.new(
variant_key: v['key'],
Expand All @@ -191,9 +187,10 @@ def get_matching_variant(variant_key, flag)
end

def get_assigned_rollout(flag, context_value, context)
return nil unless flag['ruleset'] && flag['ruleset']['rollout']
rollouts = flag.dig('ruleset', 'rollout')
return nil unless rollouts

flag['ruleset']['rollout'].each_with_index do |rollout, index|
rollouts.each_with_index do |rollout, index|
salt = if flag['hash_salt']
"#{flag['key']}#{flag['hash_salt']}#{index}"
else
Expand Down Expand Up @@ -224,7 +221,7 @@ def get_assigned_variant(flag, context_value, flag_key, rollout)
salt = "#{flag_key}#{stored_salt}variant"
variant_hash = Utils.normalized_hash(context_value.to_s, salt)

variants = flag['ruleset']['variants'].map { |v| v.dup }
variants = flag['ruleset']['variants'].map(&:dup)
if rollout['variant_splits']
variants.each do |v|
v['split'] = rollout['variant_splits'][v['key']] if rollout['variant_splits'].key?(v['key'])
Expand Down
2 changes: 1 addition & 1 deletion lib/mixpanel-ruby/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Mixpanel
VERSION = '3.0.0'
VERSION = '3.1.0'
end
7 changes: 7 additions & 0 deletions openfeature-provider/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

source 'https://rubygems.org'

gemspec

gem 'mixpanel-ruby', path: '..'
Loading
Loading