stoplight-admin 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +57 -0
- data/Rakefile +1 -0
- data/lib/sinatra/stoplight_admin.rb +145 -0
- data/lib/sinatra/views/index.haml +70 -0
- data/lib/sinatra/views/layout.haml +52 -0
- data/stoplight-admin.gemspec +25 -0
- metadata +139 -0
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
data/Gemfile
ADDED
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: []
|