codecov

ReleaseFeature

ReleaseFeature is feature toggle.

Installation

Using bundler, please add following line to your Gemfile.

gem 'release_feature'

Using gem

gem install release_feature

If you want to use latest main branch, please add following line to Gemfile.

gem 'release_feature', git: 'https://github.com/junara/release_feature.git', branch: 'main'

And then execute:

$ bundle install

Usage

Prepare client by configuring repository and initialize client.

You can select 4 repository types. From yaml (YamlRepository), hash (HashRepository) or ActiveRecord ( ActiveRecordRepository).

Client can have maximum 2 repositories (called to base_repository and extra_repository). extra_repository is optional.

If extra_repository is set, base_repository is merged by extra_repository. extra_repository setting has priority

Using hash repository

config = { features: { hogehoge_function: { development: { open_at: Time.now, close_at: Time.now + 60 * 60 * 24 * 30 } } } }
hash_repo = ReleaseFeature::Repository::HashRepository.new(hash: config)
client = ReleaseFeature::Client.new(environment: :development, base_repository: hash_repo)
client.permitted?(:hogehoge_function) #=> true
client.permitted?(:hogehoge_function, time: Time.now + 60) #=> true
client.permitted?(:hogehoge_function, time: Time.now - 60 * 60 * 24) #=> false

Using yaml repository

Create yaml in 'release_feature_config.yml'. Write following.

timezone: +09:00
features:
  hoge_feature:
    development:
      open_at: 2000-01-01 00:00
      close_at: 2999-12-31 23:59
    staging:
      open_at: 2030-11-01 10:00
      close_at: 2999-12-31 23:59
    production:
      open_at: 2040-12-01 10:00
      close_at: 2999-12-31 23:59
  puyo_feature:
    development:
      open_at: 2000-01-01 00:00
      close_at: 2999-12-31 23:59
    production:
      open_at: 2022-12-01 10:00
      close_at: 2999-12-31 23:59

Set zone to timezone . zone is defined in https://docs.ruby-lang.org/en/3.1/Time.html

zone: a timezone, which may be: A string offset from UTC. A single letter offset from UTC, in the range 'A'..'Z', 'J' (the so-called military timezone) excluded. An integer number of seconds. A timezone object; see Timezone Argument for details.

path = 'release_feature_config.yml'
yaml_repo = ReleaseFeature::Repository::YamlRepository.new(path: path)
development_client = ReleaseFeature::Client.new(environment: :development, base_repository: yaml_repo)
development_client.permitted?(:hoge_feature) #=> true

staging_client = ReleaseFeature::Client.new(environment: :staging, base_repository: yaml_repo)
staging_client.permitted?(:hoge_feature) #=> false

Using ActiveRecord repository

Model have four attributes (name (:string), environment (:string), open_at (:datetime), close_at (:datetime)

You cac migrate model by command line.

rails g model ReleaseFeatureItem name:string environment:string open_at:datetime close_at:datetime

Above command create following migration file.


class CreateReleaseFeatureItems < ActiveRecord::Migration[7.0]
  def change
    create_table :release_feature_items do |t|
      t.string :name
      t.string :environment
      t.datetime :open_at
      t.datetime :close_at

      t.timestamps
    end
  end
end

And run migrate.

rails db:migrate

Using created ActiveRecord for base_repository like this.

model = ReleaseFeatureItem # migrated by active_record
ReleaseFeatureItem.create!(name: 'hoge_feature', environment: 'development', open_at: '2000-01-01 00:00 +09:00', close_at: '2002-01-01 00:00 +09:00')
ar_repo = ReleaseFeature::Repository::ActiveRecordRepository.new(model: model)
client = ReleaseFeature::Client.new(environment: :development, base_repository: ar_repo)
client.permitted?(:hoge_feature) #=> false

Using "extra_repository"

Document under Construction

extra_repository overrides base_repository.

ex)

base_repository is yaml repository. extra_repository is ActiveRecord repository.

path = 'release_feature_config.yml'
yaml_repo = ReleaseFeature::Repository::YamlRepository.new(path: path)

model = ReleaseFeatureItem # migrated by active_record

ReleaseFeatureItem.create!(name: 'hoge_feature', environment: 'development', open_at: '2000-01-01 00:00 +09:00', close_at: '2002-01-01 00:00 +09:00')
ar_repo = ReleaseFeature::Repository::ActiveRecordRepository.new(model: model)

client = ReleaseFeature::Client.new(environment: :development, base_repository: yaml_repo, extra_repository: ar_repo)

# activerecord_repository override yaml_repository hoge_feature.
client.permitted?(:hoge_feature) #=> false

release_feature_item = ReleaseFeatureItem.find_by(name: 'hoge_feature', environment: 'development')
release_feature_item.update(close_at: '2099-01-01 00:00 +09:00')

# Default caching time (10 min) later

client.permitted?(:hoge_feature) #=> true

Caching

In default, repository data is cached 10 min (600sec). Caching time is changed by refresh_interval_sec parameter.

Following exmple, refresh interval is 1 hour (60 * 60 = 3600 sec ).

config = { features: { hogehoge_function: { development: { open_at: Time.now, close_at: Time.now + 60 * 60 * 24 * 30 } } } }
hash_repo = ReleaseFeature::Repository::HashRepository.new(hash: config)
client = ReleaseFeature::Client.new(environment: :development, refresh_interval_sec: 60 * 60, base_repository: hash_repo)

client.permitted?(:hoge_feature) #=> true
# Repository data is cached and is not loaded for 1 hour (60 * 60 sec).

With Rails app

In Ruby on Rails app, Bt Yaml repository, you can use like this.


class YourAppFlag
  include Singleton

  def initialize(environment = nil, path:)
    environment ||= Rails.env
    yaml_repo = ReleaseFeature::Repository::YamlRepository.new(path: path)
    @client = ReleaseFeature::Client.new(environment: environment.to_sym, base_repository: yaml_repo)
  end

  def permitted?(feature)
    @client.permitted?(feature.to_sym)
  end

  def run_if_permitted
    return unless permitted?
    yield
  end
end

# Before use, please prepare 'release_feature_config.yml'. See above.
flag = YourAppFlag.instance.new(path: 'release_feature_config.yml')

# Using simple boolean flag.
if flag.permitted?(:hoge_feature)
  put 'run if permitted.'
end

# Using block
flag.run_if_permitted do
  put 'run if permitted.'
end

Development

After checking out the repo, run bin/setup to install dependencies.

Then, run rake spec to run the tests.

Then, run steep check to run rbs check.

You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/release_feature. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the ReleaseFeature project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.