stoplight-admin 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 720f024afd31b7bd10e275d8e308adcb4bfe3a5a
4
+ data.tar.gz: 6198427cb003abba4b76d4f26ff8646fb3320402
5
+ SHA512:
6
+ metadata.gz: c5bb750a5a81f710ee638062625fc571303ab847259f5fa512a56eb56d554cedcea56e27bee7dbdd43f3af72a7fca4359e03c039c258985ac522cb162301f08a
7
+ data.tar.gz: ead92213a7d26b7366ce5631cb66821065d1ce3a386cfb8011c985e7c7fb948591ff718da278fa7017f379ce297395367bb2c8154df2be99c91925a295e062f4
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in stoplight-admin.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Cameron Desautels
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # [Stoplight Admin][1]
2
+
3
+ A simple administration interface for [stoplight][2]. Monitor the
4
+ status, failures, and invocations of your stoplights. Change
5
+ stoplight colors, or lock them in either red or green state.
6
+
7
+ ## Configuration
8
+
9
+ This project is packaged as a Ruby gem so that you can easily embed it
10
+ in your own code containing the configuration details for your
11
+ [stoplight][2] data store.
12
+
13
+ First you'll need a `Gemfile`:
14
+
15
+ ``` rb
16
+ source 'https://rubygems.org'
17
+
18
+ gem 'stoplight-admin', '~> 0.1.0'
19
+ ```
20
+
21
+ Run [Bundler][3] to install the dependencies:
22
+
23
+ ``` sh
24
+ $ bundle install
25
+ ```
26
+
27
+ Lastly we need to make our (tiny) application. Here's a typical
28
+ example using a local Redis data store:
29
+
30
+ ``` rb
31
+ # app.rb
32
+
33
+ require 'sinatra'
34
+ require 'sinatra/stoplight_admin'
35
+
36
+ REDIS_URL = 'redis://localhost:6379'
37
+ set :data_store, Stoplight::DataStore::Redis.new(url: REDIS_URL)
38
+
39
+ ```
40
+
41
+ ## Usage
42
+
43
+ ``` sh
44
+ $ bundle exec ruby app.rb
45
+ ```
46
+
47
+ ## Credits
48
+
49
+ Stoplight is brought to you by [@camdez][4] and [@tfausak][5] from
50
+ [@OrgSync][6].
51
+
52
+ [1]: https://github.com/orgsync/stoplight-admin
53
+ [2]: https://github.com/orgsync/stoplight
54
+ [3]: http://bundler.io
55
+ [4]: https://github.com/camdez
56
+ [5]: https://github.com/tfausak
57
+ [6]: https://github.com/OrgSync
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,145 @@
1
+ # coding: utf-8
2
+
3
+ require 'haml'
4
+ require 'sinatra/base'
5
+ require 'stoplight'
6
+
7
+ module Sinatra
8
+ module StoplightAdmin
9
+ module Helpers
10
+ def data_store
11
+ return @data_store if defined?(@data_store)
12
+
13
+ Stoplight.data_store settings.data_store
14
+ @data_store = Stoplight.data_store
15
+ end
16
+
17
+ def lights
18
+ data_store
19
+ .names
20
+ .map { |name| light_info(name) }
21
+ .sort_by { |light| light_sort_key(light) }
22
+ end
23
+
24
+ def light_info(light)
25
+ green = Stoplight.green?(light)
26
+ attempts = green ? 0 : data_store.attempts(light)
27
+ failures = green ? [] : data_store.failures(light).map do |f|
28
+ JSON.parse(f)
29
+ end
30
+
31
+ {
32
+ name: light,
33
+ green: green,
34
+ failures: failures,
35
+ attempts: attempts,
36
+ locked: locked?(light)
37
+ }
38
+ end
39
+
40
+ def light_sort_key(light)
41
+ [light[:green] ? 1 : 0,
42
+ light[:attempts] * -1,
43
+ light[:name]]
44
+ end
45
+
46
+ def locked?(light_name)
47
+ [Stoplight::DataStore::STATE_LOCKED_GREEN,
48
+ Stoplight::DataStore::STATE_LOCKED_RED]
49
+ .include?(data_store.state(light_name))
50
+ end
51
+
52
+ def stat_params(ls)
53
+ total_count = ls.size
54
+ success_count = ls.count { |l| l[:green] }
55
+ failure_count = total_count - success_count
56
+
57
+ if total_count > 0
58
+ failure_percentage = (100.0 * failure_count / total_count).ceil
59
+ success_percentage = 100 - failure_percentage
60
+ else
61
+ failure_percentage = success_percentage = 0
62
+ end
63
+
64
+ {
65
+ success_count: success_count,
66
+ failure_count: failure_count,
67
+ success_percentage: success_percentage,
68
+ failure_percentage: failure_percentage
69
+ }
70
+ end
71
+
72
+ def lock(light)
73
+ new_state =
74
+ if Stoplight.green?(light)
75
+ Stoplight::DataStore::STATE_LOCKED_GREEN
76
+ else
77
+ Stoplight::DataStore::STATE_LOCKED_RED
78
+ end
79
+
80
+ data_store.set_state(light, new_state)
81
+ end
82
+
83
+ def unlock(light)
84
+ data_store.set_state(light, Stoplight::DataStore::STATE_UNLOCKED)
85
+ end
86
+
87
+ def green(light)
88
+ if data_store.state(light) == Stoplight::DataStore::STATE_LOCKED_RED
89
+ new_state = Stoplight::DataStore::STATE_LOCKED_GREEN
90
+ data_store.set_state(light, new_state)
91
+ end
92
+
93
+ data_store.clear_attempts(light)
94
+ data_store.clear_failures(light)
95
+ end
96
+
97
+ def red(light)
98
+ data_store.set_state(light, Stoplight::DataStore::STATE_LOCKED_RED)
99
+ end
100
+ end
101
+
102
+ def self.registered(app)
103
+ app.helpers StoplightAdmin::Helpers
104
+
105
+ app.set :data_store, nil
106
+ app.set :views, File.join(File.dirname(__FILE__), 'views')
107
+
108
+ app.get '/' do
109
+ ls = lights
110
+ stats = stat_params(ls)
111
+
112
+ haml :index, locals: stats.merge(lights: ls)
113
+ end
114
+
115
+ app.post '/lock' do
116
+ [*params[:names]].each { |l| lock(l) }
117
+ redirect to('/')
118
+ end
119
+
120
+ app.post '/unlock' do
121
+ [*params[:names]].each { |l| unlock(l) }
122
+ redirect to('/')
123
+ end
124
+
125
+ app.post '/green' do
126
+ [*params[:names]].each { |l| green(l) }
127
+ redirect to('/')
128
+ end
129
+
130
+ app.post '/red' do
131
+ [*params[:names]].each { |l| red(l) }
132
+ redirect to('/')
133
+ end
134
+
135
+ app.post '/green_all' do
136
+ data_store.names
137
+ .reject { |l| Stoplight.green?(l) }
138
+ .each { |l| green(l) }
139
+ redirect to('/')
140
+ end
141
+ end
142
+ end
143
+
144
+ register StoplightAdmin
145
+ end
@@ -0,0 +1,70 @@
1
+ .jumbotron
2
+ %h1 🚦 All of the Lights
3
+ %p Cop lights, flashlights, spotlights, strobe lights…
4
+
5
+ .main
6
+ - if lights.any?
7
+ .btn-group
8
+ %form{method: 'post', action: '/green_all'}
9
+ %button.btn-lg.btn.btn-success{type: 'submit', disabled: failure_count > 0 ? nil : 'disabled'} Greenify All
10
+
11
+ .progress
12
+ .progress-bar.progress-bar-danger{style: "width: #{failure_percentage}%"}
13
+ .span= failure_count
14
+ .progress-bar.progress-bar-success{style: "width: #{success_percentage}%"}
15
+ .span= success_count
16
+
17
+ .lights
18
+ %table.table.table-hover
19
+ %thead
20
+ %tr
21
+ %th Status
22
+ %th
23
+ %abbr{title: 'Locked lights will not change color automatically.'} Locked?
24
+ %th
25
+ %abbr{title: 'Exceptions which caused the light to turn red.'} Failures
26
+ %th
27
+ %abbr{title: 'Number of times the light was invoked while red.'} Attempts
28
+ %th Name
29
+ %tbody
30
+ - lights.each do |l|
31
+ %tr
32
+ %td.indicator
33
+ - if l[:green]
34
+ %form{method: 'post', action: '/red'}
35
+ %input{type: 'hidden', name: 'names', value: URI.escape(l[:name])}
36
+ %button{type: 'submit', class: 'btn btn-success'} GREEN
37
+ - else
38
+ %form{method: 'post', action: '/green'}
39
+ %input{type: 'hidden', name: 'names', value: URI.escape(l[:name])}
40
+ %button{type: 'submit', class: 'btn btn-danger'} RED
41
+ %td.locked
42
+ - if l[:locked]
43
+ %form{method: 'post', action: '/unlock'}
44
+ %input{type: 'hidden', name: 'names', value: URI.escape(l[:name])}
45
+ %button{type: 'submit', class: 'btn btn-link'}
46
+ %span{class: 'glyphicon glyphicon-lock'}
47
+ - else
48
+ %form{method: 'post', action: '/lock'}
49
+ %input{type: 'hidden', name: 'names', value: URI.escape(l[:name])}
50
+ %button{type: 'submit', class: 'btn btn-link'}
51
+ %span{class: 'glyphicon glyphicon-minus'}
52
+ %td.failures
53
+ - if l[:failures]
54
+ %ul
55
+ - l[:failures].each do |failure|
56
+ %li
57
+ %span.error
58
+ &= failure['error']
59
+ @
60
+ %span.timestamp
61
+ &= failure['time']
62
+ %td.attempts
63
+ - if l[:attempts] > 0
64
+ = l[:attempts]
65
+ %td.name
66
+ = l[:name]
67
+ - else
68
+ .alert.alert-warning{role: 'alert'}
69
+ %strong No lights found.
70
+ Ensure that your Stoplight data store is properly configured and that your Stoplight blocks have been run.
@@ -0,0 +1,52 @@
1
+ !!! 5
2
+ %html{lang: 'en'}
3
+ %head
4
+ %meta{charset: 'utf-8'}
5
+ %meta{viewport: 'width=device-width, initial-scale=1'}
6
+
7
+ %title Stoplight Admin
8
+
9
+ %link{rel: 'stylesheet', href: '//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css'}
10
+ %link{rel: 'stylesheet', href: '//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css'}
11
+
12
+ :css
13
+ body {
14
+ padding-top: 70px;
15
+ padding-bottom: 30px;
16
+ }
17
+
18
+ .progress {
19
+ margin-top: 30px
20
+ }
21
+
22
+ td.indicator {
23
+ font-size: 200%;
24
+ }
25
+
26
+ td.name {
27
+ font-weight: bold;
28
+ }
29
+
30
+ td.locked button {
31
+ font-size: 200%;
32
+ }
33
+
34
+ td.failures span.error {
35
+ font-weight: bold;
36
+ }
37
+
38
+ td.failures ul {
39
+ padding: 0;
40
+ list-style-type: none;
41
+ }
42
+
43
+ %body
44
+ .navbar.navbar-inverse.navbar-fixed-top{role: 'navigation'}
45
+ .container
46
+ .navbar-header
47
+ %a{class: 'navbar-brand', href: '/'} Stoplight Admin
48
+
49
+ .container{role: 'main'}
50
+ = yield
51
+
52
+ %script{src: '//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js'}
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'stoplight-admin'
5
+ spec.version = '0.1.0'
6
+ spec.authors = ['Cameron Desautels', 'Taylor Fausak']
7
+ spec.email = %w(camdez@gmail.com taylor@fausak.me)
8
+ spec.summary = %q{A simple administration interface for the stoplight gem.}
9
+ spec.description = spec.summary
10
+ spec.homepage = 'https://github.com/orgsync/stoplight-admin'
11
+ spec.license = 'MIT'
12
+
13
+ spec.files = `git ls-files`.split($/)
14
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
15
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
16
+ spec.require_paths = ['lib']
17
+
18
+ spec.add_development_dependency 'bundler', '~> 1.3'
19
+ spec.add_development_dependency 'rake'
20
+
21
+ spec.add_dependency 'haml', '~> 4.0.4'
22
+ spec.add_dependency 'redis', '~> 3.1.0'
23
+ spec.add_dependency 'sinatra', '~> 1.4.5'
24
+ spec.add_dependency 'stoplight', '~> 0.1.0'
25
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stoplight-admin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Cameron Desautels
8
+ - Taylor Fausak
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-08-12 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ~>
19
+ - !ruby/object:Gem::Version
20
+ version: '1.3'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ version: '1.3'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: haml
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ~>
47
+ - !ruby/object:Gem::Version
48
+ version: 4.0.4
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: 4.0.4
56
+ - !ruby/object:Gem::Dependency
57
+ name: redis
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: 3.1.0
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 3.1.0
70
+ - !ruby/object:Gem::Dependency
71
+ name: sinatra
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: 1.4.5
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ~>
82
+ - !ruby/object:Gem::Version
83
+ version: 1.4.5
84
+ - !ruby/object:Gem::Dependency
85
+ name: stoplight
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ~>
89
+ - !ruby/object:Gem::Version
90
+ version: 0.1.0
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ~>
96
+ - !ruby/object:Gem::Version
97
+ version: 0.1.0
98
+ description: A simple administration interface for the stoplight gem.
99
+ email:
100
+ - camdez@gmail.com
101
+ - taylor@fausak.me
102
+ executables: []
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - .gitignore
107
+ - Gemfile
108
+ - LICENSE.txt
109
+ - README.md
110
+ - Rakefile
111
+ - lib/sinatra/stoplight_admin.rb
112
+ - lib/sinatra/views/index.haml
113
+ - lib/sinatra/views/layout.haml
114
+ - stoplight-admin.gemspec
115
+ homepage: https://github.com/orgsync/stoplight-admin
116
+ licenses:
117
+ - MIT
118
+ metadata: {}
119
+ post_install_message:
120
+ rdoc_options: []
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ requirements: []
134
+ rubyforge_project:
135
+ rubygems_version: 2.1.11
136
+ signing_key:
137
+ specification_version: 4
138
+ summary: A simple administration interface for the stoplight gem.
139
+ test_files: []