dpl-connect 1.8.43

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.
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