mgmt_console 0.4.1

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.
@@ -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: []