mgmt_console 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,241 @@
1
+ module MgmtConsole
2
+ # Custom error class for rescuing from all GitHub errors
3
+ class Error < StandardError
4
+
5
+ # Returns the appropriate MgmtConsole::Error subclass based
6
+ # on status and response message
7
+ #
8
+ # @param [Hash] response HTTP response
9
+ # @return [MgmtConsole::Error]
10
+ def self.from_response(response)
11
+ status = response[:status].to_i
12
+ body = response[:body].to_s
13
+ headers = response[:response_headers]
14
+
15
+ if klass = case status
16
+ when 400 then MgmtConsole::BadRequest
17
+ when 401 then error_for_401(headers)
18
+ when 403 then error_for_403(body)
19
+ when 404 then MgmtConsole::NotFound
20
+ when 405 then MgmtConsole::MethodNotAllowed
21
+ when 406 then MgmtConsole::NotAcceptable
22
+ when 409 then MgmtConsole::Conflict
23
+ when 415 then MgmtConsole::UnsupportedMediaType
24
+ when 422 then MgmtConsole::UnprocessableEntity
25
+ when 400..499 then MgmtConsole::ClientError
26
+ when 500 then MgmtConsole::InternalServerError
27
+ when 501 then MgmtConsole::NotImplemented
28
+ when 502 then MgmtConsole::BadGateway
29
+ when 503 then MgmtConsole::ServiceUnavailable
30
+ when 500..599 then MgmtConsole::ServerError
31
+ end
32
+ klass.new(response)
33
+ end
34
+ end
35
+
36
+ def initialize(response=nil)
37
+ @response = response
38
+ super(build_error_message)
39
+ end
40
+
41
+ # Documentation URL returned by the API for some errors
42
+ #
43
+ # @return [String]
44
+ def documentation_url
45
+ data[:documentation_url] if data.is_a? Hash
46
+ end
47
+
48
+ # Returns most appropriate error for 401 HTTP status code
49
+ # @private
50
+ def self.error_for_401(headers)
51
+ if MgmtConsole::OneTimePasswordRequired.required_header(headers)
52
+ MgmtConsole::OneTimePasswordRequired
53
+ else
54
+ MgmtConsole::Unauthorized
55
+ end
56
+ end
57
+
58
+ # Returns most appropriate error for 403 HTTP status code
59
+ # @private
60
+ def self.error_for_403(body)
61
+ if body =~ /rate limit exceeded/i
62
+ MgmtConsole::TooManyRequests
63
+ elsif body =~ /login attempts exceeded/i
64
+ MgmtConsole::TooManyLoginAttempts
65
+ elsif body =~ /abuse/i
66
+ MgmtConsole::AbuseDetected
67
+ elsif body =~ /repository access blocked/i
68
+ MgmtConsole::RepositoryUnavailable
69
+ else
70
+ MgmtConsole::Forbidden
71
+ end
72
+ end
73
+
74
+ # Array of validation errors
75
+ # @return [Array<Hash>] Error info
76
+ def errors
77
+ if data && data.is_a?(Hash)
78
+ data[:errors] || []
79
+ else
80
+ []
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+ def data
87
+ @data ||=
88
+ if (body = @response[:body]) && !body.empty?
89
+ if body.is_a?(String) &&
90
+ @response[:response_headers] &&
91
+ @response[:response_headers][:content_type] =~ /json/
92
+
93
+ Sawyer::Agent.serializer.decode(body)
94
+ else
95
+ body
96
+ end
97
+ else
98
+ nil
99
+ end
100
+ end
101
+
102
+ def response_message
103
+ case data
104
+ when Hash
105
+ data[:message]
106
+ when String
107
+ data
108
+ end
109
+ end
110
+
111
+ def response_error
112
+ "Error: #{data[:error]}" if data.is_a?(Hash) && data[:error]
113
+ end
114
+
115
+ def response_error_summary
116
+ return nil unless data.is_a?(Hash) && !Array(data[:errors]).empty?
117
+
118
+ summary = "\nError summary:\n"
119
+ summary << data[:errors].map do |hash|
120
+ hash.map { |k,v| " #{k}: #{v}" }
121
+ end.join("\n")
122
+
123
+ summary
124
+ end
125
+
126
+ def build_error_message
127
+ return nil if @response.nil?
128
+
129
+ message = "#{@response[:method].to_s.upcase} "
130
+ message << redact_url(@response[:url].to_s) + ": "
131
+ message << "#{@response[:status]} - "
132
+ message << "#{response_message}" unless response_message.nil?
133
+ message << "#{response_error}" unless response_error.nil?
134
+ message << "#{response_error_summary}" unless response_error_summary.nil?
135
+ message << " // See: #{documentation_url}" unless documentation_url.nil?
136
+ message
137
+ end
138
+
139
+ def redact_url(url_string)
140
+ %w[client_secret access_token].each do |token|
141
+ url_string.gsub!(/#{token}=\S+/, "#{token}=(redacted)") if url_string.include? token
142
+ end
143
+ url_string
144
+ end
145
+ end
146
+
147
+ # Raised on errors in the 400-499 range
148
+ class ClientError < Error; end
149
+
150
+ # Raised when GitHub returns a 400 HTTP status code
151
+ class BadRequest < ClientError; end
152
+
153
+ # Raised when GitHub returns a 401 HTTP status code
154
+ class Unauthorized < ClientError; end
155
+
156
+ # Raised when GitHub returns a 401 HTTP status code
157
+ # and headers include "X-GitHub-OTP"
158
+ class OneTimePasswordRequired < ClientError
159
+ #@private
160
+ OTP_DELIVERY_PATTERN = /required; (\w+)/i
161
+
162
+ #@private
163
+ def self.required_header(headers)
164
+ OTP_DELIVERY_PATTERN.match headers['X-GitHub-OTP'].to_s
165
+ end
166
+
167
+ # Delivery method for the user's OTP
168
+ #
169
+ # @return [String]
170
+ def password_delivery
171
+ @password_delivery ||= delivery_method_from_header
172
+ end
173
+
174
+ private
175
+
176
+ def delivery_method_from_header
177
+ if match = self.class.required_header(@response[:response_headers])
178
+ match[1]
179
+ end
180
+ end
181
+ end
182
+
183
+ # Raised when GitHub returns a 403 HTTP status code
184
+ class Forbidden < ClientError; end
185
+
186
+ # Raised when GitHub returns a 403 HTTP status code
187
+ # and body matches 'rate limit exceeded'
188
+ class TooManyRequests < Forbidden; end
189
+
190
+ # Raised when GitHub returns a 403 HTTP status code
191
+ # and body matches 'login attempts exceeded'
192
+ class TooManyLoginAttempts < Forbidden; end
193
+
194
+ # Raised when GitHub returns a 403 HTTP status code
195
+ # and body matches 'abuse'
196
+ class AbuseDetected < Forbidden; end
197
+
198
+ # Raised when GitHub returns a 403 HTTP status code
199
+ # and body matches 'repository access blocked'
200
+ class RepositoryUnavailable < Forbidden; end
201
+
202
+ # Raised when GitHub returns a 404 HTTP status code
203
+ class NotFound < ClientError; end
204
+
205
+ # Raised when GitHub returns a 405 HTTP status code
206
+ class MethodNotAllowed < ClientError; end
207
+
208
+ # Raised when GitHub returns a 406 HTTP status code
209
+ class NotAcceptable < ClientError; end
210
+
211
+ # Raised when GitHub returns a 409 HTTP status code
212
+ class Conflict < ClientError; end
213
+
214
+ # Raised when GitHub returns a 414 HTTP status code
215
+ class UnsupportedMediaType < ClientError; end
216
+
217
+ # Raised when GitHub returns a 422 HTTP status code
218
+ class UnprocessableEntity < ClientError; end
219
+
220
+ # Raised on errors in the 500-599 range
221
+ class ServerError < Error; end
222
+
223
+ # Raised when GitHub returns a 500 HTTP status code
224
+ class InternalServerError < ServerError; end
225
+
226
+ # Raised when GitHub returns a 501 HTTP status code
227
+ class NotImplemented < ServerError; end
228
+
229
+ # Raised when GitHub returns a 502 HTTP status code
230
+ class BadGateway < ServerError; end
231
+
232
+ # Raised when GitHub returns a 503 HTTP status code
233
+ class ServiceUnavailable < ServerError; end
234
+
235
+ # Raised when client fails to provide valid Content-Type
236
+ class MissingContentType < ArgumentError; end
237
+
238
+ # Raised when a method requires an application client_id
239
+ # and secret but none is provided
240
+ class ApplicationCredentialsRequired < StandardError; end
241
+ end
@@ -0,0 +1,21 @@
1
+ require 'faraday'
2
+
3
+ module MgmtConsole
4
+
5
+ module Response
6
+
7
+ # Parses RSS and Atom feed responses.
8
+ class FeedParser < Faraday::Response::Middleware
9
+
10
+ private
11
+
12
+ def on_complete(env)
13
+ if env[:response_headers]["content-type"] =~ /(\batom|\brss)/
14
+ require 'rss'
15
+ env[:body] = RSS::Parser.parse env[:body]
16
+ end
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ require 'faraday'
2
+ require 'mgmt_console/error'
3
+
4
+ module MgmtConsole
5
+ # Faraday response middleware
6
+ module Response
7
+
8
+ # This class raises an MgmtConsole-flavored exception based
9
+ # HTTP status codes returned by the API
10
+ class RaiseError < Faraday::Response::Middleware
11
+
12
+ private
13
+
14
+ def on_complete(response)
15
+ if error = MgmtConsole::Error.from_response(response)
16
+ raise error
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ module MgmtConsole
2
+ VERSION = "0.4.1"
3
+ end
@@ -0,0 +1,33 @@
1
+ require 'mgmt_console/client'
2
+ require 'mgmt_console/default'
3
+
4
+ # Ruby toolkit for the Mgmt Console API
5
+ module MgmtConsole
6
+
7
+ class << self
8
+ include MgmtConsole::Configurable
9
+
10
+ # API client based on configured options {Configurable}
11
+ #
12
+ # @return [MgmtConsole::Client] API wrapper
13
+ def client
14
+ @client = MgmtConsole::Client.new(options) unless defined?(@client) && @client.same_options?(options)
15
+ @client
16
+ end
17
+
18
+ # @private
19
+ def respond_to_missing?(method_name, include_private=false); client.respond_to?(method_name, include_private); end if RUBY_VERSION >= "1.9"
20
+ # @private
21
+ def respond_to?(method_name, include_private=false); client.respond_to?(method_name, include_private) || super; end if RUBY_VERSION < "1.9"
22
+
23
+ private
24
+
25
+ def method_missing(method_name, *args, &block)
26
+ return super unless client.respond_to?(method_name)
27
+ client.send(method_name, *args, &block)
28
+ end
29
+
30
+ end
31
+ end
32
+
33
+ MgmtConsole.setup
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mgmt_console/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "mgmt_console"
8
+ spec.version = MgmtConsole::VERSION
9
+ spec.authors = ["Jason Barnett"]
10
+ spec.email = ["jason.w.barnett@gmail.com"]
11
+
12
+ spec.summary = "Ruby toolkit for working with the Mgmt Console API"
13
+ spec.description = %q{Simple wrapper for the Mgmt Console API}
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
+ spec.bindir = "exe"
17
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.required_ruby_version = '>= 1.9.2'
21
+ spec.required_rubygems_version = '>= 1.3.5'
22
+
23
+ spec.add_runtime_dependency "sawyer", "~> 0.6.0"
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.9"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mgmt_console
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.1
5
+ platform: ruby
6
+ authors:
7
+ - Jason Barnett
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-09-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sawyer
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.6.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.6.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.9'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.9'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ description: Simple wrapper for the Mgmt Console API
56
+ email:
57
+ - jason.w.barnett@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".travis.yml"
64
+ - CODE_OF_CONDUCT.md
65
+ - Gemfile
66
+ - README.md
67
+ - Rakefile
68
+ - bin/console
69
+ - bin/setup
70
+ - examples/query_engage_.md
71
+ - lib/mgmt_console.rb
72
+ - lib/mgmt_console/api_error.rb
73
+ - lib/mgmt_console/authentication.rb
74
+ - lib/mgmt_console/client.rb
75
+ - lib/mgmt_console/client/engage_communities.rb
76
+ - lib/mgmt_console/client/engage_environments.rb
77
+ - lib/mgmt_console/client/engage_instances.rb
78
+ - lib/mgmt_console/client/engage_servers.rb
79
+ - lib/mgmt_console/client/server_environments.rb
80
+ - lib/mgmt_console/client/spigit_configs.rb
81
+ - lib/mgmt_console/configurable.rb
82
+ - lib/mgmt_console/default.rb
83
+ - lib/mgmt_console/error.rb
84
+ - lib/mgmt_console/response/feed_parser.rb
85
+ - lib/mgmt_console/response/raise_error.rb
86
+ - lib/mgmt_console/version.rb
87
+ - mgmt_console_client.gemspec
88
+ homepage:
89
+ licenses: []
90
+ metadata: {}
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: 1.9.2
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: 1.3.5
105
+ requirements: []
106
+ rubyforge_project:
107
+ rubygems_version: 2.4.8
108
+ signing_key:
109
+ specification_version: 4
110
+ summary: Ruby toolkit for working with the Mgmt Console API
111
+ test_files: []