Class: DPL::Provider::Heroku::API

Inherits:
Generic show all
Defined in:
lib/dpl/provider/heroku/api.rb

Instance Attribute Summary collapse

Attributes inherited from DPL::Provider

#context, #options

Instance Method Summary collapse

Methods inherited from Generic

#api, #api_options, #deploy, #info, #needs_key?, #user

Methods inherited from DPL::Provider

apt_get, #cleanup, #commit_msg, context, #create_key, #default_text_charset, #default_text_charset?, #deploy, #detect_encoding?, #encoding_for, #error, experimental, #initialize, #log, #needs_key?, new, npm_g, #option, pip, requires, #setup_git_credentials, #setup_git_ssh, #sha, shell, #uncleanup, #user_agent, #warn

Constructor Details

This class inherits a constructor from DPL::Provider

Instance Attribute Details

#build_idObject (readonly)

Returns the value of attribute build_id.



9
10
11
# File 'lib/dpl/provider/heroku/api.rb', line 9

def build_id
  @build_id
end

Instance Method Details

#archive_fileObject



73
74
75
# File 'lib/dpl/provider/heroku/api.rb', line 73

def archive_file
  Shellwords.escape("#{context.env['HOME']}/.dpl.#{option(:app)}.tgz")
end

#check_appObject



50
51
52
53
54
55
56
57
58
59
# File 'lib/dpl/provider/heroku/api.rb', line 50

def check_app
  log "checking for app #{option(:app)}"
  response = faraday.get("/apps/#{option(:app)}")
  if response.success?
    name = JSON.parse(response.body)["name"]
    log "found app #{name}"
  else
    handle_error_response(response)
  end
end

#check_authObject



13
14
15
16
17
18
19
20
21
22
# File 'lib/dpl/provider/heroku/api.rb', line 13

def check_auth
  response = faraday.get('/account')

  if response.success?
    email = JSON.parse(response.body)["email"]
    log "authenticated as #{email}"
  else
    handle_error_response(response)
  end
end

#faradayObject



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/dpl/provider/heroku/api.rb', line 24

def faraday
  return @conn if @conn
  headers = { "Accept" => "application/vnd.heroku+json; version=3" }

  if options[:user] and options[:password]
    # no-op
  else
    headers.merge!({ "Authorization" => "Bearer #{option(:api_key)}" })
  end

  @conn = Faraday.new( url: 'https://api.heroku.com', headers: headers ) do |faraday|
    if options[:user] and options[:password]
      faraday.basic_auth(options[:user], options[:password])
    end
    if log_level = options[:log_level]
      logger = Logger.new($stderr)
      logger.level = Logger.const_get(log_level.upcase)

      faraday.response :logger, logger do | logger |
        logger.filter(/(.*Authorization: ).*/,'\1[REDACTED]')
      end
    end
    faraday.adapter Faraday.default_adapter
  end
end

#get_urlObject



124
125
126
# File 'lib/dpl/provider/heroku/api.rb', line 124

def get_url
  source_blob.fetch("get_url")
end

#handle_error_response(response) ⇒ Object



61
62
63
64
# File 'lib/dpl/provider/heroku/api.rb', line 61

def handle_error_response(response)
  error_response = JSON.parse(response.body)
  error "API request failed.\nMessage: #{error_response["message"]}\nReference: #{error_response["url"]}"
end

#pack_archiveObject



77
78
79
80
# File 'lib/dpl/provider/heroku/api.rb', line 77

def pack_archive
  log "creating application archive"
  context.shell "tar -zcf #{archive_file} --exclude .git ."
end

#push_appObject



66
67
68
69
70
71
# File 'lib/dpl/provider/heroku/api.rb', line 66

def push_app
  pack_archive
  upload_archive
  trigger_build
  verify_build
end

#put_urlObject



128
129
130
# File 'lib/dpl/provider/heroku/api.rb', line 128

def put_url
  source_blob.fetch("put_url")
end

#restartObject



148
149
150
151
152
153
154
155
# File 'lib/dpl/provider/heroku/api.rb', line 148

def restart
  response = faraday.delete "/apps/#{option(:app)}/dynos" do |req|
    req.headers['Content-Type'] = 'application/json'
  end
  unless response.success?
    handle_error_response(response)
  end
end

#run(command) ⇒ Object



157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/dpl/provider/heroku/api.rb', line 157

def run(command)
  response = faraday.post "/apps/#{option(:app)}/dynos" do |req|
    req.headers['Content-Type'] = 'application/json'
    req.body = {"command" => command, "attach" => true}.to_json
  end
  if response.success?
    rendezvous_url = JSON.parse(response.body)["attach_url"]
    Rendezvous.start(url: rendezvous_url)
  else
    handle_error_response(response)
  end
end

#source_blobObject



132
133
134
135
136
137
138
139
140
141
142
# File 'lib/dpl/provider/heroku/api.rb', line 132

def source_blob
  return @source_blob if @source_blob

  response = faraday.post('/sources')

  if response.success?
    @source_blob = JSON.parse(response.body)["source_blob"]
  else
    handle_error_response(response)
  end
end

#trigger_buildObject



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/dpl/provider/heroku/api.rb', line 87

def trigger_build
  log "triggering new deployment"
  response = faraday.post("/apps/#{option(:app)}/builds") do |req|
    req.headers['Content-Type'] = 'application/json'
    req.body = {
      "source_blob" => {
        "url" => get_url,
        "version" => version
      }
      }.to_json
  end

  if response.success?
    @build_id  = JSON.parse(response.body)['id']
    output_stream_url = JSON.parse(response.body)['output_stream_url']
    context.shell "curl #{Shellwords.escape(output_stream_url)} -H 'Accept: application/vnd.heroku+json; version=3'"
  else
    handle_error_response(response)
  end
end

#upload_archiveObject



82
83
84
85
# File 'lib/dpl/provider/heroku/api.rb', line 82

def upload_archive
  log "uploading application archive"
  context.shell "curl #{Shellwords.escape(put_url)} -X PUT -H 'Content-Type:' -H 'Accept: application/vnd.heroku+json; version=3' --data-binary @#{archive_file}"
end

#verify_buildObject



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/dpl/provider/heroku/api.rb', line 108

def verify_build
  loop do
    response = faraday.get("/apps/#{option(:app)}/builds/#{build_id}/result")
    exit_code = JSON.parse(response.body)['exit_code']
    if exit_code.nil?
      log "heroku build still pending"
      sleep 5
      next
    elsif exit_code == 0
      break
    else
      error "deploy failed, build exited with code #{exit_code}"
    end
  end
end

#versionObject



144
145
146
# File 'lib/dpl/provider/heroku/api.rb', line 144

def version
  @version ||= options[:version] || context.env['TRAVIS_COMMIT'] || `git rev-parse HEAD`.strip
end