dpl 1.8.37.travis.2118.5 → 1.8.37.travis.2137.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e70689f1c5f495770fa775f5e1a181727124da1d
4
- data.tar.gz: 8a2f7c9b872867fe8d276ac920a9bd72b20b8044
3
+ metadata.gz: bcd6ea4fb05d81e5fab3dcce86798099d57c1b8d
4
+ data.tar.gz: 41ed97cf489fd15bf0265677054f4abad4e4bf0d
5
5
  SHA512:
6
- metadata.gz: 30c8e4017a804f1f9d2a1c57a30fd254437140fc52cb77e659525cedbc66773398592b8f4080124d3bd607dcfb9bbb3b9a404277633195f11634790b600d7ca8
7
- data.tar.gz: 455bcd5016831bd76487ee13d0ae0de0c9b930efee7c82add44b80e4cad6f58a19509543efdb2cd6844362e07aa52c296f1a0a72756474b8ae9c7592fd9e50b0
6
+ metadata.gz: 69235b6920209a34bd4d908cfdf14f34b0be63f6f134607ddafcbf7a55fd0980a6cc7873df67c9353fe1afb68b72bf0961a4e88ce2d57b89e2860eee716bc4a7
7
+ data.tar.gz: 9afb31a2f32c25f22ad1b6d54c8171081e67190f35b5f0895f69862cde9d8a18a939f93bf595305dec0b914902ebf554f6e9a6916da1453e9627005f16f0fde2
@@ -1,7 +1,6 @@
1
1
  module DPL
2
2
  class Provider
3
3
  module Heroku
4
- autoload :Anvil, 'dpl/provider/heroku/anvil'
5
4
  autoload :API, 'dpl/provider/heroku/api'
6
5
  autoload :Generic, 'dpl/provider/heroku/generic'
7
6
  autoload :Git, 'dpl/provider/heroku/git'
@@ -10,59 +10,6 @@ module DPL
10
10
  requires 'faraday'
11
11
  requires 'rendezvous'
12
12
 
13
- def check_auth
14
- response = faraday.get('/account')
15
-
16
- if response.success?
17
- email = JSON.parse(response.body)["email"]
18
- log "authenticated as #{email}"
19
- else
20
- handle_error_response(response)
21
- end
22
- end
23
-
24
- def faraday
25
- return @conn if @conn
26
- headers = { "Accept" => "application/vnd.heroku+json; version=3" }
27
-
28
- if options[:user] and options[:password]
29
- # no-op
30
- else
31
- headers.merge!({ "Authorization" => "Bearer #{option(:api_key)}" })
32
- end
33
-
34
- @conn = Faraday.new( url: 'https://api.heroku.com', headers: headers ) do |faraday|
35
- if options[:user] and options[:password]
36
- faraday.basic_auth(options[:user], options[:password])
37
- end
38
- if log_level = options[:log_level]
39
- logger = Logger.new($stderr)
40
- logger.level = Logger.const_get(log_level.upcase)
41
-
42
- faraday.response :logger, logger do | logger |
43
- logger.filter(/(.*Authorization: ).*/,'\1[REDACTED]')
44
- end
45
- end
46
- faraday.adapter Faraday.default_adapter
47
- end
48
- end
49
-
50
- def check_app
51
- log "checking for app #{option(:app)}"
52
- response = faraday.get("/apps/#{option(:app)}")
53
- if response.success?
54
- name = JSON.parse(response.body)["name"]
55
- log "found app #{name}"
56
- else
57
- handle_error_response(response)
58
- end
59
- end
60
-
61
- def handle_error_response(response)
62
- error_response = JSON.parse(response.body)
63
- error "API request failed.\nMessage: #{error_response["message"]}\nReference: #{error_response["url"]}"
64
- end
65
-
66
13
  def push_app
67
14
  pack_archive
68
15
  upload_archive
@@ -145,27 +92,6 @@ module DPL
145
92
  @version ||= options[:version] || context.env['TRAVIS_COMMIT'] || `git rev-parse HEAD`.strip
146
93
  end
147
94
 
