stackster 0.0.1
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.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/Rakefile +1 -0
- data/bin/stackster +6 -0
- data/lib/stackster/aws/cloud_formation.rb +46 -0
- data/lib/stackster/aws/ec2.rb +24 -0
- data/lib/stackster/aws/simpledb.rb +36 -0
- data/lib/stackster/aws.rb +3 -0
- data/lib/stackster/cli.rb +62 -0
- data/lib/stackster/config.rb +20 -0
- data/lib/stackster/entry/entry_lister.rb +15 -0
- data/lib/stackster/entry.rb +57 -0
- data/lib/stackster/instance/instance_reader.rb +27 -0
- data/lib/stackster/instance.rb +1 -0
- data/lib/stackster/stack/stack_creater.rb +38 -0
- data/lib/stackster/stack/stack_destroyer.rb +14 -0
- data/lib/stackster/stack/stack_formater.rb +39 -0
- data/lib/stackster/stack/stack_lister.rb +15 -0
- data/lib/stackster/stack/stack_reader.rb +42 -0
- data/lib/stackster/stack.rb +42 -0
- data/lib/stackster/version.rb +3 -0
- data/lib/stackster.rb +6 -0
- data/stackster.gemspec +25 -0
- metadata +97 -0
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/stackster
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'fog'
|
2
|
+
|
3
|
+
module Stackster
|
4
|
+
class AWS
|
5
|
+
class CloudFormation
|
6
|
+
|
7
|
+
def initialize(environment)
|
8
|
+
c = Config.environment environment
|
9
|
+
@connect = Fog::AWS::CloudFormation.new :aws_access_key_id => c['access_key'],
|
10
|
+
:aws_secret_access_key => c['secret_key'],
|
11
|
+
:region => c['region']
|
12
|
+
end
|
13
|
+
|
14
|
+
def create(args)
|
15
|
+
data = { 'Capabilities' => ['CAPABILITY_IAM'],
|
16
|
+
'TemplateBody' => args[:template] }.merge( { 'Parameters' => args[:parameters] } )
|
17
|
+
@connect.create_stack(args[:name], data)
|
18
|
+
end
|
19
|
+
|
20
|
+
def destroy(name)
|
21
|
+
@connect.delete_stack name
|
22
|
+
end
|
23
|
+
|
24
|
+
def describe_stack(name)
|
25
|
+
@connect.describe_stacks('StackName' => name).body['Stacks']
|
26
|
+
end
|
27
|
+
|
28
|
+
def stack_resources(name)
|
29
|
+
@connect.describe_stack_resources('StackName' => name).body['StackResources']
|
30
|
+
end
|
31
|
+
|
32
|
+
def stack_events(name)
|
33
|
+
@connect.describe_stack_events(name).body['StackEvents']
|
34
|
+
end
|
35
|
+
|
36
|
+
def stack_status(name)
|
37
|
+
describe_stack(name).first['StackStatus']
|
38
|
+
end
|
39
|
+
|
40
|
+
def stack_outputs(name)
|
41
|
+
describe_stack(name).last['Outputs']
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'fog'
|
2
|
+
|
3
|
+
module Stackster
|
4
|
+
class AWS
|
5
|
+
class EC2
|
6
|
+
|
7
|
+
def initialize(environment)
|
8
|
+
c = Config.environment environment
|
9
|
+
@connect = Fog::Compute::AWS.new :aws_access_key_id => c['access_key'],
|
10
|
+
:aws_secret_access_key => c['secret_key'],
|
11
|
+
:region => c['region']
|
12
|
+
end
|
13
|
+
|
14
|
+
def describe_instances
|
15
|
+
i = []
|
16
|
+
@connect.describe_instances.body['reservationSet'].each do |instance|
|
17
|
+
i << instance
|
18
|
+
end
|
19
|
+
i
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'fog'
|
2
|
+
|
3
|
+
module Stackster
|
4
|
+
class AWS
|
5
|
+
class SimpleDB
|
6
|
+
|
7
|
+
def initialize(environment)
|
8
|
+
c = Config.environment environment
|
9
|
+
@connect = Fog::AWS::SimpleDB.new :aws_access_key_id => c['access_key'],
|
10
|
+
:aws_secret_access_key => c['secret_key'],
|
11
|
+
:region => c['region']
|
12
|
+
end
|
13
|
+
|
14
|
+
def domains
|
15
|
+
@connect.list_domains.body['Domains']
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_domain(domain)
|
19
|
+
@connect.create_domain(domain) unless domains.include? domain
|
20
|
+
end
|
21
|
+
|
22
|
+
def put_attributes(domain, key, attributes, options)
|
23
|
+
@connect.put_attributes domain, key, attributes, options
|
24
|
+
end
|
25
|
+
|
26
|
+
def select(query)
|
27
|
+
@connect.select(query).body['Items']
|
28
|
+
end
|
29
|
+
|
30
|
+
def delete(domain, key)
|
31
|
+
@connect.delete_attributes domain, key
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'trollop'
|
2
|
+
|
3
|
+
module Stackster
|
4
|
+
module CLI
|
5
|
+
def self.start
|
6
|
+
@opts = Trollop::options do
|
7
|
+
banner <<-EOS
|
8
|
+
build and manage stacks
|
9
|
+
EOS
|
10
|
+
opt :help, "Display Help"
|
11
|
+
opt :attributes, "CSV list of = seperated attributes to set", :type => :string
|
12
|
+
opt :environment, "Set the target environment", :type => :string
|
13
|
+
opt :name, "Stack name to manage", :type => :string
|
14
|
+
opt :template, "Path to the template file", :type => :string
|
15
|
+
end
|
16
|
+
|
17
|
+
@cmd = ARGV.shift
|
18
|
+
|
19
|
+
unless Config.environments.include? @opts[:environment]
|
20
|
+
puts "Please specify a valid environment: #{Config.environments.to_s}"
|
21
|
+
exit 1
|
22
|
+
end
|
23
|
+
|
24
|
+
s = Stack.new :environment => @opts[:environment],
|
25
|
+
:name => @opts[:name]
|
26
|
+
read_attributes
|
27
|
+
|
28
|
+
case @cmd
|
29
|
+
when 'create'
|
30
|
+
s.create :attributes => attributes,
|
31
|
+
:template => @opts[:template]
|
32
|
+
puts "#{@opts[:name]} created."
|
33
|
+
when 'destroy', 'delete'
|
34
|
+
s.destroy
|
35
|
+
puts "#{@opts[:name]} destroyed."
|
36
|
+
when 'show'
|
37
|
+
sf = StackFormater.new :environment => @opts[:environment],
|
38
|
+
:name => @opts[:name]
|
39
|
+
puts sf.display_short.to_yaml
|
40
|
+
when 'list'
|
41
|
+
s = StackLister.new @opts[:environment]
|
42
|
+
puts s.all
|
43
|
+
else
|
44
|
+
puts "Unkown command '#{@cmd}'"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.attributes
|
49
|
+
attrs = []
|
50
|
+
read_attributes.each do |attribs|
|
51
|
+
a = attribs.split('=')
|
52
|
+
attrs << { a.first => a.last }
|
53
|
+
end
|
54
|
+
attrs
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.read_attributes
|
58
|
+
@opts[:attributes].nil? ? [] : @opts[:attributes].split(',')
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Stackster
|
2
|
+
class Config
|
3
|
+
def self.load_config_file(config_file = "#{ENV['HOME']}/.stackster.yml")
|
4
|
+
YAML::load File.open( config_file )
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.environment(environment)
|
8
|
+
load_config_file[environment]
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.region(environment)
|
12
|
+
load_config_file[environment]['region']
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.environments
|
16
|
+
load_config_file.keys
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Stackster
|
2
|
+
class EntryLister
|
3
|
+
|
4
|
+
def initialize(environment)
|
5
|
+
@environment = environment
|
6
|
+
@domain = 'stacks'
|
7
|
+
@sdb_connect = AWS::SimpleDB.new @environment
|
8
|
+
end
|
9
|
+
|
10
|
+
def all
|
11
|
+
@sdb_connect.select "select * from #{@domain}"
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'stackster/entry/entry_lister'
|
2
|
+
|
3
|
+
module Stackster
|
4
|
+
class Entry
|
5
|
+
attr_accessor :name, :attributes
|
6
|
+
|
7
|
+
def initialize(args)
|
8
|
+
@environment = args[:environment]
|
9
|
+
@domain = 'stacks'
|
10
|
+
@sdb_connect = AWS::SimpleDB.new @environment
|
11
|
+
self.name = "#{args[:name]}-#{Config.region @environment}"
|
12
|
+
create_domain
|
13
|
+
get_attributes
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.find(args)
|
17
|
+
e = Entry.new :name => args[:name],
|
18
|
+
:environment => args[:environment]
|
19
|
+
e.get_attributes
|
20
|
+
e
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_domain
|
24
|
+
@sdb_connect.create_domain(@domain)
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_attributes
|
28
|
+
u = {}
|
29
|
+
attrs = @sdb_connect.select("select * from stacks where itemName() = '#{name}'")
|
30
|
+
if attrs[name]
|
31
|
+
attrs[name].each_pair do |k, v|
|
32
|
+
u[k] = v.first
|
33
|
+
end
|
34
|
+
end
|
35
|
+
self.attributes = u
|
36
|
+
end
|
37
|
+
|
38
|
+
def save
|
39
|
+
attributes.each_pair do |k,v|
|
40
|
+
@sdb_connect.put_attributes('stacks', name, { k => v }, { :replace => k })
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_attributes(a)
|
45
|
+
a.each { |attribute| set_attribute(attribute) }
|
46
|
+
end
|
47
|
+
|
48
|
+
def set_attribute(attribute)
|
49
|
+
self.attributes = attributes.merge(attribute)
|
50
|
+
end
|
51
|
+
|
52
|
+
def delete_attributes
|
53
|
+
@sdb_connect.delete('stacks', name)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Stackster
|
2
|
+
class InstanceReader
|
3
|
+
|
4
|
+
def initialize(environment)
|
5
|
+
@environment = environment
|
6
|
+
@ec2 = AWS::EC2.new @environment
|
7
|
+
end
|
8
|
+
|
9
|
+
# Data structure is return deffernelty for class
|
10
|
+
# Currently only supports VPC
|
11
|
+
def list_stack_instances(stack_name)
|
12
|
+
h = []
|
13
|
+
describe_instances.each do |instance|
|
14
|
+
tag_set = instance['instancesSet'].first['tagSet']
|
15
|
+
if tag_set['aws:cloudformation:stack-name']
|
16
|
+
h << instance if tag_set['aws:cloudformation:stack-name'] == stack_name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
h
|
20
|
+
end
|
21
|
+
|
22
|
+
def describe_instances
|
23
|
+
@ec2.describe_instances
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'stackster/instance/instance_reader'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Stackster
|
4
|
+
class StackCreater
|
5
|
+
|
6
|
+
def initialize(args)
|
7
|
+
@cf = AWS::CloudFormation.new args[:environment]
|
8
|
+
@entry = args[:entry]
|
9
|
+
@name = args[:name]
|
10
|
+
@template = read_template_from_file args[:template]
|
11
|
+
end
|
12
|
+
|
13
|
+
def read_template_from_file(template_file)
|
14
|
+
file = File.open template_file
|
15
|
+
file.read
|
16
|
+
end
|
17
|
+
|
18
|
+
def read_parameters_from_template
|
19
|
+
t = JSON.parse(@template)
|
20
|
+
t['Paramaters'].nil? ? t['Parameters'].keys : []
|
21
|
+
end
|
22
|
+
|
23
|
+
def read_parameters_from_entry
|
24
|
+
h = {}
|
25
|
+
read_parameters_from_template.each do |p|
|
26
|
+
h[p] = @entry.attributes[p] if @entry.attributes[p]
|
27
|
+
end
|
28
|
+
h
|
29
|
+
end
|
30
|
+
|
31
|
+
def create
|
32
|
+
@cf.create :name => @name,
|
33
|
+
:parameters => read_parameters_from_entry,
|
34
|
+
:template => @template
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Stackster
|
2
|
+
class StackFormater
|
3
|
+
|
4
|
+
def initialize(args)
|
5
|
+
@sr = StackReader.new :name => args[:name],
|
6
|
+
:environment => args[:environment]
|
7
|
+
end
|
8
|
+
|
9
|
+
def display_short
|
10
|
+
{
|
11
|
+
'attributes' => @sr.attributes,
|
12
|
+
'status' => @sr.status,
|
13
|
+
'outputs' => @sr.outputs,
|
14
|
+
'last_event' => events_summary.first,
|
15
|
+
'resources' => resources_summary,
|
16
|
+
'instances' => instances_public_ip_addresses
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def instances_public_ip_addresses
|
21
|
+
@sr.instances.map { |i| i['instancesSet'].first['ipAddress'] }
|
22
|
+
end
|
23
|
+
|
24
|
+
def resources_summary
|
25
|
+
@sr.resources.map do |i|
|
26
|
+
{ 'LogicalResourceId' => i['LogicalResourceId'],
|
27
|
+
'PhysicalResourceId' => i['PhysicalResourceId'] }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def events_summary
|
32
|
+
@sr.events.map do |i|
|
33
|
+
{ 'ResourceStatus' => i['ResourceStatus'],
|
34
|
+
'LogicalResourceId' => i['LogicalResourceId'] }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Stackster
|
2
|
+
class StackReader
|
3
|
+
|
4
|
+
def initialize(args)
|
5
|
+
@name = args[:name]
|
6
|
+
@environment = args[:environment]
|
7
|
+
@cf = AWS::CloudFormation.new @environment
|
8
|
+
@entry = Entry.find :name => @name,
|
9
|
+
:environment => @environment
|
10
|
+
end
|
11
|
+
|
12
|
+
def attributes
|
13
|
+
@entry.attributes
|
14
|
+
end
|
15
|
+
|
16
|
+
def outputs
|
17
|
+
@cf.stack_outputs @name
|
18
|
+
end
|
19
|
+
|
20
|
+
def status
|
21
|
+
@cf.stack_status @name
|
22
|
+
end
|
23
|
+
|
24
|
+
def events
|
25
|
+
@cf.stack_events @name
|
26
|
+
end
|
27
|
+
|
28
|
+
def resources
|
29
|
+
@cf.stack_resources @name
|
30
|
+
end
|
31
|
+
|
32
|
+
def last_event
|
33
|
+
events.first
|
34
|
+
end
|
35
|
+
|
36
|
+
def instances
|
37
|
+
ir = InstanceReader.new @environment
|
38
|
+
ir.list_stack_instances @name
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'stackster/stack/stack_creater'
|
2
|
+
require 'stackster/stack/stack_destroyer'
|
3
|
+
require 'stackster/stack/stack_reader'
|
4
|
+
require 'stackster/stack/stack_formater'
|
5
|
+
require 'stackster/stack/stack_lister'
|
6
|
+
|
7
|
+
module Stackster
|
8
|
+
class Stack
|
9
|
+
|
10
|
+
def initialize(args)
|
11
|
+
@name = args[:name]
|
12
|
+
@environment = args[:environment]
|
13
|
+
@entry = Entry.new :name => @name,
|
14
|
+
:environment => @environment
|
15
|
+
end
|
16
|
+
|
17
|
+
def create(args)
|
18
|
+
@entry.set_attributes args[:attributes]
|
19
|
+
@entry.save
|
20
|
+
|
21
|
+
s = StackCreater.new :name => @name,
|
22
|
+
:environment => @environment,
|
23
|
+
:entry => @entry,
|
24
|
+
:template => args[:template]
|
25
|
+
s.create
|
26
|
+
end
|
27
|
+
|
28
|
+
def destroy
|
29
|
+
s = StackDestroyer.new :name => @name,
|
30
|
+
:environment => @environment
|
31
|
+
s.destroy
|
32
|
+
@entry.delete_attributes
|
33
|
+
end
|
34
|
+
|
35
|
+
def show
|
36
|
+
s = StackReader.new :name => @name,
|
37
|
+
:environment => @environment
|
38
|
+
s.show
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
data/lib/stackster.rb
ADDED
data/stackster.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "stackster/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "stackster"
|
7
|
+
s.version = Stackster::VERSION
|
8
|
+
s.authors = ["Brett Weaver"]
|
9
|
+
s.email = ["brett@weav.net"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{I make deployments easier}
|
12
|
+
s.description = %q{Thats what I do}
|
13
|
+
|
14
|
+
s.rubyforge_project = "stackster"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
s.add_runtime_dependency "fog"
|
24
|
+
s.add_runtime_dependency "trollop"
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: stackster
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Brett Weaver
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: fog
|
16
|
+
requirement: &70312936224120 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70312936224120
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: trollop
|
27
|
+
requirement: &70312936223700 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70312936223700
|
36
|
+
description: Thats what I do
|
37
|
+
email:
|
38
|
+
- brett@weav.net
|
39
|
+
executables:
|
40
|
+
- stackster
|
41
|
+
extensions: []
|
42
|
+
extra_rdoc_files: []
|
43
|
+
files:
|
44
|
+
- .gitignore
|
45
|
+
- Gemfile
|
46
|
+
- Rakefile
|
47
|
+
- bin/stackster
|
48
|
+
- lib/stackster.rb
|
49
|
+
- lib/stackster/aws.rb
|
50
|
+
- lib/stackster/aws/cloud_formation.rb
|
51
|
+
- lib/stackster/aws/ec2.rb
|
52
|
+
- lib/stackster/aws/simpledb.rb
|
53
|
+
- lib/stackster/cli.rb
|
54
|
+
- lib/stackster/config.rb
|
55
|
+
- lib/stackster/entry.rb
|
56
|
+
- lib/stackster/entry/entry_lister.rb
|
57
|
+
- lib/stackster/instance.rb
|
58
|
+
- lib/stackster/instance/instance_reader.rb
|
59
|
+
- lib/stackster/stack.rb
|
60
|
+
- lib/stackster/stack/stack_creater.rb
|
61
|
+
- lib/stackster/stack/stack_destroyer.rb
|
62
|
+
- lib/stackster/stack/stack_formater.rb
|
63
|
+
- lib/stackster/stack/stack_lister.rb
|
64
|
+
- lib/stackster/stack/stack_reader.rb
|
65
|
+
- lib/stackster/version.rb
|
66
|
+
- stackster.gemspec
|
67
|
+
homepage: ''
|
68
|
+
licenses: []
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
segments:
|
80
|
+
- 0
|
81
|
+
hash: -4027145731470457093
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
segments:
|
89
|
+
- 0
|
90
|
+
hash: -4027145731470457093
|
91
|
+
requirements: []
|
92
|
+
rubyforge_project: stackster
|
93
|
+
rubygems_version: 1.8.16
|
94
|
+
signing_key:
|
95
|
+
specification_version: 3
|
96
|
+
summary: I make deployments easier
|
97
|
+
test_files: []
|