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
@@ -0,0 +1,33 @@
|
|
1
|
+
module Heroku
|
2
|
+
class API
|
3
|
+
|
4
|
+
# DELETE /apps/:app/domains/:domain
|
5
|
+
def delete_domain(app, domain)
|
6
|
+
request(
|
7
|
+
:expects => 200,
|
8
|
+
:method => :delete,
|
9
|
+
:path => "/apps/#{app}/domains/#{CGI.escape(domain)}"
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
# GET /apps/:app/domains
|
14
|
+
def get_domains(app)
|
15
|
+
request(
|
16
|
+
:expects => 200,
|
17
|
+
:method => :get,
|
18
|
+
:path => "/apps/#{app}/domains"
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
# POST /apps/:app/domains
|
23
|
+
def post_domain(app, domain)
|
24
|
+
request(
|
25
|
+
:expects => 201,
|
26
|
+
:method => :post,
|
27
|
+
:path => "/apps/#{app}/domains",
|
28
|
+
:query => {'domain_name[domain]' => domain}
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Heroku
|
2
|
+
class API
|
3
|
+
|
4
|
+
# DELETE /user/keys/:key
|
5
|
+
def delete_key(key)
|
6
|
+
request(
|
7
|
+
:expects => 200,
|
8
|
+
:method => :delete,
|
9
|
+
:path => "/user/keys/#{CGI.escape(key).gsub('.','%2E')}"
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
# DELETE /user/keys
|
14
|
+
def delete_keys
|
15
|
+
request(
|
16
|
+
:expects => 200,
|
17
|
+
:method => :delete,
|
18
|
+
:path => "/user/keys"
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
# GET /user/keys
|
23
|
+
def get_keys
|
24
|
+
request(
|
25
|
+
:expects => 200,
|
26
|
+
:method => :get,
|
27
|
+
:path => "/user/keys"
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
# POST /user/keys
|
32
|
+
def post_key(key)
|
33
|
+
request(
|
34
|
+
:body => key,
|
35
|
+
:expects => 200,
|
36
|
+
:method => :post,
|
37
|
+
:path => "/user/keys"
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Heroku
|
2
|
+
class API
|
3
|
+
|
4
|
+
# GET /apps/:app/logs
|
5
|
+
def get_logs(app, options)
|
6
|
+
options = {
|
7
|
+
'logplex' => 'true'
|
8
|
+
}.merge(options)
|
9
|
+
request(
|
10
|
+
:expects => 200,
|
11
|
+
:method => :get,
|
12
|
+
:path => "/apps/#{app}/logs",
|
13
|
+
:query => options
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'heroku/api/mock/addons'
|
2
|
+
require 'heroku/api/mock/apps'
|
3
|
+
require 'heroku/api/mock/collaborators'
|
4
|
+
require 'heroku/api/mock/config_vars'
|
5
|
+
require 'heroku/api/mock/domains'
|
6
|
+
require 'heroku/api/mock/keys'
|
7
|
+
require 'heroku/api/mock/logs'
|
8
|
+
require 'heroku/api/mock/processes'
|
9
|
+
require 'heroku/api/mock/releases'
|
10
|
+
require 'heroku/api/mock/stacks'
|
11
|
+
|
12
|
+
module Heroku
|
13
|
+
class API
|
14
|
+
module Mock
|
15
|
+
|
16
|
+
APP_NOT_FOUND = { :body => 'App not found.', :status => 404 }
|
17
|
+
USER_NOT_FOUND = { :body => 'User not found.', :status => 404 }
|
18
|
+
|
19
|
+
@mock_data = Hash.new do |hash, key|
|
20
|
+
hash[key] = {
|
21
|
+
:addons => {},
|
22
|
+
:apps => [],
|
23
|
+
:collaborators => {},
|
24
|
+
:config_vars => {},
|
25
|
+
:domains => {},
|
26
|
+
:keys => [],
|
27
|
+
:maintenance_mode => [],
|
28
|
+
:ps => {},
|
29
|
+
:releases => {}
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.add_mock_app_addon(mock_data, app, addon)
|
34
|
+
addon_data = get_mock_addon(mock_data, addon)
|
35
|
+
mock_data[:addons][app] << addon_data.reject {|key, value| !['beta', 'configured', 'description', 'name', 'state', 'url'].include?(key)}
|
36
|
+
version = mock_data[:releases][app].map {|release| release['name'][1..-1].to_i}.max || 0
|
37
|
+
env = if get_mock_app(mock_data, app)['stack'] == 'cedar'
|
38
|
+
{
|
39
|
+
'BUNDLE_WITHOUT' => 'development:test',
|
40
|
+
'DATABASE_URL' => 'postgres://username:password@ec2-123-123-123-123.compute-1.amazonaws.com/username',
|
41
|
+
'LANG' => 'en_US.UTF-8',
|
42
|
+
'RACK_ENV' => 'production',
|
43
|
+
'SHARED_DATABASE_URL' => 'postgres://username:password@ec2-123-123-123-123.compute-1.amazonaws.com/username'
|
44
|
+
}
|
45
|
+
else
|
46
|
+
{}
|
47
|
+
end
|
48
|
+
mock_data[:releases][app] << {
|
49
|
+
'addons' => mock_data[:addons][app].map {|addon| addon['name']},
|
50
|
+
'commit' => nil,
|
51
|
+
'created_at' => timestamp,
|
52
|
+
'descr' => "Add-on add #{addon_data['name']}",
|
53
|
+
'env' => env,
|
54
|
+
'name' => "v#{version + 1}",
|
55
|
+
'pstable' => { 'web' => '' },
|
56
|
+
'user' => 'email@example.com'
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.get_mock_addon(mock_data, addon)
|
61
|
+
@addons ||= begin
|
62
|
+
data = File.read("#{File.dirname(__FILE__)}/mock/cache/get_addons.json")
|
63
|
+
Heroku::API::OkJson.decode(data)
|
64
|
+
end
|
65
|
+
@addons.detect {|addon_data| addon_data['name'] == addon}
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.get_mock_addon_price(mock_data, addon)
|
69
|
+
addon_data = get_mock_addon(mock_data, addon)
|
70
|
+
price_cents = addon_data['price_cents'] || 0
|
71
|
+
price = format("$%d/mo", price_cents / 100)
|
72
|
+
if price == '$0/mo'
|
73
|
+
price = 'free'
|
74
|
+
end
|
75
|
+
price
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.get_mock_app(mock_data, app)
|
79
|
+
mock_data[:apps].detect {|app_data| app_data['name'] == app}
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.get_mock_app_addon(mock_data, app, addon)
|
83
|
+
mock_data[:addons][app].detect {|addon_data| addon_data['name'] == addon}
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.get_mock_app_domain(mock_data, app, domain)
|
87
|
+
mock_data[:domains][app].detect {|domain_data| domain_data['domain'] == domain}
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.get_mock_collaborator(mock_data, app, email)
|
91
|
+
mock_data[:collaborators][app].detect {|collaborator_data| collaborator_data['email'] == email}
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.get_mock_key(mock_data, key)
|
95
|
+
mock_data[:keys].detect {|key_data| %r{ #{Regexp.escape(key)}$}.match(key_data['contents'])}
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.get_mock_processes(mock_data, app)
|
99
|
+
mock_data[:ps][app].map do |ps|
|
100
|
+
|
101
|
+
# swap day/month positions for Time.parse
|
102
|
+
time_parts = ps['transitioned_at'].split(' ')
|
103
|
+
date_parts = time_parts.first.split('/')
|
104
|
+
date_parts[1], date_parts[2] = date_parts[2], date_parts[1]
|
105
|
+
time_parts[0] = date_parts.join('/')
|
106
|
+
munged_time = time_parts.join(' ')
|
107
|
+
elapsed = Time.now.to_i - Time.parse(munged_time).to_i
|
108
|
+
ps['elapsed'] = elapsed
|
109
|
+
|
110
|
+
pretty_elapsed = if elapsed < 60
|
111
|
+
"#{elapsed}s"
|
112
|
+
elsif elapsed < (60 * 60)
|
113
|
+
"#{elapsed / 60}m"
|
114
|
+
else
|
115
|
+
"#{elapsed / 60 / 60}h"
|
116
|
+
end
|
117
|
+
ps['pretty_state'] = "#{ps['state']} for #{pretty_elapsed}"
|
118
|
+
|
119
|
+
ps
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.parse_stub_params(params)
|
124
|
+
api_key = Base64.decode64(params[:headers]['Authorization']).split(':').last
|
125
|
+
|
126
|
+
parsed = params.dup
|
127
|
+
begin # try to JSON decode
|
128
|
+
parsed[:body] &&= Heroku::API::OkJson.decode(parsed[:body])
|
129
|
+
rescue # else leave as is
|
130
|
+
end
|
131
|
+
|
132
|
+
[parsed, @mock_data[api_key]]
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.remove_mock_app_addon(mock_data, app, addon)
|
136
|
+
addon_data = mock_data[:addons][app].detect {|addon_data| addon_data['name'] == addon}
|
137
|
+
mock_data[:addons][app].delete(addon_data)
|
138
|
+
version = mock_data[:releases][app].map {|release| release['name'][1..-1].to_i}.max || 0
|
139
|
+
env = if get_mock_app(mock_data, app)['stack'] == 'cedar'
|
140
|
+
{
|
141
|
+
'BUNDLE_WITHOUT' => 'development:test',
|
142
|
+
'DATABASE_URL' => 'postgres://username:password@ec2-123-123-123-123.compute-1.amazonaws.com/username',
|
143
|
+
'LANG' => 'en_US.UTF-8',
|
144
|
+
'RACK_ENV' => 'production',
|
145
|
+
'SHARED_DATABASE_URL' => 'postgres://username:password@ec2-123-123-123-123.compute-1.amazonaws.com/username'
|
146
|
+
}
|
147
|
+
else
|
148
|
+
{}
|
149
|
+
end
|
150
|
+
mock_data[:releases][app] << {
|
151
|
+
'addons' => mock_data[:addons][app].map {|addon| addon['name']},
|
152
|
+
'commit' => nil,
|
153
|
+
'created_at' => timestamp,
|
154
|
+
'descr' => "Add-on remove #{addon_data['name']}",
|
155
|
+
'env' => env,
|
156
|
+
'name' => "v#{version + 1}",
|
157
|
+
'pstable' => { 'web' => '' },
|
158
|
+
'user' => 'email@example.com'
|
159
|
+
}
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.with_mock_app(mock_data, app, &block)
|
163
|
+
if app_data = get_mock_app(mock_data, app)
|
164
|
+
yield(app_data)
|
165
|
+
else
|
166
|
+
APP_NOT_FOUND
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def self.timestamp
|
171
|
+
Time.now.strftime("%G/%d/%m %H:%M:%S %z")
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
module Heroku
|
2
|
+
class API
|
3
|
+
module Mock
|
4
|
+
|
5
|
+
# stub DELETE /apps/:app/addons/:addon
|
6
|
+
Excon.stub(:expects => 200, :method => :delete, :path => %r{^/apps/([^/]+)/addons/([^/]+)$}) do |params|
|
7
|
+
request_params, mock_data = parse_stub_params(params)
|
8
|
+
app, addon, _ = request_params[:captures][:path]
|
9
|
+
with_mock_app(mock_data, app) do
|
10
|
+
addon_names = mock_data[:addons][app].map {|data| data['name']}
|
11
|
+
if addon_data = get_mock_addon(mock_data, addon)
|
12
|
+
# addon exists
|
13
|
+
if app_addon_data = get_mock_app_addon(mock_data, app, addon)
|
14
|
+
# addon is currently installed
|
15
|
+
remove_mock_app_addon(mock_data, app, addon)
|
16
|
+
{
|
17
|
+
:body => Heroku::API::OkJson.encode({
|
18
|
+
:message => nil,
|
19
|
+
:price => get_mock_addon_price(mock_data, addon),
|
20
|
+
:status => 'Uninstalled'
|
21
|
+
}),
|
22
|
+
:status => 200
|
23
|
+
}
|
24
|
+
else
|
25
|
+
# addon is not currently installed
|
26
|
+
{
|
27
|
+
:body => Heroku::API::OkJson.encode({'error' => "The add-on #{addon} is not installed for this app. Did you mean:\n\t#{addon_names.join("\n\t")}"}),
|
28
|
+
:status => 422
|
29
|
+
}
|
30
|
+
end
|
31
|
+
else
|
32
|
+
# addon does not exist
|
33
|
+
{
|
34
|
+
:body => Heroku::API::OkJson.encode({'error' => "Could not find add-on #{addon}. Did you mean:\n\t#{addon_names.join("\n\t")}"}),
|
35
|
+
:status => 422
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# stub GET /addons
|
42
|
+
Excon.stub(:expects => 200, :method => :get, :path => "/addons") do |params|
|
43
|
+
request_params, mock_data = parse_stub_params(params)
|
44
|
+
{
|
45
|
+
:body => File.read("#{File.dirname(__FILE__)}/cache/get_addons.json"),
|
46
|
+
:status => 200
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
# stub GET /apps/:app/addons
|
51
|
+
Excon.stub(:expects => 200, :method => :get, :path => %r{^/apps/([^/]+)/addons$}) do |params|
|
52
|
+
request_params, mock_data = parse_stub_params(params)
|
53
|
+
app, _ = request_params[:captures][:path]
|
54
|
+
with_mock_app(mock_data, app) do
|
55
|
+
{
|
56
|
+
:body => Heroku::API::OkJson.encode(mock_data[:addons][app].map {|addon| addon['configured'] = true; addon}),
|
57
|
+
:status => 200
|
58
|
+
}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# stub POST /apps/:app/addons
|
63
|
+
Excon.stub(:expects => 200, :method => :post, :path => %r{^/apps/([^/]+)/addons/([^/]+)$}) do |params|
|
64
|
+
request_params, mock_data = parse_stub_params(params)
|
65
|
+
app, addon, _ = request_params[:captures][:path]
|
66
|
+
with_mock_app(mock_data, app) do
|
67
|
+
if addon_data = get_mock_addon(mock_data, addon)
|
68
|
+
# addon exists
|
69
|
+
unless app_addon_type_data = mock_data[:addons][app].detect {|data| data['name'] =~ %r{^#{addon.split(':').first}}}
|
70
|
+
# addon of same type does not exist
|
71
|
+
unless app_addon_data = get_mock_app_addon(mock_data, app, addon)
|
72
|
+
# addon is not currently installed
|
73
|
+
add_mock_app_addon(mock_data, app, addon)
|
74
|
+
{
|
75
|
+
:body => Heroku::API::OkJson.encode({
|
76
|
+
:message => nil,
|
77
|
+
:price => get_mock_addon_price(mock_data, addon),
|
78
|
+
:status => 'Installed'
|
79
|
+
}),
|
80
|
+
:status => 200
|
81
|
+
}
|
82
|
+
else
|
83
|
+
# addon is currently installed
|
84
|
+
{
|
85
|
+
:body => Heroku::API::OkJson.encode({'error' => "Add-on already installed."}),
|
86
|
+
:status => 422
|
87
|
+
}
|
88
|
+
end
|
89
|
+
else
|
90
|
+
# addon of same type exists
|
91
|
+
{
|
92
|
+
:body => Heroku::API::OkJson.encode({'error' => "#{app_addon_type_data['name']} add-on already added.\nTo upgrade, use addons:upgrade instead.\n"}),
|
93
|
+
:status => 422
|
94
|
+
}
|
95
|
+
end
|
96
|
+
else
|
97
|
+
# addon does not exist
|
98
|
+
{
|
99
|
+
:body => Heroku::API::OkJson.encode({'error' => "Add-on not found."}),
|
100
|
+
:status => 422
|
101
|
+
}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# stub PUT /apps/:app/addons
|
107
|
+
Excon.stub(:expects => 200, :method => :put, :path => %r{^/apps/([^/]+)/addons/([^/]+)$}) do |params|
|
108
|
+
request_params, mock_data = parse_stub_params(params)
|
109
|
+
app, addon, _ = request_params[:captures][:path]
|
110
|
+
with_mock_app(mock_data, app) do
|
111
|
+
if addon_data = get_mock_addon(mock_data, addon)
|
112
|
+
# addon exists
|
113
|
+
if mock_data[:addons][app].detect {|data| data['name'] =~ %r{^#{addon.split(':').first}}}
|
114
|
+
# addon of same type exists
|
115
|
+
unless app_addon_data = get_mock_app_addon(mock_data, app, addon)
|
116
|
+
# addon is not currently installed
|
117
|
+
mock_data[:addons][app].delete(app_addon_data)
|
118
|
+
add_mock_app_addon(mock_data, app, addon)
|
119
|
+
{
|
120
|
+
:body => Heroku::API::OkJson.encode({
|
121
|
+
:message => nil,
|
122
|
+
:price => get_mock_addon_price(mock_data, addon),
|
123
|
+
:status => 'Updated'
|
124
|
+
}),
|
125
|
+
:status => 200
|
126
|
+
}
|
127
|
+
else
|
128
|
+
# addon is currently installed
|
129
|
+
{
|
130
|
+
:body => Heroku::API::OkJson.encode({'error' => "Add-on already installed."}),
|
131
|
+
:status => 422
|
132
|
+
}
|
133
|
+
end
|
134
|
+
else
|
135
|
+
# addon of same type not installed
|
136
|
+
{
|
137
|
+
:body => Heroku::API::OkJson.encode({'error' => "Can't upgrade, no #{addon.split(':').join(' ')} add-on has been added.\nTo add, use addons:add instead.\n"}),
|
138
|
+
:status => 422
|
139
|
+
}
|
140
|
+
end
|
141
|
+
else
|
142
|
+
# addon does not exist
|
143
|
+
{
|
144
|
+
:body => Heroku::API::OkJson.encode({'error' => "Add-on not found."}),
|
145
|
+
:status => 422
|
146
|
+
}
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
module Heroku
|
2
|
+
class API
|
3
|
+
module Mock
|
4
|
+
|
5
|
+
# stub DELETE /apps/:app
|
6
|
+
Excon.stub(:expects => 200, :method => :delete, :path => %r{^/apps/([^/]+)$} ) do |params|
|
7
|
+
request_params, mock_data = parse_stub_params(params)
|
8
|
+
app, _ = request_params[:captures][:path]
|
9
|
+
with_mock_app(mock_data, app) do |app_data|
|
10
|
+
mock_data[:addons].delete(app)
|
11
|
+
mock_data[:apps].delete(app_data)
|
12
|
+
mock_data[:collaborators].delete(app)
|
13
|
+
mock_data[:config_vars].delete(app)
|
14
|
+
mock_data[:domains].delete(app)
|
15
|
+
mock_data[:ps].delete(app)
|
16
|
+
mock_data[:releases].delete(app)
|
17
|
+
{
|
18
|
+
:body => Heroku::API::OkJson.encode({}),
|
19
|
+
:status => 200
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# stub GET /apps/
|
25
|
+
Excon.stub(:expects => 200, :method => :get, :path => '/apps') do |params|
|
26
|
+
request_params, mock_data = parse_stub_params(params)
|
27
|
+
{
|
28
|
+
:body => Heroku::API::OkJson.encode(mock_data[:apps]),
|
29
|
+
:status => 200
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
# stub GET /apps/:app
|
34
|
+
Excon.stub(:expects => 200, :method => :get, :path => %r{^/apps/([^/]+)$} ) do |params|
|
35
|
+
request_params, mock_data = parse_stub_params(params)
|
36
|
+
app, _ = request_params[:captures][:path]
|
37
|
+
with_mock_app(mock_data, app) do |app_data|
|
38
|
+
{
|
39
|
+
:body => Heroku::API::OkJson.encode(app_data),
|
40
|
+
:status => 200
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# stub POST /apps
|
46
|
+
Excon.stub(:expects => 202, :method => :post, :path => '/apps') do |params|
|
47
|
+
request_params, mock_data = parse_stub_params(params)
|
48
|
+
app = request_params[:query].has_key?('app[name]') && request_params[:query]['app[name]'] || "generated-name-#{rand(999)}"
|
49
|
+
|
50
|
+
if get_mock_app(mock_data, app)
|
51
|
+
{
|
52
|
+
:body => Heroku::API::OkJson.encode('error' => 'Name is already taken'),
|
53
|
+
:status => 422
|
54
|
+
}
|
55
|
+
else
|
56
|
+
stack = request_params[:query].has_key?('app[stack]') && request_params[:query]['app[stack]'] || 'bamboo-mri-1.9.2'
|
57
|
+
app_data = {
|
58
|
+
'created_at' => timestamp,
|
59
|
+
'create_status' => 'complete',
|
60
|
+
'id' => rand(99999),
|
61
|
+
'name' => app,
|
62
|
+
'owner_email' => 'email@example.com',
|
63
|
+
'slug_size' => nil,
|
64
|
+
'stack' => request_params[:query].has_key?('app[stack]') && request_params[:query]['app[stack]'] || 'bamboo-mri-1.9.2',
|
65
|
+
'requested_stack' => nil,
|
66
|
+
'git_url' => "git@heroku.com:#{app}.git",
|
67
|
+
'repo_migrate_status' => 'complete',
|
68
|
+
'repo_size' => nil,
|
69
|
+
'dynos' => 0,
|
70
|
+
'web_url' => "http://#{app}.herokuapp.com/",
|
71
|
+
'workers' => 0
|
72
|
+
}
|
73
|
+
|
74
|
+
mock_data[:addons][app] = []
|
75
|
+
mock_data[:apps] << app_data
|
76
|
+
mock_data[:collaborators][app] = [{
|
77
|
+
'access' => 'edit',
|
78
|
+
'email' => 'email@example.com'
|
79
|
+
}]
|
80
|
+
mock_data[:config_vars][app] = {}
|
81
|
+
mock_data[:domains][app] = []
|
82
|
+
mock_data[:ps][app] = [{
|
83
|
+
'action' => 'up',
|
84
|
+
'app_name' => app,
|
85
|
+
'attached' => false,
|
86
|
+
'command' => nil, # set by stack below
|
87
|
+
'elapsed' => 0,
|
88
|
+
'pretty_state' => 'created for 0s',
|
89
|
+
'process' => 'web.1',
|
90
|
+
'rendezvous_url' => nil,
|
91
|
+
'slug' => 'NONE',
|
92
|
+
'state' => 'created',
|
93
|
+
'transitioned_at' => app_data['created_at'],
|
94
|
+
'type' => nil, # set by stack below
|
95
|
+
'upid' => rand(99999999).to_s
|
96
|
+
}]
|
97
|
+
mock_data[:releases][app] = []
|
98
|
+
|
99
|
+
add_mock_app_addon(mock_data, app, 'logging:basic')
|
100
|
+
if stack == 'cedar'
|
101
|
+
add_mock_app_addon(mock_data, app, 'releases:basic')
|
102
|
+
mock_data[:ps][app].first['type'] = 'Ps'
|
103
|
+
else
|
104
|
+
add_mock_app_addon(mock_data, app, 'shared-database:5mb')
|
105
|
+
mock_data[:config_vars][app] = {
|
106
|
+
'BUNDLE_WITHOUT' => 'development:test',
|
107
|
+
'LANG' => 'en_US.UTF-8',
|
108
|
+
'RACK_ENV' => 'production'
|
109
|
+
}
|
110
|
+
mock_data[:ps][app].first['command'] = 'thin -p $PORT -e $RACK_ENV -R $HEROKU_RACK start'
|
111
|
+
mock_data[:ps][app].first['type'] = 'Dyno'
|
112
|
+
end
|
113
|
+
|
114
|
+
{
|
115
|
+
:body => Heroku::API::OkJson.encode(app_data),
|
116
|
+
:status => 202
|
117
|
+
}
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# stub POST /apps/:app/server/maintenance
|
122
|
+
Excon.stub(:expects => 200, :method => :post, :path => %r{^/apps/([^/]+)/server/maintenance$}) do |params|
|
123
|
+
request_params, mock_data = parse_stub_params(params)
|
124
|
+
app, _ = request_params[:captures][:path].first
|
125
|
+
|
126
|
+
with_mock_app(mock_data, app) do
|
127
|
+
case request_params[:query]['maintenance_mode']
|
128
|
+
when '0'
|
129
|
+
mock_data[:maintenance_mode] -= [app]
|
130
|
+
when '1'
|
131
|
+
mock_data[:maintenance_mode] |= [app]
|
132
|
+
end
|
133
|
+
|
134
|
+
{
|
135
|
+
:status => 200
|
136
|
+
}
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# stub PUT /apps/:app
|
141
|
+
Excon.stub(:expects => 200, :method => :put, :path => %r{^/apps/([^/]+)$}) do |params|
|
142
|
+
request_params, mock_data = parse_stub_params(params)
|
143
|
+
app, _ = request_params[:captures][:path]
|
144
|
+
|
145
|
+
with_mock_app(mock_data, app) do |app_data|
|
146
|
+
if request_params[:query].has_key?('app[name]')
|
147
|
+
app_data['name'] = request_params[:query]['app[name]']
|
148
|
+
end
|
149
|
+
if request_params[:query].has_key?('app[transfer_owner]')
|
150
|
+
email = request_params[:query]['app[transfer_owner]']
|
151
|
+
if collaborator = get_mock_collaborator(mock_data, app, email)
|
152
|
+
app_data['owner_email'] = email
|
153
|
+
end
|
154
|
+
end
|
155
|
+
if email && !collaborator
|
156
|
+
{
|
157
|
+
:body => Heroku::API::OkJson.encode('error' => 'Only existing collaborators can receive ownership for an app'),
|
158
|
+
:status => 422
|
159
|
+
}
|
160
|
+
else
|
161
|
+
{
|
162
|
+
:body => Heroku::API::OkJson.encode('name' => app_data['name']),
|
163
|
+
:status => 200
|
164
|
+
}
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# stub PUT /apps/:app/status
|
170
|
+
Excon.stub(:method => :put, :path => %r{^/apps/([^/]+)/status}) do |params|
|
171
|
+
request_params, mock_data = parse_stub_params(params)
|
172
|
+
app, _ = request_params[:captures][:path]
|
173
|
+
|
174
|
+
with_mock_app(mock_data, app) do |app_data|
|
175
|
+
{
|
176
|
+
:body => Heroku::API::OkJson.encode({}),
|
177
|
+
:status => 201
|
178
|
+
}
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|