148
- def restart
149
- response = faraday.delete "/apps/#{option(:app)}/dynos" do |req|
150
- req.headers['Content-Type'] = 'application/json'
151
- end
152
- unless response.success?
153
- handle_error_response(response)
154
- end
155
- end
156
-
157
- def run(command)
158
- response = faraday.post "/apps/#{option(:app)}/dynos" do |req|
159
- req.headers['Content-Type'] = 'application/json'
160
- req.body = {"command" => command, "attach" => true}.to_json
161
- end
162
- if response.success?
163
- rendezvous_url = JSON.parse(response.body)["attach_url"]
164
- Rendezvous.start(url: rendezvous_url)
165
- else
166
- handle_error_response(response)
167
- end
168
- end
169
95
  end
170
96
  end
171
97
  end
@@ -1,64 +1,92 @@
1
+ require 'json'
2
+
1
3
  module DPL
2
4
  class Provider
3
5
  module Heroku
4
6
  class Generic < Provider
5
- requires 'heroku-api'
6
7
  requires 'rendezvous'
8
+ requires 'faraday'
9
+
10
+ attr_reader :app, :user
7
11
 
8
12
  def needs_key?
9
13
  false
10
14
  end
11
15
 
12
- def api
13
- @api ||= ::Heroku::API.new(api_options)
14
- end
16
+ def faraday
17
+ return @conn if @conn
18
+ headers = { "Accept" => "application/vnd.heroku+json; version=3" }
15
19
 
16
- def api_options
17
- api_options = { headers: { 'User-Agent' => user_agent(::Heroku::API::HEADERS.fetch('User-Agent')) } }
18
20
  if options[:user] and options[:password]
19
- api_options[:user] = options[:user]
20
- api_options[:password] = options[:password]
21
+ # no-op
21
22
  else
22
- api_options[:api_key] = option(:api_key)
23
+ headers.merge!({ "Authorization" => "Bearer #{option(:api_key)}" })
23
24
  end
24
- api_options
25
- end
26
25
 
27
- def user
28
- @user ||= api.get_user.body["email"]
26
+ @conn = Faraday.new( url: 'https://api.heroku.com', headers: headers ) do |faraday|
27
+ if options[:user] and options[:password]
28
+ faraday.basic_auth(options[:user], options[:password])
29
+ end
30
+ if log_level = options[:log_level]
31
+ logger = Logger.new($stderr)
32
+ logger.level = Logger.const_get(log_level.upcase)
33
+
34
+ faraday.response :logger, logger do | logger |
35
+ logger.filter(/(.*Authorization: ).*/,'\1[REDACTED]')
36
+ end
37
+ end
38
+ faraday.adapter Faraday.default_adapter
39
+ end
29
40
  end
30
41
 
31
42
  def check_auth
32
- log "authenticated as %s" % user
33
- end
43
+ response = faraday.get('/account')
34
44
 
35
- def info
36
- @info ||= api.get_app(option(:app)).body
45
+ if response.success?
46
+ email = JSON.parse(response.body)["email"]
47
+ @user = email
48
+ log "authenticated as #{email}"
49
+ else
50
+ handle_error_response(response)
51
+ end
37
52
  end
38
53
 
39
- def check_app
40
- log "checking for app '#{option(:app)}'"
41
- log "found app '#{info['name']}'"
42
- rescue ::Heroku::API::Errors::Forbidden => error
43
- raise Error, "#{error.message} (does the app '#{option(:app)}' exist and does your account have access to it?)", error.backtrace
54
+ def handle_error_response(response)
55
+ error_response = JSON.parse(response.body)
56
+ error "API request failed.\nMessage: #{error_response["message"]}\nReference: #{error_response["url"]}"
44
57
  end
45
58
 
46
- def run(command)
47
- data = api.post_ps(option(:app), command, :attach => true).body
48
- rendezvous_url = data['rendezvous_url']
49
- Rendezvous.start(:url => rendezvous_url) unless rendezvous_url.nil?
59
+ def check_app
60
+ log "checking for app #{option(:app)}"
61
+ response = faraday.get("/apps/#{option(:app)}")
62
+ if response.success?
63
+ @app = JSON.parse(response.body)
64
+ log "found app #{@app["name"]}"
65
+ else
66
+ handle_error_response(response)
67
+ end
50
68
  end
51
69
 
52
70
  def restart
