Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: new GO Feature Flag ruby provider #38

Merged
merged 19 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
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
24 changes: 23 additions & 1 deletion .github/workflows/ruby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
working-directory: ./providers/openfeature-flagd-provider
- name: Launch flagd instance
run: docker-compose up -d flagd
run: docker compose up -d flagd
thomaspoignant marked this conversation as resolved.
Show resolved Hide resolved
working-directory: ./providers/openfeature-flagd-provider/docker
- name: Check linting
run: bundle exec rubocop
Expand All @@ -64,3 +64,25 @@ jobs:
working-directory: ./providers/openfeature-meta_provider
- name: Lint and test
run: bin/rake

test_go_feature_flag_provider:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./providers/openfeature-go-feature-flag-provider
strategy:
matrix:
ruby-version:
- "3.3"
- "3.2"
- "3.1"
steps:
- uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
working-directory: ./providers/openfeature-go-feature-flag-provider
- name: Lint and test
run: bin/rake
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,6 @@ build-iPhoneSimulator/
# .rubocop-https?--*

.DS_Store

# Ignore jetbrains files
.idea/
3 changes: 2 additions & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"providers/openfeature-flagd-provider": "0.1.1",
"providers/openfeature-meta_provider": "0.0.3"
"providers/openfeature-meta_provider": "0.0.3",
"providers/openfeature-go-feature-flag-provider": "0.1.0"
}
5 changes: 5 additions & 0 deletions providers/openfeature-go-feature-flag-provider/.rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
inherit_from: ../../shared_config/.rubocop.yml

inherit_mode:
merge:
- Exclude
3 changes: 3 additions & 0 deletions providers/openfeature-go-feature-flag-provider/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
source "https://rubygems.org"

gemspec
104 changes: 104 additions & 0 deletions providers/openfeature-go-feature-flag-provider/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
PATH
remote: .
specs:
openfeature-go-feature-flag-provider (0.1.0)
openfeature-sdk (~> 0.3.1)

GEM
remote: https://rubygems.org/
specs:
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
ast (2.4.2)
bigdecimal (3.1.8)
crack (1.0.0)
bigdecimal
rexml
diff-lcs (1.5.1)
docile (1.4.1)
hashdiff (1.1.1)
json (2.7.2)
language_server-protocol (3.17.0.3)
lint_roller (1.1.0)
openfeature-sdk (0.3.1)
parallel (1.24.0)
parser (3.3.0.5)
ast (~> 2.4.1)
racc
public_suffix (6.0.1)
racc (1.7.3)
rainbow (3.1.1)
rake (13.2.1)
regexp_parser (2.9.0)
rexml (3.3.4)
strscan
rspec (3.12.0)
rspec-core (~> 3.12.0)
rspec-expectations (~> 3.12.0)
rspec-mocks (~> 3.12.0)
rspec-core (3.12.3)
rspec-support (~> 3.12.0)
rspec-expectations (3.12.4)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-mocks (3.12.7)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-support (3.12.2)
rubocop (1.62.1)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.31.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.31.2)
parser (>= 3.3.0.4)
rubocop-performance (1.20.2)
rubocop (>= 1.48.1, < 2.0)
rubocop-ast (>= 1.30.0, < 2.0)
ruby-progressbar (1.13.0)
simplecov (0.22.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
simplecov_json_formatter (~> 0.1)
simplecov-html (0.12.3)
simplecov_json_formatter (0.1.4)
standard (1.35.1)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.0)
rubocop (~> 1.62.0)
standard-custom (~> 1.0.0)
standard-performance (~> 1.3)
standard-custom (1.0.2)
lint_roller (~> 1.0)
rubocop (~> 1.50)
standard-performance (1.3.1)
lint_roller (~> 1.1)
rubocop-performance (~> 1.20.2)
strscan (3.1.0)
unicode-display_width (2.5.0)
webmock (3.23.1)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)

PLATFORMS
arm64-darwin-23
ruby

DEPENDENCIES
openfeature-go-feature-flag-provider!
rake (~> 13.0)
rspec (~> 3.12.0)
rubocop
simplecov
standard
webmock

BUNDLED WITH
2.5.11
128 changes: 128 additions & 0 deletions providers/openfeature-go-feature-flag-provider/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<p align="center">
<img width="400" src="https://raw.githubusercontent.com/thomaspoignant/go-feature-flag/main/gofeatureflag.svg" alt="go-feature-flag logo" />

</p>

# GO Feature Flag - OpenFeature Ruby provider
<p align="center">
<a href="https://github.com/open-feature/ruby-sdk-contrib/tree/main/providers/openfeature-go-feature-flag-provider"><img src="https://img.shields.io/gem/v/openfeature-go-feature-flag-provider?color=blue&style=flat-square&logo=ruby" alt="gem"></a>
<a href="https://gofeatureflag.org/"><img src="https://img.shields.io/badge/%F0%9F%93%92-Website-blue" alt="Documentation"></a>
<a href="https://github.com/thomaspoignant/go-feature-flag/issues"><img src="https://img.shields.io/badge/%E2%9C%8F%EF%B8%8F-issues-red" alt="Issues"></a>
<a href="https://gofeatureflag.org/slack"><img src="https://img.shields.io/badge/join-us%20on%20slack-gray.svg?longCache=true&logo=slack&colorB=green" alt="Join us on slack"></a>
</p>

