dpl-lambda 1.9.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: 2ca31356644301a0e6cac4f7a8368e7d534ecf55
4
+ data.tar.gz: 8f10f9abd9d4f670a0349105bf8c2f079382d275
5
+ SHA512:
6
+ metadata.gz: dd57f55db2c061b649796fb1101a522f9b1539042c5b60f7be845d9508447a4530d54ea6b05c869849b2e9c3a349334243b4c203f115e0fcbd20670351c53248
7
+ data.tar.gz: 6ae409607b321e1f0349abe6bc47bc6c42b5e38f2ee98c614e4abf0b7f27a557a04e8159d1a4baedbd58a2df8081504fd4bcdeca832bf3ced314f8ba6663da96
@@ -0,0 +1,3 @@
1
+ require './gemspec_helper'
2
+
3
+ gemspec_for 'lambda', [['aws-sdk', '~> 2.0'], ['rubyzip']]
@@ -0,0 +1,235 @@
1
+ require 'json'
2
+ require 'tempfile'
3
+ require 'fileutils'
4
+ require 'aws-sdk'
5
+ require 'zip'
6
+
7
+ module DPL
8
+ class Provider
9
+ class Lambda < Provider
10
+ def lambda
11
+ @lambda ||= ::Aws::Lambda::Client.new(lambda_options)
12
+ end
13
+
14
+ def lambda_options
15
+ {
16
+ region: options[:region] || 'us-east-1',
17
+ credentials: ::Aws::Credentials.new(option(:access_key_id), option(:secret_access_key))
18
+ }
19
+ end
20
+
21
+ def push_app
22
+
23
+ # The original LambdaPreview client supported create/update in one call
24
+ # To keep compatibility we try to fetch the function and then decide
25
+ # whether to update the code or create a new function
26
+
27
+ function_name = options[:name] || option(:function_name)
28
+
29
+ begin
30
+ response = lambda.get_function({function_name: function_name})
31
+
32
+ log "Function #{function_name} already exists, updating."
33
+
34
+ # Options defined at
35
+ # https://docs.aws.amazon.com/sdkforruby/api/Aws/Lambda/Client.html#update_function_configuration-instance_method
36
+ response = lambda.update_function_configuration({
37
+ function_name: function_name,
38
+ description: options[:description] || default_description,
39
+ timeout: options[:timeout] || default_timeout,
40
+ memory_size: options[:memory_size] || default_memory_size,
41
+ role: option(:role),
42
+ handler: handler,
43
+ runtime: options[:runtime] || default_runtime,
44
+ vpc_config: vpc_config,
45
+ environment: environment_variables,
46
+ dead_letter_config: dead_letter_arn,
47
+ kms_key_arn: options[:kms_key_arn] || default_kms_key_arn,
48
+ tracing_config: tracing_mode
49
+ })
50
+
51
+ log "Updated configuration of function: #{response.function_name}."
52
+
53
+ if function_tags
54
+ log "Add tags to function #{response.function_name}."
55
+ response = lambda.tag_resource({
56
+ resource: response.function_arn,
57
+ tags: function_tags
58
+ })
59
+ end
60
+
61
+ # Options defined at
62
+ # https://docs.aws.amazon.com/sdkforruby/api/Aws/Lambda/Client.html#update_function_code-instance_method
63
+ response = lambda.update_function_code({
64
+ function_name: options[:name] || option(:function_name),
65
+ zip_file: function_zip,
66
+ publish: publish
67
+ })
68
+
69
+ log "Updated code of function: #{response.function_name}."
70
+ rescue ::Aws::Lambda::Errors::ResourceNotFoundException
71
+ log "Function #{function_name} does not exist, creating."
72
+ # Options defined at
73
+ # https://docs.aws.amazon.com/lambda/latest/dg/API_CreateFunction.html
74
+ response = lambda.create_function({
75
+ function_name: options[:name] || option(:function_name),
76
+ description: options[:description] || default_description,
77
+ timeout: options[:timeout] || default_timeout,
78
+ memory_size: options[:memory_size] || default_memory_size,
79
+ role: option(:role),
80
+ handler: handler,
81
+ code: {
82
+ zip_file: function_zip,
83
+ },
84
+ runtime: options[:runtime] || default_runtime,
85
+ publish: publish,
86
+ vpc_config: vpc_config,
87
+ environment: environment_variables,
88
+ dead_letter_config: dead_letter_arn,
89
+ kms_key_arn: options[:kms_key_arn] || default_kms_key_arn,
90
+ tracing_config: tracing_mode,
91
+ tags: function_tags
92
+ })
93
+
94
+ log "Created lambda: #{response.function_name}."
95
+ end
96
+ rescue ::Aws::Lambda::Errors::ServiceException => exception
97
+ error(exception.message)
98
+ rescue ::Aws::Lambda::Errors::InvalidParameterValueException => exception
99
+ error(exception.message)
100
+ rescue ::Aws::Lambda::Errors::ResourceNotFoundException => exception
101
+ error(exception.message)
102
+ end
103
+
104
+ def handler
105
+ module_name = options[:module_name] || default_module_name
106
+ handler_name = option(:handler_name)
107
+
108
+ "#{module_name}.#{handler_name}"
109
+ end
110
+
111
+ def function_zip
112
+ target_zip_path = File.absolute_path(options[:zip] || Dir.pwd)
113
+ dest_file_path = output_file_path
114
+
115
+ if File.directory?(target_zip_path)
116
+ zip_directory(dest_file_path, target_zip_path)
117
+ elsif File.file?(target_zip_path)
118
+ zip_file(dest_file_path, target_zip_path)
119
+ else
120
+ error('Invalid zip option. If set, must be path to directory, js file, or a zip file.')
121
+ end
122
+
123
+ File.new(dest_file_path)
124
+ end
125
+
126
+ def zip_file(dest_file_path, target_file_path)
127
+ if File.extname(target_file_path) == '.zip'
128
+ # Just copy it to the destination right away, since it is already a zip.
129
+ FileUtils.cp(target_file_path, dest_file_path)
130
+ dest_file_path
131
+ else
132
+ # Zip up the file.
133
+ src_directory_path = File.dirname(target_file_path)
134
+ files = [ target_file_path ]
135
+
136
+ create_zip(dest_file_path, src_directory_path, files)
137
+ end
138
+ end
139
+
140
+ def zip_directory(dest_file_path, target_directory_path)
141
+ files = Dir[File.join(target_directory_path, '**', '**')]
142
+ create_zip(dest_file_path, target_directory_path, files)
143
+ end
144
+
145
+ def create_zip(dest_file_path, src_directory_path, files)
146
+ Zip::File.open(dest_file_path, Zip::File::CREATE) do |zipfile|
147
+ files.each do |file|
148
+ zipfile.add(file.sub(src_directory_path + File::SEPARATOR, ''), file)
149
+ end
150
+ end
151
+
152
+ dest_file_path
153
+ end
154
+
155
+ def needs_key?
156
+ false
157
+ end
158
+
159
+ def check_auth
160
+ log "Using Access Key: #{option(:access_key_id)[-4..-1].rjust(20, '*')}"
161
+ end
162
+
163
+ def output_file_path
164
+ @output_file_path ||= '/tmp/' + random_chars(8) + '-lambda.zip'
165
+ end
166
+
167
+ def vpc_config
168
+ options[:subnet_ids] && options[:security_group_ids] ? { :subnet_ids => Array(options[:subnet_ids]), :security_group_ids => Array(options[:security_group_ids]) } : nil
169
+ end
170
+
171
+ def environment_variables
172
+ options[:environment_variables] ? { :variables => split_string_array_to_hash(options[:environment_variables]) } : nil
173
+ end
174
+
175
+ def dead_letter_arn
176
+ options[:dead_letter_arn] ? { :target_arn => options[:dead_letter_arn]} : nil
177
+ end
178
+
179
+ def tracing_mode
180
+ options[:tracing_mode] ? { :mode => options[:tracing_mode]} : nil
181
+ end
182
+
183
+ def default_kms_key_arn
184
+ nil
185
+ end
186
+
187
+ def function_tags
188
+ options[:function_tags] ? split_string_array_to_hash(options[:function_tags]) : nil
189
+ end
190
+
191
+ def default_runtime
192
+ 'nodejs'
193
+ end
194
+
195
+ def default_timeout
196
+ 3 # seconds
197
+ end
198
+
199
+ def default_description
200
+ "Deploy build #{context.env['TRAVIS_BUILD_NUMBER']} to AWS Lambda via Travis CI"
201
+ end
202
+
203
+ def default_memory_size
204
+ 128
205
+ end
206
+
207
+ def default_module_name
208
+ 'index'
209
+ end
210
+
211
+ def publish
212
+ !!options[:publish]
213
+ end
214
+
215
+ def split_string_array_to_hash(arr, delimiter="=")
216
+ variables = {}
217
+ Array(arr).map do |val|
218
+ keyval = val.split(delimiter)
219
+ variables[keyval[0]] = keyval[1]
220
+ end
221
+ variables
222
+ end
223
+
224
+ def random_chars(count=8)
225
+ (36**(count-1) + rand(36**count - 36**(count-1))).to_s(36)
226
+ end
227
+
228
+ def cleanup
229
+ end
230
+
231
+ def uncleanup
232
+ end
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,434 @@
1
+ require 'spec_helper'
2
+ require 'aws-sdk'
3
+ require 'dpl/error'
4
+ require 'dpl/provider'
5
+ require 'dpl/provider/lambda'
6
+
7
+ describe DPL::Provider::Lambda do
8
+
9
+ subject :provider do
10
+ described_class.new(DummyContext.new, :access_key_id => 'qwertyuiopasdfghjklz', :secret_access_key => 'qwertyuiopasdfghjklzqwertyuiopasdfghjklz')
11
+ end
12
+
13
+ describe '#lambda_options' do
14
+ context 'without region' do
15
+ example do
16
+ options = provider.lambda_options
17
+ expect(options[:region]).to eq('us-east-1')
18
+ end
19
+ end
20
+
21
+ context 'with region' do
22
+ example do
23
+ region = 'us-west-1'
24
+ provider.options.update(:region => region)
25
+ options = provider.lambda_options
26
+ expect(options[:region]).to eq(region)
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ describe DPL::Provider::Lambda do
33
+ access_key_id = 'someaccesskey'
34
+ secret_access_key = 'somesecretaccesskey'
35
+ region = 'us-east-1'
36
+
37
+ client_options = {
38
+ stub_responses: true,
39
+ region: region,
40
+ credentials: Aws::Credentials.new(access_key_id, secret_access_key)
41
+ }
42
+
43
+ subject :provider do
44
+ described_class.new(DummyContext.new, {
45
+ access_key_id: access_key_id,
46
+ secret_access_key: secret_access_key
47
+ })
48
+ end
49
+
50
+ before :each do
51
+ FileUtils.touch provider.output_file_path
52
+ allow(provider).to receive(:lambda_options).and_return(client_options)
53
+ allow(provider).to receive(:create_zip).and_return(provider.output_file_path)
54
+ end
55
+
56
+ describe '#lambda' do
57
+ example do
58
+ expect(Aws::Lambda::Client).to receive(:new).with(client_options).once
59
+ provider.lambda
60
+ end
61
+ end
62
+
63
+ describe '#push_app' do
64
+ lambda_options = {
65
+ function_name: 'test-function',
66
+ role: 'some-role',
67
+ module_name: 'index',
68
+ handler_name: 'handler'
69
+ }
70
+
71
+ example_get_function_response = {
72
+ code: {
73
+ location: 'location',
74
+ repository_type: 's3',
75
+ },
76
+ configuration: {
77
+ function_name: 'test-function'
78
+ }
79
+ }
80
+
81
+ example_response = {
82
+ function_name: 'test-function',
83
+ function_arn: 'arn:lambda:region:account-id:function:test-function',
84
+ role: 'some-role',
85
+ handler: 'index.handler'
86
+ }
87
+
88
+ before(:each) do
89
+ old_options = provider.options
90
+ allow(provider).to receive(:options) { old_options.merge(lambda_options) }
91
+ end
92
+
93
+ context 'by creating a new function' do
94
+ before do
95
+ provider.lambda.stub_responses(:get_function, 'ResourceNotFoundException')
96
+ provider.lambda.stub_responses(:create_function, example_response)
97
+ end
98
+
99
+ example do
100
+ expect(provider).to receive(:log).with(/Function #{lambda_options[:function_name]} does not exist, creating\./)
101
+ expect(provider).to receive(:log).with(/Created lambda: #{lambda_options[:function_name]}\./)
102
+ provider.push_app
103
+ end
104
+ end
105
+
106
+ context 'by updating an existing function' do
107
+ before do
108
+ provider.lambda.stub_responses(:get_function, example_get_function_response)
109
+ provider.lambda.stub_responses(:update_function_configuration, example_response)
110
+ provider.lambda.stub_responses(:update_function_code, example_response)
111
+ end
112
+
113
+ example do
114
+ expect(provider).to receive(:log).with(/Function #{lambda_options[:function_name]} already exists, updating\./)
115
+ expect(provider).to receive(:log).with(/Updated configuration of function: #{lambda_options[:function_name]}\./)
116
+ expect(provider).to receive(:log).with(/Updated code of function: #{lambda_options[:function_name]}\./)
117
+ provider.push_app
118
+ end
119
+ end
120
+
121
+ context 'by updating an existing function with new tags' do
122
+ before do
123
+ lambda_options[:function_tags] = [ 'TAG_KEY=some-value' ]
124
+ provider.lambda.stub_responses(:get_function, example_get_function_response)
125
+ provider.lambda.stub_responses(:update_function_configuration, example_response)
126
+ provider.lambda.stub_responses(:tag_resource)
127
+ provider.lambda.stub_responses(:update_function_code, example_response)
128
+ end
129
+
130
+ example do
131
+ expect(provider).to receive(:log).with(/Function #{lambda_options[:function_name]} already exists, updating\./)
132
+ expect(provider).to receive(:log).with(/Updated configuration of function: #{lambda_options[:function_name]}\./)
133
+ expect(provider).to receive(:log).with(/Add tags to function #{lambda_options[:function_name]}\./)
134
+ expect(provider).to receive(:log).with(/Updated code of function: #{lambda_options[:function_name]}\./)
135
+ provider.push_app
136
+ end
137
+ end
138
+
139
+ context 'with a ServiceException response' do
140
+ before do
141
+ provider.lambda.stub_responses(:get_function, 'ResourceNotFoundException')
142
+ provider.lambda.stub_responses(:create_function, 'ServiceException')
143
+ end
144
+
145
+ example do
146
+ expect(provider).to receive(:error).once
147
+ provider.push_app
148
+ end
149
+ end
150
+
151
+ context 'with a InvalidParameterValueException response' do
152
+ before do
153
+ provider.lambda.stub_responses(:get_function, 'InvalidParameterValueException')
154
+ end
155
+
156
+ example do
157
+ expect(provider).to receive(:error).once
158
+ provider.push_app
159
+ end
160
+ end
161
+
162
+ context 'with a ResourceNotFoundException response' do
163
+ before do
164
+ provider.lambda.stub_responses(:get_function, 'ResourceNotFoundException')
165
+ provider.lambda.stub_responses(:create_function, 'ResourceNotFoundException')
166
+ end
167
+
168
+ example do
169
+ expect(provider).to receive(:error).once
170
+ provider.push_app
171
+ end
172
+ end
173
+ end
174
+
175
+ describe "#handler" do
176
+ context "without a module name" do
177
+ module_name = 'index'
178
+ handler_name = 'HandlerName'
179
+ expected_handler = "#{module_name}.#{handler_name}"
180
+
181
+ before do
182
+ expect(provider.options).to receive(:[]).with(:module_name).and_return(nil)
183
+ expect(provider.options).to receive(:fetch).with(:handler_name).and_return(handler_name)
184
+ end
185
+
186
+ example do
187
+ expect(provider.handler).to eq(expected_handler)
188
+ end
189
+ end
190
+
191
+ context "with a module name" do
192
+ module_name = 'ModuleName'
193
+ handler_name = 'HandlerName'
194
+ expected_handler = "#{module_name}.#{handler_name}"
195
+
196
+ before do
197
+ expect(provider.options).to receive(:[]).with(:module_name).and_return(module_name)
198
+ expect(provider.options).to receive(:fetch).with(:handler_name).and_return(handler_name)
199
+ end
200
+
201
+ example do
202
+ expect(provider.handler).to eq(expected_handler)
203
+ end
204
+ end
205
+ end
206
+
207
+ describe '#function_zip' do
208
+ context 'when zip is not specified' do
209
+ path = Dir.pwd
210
+ output_file_path = '/some/path.zip'
211
+
212
+ before do
213
+ expect(provider.options).to receive(:[]).with(:zip).and_return(nil)
214
+ expect(provider).to receive(:output_file_path).and_return(output_file_path)
215
+ expect(File).to receive(:directory?).with(path).and_return(true)
216
+ expect(provider).to receive(:zip_directory).with(output_file_path, path)
217
+ expect(File).to receive(:new).with(output_file_path)
218
+ end
219
+
220
+ example do
221
+ provider.function_zip
222
+ end
223
+ end
224
+
225
+ context 'when zip is a file path' do
226
+ path = '/some/file/path.zip'
227
+ output_file_path = '/some/path.zip'
228
+
229
+ before do
230
+ expect(provider.options).to receive(:[]).with(:zip).and_return(path)
231
+ expect(provider).to receive(:output_file_path).and_return(output_file_path)
232
+ expect(File).to receive(:directory?).with(path).and_return(false)
233
+ expect(File).to receive(:file?).with(path).and_return(true)
234
+ expect(provider).to receive(:zip_file).with(output_file_path, path)
235
+ expect(File).to receive(:new).with(output_file_path)
236
+ end
237
+
238
+ example do
239
+ provider.function_zip
240
+ end
241
+ end
242
+
243
+ context 'when zip is a directory' do
244
+ path = '/some/dir/path'
245
+ output_file_path = '/some/path.zip'
246
+
247
+ before do
248
+ expect(provider.options).to receive(:[]).with(:zip).and_return(path)
249
+ expect(provider).to receive(:output_file_path).and_return(output_file_path)
250
+ expect(File).to receive(:directory?).with(path).and_return(true)
251
+ expect(provider).to receive(:zip_directory).with(output_file_path, path)
252
+ expect(File).to receive(:new).with(output_file_path)
253
+ end
254
+
255
+ example do
256
+ provider.function_zip
257
+ end
258
+ end
259
+
260
+ context 'with an invalid zip option' do
261
+ path = '/some/file/path.zip'
262
+ output_file_path = '/some/path.zip'
263
+ error = 'Invalid zip option. If set, must be path to directory, js file, or a zip file.'
264
+
265
+ before do
266
+ expect(provider.options).to receive(:[]).with(:zip).and_return(path)
267
+ expect(provider).to receive(:output_file_path).and_return(output_file_path)
268
+ expect(File).to receive(:directory?).with(path).and_return(false)
269
+ expect(File).to receive(:file?).with(path).and_return(false)
270
+ end
271
+
272
+ example do
273
+ expect { provider.function_zip }.to raise_error(DPL::Error, error)
274
+ end
275
+ end
276
+ end
277
+
278
+ describe '#zip_file' do
279
+ dest = '/some/path/to/write.zip'
280
+
281
+ context 'when zip is a file path' do
282
+ dir = '/some/target'
283
+ target = File.join(dir, 'file.js')
284
+
285
+ before do
286
+ expect(File).to receive(:extname).with(target).and_return('.js')
287
+ expect(provider).to receive(:create_zip).with(dest, dir, [ target ])
288
+ end
289
+
290
+ example do
291
+ provider.zip_file(dest, target)
292
+ end
293
+ end
294
+
295
+ context 'when zip is an existing zip file' do
296
+ dir = '/some/target'
297
+ target = File.join(dir, 'file.js')
298
+
299
+ before do
300
+ expect(File).to receive(:extname).with(target).and_return('.zip')
301
+ expect(FileUtils).to receive(:cp).with(target, dest)
302
+ end
303
+
304
+ example do
305
+ provider.zip_file(dest, target)
306
+ end
307
+ end
308
+ end
309
+
310
+ describe '#zip_directory' do
311
+ dest = '/some/path/to/write.zip'
312
+ target = '/some/dir'
313
+ glob = File.join(target, '**', '**')
314
+ files = %w[ 'one' 'two' ]
315
+
316
+ before do
317
+ expect(Dir).to receive(:[]).with(glob).and_return(files)
318
+ expect(provider).to receive(:create_zip).with(dest, target, files)
319
+ end
320
+
321
+ example do
322
+ provider.zip_directory(dest, target)
323
+ end
324
+ end
325
+
326
+ describe '#create_zip' do
327
+ dest = '/some/dest.zip'
328
+ src = '/some/src/dir'
329
+ file_one = 'one.js'
330
+ file_two = 'two.js'
331
+ files = [
332
+ File.join(src, file_one),
333
+ File.join(src, file_two)
334
+ ]
335
+
336
+ before do
337
+ expect(provider).to receive(:create_zip).and_call_original
338
+ zip_file = double(Zip::File)
339
+ expect(Zip::File).to receive(:open).with(dest, Zip::File::CREATE).and_yield(zip_file)
340
+ expect(zip_file).to receive(:add).once.with(file_one, File.join(src, file_one))
341
+ expect(zip_file).to receive(:add).once.with(file_two, File.join(src, file_two))
342
+ end
343
+
344
+ example do
345
+ provider.create_zip(dest, src, files)
346
+ end
347
+ end
348
+
349
+ describe '#needs_key?' do
350
+ example do
351
+ expect(provider.needs_key?).to eq(false)
352
+ end
353
+ end
354
+
355
+ describe '#check_auth' do
356
+ example do
357
+ expect(provider).to receive(:log).with("Using Access Key: #{access_key_id[-4..-1].rjust(20, '*')}")
358
+ provider.check_auth
359
+ end
360
+ end
361
+
362
+ describe '#output_file_path' do
363
+ example do
364
+ expect(provider.output_file_path).to match(/tmp\/\w{8}\-lambda\.zip/)
365
+ end
366
+ end
367
+
368
+ describe '#default_runtime' do
369
+ example do
370
+ expect(provider.default_runtime).to eq('nodejs')
371
+ end
372
+ end
373
+
374
+ describe '#default_timeout' do
375
+ example do
376
+ expect(provider.default_timeout).to eq(3)
377
+ end
378
+ end
379
+
380
+ describe '#default_description' do
381
+ build_number = 2
382
+
383
+ before do
384
+ allow(provider.context.env).to receive(:[]).with('TRAVIS_BUILD_NUMBER').and_return(build_number)
385
+ end
386
+
387
+ let(:build_number) { provider.context.env['TRAVIS_BUILD_NUMBER'] }
388
+
389
+ example do
390
+ expect(provider.default_description).to eq(
391
+ "Deploy build #{build_number} to AWS Lambda via Travis CI"
392
+ )
393
+ end
394
+ end
395
+
396
+ describe '#default_memory_size' do
397
+ example do
398
+ expect(provider.default_memory_size).to eq(128)
399
+ end
400
+ end
401
+
402
+ describe '#publish' do
403
+ context 'is default turned off' do
404
+ example do
405
+ expect(provider.publish).to eq(false)
406
+ end
407
+ end
408
+ context 'can be turned on' do
409
+ before do
410
+ expect(provider.options).to receive(:[]).with(:publish).and_return(true)
411
+ end
412
+
413
+ example do
414
+ expect(provider.publish).to eq(true)
415
+ end
416
+ end
417
+ end
418
+
419
+ describe '#random_chars' do
420
+ context 'without specifying count' do
421
+ example do
422
+ expect(provider.random_chars.length).to eq(8)
423
+ end
424
+ end
425
+
426
+ context 'with specified count' do
427
+ count = 4
428
+ example do
429
+ expect(provider.random_chars(count).length).to eq(count)
430
+ end
431
+ end
432
+ end
433
+
434
+ end
metadata ADDED
@@ -0,0 +1,187 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dpl-lambda
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.9.0
5
+ platform: ruby
6
+ authors:
7
+ - Konstantin Haase
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-03-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dpl
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.9.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.9.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: aws-sdk
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubyzip
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-its
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: json_pure
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: tins
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: coveralls
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: highline
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ description: deploy tool abstraction for clients
154
+ email: konstantin.mailinglists@googlemail.com
155
+ executables: []
156
+ extensions: []
157
+ extra_rdoc_files: []
158
+ files:
159
+ - dpl-lambda.gemspec
160
+ - lib/dpl/provider/lambda.rb
161
+ - spec/provider/lambda_spec.rb
162
+ homepage: https://github.com/travis-ci/dpl
163
+ licenses:
164
+ - MIT
165
+ metadata: {}
166
+ post_install_message:
167
+ rdoc_options: []
168
+ require_paths:
169
+ - lib
170
+ required_ruby_version: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: '2.2'
175
+ required_rubygems_version: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ requirements: []
181
+ rubyforge_project:
182
+ rubygems_version: 2.6.13
183
+ signing_key:
184
+ specification_version: 4
185
+ summary: deploy tool
186
+ test_files:
187
+ - spec/provider/lambda_spec.rb