53
- api.post_ps_restart option(:app)
71
+ response = faraday.delete "/apps/#{option(:app)}/dynos" do |req|
72
+ req.headers['Content-Type'] = 'application/json'
73
+ end
74
+ unless response.success?
75
+ handle_error_response(response)
76
+ end
54
77
  end
55
78
 
56
- def deploy
57
- super
58
- rescue ::Heroku::API::Errors::NotFound => error
59
- raise Error, "#{error.message} (wrong app #{options[:app].inspect}?)", error.backtrace
60
- rescue ::Heroku::API::Errors::Unauthorized => error
61
- raise Error, "#{error.message} (wrong API key?)", error.backtrace
79
+ def run(command)
80
+ response = faraday.post "/apps/#{option(:app)}/dynos" do |req|
81
+ req.headers['Content-Type'] = 'application/json'
82
+ req.body = {"command" => command, "attach" => true}.to_json
83
+ end
84
+ if response.success?
85
+ rendezvous_url = JSON.parse(response.body)["attach_url"]
86
+ Rendezvous.start(url: rendezvous_url)
87
+ else
88
+ handle_error_response(response)
89
+ end
62
90
  end
63
91
  end
64
92
  end
@@ -2,6 +2,11 @@ module DPL
2
2
  class Provider
3
3
  module Heroku
4
4
  class GitDeployKey < GitSSH
5
+ deprecated(
6
+ "git-deploy-key strategy is deprecated, and will be shut down on June 26, 2017.",
7
+ "Please consider moving to the \`api\` or \`git\` strategy."
8
+ )
9
+
5
10
  def needs_key?
6
11
  false
7
12
  end
@@ -1,12 +1,87 @@
1
1
  module DPL
2
2
  class Provider
3
3
  module Heroku
4
- class GitSSH < Git
4
+ class GitSSH < Provider
5
5
  deprecated(
6
6
  "git-ssh strategy is deprecated, and will be shut down on June 26, 2017.",
7
7
  "Please consider moving to the \`api\` or \`git\` strategy."
8
8
  )
9
9
 
10
+ requires 'heroku-api'
11
+ requires 'rendezvous'
12
+ requires 'netrc'
13
+
14
+ def needs_key?
15
+ false
16
+ end
17
+
18
+ def api
19
+ @api ||= ::Heroku::API.new(api_options)
20
+ end
21
+
22
+ def api_options
23
+ api_options = { headers: { 'User-Agent' => user_agent(::Heroku::API::HEADERS.fetch('User-Agent')) } }
24
+ if options[:user] and options[:password]
25
+ api_options[:user] = options[:user]
26
+ api_options[:password] = options[:password]
27
+ else
28
+ api_options[:api_key] = option(:api_key)
29
+ end
30
+ api_options
31
+ end
32
+
33
+ def user
34
+ @user ||= api.get_user.body["email"]
35
+ end
36
+
37
+ def check_auth
38
+ log "authenticated as %s" % user
39
+ end
40
+
41
+ def info
42
+ @info ||= api.get_app(option(:app)).body
43
+ end
44
+
45
+ def check_app
46
+ log "checking for app '#{option(:app)}'"
47
+ log "found app '#{info['name']}'"
48
+ rescue ::Heroku::API::Errors::Forbidden => error
49
+ raise Error, "#{error.message} (does the app '#{option(:app)}' exist and does your account have access to it?)", error.backtrace
50
+ end
51
+
52
+ def run(command)
53
+ data = api.post_ps(option(:app), command, :attach => true).body
54
+ rendezvous_url = data['rendezvous_url']
55
+ Rendezvous.start(:url => rendezvous_url) unless rendezvous_url.nil?
56
+ end
57
+
58
+ def restart
59
+ api.post_ps_restart option(:app)
60
+ end
61
+
62
+ def deploy
63
+ super
64
+ rescue ::Heroku::API::Errors::NotFound => error
65
+ raise Error, "#{error.message} (wrong app #{options[:app].inspect}?)", error.backtrace
66
+ rescue ::Heroku::API::Errors::Unauthorized => error
67
+ raise Error, "#{error.message} (wrong API key?)", error.backtrace
68
+ end
69
+
70
+ def push_app
71
+ git_remote = options[:git] || git_url
72
+ write_netrc if git_remote.start_with?("https://")
73
+ log "$ git fetch origin $TRAVIS_BRANCH --unshallow"
74
+ context.shell "git fetch origin $TRAVIS_BRANCH --unshallow"
75
+ log "$ git push #{git_remote} HEAD:refs/heads/master -f"
76
+ context.shell "git push #{git_remote} HEAD:refs/heads/master -f"
77
+ end
78
+
79
+ def write_netrc
80
+ n = Netrc.read
81
+ n['git.heroku.com'] = [user, option(:api_key)]
82
+ n.save
83
+ end
84
+
10
85
  def git_url