This repository contains the official Ruby OpenFeature provider for accessing your feature flags with [GO Feature Flag](https://gofeatureflag.org).

In conjunction with the [OpenFeature SDK](https://openfeature.dev/docs/reference/concepts/provider) you will be able
to evaluate your feature flags in your Ruby applications.

For documentation related to flags management in GO Feature Flag,
refer to the [GO Feature Flag documentation website](https://gofeatureflag.org/docs).

### Functionalities:
- Manage the integration of the OpenFeature Ruby SDK and GO Feature Flag relay-proxy.

## Dependency Setup

### Gem Package Manager

Add this line to your application's Gemfile:
```
gem 'openfeature-go-feature-flag-provider'
```
And then execute:
```
bundle install
```
Or install it yourself as:
```
gem install openfeature-go-feature-flag-provider
```

## Getting started

### Initialize the provider

The `OpenFeature::GoFeatureFlag::Provider` needs some options to be created and then set in the OpenFeature SDK.

| **Option** | **Description** |
|------------|---------------------------------------------------------------------------------------------------------------------------------------------|
| `endpoint` | **(mandatory)** The URL to access to the relay-proxy.<br />*(example: `https://relay.proxy.gofeatureflag.org/`)* |
| `headers` | A `Hash` object containing the headers to send to the relay-proxy.<br/>*(example to send APIKey: `{"Authorization" => "Bearer my-api-key"}` |

The only required option to create a `GoFeatureFlagProvider` is the URL _(`endpoint`)_ to your GO Feature Flag relay-proxy instance.

```ruby
options = OpenFeature::GoFeatureFlag::Options.new(endpoint: "http://localhost:1031")
provider = OpenFeature::GoFeatureFlag::Provider.new(options: options)

evaluation_context = OpenFeature::SDK::EvaluationContext.new(targeting_key: "9b9450f8-ab5c-4dcf-872f-feda3f6ccb16")

OpenFeature::SDK.configure do |config|
config.set_provider(provider)
end
client = OpenFeature::SDK.build_client()

bool_value = client.fetch_boolean_value(
flag_key: "my-boolean-flag",
default_value: false,
evaluation_context: evaluation_context
)
thomaspoignant marked this conversation as resolved.
Show resolved Hide resolved
thomaspoignant marked this conversation as resolved.
Show resolved Hide resolved

if bool_value
puts "The flag is enabled"
else
puts "The flag is disabled"
end
```

The evaluation context is the way for the client to specify contextual data that GO Feature Flag uses to evaluate the feature flags, it allows to define rules on the flag.

The `targeting_key` is mandatory for GO Feature Flag to evaluate the feature flag, it could be the id of a user, a session ID or anything you find relevant to use as identifier during the evaluation.


### Evaluate a feature flag
The client is used to retrieve values for the current `EvaluationContext`.
For example, retrieving a boolean value for the flag **"my-flag"**:

```ruby
client = OpenFeature::SDK.build_client()

bool_value = client.fetch_boolean_value(
flag_key: "my-boolean-flag",
default_value: false,
evaluation_context: evaluation_context
)
```

GO Feature Flag supports different all OpenFeature supported types of feature flags, it means that you can use all the accessor directly
```ruby
# Bool
client.fetch_boolean_value(flag_key: 'my-flag', default_value: false, evaluation_context: evaluation_context)

# String
client.fetch_string_value(flag_key: 'my-flag', default_value: "default", evaluation_context: evaluation_context)

# Number
client.fetch_number_value(flag_key: 'my-flag', default_value: 0, evaluation_context: evaluation_context)

# Object
client.fetch_object_value(flag_key: 'my-flag', default_value: {"default" => true}, evaluation_context: evaluation_context)
thomaspoignant marked this conversation as resolved.
Show resolved Hide resolved
```

## Features status

| Status | Feature | Description |
|--------|-----------------|----------------------------------------------------------------------------|
| ✅ | Flag evaluation | It is possible to evaluate all the type of flags |
| ❌ | Caching | Mechanism is in place to refresh the cache in case of configuration change |
| ❌ | Event Streaming | Not supported by the SDK |
| ❌ | Logging | Not supported by the SDK |
| ✅ | Flag Metadata | You can retrieve your flag metadata directly in the evaluation details. |


<sub>**Implemented**: ✅ | In-progress: ⚠️ | Not implemented yet: ❌</sub>

## Contributing
This project welcomes contributions from the community.
If you're interested in contributing, see the [contributors' guide](https://github.com/thomaspoignant/go-feature-flag/blob/main/CONTRIBUTING.md) for some helpful tips.
10 changes: 10 additions & 0 deletions providers/openfeature-go-feature-flag-provider/Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

require "bundler/gem_tasks"
require "rspec/core/rake_task"

RSpec::Core::RakeTask.new(:spec)

require "standard/rake"

task default: %i[standard spec]
27 changes: 27 additions & 0 deletions providers/openfeature-go-feature-flag-provider/bin/rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

#
# This file was generated by Bundler.
#
# The application 'rake' is installed as part of a gem, and
# this file is here to facilitate running it.
#

ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)

bundle_binstub = File.expand_path("bundle", __dir__)

if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
load(bundle_binstub)
else
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
end
end

require "rubygems"
require "bundler/setup"

load Gem.bin_path("rake", "rake")
Loading