dpl 1.8.33.travis.2049.5 → 1.8.34.travis.2089.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: 6bc174c17fad30b36ac9b2e2367a6b535a46ebd8
4
- data.tar.gz: 058ee4f23d5412dc20611a0c91c6e813362c6ed0
3
+ metadata.gz: 344f328801c80df62034fbfcc73345c4f1777df5
4
+ data.tar.gz: 126e4bd8d202e46a3b2096fcd1a45b137742fb16
5
5
  SHA512:
6
- metadata.gz: 44cb5e03513e86c8ee0610c705a64f73cb59d0fb17db8ca1d863a06b1462d4650e77a3134042f636c7133c1d185783b3ddcab4e368379058142fd89250486e94
7
- data.tar.gz: 4c02d030e307fb7adb256276eff47fa700bc1baf23865c157306548f66b5f2112a4039a31ae31edb17efb8c3de9bb0de1f2733fe672202635710a008b40bcc8d
6
+ metadata.gz: a57556f2852be0c4df1a23656529984bc66225f84b4519690114b9387824828b11fafb3e2ba06c70823125621878822386e775e9dbc04aea523899e71328041d
7
+ data.tar.gz: c2890e7cc455e59bfeb074fc9779754a12d1c8e8c9887ad07e724175434f8c6ce6afe41886c03189be5cd878a001ffeb80af40b7d43393e213fad8bb632f675d
data/Gemfile CHANGED
@@ -15,6 +15,7 @@ group :heroku do
15
15
  gem 'heroku-api', '= 0.3.16'
16
16
  gem 'anvil-cli', '~> 0.16.1'
17
17
  gem 'netrc'
18
+ gem 'faraday'
18
19
  end
19
20
 
20
21
  group :openshift do
@@ -1,11 +1,67 @@
1
1
  require 'json'
2
2
  require 'shellwords'
3
+ require 'logger'
3
4
 
4
5
  module DPL
5
6
  class Provider
6
7
  module Heroku
7
8
  class API < Generic
8
9
  attr_reader :build_id
10
+ requires 'faraday'
11
+ requires 'rendezvous'
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
9
65
 
10
66
  def push_app
11
67
  pack_archive
@@ -30,16 +86,29 @@ module DPL
30
86
 
31
87
  def trigger_build
32
88
  log "triggering new deployment"
33
- response = post(:builds, source_blob: { url: get_url, version: version })
34
- @build_id = response.fetch('id')
35
- output_stream_url = response.fetch('output_stream_url')
36
- context.shell "curl #{Shellwords.escape(output_stream_url)}"
89
+ response = faraday.post("/apps/#{option(:app)}/builds") do |req|
90
+ req.headers['Content-Type'] = 'application/json'
91
+ req.body = {
92
+ "source_blob" => {
93
+ "url" => get_url,
94
+ "version" => version
95
+ }
96
+ }.to_json
97
+ end
98
+
99
+ if response.success?
100
+ @build_id = JSON.parse(response.body)['id']
101
+ output_stream_url = JSON.parse(response.body)['output_stream_url']
102
+ context.shell "curl #{Shellwords.escape(output_stream_url)}"
103
+ else
104
+ handle_error_response(response)
105
+ end
37
106
  end
38
107
 
39
108
  def verify_build
40
109
  loop do
41
- response = get("builds/#{build_id}/result")
42
- exit_code = response.fetch('exit_code')
110
+ response = faraday.get("/apps/#{option(:app)}/builds/#{build_id}/result")
111
+ exit_code = JSON.parse(response.body)['exit_code']
43
112
  if exit_code.nil?
44
113
  log "heroku build still pending"
45
114
  sleep 5
@@ -61,38 +130,41 @@ module DPL
61
130
  end
62
131
 
63
132
  def source_blob
64
- @source_blob ||= post(:sources).fetch("source_blob")
133
+ return @source_blob if @source_blob
134
+
135
+ response = faraday.post('/sources')
136
+
137
+ if response.success?
138
+ @source_blob = JSON.parse(response.body)["source_blob"]
139
+ else
140
+ handle_error_response(response)
141
+ end
65
142
  end
66
143
 
67
144
  def version
68
145
  @version ||= options[:version] || context.env['TRAVIS_COMMIT'] || `git rev-parse HEAD`.strip
69
146
  end
70
147
 
71
- def get(subpath, options = {})
72
- options = {
73
- method: :get,
74
- path: "/apps/#{option(:app)}/#{subpath}",
75
- headers: { "Accept" => "application/vnd.heroku+json; version=3" },
76
- expects: [200]
77
- }.merge(options)
78
-
79
- api.request(options).body
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
80
155
  end
81
156
 
82
- def post(subpath, body = nil, options = {})
83
- options = {
84
- method: :post,
85
- path: "/apps/#{option(:app)}/#{subpath}",
86
- headers: { "Accept" => "application/vnd.heroku+json; version=3" },
87
- expects: [200, 201]
88
- }.merge(options)
89
-
90
- if body
91
- options[:body] = JSON.dump(body)
92
- options[:headers]['Content-Type'] = 'application/json'
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)
93
167
  end
94
-
95
- api.request(options).body
96
168
  end
97
169
  end
98
170
  end
