rainforest 1.0.7 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -6
  3. data/.travis.yml +13 -1
  4. data/Gemfile +6 -0
  5. data/README.md +72 -21
  6. data/Rakefile +6 -13
  7. data/VERSION +1 -1
  8. data/bin/rainforest-console +1 -1
  9. data/gemfiles/default-with-activesupport.gemfile +8 -1
  10. data/gemfiles/json.gemfile +10 -2
  11. data/gemfiles/yajl.gemfile +10 -2
  12. data/lib/rainforest.rb +61 -240
  13. data/lib/rainforest/apibits/api_client.rb +28 -0
  14. data/lib/rainforest/apibits/api_endpoint.rb +11 -0
  15. data/lib/rainforest/apibits/api_list.rb +88 -0
  16. data/lib/rainforest/apibits/api_method.rb +95 -0
  17. data/lib/rainforest/apibits/api_object.rb +52 -0
  18. data/lib/rainforest/apibits/api_resource.rb +153 -0
  19. data/lib/rainforest/apibits/headers_builder.rb +47 -0
  20. data/lib/rainforest/apibits/params_builder.rb +27 -0
  21. data/lib/rainforest/apibits/path_builder.rb +38 -0
  22. data/lib/rainforest/apibits/requester.rb +104 -0
  23. data/lib/rainforest/apibits/util.rb +51 -0
  24. data/lib/rainforest/clients/default_client.rb +59 -0
  25. data/lib/rainforest/endpoints/client_stats_endpoint.rb +11 -0
  26. data/lib/rainforest/endpoints/environment_runs_endpoint.rb +11 -0
  27. data/lib/rainforest/endpoints/environments_endpoint.rb +48 -0
  28. data/lib/rainforest/endpoints/generator_rows_endpoint.rb +17 -0
  29. data/lib/rainforest/endpoints/generators_endpoint.rb +48 -0
  30. data/lib/rainforest/endpoints/integrations_endpoint.rb +33 -0
  31. data/lib/rainforest/endpoints/run_tests_endpoint.rb +20 -0
  32. data/lib/rainforest/endpoints/runs_endpoint.rb +48 -0
  33. data/lib/rainforest/endpoints/schedules_endpoint.rb +48 -0
  34. data/lib/rainforest/endpoints/site_environments_endpoint.rb +24 -0
  35. data/lib/rainforest/endpoints/sites_endpoint.rb +39 -0
  36. data/lib/rainforest/endpoints/tests_endpoint.rb +57 -0
  37. data/lib/rainforest/endpoints/users_endpoint.rb +48 -0
  38. data/lib/rainforest/errors/api_connection_error.rb +1 -1
  39. data/lib/rainforest/errors/api_error.rb +32 -1
  40. data/lib/rainforest/errors/authentication_error.rb +1 -1
  41. data/lib/rainforest/errors/rainforest_error.rb +2 -9
  42. data/lib/rainforest/resources/client_stats.rb +31 -0
  43. data/lib/rainforest/resources/environment.rb +73 -0
  44. data/lib/rainforest/resources/generator.rb +73 -0
  45. data/lib/rainforest/resources/integration.rb +52 -0
  46. data/lib/rainforest/resources/run.rb +93 -0
  47. data/lib/rainforest/resources/schedule.rb +63 -0
  48. data/lib/rainforest/resources/site.rb +53 -0
  49. data/lib/rainforest/resources/site_environment.rb +40 -0
  50. data/lib/rainforest/resources/test.rb +98 -0
  51. data/lib/rainforest/resources/user.rb +75 -0
  52. data/rainforest.gemspec +8 -6
  53. data/test/rainforest/api_client_test.rb +51 -0
  54. data/test/rainforest/api_endpoint_test.rb +13 -0
  55. data/test/rainforest/api_list_test.rb +49 -0
  56. data/test/rainforest/api_method_test.rb +78 -0
  57. data/test/rainforest/headers_builder_test.rb +28 -0
  58. data/test/rainforest/params_builder_test.rb +57 -0
  59. data/test/rainforest/path_builder_test.rb +50 -0
  60. data/test/rainforest/requester_test.rb +86 -0
  61. data/test/rainforest/util_test.rb +41 -19
  62. data/test/test_data.rb +72 -0
  63. data/test/test_helper.rb +17 -134
  64. metadata +99 -59
  65. data/CONTRIBUTORS +0 -2
  66. data/History.txt +0 -4
  67. data/LICENSE +0 -21
  68. data/lib/data/ca-certificates.crt +0 -3918
  69. data/lib/rainforest/api_operations/create.rb +0 -16
  70. data/lib/rainforest/api_operations/delete.rb +0 -11
  71. data/lib/rainforest/api_operations/list.rb +0 -16
  72. data/lib/rainforest/api_operations/update.rb +0 -61
  73. data/lib/rainforest/api_resource.rb +0 -33
  74. data/lib/rainforest/errors/invalid_request_error.rb +0 -10
  75. data/lib/rainforest/json.rb +0 -21
  76. data/lib/rainforest/list_object.rb +0 -35
  77. data/lib/rainforest/rainforest_object.rb +0 -165
  78. data/lib/rainforest/run.rb +0 -8
  79. data/lib/rainforest/singleton_api_resource.rb +0 -20
  80. data/lib/rainforest/util.rb +0 -100
  81. data/test/rainforest/api_resource_test.rb +0 -11
  82. data/test/rainforest/auth_test.rb +0 -24
  83. data/test/rainforest/list_object_test.rb +0 -7
  84. data/test/rainforest/metadata_test.rb +0 -7
  85. data/test/rainforest/run_test.rb +0 -36