11
86
  info['git_url']
12
87
  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("authenticated as username@example.com")
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
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dpl
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.37.travis.2118.5
4
+ version: 1.8.37.travis.2137.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Haase
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-02 00:00:00.000000000 Z
11
+ date: 2017-06-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -145,7 +145,6 @@ files:
145
145
  - lib/dpl/provider/gcs.rb
146
146
  - lib/dpl/provider/hackage.rb
147
147
  - lib/dpl/provider/heroku.rb
148
- - lib/dpl/provider/heroku/anvil.rb
149
148
  - lib/dpl/provider/heroku/api.rb
150
149
  - lib/dpl/provider/heroku/generic.rb
151
150
  - lib/dpl/provider/heroku/git.rb
@@ -195,10 +194,9 @@ files:
195
194
  - spec/provider/gae_spec.rb
196
195
  - spec/provider/gcs_spec.rb
197
196
  - spec/provider/hackage_spec.rb
198
- - spec/provider/heroku_anvil_spec.rb
199
- - spec/provider/heroku_api_spec.rb
200
197
  - spec/provider/heroku_git_deploy_key_spec.rb
201
- - spec/provider/heroku_git_spec.rb
198
+ - spec/provider/heroku_git_ssh_spec.rb
199
+ - spec/provider/heroku_spec.rb
202
200
  - spec/provider/lambda_spec.rb
203
201
  - spec/provider/launchpad_spec.rb
204
202
  - spec/provider/modulus_spec.rb
