Class: Amitree::HerokuClient

Inherits:
Object
  • Object
show all
Defined in:
lib/amitree/heroku_client.rb

Defined Under Namespace

Classes: Error, PostDeploymentError

Instance Method Summary collapse

Constructor Details

#initialize(api_key, staging_app_name, production_app_name) ⇒ HerokuClient

Returns a new instance of HerokuClient.



14
15
16
17
18
19
20
# File 'lib/amitree/heroku_client.rb', line 14

def initialize(api_key, staging_app_name, production_app_name)
  @api_key = api_key
  @heroku = PlatformAPI.connect(api_key)
  @staging_app_name = staging_app_name
  @production_app_name = production_app_name
  @promoted_release_regexp = /Promote #{@staging_app_name} v(\d+)/
end

Instance Method Details

#current_production_releaseObject



30
31
32
# File 'lib/amitree/heroku_client.rb', line 30

def current_production_release
  get_releases(@production_app_name).to_a.last
end

#db_migrate_on_production(options = {}, attempts = 0) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/amitree/heroku_client.rb', line 77

def db_migrate_on_production(options={}, attempts=0)
  begin
    tasks = Array(options[:rake_prepend]) + %w(db:migrate db:seed) + Array(options[:rake])
    heroku_run @production_app_name, "rake #{tasks.join(' ')}"
  rescue => e
    if attempts < 2
      db_migrate_on_production(options, attempts+1)
      raise PostDeploymentError if attempts == 0
    else
      raise e
    end
  end
end

#deploy_to_production(staging_release, options = {}) ⇒ Object



59
60
61
62
63
64
65
66
67
# File 'lib/amitree/heroku_client.rb', line 59

def deploy_to_production(staging_release, options={})
  staging_release_version = staging_release['version']
  slug = staging_slug(staging_release_version)
  puts "Deploying slug to production: #{slug}"
  unless options[:dry_run]
    @heroku.release.create(@production_app_name, {'slug' => slug, 'description' => "Promote #{@staging_app_name} v#{staging_release_version}"})
    db_migrate_on_production(options)
  end
end

#get_production_commit(release) ⇒ Object



26
27
28
# File 'lib/amitree/heroku_client.rb', line 26

def get_production_commit(release)
  @heroku.slug.info(@production_app_name, release['slug']['id'])['commit']
end

#get_staging_commit(release) ⇒ Object



22
23
24
# File 'lib/amitree/heroku_client.rb', line 22

def get_staging_commit(release)
  @heroku.slug.info(@staging_app_name, release['slug']['id'])['commit']
end

#last_promoted_production_releaseObject



34
35
36
# File 'lib/amitree/heroku_client.rb', line 34

def last_promoted_production_release
  get_releases(@production_app_name).to_a.reverse.detect{|release| promoted_from_staging?(release)} or raise Error.new "Can't find a production release that was promoted from staging!"
end

Returns:

  • (Boolean)


45
46
47
# File 'lib/amitree/heroku_client.rb', line 45

def promoted_from_staging?(release)
  release['description'] =~ @promoted_release_regexp
end

#review_app_info(branch_name) ⇒ Object



95
96
97
98
99
100
101
102
103
104
# File 'lib/amitree/heroku_client.rb', line 95

def review_app_info(branch_name)
  pipeline_id = @heroku.pipeline_coupling.info_by_app(@staging_app_name)['pipeline']['id']

  # The current version of platform-api does not include the review-apps API
  review_apps = connection.get("https://api.heroku.com/pipelines/#{pipeline_id}/review-apps").body

  review_apps
    .select { |review_app| review_app['branch'] == branch_name }
    .map { |review_app| { pr_number: review_app['pr_number'], endpoint: @heroku.app.info(review_app['app']['id'])['web_url'].chomp('/') } }
end

#staging_release_version(production_release) ⇒ Object



38
39
40
41
42
43
# File 'lib/amitree/heroku_client.rb', line 38

def staging_release_version(production_release)
  unless production_release['description'] =~ @promoted_release_regexp
    raise Error.new "Production release was not promoted from staging: #{production_release['description']}"
  end
  $1.to_i
end

#staging_releases_since(production_release) ⇒ Object



49
50
51
52
53
54
55
56
57
# File 'lib/amitree/heroku_client.rb', line 49

def staging_releases_since(production_release)
  staging_release_version = self.staging_release_version(production_release)
  staging_releases = get_releases(@staging_app_name).to_a
  index = staging_releases.index { |release| release['version'] == staging_release_version }
  if index.nil?
    raise Error.new "Could not find staging release #{staging_release_version}"
  end
  staging_releases.slice(index+1, staging_releases.length)
end

#staging_slug(staging_release_version) ⇒ Object



69
70
71
72
73
74
75
# File 'lib/amitree/heroku_client.rb', line 69

def staging_slug(staging_release_version)
  unless staging_release_version.is_a?(Fixnum)
    raise Error.new "Unexpected release version: #{staging_release_version}"
  end
  result = @heroku.release.info(@staging_app_name, staging_release_version)
  result['slug']['id'] || raise(Error.new("Could not find slug in API response: #{result.inspect}"))
end

#version(release) ⇒ Object



91
92
93
# File 'lib/amitree/heroku_client.rb', line 91

def version(release)
  "v#{release['version']}"
end