@@ -0,0 +1,27 @@
1
+ module Rainforest
2
+ module ParamsBuilder
3
+
4
+ def self.clean(params)
5
+ Util.symbolize_keys(params || {})
6
+ end
7
+
8
+ # Clean the params, and the hash to_merge, and then merge them.
9
+ # This ensures that we dont get something like { "id" => 123, :id => 321 }.
10
+ def self.merge(*args)
11
+ ret = {}
12
+ args.each do |arg|
13
+ ret = ret.merge(clean(arg))
14
+ end
15
+ ret
16
+ end
17
+
18
+ def self.build(params, api_key=nil, auth_key=nil)
19
+ default_params.merge(clean(params))
20
+ end
21
+
22
+ def self.default_params
23
+ params = {}
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,38 @@
1
+ module Rainforest
2
+ module PathBuilder
3
+
4
+ # Take a path like:
5
+ # ":path/:id/dogs/:dog_id"
6
+ # and convert it to:
7
+ # "#{object.path}/#{object.id}/dogs/#{params[:id]}" => "/objects/1/dogs/2"
8
+ #
9
+ # Path priority is:
10
+ # 1. Object - this will be a class or an instance of a class.
11
+ # 2. Params - this is a hash of key values. All keys *must* be symbolized.
12
+ def self.build(path, object, params)
13
+ ret = path.dup
14
+ if ret.include?(":")
15
+ matches = ret.scan(/:([^\/]*)/).flatten.map(&:to_sym)
16
+ missing = Set.new(matches)
17
+
18
+ matches.each do |match|
19
+ value = determine_value(match, object, params)
20
+ missing.delete(match) unless value.nil?
21
+ ret.sub!(match.inspect, "#{value}")
22
+ end
23
+
24
+ if missing.any?
25
+ raise ArgumentError.new("Could not determine the full URL. The following values of the path are missing: #{missing.to_a.join(', ')}. Try setting them in your params.")
26
+ end
27
+ end
28
+ ret
29
+ end
30
+
31
+ def self.determine_value(match, object, params)
32
+ value = object.send(match) if object && object.respond_to?(match)
33
+ value ||= params[match] if params && params.has_key?(match)
34
+ value
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,104 @@
1
+ module Rainforest
2
+ module Requester
3
+
4
+ def self.request(method, url, params={}, headers={})
5
+ method = method.to_sym
6
+ url, params = prepare_params(method, url, params, headers)
7
+ request_opts = {
8
+ :method => method,
9
+ :url => url,
10
+ :headers => headers,
11
+ :payload => params,
12
+
13
+ :verify_ssl => false,
14
+ :open_timeout => 30,
15
+ :timeout => 60
16
+ }
17
+
18
+ execute_request(request_opts)
19
+ end
20
+
21
+ def self.execute_request(opts)
22
+ RestClient::Request.execute(opts)
23
+ end
24
+
25
+ def self.get(url, params, headers)
26
+ self.request(:get, url, params, headers)
27
+ end
28
+
29
+ def self.delete(url, params, headers)
30
+ self.request(:delete, url, params, headers)
31
+ end
32
+
33
+ def self.put(url, params, headers)
34
+ self.request(:put, url, params, headers)
35
+ end
36
+
37
+ def self.post(url, params, headers)
38
+ self.request(:post, url, params, headers)
39
+ end
40
+
41
+ def self.prepare_params(method, url, params={}, headers={})
42
+ if [:get, :head, :delete].include?(method)
43
+ unless params.empty?
44
+ url += URI.parse(url).query ? '&' : '?' + query_string(params)
45
+ end
46
+ params = nil
47
+ else
48
+ if headers["Content-Type"] == "application/json" || headers[:"Content-Type"] == "application/json"
49
+ params = JSON.generate(params)
50
+ else
51
+ headers["Content-Type"] = "application/x-www-form-urlencoded"
52
+ if !RestClient::Payload.has_file?(params)
53
+ params = query_string(params)
54
+ end
55
+ end
56
+ end
57
+ [url, params]
58
+ end
59
+
60
+ def self.query_string(params)
61
+ params ||= {}
62
+ if params.any?
63
+ query_array(params).join('&')
64
+ else
65
+ ""
66
+ end
67
+ end
68
+
69
+ # Three major use cases (and nesting of them needs to be supported):
70
+ # { :a => { :b => "bvalue" } } => ["a[b]=bvalue"]
71
+ # { :a => [1, 2] } => ["a[]=1", "a[]=2"]
72
+ # { :a => "value" } => ["a=value"]
73
+ def self.query_array(params, key_prefix=nil)
74
+ ret = []
75
+ params.each do |key, value|
76
+ if params.is_a?(Array)
77
+ value = key
78
+ key = ''
79
+ end
80
+ key_suffix = escape(key)
81
+ full_key = key_prefix ? "#{key_prefix}[#{key_suffix}]" : key_suffix
82
+
83
+ if value.is_a?(Hash) || value.is_a?(Array)
84
+ # Handles the following cases:
85
+ # { :a => { :b => "bvalue" } } => ["a[b]=bvalue"]
86
+ # { :a => [1, 2] } => ["a[]=1", "a[]=2"]
87
+ ret += query_array(value, full_key)
88
+ elsif value.is_a?(ApiObject)
89
+ ret += query_array(value.json, full_key)
90
+ else
91
+ # Handles the base case with just key and value:
92
+ # { :a => "value" } => ["a=value"]
93
+ ret << "#{full_key}=#{escape(value)}"
94
+ end
95
+ end
96
+ ret
97
+ end
98
+
99
+ def self.escape(val)
100
+ URI.escape(val.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
101
+ end
102
+
103
+ end
104
+ end
@@ -0,0 +1,51 @@
1
+ module Rainforest
2
+ module Util
3
+
4
+ def self.symbolize_keys(obj)
5
+ if obj.is_a?(Hash)
6
+ ret = {}
7
+ obj.each do |key, value|
8
+ ret[(key.to_sym rescue key) || key] = symbolize_keys(value)
9
+ end
10
+ return ret
11
+ elsif obj.is_a?(Array)
12
+ return obj.map{ |value| symbolize_keys(value) }
13
+ else
14
+ return obj
15
+ end
16
+ end
17
+
18
+ def self.sorta_deep_clone(json)
19
+ if json.is_a?(Hash)
20
+ ret = {}
21
+ json.each do |k, v|
22
+ ret[k] = sorta_deep_clone(v)
23
+ end
24
+ ret
25
+ elsif json.is_a?(Array)
26
+ json.map{ |j| sorta_deep_clone(j) }
27
+ else
28
+ begin
29
+ json.dup
30
+ rescue
31
+ json
32
+ end
33
+ end
34
+ end
35
+
36
+ def self.constantize(str, prefix=false)
37
+ str = str.to_s
38
+ begin
39
+ str.split('::').reduce(Rainforest, :const_get)
40
+ rescue NameError => e
41
+ if prefix
42
+ raise e
43
+ else
44
+ p = "#{self.name}".split("::").first
45
+ constantize("#{p}::#{str}", true)
46
+ end
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,59 @@
1
+ module Rainforest
2
+ class DefaultClient < ApiClient
3
+
4
+ def initialize(api_key)
5
+ self.refresh_from(api_key)
6
+ end
7
+
8
+ def refresh_from(api_key)
9
+ headers = {
10
+ :Accept => "application/json",
11
+ :"Content-Type" => "application/x-www-form-urlencoded",
12
+ :CLIENT_TOKEN => api_key,
13
+ }
14
+ params = {}
15
+ super(headers, params)
16
+ end
17
+
18
+ def client_stats
19
+ @client_stats ||= ClientStatsEndpoint.new(self)
20
+ end
21
+
22
+ def environments
23
+ @environments ||= EnvironmentsEndpoint.new(self)
24
+ end
25
+
26
+ def generators
27
+ @generators ||= GeneratorsEndpoint.new(self)
28
+ end
29
+
30
+ def integrations
31
+ @integrations ||= IntegrationsEndpoint.new(self)
32
+ end
33
+
34
+ def runs
35
+ @runs ||= RunsEndpoint.new(self)
36
+ end
37
+
38
+ def schedules
39
+ @schedules ||= SchedulesEndpoint.new(self)
40
+ end
41
+
42
+ def site_environments
43
+ @site_environments ||= SiteEnvironmentsEndpoint.new(self)
44
+ end
45
+
46
+ def sites
47
+ @sites ||= SitesEndpoint.new(self)
48
+ end
49
+
50
+ def tests
51
+ @tests ||= TestsEndpoint.new(self)
52
+ end
53
+
54
+ def users
55
+ @users ||= UsersEndpoint.new(self)
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,11 @@
1
+ module Rainforest
2
+ class ClientStatsEndpoint < ApiEndpoint
3
+
4
+ def retrieve(params={}, headers={})
5
+ method = ApiMethod.new(:get, "/clients/stats", params, headers, @parent)
6
+ json = @client.execute(method)
7
+ ClientStats.new(json, method)
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Rainforest
2
+ class EnvironmentRunsEndpoint < ApiEndpoint
3
+
4
+ def all(params={}, headers={})
5
+ method = ApiMethod.new(:get, "/environments/:id/runs", params, headers, @parent)
6
+ json = @client.execute(method)
7
+ ApiList.new(:Run, json, method)
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,48 @@
1
+ module Rainforest
2
+ class EnvironmentsEndpoint < ApiEndpoint
3
+
4
+ def new(id)
5
+ Environment.new({:id => id}, nil, @client)
6
+ end
7
+
8
+ def all(params={}, headers={})
9
+ method = ApiMethod.new(:get, "/environments", params, headers, @parent)
10
+ json = @client.execute(method)
11
+ ApiList.new(:Environment, json, method)
12
+ end
13
+
14
+ def retrieve(environment_id, params={}, headers={})
15
+ params = ParamsBuilder.merge({
16
+ :environment_id => environment_id,
17
+ }, params)
18
+ method = ApiMethod.new(:get, "/environments/:environment_id", params, headers, @parent)
19
+ json = @client.execute(method)
20
+ Environment.new(json, method)
21
+ end
22
+
23
+ def delete(environment_id, params={}, headers={})
24
+ params = ParamsBuilder.merge({
25
+ :environment_id => environment_id,
26
+ }, params)
27
+ method = ApiMethod.new(:delete, "/environments/:environment_id", params, headers, @parent)
28
+ json = @client.execute(method)
29
+ json
30
+ end
31
+
32
+ def update(environment_id, params={}, headers={})
33
+ params = ParamsBuilder.merge({
34
+ :environment_id => environment_id,
35
+ }, params)
36
+ method = ApiMethod.new(:put, "/environments/:environment_id", params, headers, @parent)
37
+ json = @client.execute(method)
38
+ Environment.new(json, method)
39
+ end
40
+
41
+ def create(params={}, headers={})
42
+ method = ApiMethod.new(:post, "/environments", params, headers, @parent)
43
+ json = @client.execute(method)
44
+ Environment.new(json, method)
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,17 @@
1
+ module Rainforest
2
+ class GeneratorRowsEndpoint < ApiEndpoint
3
+
4
+ def all(params={}, headers={})
5
+ method = ApiMethod.new(:get, "/generators/:id/rows", params, headers, @parent)
6
+ json = @client.execute(method)
7
+ json
8
+ end
9
+
10
+ def create(params={}, headers={})
11
+ method = ApiMethod.new(:post, "/generators/:id/rows", params, headers, @parent)
12
+ json = @client.execute(method)
13
+ json
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,48 @@
1
+ module Rainforest
2
+ class GeneratorsEndpoint < ApiEndpoint
3
+
4
+ def new(id)
5
+ Generator.new({:id => id}, nil, @client)
6
+ end
7
+
8
+ def all(params={}, headers={})
9
+ method = ApiMethod.new(:get, "/generators", params, headers, @parent)
10
+ json = @client.execute(method)
11
+ ApiList.new(:Generator, json, method)
12
+ end
13
+
14
+ def retrieve(generator_id, params={}, headers={})
15
+ params = ParamsBuilder.merge({
16
+ :generator_id => generator_id,
17
+ }, params)
18
+ method = ApiMethod.new(:get, "/generators/:generator_id", params, headers, @parent)
19
+ json = @client.execute(method)
20
+ Generator.new(json, method)
21
+ end
22
+
23
+ def delete(generator_id, params={}, headers={})
24
+ params = ParamsBuilder.merge({
25
+ :generator_id => generator_id,
26
+ }, params)
27
+ method = ApiMethod.new(:delete, "/generators/:generator_id", params, headers, @parent)
28
+ json = @client.execute(method)
29
+ Generator.new(json, method)
30
+ end
31
+
32
+ def update(generator_id, params={}, headers={})
33
+ params = ParamsBuilder.merge({
34
+ :generator_id => generator_id,
35
+ }, params)
36
+ method = ApiMethod.new(:put, "/generators/:generator_id", params, headers, @parent)
37
+ json = @client.execute(method)
38
+ Generator.new(json, method)
39
+ end
40
+
41
+ def create(params={}, headers={})
42
+ method = ApiMethod.new(:post, "/generators", params, headers, @parent)
43
+ json = @client.execute(method)
44
+ Generator.new(json, method)
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,33 @@
1
+ module Rainforest
2
+ class IntegrationsEndpoint < ApiEndpoint
3
+
4
+ def new(id)
5
+ Integration.new({:id => id}, nil, @client)
6
+ end
7
+
8
+ def all(params={}, headers={})
9
+ method = ApiMethod.new(:get, "/integrations", params, headers, @parent)
10
+ json = @client.execute(method)
11
+ ApiList.new(:Integration, json, method)
12
+ end
13
+
14
+ def retrieve(integration_id, params={}, headers={})
15
+ params = ParamsBuilder.merge({
16
+ :integration_id => integration_id,
17
+ }, params)
18
+ method = ApiMethod.new(:get, "/integrations/:integration_id", params, headers, @parent)
19
+ json = @client.execute(method)
20
+ Integration.new(json, method)
21
+ end
22
+
23
+ def update(integration_id, params={}, headers={})
24
+ params = ParamsBuilder.merge({
25
+ :integration_id => integration_id,
26
+ }, params)
27
+ method = ApiMethod.new(:put, "/integrations/:integration_id", params, headers, @parent)
28
+ json = @client.execute(method)
29
+ Integration.new(json, method)
30
+ end
31
+
32
+ end
33
+ end