Skip to content

Commit

Permalink
Installed FlipFlop gem
Browse files Browse the repository at this point in the history
We are installing the FlipFlop gem to enable us to use feature flags with a lower barrier to entry that the current process of using user permissions. The FlipFlop gem can store feature flag information inside the Whitehall database, meaning that we no longer have to create permissions inside of signon to deploy code without releasing it to users.

We have disabled the cookie strategy because our main use case at the moment is toggling features on and off in different environments, but we may consider using it in future if our needs change.

We have also only enabled the Flipflop user interface in local development environments. Developers will use the rake task provided by the library to toggle features in cloud environments.

This commit also switches the FlipFlop strategy to use an in-memory store for feature flags and makes the flag data available to test cases.
  • Loading branch information
ryanb-gds committed Nov 2, 2023
1 parent e50b4ed commit 918bf25
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 1 deletion.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ gem "carrierwave-i18n"
gem "chronic"
gem "dalli"
gem "diffy"
gem "flipflop"
gem "fog-aws"
gem "friendly_id"
gem "fuzzy_match"
Expand Down
4 changes: 4 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ GEM
ffi (1.15.5)
filelock (1.1.1)
find_a_port (1.0.1)
flipflop (2.7.1)
activesupport (>= 4.0)
terminal-table (>= 1.8)
fog-aws (3.21.0)
fog-core (~> 2.1)
fog-json (~> 1.1)
Expand Down Expand Up @@ -967,6 +970,7 @@ DEPENDENCIES
equivalent-xml
erb_lint
factory_bot
flipflop
fog-aws
friendly_id
fuzzy_match
Expand Down
8 changes: 8 additions & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,13 @@ class Application < Rails::Application
unless Rails.application.secrets.jwt_auth_secret
raise "JWT auth secret is not configured. See config/secrets.yml"
end

# Before filter for Flipflop dashboard. Replace with a lambda or method name
# defined in ApplicationController to implement access control.
config.flipflop.dashboard_access_filter = -> { head :forbidden unless ENV["RAILS_ENV"] == "development" }

# By default, when set to `nil`, strategy loading errors are suppressed in test
# mode. Set to `true` to always raise errors, or `false` to always warn.
config.flipflop.raise_strategy_errors = nil
end
end
23 changes: 23 additions & 0 deletions config/features.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Flipflop.configure do
# Strategies will be used in the order listed here.
strategy :active_record
strategy :default

# Other strategies:
#
# strategy :sequel
# strategy :redis
#
# strategy :query_string
# strategy :session
#
# strategy :my_strategy do |feature|
# # ... your custom code here; return true/false/nil.
# end

# Declare your features, e.g:
#
# feature :world_domination,
# default: true,
# description: "Take over the world."
end
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -397,5 +397,7 @@ def redirect(path, options = { prefix: Whitehall.router_prefix })

mount SidekiqGdsSsoMiddleware, at: "/sidekiq"

mount Flipflop::Engine => "/flipflop"

mount GovukPublishingComponents::Engine, at: "/component-guide" unless Rails.env.production?
end
10 changes: 10 additions & 0 deletions db/migrate/20231102101641_create_features.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class CreateFeatures < ActiveRecord::Migration[7.0]
def change
create_table :flipflop_features do |t|
t.string :key, null: false
t.boolean :enabled, null: false, default: false

t.timestamps null: false
end
end
end
9 changes: 8 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.0].define(version: 2023_10_31_222012) do
ActiveRecord::Schema[7.0].define(version: 2023_11_02_101641) do
create_table "assets", charset: "utf8mb3", force: :cascade do |t|
t.string "asset_manager_id", null: false
t.string "variant", null: false
Expand Down Expand Up @@ -501,6 +501,13 @@
t.index ["year"], name: "index_financial_reports_on_year"
end

create_table "flipflop_features", charset: "utf8mb3", force: :cascade do |t|
t.string "key", null: false
t.boolean "enabled", default: false, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

create_table "force_publication_attempts", id: :integer, charset: "utf8mb3", force: :cascade do |t|
t.integer "import_id"
t.integer "total_documents"
Expand Down
25 changes: 25 additions & 0 deletions docs/feature_flags.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Feature Flags

Feature flags in Whitehall are managed using the [FlipFlop gem](https://github.com/voormedia/flipflop). The gem is currently
configured so that only the ActiveRecord and default strategies are active.

## Toggling Feature Flags

In local development environments, a UI is available to make it easy to toggle feature flags on and off during development.
The UI can be accessed at http://whitehall-admin.dev.gov.uk/flipflop. To toggle feature flags in non-local environments, the
rake task provided by FlipFlop can be used, e.g.

```bash
bundle exec rake flipflop:turn_on[new_feature,active_record] # Enables the new feature with the Active Record strategy
bundle exec rake flipflop:turn_off[new_feature,active_record] # Disables the new feature with the Active Record strategy
```

## Testing with Feature Flags

Feature flags are made accessible via the [`feature_flags`] helper on `ActionController::TestCase`.

To toggle a feature flag in your controller test:

```ruby
feature_flags.switch! :your_feature, true
```
3 changes: 3 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,13 @@ class ActionController::TestCase
include Admin::EditionRoutesHelper

attr_reader :current_user

Check failure on line 211 in test/test_helper.rb

View workflow job for this annotation

GitHub Actions / Lint Ruby / Run RuboCop

Style/AccessorGrouping: Group together all `attr_reader` attributes.
attr_reader :feature_flags

Check failure on line 212 in test/test_helper.rb

View workflow job for this annotation

GitHub Actions / Lint Ruby / Run RuboCop

Style/AccessorGrouping: Group together all `attr_reader` attributes.

setup do
request.env["warden"] = stub(authenticate!: false, authenticated?: false, user: nil)

@feature_flags = Flipflop::FeatureSet.current.test!

# In controller tests, stub out all calls to the content store. This
# implies that by default we don't care about responses from this endpoint,
# which is currently only used to render specialist sector links in the
Expand Down

0 comments on commit 918bf25

Please sign in to comment.