azuki-api 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.travis.yml +16 -0
- data/Gemfile +4 -0
- data/README.md +128 -0
- data/Rakefile +41 -0
- data/azuki-api.gemspec +23 -0
- data/changelog.txt +204 -0
- data/lib/azuki-api.rb +1 -0
- data/lib/azuki/api.rb +146 -0
- data/lib/azuki/api/addons.rb +48 -0
- data/lib/azuki/api/apps.rb +71 -0
- data/lib/azuki/api/attachments.rb +14 -0
- data/lib/azuki/api/collaborators.rb +33 -0
- data/lib/azuki/api/config_vars.rb +33 -0
- data/lib/azuki/api/domains.rb +42 -0
- data/lib/azuki/api/errors.rb +26 -0
- data/lib/azuki/api/features.rb +45 -0
- data/lib/azuki/api/keys.rb +42 -0
- data/lib/azuki/api/login.rb +14 -0
- data/lib/azuki/api/logs.rb +18 -0
- data/lib/azuki/api/mock.rb +179 -0
- data/lib/azuki/api/mock/addons.rb +153 -0
- data/lib/azuki/api/mock/apps.rb +205 -0
- data/lib/azuki/api/mock/attachments.rb +19 -0
- data/lib/azuki/api/mock/cache/get_addons.json +1 -0
- data/lib/azuki/api/mock/cache/get_features.json +1 -0
- data/lib/azuki/api/mock/cache/get_user.json +1 -0
- data/lib/azuki/api/mock/collaborators.rb +55 -0
- data/lib/azuki/api/mock/config_vars.rb +49 -0
- data/lib/azuki/api/mock/domains.rb +80 -0
- data/lib/azuki/api/mock/features.rb +120 -0
- data/lib/azuki/api/mock/keys.rb +46 -0
- data/lib/azuki/api/mock/login.rb +22 -0
- data/lib/azuki/api/mock/logs.rb +20 -0
- data/lib/azuki/api/mock/processes.rb +198 -0
- data/lib/azuki/api/mock/releases.rb +69 -0
- data/lib/azuki/api/mock/stacks.rb +83 -0
- data/lib/azuki/api/mock/user.rb +16 -0
- data/lib/azuki/api/processes.rb +77 -0
- data/lib/azuki/api/releases.rb +33 -0
- data/lib/azuki/api/ssl_endpoints.rb +62 -0
- data/lib/azuki/api/stacks.rb +22 -0
- data/lib/azuki/api/user.rb +14 -0
- data/lib/azuki/api/vendor/okjson.rb +600 -0
- data/lib/azuki/api/version.rb +5 -0
- data/test/data/site.crt +19 -0
- data/test/data/site.key +27 -0
- data/test/test_addons.rb +193 -0
- data/test/test_apps.rb +147 -0
- data/test/test_attachments.rb +23 -0
- data/test/test_collaborators.rb +73 -0
- data/test/test_config_vars.rb +54 -0
- data/test/test_domains.rb +65 -0
- data/test/test_error_conditions.rb +11 -0
- data/test/test_features.rb +87 -0
- data/test/test_helper.rb +48 -0
- data/test/test_keys.rb +39 -0
- data/test/test_login.rb +20 -0
- data/test/test_logs.rb +29 -0
- data/test/test_processes.rb +245 -0
- data/test/test_releases.rb +73 -0
- data/test/test_ssl_endpoints.rb +132 -0
- data/test/test_stacks.rb +49 -0
- data/test/test_user.rb +13 -0
- metadata +168 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
module Azuki
|
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, config = {})
|
30
|
+
request(
|
31
|
+
:expects => 200,
|
32
|
+
:method => :post,
|
33
|
+
:path => "/apps/#{app}/addons/#{addon}",
|
34
|
+
:query => addon_params(config)
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
# PUT /apps/:app/addons/:addon
|
39
|
+
def put_addon(app, addon, config = {})
|
40
|
+
request(
|
41
|
+
:expects => 200,
|
42
|
+
:method => :put,
|
43
|
+
:path => "/apps/#{app}/addons/#{addon}",
|
44
|
+
:query => addon_params(config)
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Azuki
|
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
|
+
# GET /apps/:app/server/maintenance
|
32
|
+
def get_app_maintenance(app)
|
33
|
+
request(
|
34
|
+
:expects => 200,
|
35
|
+
:method => :get,
|
36
|
+
:path => "/apps/#{app}/server/maintenance"
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
# POST /apps
|
41
|
+
def post_app(params={})
|
42
|
+
request(
|
43
|
+
:expects => 202,
|
44
|
+
:method => :post,
|
45
|
+
:path => '/apps',
|
46
|
+
:query => app_params(params)
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
# POST /apps/:app/server/maintenance
|
51
|
+
def post_app_maintenance(app, maintenance_mode)
|
52
|
+
request(
|
53
|
+
:expects => 200,
|
54
|
+
:method => :post,
|
55
|
+
:path => "/apps/#{app}/server/maintenance",
|
56
|
+
:query => {'maintenance_mode' => maintenance_mode}
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
# PUT /apps/:app
|
61
|
+
def put_app(app, params)
|
62
|
+
request(
|
63
|
+
:expects => 200,
|
64
|
+
:method => :put,
|
65
|
+
:path => "/apps/#{app}",
|
66
|
+
:query => app_params(params)
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Azuki
|
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, 201],
|
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 Azuki
|
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/#{escape(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 => Azuki::API::OkJson.encode(vars),
|
26
|
+
:expects => 200,
|
27
|
+
:method => :put,
|
28
|
+
:path => "/apps/#{app}/config_vars"
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Azuki
|
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/#{escape(domain)}"
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
# DELETE /apps/:app/domains
|
14
|
+
def delete_domains(app)
|
15
|
+
request(
|
16
|
+
:expects => 200,
|
17
|
+
:method => :delete,
|
18
|
+
:path => "/apps/#{app}/domains"
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
# GET /apps/:app/domains
|
23
|
+
def get_domains(app)
|
24
|
+
request(
|
25
|
+
:expects => 200,
|
26
|
+
:method => :get,
|
27
|
+
:path => "/apps/#{app}/domains"
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
# POST /apps/:app/domains
|
32
|
+
def post_domain(app, domain)
|
33
|
+
request(
|
34
|
+
:expects => 201,
|
35
|
+
:method => :post,
|
36
|
+
:path => "/apps/#{app}/domains",
|
37
|
+
:query => {'domain_name[domain]' => domain}
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Azuki
|
2
|
+
class API
|
3
|
+
module Errors
|
4
|
+
class Error < StandardError; end
|
5
|
+
|
6
|
+
class ErrorWithResponse < Error
|
7
|
+
attr_reader :response
|
8
|
+
|
9
|
+
def initialize(message, response)
|
10
|
+
super message
|
11
|
+
@response = response
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Unauthorized < ErrorWithResponse; end
|
16
|
+
class VerificationRequired < ErrorWithResponse; end
|
17
|
+
class Forbidden < ErrorWithResponse; end
|
18
|
+
class NotFound < ErrorWithResponse; end
|
19
|
+
class Timeout < ErrorWithResponse; end
|
20
|
+
class Locked < ErrorWithResponse; end
|
21
|
+
class RequestFailed < ErrorWithResponse; end
|
22
|
+
class NilApp < ErrorWithResponse; end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Azuki
|
2
|
+
class API
|
3
|
+
|
4
|
+
# DELETE /features/:feature
|
5
|
+
def delete_feature(feature, app = nil)
|
6
|
+
request(
|
7
|
+
:expects => 200,
|
8
|
+
:method => :delete,
|
9
|
+
:path => "/features/#{feature}",
|
10
|
+
:query => { 'app' => app }
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
# GET /features
|
15
|
+
def get_features(app = nil)
|
16
|
+
request(
|
17
|
+
:expects => 200,
|
18
|
+
:method => :get,
|
19
|
+
:path => "/features",
|
20
|
+
:query => { 'app' => app }
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
# GET /features/:feature
|
25
|
+
def get_feature(feature, app = nil)
|
26
|
+
request(
|
27
|
+
:expects => 200,
|
28
|
+
:method => :get,
|
29
|
+
:path => "/features/#{feature}",
|
30
|
+
:query => { 'app' => app }
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
# POST /features/:feature
|
35
|
+
def post_feature(feature, app = nil)
|
36
|
+
request(
|
37
|
+
:expects => [200, 201],
|
38
|
+
:method => :post,
|
39
|
+
:path => "/features/#{feature}",
|
40
|
+
:query => { 'app' => app }
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Azuki
|
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/#{escape(key)}"
|
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 Azuki
|
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,179 @@
|
|
1
|
+
require 'azuki/api/mock/addons'
|
2
|
+
require 'azuki/api/mock/apps'
|
3
|
+
require 'azuki/api/mock/attachments'
|
4
|
+
require 'azuki/api/mock/collaborators'
|
5
|
+
require 'azuki/api/mock/config_vars'
|
6
|
+
require 'azuki/api/mock/domains'
|
7
|
+
require 'azuki/api/mock/features'
|
8
|
+
require 'azuki/api/mock/keys'
|
9
|
+
require 'azuki/api/mock/login'
|
10
|
+
require 'azuki/api/mock/logs'
|
11
|
+
require 'azuki/api/mock/processes'
|
12
|
+
require 'azuki/api/mock/releases'
|
13
|
+
require 'azuki/api/mock/stacks'
|
14
|
+
require 'azuki/api/mock/user'
|
15
|
+
|
16
|
+
module Azuki
|
17
|
+
class API
|
18
|
+
module Mock
|
19
|
+
|
20
|
+
APP_NOT_FOUND = { :body => 'App not found.', :status => 404 }
|
21
|
+
USER_NOT_FOUND = { :body => 'User not found.', :status => 404 }
|
22
|
+
|
23
|
+
@mock_data = Hash.new do |hash, key|
|
24
|
+
hash[key] = {
|
25
|
+
:addons => {},
|
26
|
+
:apps => [],
|
27
|
+
:attachments => {},
|
28
|
+
:collaborators => {},
|
29
|
+
:config_vars => {},
|
30
|
+
:domains => {},
|
31
|
+
:features => {
|
32
|
+
:app => Hash.new {|hash,key| hash[key] = []},
|
33
|
+
:user => []
|
34
|
+
},
|
35
|
+
:keys => [],
|
36
|
+
:maintenance_mode => [],
|
37
|
+
:ps => {},
|
38
|
+
:releases => {},
|
39
|
+
:user => {}
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.add_mock_app_addon(mock_data, app, addon)
|
44
|
+
addon_data = get_mock_addon(mock_data, addon)
|
45
|
+
mock_data[:addons][app] << addon_data.reject {|key, value| !['attachable', 'beta', 'configured', 'consumes_dyno_hours', 'description', 'group_description', 'name', 'plan_description', 'price', 'slug', 'state', 'terms_of_service', 'url'].include?(key)}
|
46
|
+
add_mock_release(mock_data, app, {'descr' => "Add-on add #{addon_data['name']}"})
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.add_mock_release(mock_data, app, release_data)
|
50
|
+
env = if get_mock_app(mock_data, app)['stack'] == 'cedar'
|
51
|
+
{
|
52
|
+
'BUNDLE_WITHOUT' => 'development:test',
|
53
|
+
'DATABASE_URL' => 'postgres://username:password@ec2-123-123-123-123.compute-1.amazonaws.com/username',
|
54
|
+
'LANG' => 'en_US.UTF-8',
|
55
|
+
'RACK_ENV' => 'production'
|
56
|
+
}
|
57
|
+
else
|
58
|
+
{}
|
59
|
+
end
|
60
|
+
version = mock_data[:releases][app].map {|release| release['name'][1..-1].to_i}.max || 0
|
61
|
+
mock_data[:releases][app] << {
|
62
|
+
'addons' => mock_data[:addons][app].map {|addon| addon['name']},
|
63
|
+
'commit' => nil,
|
64
|
+
'created_at' => timestamp,
|
65
|
+
'descr' => "",
|
66
|
+
'env' => env,
|
67
|
+
'name' => "v#{version + 1}",
|
68
|
+
'pstable' => { 'web' => '' },
|
69
|
+
'user' => 'email@example.com'
|
70
|
+
}.merge(release_data)
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.get_mock_addon(mock_data, addon)
|
74
|
+
@addons ||= begin
|
75
|
+
data = File.read("#{File.dirname(__FILE__)}/mock/cache/get_addons.json")
|
76
|
+
Azuki::API::OkJson.decode(data)
|
77
|
+
end
|
78
|
+
@addons.detect {|addon_data| addon_data['name'] == addon}
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.get_mock_addon_price(mock_data, addon)
|
82
|
+
addon_data = get_mock_addon(mock_data, addon)
|
83
|
+
price_cents = addon_data['price_cents'] || 0
|
84
|
+
price = format("$%d/mo", price_cents / 100)
|
85
|
+
if price == '$0/mo'
|
86
|
+
price = 'free'
|
87
|
+
end
|
88
|
+
price
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.get_mock_app(mock_data, app)
|
92
|
+
mock_data[:apps].detect {|app_data| app_data['name'] == app}
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.get_mock_app_addon(mock_data, app, addon)
|
96
|
+
mock_data[:addons][app].detect {|addon_data| addon_data['name'] == addon}
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.get_mock_app_domain(mock_data, app, domain)
|
100
|
+
mock_data[:domains][app].detect {|domain_data| domain_data['domain'] == domain}
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.get_mock_collaborator(mock_data, app, email)
|
104
|
+
mock_data[:collaborators][app].detect {|collaborator_data| collaborator_data['email'] == email}
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.get_mock_feature(mock_data, feature)
|
108
|
+
@features ||= begin
|
109
|
+
data = File.read("#{File.dirname(__FILE__)}/mock/cache/get_features.json")
|
110
|
+
Azuki::API::OkJson.decode(data)
|
111
|
+
end
|
112
|
+
@features.detect {|feature_data| feature_data['name'] == feature}
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.get_mock_key(mock_data, key)
|
116
|
+
mock_data[:keys].detect {|key_data| %r{ #{Regexp.escape(key)}$}.match(key_data['contents'])}
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.get_mock_processes(mock_data, app)
|
120
|
+
mock_data[:ps][app].map do |ps|
|
121
|
+
|
122
|
+
elapsed = Time.now.to_i - Time.parse(ps['transitioned_at']).to_i
|
123
|
+
ps['elapsed'] = elapsed
|
124
|
+
|
125
|
+
pretty_elapsed = if elapsed < 60
|
126
|
+
"#{elapsed}s"
|
127
|
+
elsif elapsed < (60 * 60)
|
128
|
+
"#{elapsed / 60}m"
|
129
|
+
else
|
130
|
+
"#{elapsed / 60 / 60}h"
|
131
|
+
end
|
132
|
+
ps['pretty_state'] = "#{ps['state']} for #{pretty_elapsed}"
|
133
|
+
|
134
|
+
ps
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.parse_stub_params(params)
|
139
|
+
mock_data = nil
|
140
|
+
|
141
|
+
if params[:headers].has_key?('Authorization')
|
142
|
+
api_key = Base64.decode64(params[:headers]['Authorization']).split(':').last
|
143
|
+
|
144
|
+
parsed = params.dup
|
145
|
+
begin # try to JSON decode
|
146
|
+
parsed[:body] &&= Azuki::API::OkJson.decode(parsed[:body])
|
147
|
+
rescue # else leave as is
|
148
|
+
end
|
149
|
+
mock_data = @mock_data[api_key]
|
150
|
+
end
|
151
|
+
|
152
|
+
[parsed, mock_data]
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.remove_mock_app_addon(mock_data, app, addon)
|
156
|
+
addon_data = mock_data[:addons][app].detect {|addon_data| addon_data['name'] == addon}
|
157
|
+
mock_data[:addons][app].delete(addon_data)
|
158
|
+
add_mock_release(mock_data, app, {'descr' => "Add-on remove #{addon_data['name']}"})
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.unescape(string)
|
162
|
+
CGI.unescape(string)
|
163
|
+
end
|
164
|
+
|
165
|
+
def self.with_mock_app(mock_data, app, &block)
|
166
|
+
if app_data = get_mock_app(mock_data, app)
|
167
|
+
yield(app_data)
|
168
|
+
else
|
169
|
+
APP_NOT_FOUND
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def self.timestamp
|
174
|
+
Time.now.strftime("%G/%m/%d %H:%M:%S %z")
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|