Skip to content

Commit

Permalink
Load environment, add list subcommand
Browse files Browse the repository at this point in the history
  • Loading branch information
bkeepers committed Aug 1, 2023
1 parent 3e7eab8 commit 1b36ba0
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 59 deletions.
24 changes: 5 additions & 19 deletions lib/flipper/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
require 'flipper/cli/command'
require 'flipper/cli/enable'
require 'flipper/cli/disable'
require 'flipper/cli/list'
require 'flipper/cli/help'

module Flipper
Expand All @@ -11,29 +12,14 @@ def self.run(argv = ARGV)
end

class Base < Command
# Path to the local Rails application's environment configuration.
# Requiring this loads the application's configuration and classes.
RAILS_ENVIRONMENT_RB = File.expand_path("config/environment")

def initialize(**args)
# Program is always flipper, no matter how it's invoked
super program_name: 'flipper', **args

subcommand('enable', Flipper::CLI::Enable)
subcommand('disable', Flipper::CLI::Disable)
subcommand('help', Flipper::CLI::Help)
end

def spawn(subcommand)
# Initialize flipper before calling any subcommands
initialize_flipper!
super
end

private

def initialize_flipper!
# require RAILS_ENVIRONMENT_RB
subcommand 'enable', Flipper::CLI::Enable
subcommand 'disable', Flipper::CLI::Disable
subcommand 'list', Flipper::CLI::List
subcommand 'help', Flipper::CLI::Help
end
end
end
Expand Down
46 changes: 45 additions & 1 deletion lib/flipper/cli/command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
module Flipper
module CLI
class Command < OptionParser
# Path to the local Rails application's environment configuration.
DEFAULT_REQUIRE = "./config/environment"

attr_reader :options, :subcommands, :parent

def initialize(parent: nil, options: parent&.options || {}, program_name: nil)
Expand All @@ -12,6 +15,12 @@ def initialize(parent: nil, options: parent&.options || {}, program_name: nil)
@program_name = program_name
@parent = parent

options[:require] ||= ENV.fetch("FLIPPER_REQUIRE", DEFAULT_REQUIRE)

on_tail('-r path', "The path to load your application. Default: #{options[:require]}") do |path|
options[:require] = path
end

# Options available on all commands
on_tail('-h', '--help', 'Print help message') do
puts help
Expand Down Expand Up @@ -43,7 +52,12 @@ def subcommand(name, command)
@subcommands[name] = command
end

private
def load_environment!
require File.expand_path(options[:require])
rescue LoadError => e
warn e.message
exit 1
end

# Internal: Initialize a subcommand with state from the current command
def spawn(subcommand)
Expand All @@ -52,6 +66,36 @@ def spawn(subcommand)
program_name: "#{program_name} #{subcommand}"
)
end

private

def feature_summary(feature)
summary = case feature.state
when :on
"fully enabled"
when :off
"disabled"
else
"enabled for " + feature.enabled_gates.map do |gate|
case gate.name
when :actor
pluralize feature.actors_value.size, 'actor', 'actors'
when :group
pluralize feature.groups_value.size, 'group', 'groups'
when :percentage_of_actors
"#{feature.percentage_of_actors_value}% of actors"
when :percentage_of_time
"#{feature.percentage_of_time_value}% of actors"
end
end.join(', ')
end

"#{feature.name.to_s.inspect} is #{summary}"
end

def pluralize(count, singular, plural)
"#{count} #{count == 1 ? singular : plural}"
end
end
end
end
13 changes: 13 additions & 0 deletions lib/flipper/cli/list.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module Flipper
module CLI
class List < Command
def call
load_environment!

Flipper.features.each do |feature|
puts feature_summary(feature)
end
end
end
end
end
42 changes: 9 additions & 33 deletions lib/flipper/cli/toggle.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ class Toggle < Command
def initialize(**args)
super

self.banner = "Usage: #{program_name} [options] <feature>"

@values = []

on('-a id', '--actor=id', "#{action} for an actor") do |id|
Expand All @@ -24,44 +26,18 @@ def action
raise NotImplementedError
end

def call(feature_name)
feature = Flipper.feature(feature_name)
def call(feature)
load_environment!

if @values.empty?
feature.send(action)
else
@values.each { |value| feature.send(action, value) }
end
f = Flipper.feature(feature)

puts feature_summary(feature)
end

def feature_summary(feature)
summary = case feature.state
when :on
"fully enabled"
when :off
"disabled"
if @values.empty?
f.send(action)
else
"enabled for " + feature.enabled_gates.map do |gate|
case gate.name
when :actor
pluralize feature.actors_value.size, 'actor', 'actors'
when :group
pluralize feature.groups_value.size, 'group', 'groups'
when :percentage_of_actors
"#{feature.percentage_of_actors_value}% of actors"
when :percentage_of_time
"#{feature.percentage_of_time_value}% of actors"
end
end.join(', ')
@values.each { |value| f.send(action, value) }
end

"#{feature.name.to_s.inspect} is #{summary}"
end

def pluralize(count, singular, plural)
"#{count} #{count == 1 ? singular : plural}"
puts feature_summary(f)
end
end
end
Expand Down
1 change: 1 addition & 0 deletions spec/fixtures/environment.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Placeholder for config/environment.rb
39 changes: 33 additions & 6 deletions spec/flipper/cli_spec.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
require 'flipper/cli'
require "flipper/cli"

RSpec.describe Flipper::CLI do
subject(:argv) { self.class.parent_groups.map {|g| g.metadata[:description_args] }.reverse.flatten.drop(1) }
# Infer the command from the description
subject(:argv) do
descriptions = self.class.parent_groups.map {|g| g.metadata[:description_args] }.reverse.flatten.drop(1)
descriptions.map { |arg| arg.split }.flatten
end

subject { run argv }

before do
ENV["FLIPPER_REQUIRE"] = "./spec/fixtures/environment"
end


describe "enable" do
describe "feature" do
it do
Expand All @@ -12,10 +22,10 @@
end
end

describe %w(-a User;1 feature) do
describe "-a User;1 feature" do
it do
expect(subject).to have_attributes(status: 0, stdout: /"feature" is enabled for 1 actor/)
expect(Flipper).to be_enabled(:feature, Flipper::Actor.new('User;1'))
expect(Flipper).to be_enabled(:feature, Flipper::Actor.new("User;1"))
end
end
end
Expand All @@ -31,13 +41,30 @@
end
end

['-h', '--help', 'help'].each do |arg|
describe "list" do
before do
Flipper.enable :foo
Flipper.disable :bar
end

it "lists features" do
expect(subject).to have_attributes(status: 0, stdout: /foo.*fully enabled/)
expect(subject).to have_attributes(status: 0, stdout: /bar.*disabled/)
end
end

["-h", "--help", "help"].each do |arg|
describe arg do
it { should have_attributes(status: 0, stdout: /Usage: flipper/) }
end
end

describe 'nope' do
describe "help enable" do

it { should have_attributes(status: 0, stdout: /Usage: flipper enable \[options\] <feature>/) }
end

describe "nope" do
it { should have_attributes(status: 1, stderr: /Unknown command: nope/) }
end

Expand Down

0 comments on commit 1b36ba0

Please sign in to comment.