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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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