@@ -1,72 +0,0 @@
1
- module DPL
2
- class Provider
3
- module Heroku
4
- class Anvil < Git
5
- HEROKU_BUILDPACKS = ['ruby', 'nodejs', 'clojure', 'python', 'java', 'gradle', 'grails', 'scala', 'play']
6
- HEROKU_BUILDPACK_PREFIX = "https://github.com/heroku/heroku-buildpack-"
7
- requires 'anvil-cli', :load => 'anvil/engine'
8
- requires 'excon' # comes with heroku
9
- requires 'json'
10
-
11
- def api
12
- raise Error, 'anvil deploy strategy only works with api_key' unless options[:api_key]
13
- super
14
- end
15
-
16
- def deploy
17
- warn ''
18
- if options[:strategy]
19
- warn 'You have explicitly set your deploy strategy to %p.' % options[:strategy]
20
- warn 'Anvil support will be dropped in the near future.'
21
- warn 'Please consider changing it to "api" or "git".'
22
- else
23
- warn 'The default strategy for Heroku deployments is currently "anvil".'
24
- warn 'This will be changed to "api" in the near future.'
25
- warn 'Consider setting it explicitly to "api" or "git".'
26
- end
27
- warn ''
28
-
29
- super
30
- end
31
-
32
- def push_app
33
- sha = context.env['TRAVIS_COMMIT'] || `git rev-parse HEAD`.strip
34
- response = Excon.post release_url,
35
- :body => { "slug_url" => slug_url, "description" => "Deploy #{sha} via Travis CI" }.to_json,
36
- :headers => { 'Content-Type' => 'application/json', 'Accept' => 'application/json' }
37
-
38
- print "\nDeploying slug "
39
- while response.status == 202
40
- location = response.headers['Location']
41
- response = Excon.get("https://:#{option(:api_key)}@cisaurus.heroku.com#{location}")
42
- sleep(1)
43
- print '.'
44
- end
45
-
46
- if response.status.between? 200, 299
47
- puts " success!"
48
- else
49
- raise Error, "deploy failed, anvil response: #{response.body}"
50
- end
51
- end
52
-
53
- def slug_url
54
- @slug_url ||= begin
55
- ::Anvil.headers["X-Heroku-User"] = user
56
- ::Anvil.headers["X-Heroku-App"] = option(:app)
57
- if HEROKU_BUILDPACKS.include? options[:buildpack]
58
- options[:buildpack] = HEROKU_BUILDPACK_PREFIX + options[:buildpack] + ".git"
59
- end
60
- ::Anvil::Engine.build ".", :buildpack => options[:buildpack]
61
- rescue ::Anvil::Builder::BuildError => e
62
- raise Error, "deploy failed, anvil build error: #{e.message}"
63
- end
64
- end
65
-
66
- def release_url
67
- "https://:#{option(:api_key)}@cisaurus.heroku.com/v1/apps/#{option(:app)}/release"
68
- end
69
- end
70
- end
71
- end
72
- end
@@ -1,80 +0,0 @@
1
- require 'spec_helper'
2
- require 'anvil'
3
- require 'heroku-api'
4
- require 'excon'
5
- require 'dpl/provider/heroku'
6
-
7
- describe DPL::Provider::Heroku do
8
- subject :provider do
9
- described_class.new(DummyContext.new, :app => 'example', :api_key => 'foo', :strategy => 'anvil', :buildpack => 'git://some-buildpack.git')
10
- end
11
-
12
- describe "#api" do
13
- it 'accepts an api key' do
14
- api = double(:api)
15
- expect { provider.api }.not_to raise_error
16
- end
17
-
18
- it 'raises an error if an api key is not present' do
19
- provider.options.delete :api_key
20
- expect { provider.api }.to raise_error(DPL::Error)
21
- end
22
- end
23
-
24
- context "with fake api" do
25
- let :api do
26
- double "api",
27
- :get_user => double("get_user", :body => { "email" => "foo@bar.com" }),
28
- :get_app => double("get_app", :body => { "name" => "example", "git_url" => "GIT URL" })
29
- end
30
-
31
- before do
32
- expect(::Heroku::API).to receive(:new).and_return(api)
33
- provider.api
34
- end
35
-
36
- describe "#push_app" do
37
- example do
38
- response = double :response
39
- allow(response).to receive_messages(:status => 202)
40
- allow(response).to receive_messages(:headers => {'Location' => '/blah'})
41
-
42
- second_response = double :second_response
43
- allow(second_response).to receive_messages(:status => 200)
44
-
45
- allow(provider).to receive_messages(:slug_url => "http://slug-url")
46
-
47
- expect(provider.context.env).to receive(:[]).with('TRAVIS_COMMIT').and_return('123')
48
- expect(::Excon).to receive(:post).with(provider.release_url,
49
- :body => {"slug_url" => "http://slug-url", "description" => "Deploy 123 via Travis CI" }.to_json,
50
- :headers => {"Content-Type" => 'application/json', 'Accept' => 'application/json'}).and_return(response)
51
-
52
- expect(::Excon).to receive(:get).with("https://:#{provider.options[:api_key]}@cisaurus.heroku.com/blah").and_return(second_response)
53
- provider.push_app
54
- end
55
- end
56
-
57
- describe "#slug_url" do
58
-
59
- before(:each) do
60
- headers = double(:headers)
61
- expect(::Anvil).to receive(:headers).at_least(:twice).and_return(headers)
62
- expect(headers).to receive(:[]=).at_least(:once).with('X-Heroku-User', "foo@bar.com")
63
- expect(headers).to receive(:[]=).at_least(:once).with('X-Heroku-App', "example")
64
- end
65
-
66
- example "with full buildpack url" do
67
- expect(::Anvil::Engine).to receive(:build).with(".", :buildpack=>"git://some-buildpack.git")
68
- provider.slug_url
69
- end
70
-
71
- example "with buildpack name expansion" do
72
- DPL::Provider::Heroku::Anvil::HEROKU_BUILDPACKS.each do |b|
73
- provider.options.update(:buildpack => b)
74
- expect(::Anvil::Engine).to receive(:build).with(".", :buildpack=>described_class::Anvil::HEROKU_BUILDPACK_PREFIX + b + ".git")
75
- provider.slug_url
76
- end
77
- end
78
- end
79
- end
80
- end
@@ -1,228 +0,0 @@
1
- require 'spec_helper'
2
- require 'dpl/provider/heroku'
3
- require 'faraday'
4
-
5
- describe DPL::Provider::Heroku 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.post("/apps/example/builds") {|env| [201, response_headers, builds_response_body]}
13
- stub.get("/apps/example/builds/01234567-89ab-cdef-0123-456789abcdef/result") {|env| [200, response_headers, build_result_response_body]}
14
- stub.post("/sources") {|env| [201, response_headers, source_response_body] }
15
- end
16
- end
17
- }
18
-
19
- let(:response_headers) {
20
- {'Content-Type' => 'application/json'}
21
- }
22
-
23
- let(:account_response_body) {
24
- '{
25
- "allow_tracking": true,
26
- "beta": false,
27
- "created_at": "2012-01-01T12:00:00Z",
28
- "email": "username@example.com",
29
- "federated": false,
30
- "id": "01234567-89ab-cdef-0123-456789abcdef",
31
- "identity_provider": {
32
- "id": "01234567-89ab-cdef-0123-456789abcdef",
33
- "organization": {
34
- "name": "example"
35
- }
36
- },
37
- "last_login": "2012-01-01T12:00:00Z",
38
- "name": "Tina Edmonds",
39
- "sms_number": "+1 ***-***-1234",
40
- "suspended_at": "2012-01-01T12:00:00Z",
41
- "delinquent_at": "2012-01-01T12:00:00Z",
42
- "two_factor_authentication": false,
43
- "updated_at": "2012-01-01T12:00:00Z",
44
- "verified": false,
45
- "default_organization": {
46
- "id": "01234567-89ab-cdef-0123-456789abcdef",
47
- "name": "example"
48
- }
49
- }'
50
- }
51
-
52
- let(:builds_response_body) {
53
- '{
54
- "app": {
55
- "id": "01234567-89ab-cdef-0123-456789abcdef"
56
- },
57
- "buildpacks": [
58
- {
59
- "url": "https://github.com/heroku/heroku-buildpack-ruby"
60
- }
61
- ],
62
- "created_at": "2012-01-01T12:00:00Z",
63
- "id": "01234567-89ab-cdef-0123-456789abcdef",
64
- "output_stream_url": "https://build-output.heroku.com/streams/01234567-89ab-cdef-0123-456789abcdef",
65
- "source_blob": {
66
- "checksum": "SHA256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
67
- "url": "https://example.com/source.tgz?token=xyz",
68
- "version": "v1.3.0"
69
- },
70
- "release": {
71
- "id": "01234567-89ab-cdef-0123-456789abcdef"
72
- },
73
- "slug": {
74
- "id": "01234567-89ab-cdef-0123-456789abcdef"
75
- },
76
- "status": "succeeded",
77
- "updated_at": "2012-01-01T12:00:00Z",
78
- "user": {
79
- "id": "01234567-89ab-cdef-0123-456789abcdef",
80
- "email": "username@example.com"
81
- }
82
- }'
83
- }
84
-
85
- let(:source_response_body) {
86
- '{
87
- "source_blob": {
88
- "get_url": "https://api.heroku.com/sources/1234.tgz",
89
- "put_url": "https://api.heroku.com/sources/1234.tgz"
90
- }
91
- }'
92
- }
93
-
94
- let(:build_result_response_body) {
95
- '{
96
- "build": {
97
- "id": "01234567-89ab-cdef-0123-456789abcdef",
98
- "status": "succeeded",
99
- "output_stream_url": "https://build-output.heroku.com/streams/01234567-89ab-cdef-0123-456789abcdef"
100
- },
101
- "exit_code": 0,
102
- "lines": [
103
- {
104
- "line": "-----> Ruby app detected\n",
105
- "stream": "STDOUT"
106
- }
107
- ]
108
- }'
109
- }
110
-
111
- let(:build_result_response_body_failure) {
112
- '{
113
- "build": {
114
- "id": "01234567-89ab-cdef-0123-456789abcdef",
115
- "status": "failed",
116
- "output_stream_url": "https://build-output.heroku.com/streams/01234567-89ab-cdef-0123-456789abcdef"
117
- },
118
- "exit_code": 1,
119
- "lines": [
120
- {
121
- "line": "-----> Ruby app detected\n",
122
- "stream": "STDOUT"
123
- }
124
- ]
125
- }'
126
- }
127
-
128
- let(:build_result_response_body_in_progress) {
129
- '{
130
- "build": {
131
- "id": "01234567-89ab-cdef-0123-456789abcdef",
132
- "status": "failed",
133
- "output_stream_url": "https://build-output.heroku.com/streams/01234567-89ab-cdef-0123-456789abcdef"
134
- },
135
- "lines": [
136
- {
137
- "line": "-----> Ruby app detected\n",
138
- "stream": "STDOUT"
139
- }
140
- ]
141
- }'
142
- }
143
-
144
- subject(:provider) do
145
- described_class.new(DummyContext.new, provider_options.merge({ :api_key => api_key}))
146
- end
147
-
148
- let(:provider_options) {
149
- {:app => 'example', :key_name => 'key', :strategy => "api"}
150
- }
151
-
152
- let(:expected_headers) do
153
- { "Authorization" => "Bearer #{api_key}", "Accept" => "application/vnd.heroku+json; version=3" }
154
- end
155
-
156
- let(:api_url) { 'https://api.heroku.com' }
157
-
158
- describe "#ssh" do
159
- it "doesn't require an ssh key" do
160
- expect(provider.needs_key?).to eq(false)
161
- end
162
- end
163
-
164
- describe "#api" do
165
- it 'accepts an api key' do
166
- expect(provider).to receive(:faraday).at_least(:once).and_return(faraday)
167
- provider.check_auth
168
- end
169
-
170
- context "when api_key is not given" do
171
- let(:provider) { described_class.new(DummyContext.new, provider_options) }
172
- it 'raises DPL::Error' do
173
- provider.options.update(:user => "foo", :password => "bar")
174
- expect(::Heroku::API).not_to receive(:new)
175
- expect { provider.check_auth }.to raise_error(DPL::Error)
176
- end
177
- end
178
- end
179
-
180
- describe "#trigger_build" do
181
- it "does not initiate legacy API object" do
182
- expect(provider).to receive(:faraday).at_least(:once).and_return(faraday)
183
- expect(::Heroku::API).not_to receive(:new)
184
- provider.trigger_build
185
- end
186
-
187
- example do
188
- expect(provider).to receive(:log).with('triggering new deployment')
189
- expect(provider).to receive(:faraday).at_least(:once).and_return(faraday)
190
- expect(provider).to receive(:get_url).and_return 'http://example.com/source.tgz'
191
- expect(provider).to receive(:version).and_return 'v1.3.0'
192
- 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'")
193
- provider.trigger_build
194
- expect(provider.build_id).to eq('01234567-89ab-cdef-0123-456789abcdef')
195
- end
196
- end
197
-
198
- describe "#verify_build" do
199
- context 'when build succeeds' do
200
- example do
201
- expect(provider).to receive(:faraday).at_least(:once).and_return(faraday)
202
- expect(provider).to receive(:build_id).at_least(:once).and_return('01234567-89ab-cdef-0123-456789abcdef')
203
- expect{ provider.verify_build }.not_to raise_error
204
- end
205
- end
206
-
207
- context 'when build fails' do
208
- example do
209
- expect(provider).to receive(:faraday).at_least(:once).and_return(faraday)
210
- expect(provider).to receive(:build_id).at_least(:once).and_return('01234567-89ab-cdef-0123-456789abcdef')
211
- stubs.get("/apps/example/builds/01234567-89ab-cdef-0123-456789abcdef/result") {|env| [200, response_headers, build_result_response_body_failure]}
212
- expect{ provider.verify_build }.to raise_error("deploy failed, build exited with code 1")
213
- end
214
- end
215
-
216
- context 'when build is pending, then succeeds' do
217
- example do
218
- expect(provider).to receive(:faraday).at_least(:once).and_return(faraday)
219
- expect(provider).to receive(:build_id).at_least(:once).and_return('01234567-89ab-cdef-0123-456789abcdef')
220
- stubs.get("/apps/example/builds/01234567-89ab-cdef-0123-456789abcdef/result") {|env| [200, response_headers, build_result_response_body_in_progress]}
221
- expect(provider).to receive(:sleep).with(5) # stub sleep
222
- expect{ provider.verify_build }.not_to raise_error
223
- end
224
- end
225
-
226
- end
227
-
228
- end