dpl-connect 1.8.43

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +8 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +36 -0
  6. data/Gemfile +100 -0
  7. data/LICENSE +22 -0
  8. data/README.md +934 -0
  9. data/Rakefile +1 -0
  10. data/TESTING.md +29 -0
  11. data/bin/dpl +5 -0
  12. data/dpl.gemspec +32 -0
  13. data/lib/dpl/cli.rb +66 -0
  14. data/lib/dpl/error.rb +3 -0
  15. data/lib/dpl/provider.rb +264 -0
  16. data/lib/dpl/provider/anynines.rb +13 -0
  17. data/lib/dpl/provider/appfog.rb +21 -0
  18. data/lib/dpl/provider/atlas.rb +108 -0
  19. data/lib/dpl/provider/azure_webapps.rb +48 -0
  20. data/lib/dpl/provider/bintray.rb +509 -0
  21. data/lib/dpl/provider/bitballoon.rb +22 -0
  22. data/lib/dpl/provider/bluemix_cloud_foundry.rb +23 -0
  23. data/lib/dpl/provider/boxfuse.rb +57 -0
  24. data/lib/dpl/provider/catalyze.rb +49 -0
  25. data/lib/dpl/provider/chef_supermarket.rb +85 -0
  26. data/lib/dpl/provider/cloud66.rb +38 -0
  27. data/lib/dpl/provider/cloud_files.rb +38 -0
  28. data/lib/dpl/provider/cloud_foundry.rb +43 -0
  29. data/lib/dpl/provider/code_deploy.rb +123 -0
  30. data/lib/dpl/provider/deis.rb +119 -0
  31. data/lib/dpl/provider/divshot.rb +23 -0
  32. data/lib/dpl/provider/elastic_beanstalk.rb +195 -0
  33. data/lib/dpl/provider/engine_yard.rb +90 -0
  34. data/lib/dpl/provider/firebase.rb +27 -0
  35. data/lib/dpl/provider/gae.rb +97 -0
  36. data/lib/dpl/provider/gcs.rb +59 -0
  37. data/lib/dpl/provider/hackage.rb +29 -0
  38. data/lib/dpl/provider/heroku.rb +18 -0
  39. data/lib/dpl/provider/heroku/api.rb +98 -0
  40. data/lib/dpl/provider/heroku/generic.rb +94 -0
  41. data/lib/dpl/provider/heroku/git.rb +28 -0
  42. data/lib/dpl/provider/lambda.rb +236 -0
  43. data/lib/dpl/provider/launchpad.rb +48 -0
  44. data/lib/dpl/provider/modulus.rb +23 -0
  45. data/lib/dpl/provider/npm.rb +64 -0
  46. data/lib/dpl/provider/openshift.rb +59 -0
  47. data/lib/dpl/provider/ops_works.rb +132 -0
  48. data/lib/dpl/provider/packagecloud.rb +144 -0
  49. data/lib/dpl/provider/pages.rb +79 -0
  50. data/lib/dpl/provider/puppet_forge.rb +43 -0
  51. data/lib/dpl/provider/pypi.rb +111 -0
  52. data/lib/dpl/provider/releases.rb +139 -0
  53. data/lib/dpl/provider/rubygems.rb +51 -0
  54. data/lib/dpl/provider/s3.rb +123 -0
  55. data/lib/dpl/provider/scalingo.rb +97 -0
  56. data/lib/dpl/provider/script.rb +29 -0
  57. data/lib/dpl/provider/surge.rb +33 -0
  58. data/lib/dpl/provider/testfairy.rb +190 -0
  59. data/lib/dpl/provider/transifex.rb +45 -0
  60. data/lib/dpl/version.rb +3 -0
  61. data/notes/engine_yard.md +1 -0
  62. data/notes/heroku.md +3 -0
  63. data/spec/cli_spec.rb +36 -0
  64. data/spec/provider/anynines_spec.rb +20 -0
  65. data/spec/provider/appfog_spec.rb +35 -0
  66. data/spec/provider/atlas_spec.rb +99 -0
  67. data/spec/provider/azure_webapps_spec.rb +95 -0
  68. data/spec/provider/bintray_spec.rb +259 -0
  69. data/spec/provider/bitballoon_spec.rb +32 -0
  70. data/spec/provider/bluemixcloudfoundry_spec.rb +23 -0
  71. data/spec/provider/boxfuse_spec.rb +16 -0
  72. data/spec/provider/catalyze_spec.rb +39 -0
  73. data/spec/provider/chef_supermarket_spec.rb +51 -0
  74. data/spec/provider/cloud66_spec.rb +44 -0
  75. data/spec/provider/cloud_files_spec.rb +88 -0
  76. data/spec/provider/cloudfoundry_spec.rb +71 -0
  77. data/spec/provider/code_deploy_spec.rb +360 -0
  78. data/spec/provider/deis_spec.rb +116 -0
  79. data/spec/provider/divshot_spec.rb +28 -0
  80. data/spec/provider/elastic_beanstalk_spec.rb +209 -0
  81. data/spec/provider/firebase_spec.rb +40 -0
  82. data/spec/provider/gae_spec.rb +26 -0
  83. data/spec/provider/gcs_spec.rb +115 -0
  84. data/spec/provider/hackage_spec.rb +47 -0
  85. data/spec/provider/heroku_spec.rb +357 -0
  86. data/spec/provider/lambda_spec.rb +432 -0
  87. data/spec/provider/launchpad_spec.rb +33 -0
  88. data/spec/provider/modulus_spec.rb +29 -0
  89. data/spec/provider/npm_spec.rb +95 -0
  90. data/spec/provider/openshift_spec.rb +91 -0
  91. data/spec/provider/ops_works_spec.rb +127 -0
  92. data/spec/provider/packagecloud_spec.rb +56 -0
  93. data/spec/provider/puppet_forge_spec.rb +60 -0
  94. data/spec/provider/pypi_spec.rb +103 -0
  95. data/spec/provider/releases_spec.rb +303 -0
  96. data/spec/provider/rubygems_spec.rb +106 -0
  97. data/spec/provider/s3_spec.rb +174 -0
  98. data/spec/provider/scalingo_spec.rb +64 -0
  99. data/spec/provider/script_spec.rb +26 -0
  100. data/spec/provider/surge_spec.rb +15 -0
  101. data/spec/provider/testfairy_spec.rb +86 -0
  102. data/spec/provider/transifex_spec.rb +110 -0
  103. data/spec/provider_spec.rb +210 -0
  104. data/spec/spec_helper.rb +20 -0
  105. metadata +279 -0
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+ require 'dpl/provider/hackage'
3
+
4
+ describe DPL::Provider::Hackage do
5
+ subject :provider do
6
+ described_class.new(DummyContext.new, :username => 'FooUser', :password => 'bar')
7
+ end
8
+
9
+ describe "#check_auth" do
10
+ it 'should require username' do
11
+ provider.options.update(:username => nil)
12
+ expect {
13
+ provider.check_auth
14
+ }.to raise_error(DPL::Error)
15
+ end
16
+
17
+ it 'should require password' do
18
+ provider.options.update(:password => nil)
19
+ expect {
20
+ provider.check_auth
21
+ }.to raise_error(DPL::Error)
22
+ end
23
+ end
24
+
25
+ describe "#check_app" do
26
+ it 'calls cabal' do
27
+ expect(provider.context).to receive(:shell).with("cabal check").and_return(true)
28
+ provider.check_app
29
+ end
30
+
31
+ it 'fails when cabal complains' do
32
+ expect(provider.context).to receive(:shell).with("cabal check").and_return(false)
33
+ expect {
34
+ provider.check_app
35
+ }.to raise_error(DPL::Error)
36
+ end
37
+ end
38
+
39
+ describe "#push_app" do
40
+ example do
41
+ expect(provider.context).to receive(:shell).with("cabal sdist").and_return(true)
42
+ expect(Dir).to receive(:glob).and_yield('dist/package-0.1.2.3.tar.gz')
43
+ expect(provider.context).to receive(:shell).with("cabal upload --username=FooUser --password=bar dist/package-0.1.2.3.tar.gz")
44
+ provider.push_app
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,357 @@
1
+ require 'spec_helper'
2
+ require 'dpl/provider/heroku'
3
+ require 'faraday'
4
+
5
+ RSpec.shared_context 'with faraday' do
6
+ let(:api_key) { 'foo' }
7
+ let(:stubs) { Faraday::Adapter::Test::Stubs.new }
8
+ let(:faraday) {
9
+ Faraday.new do |builder|
10
+ builder.adapter :test, stubs do |stub|
11
+ stub.get("/account") {|env| [200, response_headers, account_response_body]}
12
+ stub.get("/apps/example") {|env| [200, response_headers, app_response_body]}
13
+ stub.post("/apps/example/builds") {|env| [201, response_headers, builds_response_body]}
14
+ stub.get("/apps/example/builds/01234567-89ab-cdef-0123-456789abcdef/result") {|env| [200, response_headers, build_result_response_body]}
15
+ stub.post("/sources") {|env| [201, response_headers, source_response_body] }
16
+ stub.post("/apps/example/dynos") {|env| [201, response_headers, dynos_create_response_body]}
17
+ stub.delete("/apps/example/dynos") {|env| [202, response_headers, '{}'] }
18
+ end
19
+ end
20
+ }
21
+
22
+ let(:response_headers) {
23
+ {'Content-Type' => 'application/json'}
24
+ }
25
+
26
+ let(:app_response_body) {
27
+ '{
28
+ "acm": false,
29
+ "archived_at": "2012-01-01T12:00:00Z",
30
+ "buildpack_provided_description": "Ruby/Rack",
31
+ "build_stack": {
32
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
33
+ "name": "cedar-14"
34
+ },
35
+ "created_at": "2012-01-01T12:00:00Z",
36
+ "git_url": "https://git.heroku.com/example.git",
37
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
38
+ "maintenance": false,
39
+ "name": "example",
40
+ "owner": {
41
+ "email": "username@example.com",
42
+ "id": "01234567-89ab-cdef-0123-456789abcdef"
43
+ },
44
+ "organization": {
45
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
46
+ "name": "example"
47
+ },
48
+ "team": {
49
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
50
+ "name": "example"
51
+ },
52
+ "region": {
53
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
54
+ "name": "us"
55
+ },
56
+ "released_at": "2012-01-01T12:00:00Z",
57
+ "repo_size": 0,
58
+ "slug_size": 0,
59
+ "space": {
60
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
61
+ "name": "nasa",
62
+ "shield": true
63
+ },
64
+ "stack": {
65
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
66
+ "name": "cedar-14"
67
+ },
68
+ "updated_at": "2012-01-01T12:00:00Z",
69
+ "web_url": "https://example.herokuapp.com/"
70
+ }'
71
+ }
72
+
73
+ let(:account_response_body) {
74
+ '{
75
+ "allow_tracking": true,
76
+ "beta": false,
77
+ "created_at": "2012-01-01T12:00:00Z",
78
+ "email": "username@example.com",
79
+ "federated": false,
80
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
81
+ "identity_provider": {
82
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
83
+ "organization": {
84
+ "name": "example"
85
+ }
86
+ },
87
+ "last_login": "2012-01-01T12:00:00Z",
88
+ "name": "Tina Edmonds",
89
+ "sms_number": "+1 ***-***-1234",
90
+ "suspended_at": "2012-01-01T12:00:00Z",
91
+ "delinquent_at": "2012-01-01T12:00:00Z",
92
+ "two_factor_authentication": false,
93
+ "updated_at": "2012-01-01T12:00:00Z",
94
+ "verified": false,
95
+ "default_organization": {
96
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
97
+ "name": "example"
98
+ }
99
+ }'
100
+ }
101
+
102
+ let(:builds_response_body) {
103
+ '{
104
+ "app": {
105
+ "id": "01234567-89ab-cdef-0123-456789abcdef"
106
+ },
107
+ "buildpacks": [
108
+ {
109
+ "url": "https://github.com/heroku/heroku-buildpack-ruby"
110
+ }
111
+ ],
112
+ "created_at": "2012-01-01T12:00:00Z",
113
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
114
+ "output_stream_url": "https://build-output.heroku.com/streams/01234567-89ab-cdef-0123-456789abcdef",
115
+ "source_blob": {
116
+ "checksum": "SHA256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
117
+ "url": "https://example.com/source.tgz?token=xyz",
118
+ "version": "v1.3.0"
119
+ },
120
+ "release": {
121
+ "id": "01234567-89ab-cdef-0123-456789abcdef"
122
+ },
123
+ "slug": {
124
+ "id": "01234567-89ab-cdef-0123-456789abcdef"
125
+ },
126
+ "status": "succeeded",
127
+ "updated_at": "2012-01-01T12:00:00Z",
128
+ "user": {
129
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
130
+ "email": "username@example.com"
131
+ }
132
+ }'
133
+ }
134
+
135
+ let(:source_response_body) {
136
+ '{
137
+ "source_blob": {
138
+ "get_url": "https://api.heroku.com/sources/1234.tgz",
139
+ "put_url": "https://api.heroku.com/sources/1234.tgz"
140
+ }
141
+ }'
142
+ }
143
+
144
+ let(:dynos_create_response_body) {
145
+ '{
146
+ "attach_url": "rendezvous://rendezvous.runtime.heroku.com:5000/rendezvous",
147
+ "command": "bash",
148
+ "created_at": "2012-01-01T12:00:00Z",
149
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
150
+ "name": "run.1",
151
+ "release": {
152
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
153
+ "version": 11
154
+ },
155
+ "app": {
156
+ "name": "example",
157
+ "id": "01234567-89ab-cdef-0123-456789abcdef"
158
+ },
159
+ "size": "standard-1X",
160
+ "state": "up",
161
+ "type": "run",
162
+ "updated_at": "2012-01-01T12:00:00Z"
163
+ }'
164
+ }
165
+
166
+ let(:build_result_response_body) {
167
+ '{
168
+ "build": {
169
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
170
+ "status": "succeeded",
171
+ "output_stream_url": "https://build-output.heroku.com/streams/01234567-89ab-cdef-0123-456789abcdef"
172
+ },
173
+ "exit_code": 0,
174
+ "lines": [
175
+ {
176
+ "line": "-----> Ruby app detected\n",
177
+ "stream": "STDOUT"
178
+ }
179
+ ]
180
+ }'
181
+ }
182
+
183
+ let(:build_result_response_body_failure) {
184
+ '{
185
+ "build": {
186
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
187
+ "status": "failed",
188
+ "output_stream_url": "https://build-output.heroku.com/streams/01234567-89ab-cdef-0123-456789abcdef"
189
+ },
190
+ "exit_code": 1,
191
+ "lines": [
192
+ {
193
+ "line": "-----> Ruby app detected\n",
194
+ "stream": "STDOUT"
195
+ }
196
+ ]
197
+ }'
198
+ }
199
+
200
+ let(:build_result_response_body_in_progress) {
201
+ '{
202
+ "build": {
203
+ "id": "01234567-89ab-cdef-0123-456789abcdef",
204
+ "status": "failed",
205
+ "output_stream_url": "https://build-output.heroku.com/streams/01234567-89ab-cdef-0123-456789abcdef"
206
+ },
207
+ "lines": [
208
+ {
209
+ "line": "-----> Ruby app detected\n",
210
+ "stream": "STDOUT"
211
+ }
212
+ ]
213
+ }'
214
+ }
215
+ end
216
+
217
+ describe DPL::Provider::Heroku, :api do
218
+ include_context 'with faraday'
219
+
220
+ subject(:provider) do
221
+ described_class.new(DummyContext.new, provider_options.merge({ :api_key => api_key}))
222
+ end
223
+
224
+ let(:provider_options) {
225
+ {:app => 'example', :key_name => 'key', :strategy => "api"}
226
+ }
227
+
228
+ describe "#ssh" do
229
+ it "doesn't require an ssh key" do
230
+ expect(provider.needs_key?).to eq(false)
231
+ end
232
+ end
233
+
234
+ describe "#api" do
235
+ it 'accepts an api key' do
236
+ expect(provider).to receive(:faraday).at_least(:once).and_return(faraday)
237
+ provider.check_auth
238
+ end
239
+
240
+ context "when api_key is not given" do
241
+ let(:provider) { described_class.new(DummyContext.new, provider_options) }
242
+ it 'raises DPL::Error' do
243
+ provider.options.update(:user => "foo", :password => "bar")
244
+ expect { provider.check_auth }.to raise_error(DPL::Error)
245
+ end
246
+ end
247
+ end
248
+
249
+ describe "#trigger_build" do
250
+ it "does not initiate legacy API object" do
251
+ expect(provider).to receive(:faraday).at_least(:once).and_return(faraday)
252
+ provider.trigger_build
253
+ end
254
+
255
+ example do
256
+ expect(provider).to receive(:log).with('triggering new deployment')
257
+ expect(provider).to receive(:faraday).at_least(:once).and_return(faraday)
258
+ expect(provider).to receive(:get_url).and_return 'http://example.com/source.tgz'
259
+ expect(provider).to receive(:version).and_return 'v1.3.0'
260
+ expect(provider.context).to receive(:shell).with("curl https://build-output.heroku.com/streams/01234567-89ab-cdef-0123-456789abcdef -H 'Accept: application/vnd.heroku+json; version=3'")
261
+ provider.trigger_build
262
+ expect(provider.build_id).to eq('01234567-89ab-cdef-0123-456789abcdef')
263
+ end
264
+ end
265
+
266
+ describe "#verify_build" do
267
+ context 'when build succeeds' do
268
+ example do
269
+ expect(provider).to receive(:faraday).at_least(:once).and_return(faraday)
270
+ expect(provider).to receive(:build_id).at_least(:once).and_return('01234567-89ab-cdef-0123-456789abcdef')
271
+ expect{ provider.verify_build }.not_to raise_error
272
+ end
273
+ end
274
+
275
+ context 'when build fails' do
276
+ example do
277
+ expect(provider).to receive(:faraday).at_least(:once).and_return(faraday)
278
+ expect(provider).to receive(:build_id).at_least(:once).and_return('01234567-89ab-cdef-0123-456789abcdef')
279
+ stubs.get("/apps/example/builds/01234567-89ab-cdef-0123-456789abcdef/result") {|env| [200, response_headers, build_result_response_body_failure]}
280
+ expect{ provider.verify_build }.to raise_error("deploy failed, build exited with code 1")
281
+ end
282
+ end
283
+
284
+ context 'when build is pending, then succeeds' do
285
+ example do
286
+ expect(provider).to receive(:faraday).at_least(:once).and_return(faraday)
287
+ expect(provider).to receive(:build_id).at_least(:once).and_return('01234567-89ab-cdef-0123-456789abcdef')
288
+ stubs.get("/apps/example/builds/01234567-89ab-cdef-0123-456789abcdef/result") {|env| [200, response_headers, build_result_response_body_in_progress]}
289
+ expect(provider).to receive(:sleep).with(5).and_return(true)
290
+ expect{ provider.verify_build }.not_to raise_error
291
+ end
292
+ end
293
+
294
+ end
295
+
296
+ end
297
+
298
+
299
+ describe DPL::Provider::Heroku, :git do
300
+ include_context "with faraday"
301
+
302
+ subject :provider do
303
+ described_class.new(DummyContext.new, :app => 'example', :key_name => 'key', :api_key => api_key, :strategy => "git")
304
+ end
305
+
306
+ describe "#api" do
307
+ it 'accepts an api key' do
308
+ expect(provider).to receive(:faraday).at_least(:once).and_return(faraday)
309
+ provider.check_auth
310
+ end
311
+ end
312
+
313
+ context "with faraday" do
314
+ before :each do
315
+ expect(provider).to receive(:faraday).at_least(:once).and_return(faraday)
316
+ end
317
+
318
+ describe "#check_auth" do
319
+ example do
320
+ expect(provider).to receive(:log).with("authentication succeeded")
321
+ provider.check_auth
322
+ end
323
+ end
324
+
325
+ describe "#check_app" do
326
+ example do
327
+ expect(provider).to receive(:log).at_least(1).times.with(/example/)
328
+ provider.check_app
329
+ end
330
+ end
331
+
332
+ describe "#run" do
333
+ example do
334
+ expect(Rendezvous).to receive(:start).with(:url => "rendezvous://rendezvous.runtime.heroku.com:5000/rendezvous")
335
+ provider.run("that command")
336
+ end
337
+ end
338
+
339
+ describe "#restart" do
340
+ example do
341
+ provider.restart
342
+ end
343
+ end
344
+ end
345
+
346
+ context "without faraday" do
347
+ describe "#push_app" do
348
+ example do
349
+ provider.options[:git] = "git://something"
350
+ expect(provider.context).to receive(:shell).with("git fetch origin $TRAVIS_BRANCH --unshallow")
351
+ expect(provider.context).to receive(:shell).with("git push git://something HEAD:refs/heads/master -f")
352
+ provider.push_app
353
+ expect(provider.context.env['GIT_HTTP_USER_AGENT']).to include("dpl/#{DPL::VERSION}")
354
+ end
355
+ end
356
+ end
357
+ end
@@ -0,0 +1,432 @@
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
+ provider.stub(:lambda_options).and_return(client_options)
52
+ end
53
+
54
+ describe '#lambda' do
55
+ example do
56
+ expect(Aws::Lambda::Client).to receive(:new).with(client_options).once
57
+ provider.lambda
58
+ end
59
+ end
60
+
61
+ describe '#push_app' do
62
+ lambda_options = {
63
+ function_name: 'test-function',
64
+ role: 'some-role',
65
+ module_name: 'index',
66
+ handler_name: 'handler'
67
+ }
68
+
69
+ example_get_function_response = {
70
+ code: {
71
+ location: 'location',
72
+ repository_type: 's3',
73
+ },
74
+ configuration: {
75
+ function_name: 'test-function'
76
+ }
77
+ }
78
+
79
+ example_response = {
80
+ function_name: 'test-function',
81
+ function_arn: 'arn:lambda:region:account-id:function:test-function',
82
+ role: 'some-role',
83
+ handler: 'index.handler'
84
+ }
85
+
86
+ before(:each) do
87
+ old_options = provider.options
88
+ provider.stub(:options) { old_options.merge(lambda_options) }
89
+ end
90
+
91
+ context 'by creating a new function' do
92
+ before do
93
+ provider.lambda.stub_responses(:get_function, 'ResourceNotFoundException')
94
+ provider.lambda.stub_responses(:create_function, example_response)
95
+ end
96
+
97
+ example do
98
+
99
+ expect(provider).to receive(:log).with(/Function #{lambda_options[:function_name]} does not exist, creating\./)
100
+ expect(provider).to receive(:log).with(/Created lambda: #{lambda_options[:function_name]}\./)
101
+ provider.push_app
102
+ end
103
+ end
104
+
105
+ context 'by updating an existing function' do
106
+ before do
107
+ provider.lambda.stub_responses(:get_function, example_get_function_response)
108
+ provider.lambda.stub_responses(:update_function_configuration, example_response)
109
+ provider.lambda.stub_responses(:update_function_code, example_response)
110
+ end
111
+
112
+ example do
113
+ expect(provider).to receive(:log).with(/Function #{lambda_options[:function_name]} already exists, updating\./)
114
+ expect(provider).to receive(:log).with(/Updated configuration of function: #{lambda_options[:function_name]}\./)
115
+ expect(provider).to receive(:log).with(/Updated code of function: #{lambda_options[:function_name]}\./)
116
+ provider.push_app
117
+ end
118
+ end
119
+
120
+ context 'by updating an existing function with new tags' do
121
+ before do
122
+ lambda_options[:function_tags] = [ 'TAG_KEY=some-value' ]
123
+ provider.lambda.stub_responses(:get_function, example_get_function_response)
124
+ provider.lambda.stub_responses(:update_function_configuration, example_response)
125
+ provider.lambda.stub_responses(:tag_resource)
126
+ provider.lambda.stub_responses(:update_function_code, example_response)
127
+ end
128
+
129
+ example do
130
+ expect(provider).to receive(:log).with(/Function #{lambda_options[:function_name]} already exists, updating\./)
131
+ expect(provider).to receive(:log).with(/Updated configuration of function: #{lambda_options[:function_name]}\./)
132
+ expect(provider).to receive(:log).with(/Add tags to function #{lambda_options[:function_name]}\./)
133
+ expect(provider).to receive(:log).with(/Updated code of function: #{lambda_options[:function_name]}\./)
134
+ provider.push_app
135
+ end
136
+ end
137
+
138
+ context 'with a ServiceException response' do
139
+ before do
140
+ provider.lambda.stub_responses(:get_function, 'ResourceNotFoundException')
141
+ provider.lambda.stub_responses(:create_function, 'ServiceException')
142
+ end
143
+
144
+ example do
145
+ expect(provider).to receive(:error).once
146
+ provider.push_app
147
+ end
148
+ end
149
+
150
+ context 'with a InvalidParameterValueException response' do
151
+ before do
152
+ provider.lambda.stub_responses(:get_function, 'InvalidParameterValueException')
153
+ end
154
+
155
+ example do
156
+ expect(provider).to receive(:error).once
157
+ provider.push_app
158
+ end
159
+ end
160
+
161
+ context 'with a ResourceNotFoundException response' do
162
+ before do
163
+ provider.lambda.stub_responses(:get_function, 'ResourceNotFoundException')
164
+ provider.lambda.stub_responses(:create_function, 'ResourceNotFoundException')
165
+ end
166
+
167
+ example do
168
+ expect(provider).to receive(:error).once
169
+ provider.push_app
170
+ end
171
+ end
172
+ end
173
+
174
+ describe "#handler" do
175
+ context "without a module name" do
176
+ module_name = 'index'
177
+ handler_name = 'HandlerName'
178
+ expected_handler = "#{module_name}.#{handler_name}"
179
+
180
+ before do
181
+ expect(provider.options).to receive(:[]).with(:module_name).and_return(nil)
182
+ expect(provider.options).to receive(:fetch).with(:handler_name).and_return(handler_name)
183
+ end
184
+
185
+ example do
186
+ expect(provider.handler).to eq(expected_handler)
187
+ end
188
+ end
189
+
190
+ context "with a module name" do
191
+ module_name = 'ModuleName'
192
+ handler_name = 'HandlerName'
193
+ expected_handler = "#{module_name}.#{handler_name}"
194
+
195
+ before do
196
+ expect(provider.options).to receive(:[]).with(:module_name).and_return(module_name)
197
+ expect(provider.options).to receive(:fetch).with(:handler_name).and_return(handler_name)
198
+ end
199
+
200
+ example do
201
+ expect(provider.handler).to eq(expected_handler)
202
+ end
203
+ end
204
+ end
205
+
206
+ describe '#function_zip' do
207
+ context 'when zip is not specified' do
208
+ path = Dir.pwd
209
+ output_file_path = '/some/path.zip'
210
+
211
+ before do
212
+ expect(provider.options).to receive(:[]).with(:zip).and_return(nil)
213
+ expect(provider).to receive(:output_file_path).and_return(output_file_path)
214
+ expect(File).to receive(:directory?).with(path).and_return(true)
215
+ expect(provider).to receive(:zip_directory).with(output_file_path, path)
216
+ expect(File).to receive(:new).with(output_file_path)
217
+ end
218
+
219
+ example do
220
+ provider.function_zip
221
+ end
222
+ end
223
+
224
+ context 'when zip is a file path' do
225
+ path = '/some/file/path.zip'
226
+ output_file_path = '/some/path.zip'
227
+
228
+ before do
229
+ expect(provider.options).to receive(:[]).with(:zip).and_return(path)
230
+ expect(provider).to receive(:output_file_path).and_return(output_file_path)
231
+ expect(File).to receive(:directory?).with(path).and_return(false)
232
+ expect(File).to receive(:file?).with(path).and_return(true)
233
+ expect(provider).to receive(:zip_file).with(output_file_path, path)
234
+ expect(File).to receive(:new).with(output_file_path)
235
+ end
236
+
237
+ example do
238
+ provider.function_zip
239
+ end
240
+ end
241
+
242
+ context 'when zip is a directory' do
243
+ path = '/some/dir/path'
244
+ output_file_path = '/some/path.zip'
245
+
246
+ before do
247
+ expect(provider.options).to receive(:[]).with(:zip).and_return(path)
248
+ expect(provider).to receive(:output_file_path).and_return(output_file_path)
249
+ expect(File).to receive(:directory?).with(path).and_return(true)
250
+ expect(provider).to receive(:zip_directory).with(output_file_path, path)
251
+ expect(File).to receive(:new).with(output_file_path)
252
+ end
253
+
254
+ example do
255
+ provider.function_zip
256
+ end
257
+ end
258
+
259
+ context 'with an invalid zip option' do
260
+ path = '/some/file/path.zip'
261
+ output_file_path = '/some/path.zip'
262
+ error = 'Invalid zip option. If set, must be path to directory, js file, or a zip file.'
263
+
264
+ before do
265
+ expect(provider.options).to receive(:[]).with(:zip).and_return(path)
266
+ expect(provider).to receive(:output_file_path).and_return(output_file_path)
267
+ expect(File).to receive(:directory?).with(path).and_return(false)
268
+ expect(File).to receive(:file?).with(path).and_return(false)
269
+ end
270
+
271
+ example do
272
+ expect { provider.function_zip }.to raise_error(DPL::Error, error)
273
+ end
274
+ end
275
+ end
276
+
277
+ describe '#zip_file' do
278
+ dest = '/some/path/to/write.zip'
279
+
280
+ context 'when zip is a file path' do
281
+ dir = '/some/target'
282
+ target = File.join(dir, 'file.js')
283
+
284
+ before do
285
+ expect(File).to receive(:extname).with(target).and_return('.js')
286
+ expect(provider).to receive(:create_zip).with(dest, dir, [ target ])
287
+ end
288
+
289
+ example do
290
+ provider.zip_file(dest, target)
291
+ end
292
+ end
293
+
294
+ context 'when zip is an existing zip file' do
295
+ dir = '/some/target'
296
+ target = File.join(dir, 'file.js')
297
+
298
+ before do
299
+ expect(File).to receive(:extname).with(target).and_return('.zip')
300
+ expect(FileUtils).to receive(:cp).with(target, dest)
301
+ end
302
+
303
+ example do
304
+ provider.zip_file(dest, target)
305
+ end
306
+ end
307
+ end
308
+
309
+ describe '#zip_directory' do
310
+ dest = '/some/path/to/write.zip'
311
+ target = '/some/dir'
312
+ glob = File.join(target, '**', '**')
313
+ files = %w[ 'one' 'two' ]
314
+
315
+ before do
316
+ expect(Dir).to receive(:[]).with(glob).and_return(files)
317
+ expect(provider).to receive(:create_zip).with(dest, target, files)
318
+ end
319
+
320
+ example do
321
+ provider.zip_directory(dest, target)
322
+ end
323
+ end
324
+
325
+ describe '#create_zip' do
326
+ dest = '/some/dest.zip'
327
+ src = '/some/src/dir'
328
+ file_one = 'one.js'
329
+ file_two = 'two.js'
330
+ files = [
331
+ File.join(src, file_one),
332
+ File.join(src, file_two)
333
+ ]
334
+
335
+ before do
336
+ zip_file = double(Zip::File)
337
+ expect(Zip::File).to receive(:open).with(dest, Zip::File::CREATE).and_yield(zip_file)
338
+ expect(zip_file).to receive(:add).once.with(file_one, File.join(src, file_one))
339
+ expect(zip_file).to receive(:add).once.with(file_two, File.join(src, file_two))
340
+ end
341
+
342
+ example do
343
+ provider.create_zip(dest, src, files)
344
+ end
345
+ end
346
+
347
+ describe '#needs_key?' do
348
+ example do
349
+ expect(provider.needs_key?).to eq(false)
350
+ end
351
+ end
352
+
353
+ describe '#check_auth' do
354
+ example do
355
+ expect(provider).to receive(:log).with("Using Access Key: #{access_key_id[-4..-1].rjust(20, '*')}")
356
+ provider.check_auth
357
+ end
358
+ end
359
+
360
+ describe '#output_file_path' do
361
+ example do
362
+ expect(provider.output_file_path).to match(/tmp\/\w{8}\-lambda\.zip/)
363
+ end
364
+ end
365
+
366
+ describe '#default_runtime' do
367
+ example do
368
+ expect(provider.default_runtime).to eq('nodejs')
369
+ end
370
+ end
371
+
372
+ describe '#default_timeout' do
373
+ example do
374
+ expect(provider.default_timeout).to eq(3)
375
+ end
376
+ end
377
+
378
+ describe '#default_description' do
379
+ build_number = 2
380
+
381
+ before do
382
+ provider.context.env.stub(:[]).with('TRAVIS_BUILD_NUMBER').and_return(build_number)
383
+ end
384
+
385
+ let(:build_number) { provider.context.env['TRAVIS_BUILD_NUMBER'] }
386
+
387
+ example do
388
+ expect(provider.default_description).to eq(
389
+ "Deploy build #{build_number} to AWS Lambda via Travis CI"
390
+ )
391
+ end
392
+ end
393
+
394
+ describe '#default_memory_size' do
395
+ example do
396
+ expect(provider.default_memory_size).to eq(128)
397
+ end
398
+ end
399
+
400
+ describe '#publish' do
401
+ context 'is default turned off' do
402
+ example do
403
+ expect(provider.publish).to eq(false)
404
+ end
405
+ end
406
+ context 'can be turned on' do
407
+ before do
408
+ expect(provider.options).to receive(:[]).with(:publish).and_return(true)
409
+ end
410
+
411
+ example do
412
+ expect(provider.publish).to eq(true)
413
+ end
414
+ end
415
+ end
416
+
417
+ describe '#random_chars' do
418
+ context 'without specifying count' do
419
+ example do
420
+ expect(provider.random_chars.length).to eq(8)
421
+ end
422
+ end
423
+
424
+ context 'with specified count' do
425
+ count = 4
426
+ example do
427
+ expect(provider.random_chars(count).length).to eq(count)
428
+ end
429
+ end
430
+ end
431
+
432
+ end