dpl-lambda 1.9.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 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