heroku-api 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.travis.yml +14 -0
- data/Gemfile +4 -0
- data/README.md +120 -0
- data/Rakefile +23 -0
- data/changelog.txt +4 -0
- data/heroku-api.gemspec +23 -0
- data/lib/heroku-api.rb +1 -0
- data/lib/heroku/api.rb +85 -0
- data/lib/heroku/api/addons.rb +47 -0
- data/lib/heroku/api/apps.rb +62 -0
- data/lib/heroku/api/collaborators.rb +33 -0
- data/lib/heroku/api/config_vars.rb +33 -0
- data/lib/heroku/api/domains.rb +33 -0
- data/lib/heroku/api/errors.rb +9 -0
- data/lib/heroku/api/keys.rb +42 -0
- data/lib/heroku/api/logs.rb +18 -0
- data/lib/heroku/api/mock.rb +176 -0
- data/lib/heroku/api/mock/addons.rb +153 -0
- data/lib/heroku/api/mock/apps.rb +184 -0
- data/lib/heroku/api/mock/cache/get_addons.json +1 -0
- data/lib/heroku/api/mock/collaborators.rb +55 -0
- data/lib/heroku/api/mock/config_vars.rb +46 -0
- data/lib/heroku/api/mock/domains.rb +71 -0
- data/lib/heroku/api/mock/keys.rb +46 -0
- data/lib/heroku/api/mock/logs.rb +20 -0
- data/lib/heroku/api/mock/processes.rb +191 -0
- data/lib/heroku/api/mock/releases.rb +124 -0
- data/lib/heroku/api/mock/stacks.rb +84 -0
- data/lib/heroku/api/processes.rb +77 -0
- data/lib/heroku/api/releases.rb +33 -0
- data/lib/heroku/api/stacks.rb +22 -0
- data/lib/heroku/api/vendor/okjson.rb +559 -0
- data/lib/heroku/api/version.rb +5 -0
- data/test/test_addons.rb +169 -0
- data/test/test_apps.rb +119 -0
- data/test/test_collaborators.rb +73 -0
- data/test/test_config_vars.rb +54 -0
- data/test/test_domains.rb +63 -0
- data/test/test_helper.rb +35 -0
- data/test/test_keys.rb +39 -0
- data/test/test_logs.rb +20 -0
- data/test/test_processes.rb +245 -0
- data/test/test_releases.rb +91 -0
- data/test/test_stacks.rb +49 -0
- metadata +134 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
Heroku Ruby Client
|
2
|
+
==================
|
3
|
+
|
4
|
+
The Heroku Ruby Client is used to interact with the Heroku API from Ruby.
|
5
|
+
|
6
|
+
For more about the Heroku API see <http://api-docs.heroku.com>.
|
7
|
+
|
8
|
+
[![Build Status](https://secure.travis-ci.org/heroku/heroku.rb.png)](https://secure.travis-ci.org/heroku/heroku.rb)
|
9
|
+
|
10
|
+
Usage
|
11
|
+
-----
|
12
|
+
|
13
|
+
Start by creating a connection to Heroku with your credentials:
|
14
|
+
|
15
|
+
require 'heroku-rb'
|
16
|
+
|
17
|
+
heroku = Heroku.new(:api_key => API_KEY)
|
18
|
+
|
19
|
+
NOTE: You can leave out the `:api_key` if `ENV['HEROKU_API_KEY']` is set instead.
|
20
|
+
|
21
|
+
Now you can make requests to the api.
|
22
|
+
|
23
|
+
Requests
|
24
|
+
--------
|
25
|
+
|
26
|
+
What follows is an overview of commands you can run for the client.
|
27
|
+
|
28
|
+
For additional details about any of the commands, see the [API docs](http://api-docs.heroku.com).
|
29
|
+
|
30
|
+
### Add-ons
|
31
|
+
|
32
|
+
heroku.delete('app', 'addon') # remove 'addon' add-on from an 'app' app
|
33
|
+
heroku.get_addons # see a listing of all available add-ons
|
34
|
+
heroku.get_addons('app') # see listing of installed add-ons for 'app' app
|
35
|
+
heroku.post_addon('app', 'addon') # add 'addon' add-on to 'app' app
|
36
|
+
heroku.put_addon('app', 'addon') # update 'addon' add-on on 'app' app
|
37
|
+
|
38
|
+
### Apps
|
39
|
+
|
40
|
+
heroku.delete_app('app') # delete an app named 'app'
|
41
|
+
heroku.get_app('app') # get info about an app named 'app'
|
42
|
+
heroku.get_apps # get a list of your apps
|
43
|
+
heroku.post_apps # create an app with a generated name and the default stack
|
44
|
+
|
45
|
+
heroku.post_apps('name' => 'app') # create an app with a specified name
|
46
|
+
|
47
|
+
### Collaborators
|
48
|
+
|
49
|
+
delete_collaborator('app', 'email@example.com') # remove 'email@example.com' collaborator from 'app' app
|
50
|
+
delete_collaborator('app') # list collaborators for 'app' app
|
51
|
+
post_collaborator('app', 'email@example.com') # add 'email@example.com' collaborator to 'app' app
|
52
|
+
|
53
|
+
### Config Variables
|
54
|
+
|
55
|
+
delete_config_var('app', 'KEY') # remove 'KEY' key from 'app' app
|
56
|
+
get_config_vars('app') # get list of config vars for 'app' app
|
57
|
+
put_config_vars('app', 'KEY' => 'value') # set 'KEY' key to 'value' for 'app' app
|
58
|
+
|
59
|
+
### Domains
|
60
|
+
|
61
|
+
delete_domain('app', 'example.com') # remove the 'example.com' domain from the 'app' app
|
62
|
+
get_domains('app') # list configured domains for the 'app' app
|
63
|
+
post_domains('app', 'example.com') # add 'example.com' domain to the 'app' app
|
64
|
+
|
65
|
+
### Keys
|
66
|
+
|
67
|
+
delete_key('user@hostname.local') # remove the 'user@hostname.local' key
|
68
|
+
delete_keys # remove all keys
|
69
|
+
get_keys # list configured keys
|
70
|
+
post_key('key data') # add key defined by 'key data'
|
71
|
+
|
72
|
+
### Logs
|
73
|
+
|
74
|
+
get_logs('app') # return logs information for 'app' app
|
75
|
+
|
76
|
+
### Processes
|
77
|
+
|
78
|
+
get_ps('app') # list current processes for 'app' app
|
79
|
+
post_ps('app', 'command') # run 'command' command in context of 'app' app
|
80
|
+
post_ps_restart('app') # restart all processes for 'app' app
|
81
|
+
post_ps_scale('app', 'type', 'quantity') # scale 'type' type processes to 'quantity' for 'app' app
|
82
|
+
post_ps_stop('app', 'ps' => 'web.1') # stop 'web.1' process for 'app' app
|
83
|
+
post_ps_stop('app', 'type' => 'web') # stop all 'web' processes for 'app' app
|
84
|
+
put_dynos('app', 'dynos') # set number of dynos for bamboo app 'app' to 'dynos'
|
85
|
+
put_workers('app', 'workers') # set number of workers for bamboo app 'app' to 'workers'
|
86
|
+
|
87
|
+
post_ps_restart('app', 'ps' => 'web.1') # restart 'web.1' process for 'app' app
|
88
|
+
|
89
|
+
### Releases
|
90
|
+
|
91
|
+
get_releases('app') # list of releases for 'app' app
|
92
|
+
get_release('app', 'v#') # get details of 'v#' release for 'app' app
|
93
|
+
post_release('app', 'v#') # rollback 'app' app to 'v#' release
|
94
|
+
|
95
|
+
### Stacks
|
96
|
+
|
97
|
+
get_stack('app') # list available stacks
|
98
|
+
put_stack('app', 'stack') # migrate 'app' app to 'stack' stack
|
99
|
+
|
100
|
+
|
101
|
+
Mock
|
102
|
+
----
|
103
|
+
|
104
|
+
For practice or testing you can also use a simulated Heroku:
|
105
|
+
|
106
|
+
require 'heroku-rb'
|
107
|
+
|
108
|
+
heroku = Heroku.new(:api_key => API_KEY, :mock => true)
|
109
|
+
|
110
|
+
After that commands should still behave the same, but they will only modify some local data instead of updating the state of things on Heroku.
|
111
|
+
|
112
|
+
Tests
|
113
|
+
-----
|
114
|
+
|
115
|
+
To run tests, first set `ENV['HEROKU_API_KEY']` to your api key. Then use `bundle exec rake` to run mock tests or `MOCK=false bundle exec rake` to run integration tests.
|
116
|
+
|
117
|
+
Meta
|
118
|
+
----
|
119
|
+
|
120
|
+
Released under the [MIT license](http://www.opensource.org/licenses/mit-license.php).
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
task :default => :test
|
6
|
+
|
7
|
+
Rake::TestTask.new do |task|
|
8
|
+
task.name = :test
|
9
|
+
task.test_files = FileList['test/test*.rb']
|
10
|
+
end
|
11
|
+
|
12
|
+
task :cache, [:api_key] do |task, args|
|
13
|
+
unless args.api_key
|
14
|
+
puts('cache requires an api key, please call as `cache[api_key]`')
|
15
|
+
else
|
16
|
+
require "#{File.dirname(__FILE__)}/lib/heroku/api"
|
17
|
+
heroku = Heroku.new(:api_key => args.api_key)
|
18
|
+
data = Heroku::API::OkJson.encode(heroku.get_addons.body)
|
19
|
+
File.open("#{File.dirname(__FILE__)}/lib/heroku/stubs/cache/get_addons.json", 'w') do |file|
|
20
|
+
file.write(data)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/changelog.txt
ADDED
data/heroku-api.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "heroku/api/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "heroku-api"
|
7
|
+
s.version = Heroku::API::VERSION
|
8
|
+
s.authors = ["geemus (Wesley Beary)"]
|
9
|
+
s.email = ["wesley@heroku.com"]
|
10
|
+
s.homepage = "http://github.com/heroku/heroku.rb"
|
11
|
+
s.summary = %q{Ruby Client for the Heroku API}
|
12
|
+
s.description = %q{Ruby Client for the Heroku API}
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
|
19
|
+
s.add_runtime_dependency 'excon', '~>0.9.4'
|
20
|
+
|
21
|
+
s.add_development_dependency 'minitest'
|
22
|
+
s.add_development_dependency 'rake'
|
23
|
+
end
|
data/lib/heroku-api.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "heroku/api"
|
data/lib/heroku/api.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require "base64"
|
2
|
+
require "cgi"
|
3
|
+
require "excon"
|
4
|
+
require "securerandom"
|
5
|
+
|
6
|
+
require "heroku/api/vendor/okjson"
|
7
|
+
|
8
|
+
require "heroku/api/errors"
|
9
|
+
require "heroku/api/mock"
|
10
|
+
require "heroku/api/version"
|
11
|
+
|
12
|
+
require "heroku/api/addons"
|
13
|
+
require "heroku/api/apps"
|
14
|
+
require "heroku/api/collaborators"
|
15
|
+
require "heroku/api/config_vars"
|
16
|
+
require "heroku/api/domains"
|
17
|
+
require "heroku/api/keys"
|
18
|
+
require "heroku/api/logs"
|
19
|
+
require "heroku/api/processes"
|
20
|
+
require "heroku/api/releases"
|
21
|
+
require "heroku/api/stacks"
|
22
|
+
|
23
|
+
srand
|
24
|
+
|
25
|
+
module Heroku
|
26
|
+
class API
|
27
|
+
|
28
|
+
def initialize(options={})
|
29
|
+
@api_key = options.delete(:api_key) || ENV['HEROKU_API_KEY']
|
30
|
+
user_pass = ":#{@api_key}"
|
31
|
+
options = {
|
32
|
+
:headers => {},
|
33
|
+
:host => 'api.heroku.com',
|
34
|
+
:scheme => 'https'
|
35
|
+
}.merge(options)
|
36
|
+
options[:headers] = {
|
37
|
+
'Accept' => 'application/json',
|
38
|
+
'Authorization' => "Basic #{Base64.encode64(user_pass).gsub("\n", '')}",
|
39
|
+
'User-Agent' => "heroku-rb/#{Heroku::API::VERSION}",
|
40
|
+
'X-Heroku-API-Version' => '3',
|
41
|
+
'X-Ruby-Version' => RUBY_VERSION,
|
42
|
+
'X-Ruby-Platform' => RUBY_PLATFORM
|
43
|
+
}.merge(options[:headers])
|
44
|
+
@connection = Excon.new("#{options[:scheme]}://#{options[:host]}", options)
|
45
|
+
end
|
46
|
+
|
47
|
+
def request(params, &block)
|
48
|
+
begin
|
49
|
+
response = @connection.request(params, &block)
|
50
|
+
rescue Excon::Errors::NotFound => error
|
51
|
+
reerror = Heroku::API::Errors::NotFound.new(error.message)
|
52
|
+
reerror.set_backtrace(error.backtrace)
|
53
|
+
raise reerror
|
54
|
+
rescue Excon::Errors::Error => error
|
55
|
+
reerror = Heroku::API::Errors::Error.new(error.message)
|
56
|
+
reerror.set_backtrace(error.backtrace)
|
57
|
+
raise reerror
|
58
|
+
end
|
59
|
+
|
60
|
+
if response.body && !response.body.empty?
|
61
|
+
begin
|
62
|
+
response.body = Heroku::API::OkJson.decode(response.body)
|
63
|
+
rescue
|
64
|
+
# leave non-JSON body as is
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# reset (non-persistent) connection
|
69
|
+
@connection.reset
|
70
|
+
|
71
|
+
response
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def app_params(params)
|
77
|
+
app_params = {}
|
78
|
+
params.each do |key, value|
|
79
|
+
app_params["app[#{key}]"] = value
|
80
|
+
end
|
81
|
+
app_params
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Heroku
|
2
|
+
class API
|
3
|
+
|
4
|
+
# DELETE /apps/:app/addons/:addon
|
5
|
+
def delete_addon(app, addon)
|
6
|
+
request(
|
7
|
+
:expects => 200,
|
8
|
+
:method => :delete,
|
9
|
+
:path => "/apps/#{app}/addons/#{addon}"
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
# GET /addons
|
14
|
+
# GET /apps/:app/addons
|
15
|
+
def get_addons(app=nil)
|
16
|
+
path = if app
|
17
|
+
"/apps/#{app}/addons"
|
18
|
+
else
|
19
|
+
"/addons"
|
20
|
+
end
|
21
|
+
request(
|
22
|
+
:expects => 200,
|
23
|
+
:method => :get,
|
24
|
+
:path => path
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
# POST /apps/:app/addons/:addon
|
29
|
+
def post_addon(app, addon)
|
30
|
+
request(
|
31
|
+
:expects => 200,
|
32
|
+
:method => :post,
|
33
|
+
:path => "/apps/#{app}/addons/#{addon}"
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
# PUT /apps/:app/addons/:addon
|
38
|
+
def put_addon(app, addon)
|
39
|
+
request(
|
40
|
+
:expects => 200,
|
41
|
+
:method => :put,
|
42
|
+
:path => "/apps/#{app}/addons/#{addon}"
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Heroku
|
2
|
+
class API
|
3
|
+
|
4
|
+
# DELETE /apps/:app
|
5
|
+
def delete_app(app)
|
6
|
+
request(
|
7
|
+
:expects => 200,
|
8
|
+
:method => :delete,
|
9
|
+
:path => "/apps/#{app}"
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
# GET /apps
|
14
|
+
def get_apps
|
15
|
+
request(
|
16
|
+
:expects => 200,
|
17
|
+
:method => :get,
|
18
|
+
:path => "/apps"
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
# GET /apps/:app
|
23
|
+
def get_app(app)
|
24
|
+
request(
|
25
|
+
:expects => 200,
|
26
|
+
:method => :get,
|
27
|
+
:path => "/apps/#{app}"
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
# POST /apps
|
32
|
+
def post_app(params={})
|
33
|
+
request(
|
34
|
+
:expects => 202,
|
35
|
+
:method => :post,
|
36
|
+
:path => '/apps',
|
37
|
+
:query => app_params(params)
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
# POST /apps/:app/server/maintenance
|
42
|
+
def post_app_server_maintenance(app, new_server_maintenance)
|
43
|
+
request(
|
44
|
+
:expects => 200,
|
45
|
+
:method => :post,
|
46
|
+
:path => "/apps/#{app}/server/maintenance",
|
47
|
+
:query => {'maintenance_mode' => maintenance_mode}
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
# PUT /apps/:app
|
52
|
+
def put_app(app, params)
|
53
|
+
request(
|
54
|
+
:expects => 200,
|
55
|
+
:method => :put,
|
56
|
+
:path => "/apps/#{app}",
|
57
|
+
:query => app_params(params)
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Heroku
|
2
|
+
class API
|
3
|
+
|
4
|
+
# DELETE /apps/:app/collaborators/:email
|
5
|
+
def delete_collaborator(app, email)
|
6
|
+
request(
|
7
|
+
:expects => 200,
|
8
|
+
:method => :delete,
|
9
|
+
:path => "/apps/#{app}/collaborators/#{email}"
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
# GET /apps/:app/collaborators
|
14
|
+
def get_collaborators(app)
|
15
|
+
request(
|
16
|
+
:expects => 200,
|
17
|
+
:method => :get,
|
18
|
+
:path => "/apps/#{app}/collaborators"
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
# POST /apps/:app/collaborators
|
23
|
+
def post_collaborator(app, email)
|
24
|
+
request(
|
25
|
+
:expects => 200,
|
26
|
+
:method => :post,
|
27
|
+
:path => "/apps/#{app}/collaborators",
|
28
|
+
:query => {'collaborator[email]' => email}
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Heroku
|
2
|
+
class API
|
3
|
+
|
4
|
+
# DELETE /apps/:app/config_vars/:key
|
5
|
+
def delete_config_var(app, key)
|
6
|
+
request(
|
7
|
+
:expects => 200,
|
8
|
+
:method => :delete,
|
9
|
+
:path => "/apps/#{app}/config_vars/#{key}"
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
# GET /apps/:app/config_vars
|
14
|
+
def get_config_vars(app)
|
15
|
+
request(
|
16
|
+
:expects => 200,
|
17
|
+
:method => :get,
|
18
|
+
:path => "/apps/#{app}/config_vars"
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
# PUT /apps/:app/config_vars
|
23
|
+
def put_config_vars(app, vars)
|
24
|
+
request(
|
25
|
+
:body => Heroku::API::OkJson.encode(vars),
|
26
|
+
:expects => 200,
|
27
|
+
:method => :put,
|
28
|
+
:path => "/apps/#{app}/config_vars"
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|