cf_deployer 1.3.9 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/ChangeLog.md +6 -2
- data/DETAILS.md +12 -0
- data/lib/cf_deployer/component.rb +4 -3
- data/lib/cf_deployer/config_loader.rb +6 -4
- data/lib/cf_deployer/config_validation.rb +0 -1
- data/lib/cf_deployer/defaults.rb +2 -0
- data/lib/cf_deployer/stack.rb +35 -13
- data/lib/cf_deployer/version.rb +1 -1
- data/spec/unit/component_spec.rb +37 -7
- data/spec/unit/config_loader_spec.rb +2 -2
- data/spec/unit/stack_spec.rb +76 -14
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ff8335edd7be5ca468d0a45f6cf614f401cbdce
|
4
|
+
data.tar.gz: ceecfb7632c801761d0b655f87a147ce181dfd1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 330695b0672d8af04459a26eb04973cf11e3f95415d453743fb9fed6d269530633bb876d37527e366b990d3980628c3778db8715cfbf9ac40e00eae35b6fecfc
|
7
|
+
data.tar.gz: 7416a2d5697ef2d66fcd89b556c1adb902e299f4acfa84c36746c51694d775b8898b39d751485cd50e73666f79e08e79d09f6a37331922809468ef1e09630fb7
|
data/.travis.yml
CHANGED
data/ChangeLog.md
CHANGED
@@ -22,10 +22,10 @@ version 1.2.10
|
|
22
22
|
- Update DETAILS.md
|
23
23
|
|
24
24
|
version 1.2.11
|
25
|
-
- Remove record set in R53 when stacks are deployed
|
25
|
+
- Remove record set in R53 when stacks are deployed
|
26
26
|
|
27
27
|
version 1.3.1
|
28
|
-
- Adding way to run hooks manually (outside of deploy)
|
28
|
+
- Adding way to run hooks manually (outside of deploy)
|
29
29
|
- Adding new command 'diff' to allow diffing between the deployed JSON
|
30
30
|
- Split after-create and after-update hooks for create-or-update strategy
|
31
31
|
|
@@ -50,3 +50,7 @@ version 1.3.8
|
|
50
50
|
version 1.3.9
|
51
51
|
- Allow new ASGs to be added to template (See: https://github.com/manheim/cf_deployer/issues/31)
|
52
52
|
|
53
|
+
version 1.4.0
|
54
|
+
- Merge settings from parent component when given (https://github.com/manheim/cf_deployer/pull/37)
|
55
|
+
- Added support for stack policies (https://github.com/manheim/cf_deployer/pull/40)
|
56
|
+
- Fix broken Travis builds with newer version of bundler (https://github.com/manheim/cf_deployer/pull/42)
|
data/DETAILS.md
CHANGED
@@ -82,6 +82,18 @@ Used by the gem for blue/green deployments and naming conventions
|
|
82
82
|
* keep-previous-stack (True/False: for Cname-Swap and Auto Scaling Group Swap, previous stack will be kept after new stack is created by default. Set it to false to delete the previous stack)
|
83
83
|
* raise-error-for-unused-inputs (True/False: it is false by default. If it is set to true, errors will be thrown if there are any inputs which are not used as parameters of CloudFormation json templates. If it is set to false or the setting does not exist, warnings will be printed in the console if there are un-used inputs.)
|
84
84
|
* auto-scaling-group-name-output
|
85
|
+
* create-stack-policy: The name of the stack policy to be used during the
|
86
|
+
creation of the component stack. The location of the policy json file is
|
87
|
+
assumed to be "config/{create-stack-policy}.json". The intended use of
|
88
|
+
this setting is to make it persistent by placing it in your
|
89
|
+
`cf_deployer.yml` file.
|
90
|
+
* override-stack-policy: The name of the override stack policy to be used
|
91
|
+
during an update of the component stack. The location of the policy json
|
92
|
+
file is assumed to be "config/{override-stack-policy}.json". Since the
|
93
|
+
override policy is only used occasionally to override the
|
94
|
+
`create-stack-policy`, the intended use of this setting is for it to be
|
95
|
+
called via the `--settings` cli flag, v.s. being persistently set in the
|
96
|
+
config file.
|
85
97
|
* **For Components Using the Cname-Swap Deployment Strategy**
|
86
98
|
* dns-fqdn (DNS record set name, for example, myApp.api.abc.com)
|
87
99
|
* dns-zone (DNS hosted zone, for example, api.abc.com)
|
@@ -35,7 +35,7 @@ module CfDeployer
|
|
35
35
|
def json
|
36
36
|
resolve_settings
|
37
37
|
puts "#{name} json template:"
|
38
|
-
puts ConfigLoader.
|
38
|
+
puts ConfigLoader.erb_to_json(name, @context)
|
39
39
|
end
|
40
40
|
|
41
41
|
def diff
|
@@ -43,7 +43,7 @@ module CfDeployer
|
|
43
43
|
current_json = strategy.active_template
|
44
44
|
if current_json
|
45
45
|
puts "#{name} json template diff:"
|
46
|
-
new_json = ConfigLoader.
|
46
|
+
new_json = ConfigLoader.erb_to_json(name, @context)
|
47
47
|
Diffy::Diff.default_format = :color
|
48
48
|
puts Diffy::Diff.new( current_json, new_json )
|
49
49
|
else
|
@@ -100,8 +100,9 @@ module CfDeployer
|
|
100
100
|
|
101
101
|
def resolve_settings
|
102
102
|
inputs.each do |key, value|
|
103
|
-
if(value.is_a?
|
103
|
+
if(value.is_a?(Hash) && value.key?(:component))
|
104
104
|
dependency = @dependencies.find { |d| d.name == value[:component] }
|
105
|
+
raise "No component '#{value[:component]}' found when attempting to derive input '#{key}'" unless dependency
|
105
106
|
output_key = value[:'output-key']
|
106
107
|
inputs[key] = dependency.output_value(output_key)
|
107
108
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module CfDeployer
|
2
2
|
class ConfigLoader
|
3
3
|
|
4
|
-
def self.
|
5
|
-
json_file = File.join(config[:config_dir], "#{
|
4
|
+
def self.erb_to_json filename, config
|
5
|
+
json_file = File.join(config[:config_dir], "#{filename}.json")
|
6
6
|
raise ApplicationError.new("#{json_file} is missing") unless File.exists?(json_file)
|
7
|
-
CfDeployer::Log.info "ERBing JSON for #{
|
7
|
+
CfDeployer::Log.info "ERBing JSON for #{filename}"
|
8
8
|
ERB.new(File.read(json_file)).result(binding)
|
9
9
|
rescue RuntimeError,TypeError,NoMethodError => e
|
10
10
|
self.new.send :error_document, File.read(json_file)
|
@@ -112,6 +112,8 @@ module CfDeployer
|
|
112
112
|
if component[:settings][:'keep-previous-stack'] == nil
|
113
113
|
component[:settings][:'keep-previous-stack'] = Defaults::KeepPreviousStack
|
114
114
|
end
|
115
|
+
component[:settings][:'create-stack-policy'] ||= Defaults::CreateStackPolicy
|
116
|
+
component[:settings][:'override-stack-policy'] ||= Defaults::OverrideStackPolicy
|
115
117
|
end
|
116
118
|
end
|
117
119
|
|
@@ -131,7 +133,7 @@ module CfDeployer
|
|
131
133
|
end
|
132
134
|
end
|
133
135
|
|
134
|
-
json_content = self.class.
|
136
|
+
json_content = self.class.erb_to_json component.to_s, config
|
135
137
|
CfDeployer::Log.info "Parsing JSON for #{component}"
|
136
138
|
begin
|
137
139
|
JSON.load json_content
|
data/lib/cf_deployer/defaults.rb
CHANGED
data/lib/cf_deployer/stack.rb
CHANGED
@@ -17,13 +17,25 @@ module CfDeployer
|
|
17
17
|
|
18
18
|
def deploy
|
19
19
|
config_dir = @context[:config_dir]
|
20
|
-
template = CfDeployer::ConfigLoader.
|
20
|
+
template = CfDeployer::ConfigLoader.erb_to_json(@component, @context)
|
21
21
|
capabilities = @context[:capabilities] || []
|
22
22
|
notify = @context[:notify] || []
|
23
23
|
tags = @context[:tags] || {}
|
24
24
|
params = to_str(@context[:inputs].select{|key, value| @context[:defined_parameters].keys.include?(key)})
|
25
25
|
CfDeployer::Driver::DryRun.guard "Skipping deploy" do
|
26
|
-
exists?
|
26
|
+
if exists?
|
27
|
+
override_policy_json = nil
|
28
|
+
unless @context[:settings][:'override-stack-policy'].nil?
|
29
|
+
override_policy_json = CfDeployer::ConfigLoader.erb_to_json(@context[:settings][:'override-stack-policy'], @context)
|
30
|
+
end
|
31
|
+
update_stack(template, params, capabilities, tags, override_policy_json)
|
32
|
+
else
|
33
|
+
create_policy_json = nil
|
34
|
+
unless @context[:settings][:'create-stack-policy'].nil?
|
35
|
+
create_policy_json = CfDeployer::ConfigLoader.erb_to_json(@context[:settings][:'create-stack-policy'], @context)
|
36
|
+
end
|
37
|
+
create_stack(template, params, capabilities, tags, notify, create_policy_json)
|
38
|
+
end
|
27
39
|
end
|
28
40
|
end
|
29
41
|
|
@@ -106,22 +118,32 @@ module CfDeployer
|
|
106
118
|
hash.each { |k,v| hash[k] = v.to_s }
|
107
119
|
end
|
108
120
|
|
109
|
-
def update_stack(template, params, capabilities, tags)
|
121
|
+
def update_stack(template, params, capabilities, tags, override_policy_json)
|
110
122
|
Log.info "Updating stack #{@stack_name}..."
|
111
|
-
|
112
|
-
|
113
|
-
|
123
|
+
args = {
|
124
|
+
:capabilities => capabilities,
|
125
|
+
:parameters => params
|
126
|
+
}
|
127
|
+
unless override_policy_json.nil?
|
128
|
+
args[:stack_policy_during_update_body] = override_policy_json
|
129
|
+
end
|
130
|
+
@cf_driver.update_stack(template, args)
|
114
131
|
wait_for_stack_op_terminate
|
115
132
|
end
|
116
133
|
|
117
|
-
def create_stack(template, params, capabilities, tags, notify)
|
134
|
+
def create_stack(template, params, capabilities, tags, notify, create_policy_json)
|
118
135
|
Log.info "Creating stack #{@stack_name}..."
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
136
|
+
args = {
|
137
|
+
:disable_rollback => true,
|
138
|
+
:capabilities => capabilities,
|
139
|
+
:notify => notify,
|
140
|
+
:tags => reformat_tags(tags),
|
141
|
+
:parameters => params
|
142
|
+
}
|
143
|
+
unless create_policy_json.nil?
|
144
|
+
args[:stack_policy_body] = create_policy_json
|
145
|
+
end
|
146
|
+
@cf_driver.create_stack(template, args)
|
125
147
|
wait_for_stack_op_terminate
|
126
148
|
end
|
127
149
|
|
data/lib/cf_deployer/version.rb
CHANGED
data/spec/unit/component_spec.rb
CHANGED
@@ -12,13 +12,17 @@ describe "component" do
|
|
12
12
|
:'vpc-subnets' => {
|
13
13
|
:component => 'base',
|
14
14
|
:'output-key' => 'subnets'
|
15
|
+
},
|
16
|
+
:'nested-hash' => {
|
17
|
+
:foo => 'foo value',
|
18
|
+
:bar => 'bar value'
|
15
19
|
}
|
16
20
|
}
|
17
21
|
}
|
18
22
|
@base = CfDeployer::Component.new('myApp', 'uat', 'base', {})
|
19
23
|
@db = CfDeployer::Component.new('myApp', 'uat', 'db', {})
|
20
24
|
|
21
|
-
@web = CfDeployer::Component.new('myApp', 'uat', '
|
25
|
+
@web = CfDeployer::Component.new('myApp', 'uat', 'component', @context)
|
22
26
|
@web.dependencies << @base
|
23
27
|
@web.dependencies << @db
|
24
28
|
@base.children << @web
|
@@ -30,13 +34,39 @@ describe "component" do
|
|
30
34
|
it 'should revolve settings from parent components if parent components has been deployed' do
|
31
35
|
allow(@base).to receive(:exists?){ true }
|
32
36
|
allow(@base).to receive(:output_value).with('subnets') { 'abcd1234, edfas1234' }
|
33
|
-
expect(CfDeployer::ConfigLoader).to receive(:
|
37
|
+
expect(CfDeployer::ConfigLoader).to receive(:erb_to_json).with('component', @context)
|
34
38
|
@web.json
|
35
39
|
|
36
40
|
expect(@context[:inputs][:'vpc-subnets']).to eq('abcd1234, edfas1234')
|
37
41
|
end
|
38
|
-
end
|
39
42
|
|
43
|
+
it 'should not attempt to resolve settings from referenced component unless component is specified' do
|
44
|
+
expected = {
|
45
|
+
:foo => 'foo value',
|
46
|
+
:bar => 'bar value'
|
47
|
+
}
|
48
|
+
allow(@base).to receive(:output_value).with('subnets') { 'abcd1234, edfas1234' }
|
49
|
+
expect(CfDeployer::ConfigLoader).to receive(:erb_to_json).with('component', @context)
|
50
|
+
@web.json
|
51
|
+
|
52
|
+
expect(@context[:inputs][:'nested-hash']).to eq(expected)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should provide a descriptive error message when referenced component does not exist' do
|
56
|
+
context = {
|
57
|
+
:inputs => {
|
58
|
+
:some_key => {
|
59
|
+
:component => 'blah',
|
60
|
+
:'output-key' => 'referenced_key'
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
expected_message = "No component 'blah' found when attempting to derive input 'some_key'"
|
65
|
+
|
66
|
+
component = CfDeployer::Component.new('myApp', 'uat', 'component', context)
|
67
|
+
expect {component.json}.to raise_error(expected_message)
|
68
|
+
end
|
69
|
+
end
|
40
70
|
|
41
71
|
it "should destroy component" do
|
42
72
|
expect(@strategy).to receive(:destroy)
|
@@ -72,7 +102,7 @@ describe "component" do
|
|
72
102
|
end
|
73
103
|
|
74
104
|
it "should find direct dependencies" do
|
75
|
-
web = CfDeployer::Component.new('myApp', 'uat', '
|
105
|
+
web = CfDeployer::Component.new('myApp', 'uat', 'component', {})
|
76
106
|
base = CfDeployer::Component.new('myApp', 'uat', 'base', {})
|
77
107
|
web.dependencies << base
|
78
108
|
|
@@ -80,7 +110,7 @@ describe "component" do
|
|
80
110
|
end
|
81
111
|
|
82
112
|
it "should find transitive dependencies" do
|
83
|
-
web = CfDeployer::Component.new('myApp', 'uat', '
|
113
|
+
web = CfDeployer::Component.new('myApp', 'uat', 'component', {})
|
84
114
|
haproxy = CfDeployer::Component.new('myApp', 'uat', 'haproxy', {})
|
85
115
|
base = CfDeployer::Component.new('myApp', 'uat', 'base', {})
|
86
116
|
|
@@ -91,7 +121,7 @@ describe "component" do
|
|
91
121
|
end
|
92
122
|
|
93
123
|
it "should find cyclic dependency" do
|
94
|
-
web = CfDeployer::Component.new('myApp', 'uat', '
|
124
|
+
web = CfDeployer::Component.new('myApp', 'uat', 'component', {})
|
95
125
|
haproxy = CfDeployer::Component.new('myApp', 'uat', 'haproxy', {})
|
96
126
|
base = CfDeployer::Component.new('myApp', 'uat', 'base', {})
|
97
127
|
foo = CfDeployer::Component.new('myApp', 'uat', 'foo', {})
|
@@ -127,7 +157,7 @@ describe "component" do
|
|
127
157
|
it 'should raise an error that there is no stack for the component' do
|
128
158
|
allow(@strategy).to receive(:exists?) { false }
|
129
159
|
expect(@strategy).not_to receive(:switch)
|
130
|
-
expect { @web.switch }.to raise_error 'No stack exists for component:
|
160
|
+
expect { @web.switch }.to raise_error 'No stack exists for component: component'
|
131
161
|
end
|
132
162
|
end
|
133
163
|
|
@@ -329,13 +329,13 @@ environments:
|
|
329
329
|
|
330
330
|
it "should ERB the component JSON and make the parsed template available" do
|
331
331
|
config = CfDeployer::ConfigLoader.new.load(:'config-file' => @config_file, :environment => 'DrWho')
|
332
|
-
CfDeployer::ConfigLoader.
|
332
|
+
CfDeployer::ConfigLoader.erb_to_json('json-with-erb', config[:components][:'json-with-erb']).should include('DrWho')
|
333
333
|
end
|
334
334
|
|
335
335
|
it 'should use error_document to show the broken document when parsing broken ERB' do
|
336
336
|
config = { :config_dir => File.dirname(@config_file) }
|
337
337
|
CfDeployer::ConfigLoader.any_instance.should_receive(:error_document)
|
338
|
-
expect { CfDeployer::ConfigLoader.
|
338
|
+
expect { CfDeployer::ConfigLoader.erb_to_json('broken_erb', config) }.to raise_error
|
339
339
|
end
|
340
340
|
|
341
341
|
it 'should use error_document to show the broken document when parsing broken json' do
|
data/spec/unit/stack_spec.rb
CHANGED
@@ -1,23 +1,30 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe CfDeployer::Stack do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
before do
|
5
|
+
@cf_driver = double CfDeployer::Driver::CloudFormation
|
6
|
+
@stack = CfDeployer::Stack.new('test', 'web', {:cf_driver => @cf_driver})
|
7
|
+
@config = {
|
8
|
+
:inputs => { :foo => :bar, :goo => :hoo },
|
9
|
+
:tags => { :app => 'app1', :env => 'dev'},
|
10
|
+
:defined_parameters => { :foo => 'bar' },
|
11
|
+
:notify => ['topic1_arn', 'topic2_arn'],
|
12
|
+
:cf_driver => @cf_driver,
|
13
|
+
:settings => {
|
14
|
+
'create-stack-policy' => nil,
|
15
|
+
'override-stack-policy' => nil
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
8
19
|
|
9
20
|
context '#deploy' do
|
10
|
-
it '
|
11
|
-
|
12
|
-
|
13
|
-
:defined_parameters => { :foo => 'bar' },
|
14
|
-
:notify => ['topic1_arn', 'topic2_arn'],
|
15
|
-
:cf_driver => @cf_driver }
|
16
|
-
template = { :resourses => {}}
|
17
|
-
allow(CfDeployer::ConfigLoader).to receive(:component_json).with('web', config).and_return(template)
|
21
|
+
it 'creates a stack, when it doesnt exist' do
|
22
|
+
template = { :resources => {}}
|
23
|
+
allow(CfDeployer::ConfigLoader).to receive(:erb_to_json).with('web', @config).and_return(template)
|
18
24
|
allow(@cf_driver).to receive(:stack_exists?) { false }
|
19
25
|
allow(@cf_driver).to receive(:stack_status) { :create_complete }
|
20
|
-
expected_opt = {
|
26
|
+
expected_opt = {
|
27
|
+
:disable_rollback => true,
|
21
28
|
:capabilities => [],
|
22
29
|
:notify => ['topic1_arn', 'topic2_arn'],
|
23
30
|
:tags => [{'Key' => 'app', 'Value' => 'app1'},
|
@@ -25,9 +32,64 @@ describe CfDeployer::Stack do
|
|
25
32
|
:parameters => {:foo => 'bar'}
|
26
33
|
}
|
27
34
|
expect(@cf_driver).to receive(:create_stack).with(template, expected_opt)
|
28
|
-
stack = CfDeployer::Stack.new('test','web', config)
|
35
|
+
stack = CfDeployer::Stack.new('test','web', @config)
|
36
|
+
stack.deploy
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'creates a stack using a policy when defined' do
|
40
|
+
template = { :resources => {}}
|
41
|
+
create_policy = { :Statement => [] }
|
42
|
+
@config[:settings][:'create-stack-policy'] = 'create-policy'
|
43
|
+
allow(CfDeployer::ConfigLoader).to receive(:erb_to_json).with('web', @config).and_return(template)
|
44
|
+
allow(CfDeployer::ConfigLoader).to receive(:erb_to_json).with('create-policy', @config).and_return(create_policy)
|
45
|
+
allow(@cf_driver).to receive(:stack_exists?) { false }
|
46
|
+
allow(@cf_driver).to receive(:stack_status) { :create_complete }
|
47
|
+
expected_opt = {
|
48
|
+
:disable_rollback => true,
|
49
|
+
:capabilities => [],
|
50
|
+
:notify => ['topic1_arn', 'topic2_arn'],
|
51
|
+
:tags => [{'Key' => 'app', 'Value' => 'app1'},
|
52
|
+
{'Key' => 'env', 'Value' => 'dev'}],
|
53
|
+
:parameters => {:foo => 'bar'},
|
54
|
+
:stack_policy_body => create_policy
|
55
|
+
}
|
56
|
+
expect(@cf_driver).to receive(:create_stack).with(template, expected_opt)
|
57
|
+
stack = CfDeployer::Stack.new('test','web', @config)
|
29
58
|
stack.deploy
|
30
59
|
end
|
60
|
+
|
61
|
+
it 'updates a stack, when it exists' do
|
62
|
+
template = { :resources => {}}
|
63
|
+
allow(CfDeployer::ConfigLoader).to receive(:erb_to_json).with('web', @config).and_return(template)
|
64
|
+
allow(@cf_driver).to receive(:stack_exists?) { true }
|
65
|
+
allow(@cf_driver).to receive(:stack_status) { :create_complete }
|
66
|
+
expected_opt = {
|
67
|
+
:capabilities => [],
|
68
|
+
:parameters => {:foo => 'bar'}
|
69
|
+
}
|
70
|
+
expect(@cf_driver).to receive(:update_stack).with(template, expected_opt)
|
71
|
+
stack = CfDeployer::Stack.new('test','web', @config)
|
72
|
+
stack.deploy
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'updates a stack using the override policy, when defined' do
|
76
|
+
template = { :resources => {}}
|
77
|
+
override_policy = { :Statement => [] }
|
78
|
+
@config[:settings][:'override-stack-policy'] = 'override-policy'
|
79
|
+
allow(CfDeployer::ConfigLoader).to receive(:erb_to_json).with('web', @config).and_return(template)
|
80
|
+
allow(CfDeployer::ConfigLoader).to receive(:erb_to_json).with('override-policy', @config).and_return(override_policy)
|
81
|
+
allow(@cf_driver).to receive(:stack_exists?) { true }
|
82
|
+
allow(@cf_driver).to receive(:stack_status) { :create_complete }
|
83
|
+
expected_opt = {
|
84
|
+
:capabilities => [],
|
85
|
+
:parameters => {:foo => 'bar'},
|
86
|
+
:stack_policy_during_update_body => override_policy
|
87
|
+
}
|
88
|
+
expect(@cf_driver).to receive(:update_stack).with(template, expected_opt)
|
89
|
+
stack = CfDeployer::Stack.new('test','web', @config)
|
90
|
+
stack.deploy
|
91
|
+
end
|
92
|
+
|
31
93
|
end
|
32
94
|
|
33
95
|
context '#parameters' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cf_deployer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jame Brechtel
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2016-04-12 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: aws-sdk
|