green_flag 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.hound.yml +4 -0
- data/.rubocop.yml +1260 -0
- data/CONTRIBUTING.md +28 -0
- data/app/assets/javascripts/green_flag/admin/feature-deletion.js +3 -0
- data/app/assets/javascripts/green_flag/admin/features.js +1 -1
- data/app/assets/stylesheets/green_flag/admin/features.css.scss +5 -1
- data/app/controllers/green_flag/admin/features_controller.rb +22 -2
- data/app/helpers/green_flag/application_helper.rb +1 -0
- data/app/models/green_flag/feature.rb +13 -1
- data/app/views/green_flag/admin/features/_delete_flag_button.html.erb +18 -0
- data/app/views/green_flag/admin/features/index.html.erb +5 -0
- data/app/views/green_flag/admin/features/show.html.erb +4 -2
- data/green_flag.gemspec +1 -1
- data/lib/green_flag/version.rb +1 -1
- data/spec/controllers/admin/features_controller_spec.rb +51 -2
- data/spec/dummy/log/development.log +54000 -7025
- data/spec/dummy/log/test.log +37566 -31044
- data/spec/dummy/tmp/cache/assets/{D68/760/sprockets%2Fea24808c41a3dff75b995b0f090e1a6a → C4A/640/sprockets%2F8a0527fb4c2402950e34518216e856b5} +0 -0
- data/spec/dummy/tmp/cache/assets/C6A/420/sprockets%2F10f5bf24a82184a4790391b0321bd318 +0 -0
- data/spec/dummy/tmp/cache/assets/CB2/480/sprockets%2Fdffc90cb8265f2042063557905188b1f +0 -0
- data/spec/dummy/tmp/cache/assets/CB9/C30/sprockets%2F8c5e58364159f49f2242f171653cadf1 +0 -0
- data/spec/dummy/tmp/cache/assets/CEA/0F0/sprockets%2F7d5273f602c66c790a79a75c088ff01d +0 -0
- data/spec/dummy/tmp/cache/assets/{C89/D60/sprockets%2F73cd073739a0655341b7278fae57518f → D05/9B0/sprockets%2Fa5b09f162635302e890302aed86bbd6e} +0 -0
- data/spec/dummy/tmp/cache/assets/D1A/760/sprockets%2Fc2f1fda4977960d755da14289d49b51b +0 -0
- data/spec/dummy/tmp/cache/assets/D34/660/sprockets%2Fcfd906f8a0a2386735d1dcf52cc40403 +0 -0
- data/spec/dummy/tmp/cache/assets/{E34/D30/sprockets%2F99c2d0bbd78f1b867beeb3a2eefda618 → D3E/110/sprockets%2Fcb870c7f25e6162da93a720e1be65c76} +0 -0
- data/spec/dummy/tmp/cache/assets/D3E/340/sprockets%2Fad85a878e73a3075722c09b0bdc17cd8 +0 -0
- data/spec/dummy/tmp/cache/assets/{E07/200/sprockets%2F82a8ce7f5bcfb07f773df4cbfeb04762 → D3E/E90/sprockets%2F07bfdbaf75a7c43c05315078db879c43} +0 -0
- data/spec/dummy/tmp/cache/assets/{CE7/FF0/sprockets%2Fe45f3a7675a8c5a5b064117792bf5e28 → D40/260/sprockets%2F35049c3c82baf75b9adfc9662c05e172} +0 -0
- data/spec/dummy/tmp/cache/assets/D62/040/sprockets%2F388ca040babbebd910f7338b606736bd +0 -0
- data/spec/dummy/tmp/cache/assets/D6F/650/sprockets%2F9710be3c17f826e702a9ccea335cdf83 +0 -0
- data/spec/dummy/tmp/cache/assets/{D07/670/sprockets%2F761d03a66b753d628feccd12072c814c → D82/990/sprockets%2F708fb789dee8ecdf5a4a39b9216c1295} +0 -0
- data/spec/dummy/tmp/cache/assets/D8D/1D0/sprockets%2F0e45f412d3a303eda9d7d10d8fc3a5d3 +0 -0
- data/spec/dummy/tmp/cache/assets/D9D/660/sprockets%2Fd306fa5f1db77c33117fbf27276b3ffd +0 -0
- data/spec/dummy/tmp/cache/assets/{DB2/0C0/sprockets%2F95cf35cd3e97774df3c41ee0ef564a8d → DF4/060/sprockets%2F3a6c5e41f435db6af7fb91fa0da49bb1} +0 -0
- data/spec/dummy/tmp/cache/assets/{D13/270/sprockets%2F701a30cd450ae3cfa114092bafc16004 → DF8/280/sprockets%2Fa245a66abbfe76d9de5aa5a40c557f0e} +0 -0
- data/spec/dummy/tmp/cache/assets/DFC/AB0/sprockets%2Fcbca52f6723bcc63ade1b269e299a7bf +0 -0
- data/spec/dummy/tmp/cache/assets/{D6A/580/sprockets%2F18c12847aa1bb46ce9b5661f0e9e5fb0 → E0D/870/sprockets%2Fc21ca057d9f87e8cb797dbe5b8fe3bd2} +0 -0
- data/spec/dummy/tmp/pids/server.pid +1 -0
- data/spec/factories/green_flag/feature_decision.rb +5 -0
- data/spec/factories/green_flag/feature_event.rb +6 -0
- data/spec/factories/green_flag/rule.rb +2 -2
- data/spec/models/green_flag/feature_spec.rb +166 -108
- metadata +60 -60
- data/Gemfile.lock +0 -143
- data/spec/dummy/tmp/cache/assets/C47/3D0/sprockets%2F8f17c33229239b023190617bf2e915a3 +0 -0
- data/spec/dummy/tmp/cache/assets/C81/770/sprockets%2Fdbcf34796b062155788f0b550808541a +0 -0
- data/spec/dummy/tmp/cache/assets/CB6/8F0/sprockets%2F5ea0f1f2583683678e122a9a9391a80f +0 -0
- data/spec/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
- data/spec/dummy/tmp/cache/assets/D10/860/sprockets%2F4582878dbb5b72bfa76615d31b34ed51 +0 -0
- data/spec/dummy/tmp/cache/assets/D15/C10/sprockets%2F6f42f843c916d7864a0dfa912fb3194a +0 -0
- data/spec/dummy/tmp/cache/assets/D18/860/sprockets%2Fce00769800ae939cebb28501947ea96f +0 -0
- data/spec/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/spec/dummy/tmp/cache/assets/D4A/970/sprockets%2F2a7d3b403cbdd8b59d57d26964ea5768 +0 -0
- data/spec/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/spec/dummy/tmp/cache/assets/D59/090/sprockets%2F88788ba6a64e6279624e5c2ff7eead53 +0 -0
- data/spec/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/spec/dummy/tmp/cache/assets/D5C/330/sprockets%2Fd1b1c9a53f4a8a5827e5b02bf0e100e8 +0 -0
- data/spec/dummy/tmp/cache/assets/DA1/210/sprockets%2F25a2979e392c8bc3adce7075cf19ab4b +0 -0
- data/spec/dummy/tmp/cache/assets/DA9/2C0/sprockets%2Ff95d82b2bbb6db8ffe1a87f67b415291 +0 -0
- data/spec/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/spec/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Contributing to GreenFlag
|
2
|
+
|
3
|
+
## Developing
|
4
|
+
|
5
|
+
We're following a pretty standard process for a Github hosted project:
|
6
|
+
|
7
|
+
- Fork the project (core team members can skip this and work directly in this repo)
|
8
|
+
- Clone to your local machine
|
9
|
+
- Create a branch for your changes
|
10
|
+
- Push your branch to Github
|
11
|
+
- Submit a PR to master.
|
12
|
+
- After code review, your PR will be merged into master for inclusion in the next release.
|
13
|
+
|
14
|
+
## Release
|
15
|
+
|
16
|
+
The `gem-release` gem is included as a development dependency. Documented here is the "normal release" process using that gem. More options can be found here: https://github.com/svenfuchs/gem-release
|
17
|
+
|
18
|
+
- You should be on the `master` branch, with all of the releasable code merged in.
|
19
|
+
- Run `rake spec` to make sure the specs pass.
|
20
|
+
- Run this command: `gem bump --version minor --tag`
|
21
|
+
- That's for a "minor" version. You can also use "major" or "patch".
|
22
|
+
- This does the following:
|
23
|
+
- Increments the version in `lib/green_flag/version.rb` and commits that change
|
24
|
+
- Creates a tag for the new version
|
25
|
+
- Pushes the commits and tag to Github
|
26
|
+
- Run this command: `gem release`
|
27
|
+
- This actually pushes the gem to RubyGems.
|
28
|
+
- In your project that uses GreenFlag, update to the latest: `bundle update green_flag`
|
@@ -1,16 +1,29 @@
|
|
1
1
|
class GreenFlag::Admin::FeaturesController < ApplicationController
|
2
|
-
|
3
2
|
layout 'green_flag/application'
|
3
|
+
helper_method :flash_class
|
4
4
|
|
5
5
|
def index
|
6
6
|
@features = GreenFlag::Feature.order(:created_at).all
|
7
7
|
end
|
8
8
|
|
9
9
|
def show
|
10
|
-
@feature = GreenFlag::Feature.
|
10
|
+
@feature = GreenFlag::Feature.where(id: params[:id]).first
|
11
|
+
|
11
12
|
@visitor_groups = GreenFlag::VisitorGroup.all.map { |group| { key: group.key, description: group.description } }
|
12
13
|
end
|
13
14
|
|
15
|
+
def destroy
|
16
|
+
@feature = GreenFlag::Feature.where(id: params[:id]).first
|
17
|
+
|
18
|
+
if @feature.present?
|
19
|
+
destroy_feature
|
20
|
+
else
|
21
|
+
flash[:error] = "The feature could not be found."
|
22
|
+
end
|
23
|
+
|
24
|
+
redirect_to action: :index
|
25
|
+
end
|
26
|
+
|
14
27
|
def current_visitor_status
|
15
28
|
@feature = GreenFlag::Feature.find(params[:id])
|
16
29
|
fd = GreenFlag::FeatureDecision.for_feature(@feature.id).where(site_visitor_id: current_site_visitor.id).first
|
@@ -19,6 +32,13 @@ class GreenFlag::Admin::FeaturesController < ApplicationController
|
|
19
32
|
|
20
33
|
private
|
21
34
|
|
35
|
+
def destroy_feature
|
36
|
+
flash[:notice] = "Feature \"#{@feature.code}\" has been successfully deleted."
|
37
|
+
|
38
|
+
@feature.delete_associated_data
|
39
|
+
@feature.destroy
|
40
|
+
end
|
41
|
+
|
22
42
|
def status_text(feature_decison)
|
23
43
|
if feature_decison.nil? || feature_decison.undecided?
|
24
44
|
"Undecided"
|
@@ -61,7 +61,19 @@ class GreenFlag::Feature < ActiveRecord::Base
|
|
61
61
|
def fully_disabled?
|
62
62
|
rules.count == 0 || rules.all? { |rule| rule.percentage == 0 }
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
|
+
def destroyable?
|
66
|
+
fully_enabled? || fully_disabled?
|
67
|
+
end
|
68
|
+
|
69
|
+
def delete_associated_data
|
70
|
+
GreenFlag::Feature.transaction do
|
71
|
+
GreenFlag::Rule.where(feature_id: id).delete_all
|
72
|
+
GreenFlag::FeatureDecision.where(feature_id: id).delete_all
|
73
|
+
GreenFlag::FeatureEvent.where(feature_id: id).delete_all
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
65
77
|
private
|
66
78
|
|
67
79
|
def decide_feature_decision(feature_decision)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<%
|
2
|
+
button_class = @feature.destroyable? ? 'btn btn-danger' : 'btn btn-danger disabled'
|
3
|
+
|
4
|
+
confirmation_message = "Are you sure? The feature and all associated rules and \
|
5
|
+
decisions will be permanently deleted."
|
6
|
+
%>
|
7
|
+
|
8
|
+
<% unless @feature.destroyable? %>
|
9
|
+
<div class="tooltip-wrapper" data-title="For deletion, the rules must be set to
|
10
|
+
100% or 0% for all groups. After setting the rule percentages, refresh this page.">
|
11
|
+
<% end %>
|
12
|
+
|
13
|
+
<%= link_to "Delete Flag", admin_feature_path(@feature.id), class: button_class,
|
14
|
+
data: { confirm: confirmation_message }, method: :delete %>
|
15
|
+
|
16
|
+
<% unless @feature.destroyable? %>
|
17
|
+
</div>
|
18
|
+
<% end %>
|
@@ -103,8 +103,6 @@
|
|
103
103
|
</ul>
|
104
104
|
|
105
105
|
</div>
|
106
|
-
|
107
|
-
|
108
106
|
</script>
|
109
107
|
|
110
108
|
<%# Templates - white list %>
|
@@ -134,8 +132,12 @@
|
|
134
132
|
<h2>Your Status <span class="label {{labelClass}}">{{status}}</span></h2>
|
135
133
|
</script>
|
136
134
|
|
135
|
+
<%= render 'delete_flag_button' %>
|
136
|
+
|
137
137
|
<%# Javascript kickstart %>
|
138
138
|
<%= javascript_include_tag 'green_flag/admin/features' %>
|
139
|
+
<%= javascript_include_tag 'green_flag/admin/feature-deletion' %>
|
140
|
+
|
139
141
|
<script>
|
140
142
|
GreenFlag.FeatureEditor.start({
|
141
143
|
feature: <%= @feature.to_json.html_safe %>,
|
data/green_flag.gemspec
CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.add_dependency "activerecord-concurrent-index"
|
29
29
|
s.add_dependency "sass-rails"
|
30
30
|
|
31
|
-
s.add_development_dependency 'rspec-rails'
|
31
|
+
s.add_development_dependency 'rspec-rails', "~> 2"
|
32
32
|
s.add_development_dependency 'factory_girl_rails'
|
33
33
|
s.add_development_dependency 'capybara'
|
34
34
|
s.add_development_dependency 'gem-release'
|
data/lib/green_flag/version.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe GreenFlag::Admin::FeaturesController do
|
4
|
-
|
5
4
|
let(:feature) { GreenFlag::Feature.create(code: 'foo') }
|
6
5
|
|
7
6
|
describe '#index' do
|
@@ -16,6 +15,56 @@ describe GreenFlag::Admin::FeaturesController do
|
|
16
15
|
get :show, :id => feature.id
|
17
16
|
expect(response).to be_success
|
18
17
|
end
|
19
|
-
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#destroy" do
|
21
|
+
subject { delete :destroy, id: feature.id }
|
22
|
+
|
23
|
+
it "redirects to the index action" do
|
24
|
+
expect(subject).to redirect_to action: :index
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when the feature can be deleted" do
|
28
|
+
before(:each) do
|
29
|
+
5.times do
|
30
|
+
FactoryGirl.create(:green_flag_rule, feature_id: feature.id)
|
31
|
+
FactoryGirl.create(:green_flag_feature_event, feature_id: feature.id)
|
32
|
+
FactoryGirl.create(:green_flag_feature_decision, feature_id: feature.id)
|
33
|
+
end
|
34
|
+
|
35
|
+
subject
|
36
|
+
end
|
37
|
+
|
38
|
+
it "deletes the feature" do
|
39
|
+
expect(GreenFlag::Feature.find_by_id(feature.id)).to be_nil
|
40
|
+
end
|
20
41
|
|
42
|
+
it "deletes the feature's rules" do
|
43
|
+
expect(GreenFlag::Rule.where(feature_id: feature.id)).to eq []
|
44
|
+
end
|
45
|
+
|
46
|
+
it "deletes the feature's events" do
|
47
|
+
expect(GreenFlag::FeatureEvent.where(feature_id: feature.id)).to eq []
|
48
|
+
end
|
49
|
+
|
50
|
+
it "deletes the feature's feature decisions" do
|
51
|
+
expect(GreenFlag::FeatureDecision.where(feature_id: feature.id)).to eq []
|
52
|
+
end
|
53
|
+
|
54
|
+
it "sets a successful flash notice" do
|
55
|
+
expect(flash[:notice]).to eq "Feature \"#{feature.code}\" has been \
|
56
|
+
successfully deleted."
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "when the feature cannot be found" do
|
61
|
+
it "sets a flash error indicating the error" do
|
62
|
+
feature.destroy
|
63
|
+
|
64
|
+
subject
|
65
|
+
|
66
|
+
expect(flash[:error]).to eq "The feature could not be found."
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
21
70
|
end
|