data/lib/dpl/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module DPL
2
- VERSION = '1.8.32'
2
+ VERSION = '1.8.33'
3
3
  end
@@ -1,16 +1,160 @@
1
1
  require 'spec_helper'
2
- require 'heroku-api'
3
2
  require 'dpl/provider/heroku'
3
+ require 'faraday'
4
4
 
5
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
+
6
144
  subject(:provider) do
7
- described_class.new(DummyContext.new, :app => 'example', :key_name => 'key', :api_key => "foo", :strategy => "api")
145
+ described_class.new(DummyContext.new, provider_options.merge({ :api_key => api_key}))
8
146
  end
9
147
 
148
+ let(:provider_options) {
149
+ {:app => 'example', :key_name => 'key', :strategy => "api"}
150
+ }
151
+
10
152
  let(:expected_headers) do
11
- { "User-Agent" => "dpl/#{DPL::VERSION} heroku-rb/#{Heroku::API::VERSION}", "Accept" => "application/vnd.heroku+json; version=3" }
153
+ { "Authorization" => "Bearer #{api_key}", "Accept" => "application/vnd.heroku+json; version=3" }
12
154
  end
13
155
 
156
+ let(:api_url) { 'https://api.heroku.com' }
157
+
14
158
  describe "#ssh" do
15
159
  it "doesn't require an ssh key" do
16
160
  expect(provider.needs_key?).to eq(false)
@@ -19,74 +163,61 @@ describe DPL::Provider::Heroku do
19
163
 
20
164
  describe "#api" do
21
165
  it 'accepts an api key' do
22
- api = double(:api)
23
- expect(::Heroku::API).to receive(:new).with(:api_key => "foo", :headers => expected_headers).and_return(api)
24
- expect(provider.api).to eq(api)
166
+ expect(provider).to receive(:faraday).at_least(:once).and_return(faraday)
167
+ provider.check_auth
25
168
  end
26
169
 
27
- it 'accepts a user and a password' do
28
- api = double(:api)
29
- provider.options.update(:user => "foo", :password => "bar")
30
- expect(::Heroku::API).to receive(:new).with(:user => "foo", :password => "bar", :headers => expected_headers).and_return(api)
31
- expect(provider.api).to eq(api)
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
32
177
  end
33
178
  end
34
179
 
35
180
  describe "#trigger_build" do
36
- let(:response_body) { {
37
- "created_at" => "2012-01-01T12:00:00Z",
38
- "id" => "abc",
39
- "status" => "pending",
40
- "output_stream_url" => "http://example.com/stream",
41
- "updated_at" => "2012-01-01T12:00:00Z",
42
- "user" => { "id" => "01234567-89ab-cdef-0123-456789abcdef", "email" => "username@example.com" }
43
- } }
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
+
44
187
  example do
45
188
  expect(provider).to receive(:log).with('triggering new deployment')
189
+ expect(provider).to receive(:faraday).at_least(:once).and_return(faraday)
46
190
  expect(provider).to receive(:get_url).and_return 'http://example.com/source.tgz'
47
- expect(provider).to receive(:version).and_return 'sha'
48
- expect(provider).to receive(:post).with(
49
- :builds, source_blob: {url: 'http://example.com/source.tgz', version: 'sha'}
50
- ).and_return(response_body)
51
- expect(provider.context).to receive(:shell).with('curl http://example.com/stream')
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')
52
193
  provider.trigger_build
53
- expect(provider.build_id).to eq('abc')
194
+ expect(provider.build_id).to eq('01234567-89ab-cdef-0123-456789abcdef')
54
195
  end
55
196
  end
56
197
 
57
198
  describe "#verify_build" do
58
- def response_body(status, exit_code)
59
- {
60
- "build" => {
61
- "id" => "01234567-89ab-cdef-0123-456789abcdef",
62
- "status" => status
63
- },
64
- "exit_code" => exit_code
65
- }
66
- end
67
-
68
- before do
69
- allow(provider).to receive(:build_id).and_return('abc')
70
- end
71
-
72
199
  context 'when build succeeds' do
73
200
  example do
74
- expect(provider).to receive(:get).with('builds/abc/result').and_return(response_body('succeeded', 0))
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')
75
203
  expect{ provider.verify_build }.not_to raise_error
76
204
  end
77
205
  end
78
206
 
79
207
  context 'when build fails' do
80
208
  example do
81
- expect(provider).to receive(:get).with('builds/abc/result').and_return(response_body('failed', 1))
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]}
82
212
  expect{ provider.verify_build }.to raise_error("deploy failed, build exited with code 1")
83
213
  end
84
214
  end
85
215
 
86
216
  context 'when build is pending, then succeeds' do
87
217
  example do
88
- expect(provider).to receive(:get).with('builds/abc/result').and_return(response_body('pending', nil), response_body('succeeded', 0))
89
- expect(provider).to receive(:log).with('heroku build still pending')
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]}
90
221
  expect(provider).to receive(:sleep).with(5) # stub sleep
91
222
  expect{ provider.verify_build }.not_to raise_error
92
223
  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.33.travis.2049.5
4
+ version: 1.8.34.travis.2089.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-05-30 00:00:00.000000000 Z
11
+ date: 2017-06-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec